summaryrefslogtreecommitdiff
path: root/miranda-wine/protocols
diff options
context:
space:
mode:
Diffstat (limited to 'miranda-wine/protocols')
-rw-r--r--miranda-wine/protocols/IcqOscarJ/UI/askauthentication.c120
-rw-r--r--miranda-wine/protocols/IcqOscarJ/UI/askauthentication.h39
-rw-r--r--miranda-wine/protocols/IcqOscarJ/UI/loginpassword.c106
-rw-r--r--miranda-wine/protocols/IcqOscarJ/UI/loginpassword.h39
-rw-r--r--miranda-wine/protocols/IcqOscarJ/UI/m_flash.h71
-rw-r--r--miranda-wine/protocols/IcqOscarJ/UI/userinfotab.c656
-rw-r--r--miranda-wine/protocols/IcqOscarJ/UI/userinfotab.h38
-rw-r--r--miranda-wine/protocols/IcqOscarJ/capabilities.c162
-rw-r--r--miranda-wine/protocols/IcqOscarJ/capabilities.h51
-rw-r--r--miranda-wine/protocols/IcqOscarJ/chan_01login.c115
-rw-r--r--miranda-wine/protocols/IcqOscarJ/chan_02data.c216
-rw-r--r--miranda-wine/protocols/IcqOscarJ/chan_03error.c43
-rw-r--r--miranda-wine/protocols/IcqOscarJ/chan_04close.c323
-rw-r--r--miranda-wine/protocols/IcqOscarJ/chan_05ping.c105
-rw-r--r--miranda-wine/protocols/IcqOscarJ/changeinfo/changeinfo.h116
-rw-r--r--miranda-wine/protocols/IcqOscarJ/changeinfo/constants.c658
-rw-r--r--miranda-wine/protocols/IcqOscarJ/changeinfo/db.c226
-rw-r--r--miranda-wine/protocols/IcqOscarJ/changeinfo/dlgproc.c560
-rw-r--r--miranda-wine/protocols/IcqOscarJ/changeinfo/editlist.c173
-rw-r--r--miranda-wine/protocols/IcqOscarJ/changeinfo/editstring.c362
-rw-r--r--miranda-wine/protocols/IcqOscarJ/changeinfo/expandst.icobin0 -> 318 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/changeinfo/main.c54
-rw-r--r--miranda-wine/protocols/IcqOscarJ/changeinfo/upload.c204
-rw-r--r--miranda-wine/protocols/IcqOscarJ/channels.h52
-rw-r--r--miranda-wine/protocols/IcqOscarJ/cookies.c365
-rw-r--r--miranda-wine/protocols/IcqOscarJ/cookies.h140
-rw-r--r--miranda-wine/protocols/IcqOscarJ/directpackets.c303
-rw-r--r--miranda-wine/protocols/IcqOscarJ/directpackets.h55
-rw-r--r--miranda-wine/protocols/IcqOscarJ/fam_01service.c1014
-rw-r--r--miranda-wine/protocols/IcqOscarJ/fam_02location.c301
-rw-r--r--miranda-wine/protocols/IcqOscarJ/fam_03buddy.c499
-rw-r--r--miranda-wine/protocols/IcqOscarJ/fam_04message.c2512
-rw-r--r--miranda-wine/protocols/IcqOscarJ/fam_09bos.c132
-rw-r--r--miranda-wine/protocols/IcqOscarJ/fam_0alookup.c144
-rw-r--r--miranda-wine/protocols/IcqOscarJ/fam_0bstatus.c70
-rw-r--r--miranda-wine/protocols/IcqOscarJ/fam_13servclist.c1863
-rw-r--r--miranda-wine/protocols/IcqOscarJ/fam_15icqserver.c1179
-rw-r--r--miranda-wine/protocols/IcqOscarJ/fam_17signon.c198
-rw-r--r--miranda-wine/protocols/IcqOscarJ/families.h90
-rw-r--r--miranda-wine/protocols/IcqOscarJ/forkthread.c121
-rw-r--r--miranda-wine/protocols/IcqOscarJ/forkthread.h73
-rw-r--r--miranda-wine/protocols/IcqOscarJ/globals.h90
-rw-r--r--miranda-wine/protocols/IcqOscarJ/guids.h92
-rw-r--r--miranda-wine/protocols/IcqOscarJ/i18n.c477
-rw-r--r--miranda-wine/protocols/IcqOscarJ/i18n.h55
-rw-r--r--miranda-wine/protocols/IcqOscarJ/iconlib.c126
-rw-r--r--miranda-wine/protocols/IcqOscarJ/iconlib.h50
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icons_pack/ICONS.rc78
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/auth_ask.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/auth_grant.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/auth_revoke.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/icq.icobin0 -> 1718 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus01.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus02.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus03.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus04.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus05.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus06.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus07.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus08.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus09.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus10.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus11.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus12.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus13.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus14.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus15.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus16.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus17.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus18.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus19.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus20.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus21.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus22.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus23.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus24.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus25.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus26.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus27.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus28.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus29.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus30.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus31.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icos/xstatus32.icobin0 -> 2038 bytes
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_advsearch.c211
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_advsearch.h39
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_avatar.c1275
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_avatar.h62
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_clients.c665
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_constants.h552
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_db.c350
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_db.h77
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_direct.c1347
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_direct.h130
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_directmsg.c418
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_fieldnames.c280
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_fieldnames.h51
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_filerequests.c236
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_filetransfer.c575
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_firstrun.c129
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_http.c228
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_http.h55
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_infoupdate.c355
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_infoupdate.h58
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_opts.c862
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_opts.h42
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_packet.c711
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_packet.h114
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_popups.c279
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_popups.h50
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_rates.c330
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_rates.h68
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_server.c399
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_server.h67
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_servlist.c1925
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_servlist.h124
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_uploadui.c1075
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_uploadui.h39
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_xstatus.c1245
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_xtraz.c454
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icq_xtraz.h70
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icqosc_svcs.c2316
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icqosc_svcs.h95
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icqoscar.c42
-rw-r--r--miranda-wine/protocols/IcqOscarJ/icqoscar.h124
-rw-r--r--miranda-wine/protocols/IcqOscarJ/init.c573
-rw-r--r--miranda-wine/protocols/IcqOscarJ/init.h50
-rw-r--r--miranda-wine/protocols/IcqOscarJ/log.c158
-rw-r--r--miranda-wine/protocols/IcqOscarJ/log.h51
-rw-r--r--miranda-wine/protocols/IcqOscarJ/m_cluiframes.h255
-rw-r--r--miranda-wine/protocols/IcqOscarJ/m_icolib.h75
-rw-r--r--miranda-wine/protocols/IcqOscarJ/m_icq.h294
-rw-r--r--miranda-wine/protocols/IcqOscarJ/m_popupw.h56
-rw-r--r--miranda-wine/protocols/IcqOscarJ/m_updater.h117
-rw-r--r--miranda-wine/protocols/IcqOscarJ/md5.c352
-rw-r--r--miranda-wine/protocols/IcqOscarJ/md5.h82
-rw-r--r--miranda-wine/protocols/IcqOscarJ/oscar_filetransfer.c1211
-rw-r--r--miranda-wine/protocols/IcqOscarJ/oscar_filetransfer.h155
-rw-r--r--miranda-wine/protocols/IcqOscarJ/resource.h207
-rw-r--r--miranda-wine/protocols/IcqOscarJ/resources.rc716
-rw-r--r--miranda-wine/protocols/IcqOscarJ/stdpackets.c1613
-rw-r--r--miranda-wine/protocols/IcqOscarJ/stdpackets.h111
-rw-r--r--miranda-wine/protocols/IcqOscarJ/tlv.c222
-rw-r--r--miranda-wine/protocols/IcqOscarJ/tlv.h68
-rw-r--r--miranda-wine/protocols/IcqOscarJ/utilities.c1875
-rw-r--r--miranda-wine/protocols/IcqOscarJ/utilities.h157
-rw-r--r--miranda-wine/protocols/JabberG/icos/add2roster.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/JabberG/icos/addcontact.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/JabberG/icos/block.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/JabberG/icos/delete.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/JabberG/icos/grant.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/JabberG/icos/group.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/JabberG/icos/jabber.icobin0 -> 9062 bytes
-rw-r--r--miranda-wine/protocols/JabberG/icos/key.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/JabberG/icos/open.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/JabberG/icos/pages.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/JabberG/icos/rename.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/JabberG/icos/request.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/JabberG/icos/save.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/JabberG/icos/user2room.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/JabberG/icos/write.icobin0 -> 9062 bytes
-rw-r--r--miranda-wine/protocols/JabberG/jabber.cpp350
-rw-r--r--miranda-wine/protocols/JabberG/jabber.h586
-rw-r--r--miranda-wine/protocols/JabberG/jabber.rc839
-rw-r--r--miranda-wine/protocols/JabberG/jabber_agent.cpp565
-rw-r--r--miranda-wine/protocols/JabberG/jabber_bitmap.cpp53
-rw-r--r--miranda-wine/protocols/JabberG/jabber_byte.cpp459
-rw-r--r--miranda-wine/protocols/JabberG/jabber_byte.h52
-rw-r--r--miranda-wine/protocols/JabberG/jabber_chat.cpp796
-rw-r--r--miranda-wine/protocols/JabberG/jabber_file.cpp611
-rw-r--r--miranda-wine/protocols/JabberG/jabber_form.cpp479
-rw-r--r--miranda-wine/protocols/JabberG/jabber_ft.cpp419
-rw-r--r--miranda-wine/protocols/JabberG/jabber_groupchat.cpp886
-rw-r--r--miranda-wine/protocols/JabberG/jabber_iq.cpp173
-rw-r--r--miranda-wine/protocols/JabberG/jabber_iq.h87
-rw-r--r--miranda-wine/protocols/JabberG/jabber_iqid.cpp1429
-rw-r--r--miranda-wine/protocols/JabberG/jabber_iqid_muc.cpp531
-rw-r--r--miranda-wine/protocols/JabberG/jabber_libstr.cpp76
-rw-r--r--miranda-wine/protocols/JabberG/jabber_list.cpp388
-rw-r--r--miranda-wine/protocols/JabberG/jabber_list.h174
-rw-r--r--miranda-wine/protocols/JabberG/jabber_menu.cpp281
-rw-r--r--miranda-wine/protocols/JabberG/jabber_misc.cpp382
-rw-r--r--miranda-wine/protocols/JabberG/jabber_opt.cpp724
-rw-r--r--miranda-wine/protocols/JabberG/jabber_password.cpp100
-rw-r--r--miranda-wine/protocols/JabberG/jabber_proxy.cpp154
-rw-r--r--miranda-wine/protocols/JabberG/jabber_proxy.h34
-rw-r--r--miranda-wine/protocols/JabberG/jabber_ssl.cpp181
-rw-r--r--miranda-wine/protocols/JabberG/jabber_ssl.h64
-rw-r--r--miranda-wine/protocols/JabberG/jabber_std.cpp171
-rw-r--r--miranda-wine/protocols/JabberG/jabber_svc.cpp1431
-rw-r--r--miranda-wine/protocols/JabberG/jabber_thread.cpp1793
-rw-r--r--miranda-wine/protocols/JabberG/jabber_userinfo.cpp525
-rw-r--r--miranda-wine/protocols/JabberG/jabber_util.cpp1133
-rw-r--r--miranda-wine/protocols/JabberG/jabber_vcard.cpp1179
-rw-r--r--miranda-wine/protocols/JabberG/jabber_ws.cpp92
-rw-r--r--miranda-wine/protocols/JabberG/jabber_xml.cpp786
-rw-r--r--miranda-wine/protocols/JabberG/jabber_xml.h152
-rw-r--r--miranda-wine/protocols/JabberG/jabber_xmlns.cpp107
-rw-r--r--miranda-wine/protocols/JabberG/jabber_xmlns.h34
-rw-r--r--miranda-wine/protocols/JabberG/msvc6.rc2
-rw-r--r--miranda-wine/protocols/JabberG/resource.h232
-rw-r--r--miranda-wine/protocols/JabberG/sdk/m_smileyadd.h78
-rw-r--r--miranda-wine/protocols/JabberG/sha1.cpp446
-rw-r--r--miranda-wine/protocols/JabberG/sha1.h133
-rw-r--r--miranda-wine/protocols/JabberG/version.h3
-rw-r--r--miranda-wine/protocols/JabberG/version.rc52
-rw-r--r--miranda-wine/protocols/MSN/Icos/avatar.icobin0 -> 1406 bytes
-rw-r--r--miranda-wine/protocols/MSN/Icos/inbox.icobin0 -> 1406 bytes
-rw-r--r--miranda-wine/protocols/MSN/Icos/invite.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/MSN/Icos/list_al.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/MSN/Icos/list_bl.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/MSN/Icos/list_fl.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/MSN/Icos/list_rl.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/MSN/Icos/msn.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/MSN/Icos/msnblock.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/MSN/Icos/netmeeting.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/MSN/Icos/nudge.icobin0 -> 1406 bytes
-rw-r--r--miranda-wine/protocols/MSN/Icos/profile.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/MSN/Icos/services.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/MSN/SDK/m_chat.h424
-rw-r--r--miranda-wine/protocols/MSN/mmdecsjis.cpp489
-rw-r--r--miranda-wine/protocols/MSN/msn.cpp407
-rw-r--r--miranda-wine/protocols/MSN/msn.rc348
-rw-r--r--miranda-wine/protocols/MSN/msn_bitmap.cpp213
-rw-r--r--miranda-wine/protocols/MSN/msn_block.cpp33
-rw-r--r--miranda-wine/protocols/MSN/msn_chat.cpp335
-rw-r--r--miranda-wine/protocols/MSN/msn_commands.cpp1841
-rw-r--r--miranda-wine/protocols/MSN/msn_contact.cpp74
-rw-r--r--miranda-wine/protocols/MSN/msn_errors.cpp95
-rw-r--r--miranda-wine/protocols/MSN/msn_ftold.cpp347
-rw-r--r--miranda-wine/protocols/MSN/msn_global.h641
-rw-r--r--miranda-wine/protocols/MSN/msn_http.cpp97
-rw-r--r--miranda-wine/protocols/MSN/msn_libstr.cpp54
-rw-r--r--miranda-wine/protocols/MSN/msn_lists.cpp346
-rw-r--r--miranda-wine/protocols/MSN/msn_md5.h59
-rw-r--r--miranda-wine/protocols/MSN/msn_md5c.cpp287
-rw-r--r--miranda-wine/protocols/MSN/msn_mime.cpp162
-rw-r--r--miranda-wine/protocols/MSN/msn_misc.cpp1069
-rw-r--r--miranda-wine/protocols/MSN/msn_msgqueue.cpp162
-rw-r--r--miranda-wine/protocols/MSN/msn_opts.cpp866
-rw-r--r--miranda-wine/protocols/MSN/msn_p2p.cpp1433
-rw-r--r--miranda-wine/protocols/MSN/msn_p2ps.cpp248
-rw-r--r--miranda-wine/protocols/MSN/msn_srv.cpp184
-rw-r--r--miranda-wine/protocols/MSN/msn_ssl.cpp667
-rw-r--r--miranda-wine/protocols/MSN/msn_std.cpp158
-rw-r--r--miranda-wine/protocols/MSN/msn_svcs.cpp1404
-rw-r--r--miranda-wine/protocols/MSN/msn_switchboard.cpp53
-rw-r--r--miranda-wine/protocols/MSN/msn_threads.cpp723
-rw-r--r--miranda-wine/protocols/MSN/msn_useropts.cpp287
-rw-r--r--miranda-wine/protocols/MSN/msn_ws.cpp324
-rw-r--r--miranda-wine/protocols/MSN/resource.h111
-rw-r--r--miranda-wine/protocols/MSN/resource.rc2
-rw-r--r--miranda-wine/protocols/MSN/sha1.c419
-rw-r--r--miranda-wine/protocols/MSN/sha1.h114
-rw-r--r--miranda-wine/protocols/MSN/version.h3
-rw-r--r--miranda-wine/protocols/MSN/version.rc36
-rw-r--r--miranda-wine/protocols/Yahoo/Yahoo.rc124
-rw-r--r--miranda-wine/protocols/Yahoo/avatar.c1142
-rw-r--r--miranda-wine/protocols/Yahoo/avatar.h66
-rw-r--r--miranda-wine/protocols/Yahoo/chat.c77
-rw-r--r--miranda-wine/protocols/Yahoo/chat.h42
-rw-r--r--miranda-wine/protocols/Yahoo/file_transfer.c613
-rw-r--r--miranda-wine/protocols/Yahoo/file_transfer.h48
-rw-r--r--miranda-wine/protocols/Yahoo/http_gateway.c88
-rw-r--r--miranda-wine/protocols/Yahoo/http_gateway.h24
-rw-r--r--miranda-wine/protocols/Yahoo/icos/address_book.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/Yahoo/icos/calendar.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/Yahoo/icos/inbox.icobin0 -> 1406 bytes
-rw-r--r--miranda-wine/protocols/Yahoo/icos/invite.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/Yahoo/icos/profile.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/Yahoo/icos/refresh.icobin0 -> 1406 bytes
-rw-r--r--miranda-wine/protocols/Yahoo/icos/set_status.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/Yahoo/icos/yahoo.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/Yahoo/im.c333
-rw-r--r--miranda-wine/protocols/Yahoo/im.h23
-rw-r--r--miranda-wine/protocols/Yahoo/libyahoo2/config.h35
-rw-r--r--miranda-wine/protocols/Yahoo/libyahoo2/crypt.c207
-rw-r--r--miranda-wine/protocols/Yahoo/libyahoo2/libyahoo2.c6319
-rw-r--r--miranda-wine/protocols/Yahoo/libyahoo2/md5.c408
-rw-r--r--miranda-wine/protocols/Yahoo/libyahoo2/md5.h93
-rw-r--r--miranda-wine/protocols/Yahoo/libyahoo2/sha.c161
-rw-r--r--miranda-wine/protocols/Yahoo/libyahoo2/sha.h49
-rw-r--r--miranda-wine/protocols/Yahoo/libyahoo2/yahoo2.h216
-rw-r--r--miranda-wine/protocols/Yahoo/libyahoo2/yahoo2_callbacks.h790
-rw-r--r--miranda-wine/protocols/Yahoo/libyahoo2/yahoo2_types.h261
-rw-r--r--miranda-wine/protocols/Yahoo/libyahoo2/yahoo_debug.h55
-rw-r--r--miranda-wine/protocols/Yahoo/libyahoo2/yahoo_fn.c4622
-rw-r--r--miranda-wine/protocols/Yahoo/libyahoo2/yahoo_fn.h33
-rw-r--r--miranda-wine/protocols/Yahoo/libyahoo2/yahoo_httplib.c451
-rw-r--r--miranda-wine/protocols/Yahoo/libyahoo2/yahoo_httplib.h48
-rw-r--r--miranda-wine/protocols/Yahoo/libyahoo2/yahoo_list.c236
-rw-r--r--miranda-wine/protocols/Yahoo/libyahoo2/yahoo_list.h74
-rw-r--r--miranda-wine/protocols/Yahoo/libyahoo2/yahoo_util.c161
-rw-r--r--miranda-wine/protocols/Yahoo/libyahoo2/yahoo_util.h104
-rw-r--r--miranda-wine/protocols/Yahoo/main.c302
-rw-r--r--miranda-wine/protocols/Yahoo/options.c256
-rw-r--r--miranda-wine/protocols/Yahoo/options.h20
-rw-r--r--miranda-wine/protocols/Yahoo/pthread.c75
-rw-r--r--miranda-wine/protocols/Yahoo/pthread.h26
-rw-r--r--miranda-wine/protocols/Yahoo/resource.h70
-rw-r--r--miranda-wine/protocols/Yahoo/search.c121
-rw-r--r--miranda-wine/protocols/Yahoo/search.h19
-rw-r--r--miranda-wine/protocols/Yahoo/server.c221
-rw-r--r--miranda-wine/protocols/Yahoo/services.c1134
-rw-r--r--miranda-wine/protocols/Yahoo/util.c386
-rw-r--r--miranda-wine/protocols/Yahoo/version.h3
-rw-r--r--miranda-wine/protocols/Yahoo/version.rc36
-rw-r--r--miranda-wine/protocols/Yahoo/webcam.c64
-rw-r--r--miranda-wine/protocols/Yahoo/webcam.h31
-rw-r--r--miranda-wine/protocols/Yahoo/yahoo.c1463
-rw-r--r--miranda-wine/protocols/Yahoo/yahoo.h208
311 files changed, 95513 insertions, 0 deletions
diff --git a/miranda-wine/protocols/IcqOscarJ/UI/askauthentication.c b/miranda-wine/protocols/IcqOscarJ/UI/askauthentication.c
new file mode 100644
index 0000000..179d058
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/UI/askauthentication.c
@@ -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,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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/UI/askauthentication.c,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+static BOOL CALLBACK AskAuthProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+
+int icq_RequestAuthorization(WPARAM wParam, LPARAM lParam)
+{
+ DialogBoxUtf(TRUE, hInst, MAKEINTRESOURCEA(IDD_ASKAUTH), NULL, AskAuthProc, (LPARAM)wParam);
+
+ return 0;
+}
+
+
+
+static BOOL CALLBACK AskAuthProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hContact;
+
+ switch (msg)
+ {
+
+ case WM_INITDIALOG:
+ {
+ char str[MAX_PATH];
+
+ hContact = (HANDLE)lParam;
+
+ if (!hContact || !icqOnline)
+ EndDialog(hwndDlg, 0);
+
+ ICQTranslateDialog(hwndDlg);
+ SetWindowLong(hwndDlg, GWL_USERDATA, lParam);
+ SendDlgItemMessage(hwndDlg, IDC_EDITAUTH, EM_LIMITTEXT, (WPARAM)255, 0);
+ SetDlgItemTextUtf(hwndDlg, IDC_EDITAUTH, ICQTranslateUtfStatic("Please authorize me to add you to my contact list.", str));
+
+ return TRUE;
+ }
+
+ case WM_COMMAND:
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ {
+ DWORD dwUin;
+ uid_str szUid;
+ char* szReason;
+
+ hContact = (HANDLE)GetWindowLong(hwndDlg, GWL_USERDATA);
+
+ if (!icqOnline)
+ return TRUE;
+
+ if (ICQGetContactSettingUID(hContact, &dwUin, &szUid))
+ return TRUE; // Invalid contact
+
+ szReason = GetDlgItemTextUtf(hwndDlg, IDC_EDITAUTH);
+ icq_sendAuthReqServ(dwUin, szUid, szReason);
+ SAFE_FREE(&szReason);
+ EndDialog(hwndDlg, 0);
+
+ return TRUE;
+ }
+ break;
+
+ case IDCANCEL:
+ EndDialog(hwndDlg, 0);
+ return TRUE;
+
+ default:
+ break;
+
+ }
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hwndDlg,0);
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/UI/askauthentication.h b/miranda-wine/protocols/IcqOscarJ/UI/askauthentication.h
new file mode 100644
index 0000000..114daf5
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/UI/askauthentication.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,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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/UI/askauthentication.h,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+
+
+int icq_RequestAuthorization(WPARAM wParam, LPARAM lParam);
+
diff --git a/miranda-wine/protocols/IcqOscarJ/UI/loginpassword.c b/miranda-wine/protocols/IcqOscarJ/UI/loginpassword.c
new file mode 100644
index 0000000..7fd01d5
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/UI/loginpassword.c
@@ -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,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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/UI/loginpassword.c,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+BOOL CALLBACK LoginPasswdDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+
+void RequestPassword()
+{
+ DialogBox(hInst, MAKEINTRESOURCE(IDD_LOGINPW), NULL, LoginPasswdDlgProc);
+}
+
+
+BOOL CALLBACK LoginPasswdDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ char pszUIN[MAX_PATH];
+ char str[MAX_PATH];
+ DWORD dwUin;
+
+ ICQTranslateDialog(hwndDlg);
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICQ)));
+ dwUin = ICQGetContactSettingUIN(NULL);
+ null_snprintf(pszUIN, 128, ICQTranslateUtfStatic("Enter a password for UIN %u:", str), dwUin);
+ SetDlgItemTextUtf(hwndDlg, IDC_INSTRUCTION, pszUIN);
+
+ SendDlgItemMessage(hwndDlg, IDC_LOGINPW, EM_LIMITTEXT, 10, 0);
+
+ CheckDlgButton(hwndDlg, IDC_SAVEPASS, ICQGetContactSettingByte(NULL, "RememberPass", 0));
+ }
+ break;
+
+ case WM_CLOSE:
+
+ EndDialog(hwndDlg, 0);
+ break;
+
+ case WM_COMMAND:
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ {
+ gbRememberPwd = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_SAVEPASS);
+ ICQWriteContactSettingByte(NULL, "RememberPass", gbRememberPwd);
+
+ GetDlgItemTextA(hwndDlg, IDC_LOGINPW, gpszPassword, sizeof(gpszPassword));
+
+ icq_login(gpszPassword);
+
+ EndDialog(hwndDlg, IDOK);
+ }
+ break;
+
+ case IDCANCEL:
+ {
+ SetCurrentStatus(ID_STATUS_OFFLINE);
+
+ EndDialog(hwndDlg, IDCANCEL);
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ return FALSE;
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/UI/loginpassword.h b/miranda-wine/protocols/IcqOscarJ/UI/loginpassword.h
new file mode 100644
index 0000000..2da899a
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/UI/loginpassword.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,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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/UI/loginpassword.h,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+
+
+void RequestPassword(void);
diff --git a/miranda-wine/protocols/IcqOscarJ/UI/m_flash.h b/miranda-wine/protocols/IcqOscarJ/UI/m_flash.h
new file mode 100644
index 0000000..299bf3f
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/UI/m_flash.h
@@ -0,0 +1,71 @@
+/*
+Miranda FlashAvatars Plugin
+Plugin support header file
+Copyright (C) 2006 Big Muscle
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+// Service functions
+
+/**
+ WPARAM FLASHAVATAR* (hContact, hParentWindow)
+ LPARAM not used
+ */
+#define MS_FAVATAR_DESTROY "FlashAvatar/Destroy"
+
+/**
+ WPARAM FLASHAVATAR* (hContact, hParentWindow)
+ LPARAM not used
+ */
+#define MS_FAVATAR_MAKE "FlashAvatar/Make"
+
+/**
+ WPARAM FLASHAVATAR* (hContact, hParentWindow)
+ LPARAM LPRECT
+ */
+#define MS_FAVATAR_RESIZE "FlashAvatar/Resize"
+
+/**
+ WPARAM FLASHAVATAR* (hContact, hParentWindow)
+ LPARAM not used
+ */
+#define MS_FAVATAR_GETINFO "FlashAvatar/GetInfo"
+
+/**
+ WPARAM FLASHAVATAR* (hContact, hParentWindow)
+ LPARAM BSTR
+ */
+#define MS_FAVATAR_SETEMOFACE "FlashAvatar/SetEmoFace"
+
+// Avatar emotion faces
+#define AV_SMILE "smile"
+#define AV_SAD "sad"
+#define AV_LAUGH "laugh"
+#define AV_MAD "mad"
+#define AV_CRY "cry"
+#define AV_OFFLINE "offline"
+#define AV_BUSY "busy"
+#define AV_LOVE "love"
+#define AV_NORMAL "stam"
+
+typedef struct {
+ HANDLE hContact; // contact who flash avatar belongs to
+ HWND hWindow; // handle of flash avatar object
+ HWND hParentWindow; // handle of flash avatar's parent object
+ char* cUrl; // url of .swf file
+ int id; // unique number of plugin which wants to use avatar service
+ char* cProto; // contact's protocol
+} FLASHAVATAR;
diff --git a/miranda-wine/protocols/IcqOscarJ/UI/userinfotab.c b/miranda-wine/protocols/IcqOscarJ/UI/userinfotab.c
new file mode 100644
index 0000000..f7ccac9
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/UI/userinfotab.c
@@ -0,0 +1,656 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/UI/userinfotab.c,v $
+// Revision : $Revision: 3250 $
+// Last change on : $Date: 2006-06-30 02:08:42 +0400 (Птн, 30 Июн 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Code for User details ICQ specific pages
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+#include "m_flash.h"
+
+// icqj magic id
+#define FA_MAGIC_ID 0x4943516A
+
+
+extern WORD wListenPort;
+
+extern char* calcMD5Hash(char* szFile);
+extern char* MirandaVersionToString(char* szStr, int v, int m);
+
+extern char* nameXStatus[29];
+
+static BOOL CALLBACK IcqDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+static BOOL CALLBACK AvatarDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+static void SetValue(HWND hwndDlg, int idCtrl, HANDLE hContact, char *szModule, char *szSetting, int special);
+
+#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
+
+
+int OnDetailsInit(WPARAM wParam, LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = {0};
+
+ if ((!IsICQContact((HANDLE)lParam)) && lParam)
+ return 0;
+
+ odp.cbSize = sizeof(odp);
+ odp.hIcon = NULL;
+ odp.hInstance = hInst;
+ odp.pfnDlgProc = IcqDlgProc;
+ odp.position = -1900000000;
+ odp.pszTemplate = MAKEINTRESOURCE(IDD_INFO_ICQ);
+ AddUserInfoPageUtf(&odp, wParam, gpszICQProtoName);
+
+ if (((lParam != 0) && gbAvatarsEnabled) || (gbSsiEnabled && gbAvatarsEnabled))
+ {
+ DWORD dwUin;
+ uid_str dwUid;
+
+ if (!ICQGetContactSettingUID((HANDLE)lParam, &dwUin, &dwUid))
+ { // Avatar page only for valid contacts
+ char *szAvtTitle;
+
+ odp.pfnDlgProc = AvatarDlgProc;
+ odp.position = -1899999998;
+ odp.pszTemplate = MAKEINTRESOURCE(IDD_INFO_AVATAR);
+ if (lParam)
+ szAvtTitle = "Avatar";
+ else
+ szAvtTitle = "%s Avatar";
+
+ AddUserInfoPageUtf(&odp, wParam, szAvtTitle);
+ }
+ }
+
+ InitChangeDetails(wParam, lParam);
+
+ return 0;
+}
+
+
+
+static BOOL CALLBACK IcqDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+
+ case WM_INITDIALOG:
+ ICQTranslateDialog(hwndDlg);
+ return TRUE;
+
+ case WM_NOTIFY:
+ {
+ switch (((LPNMHDR)lParam)->idFrom)
+ {
+
+ case 0:
+ {
+ switch (((LPNMHDR)lParam)->code)
+ {
+
+ case PSN_INFOCHANGED:
+ {
+ char* szProto;
+ HANDLE hContact = (HANDLE)((LPPSHNOTIFY)lParam)->lParam;
+
+ if (hContact == NULL)
+ szProto = gpszICQProtoName;
+ else
+ szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+
+ if (szProto == NULL)
+ break;
+
+ SetValue(hwndDlg, IDC_UIN, hContact, szProto, UNIQUEIDSETTING, SVS_NORMAL);
+ SetValue(hwndDlg, IDC_ONLINESINCE, hContact, szProto, "LogonTS", SVS_TIMESTAMP);
+ SetValue(hwndDlg, IDC_IDLETIME, hContact, szProto, "IdleTS", SVS_TIMESTAMP);
+ SetValue(hwndDlg, IDC_IP, hContact, szProto, "IP", SVS_IP);
+ SetValue(hwndDlg, IDC_REALIP, hContact, szProto, "RealIP", SVS_IP);
+
+ if (hContact)
+ {
+ SetValue(hwndDlg, IDC_PORT, hContact, szProto, "UserPort", SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg, IDC_VERSION, hContact, szProto, "Version", SVS_ICQVERSION);
+ SetValue(hwndDlg, IDC_MIRVER, hContact, szProto, "MirVer", SVS_ZEROISUNSPEC);
+ if (ICQGetContactSettingByte(hContact, "ClientID", 0))
+ ICQWriteContactSettingDword(hContact, "TickTS", 0);
+ SetValue(hwndDlg, IDC_SYSTEMUPTIME, hContact, szProto, "TickTS", SVS_TIMESTAMP);
+ SetValue(hwndDlg, IDC_STATUS, hContact, szProto, "Status", SVS_STATUSID);
+ }
+ else
+ {
+ char str[MAX_PATH];
+
+ SetValue(hwndDlg, IDC_PORT, hContact, (char*)DBVT_WORD, (char*)wListenPort, SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg, IDC_VERSION, hContact, (char*)DBVT_WORD, (char*)ICQ_VERSION, SVS_ICQVERSION);
+ SetValue(hwndDlg, IDC_MIRVER, hContact, (char*)DBVT_ASCIIZ, MirandaVersionToString(str, ICQ_PLUG_VERSION, MIRANDA_VERSION), SVS_ZEROISUNSPEC);
+ SetDlgItemTextUtf(hwndDlg, IDC_SUPTIME, ICQTranslateUtfStatic("Member since:", str));
+ SetValue(hwndDlg, IDC_SYSTEMUPTIME, hContact, szProto, "MemberTS", SVS_TIMESTAMP);
+ SetValue(hwndDlg, IDC_STATUS, hContact, (char*)DBVT_WORD, (char*)gnCurrentStatus, SVS_STATUSID);
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ break;
+
+ case WM_COMMAND:
+ switch(LOWORD(wParam))
+ {
+ case IDCANCEL:
+ SendMessage(GetParent(hwndDlg),msg,wParam,lParam);
+ break;
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+typedef struct AvtDlgProcData_t
+{
+ HANDLE hContact;
+ HANDLE hEventHook;
+ HWND hFlashAvatar;
+ HBITMAP hImageAvatar;
+} AvtDlgProcData;
+
+#define HM_REBIND_AVATAR (WM_USER + 1024)
+
+static char* ChooseAvatarFileName()
+{
+ char* szDest = (char*)SAFE_MALLOC(MAX_PATH+0x10);
+ char str[MAX_PATH];
+ char szFilter[512];
+ OPENFILENAME ofn = {0};
+
+ str[0] = 0;
+ CallService(MS_UTILS_GETBITMAPFILTERSTRINGS,sizeof(szFilter),(LPARAM)szFilter);
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.lpstrFilter = szFilter;
+ ofn.lpstrFile = szDest;
+ ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
+ ofn.nMaxFile = MAX_PATH;
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.lpstrDefExt = "jpg";
+ if (!GetOpenFileName(&ofn))
+ {
+ SAFE_FREE(&szDest);
+ return NULL;
+ }
+
+ return szDest;
+}
+
+
+
+static void PrepareFlashAvatar(HWND hwndDlg, AvtDlgProcData* pData)
+{
+ FLASHAVATAR fa = {0};
+
+ fa.hContact = pData->hContact;
+ fa.cProto = gpszICQProtoName;
+ fa.id = FA_MAGIC_ID;
+ CallService(MS_FAVATAR_GETINFO, (WPARAM)&fa, 0);
+ if (fa.hWindow)
+ {
+ pData->hFlashAvatar = fa.hWindow;
+ SetParent(fa.hWindow, GetDlgItem(hwndDlg, IDC_AVATAR));
+ }
+ else
+ {
+ fa.hParentWindow = GetDlgItem(hwndDlg, IDC_AVATAR);
+ CallService(MS_FAVATAR_MAKE, (WPARAM)&fa, 0);
+ if (fa.hWindow)
+ pData->hFlashAvatar = fa.hWindow;
+ }
+}
+
+
+
+static void ReleaseFlashAvatar(AvtDlgProcData* pData)
+{
+ if (pData->hFlashAvatar)
+ { // release expired flash avatar object
+ FLASHAVATAR fa;
+
+ fa.hContact = pData->hContact;
+ fa.cProto = gpszICQProtoName;
+ fa.id = FA_MAGIC_ID; // icqj magic id
+ CallService(MS_FAVATAR_DESTROY, (WPARAM)&fa, 0);
+ pData->hFlashAvatar = NULL;
+ }
+}
+
+
+
+static void PrepareImageAvatar(HWND hwndDlg, AvtDlgProcData* pData, char* szFile)
+{
+ pData->hImageAvatar = (HBITMAP)CallService(MS_UTILS_LOADBITMAP, 0, (WPARAM)szFile);
+
+ SendDlgItemMessage(hwndDlg, IDC_AVATAR, STM_SETIMAGE, IMAGE_BITMAP, (WPARAM)pData->hImageAvatar);
+}
+
+
+
+static void ReleaseImageAvatar(HWND hwndDlg, AvtDlgProcData* pData)
+{
+ if (pData->hImageAvatar)
+ {
+ HBITMAP avt = (HBITMAP)SendDlgItemMessage(hwndDlg, IDC_AVATAR, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)NULL);
+
+ // force re-draw avatar window
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_AVATAR), NULL, FALSE);
+
+ // in XP you can get different image, and it is leaked if not Destroy()ed
+ if (avt != pData->hImageAvatar)
+ DeleteObject(avt);
+
+ DeleteObject(pData->hImageAvatar);
+ pData->hImageAvatar = NULL;
+ }
+}
+
+
+
+static BOOL CALLBACK AvatarDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ ICQTranslateDialog(hwndDlg);
+ {
+ DBVARIANT dbvHash;
+ AvtDlgProcData* pData = (AvtDlgProcData*)SAFE_MALLOC(sizeof(AvtDlgProcData));
+ DWORD dwUIN;
+ uid_str szUID;
+ char szAvatar[MAX_PATH];
+ DWORD dwPaFormat;
+ int bValid = 0;
+
+ pData->hContact = (HANDLE)lParam;
+
+ if (pData->hContact)
+ pData->hEventHook = HookEventMessage(ME_PROTO_ACK, hwndDlg, HM_REBIND_AVATAR);
+ else
+ {
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SETAVATAR), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_DELETEAVATAR), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, -1), SW_SHOW);
+ if (!icqOnline)
+ {
+ EnableDlgItem(hwndDlg, IDC_SETAVATAR, FALSE);
+ EnableDlgItem(hwndDlg, IDC_DELETEAVATAR, FALSE);
+ }
+ }
+ SetWindowLong(hwndDlg, GWL_USERDATA, (LONG)pData);
+
+ if (!ICQGetContactSettingUID((HANDLE)lParam, &dwUIN, &szUID))
+ {
+ if (!ICQGetContactSetting((HANDLE)lParam, "AvatarHash", &dbvHash))
+ {
+ dwPaFormat = ICQGetContactSettingByte((HANDLE)lParam, "AvatarType", PA_FORMAT_UNKNOWN);
+ if (!pData->hContact || (dwPaFormat != PA_FORMAT_UNKNOWN))
+ { // we do not know avatar format, so neither filename is known, not valid
+ if (pData->hContact)
+ GetFullAvatarFileName(dwUIN, szUID, dwPaFormat, szAvatar, 255);
+ else
+ { // owner's avatar
+ char* file = loadMyAvatarFileName();
+
+ if (file)
+ {
+ strcpy(szAvatar, file);
+ SAFE_FREE(&file);
+ if (dbvHash.pbVal[1] == 8) // we do this by hand, as owner's format is not saved
+ dwPaFormat = PA_FORMAT_XML;
+ }
+ else
+ szAvatar[0] = '\0';
+ }
+
+ if (!pData->hContact || !IsAvatarSaved((HANDLE)lParam, dbvHash.pbVal))
+ { // if the file exists, we know we have the current avatar
+ if (!access(szAvatar, 0)) bValid = 1;
+ }
+ }
+ }
+ else
+ return TRUE;
+
+ if (bValid)
+ { //load avatar
+ if ((dwPaFormat == PA_FORMAT_XML || dwPaFormat == PA_FORMAT_SWF) && ServiceExists(MS_FAVATAR_GETINFO))
+ { // flash avatar and we have FlashAvatars installed, init flash avatar
+ PrepareFlashAvatar(hwndDlg, pData);
+ }
+ else
+ { // static avatar processing
+ PrepareImageAvatar(hwndDlg, pData, szAvatar);
+ }
+ }
+ else if (pData->hContact) // only retrieve users avatars
+ {
+ GetAvatarFileName(dwUIN, szUID, szAvatar, 255);
+ GetAvatarData((HANDLE)lParam, dwUIN, szUID, dbvHash.pbVal, 0x14, szAvatar);
+ }
+ }
+
+ ICQFreeVariant(&dbvHash);
+ }
+ return TRUE;
+
+ case HM_REBIND_AVATAR:
+ {
+ AvtDlgProcData* pData = (AvtDlgProcData*)GetWindowLong(hwndDlg, GWL_USERDATA);
+ ACKDATA* ack = (ACKDATA*)lParam;
+
+ if (!pData->hContact) break; // we do not use this for us
+
+ if (ack->type == ACKTYPE_AVATAR && ack->hContact == pData->hContact)
+ {
+ if (ack->result == ACKRESULT_SUCCESS)
+ { // load avatar
+ PROTO_AVATAR_INFORMATION* AI = (PROTO_AVATAR_INFORMATION*)ack->hProcess;
+
+ ReleaseFlashAvatar(pData);
+ ReleaseImageAvatar(hwndDlg, pData);
+
+ if ((AI->format == PA_FORMAT_XML || AI->format == PA_FORMAT_SWF) && ServiceExists(MS_FAVATAR_GETINFO))
+ { // flash avatar and we have FlashAvatars installed, init flash avatar
+ PrepareFlashAvatar(hwndDlg, pData);
+ }
+ else
+ { // process image avatar
+ PrepareImageAvatar(hwndDlg, pData, AI->filename);
+ }
+ }
+ else if (ack->result == ACKRESULT_STATUS)
+ { // contact has changed avatar
+ DWORD dwUIN;
+ uid_str szUID;
+ DBVARIANT dbvHash;
+
+ if (!ICQGetContactSettingUID(pData->hContact, &dwUIN, &szUID))
+ {
+ if (!ICQGetContactSetting(pData->hContact, "AvatarHash", &dbvHash))
+ {
+ char szAvatar[MAX_PATH];
+
+ GetAvatarFileName(dwUIN, szUID, szAvatar, 255);
+ GetAvatarData(pData->hContact, dwUIN, szUID, dbvHash.pbVal, 0x14, szAvatar);
+ }
+ ICQFreeVariant(&dbvHash);
+ }
+ }
+ }
+ }
+ break;
+
+ case WM_COMMAND:
+ switch(LOWORD(wParam))
+ {
+ case IDC_SETAVATAR:
+ {
+ char* szFile;
+ AvtDlgProcData* pData = (AvtDlgProcData*)GetWindowLong(hwndDlg, GWL_USERDATA);
+
+ if (szFile = ChooseAvatarFileName())
+ { // user selected file for his avatar
+ DWORD dwPaFormat = DetectAvatarFormat(szFile);
+
+ if (dwPaFormat == PA_FORMAT_XML || dwPaFormat == PA_FORMAT_JPEG || dwPaFormat == PA_FORMAT_GIF || dwPaFormat == PA_FORMAT_BMP)
+ { // a valid file
+ if (!IcqSetMyAvatar(0, (LPARAM)szFile)) // set avatar
+ {
+ ReleaseFlashAvatar(pData);
+ ReleaseImageAvatar(hwndDlg, pData);
+
+ if (dwPaFormat != PA_FORMAT_XML || !ServiceExists(MS_FAVATAR_GETINFO))
+ { // it is not flash
+ PrepareImageAvatar(hwndDlg, pData, szFile);
+ }
+ else
+ { // is is flash load it
+ PrepareFlashAvatar(hwndDlg, pData);
+ }
+ }
+ }
+ SAFE_FREE(&szFile);
+ }
+ }
+ break;
+ case IDC_DELETEAVATAR:
+ {
+ AvtDlgProcData* pData = (AvtDlgProcData*)GetWindowLong(hwndDlg, GWL_USERDATA);
+
+ ReleaseFlashAvatar(pData);
+ ReleaseImageAvatar(hwndDlg, pData);
+
+ IcqSetMyAvatar(0, 0); // clear hash on server
+ }
+ break;
+ }
+ break;
+
+ case WM_DESTROY:
+ {
+ AvtDlgProcData* pData = (AvtDlgProcData*)GetWindowLong(hwndDlg, GWL_USERDATA);
+ if (pData->hContact)
+ UnhookEvent(pData->hEventHook);
+
+ ReleaseFlashAvatar(pData);
+ ReleaseImageAvatar(hwndDlg, pData);
+ SetWindowLong(hwndDlg, GWL_USERDATA, (LONG)0);
+ SAFE_FREE(&pData);
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+
+
+static void SetValue(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 && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD))
+ {
+ ICQTranslateUtfStatic(" (DC Established)", szExtra);
+ strcat(str, szExtra);
+ bUtf = 1;
+ }
+ }
+ else
+ unspecified = 1;
+ }
+ else if (special == SVS_STATUSID)
+ {
+ char* pXName;
+ char* pszStatus;
+ BYTE bXStatus = ICQGetContactSettingByte(hContact, DBSETTING_XSTATUSID, 0);
+
+ pszStatus = MirandaStatusToStringUtf(dbv.wVal);
+ if (bXStatus)
+ {
+ pXName = ICQGetContactSettingUtf(hContact, DBSETTING_XSTATUSNAME, "");
+ if (!strlennull(pXName))
+ { // give default name
+ pXName = ICQTranslateUtf(nameXStatus[bXStatus-1]);
+ }
+ null_snprintf(str, sizeof(str), "%s (%s)", pszStatus, pXName);
+ SAFE_FREE(&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 = asctime(localtime(&dbv.dVal));
+ pstr[24] = '\0'; // Remove newline
+ }
+ }
+ else
+ pstr = itoa(special == SVS_SIGNED ? dbv.lVal:dbv.dVal, str, 10);
+ break;
+
+ case DBVT_ASCIIZ:
+ unspecified = (special == SVS_ZEROISUNSPEC && dbv.pszVal[0] == '\0');
+ if (!unspecified && pstr != szSetting)
+ {
+ pstr = UniGetContactSettingUtf(hContact, szModule, szSetting, NULL);
+ bUtf = 1;
+ bAlloc = 1;
+ }
+ if (idCtrl == IDC_UIN)
+ SetDlgItemTextUtf(hwndDlg, IDC_UINSTATIC, ICQTranslateUtfStatic("ScreenName:", str));
+ break;
+
+ default:
+ pstr = str;
+ lstrcpy(str,"???");
+ break;
+ }
+ }
+
+ EnableDlgItem(hwndDlg, idCtrl, !unspecified);
+ if (unspecified)
+ SetDlgItemTextUtf(hwndDlg, idCtrl, ICQTranslateUtfStatic("<not specified>", str));
+ else if (bUtf)
+ SetDlgItemTextUtf(hwndDlg, idCtrl, pstr);
+ else
+ SetDlgItemText(hwndDlg, idCtrl, pstr);
+
+ if (bDbv)
+ ICQFreeVariant(&dbv);
+
+ if (bAlloc)
+ SAFE_FREE(&pstr);
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/UI/userinfotab.h b/miranda-wine/protocols/IcqOscarJ/UI/userinfotab.h
new file mode 100644
index 0000000..28d110f
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/UI/userinfotab.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,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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/UI/userinfotab.h,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+
+
+int OnDetailsInit(WPARAM wParam, LPARAM lParam);
diff --git a/miranda-wine/protocols/IcqOscarJ/capabilities.c b/miranda-wine/protocols/IcqOscarJ/capabilities.c
new file mode 100644
index 0000000..3b81663
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/capabilities.c
@@ -0,0 +1,162 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/capabilities.c,v $
+// Revision : $Revision: 3663 $
+// Last change on : $Date: 2006-08-31 00:18:59 +0400 (Чтв, 31 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// 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"
+
+
+typedef struct icq_capability_s
+{
+ DWORD fdwMirandaID; // A bitmask, we use it in order to save database space
+ BYTE CapCLSID[BINARY_CAP_SIZE]; // A binary representation of a oscar capability
+} icq_capability;
+
+static icq_capability CapabilityRecord[] =
+{
+ {CAPF_SRV_RELAY, {CAP_SRV_RELAY}},
+ {CAPF_UTF, {CAP_UTF }},
+ {CAPF_RTF, {CAP_RTF }},
+ {CAPF_TYPING, {CAP_TYPING }},
+ {CAPF_XTRAZ, {CAP_XTRAZ }},
+ {CAPF_AIM_FILE, {CAP_AIM_FILE }}
+};
+
+
+
+// Deletes all oscar capabilities for a given contact
+void ClearAllContactCapabilities(HANDLE hContact)
+{
+ ICQWriteContactSettingDword(hContact, DBSETTING_CAPABILITIES, 0);
+}
+
+
+
+// Deletes one or many oscar capabilities for a given contact
+void ClearContactCapabilities(HANDLE hContact, DWORD fdwCapabilities)
+{
+ DWORD fdwContactCaps;
+
+
+ // Get current capability flags
+ fdwContactCaps = ICQGetContactSettingDword(hContact, DBSETTING_CAPABILITIES, 0);
+
+ // Clear unwanted capabilities
+ fdwContactCaps &= ~fdwCapabilities;
+
+ // And write it back to disk
+ ICQWriteContactSettingDword(hContact, DBSETTING_CAPABILITIES, fdwContactCaps);
+}
+
+
+
+// Sets one or many oscar capabilities for a given contact
+void SetContactCapabilities(HANDLE hContact, DWORD fdwCapabilities)
+{
+ DWORD fdwContactCaps;
+
+
+ // Get current capability flags
+ fdwContactCaps = ICQGetContactSettingDword(hContact, DBSETTING_CAPABILITIES, 0);
+
+ // Update them
+ fdwContactCaps |= fdwCapabilities;
+
+ // And write it back to disk
+ ICQWriteContactSettingDword(hContact, DBSETTING_CAPABILITIES, fdwContactCaps);
+}
+
+
+
+// Returns true if the given contact supports the requested capabilites
+BOOL CheckContactCapabilities(HANDLE hContact, DWORD fdwCapabilities)
+{
+ DWORD fdwContactCaps;
+
+
+ // Get current capability flags
+ fdwContactCaps = ICQGetContactSettingDword(hContact, DBSETTING_CAPABILITIES, 0);
+
+ // Check if all requested capabilities are supported
+ if ((fdwContactCaps & fdwCapabilities) == fdwCapabilities)
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+
+
+// Scans a binary buffer for oscar capabilities and adds them to the contact.
+// You probably want to call ClearAllContactCapabilities() first.
+void AddCapabilitiesFromBuffer(HANDLE hContact, BYTE* pbyBuffer, int nLength)
+{
+ DWORD fdwContactCaps;
+ int iCapability;
+ int nIndex;
+ int nRecordSize;
+
+
+ // Calculate the number of records
+ nRecordSize = sizeof(CapabilityRecord)/sizeof(icq_capability);
+
+ // Get current capability flags
+ fdwContactCaps = ICQGetContactSettingDword(hContact, DBSETTING_CAPABILITIES, 0);
+
+ // Loop over all capabilities in the buffer and
+ // compare them to our own record of capabilities
+ for (iCapability = 0; (iCapability + BINARY_CAP_SIZE) <= nLength; iCapability += BINARY_CAP_SIZE)
+ {
+ for (nIndex = 0; nIndex < nRecordSize; nIndex++)
+ {
+ if (!memcmp(pbyBuffer + iCapability, CapabilityRecord[nIndex].CapCLSID, BINARY_CAP_SIZE))
+ {
+ // Match
+ fdwContactCaps |= CapabilityRecord[nIndex].fdwMirandaID;
+ break;
+ }
+ }
+ }
+
+ // And write it back to disk
+ ICQWriteContactSettingDword(hContact, DBSETTING_CAPABILITIES, fdwContactCaps);
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/capabilities.h b/miranda-wine/protocols/IcqOscarJ/capabilities.h
new file mode 100644
index 0000000..a09d2d1
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/capabilities.h
@@ -0,0 +1,51 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/capabilities.h,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Contains helper functions to handle oscar user capabilities.
+//
+// -----------------------------------------------------------------------------
+
+
+
+// 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 db.
+void AddCapabilitiesFromBuffer(HANDLE hContact, BYTE* pbyBuffer, int nLength);
diff --git a/miranda-wine/protocols/IcqOscarJ/chan_01login.c b/miranda-wine/protocols/IcqOscarJ/chan_01login.c
new file mode 100644
index 0000000..ea9a97a
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/chan_01login.c
@@ -0,0 +1,115 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/chan_01login.c,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+
+extern WORD wLocalSequence;
+
+
+void handleLoginChannel(unsigned char *buf, WORD datalen, serverthread_info *info)
+{
+ icq_packet packet;
+
+ // isLoginServer is "1" if we just received SRV_HELLO
+ if (info->isLoginServer)
+ {
+#ifdef _DEBUG
+ NetLog_Server("Received SRV_HELLO from login server");
+#endif
+ if (gbSecureLogin)
+ {
+ char szUin[UINMAXLEN];
+ WORD wUinLen;
+
+#ifdef _DEBUG
+ NetLog_Server("Sending %s to login server", "CLI_HELLO");
+#endif
+ packet.wLen = 4;
+ write_flap(&packet, ICQ_LOGIN_CHAN);
+ packDWord(&packet, 0x00000001);
+ sendServPacket(&packet); // greet login server
+
+ wUinLen = strlennull(strUID(dwLocalUIN, szUin));
+#ifdef _DEBUG
+ NetLog_Server("Sending %s to login server", "ICQ_SIGNON_AUTH_REQUEST");
+#endif
+
+ serverPacketInit(&packet, (WORD)(18 + wUinLen));
+ packFNACHeaderFull(&packet, ICQ_AUTHORIZATION_FAMILY, ICQ_SIGNON_AUTH_REQUEST, 0, 0);
+ packTLV(&packet, 0x0001, wUinLen, szUin);
+ packDWord(&packet, 0x004B0000);
+ sendServPacket(&packet); // request login digest
+ }
+ else
+ {
+ sendClientAuth(info->szAuthKey, info->wAuthKeyLen, FALSE);
+#ifdef _DEBUG
+ NetLog_Server("Sent CLI_IDENT to %s server", "login");
+#endif
+ }
+
+ info->isLoginServer = 0;
+ if (info->cookieDataLen)
+ {
+ SAFE_FREE(&info->cookieData);
+ info->cookieDataLen = 0;
+ }
+ }
+ else
+ {
+ if (info->cookieDataLen)
+ {
+ wLocalSequence = (WORD)RandRange(0, 0xffff);
+
+ serverCookieInit(&packet, info->cookieData, (WORD)info->cookieDataLen);
+ sendServPacket(&packet);
+
+#ifdef _DEBUG
+ NetLog_Server("Sent CLI_IDENT to %s server", "communication");
+#endif
+
+ SAFE_FREE(&info->cookieData);
+ info->cookieDataLen = 0;
+ }
+ else
+ {
+ // We need a cookie to identify us to the communication server
+ NetLog_Server("Something went wrong...");
+ }
+ }
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/chan_02data.c b/miranda-wine/protocols/IcqOscarJ/chan_02data.c
new file mode 100644
index 0000000..ee10bff
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/chan_02data.c
@@ -0,0 +1,216 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/chan_02data.c,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Handle channel 2 (Data) packets
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+void handleDataChannel(unsigned char *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
+ 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);
+ 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, unsigned char **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 -= 6;
+ pSnacHeader->bValid = TRUE;
+ }
+ else
+ {
+ *pwBufferLength -= wExtraBytes;
+ *pBuffer += wExtraBytes;
+ pSnacHeader->bValid = TRUE;
+ }
+ }
+ else
+ {
+ // Buffer overflow
+ pSnacHeader->bValid = FALSE;
+ }
+ }
+ else
+ {
+ // Buffer overflow
+ pSnacHeader->bValid = FALSE;
+ }
+ }
+ else
+ {
+ pSnacHeader->bValid = TRUE;
+ }
+
+ return 1;
+}
+
+
+
+void 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 too evil"; break;
+ case 0x12: msg = "Receiver 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;
+ default: msg = ""; break;
+ }
+
+ NetLog_Server("SNAC(x%02X,x01) - Error(%u): %s", wFamily, wError, msg);
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/chan_03error.c b/miranda-wine/protocols/IcqOscarJ/chan_03error.c
new file mode 100644
index 0000000..4e715ab
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/chan_03error.c
@@ -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,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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/chan_03error.c,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+void handleErrorChannel(unsigned char* buf, WORD datalen)
+{
+ NetLog_Server("Ignoring server packet on ERROR channel");
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/chan_04close.c b/miranda-wine/protocols/IcqOscarJ/chan_04close.c
new file mode 100644
index 0000000..91f8c1e
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/chan_04close.c
@@ -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,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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/chan_04close.c,v $
+// Revision : $Revision: 3545 $
+// Last change on : $Date: 2006-08-19 03:42:44 +0400 (Сбт, 19 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+extern HANDLE hServerConn;
+extern HANDLE hServerPacketRecver;
+
+static void handleMigration(serverthread_info *info);
+static int connectNewServer(serverthread_info *info);
+static void handleRuntimeError(WORD wError);
+static void handleSignonError(WORD wError);
+
+
+void handleCloseChannel(unsigned char *buf, WORD datalen, serverthread_info *info)
+{
+ oscar_tlv_chain* chain = NULL;
+ WORD wError;
+
+
+ // 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(), "Unable to connect to migrated ICQ communication server");
+ else
+ icq_LogUsingErrorCode(LOG_ERROR, GetLastError(), "Unable to connect to ICQ communication server");
+
+ info->isMigrating = 0;
+ }
+ info->newServerReady = 0;
+
+ return;
+ }
+
+ if (chain = readIntoTLVChain(&buf, datalen, 0))
+ {
+ // TLV 9 errors (runtime errors?)
+ wError = getWordFromChain(chain, 0x09, 1);
+ if (wError)
+ {
+ SetCurrentStatus(ID_STATUS_OFFLINE);
+
+ handleRuntimeError(wError);
+ }
+
+ disposeChain(&chain);
+ }
+ // Server closed connection on error, or sign off
+ NetLib_SafeCloseHandle(&hServerConn, TRUE);
+}
+
+
+
+void handleLoginReply(unsigned char *buf, WORD datalen, serverthread_info *info)
+{
+ oscar_tlv_chain* chain = NULL;
+ WORD wError;
+
+ icq_sendCloseConnection(); // imitate icq5 behaviour
+
+ if (!(chain = readIntoTLVChain(&buf, datalen, 0)))
+ {
+ NetLog_Server("Error: Missing chain on close channel");
+ NetLib_SafeCloseHandle(&hServerConn, TRUE);
+ return; // Invalid data
+ }
+
+ // TLV 8 errors (signon errors?)
+ wError = getWordFromChain(chain, 0x08, 1);
+ if (wError)
+ {
+ handleSignonError(wError);
+
+ // we return only if the server did not gave us cookie (possible to connect with soft error)
+ if (!getLenFromChain(chain, 0x06, 1))
+ {
+ disposeChain(&chain);
+ SetCurrentStatus(ID_STATUS_OFFLINE);
+ NetLib_SafeCloseHandle(&hServerConn, TRUE);
+ return; // Failure
+ }
+ }
+
+ // We are in the login phase and no errors were reported.
+ // Extract communication server info.
+ info->newServer = getStrFromChain(chain, 0x05, 1);
+ info->cookieData = getStrFromChain(chain, 0x06, 1);
+ info->cookieDataLen = getLenFromChain(chain, 0x06, 1);
+
+ // We dont need this anymore
+ disposeChain(&chain);
+
+ if (!info->newServer || !info->cookieData)
+ {
+ icq_LogMessage(LOG_FATAL, "You could not sign on because the server returned invalid data. Try again.");
+
+ SAFE_FREE(&info->newServer);
+ SAFE_FREE(&info->cookieData);
+ info->cookieDataLen = 0;
+
+ SetCurrentStatus(ID_STATUS_OFFLINE);
+ NetLib_SafeCloseHandle(&hServerConn, TRUE);
+ return; // Failure
+ }
+
+ NetLog_Server("Authenticated.");
+ info->newServerReady = 1;
+
+ return;
+}
+
+
+
+static int connectNewServer(serverthread_info *info)
+{
+ WORD servport;
+ NETLIBOPENCONNECTION nloc = {0};
+ int res = 0;
+
+ if (!gbGatewayMode)
+ { // close connection only if not in gateway mode
+ NetLib_SafeCloseHandle(&hServerConn, TRUE);
+ }
+
+ /* Get the ip and port */
+ servport = info->wServerPort; // prepare default port
+ parseServerAddress(info->newServer, &servport);
+
+ nloc.cbSize = sizeof(nloc);
+ nloc.flags = 0;
+ nloc.szHost = info->newServer;
+ nloc.wPort = servport;
+
+ if (!gbGatewayMode)
+ {
+ { /* Time to release packet receiver, connection already closed */
+ NetLib_SafeCloseHandle(&hServerPacketRecver, FALSE);
+
+ NetLog_Server("Closed connection to login server");
+ }
+
+ NetLog_Server("Connecting to %s", info->newServer);
+ hServerConn = NetLib_OpenConnection(ghServerNetlibUser, &nloc);
+ if (hServerConn)
+ { /* Time to recreate the packet receiver */
+ hServerPacketRecver = (HANDLE)CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)hServerConn, 8192);
+ if (!hServerPacketRecver)
+ {
+ 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(&info->cookieData);
+
+ // Free allocated memory
+ // NOTE: "cookie" will get freed when we have connected to the communication server.
+ SAFE_FREE(&info->newServer);
+
+ return res;
+}
+
+
+
+static void 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, "You have been disconnected from the ICQ network because the current server shut down.");
+
+ SAFE_FREE(&info->newServer);
+ SAFE_FREE(&info->cookieData);
+ info->newServerReady = 0;
+ info->isMigrating = 0;
+ }
+}
+
+
+
+static void 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
+ ICQBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD);
+ ZeroMemory(gpszPassword, sizeof(gpszPassword));
+ icq_LogFatalParam("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 0x14: // Reservation map error
+ case 0x15: // Reservation link error
+ case 0x1A: // Reservation timeout
+ icq_LogFatalParam("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("Connection failed.\nServer has too many connections from your IP (%d).", wError);
+ break;
+
+ case 0x18: // Rate limit exceeded (reserved)
+ case 0x1D: // Rate limit exceeded
+ icq_LogFatalParam("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
+ icq_LogMessage(LOG_FATAL, "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, "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, "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, "Connection failed.\nSecure (MD5) login is not supported on this account.");
+ break;
+
+ case 0:
+ 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 0x11: // Suspended account
+ case 0x19: // User too heavily warned
+ case 0x22: // Account suspended due to your age
+ case 0x2A: // Blocked account
+
+ default:
+ icq_LogFatalParam("Connection failed.\nUnknown error during sign on: 0x%02x", wError);
+ break;
+ }
+}
+
+
+
+static void handleRuntimeError(WORD wError)
+{
+ switch (wError)
+ {
+
+ case 0x01:
+ {
+ ICQBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_OTHERLOCATION);
+ icq_LogMessage(LOG_FATAL, "You have been disconnected from the ICQ network because you logged on from another location using the same ICQ number.");
+ break;
+ }
+
+ default:
+ icq_LogFatalParam("Unknown runtime error: 0x%02x", wError);
+ break;
+ }
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/chan_05ping.c b/miranda-wine/protocols/IcqOscarJ/chan_05ping.c
new file mode 100644
index 0000000..b41cafc
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/chan_05ping.c
@@ -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,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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/chan_05ping.c,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+
+extern HANDLE hServerConn;
+static HANDLE hKeepAliveEvent = NULL;
+
+
+void handlePingChannel(unsigned char* buf, WORD datalen)
+{
+ NetLog_Server("Warning: Ignoring server packet on PING channel");
+}
+
+
+
+static void __cdecl icq_keepAliveThread(void* fa)
+{
+ icq_packet packet;
+
+ NetLog_Server("Keep alive thread starting.");
+
+ hKeepAliveEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+ for(;;)
+ {
+ DWORD dwWait = WaitForSingleObjectEx(hKeepAliveEvent, 57000, TRUE);
+
+ if (dwWait == WAIT_OBJECT_0) break; // we should end
+ else if (dwWait == WAIT_TIMEOUT)
+ {
+ // Send a keep alive packet to server
+ packet.wLen = 0;
+ write_flap(&packet, ICQ_PING_CHAN);
+ if (hServerConn) // connection lost, end
+ sendServPacket(&packet);
+ else
+ break;
+ }
+ else if (dwWait == WAIT_IO_COMPLETION)
+ // Possible shutdown in progress
+ if (Miranda_Terminated()) break;
+ }
+
+ NetLog_Server("Keep alive thread shutting down.");
+
+ CloseHandle(hKeepAliveEvent);
+ hKeepAliveEvent = NULL;
+
+ return;
+}
+
+
+
+void StartKeepAlive()
+{
+ if (hKeepAliveEvent) // start only once
+ return;
+
+ if (ICQGetContactSettingByte(NULL, "KeepAlive", 0))
+ forkthread(icq_keepAliveThread, 0, NULL);
+}
+
+
+
+void StopKeepAlive()
+{ // finish keep alive thread
+ if (hKeepAliveEvent)
+ SetEvent(hKeepAliveEvent);
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/changeinfo/changeinfo.h b/miranda-wine/protocols/IcqOscarJ/changeinfo/changeinfo.h
new file mode 100644
index 0000000..d6a920d
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/changeinfo/changeinfo.h
@@ -0,0 +1,116 @@
+// ---------------------------------------------------------------------------80
+// ICQ plugin for Miranda Instant Messenger
+// ________________________________________
+//
+// Copyright © 2001,2002,2003,2004 Richard Hughes, Martin Öberg
+// Copyright © 2004,2005,2006 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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/changeinfo/changeinfo.h,v $
+// Revision : $Revision: 2991 $
+// Last change on : $Date: 2006-05-30 21:55:48 +0400 (Втр, 30 Май 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// 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
+
+char Password[10];
+HANDLE hUpload[2];
+HWND hwndList;
+HFONT hListFont;
+int iEditItem;
+
+typedef struct {
+ char *szDescription;
+ unsigned displayType; //LI_ constant
+ int dbType; //DBVT_ constant
+ char *szDbSetting;
+ void *pList;
+ int listCount;
+ LPARAM value;
+ int changed;
+} SettingItem;
+
+typedef struct {
+ int id;
+ char *szValue;
+} ListTypeDataItem;
+
+// contants.c
+extern SettingItem setting[];
+extern const int settingCount;
+
+//main.c
+int InitChangeDetails(WPARAM wParam,LPARAM lParam);
+
+//dlgproc.c
+BOOL CALLBACK ChangeInfoDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+//db.c
+void LoadSettingsFromDb(int keepChanged);
+void FreeStoredDbSettings(void);
+void ClearChangeFlags(void);
+int ChangesMade(void);
+int SaveSettingsToDb(HWND hwndDlg);
+
+//editstring.c
+void BeginStringEdit(int iItem,RECT *rc,int i,WORD wVKey);
+void EndStringEdit(int save);
+int IsStringEditWindow(HWND hwnd);
+char *BinaryToEscapes(char *str);
+
+//editlist.c
+void BeginListEdit(int iItem,RECT *rc,int i,WORD wVKey);
+void EndListEdit(int save);
+int IsListEditWindow(HWND hwnd);
+
+//upload.c
+int StringToListItemId(const char *szSetting,int def);
+int UploadSettings(HWND hwndParent);
+
+
+#endif /* __CHANGEINFO_H */
diff --git a/miranda-wine/protocols/IcqOscarJ/changeinfo/constants.c b/miranda-wine/protocols/IcqOscarJ/changeinfo/constants.c
new file mode 100644
index 0000000..1b3095b
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/changeinfo/constants.c
@@ -0,0 +1,658 @@
+// ---------------------------------------------------------------------------80
+// ICQ plugin for Miranda Instant Messenger
+// ________________________________________
+//
+// Copyright © 2001,2002,2003,2004 Richard Hughes, Martin Öberg
+// Copyright © 2004,2005,2006 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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/changeinfo/constants.c,v $
+// Revision : $Revision: 3292 $
+// Last change on : $Date: 2006-07-09 17:27:51 +0400 (Ð’Ñк, 09 Июл 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// ChangeInfo Plugin stuff
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+static ListTypeDataItem countries[]={
+ {0 ,"Unspecified"},
+ {9999,"Other"},
+ {93 ,"Afghanistan"},
+ {355 ,"Albania"},
+ {213 ,"Algeria"},
+ {684 ,"American Samoa"},
+ {376 ,"Andorra"},
+ {244 ,"Angola"},
+ {101 ,"Anguilla"},
+ {102 ,"Antigua and Barbuda"},
+ {5902,"Antilles"},
+ {54 ,"Argentina"},
+ {374 ,"Armenia"},
+ {297 ,"Aruba"},
+ {247 ,"Ascension Island"},
+ {61 ,"Australia"},
+ {43 ,"Austria"},
+ {994 ,"Azerbaijan"},
+ {103 ,"Bahamas"},
+ {973 ,"Bahrain"},
+ {880 ,"Bangladesh"},
+ {104 ,"Barbados"},
+ {120 ,"Barbuda"},
+ {375 ,"Belarus"},
+ {32 ,"Belgium"},
+ {501 ,"Belize"},
+ {229 ,"Benin"},
+ {105 ,"Bermuda"},
+ {975 ,"Bhutan"},
+ {591 ,"Bolivia"},
+ {387 ,"Bosnia and Herzegovina"},
+ {267 ,"Botswana"},
+ {55 ,"Brazil"},
+ {106 ,"British Virgin Islands"},
+ {673 ,"Brunei"},
+ {359 ,"Bulgaria"},
+ {226 ,"Burkina Faso"},
+ {257 ,"Burundi"},
+ {855 ,"Cambodia"},
+ {237 ,"Cameroon"},
+ {107 ,"Canada"},
+ {178 ,"Canary Islands"},
+ {238 ,"Cape Verde Islands"},
+ {108 ,"Cayman Islands"},
+ {236 ,"Central African Republic"},
+ {235 ,"Chad"},
+ {56 ,"Chile, Republic of"},
+ {86 ,"China"},
+ {672 ,"Christmas Island"},
+ {6101,"Cocos-Keeling Islands"},
+ {6102,"Cocos (Keeling) Islands"},
+ {57 ,"Colombia"},
+ {2691,"Comoros"},
+ {243 ,"Congo, Democratic Republic of (Zaire)"},
+ {242 ,"Congo, Republic of the"},
+ {682 ,"Cook Islands"},
+ {506 ,"Costa Rica"},
+ {225 ,"Cote d'Ivoire (Ivory Coast)"},
+ {385 ,"Croatia"},
+ {53 ,"Cuba"},
+ {357 ,"Cyprus"},
+ {420 ,"Czech Republic"},
+ {45 ,"Denmark"},
+ {246 ,"Diego Garcia"},
+ {253 ,"Djibouti"},
+ {109 ,"Dominica"},
+ {110 ,"Dominican Republic"},
+ {593 ,"Ecuador"},
+ {20 ,"Egypt"},
+ {503 ,"El Salvador"},
+ {240 ,"Equatorial Guinea"},
+ {291 ,"Eritrea"},
+ {372 ,"Estonia"},
+ {251 ,"Ethiopia"},
+ {298 ,"Faeroe Islands"},
+ {500 ,"Falkland Islands"},
+ {679 ,"Fiji"},
+ {358 ,"Finland"},
+ {33 ,"France"},
+ {5901,"French Antilles"},
+ {594 ,"French Guiana"},
+ {689 ,"French Polynesia"},
+ {241 ,"Gabon"},
+ {220 ,"Gambia"},
+ {995 ,"Georgia"},
+ {49 ,"Germany"},
+ {233 ,"Ghana"},
+ {350 ,"Gibraltar"},
+ {30 ,"Greece"},
+ {299 ,"Greenland"},
+ {111 ,"Grenada"},
+ {590 ,"Guadeloupe"},
+ {671 ,"Guam, US Territory of"},
+ {502 ,"Guatemala"},
+ {224 ,"Guinea"},
+ {245 ,"Guinea-Bissau"},
+ {592 ,"Guyana"},
+ {509 ,"Haiti"},
+ {504 ,"Honduras"},
+ {852 ,"Hong Kong"},
+ {36 ,"Hungary"},
+ {354 ,"Iceland"},
+ {91 ,"India"},
+ {62 ,"Indonesia"},
+ {98 ,"Iran (Islamic Republic of)"},
+ {964 ,"Iraq"},
+ {353 ,"Ireland"},
+ {972 ,"Israel"},
+ {39 ,"Italy"},
+ {112 ,"Jamaica"},
+ {81 ,"Japan"},
+ {962 ,"Jordan"},
+ {705 ,"Kazakhstan"},
+ {254 ,"Kenya"},
+ {686 ,"Kiribati"},
+ {850 ,"Korea, North"},
+ {82 ,"Korea, South"},
+ {965 ,"Kuwait"},
+ {706 ,"Kyrgyzstan"},
+ {856 ,"Laos"},
+ {371 ,"Latvia"},
+ {961 ,"Lebanon"},
+ {266 ,"Lesotho"},
+ {231 ,"Liberia"},
+ {218 ,"Libyan Arab Jamahiriya"},
+ {4101,"Liechtenstein"},
+ {370 ,"Lithuania"},
+ {352 ,"Luxembourg"},
+ {853 ,"Macau"},
+ {389 ,"Macedonia (F.Y.R.O.M.)"},
+ {261 ,"Madagascar"},
+ {265 ,"Malawi"},
+ {60 ,"Malaysia"},
+ {960 ,"Maldives"},
+ {223 ,"Mali"},
+ {356 ,"Malta"},
+ {692 ,"Marshall Islands"},
+ {596 ,"Martinique"},
+ {222 ,"Mauritania"},
+ {230 ,"Mauritius"},
+ {269 ,"Mayotte Island"},
+ {52 ,"Mexico"},
+ {691 ,"Micronesia, Federated States of"},
+ {373 ,"Moldova, Republic of"},
+ {377 ,"Monaco"},
+ {976 ,"Mongolia"},
+ {113 ,"Montserrat"},
+ {212 ,"Morocco"},
+ {258 ,"Mozambique"},
+ {95 ,"Myanmar"},
+ {264 ,"Namibia"},
+ {674 ,"Nauru"},
+ {977 ,"Nepal"},
+ {31 ,"Netherlands"},
+ {599 ,"Netherlands Antilles"},
+ {114 ,"Nevis"},
+ {687 ,"New Caledonia"},
+ {64 ,"New Zealand"},
+ {505 ,"Nicaragua"},
+ {227 ,"Niger"},
+ {234 ,"Nigeria"},
+ {683 ,"Niue"},
+ {6722,"Norfolk Island"},
+ {47 ,"Norway"},
+ {968 ,"Oman"},
+ {92 ,"Pakistan"},
+ {680 ,"Palau"},
+ {507 ,"Panama"},
+ {675 ,"Papua New Guinea"},
+ {595 ,"Paraguay"},
+ {51 ,"Peru"},
+ {63 ,"Philippines"},
+ {48 ,"Poland"},
+ {351 ,"Portugal"},
+ {121 ,"Puerto Rico"},
+ {974 ,"Qatar"},
+ {262 ,"Reunion Island"},
+ {40 ,"Romania"},
+ {6701,"Rota Island"},
+ {7 ,"Russia"},
+ {250 ,"Rwanda"},
+ {290 ,"Saint Helena"},
+ {115 ,"Saint Kitts"},
+ {1141,"Saint Kitts and Nevis"},
+ {122 ,"Saint Lucia"},
+ {508 ,"Saint Pierre and Miquelon"},
+ {116 ,"Saint Vincent and the Grenadines"},
+ {670 ,"Saipan Island"},
+ {378 ,"San Marino"},
+ {239 ,"Sao Tome and Principe"},
+ {966 ,"Saudi Arabia"},
+ {442 ,"Scotland"},
+ {221 ,"Senegal"},
+ {248 ,"Seychelles"},
+ {232 ,"Sierra Leone"},
+ {65 ,"Singapore"},
+ {421 ,"Slovakia"},
+ {386 ,"Slovenia"},
+ {677 ,"Solomon Islands"},
+ {252 ,"Somalia"},
+ {27 ,"South Africa"},
+ {34 ,"Spain"},
+ {94 ,"Sri Lanka"},
+ {249 ,"Sudan"},
+ {597 ,"Suriname"},
+ {268 ,"Swaziland"},
+ {46 ,"Sweden"},
+ {41 ,"Switzerland"},
+ {963 ,"Syrian Arab Republic"},
+ {886 ,"Taiwan"},
+ {708 ,"Tajikistan"},
+ {255 ,"Tanzania"},
+ {66 ,"Thailand"},
+ {6702,"Tinian Island"},
+ {228 ,"Togo"},
+ {690 ,"Tokelau"},
+ {676 ,"Tonga"},
+ {117 ,"Trinidad and Tobago"},
+ {216 ,"Tunisia"},
+ {90 ,"Turkey"},
+ {709 ,"Turkmenistan"},
+ {118 ,"Turks and Caicos Islands"},
+ {688 ,"Tuvalu"},
+ {256 ,"Uganda"},
+ {380 ,"Ukraine"},
+ {971 ,"United Arab Emirates"},
+ {44 ,"United Kingdom"},
+ {598 ,"Uruguay"},
+ {1 ,"USA"},
+ {711 ,"Uzbekistan"},
+ {678 ,"Vanuatu"},
+ {379 ,"Vatican City"},
+ {58 ,"Venezuela"},
+ {84 ,"Vietnam"},
+ {123 ,"Virgin Islands (USA)"},
+ {441 ,"Wales"},
+ {681 ,"Wallis and Futuna Islands"},
+ {685 ,"Western Samoa"},
+ {967 ,"Yemen"},
+ {381 ,"Yugoslavia"},
+ {3811,"Yugoslavia - Serbia"},
+ {382 ,"Yugoslavia - Montenegro"},
+ {260 ,"Zambia"},
+ {263 ,"Zimbabwe"},
+};
+
+static ListTypeDataItem timezones[]={
+ {-100,"Unspecified"},
+ {24 ,"GMT-12:00 Eniwetok; Kwajalein"},
+ {23 ,"GMT-11:30"},
+ {22 ,"GMT-11:00 Midway Island; Samoa"},
+ {21 ,"GMT-10:30"},
+ {20 ,"GMT-10:00 Hawaii"},
+ {19 ,"GMT-9:30"},
+ {18 ,"GMT-9:00 Alaska"},
+ {17 ,"GMT-8:30"},
+ {16 ,"GMT-8:00 Pacific Time; Tijuana"},
+ {15 ,"GMT-7:30"},
+ {14 ,"GMT-7:00 Arizona; Mountain Time"},
+ {13 ,"GMT-6:30"},
+ {12 ,"GMT-6:00 Central Time; Central America; Saskatchewan"},
+ {11 ,"GMT-5:30"},
+ {10 ,"GMT-5:00 Eastern Time; Bogota; Lima; Quito"},
+ {9 ,"GMT-4:30"},
+ {8 ,"GMT-4:00 Atlantic Time; Santiago; Caracas; La Paz"},
+ {7 ,"GMT-3:30 Newfoundland"},
+ {6 ,"GMT-3:00 Greenland; Buenos Aires; Georgetown"},
+ {5 ,"GMT-2:30"},
+ {4 ,"GMT-2:00 Mid-Atlantic"},
+ {3 ,"GMT-1:30"},
+ {2 ,"GMT-1:00 Cape Verde Islands; Azores"},
+ {1 ,"GMT-0:30"},
+ {0 ,"GMT+0:00 London; Dublin; Edinburgh; Lisbon; Casablanca"},
+ {-1 ,"GMT+0:30"},
+ {-2 ,"GMT+1:00 Central European Time; West Central Africa; Warsaw"},
+ {-3 ,"GMT+1:30"},
+ {-4 ,"GMT+2:00 Jerusalem; Helsinki; Harare; Cairo; Bucharest; Athens"},
+ {-5 ,"GMT+2:30"},
+ {-6 ,"GMT+3:00 Moscow; St. Petersburg; Nairobi; Kuwait; Baghdad"},
+ {-7 ,"GMT+3:30 Tehran"},
+ {-8 ,"GMT+4:00 Baku; Tbilisi; Yerevan; Abu Dhabi; Muscat"},
+ {-9 ,"GMT+4:30 Kabul"},
+ {-10 ,"GMT+5:00 Calcutta; Chennai; Mumbai; New Delhi; Ekaterinburg"},
+ {-11 ,"GMT+5:30"},
+ {-12 ,"GMT+6:00 Astana; Dhaka; Almaty; Novosibirsk; Sri Jayawardenepura"},
+ {-13 ,"GMT+6:30 Rangoon"},
+ {-14 ,"GMT+7:00 Bankok; Hanoi; Jakarta; Krasnoyarsk"},
+ {-15 ,"GMT+7:30"},
+ {-16 ,"GMT+8:00 Perth; Taipei; Singapore; Hong Kong; Beijing"},
+ {-17 ,"GMT+8:30"},
+ {-18 ,"GMT+9:00 Tokyo; Osaka; Seoul; Sapporo; Yakutsk"},
+ {-19 ,"GMT+9:30 Darwin; Adelaide"},
+ {-20 ,"GMT+10:00 East Australia; Guam; Vladivostok"},
+ {-21 ,"GMT+10:30"},
+ {-22 ,"GMT+11:00 Magadan; Solomon Is.; New Caledonia"},
+ {-23 ,"GMT+11:30"},
+ {-24 ,"GMT+12:00 Auckland; Wellington; Fiji; Kamchatka; Marshall Is."},
+};
+
+static ListTypeDataItem occupations[] = {
+ {0, "Unspecified"},
+ {1, "Academic"},
+ {2, "Administrative"},
+ {3, "Art/Entertainment"},
+ {4, "College Student"},
+ {5, "Computers"},
+ {6, "Community & Social"},
+ {7, "Education"},
+ {8, "Engineering"},
+ {9, "Financial Services"},
+ {10, "Government"},
+ {11, "High School Student"},
+ {12, "Home"},
+ {13, "ICQ - Providing Help"},
+ {14, "Law"},
+ {15, "Managerial"},
+ {16, "Manufacturing"},
+ {17, "Medical/Health"},
+ {18, "Military"},
+ {19, "Non-Government Organization"},
+ {20, "Professional"},
+ {21, "Retail"},
+ {22, "Retired"},
+ {23, "Science & Research"},
+ {24, "Sports"},
+ {25, "Technical"},
+ {26, "University Student"},
+ {27, "Web Building"},
+ {99, "Other Services"}
+};
+
+static ListTypeDataItem genders[]={
+ {0,"Unspecified"},
+ {'M',"Male"},
+ {'F',"Female"},
+};
+
+static ListTypeDataItem months[]={
+ {0, "Unspecified"},
+ {1, "January"},
+ {2, "February"},
+ {3, "March"},
+ {4, "April"},
+ {5, "May"},
+ {6, "June"},
+ {7, "July"},
+ {8, "August"},
+ {9, "September"},
+ {10,"October"},
+ {11,"November"},
+ {12,"December"},
+};
+
+static ListTypeDataItem languages[]={
+ {0, "None"},
+ {55,"Afrikaans"},
+ {58,"Albanian"},
+ {1, "Arabic"},
+ {59,"Armenian"},
+ {68,"Azerbaijani"},
+ {72,"Belorussian"},
+ {2, "Bhojpuri"},
+ {56,"Bosnian"},
+ {3, "Bulgarian"},
+ {4, "Burmese"},
+ {5, "Cantonese"},
+ {6, "Catalan"},
+ {61,"Chamorro"},
+ {7, "Chinese"},
+ {8, "Croatian"},
+ {9, "Czech"},
+ {10,"Danish"},
+ {11,"Dutch"},
+ {12,"English"},
+ {13,"Esperanto"},
+ {14,"Estonian"},
+ {15,"Farci"},
+ {16,"Finnish"},
+ {17,"French"},
+ {18,"Gaelic"},
+ {19,"German"},
+ {20,"Greek"},
+ {70,"Gujarati"},
+ {21,"Hebrew"},
+ {22,"Hindi"},
+ {23,"Hungarian"},
+ {24,"Icelandic"},
+ {25,"Indonesian"},
+ {26,"Italian"},
+ {27,"Japanese"},
+ {28,"Khmer"},
+ {29,"Korean"},
+ {69,"Kurdish"},
+ {30,"Lao"},
+ {31,"Latvian"},
+ {32,"Lithuanian"},
+ {65,"Macedonian"},
+ {33,"Malay"},
+ {63,"Mandarin"},
+ {62,"Mongolian"},
+ {34,"Norwegian"},
+ {57,"Persian"},
+ {35,"Polish"},
+ {36,"Portuguese"},
+ {60,"Punjabi"},
+ {37,"Romanian"},
+ {38,"Russian"},
+ {39,"Serbo-Croatian"},
+ {66,"Sindhi"},
+ {40,"Slovak"},
+ {41,"Slovenian"},
+ {42,"Somali"},
+ {43,"Spanish"},
+ {44,"Swahili"},
+ {45,"Swedish"},
+ {46,"Tagalog"},
+ {64,"Taiwaness"},
+ {71,"Tamil"},
+ {47,"Tatar"},
+ {48,"Thai"},
+ {49,"Turkish"},
+ {50,"Ukrainian"},
+ {51,"Urdu"},
+ {52,"Vietnamese"},
+ {67,"Welsh"},
+ {53,"Yiddish"},
+ {54,"Yoruba"},
+};
+
+static ListTypeDataItem interests[]={
+ {0, "Unspecified"},
+ {100, "Art"},
+ {101, "Cars"},
+ {102, "Celebrity Fans"},
+ {103, "Collections"},
+ {104, "Computers"},
+ {105, "Culture & Literature"},
+ {106, "Fitness"},
+ {107, "Games"},
+ {108, "Hobbies"},
+ {109, "ICQ - Providing Help"},
+ {110, "Internet"},
+ {111, "Lifestyle"},
+ {112, "Movies/TV"},
+ {113, "Music"},
+ {114, "Outdoor Activities"},
+ {115, "Parenting"},
+ {116, "Pets/Animals"},
+ {117, "Religion"},
+ {118, "Science/Technology"},
+ {119, "Skills"},
+ {120, "Sports"},
+ {121, "Web Design"},
+ {122, "Nature and Environment"},
+ {123, "News & Media"},
+ {124, "Government"},
+ {125, "Business & Economy"},
+ {126, "Mystics"},
+ {127, "Travel"},
+ {128, "Astronomy"},
+ {129, "Space"},
+ {130, "Clothing"},
+ {131, "Parties"},
+ {132, "Women"},
+ {133, "Social science"},
+ {134, "60's"},
+ {135, "70's"},
+ {136, "80's"},
+ {137, "50's"},
+ {138, "Finance and corporate"},
+ {139, "Entertainment"},
+ {140, "Consumer electronics"},
+ {141, "Retail stores"},
+ {142, "Health and beauty"},
+ {143, "Media"},
+ {144, "Household products"},
+ {145, "Mail order catalog"},
+ {146, "Business services"},
+ {147, "Audio and visual"},
+ {148, "Sporting and athletic"},
+ {149, "Publishing"},
+ {150, "Home automation"}
+};
+
+static ListTypeDataItem pastbackground[]={
+ {0, "Unspecified"},
+ {300, "Elementary School"},
+ {301, "High School"},
+ {302, "College"},
+ {303, "University"},
+ {304, "Military"},
+ {305, "Past Work Place"},
+ {306, "Past Organization"},
+ {399, "Other"}
+};
+
+static ListTypeDataItem affiliation[]={
+ {0, "Unspecified"},
+ {200, "Alumni Org."},
+ {201, "Charity Org."},
+ {202, "Club/Social Org."},
+ {203, "Community Org."},
+ {204, "Cultural Org."},
+ {205, "Fan Clubs"},
+ {206, "Fraternity/Sorority"},
+ {207, "Hobbyists Org."},
+ {208, "International Org."},
+ {209, "Nature and Environment Org."},
+ {210, "Professional Org."},
+ {211, "Scientific/Technical Org."},
+ {212, "Self Improvement Group"},
+ {213, "Spiritual/Religious Org."},
+ {214, "Sports Org."},
+ {215, "Support Org."},
+ {216, "Trade and Business Org."},
+ {217, "Union"},
+ {218, "Volunteer Org."},
+ {299, "Other"},
+};
+
+static ListTypeDataItem maritalstatuses[]={
+ {0, "Unspecified"},
+ {10, "Single"},
+ {11, "Close relationships"},
+ {12, "Engaged"},
+ {20, "Married"},
+ {30, "Divorced"},
+ {31, "Separated"},
+ {40, "Widowed"}
+};
+
+
+const int ageRange[]={13,0x7FFF}; // 14, 130
+const int yearRange[]={1753,0x7FFF}; // 1880, 2000
+const int dayRange[]={1,31};
+
+
+SettingItem setting[]={
+ //personal
+ {"Personal", LI_DIVIDER},
+ {"Nickname", LI_STRING, DBVT_ASCIIZ, "Nick"},
+ {"First name", LI_STRING, DBVT_ASCIIZ, "FirstName"},
+ {"Last name", LI_STRING, DBVT_ASCIIZ, "LastName"},
+ {"Age", LI_NUMBER, DBVT_WORD, "Age", (void*)ageRange},
+ {"Gender", LI_LIST, DBVT_BYTE, "Gender", genders, sizeof(genders)/sizeof(genders[0])},
+ {"About", LI_LONGSTRING, DBVT_ASCIIZ, "About"},
+ //password
+ {"Password", LI_DIVIDER},
+ {"Password", LI_STRING|LIF_PASSWORD,DBVT_ASCIIZ, "Password"},
+ //contact
+ {"Contact", LI_DIVIDER},
+ {"Primary e-mail", LI_STRING, DBVT_ASCIIZ, "e-mail"},
+ {"Secondary e-mail", LI_STRING, DBVT_ASCIIZ, "e-mail0"},
+ {"Tertiary e-mail", LI_STRING, DBVT_ASCIIZ, "e-mail1"},
+ {"Homepage", LI_STRING, DBVT_ASCIIZ, "Homepage"},
+ {"Street", LI_STRING, DBVT_ASCIIZ, "Street"},
+ {"City", LI_STRING, DBVT_ASCIIZ, "City"},
+ {"State", LI_STRING, DBVT_ASCIIZ, "State"},
+ {"ZIP/postcode", LI_STRING, DBVT_ASCIIZ, "ZIP"},
+ {"Country", LI_LIST, DBVT_WORD, "Country", countries, sizeof(countries)/sizeof(countries[0])},
+ {"Phone number", LI_STRING, DBVT_ASCIIZ, "Phone"},
+ {"Fax number", LI_STRING, DBVT_ASCIIZ, "Fax"},
+ {"Cellular number",LI_STRING, DBVT_ASCIIZ, "Cellular"},
+ //more
+ {"Personal Detail",LI_DIVIDER},
+ {"Timezone", LI_LIST|LIF_ZEROISVALID|LIF_SIGNED,DBVT_BYTE, "Timezone", timezones, sizeof(timezones)/sizeof(timezones[0])},
+ {"Year of birth", LI_NUMBER, DBVT_WORD, "BirthYear", (void*)yearRange},
+ {"Month of birth", LI_LIST, DBVT_BYTE, "BirthMonth", months, sizeof(months)/sizeof(months[0])},
+ {"Day of birth", LI_NUMBER, DBVT_BYTE, "BirthDay", (void*)dayRange},
+ {"Marital Status", LI_LIST, DBVT_BYTE, "MaritalStatus", maritalstatuses, sizeof(maritalstatuses)/sizeof(maritalstatuses[0])},
+ {"Spoken language 1", LI_LIST, DBVT_ASCIIZ, "Language1", languages, sizeof(languages)/sizeof(languages[0])},
+ {"Spoken language 2", LI_LIST, DBVT_ASCIIZ, "Language2", languages, sizeof(languages)/sizeof(languages[0])},
+ {"Spoken language 3", LI_LIST, DBVT_ASCIIZ, "Language3", languages, sizeof(languages)/sizeof(languages[0])},
+ //more
+ {"Originally from",LI_DIVIDER},
+ {"City", LI_STRING, DBVT_ASCIIZ, "OriginCity"},
+ {"State", LI_STRING, DBVT_ASCIIZ, "OriginState"},
+ {"Country", LI_LIST, DBVT_WORD, "OriginCountry", countries, sizeof(countries)/sizeof(countries[0])},
+ //work
+ {"Work", LI_DIVIDER},
+ {"Company name", LI_STRING, DBVT_ASCIIZ, "Company"},
+ {"Company homepage",LI_STRING, DBVT_ASCIIZ, "CompanyHomepage"},
+ {"Company street", LI_STRING, DBVT_ASCIIZ, "CompanyStreet"},
+ {"Company city", LI_STRING, DBVT_ASCIIZ, "CompanyCity"},
+ {"Company state", LI_STRING, DBVT_ASCIIZ, "CompanyState"},
+ {"Company phone", LI_STRING, DBVT_ASCIIZ, "CompanyPhone"},
+ {"Company fax", LI_STRING, DBVT_ASCIIZ, "CompanyFax"},
+ {"Company ZIP/postcode",LI_STRING,DBVT_ASCIIZ, "CompanyZIP"},
+ {"Company country",LI_LIST, DBVT_WORD, "CompanyCountry",countries, sizeof(countries)/sizeof(countries[0])},
+ {"Company department",LI_STRING, DBVT_ASCIIZ, "CompanyDepartment"},
+ {"Company position",LI_STRING, DBVT_ASCIIZ, "CompanyPosition"},
+ {"Company occupation",LI_LIST, DBVT_WORD, "CompanyOccupation", occupations, sizeof(occupations)/sizeof(occupations[0])},
+ //interests
+ {"Personal Interests", LI_DIVIDER},
+ {"Interest category 1",LI_LIST, DBVT_ASCIIZ, "Interest0Cat", interests, sizeof(interests)/sizeof(interests[0])},
+ {"Interest areas 1",LI_STRING, DBVT_ASCIIZ, "Interest0Text"},
+ {"Interest category 2",LI_LIST, DBVT_ASCIIZ, "Interest1Cat", interests, sizeof(interests)/sizeof(interests[0])},
+ {"Interest areas 2",LI_STRING, DBVT_ASCIIZ, "Interest1Text"},
+ {"Interest category 3",LI_LIST, DBVT_ASCIIZ, "Interest2Cat", interests, sizeof(interests)/sizeof(interests[0])},
+ {"Interest areas 3",LI_STRING, DBVT_ASCIIZ, "Interest2Text"},
+ {"Interest category 4",LI_LIST, DBVT_ASCIIZ, "Interest3Cat", interests, sizeof(interests)/sizeof(interests[0])},
+ {"Interest areas 4",LI_STRING, DBVT_ASCIIZ, "Interest3Text"},
+ //pastbackground
+ {"Past Background", LI_DIVIDER},
+ {"Category 1",LI_LIST, DBVT_ASCIIZ, "Past0", pastbackground, sizeof(pastbackground)/sizeof(pastbackground[0])},
+ {"Past Background 1",LI_STRING, DBVT_ASCIIZ, "Past0Text"},
+ {"Category 2",LI_LIST, DBVT_ASCIIZ, "Past1", pastbackground, sizeof(pastbackground)/sizeof(pastbackground[0])},
+ {"Past Background 2",LI_STRING, DBVT_ASCIIZ, "Past1Text"},
+ {"Category 3",LI_LIST, DBVT_ASCIIZ, "Past2", pastbackground, sizeof(pastbackground)/sizeof(pastbackground[0])},
+ {"Past Background 3",LI_STRING, DBVT_ASCIIZ, "Past2Text"},
+ //affiliation
+ {"Affiliations", LI_DIVIDER},
+ {"Affiliation category 1",LI_LIST,DBVT_ASCIIZ, "Affiliation0", affiliation, sizeof(affiliation)/sizeof(affiliation[0])},
+ {"Affiliation 1",LI_STRING, DBVT_ASCIIZ, "Affiliation0Text"},
+ {"Affiliation category 2",LI_LIST,DBVT_ASCIIZ, "Affiliation1", affiliation, sizeof(affiliation)/sizeof(affiliation[0])},
+ {"Affiliation 2",LI_STRING, DBVT_ASCIIZ, "Affiliation1Text"},
+ {"Affiliation category 3",LI_LIST,DBVT_ASCIIZ, "Affiliation2", affiliation, sizeof(affiliation)/sizeof(affiliation[0])},
+ {"Affiliation 3",LI_STRING, DBVT_ASCIIZ, "Affiliation2Text"}
+};
+
+const int settingCount=sizeof(setting)/sizeof(setting[0]);
diff --git a/miranda-wine/protocols/IcqOscarJ/changeinfo/db.c b/miranda-wine/protocols/IcqOscarJ/changeinfo/db.c
new file mode 100644
index 0000000..c9d09b4
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/changeinfo/db.c
@@ -0,0 +1,226 @@
+// ---------------------------------------------------------------------------80
+// ICQ plugin for Miranda Instant Messenger
+// ________________________________________
+//
+// Copyright © 2001,2002,2003,2004 Richard Hughes, Martin Öberg
+// Copyright © 2004,2005,2006 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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/changeinfo/db.c,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// ChangeInfo Plugin stuff
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+void LoadSettingsFromDb(int keepChanged)
+{
+ int i;
+ DBVARIANT dbv;
+
+ for(i=0;i<settingCount;i++)
+ {
+ if (setting[i].displayType==LI_DIVIDER) continue;
+ if (keepChanged && setting[i].changed) continue;
+ if (setting[i].dbType==DBVT_ASCIIZ)
+ {
+ SAFE_FREE((char**)&setting[i].value);
+ }
+ else if (!keepChanged)
+ setting[i].value = 0;
+
+ setting[i].changed=0;
+
+ if (setting[i].displayType&LIF_PASSWORD) continue;
+
+ if (!ICQGetContactSetting(NULL,setting[i].szDbSetting,&dbv))
+ {
+#ifdef _DEBUG
+ if(dbv.type!=setting[i].dbType)
+ MessageBoxA(NULL,"That's not supposed to happen","Huh?",MB_OK);
+#endif
+ switch(dbv.type)
+ {
+ case DBVT_ASCIIZ:
+ setting[i].value=(LPARAM)ICQGetContactSettingUtf(NULL,setting[i].szDbSetting, NULL);
+ break;
+ case DBVT_WORD:
+ if(setting[i].displayType&LIF_SIGNED)
+ setting[i].value=dbv.sVal;
+ else
+ setting[i].value=dbv.wVal;
+ break;
+ case DBVT_BYTE:
+ if(setting[i].displayType&LIF_SIGNED)
+ setting[i].value=dbv.cVal;
+ else
+ setting[i].value=dbv.bVal;
+ break;
+#ifdef _DEBUG
+ default:
+ MessageBoxA(NULL,"That's not supposed to happen either","Huh?",MB_OK);
+ break;
+#endif
+ }
+ ICQFreeVariant(&dbv);
+ }
+ }
+}
+
+
+
+void FreeStoredDbSettings(void)
+{
+ int i;
+
+ for(i=0;i<settingCount;i++)
+ if(setting[i].dbType==DBVT_ASCIIZ)
+ SAFE_FREE((char**)&setting[i].value);
+}
+
+
+
+int ChangesMade(void)
+{
+ int i;
+
+ for(i=0;i<settingCount;i++)
+ if(setting[i].changed) return 1;
+ return 0;
+}
+
+
+
+void ClearChangeFlags(void)
+{
+ int i;
+
+ for(i=0;i<settingCount;i++)
+ setting[i].changed=0;
+}
+
+
+
+static BOOL CALLBACK PwConfirmDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static char *Pass;
+
+ switch(msg)
+ {
+ case WM_INITDIALOG:
+ ICQTranslateDialog(hwndDlg);
+ Pass = (char*)lParam;
+ SendDlgItemMessage(hwndDlg,IDC_PASSWORD,EM_LIMITTEXT,15,0);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch(LOWORD(wParam))
+ {
+ case IDOK:
+ {
+ char szTest[16], str[1024], cap[MAX_PATH];
+
+ GetDlgItemTextA(hwndDlg,IDC_OLDPASS,szTest,sizeof(szTest));
+
+ if (strcmpnull(szTest, GetUserPassword(TRUE)))
+ {
+ MessageBoxUtf(hwndDlg,ICQTranslateUtfStatic("The password does not match your current password. Check Caps Lock and try again.", str), ICQTranslateUtfStatic("Change ICQ Details", cap), 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, Pass))
+ {
+ MessageBoxUtf(hwndDlg,ICQTranslateUtfStatic("The password does not match the password you originally entered. Check Caps Lock and try again.", str), ICQTranslateUtfStatic("Change ICQ Details", cap), 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 SaveSettingsToDb(HWND hwndDlg)
+{
+ int i,ret=1;
+
+ for(i=0;i<settingCount;i++)
+ {
+ if(!setting[i].changed) continue;
+ if(!(setting[i].displayType&LIF_ZEROISVALID) && setting[i].value==0)
+ {
+ ICQDeleteContactSetting(NULL,setting[i].szDbSetting);
+ continue;
+ }
+ switch(setting[i].dbType)
+ {
+ case DBVT_ASCIIZ:
+ if(setting[i].displayType&LIF_PASSWORD)
+ {
+ int nSettingLen = strlennull((char*)setting[i].value);
+
+ if (nSettingLen>8 || nSettingLen<1)
+ {
+ char str[1024], cap[MAX_PATH];
+
+ MessageBoxUtf(hwndDlg, ICQTranslateUtfStatic("The ICQ server does not support passwords longer than 8 characters. Please use a shorter password.", str), ICQTranslateUtfStatic("Change ICQ Details", cap), MB_OK);
+ ret=0;
+ break;
+ }
+ if (IDOK!=DialogBoxParam(hInst,MAKEINTRESOURCE(IDD_PWCONFIRM),hwndDlg,PwConfirmDlgProc,(LPARAM)setting[i].value))
+ {
+ ret=0;
+ break;
+ }
+ strcpy(gpszPassword, (char*)setting[i].value);
+ }
+ else
+ {
+ if(*(char*)setting[i].value)
+ ICQWriteContactSettingUtf(NULL,setting[i].szDbSetting,(char*)setting[i].value);
+ else
+ ICQDeleteContactSetting(NULL,setting[i].szDbSetting);
+ }
+ break;
+ case DBVT_WORD:
+ ICQWriteContactSettingWord(NULL,setting[i].szDbSetting,(WORD)setting[i].value);
+ break;
+ case DBVT_BYTE:
+ ICQWriteContactSettingByte(NULL,setting[i].szDbSetting,(BYTE)setting[i].value);
+ break;
+ }
+ }
+ return ret;
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/changeinfo/dlgproc.c b/miranda-wine/protocols/IcqOscarJ/changeinfo/dlgproc.c
new file mode 100644
index 0000000..119141f
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/changeinfo/dlgproc.c
@@ -0,0 +1,560 @@
+// ---------------------------------------------------------------------------80
+// ICQ plugin for Miranda Instant Messenger
+// ________________________________________
+//
+// Copyright © 2001,2002,2003,2004 Richard Hughes, Martin Öberg
+// Copyright © 2004,2005,2006 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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/changeinfo/dlgproc.c,v $
+// Revision : $Revision: 3183 $
+// Last change on : $Date: 2006-06-20 13:50:04 +0400 (Втр, 20 Июн 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// ChangeInfo Plugin stuff
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+static int editTopIndex;
+static HANDLE hAckHook = NULL;
+static HFONT hMyFont = NULL;
+
+#define DM_PROTOACK (WM_USER+10)
+
+static int DrawTextUtf(HDC hDC, char* text, LPRECT lpRect, UINT uFormat, LPSIZE lpSize)
+{
+ int res;
+
+ if (gbUnicodeAPI)
+ {
+ wchar_t *tmp = make_unicode_string(text);
+
+ res = DrawTextW(hDC, tmp, -1, lpRect, uFormat);
+ if (lpSize)
+ GetTextExtentPoint32W(hDC, tmp, wcslen(tmp), lpSize);
+ SAFE_FREE(&tmp);
+ }
+ else
+ {
+ // caution, here we change text's contents
+ utf8_decode_static(text, text, strlennull(text)+1);
+ res = DrawTextA(hDC, text, -1, lpRect, uFormat);
+ if (lpSize)
+ GetTextExtentPoint32A(hDC, text, strlennull(text), lpSize);
+ }
+ return res;
+}
+
+
+
+static void PaintItemSetting(HDC hdc,RECT *rc,int i,UINT itemState)
+{
+ char *text;
+ int alloced=0;
+ char str[MAX_PATH];
+
+ if (setting[i].value==0 && !(setting[i].displayType&LIF_ZEROISVALID))
+ {
+ SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
+
+ if (setting[i].displayType & LIF_CHANGEONLY)
+ text = ICQTranslateUtfStatic("<unremovable once applied>", str);
+ else
+ text = ICQTranslateUtfStatic("<empty>", str);
+ }
+ else
+ {
+ switch (setting[i].displayType & LIM_TYPE)
+ {
+ case LI_STRING:
+ case LI_LONGSTRING:
+ {
+ text = BinaryToEscapes((char*)setting[i].value);
+ alloced = 1;
+ break;
+ }
+
+ case LI_NUMBER:
+ text = str;
+ itoa(setting[i].value, text, 10);
+ break;
+
+ case LI_LIST:
+ if (setting[i].dbType == DBVT_ASCIIZ)
+ {
+ text = ICQTranslateUtfStatic((char*)setting[i].value, str);
+ }
+ else
+ {
+ int j;
+
+ text = ICQTranslateUtfStatic("Unknown value", str);
+
+ for(j=0; j < setting[i].listCount; j++)
+ if (((ListTypeDataItem*)setting[i].pList)[j].id == setting[i].value)
+ {
+ text = ICQTranslateUtfStatic(((ListTypeDataItem*)setting[i].pList)[j].szValue, str);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ if (setting[i].displayType & LIF_PASSWORD)
+ {
+ if (setting[i].changed)
+ {
+ int i;
+ for (i=0; text[i]; i++) text[i] = '*';
+ }
+ else
+ {
+ if (alloced)
+ {
+ SAFE_FREE(&text);
+ alloced=0;
+ }
+ text = "********";
+ }
+ }
+ 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);
+
+ if (alloced) SAFE_FREE(&text);
+}
+
+
+static int InfoDlg_Resize(HWND hwndDlg,LPARAM lParam,UTILRESIZECONTROL *urc)
+{
+ switch (urc->wId)
+ {
+ case IDC_LIST:
+ return RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT;
+ break;
+ case IDC_SAVE:
+ return RD_ANCHORX_RIGHT | RD_ANCHORY_BOTTOM;
+ break;
+ case IDC_UPLOADING:
+ return RD_ANCHORX_WIDTH | RD_ANCHORY_BOTTOM;
+ break;
+ }
+ return RD_ANCHORX_LEFT | RD_ANCHORY_TOP; // default
+}
+
+
+
+BOOL CALLBACK ChangeInfoDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg)
+ {
+ case WM_INITDIALOG:
+ ICQTranslateDialog(hwndDlg);
+ hwndList=GetDlgItem(hwndDlg,IDC_LIST);
+ LoadSettingsFromDb(0);
+ ListView_SetExtendedListViewStyle(hwndList,LVS_EX_FULLROWSELECT);
+ iEditItem=-1;
+ {
+ LOGFONT lf;
+
+ hListFont=(HFONT)SendMessage(hwndList,WM_GETFONT,0,0);
+ GetObject(hListFont,sizeof(lf),&lf);
+ lf.lfHeight-=5;
+ hMyFont=CreateFontIndirect(&lf);
+ SendMessage(hwndList,WM_SETFONT,(WPARAM)hMyFont,0);
+ }
+ {
+ LV_COLUMN lvc={0};
+ RECT rc;
+
+ GetClientRect(hwndList,&rc);
+ rc.right-=GetSystemMetrics(SM_CXVSCROLL);
+ lvc.mask = LVCF_WIDTH;
+ lvc.cx = rc.right/3;
+ ListView_InsertColumn(hwndList, 0, &lvc);
+ lvc.cx = rc.right-lvc.cx;
+ ListView_InsertColumn(hwndList, 1, &lvc);
+ }
+ {
+ LV_ITEM lvi={0};
+ lvi.mask = LVIF_PARAM;
+
+ for (lvi.iItem=0;lvi.iItem<settingCount;lvi.iItem++)
+ {
+ lvi.lParam=lvi.iItem;
+ ListView_InsertItem(hwndList, &lvi);
+ }
+ }
+ {
+ char *pwd = GetUserPassword(TRUE);
+
+ if (pwd)
+ strcpy(Password, pwd);
+ else
+ strcpy(Password, "");
+ }
+
+ SendMessage(GetParent(hwndDlg),PSM_CHANGED,0,0);
+ return TRUE;
+
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom)
+ {
+ case 0:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case PSN_INFOCHANGED:
+ LoadSettingsFromDb(1);
+ break;
+
+ case PSN_KILLACTIVE:
+ EndStringEdit(1);
+ EndListEdit(1);
+ break;
+
+ case PSN_APPLY:
+ if(ChangesMade())
+ {
+ char str[1024], cap[MAX_PATH];
+
+ if (IDYES!=MessageBoxUtf(hwndDlg, ICQTranslateUtfStatic("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?", str), ICQTranslateUtfStatic("Change ICQ Details", cap), MB_YESNOCANCEL))
+ {
+ SetWindowLongUtf(hwndDlg,DWL_MSGRESULT,PSNRET_INVALID_NOCHANGEPAGE);
+ return TRUE;
+ }
+ }
+ PostMessage(hwndList,WM_SETFONT,(WPARAM)hListFont,0);
+ break;
+ }
+ break;
+
+ case IDC_LIST:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case LVN_GETDISPINFOW:
+ case LVN_GETDISPINFO:
+ if (iEditItem != -1)
+ {
+ if (editTopIndex != ListView_GetTopIndex(hwndList))
+ {
+ EndStringEdit(1);
+ EndListEdit(1);
+ }
+ }
+ break;
+
+ case NM_CUSTOMDRAW:
+ {
+ LPNMLVCUSTOMDRAW cd=(LPNMLVCUSTOMDRAW)lParam;
+
+ switch(cd->nmcd.dwDrawStage)
+ {
+ case CDDS_PREPAINT:
+ SetWindowLongUtf(hwndDlg,DWL_MSGRESULT,CDRF_NOTIFYSUBITEMDRAW);
+ return TRUE;
+
+ case CDDS_ITEMPREPAINT:
+ {
+ RECT rc;
+
+ ListView_GetItemRect(hwndList, cd->nmcd.dwItemSpec, &rc, LVIR_BOUNDS);
+
+ if (GetWindowLong(hwndList, GWL_STYLE) & WS_DISABLED)
+ { // Disabled List
+ SetTextColor(cd->nmcd.hdc, cd->clrText);
+ FillRect(cd->nmcd.hdc, &rc, GetSysColorBrush(COLOR_3DFACE));
+ }
+ else if ((cd->nmcd.uItemState & CDIS_SELECTED || 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, &rc, GetSysColorBrush(COLOR_HIGHLIGHT));
+ }
+ else
+ { // Unselected item
+ SetTextColor(cd->nmcd.hdc, GetSysColor(COLOR_WINDOWTEXT));
+ FillRect(cd->nmcd.hdc, &rc, GetSysColorBrush(COLOR_WINDOW));
+ }
+
+ 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);
+ HFONT hoFont;
+
+ hoFont = (HFONT)SelectObject(cd->nmcd.hdc, hListFont);
+ SetTextColor(cd->nmcd.hdc, GetSysColor(COLOR_3DSHADOW));
+ ListView_GetItemRect(hwndList, cd->nmcd.dwItemSpec, &rc, LVIR_BOUNDS);
+ DrawTextUtf(cd->nmcd.hdc, szText, &rc, DT_CENTER|DT_NOCLIP|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER, &textSize);
+ rcLine.top = (rc.top + rc.bottom)/2-1;
+ rcLine.bottom = rcLine.top+2;
+ rcLine.left = rc.left + 3;
+ rcLine.right = (rc.left+rc.right-textSize.cx)/2-3;
+ DrawEdge(cd->nmcd.hdc, &rcLine, BDR_SUNKENOUTER, BF_RECT);
+ rcLine.left = (rc.left + rc.right + textSize.cx)/2 + 3;
+ rcLine.right = rc.right-3;
+ DrawEdge(cd->nmcd.hdc, &rcLine, BDR_SUNKENOUTER, BF_RECT);
+ SetWindowLongUtf(hwndDlg, DWL_MSGRESULT, CDRF_SKIPDEFAULT);
+ }
+ else
+ {
+ SetWindowLongUtf(hwndDlg, DWL_MSGRESULT, CDRF_NOTIFYSUBITEMDRAW|CDRF_NOTIFYPOSTPAINT);
+ }
+
+ return TRUE;
+ }
+
+ case CDDS_SUBITEM|CDDS_ITEMPREPAINT:
+ {
+ RECT rc;
+ HFONT hoFont;
+
+ hoFont=(HFONT)SelectObject(cd->nmcd.hdc,hListFont);
+ ListView_GetSubItemRect(hwndList,cd->nmcd.dwItemSpec,cd->iSubItem,LVIR_BOUNDS,&rc);
+
+ if (cd->iSubItem==0)
+ {
+ RECT rc2;
+ char str[MAX_PATH];
+
+ ListView_GetSubItemRect(hwndList,cd->nmcd.dwItemSpec,1,LVIR_BOUNDS,&rc2);
+ rc.right=rc2.left;
+ rc.left+=2;
+ DrawTextUtf(cd->nmcd.hdc, ICQTranslateUtfStatic(setting[cd->nmcd.lItemlParam].szDescription, str), &rc, DT_END_ELLIPSIS|DT_LEFT|DT_NOCLIP|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER, NULL);
+ }
+ else
+ PaintItemSetting(cd->nmcd.hdc, &rc, cd->nmcd.lItemlParam, cd->nmcd.uItemState);
+ SetWindowLongUtf(hwndDlg,DWL_MSGRESULT,CDRF_SKIPDEFAULT);
+
+ return TRUE;
+ }
+/*
+ case CDDS_ITEMPOSTPAINT:
+ { RECT rc;
+ ListView_GetItemRect(hwndList,cd->nmcd.dwItemSpec,&rc,LVIR_BOUNDS);
+ if(cd->nmcd.uItemState&CDIS_FOCUS) {
+ HDC hdc2
+ hdc2=GetDC(hwndList); //I don't know what the listview's done to its DC, but I can't figure out how to undo it
+ DrawFocusRect(hdc2,&rc);
+ ReleaseDC(hwndList,hdc2);
+ }
+ break;
+ }
+*/
+
+ }
+ break;
+ }
+ case NM_CLICK:
+ {
+ LPNMLISTVIEW nm=(LPNMLISTVIEW)lParam;
+ LV_ITEM lvi;
+ RECT rc;
+
+ EndStringEdit(1);
+ 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(hwndList, &lvi);
+ if (!(lvi.state & LVIS_SELECTED)) break;
+ ListView_EnsureVisible(hwndList, lvi.iItem, FALSE);
+ ListView_GetSubItemRect(hwndList, lvi.iItem, lvi.iSubItem, LVIR_BOUNDS, &rc);
+ editTopIndex = ListView_GetTopIndex(hwndList);
+ switch (setting[lvi.lParam].displayType & LIM_TYPE)
+ {
+ case LI_STRING:
+ case LI_LONGSTRING:
+ case LI_NUMBER:
+ BeginStringEdit(nm->iItem, &rc, lvi. lParam, 0);
+ break;
+ case LI_LIST:
+ BeginListEdit(nm->iItem, &rc, lvi. lParam, 0);
+ break;
+ }
+ break;
+ }
+ case LVN_KEYDOWN:
+ {
+ LPNMLVKEYDOWN nm=(LPNMLVKEYDOWN)lParam;
+ LV_ITEM lvi;
+ RECT rc;
+
+ EndStringEdit(1);
+ EndListEdit(1);
+ if(nm->wVKey==VK_SPACE || nm->wVKey==VK_RETURN) nm->wVKey=0;
+ if(nm->wVKey && (nm->wVKey<'0' || (nm->wVKey>'9' && nm->wVKey<'A') || (nm->wVKey>'Z' && nm->wVKey<VK_NUMPAD0) || nm->wVKey>=VK_F1))
+ break;
+ lvi.mask=LVIF_PARAM|LVIF_STATE;
+ lvi.stateMask=0xFFFFFFFF;
+ lvi.iItem=ListView_GetNextItem(hwndList,-1,LVNI_ALL|LVNI_SELECTED);
+ if(lvi.iItem==-1) break;
+ lvi.iSubItem=1;
+ ListView_GetItem(hwndList,&lvi);
+ ListView_EnsureVisible(hwndList,lvi.iItem,FALSE);
+ ListView_GetSubItemRect(hwndList,lvi.iItem,lvi.iSubItem,LVIR_BOUNDS,&rc);
+ editTopIndex=ListView_GetTopIndex(hwndList);
+ switch(setting[lvi.lParam].displayType&LIM_TYPE)
+ {
+ case LI_STRING:
+ case LI_LONGSTRING:
+ case LI_NUMBER:
+ BeginStringEdit(lvi.iItem,&rc,lvi.lParam,nm->wVKey);
+ break;
+ case LI_LIST:
+ BeginListEdit(lvi.iItem,&rc,lvi.lParam,nm->wVKey);
+ break;
+ }
+ SetWindowLongUtf(hwndDlg,DWL_MSGRESULT,TRUE);
+ return TRUE;
+ }
+ case NM_KILLFOCUS:
+ if(!IsStringEditWindow(GetFocus())) EndStringEdit(1);
+ if(!IsListEditWindow(GetFocus())) EndListEdit(1);
+ break;
+ }
+ break;
+ }
+ break;
+ case WM_KILLFOCUS:
+ EndStringEdit(1);
+ EndListEdit(1);
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam))
+ {
+ case IDCANCEL:
+ SendMessage(GetParent(hwndDlg), msg, wParam, lParam);
+ break;
+
+ case IDC_SAVE:
+ if (!SaveSettingsToDb(hwndDlg)) break;
+ EnableDlgItem(hwndDlg, IDC_SAVE, FALSE);
+ EnableDlgItem(hwndDlg, IDC_LIST, FALSE);
+ {
+ char str[MAX_PATH];
+
+ SetDlgItemTextUtf(hwndDlg, IDC_UPLOADING, ICQTranslateUtfStatic("Upload in progress...", str));
+ }
+ EnableDlgItem(hwndDlg, IDC_UPLOADING, TRUE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_UPLOADING), SW_SHOW);
+ hAckHook = HookEventMessage(ME_PROTO_ACK, hwndDlg, DM_PROTOACK);
+
+ if (!UploadSettings(hwndDlg))
+ {
+ EnableDlgItem(hwndDlg, IDC_SAVE, TRUE);
+ EnableDlgItem(hwndDlg, IDC_LIST, TRUE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_UPLOADING), SW_HIDE);
+ UnhookEvent(hAckHook);
+ 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 = InfoDlg_Resize;
+ CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM) &urd);
+
+ { // update listview column widths
+ RECT rc;
+
+ GetClientRect(hwndList,&rc);
+ rc.right-=GetSystemMetrics(SM_CXVSCROLL);
+ ListView_SetColumnWidth(hwndList, 0, rc.right/3);
+ ListView_SetColumnWidth(hwndList, 1, rc.right - rc.right/3);
+ }
+ break;
+ }
+
+ case DM_PROTOACK:
+ {
+ ACKDATA *ack=(ACKDATA*)lParam;
+ int i,done;
+ char str[MAX_PATH];
+
+ if (ack->type != ACKTYPE_SETINFO) break;
+ if (ack->result == ACKRESULT_SUCCESS)
+ {
+ for (i=0; i<sizeof(hUpload)/sizeof(hUpload[0]); i++)
+ if (hUpload[i] && ack->hProcess == hUpload[i]) break;
+
+ if (i == sizeof(hUpload)/sizeof(hUpload[0])) break;
+ hUpload[i] = NULL;
+ for (done = 0, i = 0; i < sizeof(hUpload)/sizeof(hUpload[0]); i++)
+ done += hUpload[i] == NULL;
+ wsprintf(str,"%s%d%%", ICQTranslateUtfStatic("Upload in progress...", str), 100*done/(sizeof(hUpload)/sizeof(hUpload[0])));
+ SetDlgItemTextUtf(hwndDlg, IDC_UPLOADING, str);
+ if (done < sizeof(hUpload)/sizeof(hUpload[0])) break;
+
+ ClearChangeFlags();
+ UnhookEvent(hAckHook); hAckHook = NULL;
+ EnableDlgItem(hwndDlg, IDC_LIST, TRUE);
+ EnableDlgItem(hwndDlg, IDC_UPLOADING, FALSE);
+ SetDlgItemTextUtf(hwndDlg, IDC_UPLOADING, ICQTranslateUtfStatic("Upload complete", str));
+ SendMessage(GetParent(hwndDlg),PSM_FORCECHANGED,0,0);
+ }
+ else if (ack->result==ACKRESULT_FAILED)
+ {
+ UnhookEvent(hAckHook);
+ hAckHook = NULL;
+ EnableDlgItem(hwndDlg, IDC_LIST, TRUE);
+ EnableDlgItem(hwndDlg, IDC_UPLOADING, FALSE);
+ SetDlgItemTextUtf(hwndDlg, IDC_UPLOADING, ICQTranslateUtfStatic("Upload FAILED", str));
+ SendMessage(GetParent(hwndDlg), PSM_FORCECHANGED, 0, 0);
+ }
+ break;
+ }
+ case WM_DESTROY:
+ if(hAckHook)
+ {
+ UnhookEvent(hAckHook);
+ hAckHook=NULL;
+ }
+ //SendMessage(hwndList,WM_GETFONT,0,0);
+ DeleteObject(hMyFont);
+ FreeStoredDbSettings();
+ break;
+ }
+ return FALSE;
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/changeinfo/editlist.c b/miranda-wine/protocols/IcqOscarJ/changeinfo/editlist.c
new file mode 100644
index 0000000..7eae0fa
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/changeinfo/editlist.c
@@ -0,0 +1,173 @@
+// ---------------------------------------------------------------------------80
+// ICQ plugin for Miranda Instant Messenger
+// ________________________________________
+//
+// Copyright © 2001,2002,2003,2004 Richard Hughes, Martin Öberg
+// Copyright © 2004,2005,2006 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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/changeinfo/editlist.c,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// ChangeInfo Plugin stuff
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+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:
+ CallWindowProcUtf(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;
+
+ i=SendMessage(hwnd,LB_GETCURSEL,0,0);
+ EndListEdit(i!=LB_ERR);
+ }
+ return 0;
+ case WM_CHAR:
+ if(wParam!='\r') break;
+ {
+ int i;
+
+ i=SendMessage(hwnd,LB_GETCURSEL,0,0);
+ EndListEdit(i!=LB_ERR);
+ }
+ return 0;
+ case WM_KILLFOCUS:
+ EndListEdit(1);
+ return 0;
+ }
+ return CallWindowProcUtf(OldListEditProc,hwnd,msg,wParam,lParam);
+}
+
+
+
+void BeginListEdit(int iItem,RECT *rc,int i,WORD wVKey)
+{
+ int j,n;
+ POINT pt;
+ int itemHeight;
+ char str[MAX_PATH];
+
+ 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);
+
+ hwndListEdit=CreateWindowEx(WS_EX_TOOLWINDOW|WS_EX_TOPMOST,"LISTBOX","",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);
+ for(j=0;j<setting[i].listCount;j++)
+ {
+ n = ListBoxAddStringUtf(hwndListEdit, ((ListTypeDataItem*)setting[i].pList)[j].szValue);
+ SendMessage(hwndListEdit,LB_SETITEMDATA,n,((ListTypeDataItem*)setting[i].pList)[j].id);
+ if ((setting[i].dbType==DBVT_ASCIIZ && (!strcmpnull((char*)setting[i].value,((ListTypeDataItem*)setting[i].pList)[j].szValue))
+ || (setting[i].dbType==DBVT_ASCIIZ && (!strcmpnull((char*)setting[i].value,ICQTranslateUtfStatic(((ListTypeDataItem*)setting[i].pList)[j].szValue, str))))
+ || ((char*)setting[i].value==NULL && ((ListTypeDataItem*)setting[i].pList)[j].id==0))
+ || (setting[i].dbType!=DBVT_ASCIIZ && setting[i].value==((ListTypeDataItem*)setting[i].pList)[j].id))
+ SendMessage(hwndListEdit,LB_SETCURSEL,n,0);
+ }
+ SendMessage(hwndListEdit,LB_SETTOPINDEX,SendMessage(hwndListEdit,LB_GETCURSEL,0,0)-3,0);
+ if(itemHeight*setting[i].listCount<150)
+ SetWindowPos(hwndListEdit,0,0,0,rc->right-rc->left,itemHeight*setting[i].listCount+GetSystemMetrics(SM_CYBORDER)*2,SWP_NOZORDER|SWP_NOMOVE);
+ OldListEditProc=(WNDPROC)SetWindowLongUtf(hwndListEdit,GWL_WNDPROC,(LONG)ListEditSubclassProc);
+ if (MyAnimateWindow=(BOOL (WINAPI*)(HWND,DWORD,DWORD))GetProcAddress(GetModuleHandle("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 EndListEdit(int save)
+{
+ if(hwndListEdit==NULL || iEditItem==-1) return;
+ if(save)
+ {
+ int i;
+ LPARAM newValue;
+ i=SendMessage(hwndListEdit,LB_GETCURSEL,0,0);
+ newValue=SendMessage(hwndListEdit,LB_GETITEMDATA,i,0);
+ if (setting[iEditItem].dbType==DBVT_ASCIIZ)
+ {
+ char *szNewValue = (((ListTypeDataItem*)setting[iEditItem].pList)[i].szValue);
+ if(newValue || setting[iEditItem].displayType&LIF_ZEROISVALID)
+ {
+ setting[iEditItem].changed=strcmpnull(szNewValue,(char*)setting[iEditItem].value);
+ SAFE_FREE((char**)&setting[iEditItem].value);
+ setting[iEditItem].value=(LPARAM)null_strdup(szNewValue);
+ }
+ else
+ {
+ setting[iEditItem].changed=(char*)setting[iEditItem].value!=NULL;
+ SAFE_FREE((char**)&setting[iEditItem].value);
+ }
+ }
+ else
+ {
+ setting[iEditItem].changed=newValue!=setting[iEditItem].value;
+ setting[iEditItem].value=newValue;
+ }
+ if (setting[iEditItem].changed) EnableDlgItem(GetParent(hwndList), IDC_SAVE, TRUE);
+ }
+ ListView_RedrawItems(hwndList, iEditItem, iEditItem);
+ iEditItem = -1;
+ DestroyWindow(hwndListEdit);
+ hwndListEdit = NULL;
+}
+
+
+
+int IsListEditWindow(HWND hwnd)
+{
+ if (hwnd == hwndListEdit) return 1;
+ return 0;
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/changeinfo/editstring.c b/miranda-wine/protocols/IcqOscarJ/changeinfo/editstring.c
new file mode 100644
index 0000000..1467eb0
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/changeinfo/editstring.c
@@ -0,0 +1,362 @@
+// ---------------------------------------------------------------------------80
+// ICQ plugin for Miranda Instant Messenger
+// ________________________________________
+//
+// Copyright © 2001,2002,2003,2004 Richard Hughes, Martin Öberg
+// Copyright © 2004,2005,2006 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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/changeinfo/editstring.c,v $
+// Revision : $Revision: 3177 $
+// Last change on : $Date: 2006-06-20 03:48:02 +0400 (Втр, 20 Июн 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// ChangeInfo Plugin stuff
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+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_t *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_t)*(wcslen(str)-1));
+
+ if (*selStart>i) --*selStart;
+ if (*selEnd>i) --*selEnd;
+ }
+ }
+}
+
+
+
+static void EscapesToBinary(char *str)
+{
+ int i;
+
+ for(;*str;str++)
+ {
+ if(*str!='\\') continue;
+ if(str[1]=='n') {*str++='\r'; i++; *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(i=0;i<sizeof(escapes)/sizeof(escapes[0]);i+=2)
+ if(str[1]==escapes[i])
+ {
+ *str=escapes[i+1];
+ memmove(str+1,str+2,strlennull(str)-1);
+ break;
+ }
+ }
+}
+
+
+
+char *BinaryToEscapes(char *str)
+{
+ int extra=10,len=strlennull(str)+11,i;
+ char *out,*pout;
+
+ out=pout=(char*)SAFE_MALLOC(len);
+ for(;*str;str++)
+ {
+ if((unsigned char)*str>=' ')
+ {
+ *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*)realloc(out,len);
+ }
+ *pout++='\\';
+ for(i=0;i<sizeof(escapes)/sizeof(escapes[0]);i+=2)
+ if(*str==escapes[i+1])
+ {
+ *pout++=escapes[i];
+ extra--;
+ break;
+ }
+ if(i<sizeof(escapes)/sizeof(escapes[0])) 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)
+ {
+ EndStringEdit(0);
+ return 0;
+ }
+ if(wParam==VK_RETURN)
+ {
+ if(GetWindowLong(hwnd,GWL_STYLE)&ES_MULTILINE && !(GetKeyState(VK_CONTROL)&0x8000)) break;
+ EndStringEdit(1);
+ return 0;
+ }
+ break;
+ case WM_GETDLGCODE:
+ return DLGC_WANTALLKEYS|CallWindowProcUtf(OldStringEditProc,hwnd,msg,wParam,lParam);
+ case WM_KILLFOCUS:
+ if((HWND)wParam==hwndExpandButton) break;
+ EndStringEdit(1);
+ return 0;
+ }
+ return CallWindowProcUtf(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_t *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=CreateWindowEx(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)SetWindowLongUtf(hwndEdit,GWL_WNDPROC,(LONG)StringEditSubclassProc);
+ SendMessage(hwndEdit,WM_SETFONT,(WPARAM)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(&text);
+ }
+ break;
+ }
+ return CallWindowProcUtf(OldExpandButtonProc,hwnd,msg,wParam,lParam);
+}
+
+
+
+void 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 && !setting[i].changed)
+ szValue=" ";
+ else if ((setting[i].displayType&LIM_TYPE)==LI_NUMBER)
+ {
+ szValue=str;
+ wsprintf(str,"%d",setting[i].value);
+ }
+ else if(setting[i].value)
+ {
+ szValue=BinaryToEscapes((char*)setting[i].value);
+ alloced=1;
+ }
+ else szValue="";
+ iEditItem=iItem;
+
+ if ((setting[i].displayType&LIM_TYPE)==LI_LONGSTRING)
+ {
+ rc->right-=rc->bottom-rc->top;
+ hwndExpandButton=CreateWindow("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)SetWindowLongUtf(hwndExpandButton,GWL_WNDPROC,(LONG)ExpandButtonSubclassProc);
+ }
+
+ hwndEdit=CreateWindow("EDIT","",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)SetWindowLongUtf(hwndEdit,GWL_WNDPROC,(LONG)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,"",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,setting[i].value);
+ if(!(setting[i].displayType&LIF_ZEROISVALID) && setting[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 EndStringEdit(int save)
+{
+ if (hwndEdit == NULL || iEditItem == -1) return;
+ if (save)
+ {
+ char *text = NULL;
+
+ text=(char*)SAFE_MALLOC(GetWindowTextLength(hwndEdit)+1);
+ GetWindowText(hwndEdit,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(newValue<range[0]) newValue=range[0];
+ if(newValue>range[1]) newValue=range[1];
+ }
+ setting[iEditItem].changed=setting[iEditItem].value!=newValue;
+ setting[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*)setting[iEditItem].value) && (strlennull(text) + strlennull((char*)setting[iEditItem].value))))
+ {
+ SAFE_FREE((char**)&setting[iEditItem].value);
+ if (text[0])
+ setting[iEditItem].value=(LPARAM)text;
+ else
+ {
+ setting[iEditItem].value=0;
+ SAFE_FREE(&text);
+ }
+ setting[iEditItem].changed=1;
+ }
+ }
+ if (setting[iEditItem].changed) EnableDlgItem(GetParent(hwndList), IDC_SAVE, TRUE);
+ }
+ ListView_RedrawItems(hwndList, iEditItem, iEditItem);
+ iEditItem = -1;
+ 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/miranda-wine/protocols/IcqOscarJ/changeinfo/expandst.ico b/miranda-wine/protocols/IcqOscarJ/changeinfo/expandst.ico
new file mode 100644
index 0000000..17367fe
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/changeinfo/expandst.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/changeinfo/main.c b/miranda-wine/protocols/IcqOscarJ/changeinfo/main.c
new file mode 100644
index 0000000..3b550d5
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/changeinfo/main.c
@@ -0,0 +1,54 @@
+// ---------------------------------------------------------------------------80
+// ICQ plugin for Miranda Instant Messenger
+// ________________________________________
+//
+// Copyright © 2001,2002,2003,2004 Richard Hughes, Martin Öberg
+// Copyright © 2004,2005,2006 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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/changeinfo/main.c,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// ChangeInfo Plugin stuff
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+int InitChangeDetails(WPARAM wParam, LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = {0};
+
+ if (lParam) return 0;
+
+ odp.cbSize = sizeof(odp);
+ odp.hIcon = NULL;
+ odp.hInstance = hInst;
+ odp.position = -1899999999;
+ odp.pszTemplate = MAKEINTRESOURCE(IDD_INFO_CHANGEINFO);
+ odp.pfnDlgProc = ChangeInfoDlgProc;
+
+ AddUserInfoPageUtf(&odp, wParam, "%s Details");
+
+ return 0;
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/changeinfo/upload.c b/miranda-wine/protocols/IcqOscarJ/changeinfo/upload.c
new file mode 100644
index 0000000..feb71b2
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/changeinfo/upload.c
@@ -0,0 +1,204 @@
+// ---------------------------------------------------------------------------80
+// ICQ plugin for Miranda Instant Messenger
+// ________________________________________
+//
+// Copyright © 2001,2002,2003,2004 Richard Hughes, Martin Öberg
+// Copyright © 2004,2005,2006 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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/changeinfo/upload.c,v $
+// Revision : $Revision: 2991 $
+// Last change on : $Date: 2006-05-30 21:55:48 +0400 (Втр, 30 Май 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// ChangeInfo Plugin stuff
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+
+int StringToListItemId(const char *szSetting,int def)
+{
+ int i,listCount;
+ char szTmp[256];
+ ListTypeDataItem *list;
+
+ for(i=0;i<settingCount;i++)
+ if(!strcmpnull(szSetting,setting[i].szDbSetting))
+ break;
+
+ if(i==settingCount) return def;
+
+ list=(ListTypeDataItem*)setting[i].pList;
+ listCount=setting[i].listCount;
+
+ if(ICQGetContactStaticString(NULL, szSetting, szTmp, sizeof(szTmp)))
+ return def;
+
+ for(i=0;i<listCount;i++)
+ if(!strcmpnull(list[i].szValue, szTmp)) break;
+
+ if(i==listCount) return def;
+
+ return list[i].id;
+}
+
+
+
+int UploadSettings(HWND hwndParent)
+{
+ PBYTE buf = NULL;
+ int buflen = 0;
+/* BYTE b;
+ WORD w;*/
+
+ if (!icqOnline)
+ {
+ char str[1024],cap[MAX_PATH];
+
+ MessageBoxUtf(hwndParent, ICQTranslateUtfStatic("You are not currently connected to the ICQ network. You must be online in order to update your information on the server.", str), ICQTranslateUtfStatic("Change ICQ Details", cap), MB_OK);
+ return 0;
+ }
+
+/* // userinfo
+ ppackTLVWord(&buf, &buflen, (WORD)GetACP(), TLV_CODEPAGE, 0);
+
+ b = !ICQGetContactSettingByte(NULL, "PublishPrimaryEmail", 0);
+ ppackTLVLNTSBytefromDB(&buf, &buflen, "e-mail", b, TLV_EMAIL);
+ ppackTLVLNTSBytefromDB(&buf, &buflen, "e-mail0", 0, TLV_EMAIL);
+ ppackTLVLNTSBytefromDB(&buf, &buflen, "e-mail1", 0, TLV_EMAIL);
+
+ ppackTLVByte(&buf, &buflen, ICQGetContactSettingByte(NULL, "AllowSpam", 0), TLV_ALLOWSPAM, 1);
+
+ ppackTLVLNTSfromDB(&buf, &buflen, "Phone", TLV_PHONE);
+ ppackTLVLNTSfromDB(&buf, &buflen, "Fax", TLV_FAX);
+ ppackTLVLNTSfromDB(&buf, &buflen, "Cellular", TLV_MOBILE);
+ ppackTLVLNTSfromDB(&buf, &buflen, "CompanyPhone", TLV_WORKPHONE);
+ ppackTLVLNTSfromDB(&buf, &buflen, "CompanyFax", TLV_WORKFAX);
+
+ ppackTLVLNTSfromDB(&buf, &buflen, "Nick", TLV_NICKNAME);
+ ppackTLVLNTSfromDB(&buf, &buflen, "FirstName", TLV_FIRSTNAME);
+ ppackTLVLNTSfromDB(&buf, &buflen, "LastName", TLV_LASTNAME);
+ ppackTLVLNTSfromDB(&buf, &buflen, "About", TLV_ABOUT);
+
+ ppackTLVWord(&buf, &buflen, ICQGetContactSettingWord(NULL, "Age", 0), TLV_AGE, 1);
+ b = ICQGetContactSettingByte(NULL, "Gender", 0);
+ ppackTLVByte(&buf, &buflen, (BYTE)(b ? (b == 'M' ? 2 : 1) : 0), TLV_GENDER, 1);
+ ppackLEWord(&buf, &buflen, TLV_BIRTH);
+ ppackLEWord(&buf, &buflen, 0x06);
+ ppackLEWord(&buf, &buflen, ICQGetContactSettingWord(NULL, "BirthYear", 0));
+ ppackLEWord(&buf, &buflen, (WORD)ICQGetContactSettingByte(NULL, "BirthMonth", 0));
+ ppackLEWord(&buf, &buflen, (WORD)ICQGetContactSettingByte(NULL, "BirthDay", 0));
+
+ ppackTLVWord(&buf, &buflen, (WORD)StringToListItemId("Language1", 0), TLV_LANGUAGE, 1);
+ ppackTLVWord(&buf, &buflen, (WORD)StringToListItemId("Language2", 0), TLV_LANGUAGE, 1);
+ ppackTLVWord(&buf, &buflen, (WORD)StringToListItemId("Language3", 0), TLV_LANGUAGE, 1);
+
+ ppackTLVLNTSfromDB(&buf, &buflen, "CompanyDepartment", TLV_DEPARTMENT);
+ ppackTLVLNTSfromDB(&buf, &buflen, "CompanyPosition", TLV_POSITION);
+ ppackTLVLNTSfromDB(&buf, &buflen, "Company", TLV_COMPANY);
+ ppackTLVLNTSfromDB(&buf, &buflen, "CompanyStreet", TLV_WORKSTREET);
+ ppackTLVLNTSfromDB(&buf, &buflen, "CompanyState", TLV_WORKSTATE);
+ ppackTLVLNTSfromDB(&buf, &buflen, "CompanyCity", TLV_WORKCITY);
+ ppackTLVLNTSfromDB(&buf, &buflen, "CompanyHomepage", TLV_WORKURL);
+ ppackTLVLNTSfromDB(&buf, &buflen, "CompanyZIP", TLV_WORKZIPCODE);
+ ppackTLVWord(&buf, &buflen, ICQGetContactSettingWord(NULL, "CompanyCountry", 0), TLV_WORKCOUNTRY, 1);
+ ppackTLVWord(&buf, &buflen, ICQGetContactSettingWord(NULL, "CompanyOccupation", 0), TLV_OCUPATION, 1);
+
+ ppackTLVLNTSfromDB(&buf, &buflen, "City", TLV_CITY);
+ ppackTLVLNTSfromDB(&buf, &buflen, "State", TLV_STATE);
+ ppackTLVWord(&buf, &buflen, ICQGetContactSettingWord(NULL, "Country", 0), TLV_COUNTRY, 1);
+ ppackTLVLNTSfromDB(&buf, &buflen, "OriginCity", TLV_ORGCITY);
+ ppackTLVLNTSfromDB(&buf, &buflen, "OriginState", TLV_ORGSTATE);
+ ppackTLVWord(&buf, &buflen, ICQGetContactSettingWord(NULL, "OriginCountry", 0), TLV_ORGCOUNTRY, 1);
+ ppackTLVLNTSfromDB(&buf, &buflen, "Street", TLV_STREET);
+ ppackTLVLNTSfromDB(&buf, &buflen, "ZIP", TLV_ZIPCODE);
+
+ ppackTLVLNTSfromDB(&buf, &buflen, "Homepage", TLV_URL);
+
+ ppackTLVByte(&buf, &buflen, ICQGetContactSettingByte(NULL, "Timezone", 0), TLV_TIMEZONE, 1);
+
+ ppackTLVByte(&buf, &buflen, ICQGetContactSettingByte(NULL, "MaritalStatus", 0), TLV_MARITAL, 1);
+
+ w = StringToListItemId("Interest0Cat", 0);
+ ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Interest0Text", TLV_INTERESTS);
+ w = StringToListItemId("Interest1Cat", 0);
+ ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Interest1Text", TLV_INTERESTS);
+ w = StringToListItemId("Interest2Cat", 0);
+ ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Interest2Text", TLV_INTERESTS);
+ w = StringToListItemId("Interest3Cat", 0);
+ ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Interest3Text", TLV_INTERESTS);
+
+ 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);
+
+ hUpload[0] = (HANDLE)icq_changeUserDetailsServ(META_SET_FULLINFO_REQ, buf, (WORD)buflen);*/
+ hUpload[0] = (HANDLE)IcqChangeInfoEx(CIXT_FULL, 0);
+
+ //password
+ {
+ char* tmp;
+
+ tmp = GetUserPassword(TRUE);
+ if(tmp)
+ {
+ if (strlennull(Password) > 0 && strcmpnull(Password, tmp))
+ {
+ buflen = 0; // re-init buffer
+
+ ppackLELNTS(&buf, &buflen, tmp);
+
+ hUpload[1] = (HANDLE)icq_changeUserDetailsServ(META_SET_PASSWORD_REQ, buf, (WORD)buflen);
+
+ {
+ char szPwd[16] = {0};
+
+ if (!ICQGetContactStaticString(NULL, "Password", szPwd, 16) && strlennull(szPwd))
+ { // password is stored in DB, update
+ char ptmp[16];
+
+ strcpy(ptmp, tmp);
+
+ CallService(MS_DB_CRYPT_ENCODESTRING, sizeof(ptmp), (LPARAM)ptmp);
+
+ ICQWriteContactSettingString(NULL, "Password", ptmp);
+ }
+ }
+ }
+ }
+ }
+
+ SAFE_FREE(&buf);
+
+ return 1;
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/channels.h b/miranda-wine/protocols/IcqOscarJ/channels.h
new file mode 100644
index 0000000..edaf0c7
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/channels.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,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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/channels.h,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#ifndef __CHANNELS_H
+#define __CHANNELS_H
+
+int unpackSnacHeader(snac_header* pSnacHeader, unsigned char **pBuffer, WORD* pwBufferLength);
+void handleLoginChannel(unsigned char *buf, WORD datalen, serverthread_info *info);
+void handleErrorChannel(unsigned char *buf, WORD datalen);
+void handleDataChannel(unsigned char *buf, WORD wLen, serverthread_info *info);
+void handlePingChannel(unsigned char *buf, WORD wLen);
+void handleCloseChannel(unsigned char *buf, WORD datalen, serverthread_info *info);
+
+void LogFamilyError(WORD wFamily, WORD wError);
+
+void StartKeepAlive();
+void StopKeepAlive();
+
+#endif /* __CHANNELS_H */
diff --git a/miranda-wine/protocols/IcqOscarJ/cookies.c b/miranda-wine/protocols/IcqOscarJ/cookies.c
new file mode 100644
index 0000000..b33434a
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/cookies.c
@@ -0,0 +1,365 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/cookies.c,v $
+// Revision : $Revision: 3343 $
+// Last change on : $Date: 2006-07-19 03:36:21 +0400 (Срд, 19 Июл 2006) $
+// Last change by : $Author: rainwater $
+//
+// DESCRIPTION:
+//
+// Handles packet & message cookies
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+
+static WORD wCookieSeq;
+static icq_cookie_info *cookie = NULL;
+static int cookieCount = 0;
+static int cookieSize = 0;
+CRITICAL_SECTION cookieMutex; // we want this in avatar thread, used as queue lock
+
+static int ResizeCookieList(int nSize)
+{
+ if ((cookieSize < nSize) || ((cookieSize > nSize + 6) && nSize))
+ {
+ icq_cookie_info *pNew;
+ int newSize;
+
+ if (cookieSize < nSize)
+ newSize = cookieSize + 4;
+ else
+ newSize = cookieSize - 4;
+
+ pNew = (icq_cookie_info *)realloc(cookie, sizeof(icq_cookie_info) * newSize);
+
+ if (!pNew)
+ { // realloc failed, cookies intact... try again
+ NetLog_Server("ResizeCookieList: realloc failed.");
+
+ return 1; // Failure
+ }
+ else
+ {
+ cookie = pNew;
+ cookieSize = newSize;
+ }
+ }
+ return 0; // Success
+}
+
+
+#define INVALID_COOKIE_INDEX -1
+
+static int FindCookieIndex(DWORD dwCookie)
+{
+ int i;
+
+ for (i = 0; i < cookieCount; i++)
+ {
+ if (dwCookie == cookie[i].dwCookie)
+ {
+ return i;
+ }
+ }
+ return INVALID_COOKIE_INDEX;
+}
+
+
+
+static void RemoveCookieIndex(int iCookie)
+{
+ cookieCount--;
+ memmove(&cookie[iCookie], &cookie[iCookie + 1], sizeof(icq_cookie_info) * (cookieCount - iCookie));
+ ResizeCookieList(cookieCount);
+}
+
+
+
+static void RemoveExpiredCookies()
+{
+ int i;
+ DWORD tNow = time(NULL);
+
+ for (i = 0; i < cookieCount; i++)
+ {
+ if ((cookie[i].dwTime + COOKIE_TIMEOUT) < tNow)
+ { // cookie expired, remove too
+ RemoveCookieIndex(i);
+ i--; // fix the loop
+ }
+ }
+}
+
+
+
+void InitCookies(void)
+{
+ InitializeCriticalSection(&cookieMutex);
+
+ cookieCount = 0;
+ cookieSize = 0;
+ cookie = NULL;
+ wCookieSeq = 2;
+
+ ResizeCookieList(4);
+}
+
+
+
+void UninitCookies(void)
+{
+ SAFE_FREE(&cookie);
+
+ DeleteCriticalSection(&cookieMutex);
+}
+
+
+
+// Generate and allocate cookie
+DWORD AllocateCookie(BYTE bType, WORD wIdent, DWORD dwUin, void *pvExtra)
+{
+ DWORD dwThisSeq;
+
+ EnterCriticalSection(&cookieMutex);
+
+ if (ResizeCookieList(cookieCount + 1))
+ { // resizing failed...
+ LeaveCriticalSection(&cookieMutex);
+ // this is horrible, but can't do anything better
+ return GenerateCookie(wIdent);
+ }
+
+ dwThisSeq = wCookieSeq++;
+ dwThisSeq &= 0x7FFF;
+ dwThisSeq |= wIdent<<0x10;
+
+ cookie[cookieCount].bType = bType;
+ cookie[cookieCount].dwCookie = dwThisSeq;
+ cookie[cookieCount].dwUin = dwUin;
+ cookie[cookieCount].pvExtra = pvExtra;
+ cookie[cookieCount].dwTime = time(NULL);
+ cookieCount++;
+
+ LeaveCriticalSection(&cookieMutex);
+
+ return dwThisSeq;
+}
+
+
+
+DWORD GenerateCookie(WORD wIdent)
+{
+ DWORD dwThisSeq;
+
+ EnterCriticalSection(&cookieMutex);
+ dwThisSeq = wCookieSeq++;
+ dwThisSeq &= 0x7FFF;
+ dwThisSeq |= wIdent<<0x10;
+ LeaveCriticalSection(&cookieMutex);
+
+ return dwThisSeq;
+}
+
+
+
+int GetCookieType(DWORD dwCookie)
+{
+ int i;
+
+ EnterCriticalSection(&cookieMutex);
+
+ i = FindCookieIndex(dwCookie);
+
+ if (i != INVALID_COOKIE_INDEX)
+ i = cookie[i].bType;
+
+ LeaveCriticalSection(&cookieMutex);
+
+ return i;
+}
+
+
+
+int FindCookie(DWORD dwCookie, DWORD *pdwUin, void **ppvExtra)
+{
+ int i;
+ int nFound = 0;
+
+
+ EnterCriticalSection(&cookieMutex);
+
+ i = FindCookieIndex(dwCookie);
+
+ if (i != INVALID_COOKIE_INDEX)
+ {
+ if (pdwUin)
+ *pdwUin = cookie[i].dwUin;
+ if (ppvExtra)
+ *ppvExtra = cookie[i].pvExtra;
+
+ // Cookie found
+ nFound = 1;
+ }
+
+ LeaveCriticalSection(&cookieMutex);
+
+ return nFound;
+}
+
+
+
+int FindCookieByData(void *pvExtra,DWORD *pdwCookie, DWORD *pdwUin)
+{
+ int i;
+ int nFound = 0;
+
+
+ EnterCriticalSection(&cookieMutex);
+
+ for (i = 0; i < cookieCount; i++)
+ {
+ if (pvExtra == cookie[i].pvExtra)
+ {
+ if (pdwUin)
+ *pdwUin = cookie[i].dwUin;
+ if (pdwCookie)
+ *pdwCookie = cookie[i].dwCookie;
+
+ // Cookie found, exit loop
+ nFound = 1;
+ break;
+
+ }
+ }
+
+ LeaveCriticalSection(&cookieMutex);
+
+ return nFound;
+}
+
+
+
+int FindMessageCookie(DWORD dwMsgID1, DWORD dwMsgID2, DWORD *pdwCookie, DWORD *pdwUin, message_cookie_data **ppvExtra)
+{
+ int i;
+ int nFound = 0;
+
+
+ EnterCriticalSection(&cookieMutex);
+
+ for (i = 0; i < cookieCount; i++)
+ {
+ if (cookie[i].bType == CKT_MESSAGE || cookie[i].bType == CKT_FILE || cookie[i].bType == CKT_REVERSEDIRECT)
+ { // message cookie found
+ message_cookie_data *pCookie = (message_cookie_data*)cookie[i].pvExtra;
+
+ if (pCookie->dwMsgID1 == dwMsgID1 && pCookie->dwMsgID2 == dwMsgID2)
+ {
+ if (pdwUin)
+ *pdwUin = cookie[i].dwUin;
+ if (pdwCookie)
+ *pdwCookie = cookie[i].dwCookie;
+ if (ppvExtra)
+ *ppvExtra = pCookie;
+
+ // Cookie found, exit loop
+ nFound = 1;
+ break;
+ }
+ }
+ }
+
+ LeaveCriticalSection(&cookieMutex);
+
+ return nFound;
+}
+
+
+
+void FreeCookie(DWORD dwCookie)
+{
+ int i;
+
+ EnterCriticalSection(&cookieMutex);
+
+ i = FindCookieIndex(dwCookie);
+
+ if (i != INVALID_COOKIE_INDEX)
+ { // Cookie found, remove from list
+ RemoveCookieIndex(i);
+ }
+ RemoveExpiredCookies();
+
+ LeaveCriticalSection(&cookieMutex);
+}
+
+
+
+void ReleaseCookie(DWORD dwCookie)
+{
+ int i;
+
+ EnterCriticalSection(&cookieMutex);
+
+ i = FindCookieIndex(dwCookie);
+
+ if (i != INVALID_COOKIE_INDEX)
+ { // Cookie found, remove from list
+ SAFE_FREE(&cookie[i].pvExtra);
+ RemoveCookieIndex(i);
+ }
+ RemoveExpiredCookies();
+
+ LeaveCriticalSection(&cookieMutex);
+}
+
+
+
+message_cookie_data *CreateMessageCookie(WORD bMsgType, BYTE bAckType)
+{
+ message_cookie_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));
+
+ pCookie = (message_cookie_data*)SAFE_MALLOC(sizeof(message_cookie_data));
+ if (pCookie)
+ {
+ pCookie->bMessageType = bMsgType;
+ pCookie->nAckType = bAckType;
+ pCookie->dwMsgID1 = dwMsgID1;
+ pCookie->dwMsgID2 = dwMsgID2;
+ }
+ return pCookie;
+} \ No newline at end of file
diff --git a/miranda-wine/protocols/IcqOscarJ/cookies.h b/miranda-wine/protocols/IcqOscarJ/cookies.h
new file mode 100644
index 0000000..99dca6e
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/cookies.h
@@ -0,0 +1,140 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/cookies.h,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// 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_AVATAR 0x20
+
+typedef struct icq_cookie_info_s
+{
+ DWORD dwCookie;
+ DWORD dwUin;
+ void *pvExtra;
+ DWORD dwTime;
+ BYTE bType;
+} icq_cookie_info;
+
+typedef struct familyrequest_rec_s
+{
+ WORD wFamily;
+ void (*familyhandler)(HANDLE hConn, char* cookie, WORD cookieLen);
+} familyrequest_rec;
+
+
+typedef struct message_cookie_data_s
+{
+ DWORD dwMsgID1;
+ DWORD dwMsgID2;
+ WORD bMessageType;
+ BYTE nAckType;
+} message_cookie_data;
+
+#define ACKTYPE_NONE 0
+#define ACKTYPE_SERVER 1
+#define ACKTYPE_CLIENT 2
+
+
+typedef struct fam15_cookie_data_s
+{
+ BYTE bRequestType;
+ HANDLE hContact;
+} fam15_cookie_data;
+
+#define REQUESTTYPE_OWNER 0
+#define REQUESTTYPE_USERAUTO 1
+#define REQUESTTYPE_USERMINIMAL 2
+#define REQUESTTYPE_USERDETAILED 3
+#define REQUESTTYPE_PROFILE 4
+
+
+typedef struct search_cookie_s
+{
+ BYTE bSearchType;
+ char* szObject;
+ DWORD dwMainId;
+ DWORD dwStatus;
+} search_cookie;
+
+#define SEARCHTYPE_UID 0
+#define SEARCHTYPE_EMAIL 1
+#define SEARCHTYPE_NAMES 2
+#define SEARCHTYPE_DETAILS 4
+
+typedef struct avatarcookie_t
+{
+ DWORD dwUin;
+ HANDLE hContact;
+ unsigned int hashlen;
+ char *hash;
+ unsigned int cbData;
+ char *szFile;
+} avatarcookie;
+
+typedef struct {
+ message_cookie_data pMessage;
+ HANDLE hContact;
+ DWORD dwUin;
+ int type;
+ void *ft;
+} reverse_cookie;
+
+
+void InitCookies(void);
+void UninitCookies(void);
+
+DWORD AllocateCookie(BYTE bType, WORD wIdent, DWORD dwUin, void *pvExtra);
+void FreeCookie(DWORD dwCookie);
+void ReleaseCookie(DWORD dwCookie);
+DWORD GenerateCookie(WORD wIdent);
+
+int GetCookieType(DWORD dwCookie);
+
+int FindCookie(DWORD wCookie, DWORD *pdwUin, void **ppvExtra);
+int FindCookieByData(void *pvExtra, DWORD *pdwCookie, DWORD *pdwUin);
+int FindMessageCookie(DWORD dwMsgID1, DWORD dwMsgID2, DWORD *pdwCookie, DWORD *pdwUin, message_cookie_data **ppvExtra);
+
+message_cookie_data *CreateMessageCookie(WORD bMsgType, BYTE bAckType);
+
+#endif /* __COOKIES_H */
diff --git a/miranda-wine/protocols/IcqOscarJ/directpackets.c b/miranda-wine/protocols/IcqOscarJ/directpackets.c
new file mode 100644
index 0000000..01e2975
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/directpackets.c
@@ -0,0 +1,303 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/directpackets.c,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+extern HANDLE hsmsgrequest;
+extern CRITICAL_SECTION modeMsgsMutex;
+extern WORD wListenPort;
+
+extern packEmptyMsg(icq_packet *packet);
+
+
+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 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, szCap, 0x26); /* GUID */
+ }
+ }
+ EncryptDirectPacket(dc, &packet);
+ sendDirectPacket(dc, &packet);
+
+ NetLog_Direct("Sent acknowledgement thru direct connection");
+}
+
+
+
+DWORD icq_sendGetAwayMsgDirect(HANDLE hContact, int type)
+{
+ icq_packet packet;
+ DWORD dwCookie;
+ message_cookie_data *pCookieData;
+
+ if (ICQGetContactSettingWord(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, ICQGetContactSettingUIN(hContact), (void*)pCookieData);
+
+ packDirectMsgHeader(&packet, 3, DIRECT_MESSAGE, dwCookie, (BYTE)type, 3, 1, 0);
+ packEmptyMsg(&packet); // message
+
+ if (SendDirectMessage(hContact, &packet))
+ return dwCookie; // Success
+ else
+ return 0;
+}
+
+
+
+void icq_sendAwayMsgReplyDirect(directconnect* dc, WORD wCookie, BYTE msgType, const char** szMsg)
+{
+ icq_packet packet;
+ WORD wMsgLen;
+
+
+ if (validateStatusMessageRequest(dc->hContact, msgType))
+ {
+ NotifyEventHooks(hsmsgrequest, (WPARAM)msgType, (LPARAM)dc->dwRemoteUin);
+
+ EnterCriticalSection(&modeMsgsMutex);
+
+ if (szMsg && *szMsg)
+ {
+ char* szAnsiMsg;
+
+ // prepare Ansi message - only Ansi supported
+ wMsgLen = strlennull(*szMsg) + 1;
+ 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, szAnsiMsg, (WORD)(wMsgLen + 1));
+ EncryptDirectPacket(dc, &packet);
+
+ sendDirectPacket(dc, &packet);
+ }
+
+ LeaveCriticalSection(&modeMsgsMutex);
+ }
+}
+
+
+
+void 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 icq_sendFileDenyDirect(HANDLE hContact, filetransfer* ft, char *szReason)
+{ // v7 packet
+ icq_packet packet;
+
+ packDirectMsgHeader(&packet, (WORD)(18+strlennull(szReason)), DIRECT_ACK, ft->dwCookie, MTYPE_FILEREQ, 0, 1, 0);
+ packLEWord(&packet, (WORD)(1+strlennull(szReason))); // description
+ if (szReason) packBuffer(&packet, szReason, (WORD)strlennull(szReason));
+ 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);
+
+ SendDirectMessage(hContact, &packet);
+
+ NetLog_Direct("Sent file deny direct.");
+}
+
+
+
+int icq_sendFileSendDirectv7(filetransfer *ft, const char* pszFiles)
+{
+ icq_packet packet;
+ WORD wDescrLen = strlennull(ft->szDescription), wFilesLen = strlennull(pszFiles);
+
+ packDirectMsgHeader(&packet, (WORD)(18 + wDescrLen + wFilesLen), DIRECT_MESSAGE, (WORD)ft->dwCookie, MTYPE_FILEREQ, 0, 0, 0);
+ packLEWord(&packet, (WORD)(wDescrLen + 1));
+ packBuffer(&packet, ft->szDescription, (WORD)(wDescrLen + 1));
+ packLEDWord(&packet, 0); // listen port
+ packLEWord(&packet, (WORD)(wFilesLen + 1));
+ packBuffer(&packet, pszFiles, (WORD)(wFilesLen + 1));
+ packLEDWord(&packet, ft->dwTotalSize);
+ packLEDWord(&packet, 0); // listen port (again)
+
+ NetLog_Direct("Sending v%u file transfer request direct", 7);
+
+ return SendDirectMessage(ft->hContact, &packet);
+}
+
+
+
+int icq_sendFileSendDirectv8(filetransfer *ft, const char *pszFiles)
+{
+ icq_packet packet;
+ WORD wDescrLen = strlennull(ft->szDescription), wFilesLen = strlennull(pszFiles);
+
+ 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, ft->szDescription, wDescrLen);
+ packWord(&packet, 0x8c82); // Unknown (port?), seen 0x80F6
+ packWord(&packet, 0x0222); // Unknown, seen 0x2e01
+ packLEWord(&packet, (WORD)(wFilesLen + 1));
+ packBuffer(&packet, pszFiles, (WORD)(wFilesLen + 1));
+ packLEDWord(&packet, ft->dwTotalSize);
+ packLEDWord(&packet, 0x0008c82); // Unknown, (seen 0xf680 ~33000)
+
+ NetLog_Direct("Sending v%u file transfer request direct", 8);
+
+ return SendDirectMessage(ft->hContact, &packet);
+}
+
+
+
+DWORD icq_SendDirectMessage(DWORD dwUin, HANDLE hContact, const char *szMessage, int nBodyLength, WORD wPriority, message_cookie_data *pCookieData, char *szCap)
+{
+ icq_packet packet;
+ DWORD dwCookie;
+
+
+ dwCookie = AllocateCookie(CKT_MESSAGE, 0, dwUin, (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, szMessage, (WORD)(nBodyLength+1)); // Message
+ packMsgColorInfo(&packet);
+ if (szCap)
+ {
+ packLEDWord(&packet, 0x00000026); // length of GUID
+ packBuffer(&packet, szCap, 0x26); // UTF-8 GUID
+ }
+
+ if (SendDirectMessage(hContact, &packet))
+ return dwCookie; // Success
+ else
+ {
+ FreeCookie(dwCookie); // release cookie
+
+ return 0; // Failure
+ }
+}
+
+
+
+void icq_sendXtrazRequestDirect(DWORD dwUin, 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, szBody, (WORD)nBodyLen);
+
+ SendDirectMessage(hContact, &packet);
+}
+
+
+
+void icq_sendXtrazResponseDirect(DWORD dwUin, 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, szBody, (WORD)nBodyLen);
+
+ SendDirectMessage(hContact, &packet);
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/directpackets.h b/miranda-wine/protocols/IcqOscarJ/directpackets.h
new file mode 100644
index 0000000..168ec66
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/directpackets.h
@@ -0,0 +1,55 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/directpackets.h,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#ifndef __ICQ_DIRECTPACKETS_H
+#define __ICQ_DIRECTPACKETS_H
+
+// Direct packet senders
+void packDirectMsgHeader(icq_packet *packet, WORD wDataLen, WORD wCommand, DWORD dwCookie, BYTE bMsgType, BYTE bMsgFlags, WORD wX1, WORD wX2);
+
+void icq_sendDirectMsgAck(directconnect* dc, WORD wCookie, BYTE bMsgType, BYTE bMsgFlags, char* szCap);
+
+DWORD icq_sendGetAwayMsgDirect(HANDLE hContact, int type);
+int icq_sendFileSendDirectv7(filetransfer *ft, const char *pszFiles);
+int icq_sendFileSendDirectv8(filetransfer *ft, const char *pszFiles);
+void icq_sendFileAcceptDirect(HANDLE hContact, filetransfer *ft);
+void icq_sendFileDenyDirect(HANDLE hContact, filetransfer* ft, char *szReason);
+DWORD icq_SendDirectMessage(DWORD dwUin, HANDLE hContact, const char *szMessage, int nBodyLength, WORD wPriority, message_cookie_data *pCookieData, char *szCap);
+
+void icq_sendXtrazRequestDirect(DWORD dwUin, HANDLE hContact, DWORD dwCookie, char* szBody, int nBodyLen, WORD wType);
+void icq_sendXtrazResponseDirect(DWORD dwUin, HANDLE hContact, WORD wCookie, char* szBody, int nBodyLen, WORD wType);
+
+#endif /* __ICQ_DIRECTPACKETS_H */
diff --git a/miranda-wine/protocols/IcqOscarJ/fam_01service.c b/miranda-wine/protocols/IcqOscarJ/fam_01service.c
new file mode 100644
index 0000000..c855124
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/fam_01service.c
@@ -0,0 +1,1014 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/fam_01service.c,v $
+// Revision : $Revision: 3663 $
+// Last change on : $Date: 2006-08-31 00:18:59 +0400 (Чтв, 31 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+extern int gbIdleAllow;
+extern int icqGoingOnlineStatus;
+extern BYTE gbOverRate;
+extern int pendingAvatarsStart;
+extern DWORD dwLocalInternalIP;
+extern WORD wListenPort;
+extern DWORD dwLocalDirectConnCookie;
+extern CRITICAL_SECTION modeMsgsMutex;
+
+extern const capstr capXStatus[];
+
+void setUserInfo();
+
+char* calcMD5Hash(char* szFile);
+
+
+void handleServiceFam(unsigned char* 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 icq5 (haven't changed since at least 2002a)
+ serverPacketInit(&packet, 50);
+ packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_FAMILIES);
+ 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");
+ NetLog_Server("Sending Rate Info Ack");
+#endif
+ /* Don't really care about this now, just send the ack */
+ serverPacketInit(&packet, 20);
+ packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_RATE_ACK);
+ packDWord(&packet, 0x00010002);
+ packDWord(&packet, 0x00030004);
+ packWord(&packet, 0x0005);
+ 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 (gbSsiEnabled)
+ {
+ DWORD dwLastUpdate;
+ WORD wRecordCount;
+ servlistcookie* ack;
+ DWORD dwCookie;
+
+ dwLastUpdate = ICQGetContactSettingDword(NULL, "SrvLastUpdate", 0);
+ wRecordCount = ICQGetContactSettingWord(NULL, "SrvRecordCount", 0);
+
+ // CLI_REQLISTS - we want to use SSI
+#ifdef _DEBUG
+ NetLog_Server("Requesting roster rights");
+#endif
+ serverPacketInit(&packet, 10);
+ packFNACHeader(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_CLI_REQLISTS);
+ 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 = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie));
+ 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;
+
+ packFNACHeaderFull(&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 = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie));
+ 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;
+
+ packFNACHeaderFull(&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, 10);
+ packFNACHeader(&packet, ICQ_BUDDY_FAMILY, ICQ_USER_CLI_REQBUDDY);
+ 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:
+ {
+ oscar_tlv_chain *chain = NULL;
+
+#ifdef _DEBUG
+ NetLog_Server("Server migration requested (Flags: %u)", pSnacHeader->wFlags);
+#endif
+ pBuffer += 2; // Unknown, seen: 0
+ wBufferLength -= 2;
+ chain = readIntoTLVChain(&pBuffer, wBufferLength, 0);
+
+ if (info->cookieDataLen > 0)
+ SAFE_FREE(&info->cookieData);
+
+ info->newServer = getStrFromChain(chain, 0x05, 1);
+ info->cookieData = getStrFromChain(chain, 0x06, 1);
+ info->cookieDataLen = getLenFromChain(chain, 0x06, 1);
+
+ if (!info->newServer || !info->cookieData)
+ {
+ icq_LogMessage(LOG_FATAL, "A server migration has failed because the server returned invalid data. You must reconnect manually.");
+ SAFE_FREE(&info->newServer);
+ SAFE_FREE(&info->cookieData);
+ info->cookieDataLen = 0;
+ info->newServerReady = 0;
+ return;
+ }
+
+ disposeChain(&chain);
+ NetLog_Server("Migration has started. New server will be %s", info->newServer);
+
+ icqGoingOnlineStatus = gnCurrentStatus;
+ 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;
+
+ 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 = getDWordFromChain(chain, 10, 1);
+ ICQWriteContactSettingDword(NULL, "IP", dwValue);
+
+ // Save member since timestamp
+ dwValue = getDWordFromChain(chain, 5, 1);
+ if (dwValue) ICQWriteContactSettingDword(NULL, "MemberTS", dwValue);
+
+ dwValue = getDWordFromChain(chain, 3, 1);
+ ICQWriteContactSettingDword(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 (!gbSsiEnabled || info->isMigrating)
+ handleServUINSettings(wListenPort, info);
+ }
+ }
+ break;
+
+ case ICQ_SERVER_RATE_CHANGE:
+
+ if (wBufferLength >= 2)
+ {
+ WORD wStatus;
+ WORD wClass;
+ // This is a horrible simplification, but the only
+ // area where we have rate control is in the user info
+ // auto request part.
+ unpackWord(&pBuffer, &wStatus);
+ unpackWord(&pBuffer, &wClass);
+
+ if (wStatus == 2 || wStatus == 3)
+ { // this is only the simplest solution, needs rate management to every section
+ ICQBroadcastAck(NULL, ICQACKTYPE_RATEWARNING, ACKRESULT_STATUS, (HANDLE)wClass, wStatus);
+ gbOverRate = 1; // block user requests (user info, status messages, etc.)
+ icq_PauseUserLookup(); // pause auto-info update thread
+ }
+ else if (wStatus == 4)
+ {
+ ICQBroadcastAck(NULL, ICQACKTYPE_RATEWARNING, ACKRESULT_STATUS, (HANDLE)wClass, wStatus);
+ gbOverRate = 0; // enable user requests
+ icq_EnableUserLookup(TRUE);
+ }
+ }
+
+ break;
+
+ case ICQ_SERVER_REDIRECT_SERVICE: // reply to family request, got new connection point
+ {
+ oscar_tlv_chain* pChain = NULL;
+ WORD wFamily;
+ familyrequest_rec* reqdata;
+
+ if (!(pChain = readIntoTLVChain(&pBuffer, wBufferLength, 0)))
+ {
+ NetLog_Server("Received Broken Redirect Service SNAC(1,5).");
+ break;
+ }
+ wFamily = getWordFromChain(pChain, 0x0D, 1);
+
+ // pick request data
+ if ((!FindCookie(pSnacHeader->dwRef, NULL, &reqdata)) || (reqdata->wFamily != wFamily))
+ {
+ disposeChain(&pChain);
+ NetLog_Server("Received unexpected SNAC(1,5), skipping.");
+ break;
+ }
+
+ FreeCookie(pSnacHeader->dwRef);
+
+ { // new family entry point received
+ char* pServer;
+ WORD wPort;
+ char* pCookie;
+ WORD wCookieLen;
+ NETLIBOPENCONNECTION nloc = {0};
+ HANDLE hConnection;
+
+ pServer = getStrFromChain(pChain, 0x05, 1);
+ pCookie = getStrFromChain(pChain, 0x06, 1);
+ wCookieLen = getLenFromChain(pChain, 0x06, 1);
+
+ if (!pServer || !pCookie)
+ {
+ NetLog_Server("Server returned invalid data, family unavailable.");
+
+ SAFE_FREE(&pServer);
+ SAFE_FREE(&pCookie);
+ break;
+ }
+
+ // Get new family server ip and port
+ wPort = info->wServerPort; // get default port
+ parseServerAddress(pServer, &wPort);
+
+ nloc.cbSize = sizeof(nloc); // establish connection
+ nloc.flags = 0;
+ nloc.szHost = pServer;
+ nloc.wPort = wPort;
+
+ hConnection = NetLib_OpenConnection(ghServerNetlibUser, &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
+ reqdata->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(&reqdata);
+ }
+
+ break;
+ }
+
+ case ICQ_SERVER_EXTSTATUS: // our avatar
+ {
+ NetLog_Server("Received our avatar hash & status.");
+
+ if ((wBufferLength >= 0x14) && gbAvatarsEnabled)
+ {
+ switch (pBuffer[2])
+ {
+ case 1: // our avatar is on the server
+ {
+ char* file;
+ char* hash;
+
+ ICQWriteContactSettingBlob(NULL, "AvatarHash", pBuffer, 0x14);
+
+ setUserInfo();
+ // here we need to find a file, check its hash, if invalid get avatar from server
+ file = loadMyAvatarFileName();
+ if (!file)
+ { // we have no avatar file, download from server
+ char szFile[MAX_PATH + 4];
+#ifdef _DEBUG
+ NetLog_Server("We have no avatar, requesting from server.");
+#endif
+ GetAvatarFileName(0, NULL, szFile, MAX_PATH);
+ GetAvatarData(NULL, dwLocalUIN, NULL, pBuffer, 0x14, szFile);
+ }
+ else
+ { // we know avatar filename
+ hash = calcMD5Hash(file);
+ if (!hash)
+ { // hash could not be calculated - probably missing file, get avatar from server
+ char szFile[MAX_PATH + 4];
+#ifdef _DEBUG
+ NetLog_Server("We have no avatar, requesting from server.");
+#endif
+ GetAvatarFileName(0, NULL, szFile, MAX_PATH);
+ GetAvatarData(NULL, dwLocalUIN, NULL, pBuffer, 0x14, szFile);
+ } // check if we had set any avatar if yes set our, if not download from server
+ else if (memcmp(hash, pBuffer+4, 0x10))
+ { // we have different avatar, sync that
+ if (ICQGetContactSettingByte(NULL, "ForceOurAvatar", 1))
+ { // we want our avatar, update hash
+ DWORD dwPaFormat = DetectAvatarFormat(file);
+ char* pHash = _alloca(0x14);
+
+ NetLog_Server("Our avatar is different, set our new hash.");
+
+ pHash[0] = 0;
+ pHash[1] = dwPaFormat == PA_FORMAT_XML ? 8 : 1;
+ 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
+ char szFile[MAX_PATH + 4];
+#ifdef _DEBUG
+ NetLog_Server("We have different avatar, requesting new from server.");
+#endif
+ GetAvatarFileName(0, NULL, szFile, MAX_PATH);
+ GetAvatarData(NULL, dwLocalUIN, NULL, pBuffer, 0x14, szFile);
+ }
+ }
+ SAFE_FREE(&hash);
+ SAFE_FREE(&file);
+ }
+ break;
+ }
+ case 0x41: // request to upload avatar data
+ case 0x81:
+ { // request to re-upload avatar data
+ char* file;
+ char* hash;
+ DWORD dwPaFormat;
+
+ if (!gbSsiEnabled) break; // we could not change serv-list if it is disabled...
+
+ file = loadMyAvatarFileName();
+ if (!file)
+ { // we have no file to upload, remove hash from server
+ NetLog_Server("We do not have avatar, removing hash.");
+ IcqSetMyAvatar(0, 0);
+ LinkContactPhotoToFile(NULL, NULL);
+ break;
+ }
+ dwPaFormat = DetectAvatarFormat(file);
+ hash = calcMD5Hash(file);
+ if (!hash)
+ { // the hash could not be calculated, remove from server
+ NetLog_Server("We could not obtain hash, removing hash.");
+ IcqSetMyAvatar(0, 0);
+ LinkContactPhotoToFile(NULL, NULL);
+ }
+ else if (!memcmp(hash, pBuffer+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 ? 8 : 1), ppMap, cbFileSize);
+ LinkContactPhotoToFile(NULL, file);
+ }
+
+ if (ppMap != NULL) UnmapViewOfFile(ppMap);
+ if (hMap != NULL) CloseHandle(hMap);
+ if (hFile != NULL) CloseHandle(hFile);
+ SAFE_FREE(&hash);
+ }
+ else
+ {
+ char* pHash = _alloca(0x14);
+
+ NetLog_Server("Our file is different, set our new hash.");
+
+ pHash[0] = 0;
+ pHash[1] = dwPaFormat == PA_FORMAT_XML ? 8 : 1;
+ pHash[2] = 1; // state of the hash
+ pHash[3] = 0x10; // len of the hash
+ memcpy(pHash + 4, hash, 0x10);
+ updateServAvatarHash(pHash, 0x14);
+
+ SAFE_FREE(&hash);
+ }
+
+ SAFE_FREE(&file);
+ break;
+ default:
+ NetLog_Server("Reiceived UNKNOWN Avatar Status.");
+ }
+ }
+ }
+ 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* calcMD5Hash(char* szFile)
+{
+ md5_state_t state;
+ md5_byte_t digest[16];
+
+ if (szFile)
+ {
+ HANDLE hFile = NULL, hMap = NULL;
+ BYTE* ppMap = NULL;
+ long cbFileSize = 0;
+ char* res;
+
+ if ((hFile = CreateFile(szFile, 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 );
+
+ res = (char*)SAFE_MALLOC(16*sizeof(char));
+ if (cbFileSize != 0 && res)
+ {
+ md5_init(&state);
+ md5_append(&state, (const md5_byte_t *)ppMap, cbFileSize);
+ md5_finish(&state, digest);
+ memcpy(res, digest, 16);
+ }
+
+ if (ppMap != NULL) UnmapViewOfFile(ppMap);
+ if (hMap != NULL) CloseHandle(hMap);
+ if (hFile != NULL) CloseHandle(hFile);
+
+ if (res) return res;
+ }
+
+ return NULL;
+}
+
+
+
+static char* 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 = ICQFindFirstContact();
+
+ while (hContact != NULL)
+ {
+ if (!ICQGetContactSettingUID(hContact, &dwUIN, &szUID))
+ {
+ szLen[0] = strlennull(strUID(dwUIN, szUID));
+
+ switch (subtype)
+ {
+
+ case BUL_VISIBLE:
+ add = ID_STATUS_ONLINE == ICQGetContactSettingWord(hContact, "ApparentMode", 0);
+ break;
+
+ case BUL_INVISIBLE:
+ add = ID_STATUS_OFFLINE == ICQGetContactSettingWord(hContact, "ApparentMode", 0);
+ break;
+
+ case BUL_TEMPVISIBLE:
+ add = ICQGetContactSettingByte(hContact, "TemporaryVisible", 0);
+ // clear temporary flag
+ // Here we assume that all temporary contacts will be in one packet
+ ICQDeleteContactSetting(hContact, "TemporaryVisible");
+ 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 (gbSsiEnabled && ICQGetContactSettingWord(hContact, "ServerId", 0) &&
+ !ICQGetContactSettingByte(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 = ICQFindNextContact(hContact);
+ }
+ *hContactResume = NULL;
+
+
+ return szList;
+}
+
+
+
+void sendEntireListServ(WORD wFamily, WORD wSubtype, int listType)
+{
+ HANDLE hResumeContact;
+ char* szList;
+ int nListLen;
+ icq_packet packet;
+
+
+ hResumeContact = NULL;
+
+ do
+ { // server doesn't seem to be able to cope with packets larger than 8k
+ // send only about 100contacts per packet
+ szList = buildUinList(listType, 0x3E8, &hResumeContact);
+ nListLen = strlennull(szList);
+
+ if (nListLen)
+ {
+ serverPacketInit(&packet, (WORD)(nListLen + 10));
+ packFNACHeader(&packet, wFamily, wSubtype);
+ packBuffer(&packet, szList, (WORD)nListLen);
+ sendServPacket(&packet);
+ }
+
+ SAFE_FREE(&szList);
+ }
+ while (hResumeContact);
+}
+
+
+
+static void packNewCap(icq_packet* packet, WORD wNewCap)
+{ // pack standard capability
+ DWORD dwQ1 = 0x09460000 | wNewCap;
+
+ packDWord(packet, dwQ1);
+ packDWord(packet, 0x4c7f11d1);
+ packDWord(packet, 0x82224445);
+ packDWord(packet, 0x53540000);
+}
+
+
+
+void setUserInfo()
+{ // CLI_SETUSERINFO
+ icq_packet packet;
+ WORD wAdditionalData = 0;
+ BYTE bXStatus = gbXStatusEnabled?ICQGetContactSettingByte(NULL, DBSETTING_XSTATUSID, 0):0;
+
+ if (gbAimEnabled)
+ wAdditionalData += 16;
+#ifdef DBG_CAPMTN
+ wAdditionalData += 16;
+#endif
+#ifdef DBG_CAPCH2
+ wAdditionalData += 16;
+#endif
+#ifdef DBG_CAPRTF
+ wAdditionalData += 16;
+#endif
+ if (gbUtfEnabled)
+ wAdditionalData += 16;
+#ifdef DBG_NEWCAPS
+ wAdditionalData += 16;
+#endif
+#ifdef DBG_CAPXTRAZ
+ wAdditionalData += 16;
+#endif
+#ifdef DBG_OSCARFT
+ wAdditionalData += 16;
+#endif
+ if (gbAvatarsEnabled)
+ wAdditionalData += 16;
+ if (bXStatus)
+ wAdditionalData += 16;
+
+ serverPacketInit(&packet, (WORD)(46 + wAdditionalData));
+ packFNACHeader(&packet, ICQ_LOCATION_FAMILY, ICQ_LOCATION_SET_USER_INFO);
+
+ /* TLV(5): capability data */
+ packWord(&packet, 0x0005);
+ packWord(&packet, (WORD)(32 + wAdditionalData));
+
+
+#ifdef DBG_CAPMTN
+ {
+ packDWord(&packet, 0x563FC809); // CAP_TYPING
+ packDWord(&packet, 0x0B6F41BD);
+ packDWord(&packet, 0x9F794226);
+ packDWord(&packet, 0x09DFA2F3);
+ }
+#endif
+#ifdef DBG_CAPCH2
+ {
+ packNewCap(&packet, 0x1349); // AIM_CAPS_ICQSERVERRELAY
+ }
+#endif
+#ifdef DBG_CAPRTF
+ {
+ packDWord(&packet, 0x97B12751); // AIM_CAPS_ICQRTF
+ packDWord(&packet, 0x243C4334); // Broadcasts the capability to receive
+ packDWord(&packet, 0xAD22D6AB); // RTF messages
+ packDWord(&packet, 0xF73F1492);
+ }
+#endif
+ if (gbUtfEnabled)
+ {
+ packNewCap(&packet, 0x134E); // CAP_UTF8MSGS
+ } // Broadcasts the capability to receive UTF8 encoded messages
+#ifdef DBG_NEWCAPS
+ {
+ packNewCap(&packet, 0x0000); // CAP_NEWCAPS
+ } // 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 (gbAvatarsEnabled)
+ {
+ packNewCap(&packet, 0x134C); // CAP_DEVILS
+ }
+#ifdef DBG_OSCARFT
+ {
+ packNewCap(&packet, 0x1343); // CAP_AIM_FILE
+ } // Broadcasts the capability to receive Oscar File Transfers
+#endif
+ if (gbAimEnabled)
+ {
+ packNewCap(&packet, 0x134D); // Tells the server we can speak to AIM
+ }
+ if (bXStatus)
+ {
+ packBuffer(&packet, capXStatus[bXStatus-1], 0x10);
+ }
+
+ packNewCap(&packet, 0x1344); // AIM_CAPS_ICQ
+
+ packDWord(&packet, 0x4D697261); // Miranda Signature
+ packDWord(&packet, 0x6E64614D);
+ packDWord(&packet, MIRANDA_VERSION);
+ packDWord(&packet, ICQ_PLUG_VERSION);
+
+ sendServPacket(&packet);
+}
+
+
+
+void handleServUINSettings(int nPort, serverthread_info *info)
+{
+ icq_packet packet;
+
+ setUserInfo();
+
+ /* SNAC 3,4: Tell server who's on our list */
+ sendEntireListServ(ICQ_BUDDY_FAMILY, ICQ_USER_ADDTOLIST, BUL_ALLCONTACTS);
+
+ if (icqGoingOnlineStatus == ID_STATUS_INVISIBLE)
+ {
+ /* Tell server who's on our visible list */
+ if (!gbSsiEnabled)
+ sendEntireListServ(ICQ_BOS_FAMILY, ICQ_CLI_ADDVISIBLE, BUL_VISIBLE);
+ else
+ updateServVisibilityCode(3);
+ }
+
+ if (icqGoingOnlineStatus != ID_STATUS_INVISIBLE)
+ {
+ /* Tell server who's on our invisible list */
+ if (!gbSsiEnabled)
+ sendEntireListServ(ICQ_BOS_FAMILY, ICQ_CLI_ADDINVISIBLE, BUL_INVISIBLE);
+ else
+ updateServVisibilityCode(4);
+ }
+
+ // SNAC 1,1E: Set status
+ {
+ WORD wStatus;
+
+ // Get status
+ wStatus = MirandaStatusToIcq(icqGoingOnlineStatus);
+
+ serverPacketInit(&packet, 71);
+ 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, 0x0000); // TLV 8: Error code
+ packDWord(&packet, 0x000c0025); // TLV C: Direct connection info
+ packDWord(&packet, ICQGetContactSettingDword(NULL, "RealIP", 0));
+ packDWord(&packet, nPort);
+ packByte(&packet, DC_TYPE); // TCP/FLAG firewall settings
+ packWord(&packet, ICQ_VERSION);
+ packDWord(&packet, dwLocalDirectConnCookie);// DC Cookie
+ packDWord(&packet, WEBFRONTPORT); // Web front port
+ packDWord(&packet, CLIENTFEATURES); // Client features
+ packDWord(&packet, 0xffffffff); // Abused timestamp
+ packDWord(&packet, ICQ_PLUG_VERSION); // Abused timestamp
+ packDWord(&packet, 0x00000000); // Timestamp
+ packWord(&packet, 0x0000); // Unknown
+ packTLVWord(&packet, 0x001F, 0x0000);
+
+ sendServPacket(&packet);
+ }
+
+ /* SNAC 1,11 */
+ serverPacketInit(&packet, 14);
+ packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_SET_IDLE);
+ packDWord(&packet, 0x00000000);
+
+ sendServPacket(&packet);
+ gbIdleAllow = 0;
+
+ // Change status
+ SetCurrentStatus(icqGoingOnlineStatus);
+
+ // Finish Login sequence
+ serverPacketInit(&packet, 90);
+ packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_READY);
+ packDWord(&packet, 0x00010004); // imitate icq5 behaviour
+ packDWord(&packet, 0x011008E4);
+ packDWord(&packet, 0x00130004);
+ packDWord(&packet, 0x011008E4);
+ packDWord(&packet, 0x00020001);
+ packDWord(&packet, 0x011008E4);
+ packDWord(&packet, 0x00030001);
+ packDWord(&packet, 0x011008E4);
+ packDWord(&packet, 0x00150001);
+ packDWord(&packet, 0x011008E4);
+ packDWord(&packet, 0x00040001);
+ packDWord(&packet, 0x011008E4);
+ packDWord(&packet, 0x00060001);
+ packDWord(&packet, 0x011008E4);
+ packDWord(&packet, 0x00090001);
+ packDWord(&packet, 0x011008E4);
+ packDWord(&packet, 0x000A0001);
+ packDWord(&packet, 0x011008E4);
+ packDWord(&packet, 0x000B0001);
+ packDWord(&packet, 0x011008E4);
+
+ sendServPacket(&packet);
+
+ NetLog_Server(" *** Yeehah, login sequence complete");
+
+ // login sequence is complete enter logged-in mode
+ info->bLoggedIn = 1;
+
+ if (!info->isMigrating)
+ { /* Get Offline Messages Reqeust */
+ serverPacketInit(&packet, 24);
+ packFNACHeaderFull(&packet, ICQ_EXTENSIONS_FAMILY, ICQ_META_CLI_REQ, 0, 0x00020001);
+ packDWord(&packet, 0x0001000a); /* TLV */
+ packLEWord(&packet, 8); /* bytes remaining */
+ packLEDWord(&packet, dwLocalUIN);
+ packDWord(&packet, 0x3c000200); /* get offline msgs */
+
+ sendServPacket(&packet);
+
+ // Update our information from the server
+ sendOwnerInfoRequest();
+
+ // Request info updates on all contacts
+ icq_RescanInfoUpdate();
+
+ // Start sending Keep-Alive packets
+ StartKeepAlive();
+
+ if (gbAvatarsEnabled)
+ { // Send SNAC 1,4 - request avatar family 0x10 connection
+ icq_requestnewfamily(ICQ_AVATAR_FAMILY, StartAvatarThread);
+
+ pendingAvatarsStart = 1;
+ NetLog_Server("Requesting Avatar family entry point.");
+ }
+ }
+ info->isMigrating = 0;
+
+ if (gbAimEnabled)
+ {
+ char** szMsg = MirandaStatusToAwayMsg(gnCurrentStatus);
+
+ EnterCriticalSection(&modeMsgsMutex);
+ if (szMsg)
+ icq_sendSetAimAwayMsgServ(*szMsg);
+ LeaveCriticalSection(&modeMsgsMutex);
+ }
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/fam_02location.c b/miranda-wine/protocols/IcqOscarJ/fam_02location.c
new file mode 100644
index 0000000..cfe63b7
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/fam_02location.c
@@ -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,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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/fam_02location.c,v $
+// Revision : $Revision: 3663 $
+// Last change on : $Date: 2006-08-31 00:18:59 +0400 (Чтв, 31 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+static void handleLocationAwayReply(BYTE* buf, WORD wLen, DWORD dwCookie);
+
+
+void handleLocationFam(unsigned char *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
+ handleLocationAwayReply(pBuffer, wBufferLength, pSnacHeader->dwRef);
+ break;
+
+ case ICQ_ERROR:
+ {
+ WORD wError;
+ DWORD dwCookieUin;
+ fam15_cookie_data *pCookieData;
+
+
+ if (wBufferLength >= 2)
+ unpackWord(&pBuffer, &wError);
+ else
+ wError = 0;
+
+ if (wError == 4)
+ {
+ if (FindCookie(pSnacHeader->dwRef, &dwCookieUin, &pCookieData) && !dwCookieUin && pCookieData->bRequestType == REQUESTTYPE_PROFILE)
+ {
+ ICQBroadcastAck(pCookieData->hContact, 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)
+ {
+ char *szEnc = strstr(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(&pszStr);
+ utf8_decode(szStr, &szRes);
+ SAFE_FREE(&szStr);
+
+ return szRes;
+ }
+ }
+ return pszStr;
+}
+
+
+
+void handleLocationAwayReply(BYTE* buf, WORD wLen, DWORD dwCookie)
+{
+ HANDLE hContact;
+ DWORD dwUIN;
+ uid_str szUID;
+ WORD wTLVCount;
+ WORD wWarningLevel;
+ DWORD dwCookieUin;
+ WORD status;
+ message_cookie_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, &dwCookieUin, &pCookieData))
+ {
+ NetLog_Server("Error: Received unexpected away reply from %s", strUID(dwUIN, szUID));
+ return;
+ }
+
+ if (dwUIN != dwCookieUin)
+ {
+ NetLog_Server("Error: Away reply UIN does not match Cookie UIN(%u != %u)", dwUIN, dwCookieUin);
+
+ ReleaseCookie(dwCookie); // This could be a bad idea, but I think it is safe
+ return;
+ }
+
+ if (GetCookieType(dwCookie) == CKT_FAMILYSPECIAL)
+ {
+ ReleaseCookie(dwCookie);
+
+ // Read user info TLVs
+ {
+ oscar_tlv_chain* pChain;
+ oscar_tlv* pTLV;
+ 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))
+ {
+ char* szEncoding = NULL;
+
+ // Get Profile encoding TLV
+ pTLV = getTLV(pChain, 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 = getTLV(pChain, 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);
+ }
+
+ ICQWriteContactSettingString(hContact, "About", szMsg);
+ ICQBroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE)1 ,0);
+
+ SAFE_FREE(&szMsg);
+ }
+ }
+ else
+ {
+ 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 = getTLV(pChain, 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 = getTLV(pChain, 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;
+ pre.flags = 0;
+ pre.szMessage = szMsg?szMsg:"";
+ pre.timestamp = time(NULL);
+ pre.lParam = dwCookie;
+
+ CallService(MS_PROTO_CHAINRECV,0,(LPARAM)&ccs);
+
+ SAFE_FREE(&szMsg);
+ }
+ }
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/fam_03buddy.c b/miranda-wine/protocols/IcqOscarJ/fam_03buddy.c
new file mode 100644
index 0000000..881e0ec
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/fam_03buddy.c
@@ -0,0 +1,499 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/fam_03buddy.c,v $
+// Revision : $Revision: 3609 $
+// Last change on : $Date: 2006-08-27 22:02:55 +0400 (Ð’Ñк, 27 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Handles packets from Buddy family
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+static void handleUserOffline(BYTE* buf, WORD wPackLen);
+static void handleUserOnline(BYTE* buf, WORD wPackLen);
+static void handleReplyBuddy(BYTE* buf, WORD wPackLen);
+static void handleNotifyRejected(BYTE* buf, WORD wPackLen);
+
+extern DWORD dwLocalDirectConnCookie;
+
+extern const capstr capAimIcon;
+extern const char* cliSpamBot;
+extern char* detectUserClient(HANDLE hContact, DWORD dwUin, WORD wVersion, DWORD dwFT1, DWORD dwFT2, DWORD dwFT3, DWORD dwOnlineSince, DWORD dwDirectCookie, DWORD dwWebPort, BYTE* caps, WORD wLen, BYTE* bClientId, char* szClientBuf);
+
+
+void handleBuddyFam(unsigned char* pBuffer, WORD wBufferLength, snac_header* pSnacHeader)
+{
+ switch (pSnacHeader->wSubtype)
+ {
+ case ICQ_USER_ONLINE:
+ handleUserOnline(pBuffer, wBufferLength);
+ 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;
+ }
+}
+
+
+// TLV(1) Unknown (x50)
+// TLV(2) Member since (not sent)
+// TLV(3) Online since
+// TLV(4) Idle time (not sent)
+// TLV(6) New status
+// TLV(A) External IP
+// TLV(C) DC Info
+// TLV(D) Capabilities
+// TLV(F) Session timer (in seconds)
+// TLV(1D) Avatar Hash (20 bytes)
+static void handleUserOnline(BYTE* buf, WORD wLen)
+{
+ HANDLE hContact;
+ DWORD dwPort = 0;
+ DWORD dwRealIP = 0;
+ DWORD dwIP = 0;
+ DWORD dwUIN;
+ uid_str szUID;
+ DWORD dwDirectConnCookie = 0;
+ DWORD dwWebPort = 0;
+ DWORD dwFT1 = 0, dwFT2 = 0, dwFT3 = 0;
+ LPSTR szClient = 0;
+ BYTE bClientId = 0;
+ WORD wVersion = 0;
+ WORD wTLVCount;
+ WORD wWarningLevel;
+ WORD wStatusFlags;
+ WORD wStatus;
+ BYTE nTCPFlag = 0;
+ DWORD dwOnlineSince;
+ WORD wIdleTimer;
+ time_t tIdleTS = 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;
+
+ // Determine contact
+ hContact = HContactFromUID(dwUIN, szUID, NULL);
+
+ // Ignore status notification if the user is not already on our list
+ 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;
+
+ if (dwUIN)
+ {
+ // Get DC info TLV
+ pTLV = getTLV(pChain, 0x0C, 1);
+ if (pTLV && (pTLV->wLen >= 15))
+ {
+ unsigned char* pBuffer;
+
+ pBuffer = pTLV->pData;
+ 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 = getTLV(pChain, 0x06, 1);
+ if (pTLV && (pTLV->wLen >= 4))
+ {
+ unsigned char* pBuffer;
+
+ pBuffer = pTLV->pData;
+ unpackWord(&pBuffer, &wStatusFlags);
+ unpackWord(&pBuffer, &wStatus);
+ }
+ else
+ {
+ // Huh? No status TLV? Lets guess then...
+ wStatusFlags = 0;
+ wStatus = ICQ_STATUS_ONLINE;
+ }
+ }
+ else
+ {
+ // Get Class word
+ WORD wClass = getWordFromChain(pChain, 0x01, 1);
+
+ if (wClass & CLASS_AWAY)
+ wStatus = ID_STATUS_AWAY;
+ 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
+ dwIP = getDWordFromChain(pChain, 0x0a, 1);
+
+ // Get Online Since TLV
+ dwOnlineSince = getDWordFromChain(pChain, 0x03, 1);
+
+ // Get Idle timer TLV
+ wIdleTimer = getWordFromChain(pChain, 0x04, 1);
+ if (wIdleTimer)
+ {
+ time(&tIdleTS);
+ tIdleTS -= (wIdleTimer*60);
+ };
+
+#ifdef _DEBUG
+ if (wIdleTimer)
+ NetLog_Server("Idle timer is %u.", wIdleTimer);
+ NetLog_Server("Online since %s", asctime(localtime(&dwOnlineSince)));
+#endif
+
+ // Check client capabilities
+ if (hContact != NULL)
+ {
+ WORD wOldStatus;
+
+ wOldStatus = ICQGetContactStatus(hContact);
+
+ // Get Avatar Hash TLV
+ pTLV = getTLV(pChain, 0x1D, 1);
+ if (pTLV)
+ handleAvatarContactHash(dwUIN, szUID, hContact, pTLV->pData, pTLV->wLen, wOldStatus);
+ else
+ handleAvatarContactHash(dwUIN, szUID, hContact, NULL, 0, wOldStatus);
+
+ // Update the contact's capabilities
+ if (wOldStatus == ID_STATUS_OFFLINE)
+ {
+ // Delete the capabilities we saved the last time this contact came online
+ ClearAllContactCapabilities(hContact);
+
+ {
+ BYTE* capBuf = NULL;
+ WORD capLen = 0;
+ oscar_tlv* pNewTLV;
+
+ // Get Location Capability Info TLVs
+ pTLV = getTLV(pChain, 0x0D, 1);
+ pNewTLV = getTLV(pChain, 0x19, 1);
+
+ if (pTLV && (pTLV->wLen >= 16))
+ capLen = pTLV->wLen;
+
+ if (pNewTLV && (pNewTLV->wLen >= 2))
+ capLen += (pNewTLV->wLen * 8);
+
+ if (capLen)
+ {
+ int i;
+ BYTE* pCap;
+
+ capBuf = pCap = (BYTE*)_alloca(capLen + 0x10);
+
+ if (pTLV && (pTLV->wLen >= 16))
+ { // copy classic Capabilities
+ char* cData = pTLV->pData;
+ int cLen = pTLV->wLen;
+
+ capLen = 0; // we need to recount that
+ while (cLen)
+ { // ohh, those damned AOL updates.... they broke it again
+ if (!MatchCap(capBuf, capLen, (capstr*)cData, 0x10))
+ { // not there, add
+ memcpy(pCap, cData, 0x10);
+ capLen += 0x10;
+ pCap += 0x10;
+ }
+ cData += 0x10;
+ cLen -= 0x10;
+ }
+ }
+
+ if (pNewTLV && (pNewTLV->wLen >= 2))
+ { // get new Capabilities
+ capstr tmp;
+ BYTE* capNew = pNewTLV->pData;
+
+ memcpy(tmp, capAimIcon, 0x10);
+
+ for (i = 0; i<pNewTLV->wLen; i+=2)
+ {
+ BYTE capVal;
+
+ capVal = capNew[0];
+ tmp[2] = capVal;
+ capVal = capNew[1];
+ tmp[3] = capVal;
+
+ capNew += 2;
+
+ if (!MatchCap(capBuf, capLen, &tmp, 0x10))
+ { // not present, add
+ memcpy(pCap, tmp, 0x10);
+ pCap += 0x10;
+ capLen += 0x10;
+ }
+ }
+ }
+ AddCapabilitiesFromBuffer(hContact, capBuf, capLen);
+ }
+ else
+ { // no capability
+ NetLog_Server("No capability info TLVs");
+ }
+
+ // handle Xtraz status
+ handleXStatusCaps(hContact, capBuf, capLen);
+
+ szClient = detectUserClient(hContact, dwUIN, wVersion, dwFT1, dwFT2, dwFT3, dwOnlineSince, dwDirectConnCookie, dwWebPort, capBuf, capLen, &bClientId, szStrBuf);
+ }
+
+#ifdef _DEBUG
+ if (CheckContactCapabilities(hContact, CAPF_SRV_RELAY))
+ NetLog_Server("Supports advanced messages");
+ else
+ NetLog_Server("Does NOT support advanced messages");
+#endif
+
+ if (dwUIN && wVersion < 8)
+ {
+ ClearContactCapabilities(hContact, CAPF_SRV_RELAY);
+ NetLog_Server("Forcing simple messages due to compability issues");
+ }
+ }
+ else
+ {
+ szClient = (char*)-1; // we don't want to client be overwritten if no capabilities received
+
+ // Get Capability Info TLV
+ pTLV = getTLV(pChain, 0x0D, 1);
+
+ if (pTLV && (pTLV->wLen >= 16))
+ {
+ // handle Xtraz status
+ handleXStatusCaps(hContact, pTLV->pData, pTLV->wLen);
+ }
+ }
+ }
+
+ // Free TLV chain
+ disposeChain(&pChain);
+ }
+
+ // Save contacts details in database
+ if (hContact != NULL)
+ {
+ if (szClient == 0) szClient = ICQTranslateUtfStatic("Unknown", szStrBuf); // if no detection, set uknown
+
+ ICQWriteContactSettingDword(hContact, "LogonTS", dwOnlineSince);
+ if (dwUIN)
+ { // on AIM these are not used
+ ICQWriteContactSettingDword(hContact, "IP", dwIP);
+ ICQWriteContactSettingDword(hContact, "RealIP", dwRealIP);
+ ICQWriteContactSettingDword(hContact, "DirectCookie", dwDirectConnCookie);
+ ICQWriteContactSettingByte(hContact, "DCType", (BYTE)nTCPFlag);
+ ICQWriteContactSettingWord(hContact, "UserPort", (WORD)(dwPort & 0xffff));
+ ICQWriteContactSettingWord(hContact, "Version", wVersion);
+ }
+ if (szClient != (char*)-1)
+ {
+ ICQWriteContactSettingUtf(hContact, "MirVer", szClient);
+ ICQWriteContactSettingByte(hContact, "ClientID", bClientId);
+ }
+ ICQWriteContactSettingWord(hContact, "Status", (WORD)IcqStatusToMiranda(wStatus));
+ ICQWriteContactSettingDword(hContact, "IdleTS", tIdleTS);
+
+ // Update info?
+ if (dwUIN && ((time(NULL) - ICQGetContactSettingDword(hContact, "InfoTS", 0)) > UPDATE_THRESHOLD))
+ icq_QueueUser(hContact);
+ }
+ else
+ {
+ dwLocalDirectConnCookie = dwDirectConnCookie;
+ }
+
+ // And a small log notice...
+ NetLog_Server("%s changed status to %s (v%d).", strUID(dwUIN, szUID),
+ MirandaStatusToString(IcqStatusToMiranda(wStatus)), wVersion);
+
+ if (szClient == cliSpamBot)
+ {
+ if (ICQGetContactSettingByte(NULL, "KillSpambots", DEFAULT_KILLSPAM_ENABLED) && DBGetContactSettingByte(hContact, "CList", "NotOnList", 0))
+ { // kill spammer
+ icq_DequeueUser(dwUIN);
+ AddToSpammerList(dwUIN);
+ icq_sendRemoveContact(dwUIN, NULL);
+ if (ICQGetContactSettingByte(NULL, "PopupsSpamEnabled", DEFAULT_SPAM_POPUPS_ENABLED))
+ ShowPopUpMsg(hContact, "Spambot Detected", "Contact deleted & further events blocked.", POPTYPE_SPAM);
+ CallService(MS_DB_CONTACT_DELETE, (WPARAM)hContact, 0);
+
+ NetLog_Server("Contact %u deleted", dwUIN);
+ }
+ }
+}
+
+
+
+static void handleUserOffline(BYTE *buf, WORD wLen)
+{
+ HANDLE hContact;
+ DWORD dwUIN;
+ uid_str szUID;
+
+ // Unpack the sender's user ID
+ if (!unpackUID(&buf, &wLen, &dwUIN, &szUID)) return;
+
+ hContact = HContactFromUID(dwUIN, szUID, NULL);
+
+ // Skip contacts that are not already on our list
+ if (hContact != INVALID_HANDLE_VALUE)
+ {
+ NetLog_Server("%s went offline.", strUID(dwUIN, szUID));
+
+ ICQWriteContactSettingWord(hContact, "Status", ID_STATUS_OFFLINE);
+ ICQWriteContactSettingDword(hContact, "IdleTS", 0);
+ // close Direct Connections to that user
+ CloseContactDirectConns(hContact);
+ // clear Xtraz status
+ handleXStatusCaps(hContact, NULL, 0);
+ }
+}
+
+
+
+static void handleReplyBuddy(BYTE *buf, WORD wPackLen)
+{
+ oscar_tlv_chain *pChain;
+
+ pChain = readIntoTLVChain(&buf, wPackLen, 0);
+
+ if (pChain)
+ {
+ DWORD wMaxUins;
+ DWORD wMaxWatchers;
+
+ wMaxUins = getWordFromChain(pChain, 1, 1);
+ wMaxWatchers = getWordFromChain(pChain, 2, 1);
+
+ NetLog_Server("MaxUINs %u", wMaxUins);
+ NetLog_Server("MaxWatchers %u", wMaxWatchers);
+
+ disposeChain(&pChain);
+ }
+ else
+ {
+ NetLog_Server("Error: Malformed BuddyReply");
+ }
+}
+
+
+
+static void handleNotifyRejected(BYTE *buf, WORD wPackLen)
+{
+ DWORD dwUIN;
+ uid_str szUID;
+
+ if (!unpackUID(&buf, &wPackLen, &dwUIN, &szUID))
+ return;
+
+ NetLog_Server("SNAC(x03,x0a) - SRV_NOTIFICATION_REJECTED for %s", strUID(dwUIN, szUID));
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/fam_04message.c b/miranda-wine/protocols/IcqOscarJ/fam_04message.c
new file mode 100644
index 0000000..4cc329f
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/fam_04message.c
@@ -0,0 +1,2512 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/fam_04message.c,v $
+// Revision : $Revision: 3720 $
+// Last change on : $Date: 2006-09-07 00:56:27 +0400 (Чтв, 07 Сен 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Handlers for Family 4 ICBM Messages
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+static void handleReplyICBM(unsigned char *buf, WORD wLen, WORD wFlags, DWORD dwRef);
+static void handleRecvServMsg(unsigned char *buf, WORD wLen, WORD wFlags, DWORD dwRef);
+static void handleRecvServMsgType1(unsigned char *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwTS1, DWORD dwTS2);
+static void handleRecvServMsgType2(unsigned char *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwTS1, DWORD dwTS2);
+static void handleRecvServMsgType4(unsigned char *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwTS1, DWORD dwTS2);
+static void handleRecvServMsgError(unsigned char *buf, WORD wLen, WORD wFlags, DWORD dwRef);
+static void handleRecvMsgResponse(unsigned char *buf, WORD wLen, WORD wFlags, DWORD dwRef);
+static void handleServerAck(unsigned char *buf, WORD wLen, WORD wFlags, DWORD dwRef);
+static void handleTypingNotification(unsigned char *buf, WORD wLen, WORD wFlags, DWORD dwRef);
+static void handleMissedMsg(unsigned char *buf, WORD wLen, WORD wFlags, DWORD dwRef);
+static void parseTLV2711(DWORD dwUin, HANDLE hContact, DWORD dwID1, DWORD dwID2, WORD wAckType, oscar_tlv* tlv);
+static void parseServerGreeting(BYTE* pDataBuf, WORD wLen, WORD wMsgLen, DWORD dwUin, BYTE bFlags, WORD wStatus, WORD wCookie, WORD wAckType, DWORD dwID1, DWORD dwID2, WORD wVersion);
+
+
+
+void handleMsgFam(unsigned char *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_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_REPLYICBM: // SNAC(4, 0x05) SRV_REPLYICBM
+ handleReplyICBM(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(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
+ sendServPacket(&packet);
+}
+
+
+
+static void handleReplyICBM(unsigned char *buf, WORD wLen, WORD wFlags, DWORD dwRef)
+{ // we don't care about the stuff, just change the params
+
+ // Set message parameters for channel 1 (CLI_SET_ICBM_PARAMS)
+#ifdef DBG_CAPMTN
+ setMsgChannelParams(0x0001, 0x0000000B);
+#else
+ setMsgChannelParams(0x0001, 0x00000003);
+#endif
+ // Set message parameters for channel 2 (CLI_SET_ICBM_PARAMS)
+ setMsgChannelParams(0x0002, 0x00000003);
+ // Set message parameters for channel 4 (CLI_SET_ICBM_PARAMS)
+ setMsgChannelParams(0x0004, 0x00000003);
+}
+
+
+
+static void handleRecvServMsg(unsigned char *buf, WORD wLen, WORD wFlags, DWORD dwRef)
+{
+ DWORD dwUin;
+ DWORD dwID1;
+ DWORD dwID2;
+ 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, &dwID1); // TODO: msg cookies should be main
+ wLen -= 4;
+ unpackLEDWord(&buf, &dwID2);
+ 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.
+ oscar_tlv_chain* chain = NULL;
+ unsigned char* pBufStart = buf;
+
+ 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 = wLen - (buf - pBufStart);
+ }
+
+
+ // This is where the format specific data begins
+
+ switch (wMessageFormat)
+ {
+
+ case 1: // Simple message format
+ handleRecvServMsgType1(buf, wLen, dwUin, szUID, dwID1, dwID2);
+ break;
+
+ case 2: // Encapsulated messages
+ handleRecvServMsgType2(buf, wLen, dwUin, szUID, dwID1, dwID2);
+ break;
+
+ case 4: // Typed messages
+ handleRecvServMsgType4(buf, wLen, dwUin, szUID, dwID1, dwID2);
+ break;
+
+ default:
+ NetLog_Server("Unknown format message thru server - Ref %u, Type: %u, UID: %s", dwRef, wMessageFormat, strUID(dwUin, szUID));
+ break;
+
+ }
+}
+
+
+
+static char* convertMsgToUserSpecificUtf(HANDLE hContact, const char* szMsg)
+{
+ WORD wCP = ICQGetContactSettingWord(hContact, "CodePage", gwAnsiCodepage);
+ wchar_t* usMsg = NULL;
+
+ if (wCP != CP_ACP)
+ {
+ int nMsgLen = strlennull(szMsg);
+
+ usMsg = (wchar_t*)SAFE_MALLOC((nMsgLen + 2)*(sizeof(wchar_t) + 1));
+ memcpy((char*)usMsg, szMsg, nMsgLen + 1);
+ MultiByteToWideChar(wCP, 0, szMsg, nMsgLen, (wchar_t*)((char*)usMsg + nMsgLen + 1), nMsgLen);
+ *(wchar_t*)((char*)usMsg + 1 + nMsgLen*(1 + sizeof(wchar_t))) = '\0'; // trailing zeros
+ }
+ return (char*)usMsg;
+}
+
+
+
+static void handleRecvServMsgType1(unsigned char *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwTS1, DWORD dwTS2)
+{
+ WORD wTLVType;
+ WORD wTLVLen;
+ BYTE* pDataBuf;
+ BYTE* pBuf;
+
+ 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, &pDataBuf);
+ NetLog_Server("Message (format %u) - UID: %s", 1, strUID(dwUin, szUID));
+ pBuf = pDataBuf;
+
+ // It must be TLV(2)
+ if (wTLVType == 2)
+ {
+ oscar_tlv_chain* pChain;
+
+ 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
+
+ if (pChain)
+ {
+ oscar_tlv* pMessageTLV;
+ oscar_tlv* pCapabilityTLV;
+
+ // Find the capability TLV
+ pCapabilityTLV = getTLV(pChain, 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.");
+ }
+
+ // Find the message TLV
+ pMessageTLV = getTLV(pChain, 0x0101, 1);
+ if (pMessageTLV)
+ {
+ if (pMessageTLV->wLen > 4)
+ {
+ WORD wMsgLen;
+ BYTE* pMsgBuf;
+ WORD wEncoding;
+ WORD wCodePage;
+ char* szMsg = NULL;
+ HANDLE hContact;
+ CCSDATA ccs;
+ PROTORECVEVENT pre = {0};
+ int bAdded;
+
+ // 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) - Encoding is 0x%X, page is 0x%X", wEncoding, wCodePage);
+
+ hContact = HContactFromUID(dwUin, szUID, &bAdded);
+
+ switch (wEncoding)
+ {
+
+ case 2: // UCS-2
+ {
+ WCHAR* usMsg;
+ int nStrSize;
+
+ usMsg = (WCHAR*)SAFE_MALLOC(wMsgLen + 2);
+ unpackWideString(&pMsgBuf, usMsg, wMsgLen);
+ usMsg[wMsgLen/2] = 0;
+
+ if (!dwUin)
+ {
+ char *utf = make_utf8_string(usMsg);
+ int nUtfLen = strlennull(utf);
+
+ SAFE_FREE(&usMsg);
+ utf = EliminateHtml(utf, nUtfLen);
+
+ usMsg = make_unicode_string(utf);
+ SAFE_FREE(&utf);
+ SetContactCapabilities(hContact, CAPF_UTF);
+ }
+
+ nStrSize = WideCharToMultiByte(CP_ACP, 0, usMsg, wMsgLen / sizeof(WCHAR), szMsg, 0, NULL, NULL);
+ szMsg = (char*)SAFE_MALLOC((nStrSize+1)*(sizeof(wchar_t)+1));
+ WideCharToMultiByte(CP_ACP, 0, usMsg, wMsgLen / sizeof(WCHAR), szMsg, nStrSize, NULL, NULL);
+ nStrSize = strlennull(szMsg); // this is necessary, sometimes it was bad
+ memcpy(szMsg+nStrSize+1, usMsg, wMsgLen);
+
+ pre.flags = PREF_UNICODE;
+
+ SAFE_FREE(&usMsg);
+
+ break;
+ }
+
+ case 0: // us-ascii
+ case 3: // ANSI
+ default:
+ {
+ // Copy the message text into a new proper string.
+ szMsg = (char *)SAFE_MALLOC(wMsgLen + 1);
+ memcpy(szMsg, pMsgBuf, wMsgLen);
+ szMsg[wMsgLen] = '\0';
+ if (!dwUin)
+ {
+ szMsg = EliminateHtml(szMsg, wMsgLen);
+ }
+
+ break;
+ }
+ }
+
+ 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_UNICODE;
+ }
+ }
+ // Create and send the message event
+ ccs.szProtoService = PSR_MESSAGE;
+ ccs.hContact = hContact;
+ ccs.wParam = 0;
+ ccs.lParam = (LPARAM)&pre;
+ pre.timestamp = time(NULL);
+ pre.szMessage = (char *)szMsg;
+ CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs);
+
+ SAFE_FREE(&szMsg);
+
+ NetLog_Server("Message (format 1) received");
+
+ // Save tick value
+ ICQWriteContactSettingDword(ccs.hContact, "TickTS", time(NULL) - (dwTS1/1000));
+ }
+ else
+ {
+ NetLog_Server("Message (format %u) - Ignoring empty message", 1);
+ }
+ }
+ else
+ {
+ NetLog_Server("Failed to find TLV(1281) message (format 1)");
+ }
+
+ // 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(&pBuf);
+}
+
+
+
+static void handleRecvServMsgType2(unsigned char *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwID1, DWORD dwID2)
+{
+ WORD wTLVType;
+ WORD wTLVLen;
+ char* pDataBuf = NULL;
+ char* 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 dwIP;
+ DWORD dwExternalIP;
+ WORD wPort;
+ WORD wAckType;
+ 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);
+ 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
+
+ if (wCommand == 1)
+ {
+ NetLog_Server("Cannot handle abort messages yet... :(");
+ SAFE_FREE(&pBuf);
+ return;
+ }
+
+ // 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); // Capability (CAP_SRV_RELAY)
+ wTLVLen -= 16;
+
+ if (CompareGUIDs(q1,q2,q3,q4, MCAP_TLV2711_FMT))
+ { // we surely have at least 4 bytes for TLV chain
+ HANDLE hContact = HContactFromUIN(dwUin, NULL);
+
+ if (wTLVLen < 4)
+ { // just check if at least one tlv is there
+ NetLog_Server("Message (format %u) - Ignoring empty message", 2);
+ return;
+ }
+ if (!dwUin)
+ { // AIM cannot send this, just sanity
+ NetLog_Server("Error: Malformed UIN in packet");
+ 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);
+
+ wAckType = getWordFromChain(chain, 0x0A, 1);
+
+ // Update the saved DC info (if contact already exists)
+ if (hContact != INVALID_HANDLE_VALUE)
+ {
+ if (dwExternalIP = getDWordFromChain(chain, 0x03, 1))
+ ICQWriteContactSettingDword(hContact, "RealIP", dwExternalIP);
+ if (dwIP = getDWordFromChain(chain, 0x04, 1))
+ ICQWriteContactSettingDword(hContact, "IP", dwIP);
+ if (wPort = getWordFromChain(chain, 0x05, 1))
+ ICQWriteContactSettingWord(hContact, "UserPort", wPort);
+
+ // Save tick value
+ ICQWriteContactSettingDword(hContact, "TickTS", time(NULL) - (dwID1/1000));
+ }
+
+ // Parse the next message level
+ if (tlv = getTLV(chain, 0x2711, 1))
+ {
+ parseTLV2711(dwUin, hContact, dwID1, dwID2, wAckType, tlv);
+ }
+ else
+ {
+ NetLog_Server("Warning, no 0x2711 TLV in message (format 2)");
+ }
+ // Clean up
+ disposeChain(&chain);
+ }
+ else if (CompareGUIDs(q1,q2,q3,q4,MCAP_REVERSE_REQ))
+ { // Handle reverse DC request
+ if (wTLVLen < 4)
+ { // just check if at least one tlv is there
+ NetLog_Server("Message (format %u) - Ignoring empty message", 2);
+ return;
+ }
+ if (!dwUin)
+ { // AIM cannot send this, just sanity
+ NetLog_Server("Error: Malformed UIN in packet");
+ return;
+ }
+ chain = readIntoTLVChain(&pDataBuf, wTLVLen, 0);
+
+ wAckType = getWordFromChain(chain, 0x0A, 1);
+ // Parse the next message level
+ if (tlv = getTLV(chain, 0x2711, 1))
+ {
+ if (tlv->wLen == 0x1B)
+ {
+ char* buf=tlv->pData;
+ DWORD dwUin, dwIp, dwPort;
+ WORD wVersion;
+ BYTE bMode;
+ HANDLE hContact;
+
+ unpackLEDWord(&buf, &dwUin);
+
+ hContact = HContactFromUIN(dwUin, NULL);
+ if (hContact == INVALID_HANDLE_VALUE)
+ {
+ NetLog_Server("Error: %s from unknown contact %u", "Reverse Connect Request", dwUin);
+ }
+ else
+ {
+ 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);
+
+ ICQWriteContactSettingDword(hContact, "IP", dwIp);
+ ICQWriteContactSettingWord(hContact, "UserPort", (WORD)dwPort);
+ ICQWriteContactSettingByte(hContact, "DCType", bMode);
+ ICQWriteContactSettingWord(hContact, "Version", wVersion);
+ if (wVersion>6)
+ {
+ reverse_cookie *pCookie = (reverse_cookie*)SAFE_MALLOC(sizeof(reverse_cookie));
+
+ unpackLEDWord(&buf, (DWORD*)&pCookie->ft);
+ pCookie->pMessage.dwMsgID1 = dwID1;
+ pCookie->pMessage.dwMsgID2 = dwID2;
+
+ 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_OSCAR_FT))
+ { // this is an OFT packet
+ handleRecvServMsgOFT(pDataBuf, wTLVLen, dwUin, szUID, dwID1, dwID2, 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(&pBuf);
+}
+
+
+
+static void parseTLV2711(DWORD dwUin, HANDLE hContact, DWORD dwID1, DWORD dwID2, WORD wAckType, oscar_tlv* tlv)
+{
+ BYTE* pDataBuf;
+ WORD wId;
+ WORD wLen;
+
+ pDataBuf = tlv->pData;
+ wLen = tlv->wLen;
+
+ 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;
+ WORD wMsgLen;
+ BYTE bMsgType;
+ BYTE bFlags;
+ 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)
+ ICQWriteContactSettingWord(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 ?
+ WORD wPritority;
+ WORD wStatus;
+
+ 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:
+ {
+ char* szMsg;
+
+ 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, dwID1, dwID2, 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:
+ {
+ parseServerGreeting(pDataBuf, wLen, wMsgLen, dwUin, bFlags, wStatus, wCookie, wAckType, dwID1, dwID2, wVersion);
+ break;
+ }
+
+ // Everything else
+ default:
+ {
+ // Only ack message packets
+ if (bMsgType == MTYPE_PLAIN || bMsgType == MTYPE_URL || bMsgType == MTYPE_CONTACTS)
+ icq_sendAdvancedMsgAck(dwUin, dwID1, dwID2, wCookie, bMsgType, bFlags);
+ handleMessageTypes(dwUin, time(NULL), dwID1, dwID2, wCookie, wVersion, bMsgType, bFlags, wAckType, tlv->wLen - 53, wMsgLen, pDataBuf, FALSE);
+ break;
+ }
+ }
+ }
+ else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, PSIG_INFO_PLUGIN))
+ { // info manager plugin - obsolete
+ 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
+ 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 parseServerGreeting(BYTE* pDataBuf, WORD wLen, WORD wMsgLen, DWORD dwUin, BYTE bFlags, WORD wStatus, WORD wCookie, WORD wAckType, DWORD dwID1, DWORD dwID2, WORD wVersion)
+{
+ WORD wInfoLen;
+ DWORD dwPluginNameLen;
+ DWORD dwLengthToEnd;
+ DWORD dwDataLen;
+ DWORD q1,q2,q3,q4;
+ WORD qt;
+ char* szPluginName;
+ int typeId;
+
+ NetLog_Server("Parsing Greeting message through server");
+
+ pDataBuf += wMsgLen; // Message
+ wLen -= wMsgLen;
+
+ //
+ unpackLEWord(&pDataBuf, &wInfoLen);
+
+ unpackDWord(&pDataBuf, &q1); // get data GUID & function id
+ unpackDWord(&pDataBuf, &q2);
+ unpackDWord(&pDataBuf, &q3);
+ unpackDWord(&pDataBuf, &q4);
+ unpackLEWord(&pDataBuf, &qt);
+ wLen -= 20;
+
+ unpackLEDWord(&pDataBuf, &dwPluginNameLen);
+ wLen -= 4;
+
+ if (dwPluginNameLen > wLen)
+ { // check for malformed plugin name
+ dwPluginNameLen = wLen;
+ NetLog_Server("Warning: malformed size of plugin name.");
+ }
+ szPluginName = (char *)_alloca(dwPluginNameLen + 1);
+ memcpy(szPluginName, pDataBuf, dwPluginNameLen);
+ szPluginName[dwPluginNameLen] = '\0';
+ wLen -= (WORD)dwPluginNameLen;
+
+ pDataBuf += dwPluginNameLen + 15;
+
+ typeId = TypeGUIDToTypeId(q1, q2, q3, q4, qt);
+ if (!typeId)
+ NetLog_Server("Error: Unknown type {%08x-%08x-%08x-%08x:%04x}: %s", q1,q2,q3,q4,qt, szPluginName);
+
+ if (wLen > 8)
+ {
+ // Length of remaining data
+ unpackLEDWord(&pDataBuf, &dwLengthToEnd);
+
+ // Length of message
+ unpackLEDWord(&pDataBuf, &dwDataLen);
+ wLen -= 8;
+
+ if (dwDataLen > wLen)
+ dwDataLen = wLen;
+
+ if (typeId == MTYPE_FILEREQ && wAckType == 2)
+ {
+ char* szMsg;
+
+ NetLog_Server("This is file ack");
+ 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 (typeId == MTYPE_FILEREQ && wAckType == 1)
+ {
+ char* szMsg;
+
+ NetLog_Server("This is a file request");
+ szMsg = (char *)_alloca(dwDataLen + 1);
+ memcpy(szMsg, pDataBuf, dwDataLen);
+ szMsg[dwDataLen] = '\0';
+ pDataBuf += dwDataLen;
+ wLen -= (WORD)dwDataLen;
+
+ handleFileRequest(pDataBuf, wLen, dwUin, wCookie, dwID1, dwID2, szMsg, 8, FALSE);
+ }
+ else if (typeId == MTYPE_CHAT && wAckType == 1)
+ { // TODO: this is deprecated
+ char* szMsg;
+
+ NetLog_Server("This is a chat request");
+ szMsg = (char *)_alloca(dwDataLen + 1);
+ memcpy(szMsg, pDataBuf, dwDataLen);
+ szMsg[dwDataLen] = '\0';
+ pDataBuf += dwDataLen;
+ wLen -= (WORD)dwDataLen;
+
+ // handleChatRequest(pDataBuf, wLen, dwUin, wCookie, dwID1, dwID2, szMsg, 8);
+ }
+ else if (typeId)
+ {
+ if (typeId == MTYPE_URL || typeId == MTYPE_CONTACTS)
+ icq_sendAdvancedMsgAck(dwUin, dwID1, dwID2, wCookie, (BYTE)typeId, bFlags);
+
+ handleMessageTypes(dwUin, time(NULL), dwID1, dwID2, wCookie, wVersion, typeId, bFlags, wAckType, dwLengthToEnd, (WORD)dwDataLen, pDataBuf, FALSE);
+ }
+ else
+ {
+ NetLog_Server("Unsupported plugin message type '%s'", szPluginName);
+ }
+ }
+}
+
+
+
+static void handleRecvServMsgType4(unsigned char *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwTS1, DWORD dwTS2)
+{
+ 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;
+ unsigned char* 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
+ { // FIX ME: here MTYPE_PLUGIN need to be processed as well - tZers added this
+ handleMessageTypes(dwUin, time(NULL), dwTS1, dwTS2, 0, 0, bMsgType, bFlags, 0, wTLVLen - 8, wMsgLen, pmsg, FALSE);
+
+ NetLog_Server("TYPE4 message thru server from %d, message type %d", dwUin, bMsgType);
+ }
+ }
+ 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(&pDataBuf);
+}
+
+
+
+//
+// Helper functions
+//
+
+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_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 (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 getPluginTypeIdLen(int nTypeID)
+{
+ switch (nTypeID)
+ {
+ case MTYPE_SCRIPT_NOTIFY:
+ return 0x51;
+
+ case MTYPE_FILEREQ:
+ return 0x2B;
+
+ 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, "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, "File", 0x0004);
+
+ packDWord(packet, 0x00000100); // More unknown binary stuff
+ packDWord(packet, 0x00010000);
+ packDWord(packet, 0x00000000);
+ packWord(packet, 0x0000);
+ packByte(packet, 0x00);
+
+ break;
+
+ default:
+ return;
+ }
+}
+
+
+
+static void handleSmsReceipt(unsigned char *buf, DWORD dwDataLen)
+{
+ DWORD dwLen;
+ DWORD dwTextLen;
+ char* szInfo;
+
+
+ if (dwDataLen < 36)
+ return;
+
+ buf += 20; // Unknown byte sequence
+ dwDataLen -= 20;
+
+ unpackLEDWord(&buf, &dwLen); // Length of message description
+ dwDataLen -= 4;
+ if (dwLen > dwDataLen)
+ {
+ NetLog_Server("SMS failed syntax check %d (%d, %d)", 1, dwDataLen, dwLen);
+ return;
+ }
+ buf += dwLen; // Skip message description (usually "ICQSMS\0")
+ dwDataLen -= dwLen;
+
+ // Unknown (0,0,0)
+ buf += 3;
+ dwDataLen -= 3;
+
+ // Remaining bytes
+ unpackLEDWord(&buf, &dwLen);
+ dwDataLen -= 4;
+ if (dwLen > dwDataLen)
+ {
+ NetLog_Server("SMS failed syntax check %d (%d, %d)", 2, dwDataLen, dwLen);
+ return;
+ }
+
+ // Length of message
+ unpackLEDWord(&buf, &dwTextLen);
+ dwDataLen -= 4;
+ if ((dwTextLen > dwDataLen) || (dwTextLen+4 != dwLen))
+ {
+ NetLog_Server("SMS failed syntax check %d (%d, %d, %d)", 3, dwDataLen, dwLen, dwTextLen);
+ return;
+ }
+
+ // Unpack message
+ szInfo = (char *)_alloca(dwTextLen + 1);
+ memcpy(szInfo, buf, dwTextLen);
+ szInfo[dwTextLen] = 0;
+
+ ICQBroadcastAck(NULL, ICQACKTYPE_SMS, ACKRESULT_SUCCESS, NULL, (LPARAM)szInfo);
+}
+
+
+
+static void handleStatusMsgReply(const char* szPrefix, HANDLE hContact, DWORD dwUin, WORD wVersion, int bMsgType, WORD wCookie, const char* szMsg)
+{
+ CCSDATA ccs;
+ PROTORECVEVENT pre = {0};
+ int status;
+ char* pszMsg;
+
+
+ if (hContact == INVALID_HANDLE_VALUE)
+ {
+ NetLog_Server("%sIgnoring status message from unknown contact %u", szPrefix, dwUin);
+ return;
+ }
+
+ status = AwayMsgTypeToStatus(bMsgType);
+ if (status == ID_STATUS_OFFLINE)
+ {
+ NetLog_Server("%sIgnoring unknown status message from %u", szPrefix, dwUin);
+ return;
+ }
+
+ pszMsg = null_strdup((char*)szMsg);
+
+ if (wVersion == 9)
+ { // it is probably UTF-8 status reply
+ pszMsg = detect_decode_utf8(pszMsg);
+ }
+
+ ccs.szProtoService = PSR_AWAYMSG;
+ ccs.hContact = hContact;
+ ccs.wParam = status;
+ ccs.lParam = (LPARAM)&pre;
+ pre.szMessage = pszMsg;
+ pre.timestamp = time(NULL);
+ pre.lParam = wCookie;
+
+ CallService(MS_PROTO_CHAINRECV,0,(LPARAM)&ccs);
+
+ SAFE_FREE(&pszMsg);
+}
+
+
+
+static HANDLE handleMessageAck(DWORD dwUin, WORD wCookie, WORD wVersion, int type, WORD wMsgLen, PBYTE buf, BYTE bFlags)
+{
+ if (bFlags == 3)
+ {
+ HANDLE hContact;
+ DWORD dwCookieUin;
+ message_cookie_data* pCookieData = NULL;
+
+ hContact = HContactFromUIN(dwUin, NULL);
+
+ if (!FindCookie(wCookie, &dwCookieUin, &pCookieData))
+ {
+ NetLog_Server("%sIgnoring unrequested status message from %u", "handleMessageAck: ", dwUin);
+
+ ReleaseCookie(wCookie);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ if (dwUin != dwCookieUin)
+ {
+ NetLog_Server("%sAck UIN does not match Cookie UIN(%u != %u)", "handleMessageAck: ", dwUin, dwCookieUin);
+
+ ReleaseCookie(wCookie);
+ return INVALID_HANDLE_VALUE;
+ }
+ ReleaseCookie(wCookie);
+
+ handleStatusMsgReply("handleMessageAck: ", hContact, dwUin, wVersion, type, wCookie, (char*)buf);
+ }
+ else
+ {
+ // Should not happen
+ NetLog_Server("%sIgnored type %u ack message (this should not happen)", "handleMessageAck: ", type);
+ }
+
+ return INVALID_HANDLE_VALUE;
+}
+
+
+
+/* this function also processes direct packets, so it should be bulletproof */
+/* pMsg points to the beginning of the message */
+void handleMessageTypes(DWORD dwUin, DWORD dwTimestamp, DWORD dwMsgID, DWORD dwMsgID2, WORD wCookie, WORD wVersion, int type, int flags, WORD wAckType, DWORD dwDataLen, WORD wMsgLen, char *pMsg, BOOL bThruDC)
+{
+ char* szMsg;
+ char* pszMsgField[2*MAX_CONTACTSSEND+1];
+ char* pszMsg;
+ int nMsgFields;
+ HANDLE hContact = INVALID_HANDLE_VALUE;
+ int bAdded;
+
+
+ if (dwDataLen < wMsgLen)
+ {
+ NetLog_Uni(bThruDC, "Ignoring overflowed message");
+ return;
+ }
+
+ if (wAckType == 2)
+ {
+ handleMessageAck(dwUin, wCookie, wVersion, type, wMsgLen, pMsg, (BYTE)flags);
+ return;
+ }
+
+ szMsg = (char *)SAFE_MALLOC(wMsgLen + 1);
+ if (wMsgLen > 0)
+ {
+ memcpy(szMsg, pMsg, wMsgLen);
+ pMsg += wMsgLen;
+ dwDataLen -= wMsgLen;
+ }
+ szMsg[wMsgLen] = '\0';
+
+
+ pszMsgField[0] = szMsg;
+ nMsgFields = 0;
+ if (type == MTYPE_URL || type == MTYPE_AUTHREQ || type == MTYPE_ADDED || type == MTYPE_CONTACTS || type == MTYPE_EEXPRESS || type == MTYPE_WWP)
+ {
+ for (pszMsg=szMsg, nMsgFields=1; *pszMsg; pszMsg++)
+ {
+ if ((unsigned char)*pszMsg == 0xFE)
+ {
+ *pszMsg = '\0';
+ pszMsgField[nMsgFields++] = pszMsg + 1;
+ if (nMsgFields >= sizeof(pszMsgField)/sizeof(pszMsgField[0]))
+ 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;
+
+ wchar_t* usMsg;
+ wchar_t* usMsgW;
+
+ if (bThruDC)
+ {
+ DWORD dwExtraLen = *(DWORD*)pMsg;
+
+ if (dwExtraLen < dwDataLen && !strncmp(szMsg, "{\\rtf", 5))
+ { // it is icq5 sending us crap, get real message from it
+ int nStrSize;
+
+ usMsg = (wchar_t*)(pMsg + 4);
+ nStrSize = WideCharToMultiByte(CP_ACP, 0, usMsg, dwExtraLen, szMsg, 0, NULL, NULL);
+ SAFE_FREE(&szMsg);
+ szMsg = (char*)SAFE_MALLOC((nStrSize+1)*(sizeof(wchar_t)+1));
+ WideCharToMultiByte(CP_ACP, 0, usMsg, dwExtraLen, szMsg, nStrSize, NULL, NULL);
+ nStrSize = strlennull(szMsg); // this is necessary, sometimes it was bad
+ memcpy(szMsg+nStrSize+1, usMsg, dwExtraLen*sizeof(wchar_t));
+
+ pre.flags = PREF_UNICODE;
+
+ dwGuidLen = 0;
+ }
+ }
+
+ if (!pre.flags)
+ {
+ 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
+ char *szAnsiMessage = NULL;
+
+ if (utf8_decode(szMsg, &szAnsiMessage))
+ {
+ if (!strcmpnull(szMsg, szAnsiMessage))
+ {
+ SAFE_FREE(&szMsg);
+ szMsg = szAnsiMessage;
+ }
+ else
+ {
+ int nMsgLen = strlennull(szAnsiMessage) + 1;
+ int nMsgWLen;
+
+ usMsg = SAFE_MALLOC((nMsgLen)*(sizeof(wchar_t) + 1));
+ memcpy((char*)usMsg, szAnsiMessage, nMsgLen);
+ usMsgW = make_unicode_string(szMsg);
+ nMsgWLen = wcslen(usMsgW);
+ memcpy((char*)usMsg + nMsgLen, (char*)usMsgW, ((nMsgWLen>nMsgLen)?nMsgLen:nMsgWLen)*sizeof(wchar_t));
+ SAFE_FREE(&usMsgW);
+ SAFE_FREE(&szAnsiMessage);
+ SAFE_FREE(&szMsg);
+ szMsg = (char*)usMsg;
+ pre.flags = PREF_UNICODE;
+ }
+ }
+ else
+ {
+ NetLog_Uni(bThruDC, "Failed to translate UTF-8 message.");
+ }
+ 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);
+
+ 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_UNICODE;
+ }
+ }
+
+ ccs.szProtoService = PSR_MESSAGE;
+ ccs.hContact = hContact;
+ ccs.wParam = 0;
+ ccs.lParam = (LPARAM)&pre;
+ pre.timestamp = dwTimestamp;
+ pre.szMessage = (char *)szMsg;
+
+ CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs);
+ }
+ break;
+
+ case MTYPE_URL:
+ {
+ CCSDATA ccs;
+ PROTORECVEVENT pre = {0};
+ char* szBlob;
+
+
+ if (nMsgFields < 2)
+ {
+ NetLog_Uni(bThruDC, "Malformed '%s' message", "URL");
+ break;
+ }
+
+ szBlob = (char *)_alloca(strlennull(pszMsgField[0]) + strlennull(pszMsgField[1]) + 2);
+ strcpy(szBlob, pszMsgField[1]);
+ strcpy(szBlob + strlennull(szBlob) + 1, pszMsgField[0]);
+
+ ccs.szProtoService = PSR_URL;
+ ccs.hContact = hContact = HContactFromUIN(dwUin, &bAdded);
+ ccs.wParam = 0;
+ ccs.lParam = (LPARAM)&pre;
+ pre.timestamp = dwTimestamp;
+ pre.szMessage = (char *)szBlob;
+
+ CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs);
+ }
+ 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;
+ 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)+sizeof(HANDLE)+strlennull(pszMsgField[0])+strlennull(pszMsgField[1])+strlennull(pszMsgField[2])+strlennull(pszMsgField[3])+4;
+ pCurBlob=pBlob=(PBYTE)_alloca(cbBlob);
+ 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]);
+
+ ICQAddEvent(NULL, EVENTTYPE_ADDED, dwTimestamp, 0, cbBlob, pBlob);
+ }
+ break;
+
+ case MTYPE_CONTACTS:
+ {
+ CCSDATA ccs;
+ PROTORECVEVENT pre = {0};
+ ICQSEARCHRESULT** isrList;
+ char* pszNContactsEnd;
+ int nContacts;
+ int i;
+ int valid;
+
+
+ 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;
+ }
+
+ valid = 1;
+ 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);
+ 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
+ isrList[i]->uid = pszMsgField[1 + i * 2];
+ if (!strlennull(isrList[i]->uid))
+ valid = 0;
+ }
+ isrList[i]->hdr.nick = pszMsgField[2 + i * 2];
+ }
+
+ if (!valid)
+ {
+ NetLog_Uni(bThruDC, "Malformed '%s' message", "contacts");
+ }
+ else
+ {
+ ccs.szProtoService = PSR_CONTACTS;
+ ccs.hContact = hContact = HContactFromUIN(dwUin, &bAdded);
+ ccs.wParam = 0;
+ ccs.lParam = (LPARAM)&pre;
+ pre.timestamp = dwTimestamp;
+ pre.szMessage = (char *)isrList;
+ pre.lParam = nContacts;
+ CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs);
+ }
+
+ for (i = 0; i < nContacts; i++)
+ SAFE_FREE(&isrList[i]);
+ }
+ break;
+
+ case MTYPE_PLUGIN:
+ hContact = NULL;
+
+ switch(dwUin)
+ {
+ case 1002: /* SMS receipt */
+ handleSmsReceipt(pMsg, dwDataLen);
+ break;
+
+ case 1111: /* icqmail 'you've got mail' - not processed */
+ break;
+ }
+ 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]);
+
+ ICQAddEvent(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]);
+
+ ICQAddEvent(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_AUTOAWAY:
+ case MTYPE_AUTOBUSY:
+ case MTYPE_AUTONA:
+ case MTYPE_AUTODND:
+ case MTYPE_AUTOFFC:
+ {
+ char** szMsg = MirandaStatusToAwayMsg(AwayMsgTypeToStatus(type));
+
+ if (szMsg)
+ {
+ rate_record rr = {0};
+
+ rr.bType = RIT_AWAYMSG_RESPONSE;
+ rr.dwUin = dwUin;
+ rr.dwMid1 = dwMsgID;
+ rr.dwMid2 = dwMsgID2;
+ rr.wCookie = wCookie;
+ rr.wVersion = wVersion;
+ rr.msgType = type;
+ rr.rate_group = 0x102;
+ if (!handleRateItem(&rr, TRUE))
+ icq_sendAwayMsgReplyServ(dwUin, dwMsgID, dwMsgID2, wCookie, wVersion, (BYTE)type, szMsg);
+ }
+
+ break;
+ }
+
+ case MTYPE_FILEREQ: // Never happens
+ default:
+ NetLog_Uni(bThruDC, "Unprocessed message type %d", type);
+ break;
+
+ }
+
+ SAFE_FREE(&szMsg);
+}
+
+
+
+static void handleRecvMsgResponse(unsigned char *buf, WORD wLen, WORD wFlags, DWORD dwRef)
+{
+ DWORD dwUin;
+ DWORD dwCookie;
+ WORD wMessageFormat;
+ WORD wStatus;
+ WORD bMsgType = 0;
+ BYTE bFlags;
+ WORD wLength;
+ HANDLE hContact;
+ DWORD dwCookieUin;
+ DWORD dwMsgID1, dwMsgID2;
+ WORD wVersion = 0;
+ message_cookie_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, NULL)) return;
+
+ hContact = HContactFromUIN(dwUin, NULL);
+
+ buf += 2; // 3. unknown
+ wLen -= 2;
+
+ if (!FindMessageCookie(dwMsgID1, dwMsgID2, &dwCookie, &dwCookieUin, &pCookieData))
+ {
+ NetLog_Server("SNAC(4.B) Received an ack that I did not ask for from (%u)", dwUin);
+ 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, &dwCookieUin, &pCookieData))
+ { // use old reliable method
+ NetLog_Server("Warning: Invalid cookie in %s from (%u)", "message response", dwUin);
+ }
+ else if (bMsgType != MTYPE_PLUGIN && bMsgType != 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
+ {
+ bMsgType = pCookieData->bMessageType;
+ bFlags = 0;
+ }
+
+ if (dwCookieUin != dwUin)
+ {
+ NetLog_Server("SNAC(4.B) Ack UIN does not match Cookie UIN(%u != %u)", dwUin, dwCookieUin);
+
+ 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));
+ }
+ 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:
+ {
+ DWORD dwLengthToEnd;
+ DWORD dwDataLen;
+ DWORD dwPluginNameLen;
+ int typeId;
+ WORD wInfoLen;
+ char* szPluginName;
+ DWORD q1,q2,q3,q4;
+ WORD qt;
+
+ if (wLength != 0x1B)
+ {
+ NetLog_Server("Invalid Greeting %s", "message response");
+
+ ReleaseCookie(dwCookie);
+ return;
+ }
+
+ NetLog_Server("Parsing Greeting %s", "message response");
+
+ // Message
+ unpackLEWord(&buf, &wInfoLen);
+ wLen -= 2;
+ buf += wInfoLen;
+ wLen -= wInfoLen;
+
+ // This packet is malformed. Possibly a file accept from Miranda IM 0.1.2.1
+ if (wLen < 20) return;
+
+ unpackLEWord(&buf, &wInfoLen);
+
+ unpackDWord(&buf, &q1); // get data GUID & function id
+ unpackDWord(&buf, &q2);
+ unpackDWord(&buf, &q3);
+ unpackDWord(&buf, &q4);
+ unpackLEWord(&buf, &qt);
+ wLen -= 20;
+
+ unpackLEDWord(&buf, &dwPluginNameLen);
+ wLen -= 4;
+ if (dwPluginNameLen > wLen)
+ { // check for malformed plugin name
+ dwPluginNameLen = wLen;
+ NetLog_Server("Warning: malformed size of plugin name.");
+ }
+ szPluginName = (char *)_alloca(dwPluginNameLen + 1);
+ memcpy(szPluginName, buf, dwPluginNameLen);
+ szPluginName[dwPluginNameLen] = '\0';
+
+ buf += dwPluginNameLen + 15;
+ if (dwPluginNameLen == wLen)
+ wLen = 0;
+ else
+ wLen -= ((WORD)dwPluginNameLen + 15);
+
+ typeId = TypeGUIDToTypeId(q1, q2, q3, q4, qt);
+ if (!typeId)
+ NetLog_Server("Error: Unknown type {%04x%04x%04x%04x-%02x}: %s", q1,q2,q3,q4,qt,szPluginName);
+
+ 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_URL:
+ ackType = ACKTYPE_URL;
+ break;
+
+ case MTYPE_CONTACTS:
+ ackType = ACKTYPE_CONTACTS;
+ break;
+
+ case MTYPE_FILEREQ:
+ {
+ char* szMsg;
+
+ NetLog_Server("This is file ack");
+ 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;
+
+ 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;
+
+ default:
+ NetLog_Server("Error: Unknown greeting %s, type \"%s\".", "message response", szPluginName);
+ 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:
+ {
+ reverse_cookie *pReverse = (reverse_cookie*)pCookieData;
+
+ if (pReverse->ft)
+ {
+ filetransfer *ft = (filetransfer*)pReverse->ft;
+
+ ICQBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0);
+ }
+ NetLog_Server("Reverse Connect request failed");
+ }
+ break;
+
+ case MTYPE_CHAT:
+ default:
+ NetLog_Server("SNAC(4.B) Unknown message type (%u) in switch", bMsgType);
+ return;
+ }
+
+ if (bMsgType != MTYPE_REVERSE_REQUEST && ((ackType == MTYPE_PLAIN && pCookieData && (pCookieData->nAckType == ACKTYPE_CLIENT)) ||
+ ackType != MTYPE_PLAIN))
+ {
+ ICQBroadcastAck(hContact, ackType, ACKRESULT_SUCCESS, (HANDLE)(WORD)dwCookie, 0);
+ }
+ }
+
+ ReleaseCookie(dwCookie);
+}
+
+
+// A response to a CLI_SENDMSG
+static void handleRecvServMsgError(unsigned char *buf, WORD wLen, WORD wFlags, DWORD dwSequence)
+{
+ WORD wError;
+ char* pszErrorMessage;
+ DWORD dwUin;
+ HANDLE hContact;
+ message_cookie_data* pCookieData = NULL;
+ int nMessageType;
+
+
+ if (wLen < 2)
+ return;
+
+ if (FindCookie((WORD)dwSequence, &dwUin, &pCookieData))
+ { // all packet cookies from msg family has command 0 in the queue
+ hContact = HContactFromUIN(dwUin, NULL);
+
+ // Error code
+ unpackWord(&buf, &wError);
+
+ if ((hContact == NULL) || (hContact == INVALID_HANDLE_VALUE))
+ {
+ NetLog_Server("SNAC(4.1) Received a SENDMSG Error (%u) from invalid contact %u", wError, dwUin);
+
+ ReleaseCookie((WORD)dwSequence);
+ return;
+ }
+ 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)));
+ packFNACHeaderFull(&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 = ICQTranslate("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 = ICQTranslate("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) // TODO: this needs better solution
+ ICQWriteContactSettingWord(hContact, "Status", ID_STATUS_OFFLINE);
+ pszErrorMessage = ICQTranslate("The user has logged off. Select 'Retry' to send an offline message.\r\nSNAC(4.1) Error x04");
+ break;
+
+ case 0x0009: // Not supported by client (resend in a simpler format)
+ pszErrorMessage = ICQTranslate("The receiving client does not support this type of message.\r\nSNAC(4.1) Error x09");
+ break;
+
+ case 0x000A: // Refused by client
+ pszErrorMessage = ICQTranslate("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 = ICQTranslate("The SNAC format was rejected by the server.\nSNAC(4.1) Error x0E");
+ break;
+
+ case 0x0013: // User temporarily unavailable
+ pszErrorMessage = ICQTranslate("The user is temporarily unavailable. Wait a while and try again.\r\nSNAC(4.1) Error x13");
+ break;
+
+ case 0x0001: // Invalid SNAC header
+ case 0x0005: // Requested service unavailable
+ 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 = _alloca(256))
+ null_snprintf(pszErrorMessage, 256, ICQTranslate("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)
+ {
+ ICQBroadcastAck(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(&pCookieData);
+ }
+ else
+ {
+ WORD wError;
+
+ unpackWord(&buf, &wError);
+
+ LogFamilyError(ICQ_MSG_FAMILY, wError);
+ }
+}
+
+
+
+static void handleServerAck(unsigned char *buf, WORD wLen, WORD wFlags, DWORD dwSequence)
+{
+ DWORD dwUin;
+ uid_str szUID;
+ WORD wChannel;
+ HANDLE hContact;
+ message_cookie_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;
+
+ hContact = HContactFromUID(dwUin, szUID, NULL);
+
+ if (FindCookie((WORD)dwSequence, &dwUin, &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)
+ ICQBroadcastAck(hContact, ackType, ackRes, (HANDLE)(WORD)dwSequence, 0);
+
+ if (pCookieData->bMessageType != MTYPE_FILEREQ)
+ SAFE_FREE(&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");
+ }
+ }
+
+ return;
+}
+
+
+
+static void handleMissedMsg(unsigned char *buf, WORD wLen, WORD wFlags, DWORD dwRef)
+{
+ DWORD dwUin;
+ WORD wChannel;
+ WORD wWarningLevel;
+ WORD wCount;
+ WORD wError;
+ WORD wTLVCount;
+ char* pszErrorMsg;
+ oscar_tlv_chain* pChain;
+
+
+ if (wLen < 14)
+ return; // Too short
+
+ // Message channel?
+ unpackWord(&buf, &wChannel);
+ wLen -= 2;
+
+ // Sender
+ if (!unpackUID(&buf, &wLen, &dwUin, NULL)) 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
+ 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;
+
+ switch (wError)
+ {
+
+ case 0:
+ pszErrorMsg = ICQTranslate("** This message was blocked by the ICQ server ** The message was invalid.");
+ break;
+
+ case 1:
+ pszErrorMsg = ICQTranslate("** This message was blocked by the ICQ server ** The message was too long.");
+ break;
+
+ case 2:
+ pszErrorMsg = ICQTranslate("** This message was blocked by the ICQ server ** The sender has flooded the server.");
+ break;
+
+ case 4:
+ pszErrorMsg = ICQTranslate("** This message was blocked by the ICQ server ** You are too evil.");
+ break;
+
+ default:
+ // 3 = Sender too evil (sender warn level > your max_msg_sevil)
+ return;
+ break;
+ }
+
+
+ // Create message to notify user
+ {
+ CCSDATA ccs;
+ PROTORECVEVENT pre;
+ int bAdded;
+
+ ccs.szProtoService = PSR_MESSAGE;
+ ccs.hContact = HContactFromUIN(dwUin, &bAdded);
+ ccs.wParam = 0;
+ ccs.lParam = (LPARAM)&pre;
+ pre.flags = 0;
+ pre.timestamp = time(NULL);
+ pre.szMessage = pszErrorMsg;
+ pre.lParam = 0;
+
+ CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs);
+ }
+}
+
+
+
+static void handleTypingNotification(unsigned char* buf, WORD wLen, WORD wFlags, DWORD dwRef)
+{
+ DWORD dwUin;
+ uid_str szUID;
+ WORD wChannel;
+ WORD wNotification;
+ HANDLE hContact;
+
+ 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;
+
+ 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;
+
+ default:
+ NetLog_Server("Unknown typing notification from %s, type %u (ch %u)", strUID(dwUin, szUID), wNotification, wChannel);
+ break;
+ }
+
+ return;
+}
+
+
+
+void sendTypingNotification(HANDLE hContact, WORD wMTNCode)
+{
+ icq_packet p;
+ BYTE byUinlen;
+ DWORD dwUin;
+ uid_str szUID;
+
+ _ASSERTE((wMTNCode == MTN_FINISHED) || (wMTNCode == MTN_TYPED) || (wMTNCode == MTN_BEGUN));
+
+ if (ICQGetContactSettingUID(hContact, &dwUin, &szUID))
+ return; // Invalid contact
+
+ byUinlen = getUIDLen(dwUin, szUID);
+
+ serverPacketInit(&p, (WORD)(23 + byUinlen));
+ packFNACHeader(&p, ICQ_MSG_FAMILY, ICQ_MSG_MTN);
+ packLEDWord(&p, 0x0000); // Msg ID
+ packLEDWord(&p, 0x0000); // Msg ID
+ packWord(&p, 0x01); // Channel
+ packUID(&p, dwUin, szUID); // User ID
+ packWord(&p, wMTNCode); // Notification type
+
+ sendServPacket(&p);
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/fam_09bos.c b/miranda-wine/protocols/IcqOscarJ/fam_09bos.c
new file mode 100644
index 0000000..eebacf3
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/fam_09bos.c
@@ -0,0 +1,132 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/fam_09bos.c,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+
+static void handlePrivacyRightsReply(unsigned char *pBuffer, WORD wBufferLength);
+
+void 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;
+
+ }
+}
+
+
+
+static void handlePrivacyRightsReply(unsigned char *pBuffer, WORD wBufferLength)
+{
+ if (wBufferLength >= 12)
+ {
+ oscar_tlv_chain* pChain;
+
+
+ pChain = readIntoTLVChain(&pBuffer, wBufferLength, 0);
+
+ if (pChain)
+ {
+ WORD wMaxVisibleContacts;
+ WORD wMaxInvisibleContacts;
+
+
+ wMaxVisibleContacts = getWordFromChain(pChain, 0x0001, 1);
+ wMaxInvisibleContacts = getWordFromChain(pChain, 0x0001, 1);
+
+ disposeChain(&pChain);
+
+ NetLog_Server("PRIVACY: Max visible %u, max invisible %u items.", wMaxVisibleContacts, wMaxInvisibleContacts);
+
+ // Success
+ return;
+ }
+ }
+
+ // Failure
+ NetLog_Server("Warning: Malformed SRV_PRIVACY_RIGHTS_REPLY");
+}
+
+
+
+void makeContactTemporaryVisible(HANDLE hContact)
+{
+ DWORD dwUin;
+ uid_str szUid;
+
+ if (ICQGetContactSettingByte(hContact, "TemporaryVisible", 0))
+ return; // already there
+
+ if (ICQGetContactSettingUID(hContact, &dwUin, &szUid))
+ return; // Invalid contact
+
+ icq_sendGenericContact(dwUin, szUid, ICQ_BOS_FAMILY, ICQ_CLI_ADDTEMPVISIBLE);
+
+ ICQWriteContactSettingByte(hContact, "TemporaryVisible", 1);
+
+#ifdef _DEBUG
+ NetLog_Server("Added contact %s to temporary visible list", strUID(dwUin, szUid));
+#endif
+}
+
+
+
+void clearTemporaryVisibleList()
+{ // remove all temporary visible contacts
+ sendEntireListServ(ICQ_BOS_FAMILY, ICQ_CLI_REMOVETEMPVISIBLE, BUL_TEMPVISIBLE);
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/fam_0alookup.c b/miranda-wine/protocols/IcqOscarJ/fam_0alookup.c
new file mode 100644
index 0000000..40eaa7c
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/fam_0alookup.c
@@ -0,0 +1,144 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/fam_0alookup.c,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+static void handleLookupEmailReply(BYTE* buf, WORD wLen, DWORD dwCookie);
+static void ReleaseLookupCookie(DWORD dwCookie, search_cookie* pCookie);
+
+
+void handleLookupFam(unsigned char *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;
+ search_cookie* pCookie;
+
+ if (wBufferLength >= 2)
+ unpackWord(&pBuffer, &wError);
+ else
+ wError = 0;
+
+ if (FindCookie(pSnacHeader->dwRef, NULL, &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;
+ }
+}
+
+
+
+static void ReleaseLookupCookie(DWORD dwCookie, search_cookie* 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)
+ ICQBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)pCookie->dwMainId, 0);
+ else // we are single
+ ICQBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)dwCookie, 0);
+
+ SAFE_FREE(&pCookie);
+ }
+}
+
+
+
+void handleLookupEmailReply(BYTE* buf, WORD wLen, DWORD dwCookie)
+{
+ ICQSEARCHRESULT sr = {0};
+ oscar_tlv_chain* pChain;
+ search_cookie* pCookie;
+ int i;
+
+ if (!FindCookie(dwCookie, NULL, &pCookie))
+ {
+ NetLog_Server("Error: Received unexpected lookup reply");
+ return;
+ }
+ else
+ NetLog_Server("SNAC(0x0A,0x3): Lookup reply");
+
+ sr.hdr.cbSize = sizeof(sr);
+ sr.hdr.email = pCookie->szObject;
+
+ // Syntax check, read chain
+ if (wLen >= 4 && (pChain = readIntoTLVChain(&buf, wLen, 0)))
+ {
+ for (i = 1; TRUE; i++)
+ { // collect the results
+ sr.hdr.nick = getStrFromChain(pChain, 1, (WORD)i);
+ if (!sr.hdr.nick) break;
+ sr.uid = sr.hdr.nick;
+ // broadcast the result
+ if (pCookie->dwMainId)
+ ICQBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)pCookie->dwMainId, (LPARAM)&sr);
+ else
+ ICQBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)dwCookie, (LPARAM)&sr);
+ SAFE_FREE(&sr.hdr.nick);
+ }
+ disposeChain(&pChain);
+ }
+
+ ReleaseLookupCookie(dwCookie, pCookie);
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/fam_0bstatus.c b/miranda-wine/protocols/IcqOscarJ/fam_0bstatus.c
new file mode 100644
index 0000000..3539695
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/fam_0bstatus.c
@@ -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,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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/fam_0bstatus.c,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+void 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/miranda-wine/protocols/IcqOscarJ/fam_13servclist.c b/miranda-wine/protocols/IcqOscarJ/fam_13servclist.c
new file mode 100644
index 0000000..828b2a9
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/fam_13servclist.c
@@ -0,0 +1,1863 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/fam_13servclist.c,v $
+// Revision : $Revision: 3432 $
+// Last change on : $Date: 2006-08-03 02:57:21 +0400 (Чтв, 03 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+extern WORD wListenPort;
+
+extern void setUserInfo();
+extern int GroupNameExistsUtf(const char *name,int skipGroup);
+
+BOOL bIsSyncingCL = FALSE;
+
+static HANDLE HContactFromRecordName(char* szRecordName, int *bAdded);
+
+static int getServerDataFromItemTLV(oscar_tlv_chain* pChain, unsigned char *buf);
+
+static int unpackServerListItem(unsigned char** pbuf, WORD* pwLen, char* pszRecordName, WORD* pwGroupId, WORD* pwItemId, WORD* pwItemType, WORD* pwTlvLength);
+
+static void handleServerCListAck(servlistcookie* sc, WORD wError);
+static void handleServerCList(unsigned char *buf, WORD wLen, WORD wFlags, serverthread_info *info);
+static void handleRecvAuthRequest(unsigned char *buf, WORD wLen);
+static void handleRecvAuthResponse(unsigned char *buf, WORD wLen);
+static void handleRecvAdded(unsigned char *buf, WORD wLen);
+void sendRosterAck(void);
+
+
+static WORD swapWord(WORD val)
+{
+ return (val & 0xFF)<<8 | (val>>8);
+}
+
+
+
+void handleServClistFam(unsigned char *pBuffer, WORD wBufferLength, snac_header* pSnacHeader, serverthread_info *info)
+{
+ switch (pSnacHeader->wSubtype)
+ {
+
+ case ICQ_LISTS_ACK: // UPDATE_ACK
+ if (wBufferLength >= 2)
+ {
+ WORD wError;
+ DWORD dwActUin;
+ servlistcookie* sc;
+
+ unpackWord(&pBuffer, &wError);
+
+ if (FindCookie(pSnacHeader->dwRef, &dwActUin, &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
+
+ handleServerCListAck(sc, wError);
+ }
+ else
+ {
+ NetLog_Server("Received unexpected server list ack %u", wError);
+ }
+ }
+ break;
+
+ case ICQ_LISTS_SRV_REPLYLISTS:
+ {
+ /* received list rights, we just skip them */
+
+ oscar_tlv_chain* chain;
+
+ if (chain = readIntoTLVChain(&pBuffer, wBufferLength, 0))
+ {
+ oscar_tlv* pTLV;
+
+ if ((pTLV = getTLV(chain, 0x04, 1)) && pTLV->wLen>=30)
+ { // limits for item types
+ WORD* pMax = (WORD*)pTLV->pData;
+
+ NetLog_Server("SSI: Max %d contacts, %d groups, %d permit, %d deny, %d ignore items.", swapWord(pMax[0]), swapWord(pMax[1]), swapWord(pMax[2]), swapWord(pMax[3]), swapWord(pMax[14]));
+ }
+
+ disposeChain(&chain);
+ }
+#ifdef _DEBUG
+ NetLog_Server("Server sent SNAC(x13,x03) - SRV_REPLYLISTS");
+#endif
+ }
+ break;
+
+ case ICQ_LISTS_LIST: // SRV_REPLYROSTER
+ {
+ servlistcookie* sc;
+ BOOL blWork;
+
+ blWork = bIsSyncingCL;
+ bIsSyncingCL = TRUE; // this is not used if cookie takes place
+
+ if (FindCookie(pSnacHeader->dwRef, NULL, &sc))
+ { // we do it by reliable cookie
+ if (!sc->dwUin)
+ { // is this first packet ?
+ ResetSettingsOnListReload();
+ sc->dwUin = 1;
+ }
+ handleServerCList(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();
+ }
+ handleServerCList(pBuffer, wBufferLength, pSnacHeader->wFlags, info);
+ }
+ break;
+ }
+
+ case ICQ_LISTS_UPTODATE: // SRV_REPLYROSTEROK
+ {
+ servlistcookie* sc;
+
+ bIsSyncingCL = FALSE;
+
+ if (FindCookie(pSnacHeader->dwRef, NULL, &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", 0x11, "Server is modifying contact list");
+ break;
+
+ case ICQ_LISTS_CLI_MODIFYEND:
+ NetLog_Server("Server sent SNAC(x13,x%02x) - %s", 0x12, "End of server modification");
+ break;
+
+ case ICQ_LISTS_UPDATEGROUP:
+ if (wBufferLength >= 10)
+ {
+ WORD wGroupId, wItemId, wItemType, wTlvLen;
+ uid_str szUID;
+
+ if (unpackServerListItem(&pBuffer, &wBufferLength, szUID, &wGroupId, &wItemId, &wItemType, &wTlvLen))
+ {
+ HANDLE hContact = HContactFromRecordName(szUID, NULL);
+
+ if (wBufferLength >= wTlvLen && hContact != INVALID_HANDLE_VALUE && wItemType == SSI_ITEM_BUDDY)
+ { // a contact was updated on server
+ if (wTlvLen > 0)
+ { // parse details
+ oscar_tlv_chain *pChain = readIntoTLVChain(&pBuffer, (WORD)(wTlvLen), 0);
+
+ if (pChain)
+ {
+ oscar_tlv* pAuth = getTLV(pChain, SSI_TLV_AWAITING_AUTH, 1);
+ BYTE bAuth = ICQGetContactSettingByte(hContact, "Auth", 0);
+
+ if (bAuth && !pAuth)
+ { // server authorised our contact
+ char str[MAX_PATH];
+ char msg[MAX_PATH];
+ char *nick = NickFromHandleUtf(hContact);
+
+ ICQWriteContactSettingByte(hContact, "Auth", 0);
+ null_snprintf(str, MAX_PATH, ICQTranslateUtfStatic("User \"%s\" was authorised in the server list.", msg), nick);
+ icq_LogMessage(LOG_WARNING, str);
+ SAFE_FREE(&nick);
+ }
+
+ { // update server's data - otherwise consequent operations can fail with 0x0E
+ unsigned char* data = (unsigned char*)_alloca(wTlvLen);
+ int datalen = getServerDataFromItemTLV(pChain, data);
+
+ if (datalen > 0)
+ ICQWriteContactSettingBlob(hContact, "ServerData", data, datalen);
+ else
+ ICQDeleteContactSetting(hContact, "ServerData");
+ }
+
+ disposeChain(&pChain);
+
+ break;
+ }
+ }
+ }
+ }
+ }
+ NetLog_Server("Server sent SNAC(x13,x%02x) - %s", 0x09, "Server updated our contact on list");
+ break;
+
+ case ICQ_LISTS_REMOVEFROMLIST:
+ if (wBufferLength >= 10)
+ {
+ WORD wGroupId, wItemId, wItemType;
+ uid_str szUID;
+
+ if (unpackServerListItem(&pBuffer, &wBufferLength, szUID, &wGroupId, &wItemId, &wItemType, NULL))
+ {
+ HANDLE hContact = HContactFromRecordName(szUID, NULL);
+
+ if (hContact != INVALID_HANDLE_VALUE && wItemType == SSI_ITEM_BUDDY)
+ { // a contact was removed from our list
+ ICQDeleteContactSetting(hContact, "ServerId");
+ ICQDeleteContactSetting(hContact, "SrvGroupId");
+ ICQDeleteContactSetting(hContact, "Auth");
+ icq_sendNewContact(0, szUID); // add to CS to see him
+ {
+ char str[MAX_PATH];
+ char msg[MAX_PATH];
+ char *nick = NickFromHandleUtf(hContact);
+
+ null_snprintf(str, MAX_PATH, ICQTranslateUtfStatic("User \"%s\" was removed from server list.", msg), nick);
+ icq_LogMessage(LOG_WARNING, str);
+ SAFE_FREE(&nick);
+ }
+ }
+ }
+ }
+ NetLog_Server("Server sent SNAC(x13,x%02x) - %s", 0x0A, "Server removed something from our list");
+ break;
+
+ case ICQ_LISTS_ADDTOLIST:
+ if (wBufferLength >= 10)
+ {
+ WORD wGroupId, wItemId, wItemType, wTlvLen;
+
+ if (unpackServerListItem(&pBuffer, &wBufferLength, NULL, &wGroupId, &wItemId, &wItemType, &wTlvLen))
+ {
+ if (wBufferLength >= wTlvLen && wItemType == SSI_ITEM_IMPORTTIME)
+ {
+ if (wTlvLen > 0)
+ { // parse timestamp
+ oscar_tlv_chain *pChain = readIntoTLVChain(&pBuffer, (WORD)(wTlvLen), 0);
+
+ if (pChain)
+ {
+ ICQWriteContactSettingDword(NULL, "ImportTS", getDWordFromChain(pChain, SSI_TLV_TIMESTAMP, 1));
+ ICQWriteContactSettingWord(NULL, "SrvImportID", wItemId);
+ disposeChain(&pChain);
+
+ NetLog_Server("Server added Import timestamp to list");
+
+ break;
+ }
+ }
+ }
+ }
+ }
+ NetLog_Server("Server sent SNAC(x13,x%02x) - %s", 0x08, "Server added something to our list");
+ 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", 0x15, "User granted us future authorization");
+ break;
+
+ case ICQ_LISTS_YOUWEREADDED:
+ handleRecvAdded(pBuffer, wBufferLength);
+ break;
+
+ case ICQ_LISTS_ERROR:
+ if (wBufferLength >= 2)
+ {
+ WORD wError;
+ DWORD dwActUin;
+ servlistcookie* sc;
+
+ unpackWord(&pBuffer, &wError);
+
+ if (FindCookie(pSnacHeader->dwRef, &dwActUin, &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, "Server contact list is unavailable, Miranda will use local contact list.");
+ gbSsiEnabled = 0;
+ handleServUINSettings(wListenPort, info);
+ }
+ SAFE_FREE(&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(unsigned char** 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
+}
+
+
+
+static DWORD updateServerGroupData(WORD wGroupId, void *groupData, int groupSize)
+{
+ DWORD dwCookie;
+ servlistcookie* ack;
+
+ ack = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie));
+ if (!ack)
+ {
+ NetLog_Server("Updating of group on server list failed (malloc error)");
+ return 0;
+ }
+ ack->dwAction = SSA_GROUP_UPDATE;
+ ack->szGroupName = getServerGroupNameUtf(wGroupId);
+ ack->wGroupId = wGroupId;
+ dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, 0, ack);
+
+ return icq_sendGroupUtf(dwCookie, ICQ_LISTS_UPDATEGROUP, ack->wGroupId, ack->szGroupName, groupData, groupSize);
+}
+
+
+
+static void handleServerCListAck(servlistcookie* 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:
+ {
+ RemovePendingOperation(sc->hContact, 1);
+ if (wError)
+ {
+ NetLog_Server("Updating of server contact failed, error %d", wError);
+ icq_LogMessage(LOG_WARNING, "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, "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, "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.");
+
+ ICQWriteContactSettingByte(sc->hContact, "Auth", 1); // we need auth
+ dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_ADDTOLIST, sc->dwUin, sc);
+ icq_sendServerContact(sc->hContact, dwCookie, ICQ_LISTS_ADDTOLIST, sc->wGroupId, sc->wContactId);
+
+ sc = NULL; // we do not want it to be freed now
+ break;
+ }
+ FreeServerID(sc->wContactId, SSIT_ITEM);
+ sendAddEnd(); // end server modifications here
+ RemovePendingOperation(sc->hContact, 0);
+
+ NetLog_Server("Adding of contact to server list failed, error %d", wError);
+ icq_LogMessage(LOG_WARNING, "Adding of contact to server list failed.");
+ }
+ else
+ {
+ void* groupData;
+ int groupSize;
+ HANDLE hPend = sc->hContact;
+
+ ICQWriteContactSettingWord(sc->hContact, "ServerId", sc->wContactId);
+ ICQWriteContactSettingWord(sc->hContact, "SrvGroupId", sc->wGroupId);
+
+ if (groupData = collectBuddyGroup(sc->wGroupId, &groupSize))
+ { // the group is not empty, just update it
+ updateServerGroupData(sc->wGroupId, groupData, groupSize);
+ SAFE_FREE(&groupData);
+ }
+ else
+ { // this should never happen
+ NetLog_Server("Group update failed.");
+ }
+ sendAddEnd(); // end server modifications here
+
+ if (hPend) RemovePendingOperation(hPend, 1);
+ }
+ 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, "Adding of group to server list failed.");
+ }
+ else // group added, we need to update master group
+ {
+ void* groupData;
+ int groupSize;
+ servlistcookie* ack;
+ DWORD dwCookie;
+
+ setServerGroupNameUtf(sc->wGroupId, sc->szGroupName); // add group to namelist
+ setServerGroupIDUtf(makeGroupPathUtf(sc->wGroupId), sc->wGroupId); // add group to known
+
+ groupData = collectGroups(&groupSize);
+ groupData = realloc(groupData, groupSize+2);
+ *(((WORD*)groupData)+(groupSize>>1)) = sc->wGroupId; // add this new group id
+ groupSize += 2;
+
+ ack = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie));
+ if (ack)
+ {
+ ack->dwAction = SSA_GROUP_UPDATE;
+ dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, 0, ack);
+
+ icq_sendGroupUtf(dwCookie, ICQ_LISTS_UPDATEGROUP, 0, ack->szGroupName, groupData, groupSize);
+ }
+ sendAddEnd(); // end server modifications here
+
+ SAFE_FREE(&groupData);
+
+ if (sc->ofCallback) // is add contact pending
+ {
+ sc->ofCallback(sc->wGroupId, (LPARAM)sc->lParam);
+ // sc = NULL; // we do not want to be freed here
+ }
+ }
+ SAFE_FREE(&sc->szGroupName);
+ break;
+ }
+ case SSA_CONTACT_REMOVE:
+ {
+ if (!wError)
+ {
+ void* groupData;
+ int groupSize;
+
+ ICQWriteContactSettingWord(sc->hContact, "ServerId", 0); // clear the values
+ ICQWriteContactSettingWord(sc->hContact, "SrvGroupId", 0);
+
+ FreeServerID(sc->wContactId, SSIT_ITEM);
+
+ if (groupData = collectBuddyGroup(sc->wGroupId, &groupSize))
+ { // the group is still not empty, just update it
+ updateServerGroupData(sc->wGroupId, groupData, groupSize);
+
+ sendAddEnd(); // end server modifications here
+ }
+ else // the group is empty, delete it if it does not have sub-groups
+ {
+ DWORD dwCookie;
+
+ if (!CheckServerID((WORD)(sc->wGroupId+1), 0) || countGroupLevel((WORD)(sc->wGroupId+1)) == 0)
+ { // is next id an sub-group, if yes, we cannot delete this group
+ sc->dwAction = SSA_GROUP_REMOVE;
+ sc->wContactId = 0;
+ sc->hContact = NULL;
+ sc->szGroupName = getServerGroupNameUtf(sc->wGroupId);
+ dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_REMOVEFROMLIST, 0, sc);
+
+ icq_sendGroupUtf(dwCookie, ICQ_LISTS_REMOVEFROMLIST, sc->wGroupId, sc->szGroupName, NULL, 0);
+ // here the modifications go on
+ sc = NULL; // we do not want it to be freed now
+ }
+ }
+ SAFE_FREE(&groupData); // free the memory
+ }
+ else
+ {
+ NetLog_Server("Removing of contact from server list failed, error %d", wError);
+ icq_LogMessage(LOG_WARNING, "Removing of contact from server list failed.");
+ sendAddEnd(); // 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, "Updating of group on server list failed.");
+ }
+ SAFE_FREE(&sc->szGroupName);
+ break;
+ }
+ case SSA_GROUP_REMOVE:
+ {
+ SAFE_FREE(&sc->szGroupName);
+ if (wError)
+ {
+ NetLog_Server("Removing of group from server list failed, error %d", wError);
+ icq_LogMessage(LOG_WARNING, "Removing of group from server list failed.");
+ }
+ else // group removed, we need to update master group
+ {
+ void* groupData;
+ int groupSize;
+ DWORD dwCookie;
+
+ setServerGroupNameUtf(sc->wGroupId, NULL); // clear group from namelist
+ FreeServerID(sc->wGroupId, SSIT_GROUP);
+ removeGroupPathLinks(sc->wGroupId);
+
+ groupData = collectGroups(&groupSize);
+ sc->wGroupId = 0;
+ sc->dwAction = SSA_GROUP_UPDATE;
+ sc->szGroupName = NULL;
+ dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, 0, sc);
+
+ icq_sendGroupUtf(dwCookie, ICQ_LISTS_UPDATEGROUP, 0, sc->szGroupName, groupData, groupSize);
+ sendAddEnd(); // end server modifications here
+
+ sc = NULL; // we do not want to be freed here
+
+ SAFE_FREE(&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)
+ {
+ RemovePendingOperation(sc->hContact, 0);
+ NetLog_Server("Moving of user to another group on server list failed, error %d", wError);
+ icq_LogMessage(LOG_WARNING, "Moving of user to another group on server list failed.");
+ 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
+
+ ICQWriteContactSettingWord(sc->hContact, "ServerId", sc->wNewContactId);
+ ICQWriteContactSettingWord(sc->hContact, "SrvGroupId", sc->wNewGroupId);
+ FreeServerID(sc->wContactId, SSIT_ITEM); // release old contact id
+
+ 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);
+ SAFE_FREE(&groupData); // free the memory
+ }
+ else if (!CheckServerID((WORD)(sc->wGroupId+1), 0) || countGroupLevel((WORD)(sc->wGroupId+1)) == 0)
+ { // the group is empty and is not followed by sub-groups, delete it
+ DWORD dwCookie;
+ servlistcookie* ack;
+
+ ack = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie));
+ if (!ack)
+ {
+ NetLog_Server("Updating of group on server list failed (malloc error)");
+ break;
+ }
+ ack->dwAction = SSA_GROUP_REMOVE;
+ ack->szGroupName = getServerGroupNameUtf(sc->wGroupId);
+ ack->wGroupId = sc->wGroupId;
+ dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_REMOVEFROMLIST, 0, ack);
+
+ icq_sendGroupUtf(dwCookie, ICQ_LISTS_REMOVEFROMLIST, ack->wGroupId, ack->szGroupName, NULL, 0);
+ bEnd = 0; // here the modifications go on
+ }
+
+ groupData = collectBuddyGroup(sc->wNewGroupId, &groupSize); // update the group we moved to
+ updateServerGroupData(sc->wNewGroupId, groupData, groupSize);
+ SAFE_FREE(&groupData);
+
+ if (bEnd) sendAddEnd();
+ if (sc->hContact) RemovePendingOperation(sc->hContact, 1);
+ }
+ else // contact was deleted from server-list
+ {
+ ICQDeleteContactSetting(sc->hContact, "ServerId");
+ ICQDeleteContactSetting(sc->hContact, "SrvGroupId");
+ sc->lParam = 1;
+ sc = NULL; // wait for second ack
+ }
+ break;
+ }
+ case SSA_GROUP_RENAME:
+ {
+ if (wError)
+ {
+ NetLog_Server("Renaming of server group failed, error %d", wError);
+ icq_LogMessage(LOG_WARNING, "Renaming of server group failed.");
+ }
+ else
+ {
+ setServerGroupNameUtf(sc->wGroupId, sc->szGroupName);
+ removeGroupPathLinks(sc->wGroupId);
+ setServerGroupIDUtf(makeGroupPathUtf(sc->wGroupId), sc->wGroupId);
+ }
+ RemoveGroupRename(sc->wGroupId);
+ SAFE_FREE(&sc->szGroupName);
+ 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);
+ ICQDeleteContactSetting(NULL, "SrvAvatarID"); // to fix old versions
+ }
+ }
+ else
+ {
+ ICQWriteContactSettingWord(NULL, "SrvAvatarID", sc->wContactId);
+ }
+ break;
+ }
+ case SSA_REMOVEAVATAR:
+ {
+ if (wError)
+ NetLog_Server("Removing of avatar hash failed.");
+ else
+ {
+ ICQDeleteContactSetting(NULL, "SrvAvatarID");
+ FreeServerID(sc->wContactId, SSIT_ITEM);
+ }
+ break;
+ }
+ case SSA_SERVLIST_ACK:
+ {
+ ICQBroadcastAck(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
+ {
+ ICQWriteContactSettingWord(NULL, "SrvImportID", 0);
+ ICQDeleteContactSetting(NULL, "ImportTS");
+ }
+ break;
+ }
+ default:
+ NetLog_Server("Server ack cookie type (%d) not recognized.", sc->dwAction);
+ }
+ SAFE_FREE(&sc); // free the memory
+
+ return;
+}
+
+
+
+static HANDLE HContactFromRecordName(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;
+
+ dwUin = atoi(szRecordName);
+ hContact = HContactFromUIN(dwUin, bAdded);
+ }
+ return hContact;
+}
+
+
+
+static int getServerDataFromItemTLV(oscar_tlv_chain* pChain, unsigned char *buf)
+{ // 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)
+ { // 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;
+}
+
+
+static void handleServerCList(unsigned char *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;
+
+
+ // 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;
+ WORD wOldGroupId;
+
+ if (bAdded)
+ { // Not already on list: added
+ char* szGroup;
+
+ NetLog_Server("SSI added new %s contact '%s'", "ICQ", szRecordName);
+
+ if (szGroup = makeGroupPathUtf(wGroupId))
+ { // try to get Miranda Group path from groupid, if succeeded save to db
+ UniWriteContactSettingUtf(hContact, "CList", "Group", szGroup);
+
+ SAFE_FREE(&szGroup);
+ }
+ 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);
+ }
+
+ wOldGroupId = ICQGetContactSettingWord(hContact, "SrvGroupId", 0);
+ // Save group and item ID
+ ICQWriteContactSettingWord(hContact, "ServerId", wItemId);
+ ICQWriteContactSettingWord(hContact, "SrvGroupId", wGroupId);
+ ReserveServerID(wItemId, SSIT_ITEM);
+
+ if (!bAdded && (wOldGroupId != wGroupId) && ICQGetContactSettingByte(NULL, "LoadServerDetails", DEFAULT_SS_LOAD))
+ { // contact has been moved on the server
+ char* szOldGroup = getServerGroupNameUtf(wOldGroupId);
+ char* szGroup = getServerGroupNameUtf(wGroupId);
+
+ if (!szOldGroup)
+ { // old group is not known, most probably not created subgroup
+ char* szTmp = UniGetContactSettingUtf(hContact, "CList", "Group", "");
+
+ if (strlennull(szTmp))
+ { // got group from CList
+ SAFE_FREE(&szOldGroup);
+ szOldGroup = szTmp;
+ }
+ else
+ SAFE_FREE(&szTmp);
+
+ if (!szOldGroup) szOldGroup = null_strdup(DEFAULT_SS_GROUP);
+ }
+
+ if (!szGroup || strlennull(szGroup)>=strlennull(szOldGroup) || strnicmp(szGroup, szOldGroup, strlennull(szGroup)))
+ { // contact moved to new group or sub-group or not to master group
+ bRegroup = 1;
+ }
+ if (bRegroup && !stricmp(DEFAULT_SS_GROUP, szGroup) && !GroupNameExistsUtf(szGroup, -1))
+ { // is it the default "General" group ? yes, does it exists in CL ?
+ bRegroup = 0; // if no, do not move to it - cause it would hide the contact
+ }
+ SAFE_FREE(&szGroup);
+ SAFE_FREE(&szOldGroup);
+ }
+
+ if (bRegroup || bAdded)
+ { // if we should load server details or contact was just added, update its group
+ char* szGroup;
+
+ if (szGroup = makeGroupPathUtf(wGroupId))
+ { // try to get Miranda Group path from groupid, if succeeded save to db
+ UniWriteContactSettingUtf(hContact, "CList", "Group", szGroup);
+
+ SAFE_FREE(&szGroup);
+ }
+ }
+
+ if (pChain)
+ { // Look for nickname TLV and copy it to the db if necessary
+ if (pTLV = getTLV(pChain, 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 (ICQGetContactSettingByte(NULL, "LoadServerDetails", DEFAULT_SS_LOAD) || bAdded)
+ { // if just added contact, save details always - does no harm
+ char *szOldNick;
+
+ if (szOldNick = UniGetContactSettingUtf(hContact,"CList","MyHandle",""))
+ {
+ if ((strcmpnull(szOldNick, pszNick)) && (strlennull(pszNick) > 0))
+ {
+ // 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");
+ UniWriteContactSettingUtf(hContact, "CList", "MyHandle", pszNick);
+ }
+ SAFE_FREE(&szOldNick);
+ }
+ else if (strlennull(pszNick) > 0)
+ {
+ DBDeleteContactSetting(hContact,"CList","MyHandle");
+ UniWriteContactSettingUtf(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 = getTLV(pChain, 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 (ICQGetContactSettingByte(NULL, "LoadServerDetails", DEFAULT_SS_LOAD) || bAdded)
+ { // if just added contact, save details always - does no harm
+ char *szOldComment;
+
+ if (szOldComment = UniGetContactSettingUtf(hContact,"UserInfo","MyNotes",""))
+ {
+ if ((strcmpnull(szOldComment, pszComment)) && (strlennull(pszComment) > 0))
+ {
+ UniWriteContactSettingUtf(hContact, "UserInfo", "MyNotes", pszComment);
+ }
+ SAFE_FREE(&szOldComment);
+ }
+ else if (strlennull(pszComment) > 0)
+ {
+ UniWriteContactSettingUtf(hContact, "UserInfo", "MyNotes", pszComment);
+ }
+ }
+ SAFE_FREE(&pszComment);
+ }
+ else
+ {
+ NetLog_Server("Invalid comment");
+ }
+ }
+
+ // Look for need-authorization TLV
+ if (getTLV(pChain, SSI_TLV_AWAITING_AUTH, 1))
+ {
+ ICQWriteContactSettingByte(hContact, "Auth", 1);
+ NetLog_Server("SSI contact need authorization");
+ }
+ else
+ {
+ ICQWriteContactSettingByte(hContact, "Auth", 0);
+ }
+
+ { // store server-list item's TLV data
+ unsigned char* data = (unsigned char*)SAFE_MALLOC(wTlvLength);
+ int datalen = getServerDataFromItemTLV(pChain, data);
+
+ if (datalen > 0)
+ ICQWriteContactSettingBlob(hContact, "ServerData", data, datalen);
+ else
+ ICQDeleteContactSetting(hContact, "ServerData");
+
+ SAFE_FREE(&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 */
+ char* pszName = NULL;
+
+ ReserveServerID(wGroupId, SSIT_GROUP);
+
+ setServerGroupNameUtf(wGroupId, szRecordName);
+
+ NetLog_Server("Group %s added to known groups.", szRecordName);
+
+ /* demangle full grouppath, create groups, set it to known */
+ pszName = makeGroupPathUtf(wGroupId);
+ SAFE_FREE(&pszName);
+
+ /* 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
+ ICQWriteContactSettingWord(hContact, "SrvPermitId", wItemId);
+ ReserveServerID(wItemId, SSIT_ITEM);
+ // Set apparent mode
+ ICQWriteContactSettingWord(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);
+ }
+ }
+ 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
+ ICQWriteContactSettingWord(hContact, "SrvDenyId", wItemId);
+ ReserveServerID(wItemId, SSIT_ITEM);
+
+ // Set apparent mode
+ ICQWriteContactSettingWord(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);
+ }
+ }
+ break;
+
+ case SSI_ITEM_VISIBILITY: /* My visibility settings */
+ {
+ BYTE bVisibility;
+
+ ReserveServerID(wItemId, SSIT_ITEM);
+
+ // Look for visibility TLV
+ if (bVisibility = getByteFromChain(pChain, SSI_TLV_VISIBILITY, 1))
+ { // found it, store the id, we do not need current visibility - we do not rely on it
+ ICQWriteContactSettingWord(NULL, "SrvVisibilityID", wItemId);
+ NetLog_Server("Visibility is %u", bVisibility);
+ }
+ }
+ 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
+ ICQWriteContactSettingWord(hContact, "SrvIgnoreId", wItemId);
+ ReserveServerID(wItemId, SSIT_ITEM);
+
+ // Set apparent mode & ignore
+ ICQWriteContactSettingWord(hContact, "ApparentMode", ID_STATUS_OFFLINE);
+ // set ignore all events
+ DBWriteContactSettingDword(hContact, "Ignore", "Mask1", 0xFFFF);
+ NetLog_Server("Ignore-contact (%s)", szRecordName);
+ }
+ else
+ { // failed to add or other error
+ NetLog_Server("SSI failed to handle %s Item '%s'", "Ignore", szRecordName);
+ }
+ }
+ break;
+
+ case SSI_ITEM_UNKNOWN2:
+ NetLog_Server("SSI unknown type 0x11");
+ 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}} */
+ ICQWriteContactSettingDword(NULL, "ImportTS", getDWordFromChain(pChain, SSI_TLV_TIMESTAMP, 1));
+ ICQWriteContactSettingWord(NULL, "SrvImportID", wItemId);
+ NetLog_Server("SSI first import recognized");
+ }
+ 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 */
+ ReserveServerID(wItemId, SSIT_ITEM);
+ ICQWriteContactSettingWord(NULL, "SrvAvatarID", wItemId);
+ NetLog_Server("SSI Avatar item recognized");
+ }
+ break;
+
+ case SSI_ITEM_UNKNOWN1:
+ if (wGroupId == 0)
+ {
+ /* ICQ2k ShortcutBar Items */
+ /* data is TLV(CD) text */
+ }
+
+ default:
+ NetLog_Server("SSI unhandled item %2x", wTlvType);
+ break;
+ }
+
+ if (pChain)
+ disposeChain(&pChain);
+
+ } // end for
+
+ NetLog_Server("Bytes left: %u", wLen);
+
+ ICQWriteContactSettingWord(NULL, "SrvRecordCount", (WORD)(wRecord + ICQGetContactSettingWord(NULL, "SrvRecordCount", 0)));
+
+ if (bIsLastPacket)
+ {
+ // No contacts left to sync
+ bIsSyncingCL = FALSE;
+
+ icq_RescanInfoUpdate();
+
+ if (wLen >= 4)
+ {
+ DWORD dwLastUpdateTime;
+
+ /* finally we get a time_t of the last update time */
+ unpackDWord(&buf, &dwLastUpdateTime);
+ ICQWriteContactSettingDword(NULL, "SrvLastUpdate", dwLastUpdateTime);
+ NetLog_Server("Last update of server list was (%u) %s", dwLastUpdateTime, asctime(localtime(&dwLastUpdateTime)));
+
+ sendRosterAck();
+ handleServUINSettings(wListenPort, info);
+ }
+ else
+ {
+ NetLog_Server("Last packet missed update time...");
+ }
+ if (ICQGetContactSettingWord(NULL, "SrvRecordCount", 0) == 0)
+ { // we got empty serv-list, create master group
+ servlistcookie* ack = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie));
+ if (ack)
+ {
+ DWORD seq;
+
+ ack->dwAction = SSA_GROUP_UPDATE;
+ ack->szGroupName = "";
+ seq = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_ADDTOLIST, 0, ack);
+ icq_sendGroupUtf(seq, ICQ_LISTS_ADDTOLIST, 0, ack->szGroupName, NULL, 0);
+ }
+ }
+ // serv-list sync finished, clear just added contacts
+ FlushJustAddedContacts();
+ }
+ else
+ {
+ NetLog_Server("Waiting for more packets");
+ }
+}
+
+
+
+static void handleRecvAuthRequest(unsigned char *buf, WORD wLen)
+{
+ WORD wReasonLen;
+ DWORD dwUin;
+ uid_str szUid;
+ HANDLE hcontact;
+ CCSDATA ccs;
+ PROTORECVEVENT pre;
+ char* szReason;
+ int nReasonLen;
+ char* szNick;
+ int nNickLen;
+ char* szBlob;
+ char* pCurBlob;
+ DBVARIANT dbv;
+ int bAdded;
+
+ if (!unpackUID(&buf, &wLen, &dwUin, &szUid)) return;
+
+ if (dwUin && IsOnSpammerList(dwUin))
+ {
+ NetLog_Server("Ignored Message from known Spammer");
+ return;
+ }
+
+ unpackWord(&buf, &wReasonLen);
+ wLen -= 2;
+ if (wReasonLen > wLen)
+ return;
+
+ hcontact = HContactFromUID(dwUin, szUid, &bAdded);
+
+ ccs.szProtoService=PSR_AUTH;
+ ccs.hContact=hcontact;
+ ccs.wParam=0;
+ ccs.lParam=(LPARAM)&pre;
+ pre.flags=0;
+ pre.timestamp=time(NULL);
+ pre.lParam=sizeof(DWORD)+sizeof(HANDLE)+wReasonLen+5;
+ szReason = (char*)SAFE_MALLOC(wReasonLen+1);
+ if (szReason)
+ {
+ memcpy(szReason, buf, wReasonLen);
+ szReason[wReasonLen] = '\0';
+ szReason = detect_decode_utf8(szReason); // detect & decode UTF-8
+ }
+ nReasonLen = strlennull(szReason);
+ // Read nick name from DB
+ if (dwUin)
+ {
+ if (ICQGetContactSetting(hcontact, "Nick", &dbv))
+ nNickLen = 0;
+ else
+ {
+ szNick = dbv.pszVal;
+ nNickLen = strlennull(szNick);
+ }
+ }
+ else
+ nNickLen = strlennull(szUid);
+ pre.lParam += nNickLen + nReasonLen;
+
+ ICQWriteContactSettingByte(ccs.hContact, "Grant", 1);
+
+ /*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);
+ 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; pCurBlob++;
+ if (nReasonLen)
+ {
+ memcpy(pCurBlob, szReason, nReasonLen);
+ pCurBlob += nReasonLen;
+ }
+ else
+ {
+ memcpy(pCurBlob, buf, wReasonLen);
+ pCurBlob += wReasonLen;
+ }
+ *(char *)pCurBlob = 0;
+ pre.szMessage=(char *)szBlob;
+
+// TODO: Change for new auth system, include all known informations
+ CallService(MS_PROTO_CHAINRECV,0,(LPARAM)&ccs);
+
+ SAFE_FREE(&szReason);
+ ICQFreeVariant(&dbv);
+ return;
+}
+
+
+
+static void handleRecvAdded(unsigned char *buf, WORD wLen)
+{
+ DWORD dwUin;
+ uid_str szUid;
+ DWORD cbBlob;
+ PBYTE pBlob,pCurBlob;
+ HANDLE hContact;
+ 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;
+ }
+
+ hContact=HContactFromUID(dwUin, szUid, &bAdded);
+
+ ICQDeleteContactSetting(hContact, "Grant");
+
+ cbBlob=sizeof(DWORD)+sizeof(HANDLE)+4;
+
+ if (dwUin)
+ {
+ if (ICQGetContactSetting(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) */
+ memcpy(pCurBlob,&dwUin,sizeof(DWORD)); pCurBlob+=sizeof(DWORD);
+ memcpy(pCurBlob,&hContact,sizeof(HANDLE)); pCurBlob+=sizeof(HANDLE);
+ 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
+
+ ICQAddEvent(NULL, EVENTTYPE_ADDED, time(NULL), 0, cbBlob, pBlob);
+}
+
+
+
+static void handleRecvAuthResponse(unsigned char *buf, WORD wLen)
+{
+ BYTE bResponse;
+ DWORD dwUin;
+ uid_str szUid;
+ HANDLE hContact;
+ char* szNick;
+ WORD nReasonLen;
+ char* szReason;
+ int bAdded;
+
+ bResponse = 0xFF;
+
+ if (!unpackUID(&buf, &wLen, &dwUin, &szUid)) return;
+
+ if (dwUin && IsOnSpammerList(dwUin))
+ {
+ NetLog_Server("Ignored Message from known Spammer");
+ return;
+ }
+
+ 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:
+ ICQWriteContactSettingByte(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 updateServVisibilityCode(BYTE bCode)
+{
+ icq_packet packet;
+ WORD wVisibilityID;
+ WORD wCommand;
+
+ if ((bCode > 0) && (bCode < 6))
+ {
+ servlistcookie* ack;
+ DWORD dwCookie;
+ BYTE bVisibility = ICQGetContactSettingByte(NULL, "SrvVisibility", 0);
+
+ if (bVisibility == bCode) // if no change was made, not necescary to update that
+ return;
+ ICQWriteContactSettingByte(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 = ICQGetContactSettingWord(NULL, "SrvVisibilityID", 0)) == 0)
+ {
+ // No, create a new random ID
+ wVisibilityID = GenerateServerId(SSIT_ITEM);
+ ICQWriteContactSettingWord(NULL, "SrvVisibilityID", wVisibilityID);
+ wCommand = ICQ_LISTS_ADDTOLIST;
+ NetLog_Server("Made new srvVisibilityID, id is %u, code is %u", wVisibilityID, bCode);
+ }
+ else
+ {
+ NetLog_Server("Reused srvVisibilityID, id is %u, code is %u", wVisibilityID, bCode);
+ wCommand = ICQ_LISTS_UPDATEGROUP;
+ }
+
+ ack = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie));
+ 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);
+ packFNACHeaderFull(&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 updateServAvatarHash(char* pHash, int size)
+{
+ icq_packet packet;
+ WORD wAvatarID;
+ WORD wCommand;
+ DBVARIANT dbvHash;
+ int bResetHash = 0;
+ BYTE bName = 0;
+
+ if (!ICQGetContactSetting(NULL, "AvatarHash", &dbvHash))
+ {
+ bName = 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
+ sendAddStart(FALSE);
+
+ if (bResetHash || !pHash)
+ {
+ servlistcookie* ack;
+ DWORD dwCookie;
+
+ // Do we have a known server avatar ID?
+ if (wAvatarID = ICQGetContactSettingWord(NULL, "SrvAvatarID", 0))
+ {
+ ack = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie));
+ 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
+
+ // Build and send packet
+ serverPacketInit(&packet, (WORD)(20 + (bName ? 1 : 0)));
+ packFNACHeaderFull(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_REMOVEFROMLIST, 0, dwCookie);
+ if (bName)
+ { // name
+ packWord(&packet, 1);
+ packByte(&packet, bName); // Name
+ }
+ else
+ packWord(&packet, 0); // Name (null)
+ packWord(&packet, 0); // GroupID (0 if not relevant)
+ packWord(&packet, wAvatarID); // EntryID
+ packWord(&packet, SSI_ITEM_BUDDYICON); // EntryType
+ packWord(&packet, 0); // Length in bytes of following TLV
+ sendServPacket(&packet);
+ }
+ }
+
+ if (pHash)
+ {
+ servlistcookie* ack;
+ DWORD dwCookie;
+ 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 = ICQGetContactSettingWord(NULL, "SrvAvatarID", 0)) == 0)
+ {
+ // No, create a new random ID
+ wAvatarID = GenerateServerId(SSIT_ITEM);
+ wCommand = ICQ_LISTS_ADDTOLIST;
+ NetLog_Server("Made new srvAvatarID, id is %u", wAvatarID);
+ }
+ else
+ {
+ NetLog_Server("Reused srvAvatarID, id is %u", wAvatarID);
+ wCommand = ICQ_LISTS_UPDATEGROUP;
+ }
+
+ ack = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie));
+ 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
+
+ // Build and send packet
+ serverPacketInit(&packet, (WORD)(29 + hashsize));
+ packFNACHeaderFull(&packet, ICQ_LISTS_FAMILY, wCommand, 0, dwCookie);
+ packWord(&packet, 1); // Name length
+ packByte(&packet, (BYTE)(0x30 + pHash[1])); // Name
+ packWord(&packet, 0); // GroupID (0 if not relevant)
+ packWord(&packet, wAvatarID); // EntryID
+ packWord(&packet, SSI_ITEM_BUDDYICON); // EntryType
+ packWord(&packet, (WORD)(0x8 + hashsize)); // Length in bytes of following TLV
+ packTLV(&packet, SSI_TLV_NAME, 0, NULL); // TLV (Name)
+ packTLV(&packet, SSI_TLV_AVATARHASH, hashsize, pHash + 2); // TLV (Hash)
+ sendServPacket(&packet);
+ // There is no need to send ICQ_LISTS_CLI_MODIFYSTART or
+ // ICQ_LISTS_CLI_MODIFYEND when modifying the avatar hash
+ }
+
+ if (bResetHash) // finish update session
+ sendAddEnd();
+}
+
+
+
+// Should be called before the server list is modified. When all
+// modifications are done, call sendAddEnd().
+void sendAddStart(int bImport)
+{
+ icq_packet packet;
+ WORD wImportID = ICQGetContactSettingWord(NULL, "SrvImportID", 0);
+
+ if (bImport && wImportID)
+ { // we should be importing, check if already have import item
+ if (ICQGetContactSettingDword(NULL, "ImportTS", 0) + 604800 < ICQGetContactSettingDword(NULL, "LogonTS", 0))
+ { // is the timestamp week older, clear it and begin new import
+ DWORD dwCookie;
+ servlistcookie* ack;
+
+ if (ack = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie)))
+ { // 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);
+ }
+ }
+ }
+
+ 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.
+void sendAddEnd(void)
+{
+ 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 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/miranda-wine/protocols/IcqOscarJ/fam_15icqserver.c b/miranda-wine/protocols/IcqOscarJ/fam_15icqserver.c
new file mode 100644
index 0000000..fc3dedb
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/fam_15icqserver.c
@@ -0,0 +1,1179 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/fam_15icqserver.c,v $
+// Revision : $Revision: 3663 $
+// Last change on : $Date: 2006-08-31 00:18:59 +0400 (Чтв, 31 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+
+static void handleExtensionError(unsigned char *buf, WORD wPackLen);
+static void handleExtensionServerInfo(unsigned char *buf, WORD wPackLen, WORD wFlags);
+static void parseOfflineMessage(unsigned char *databuf, WORD wPacketLen);
+static void parseOfflineGreeting(BYTE* pDataBuf, WORD wLen, WORD wMsgLen, DWORD dwUin, DWORD dwTimestamp, BYTE bFlags);
+static void parseEndOfOfflineMessages(unsigned char *databuf, WORD wPacketLen);
+static void handleExtensionMetaResponse(unsigned char *databuf, WORD wPacketLen, WORD wCookie, WORD wFlags);
+static void parseSearchReplies(unsigned char *databuf, WORD wPacketLen, WORD wCookie, WORD wReplySubtype, BYTE bResultCode);
+static void parseUserInfoRequestReplies(unsigned char *databuf, WORD wPacketLen, WORD wCookie, WORD wFlags, WORD wReplySubtype, BYTE bResultCode);
+static void parseUserInfoUpdateAck(unsigned char *databuf, WORD wPacketLen, WORD wCookie, WORD wReplySubtype, BYTE bResultCode);
+
+
+
+void handleIcqExtensionsFam(unsigned char *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;
+ }
+}
+
+
+
+static void handleExtensionError(unsigned char *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 = getTLV(chain, 0x21, 1); // get meta error data
+ if (pTLV && pTLV->wLen >= 8)
+ {
+ unsigned char* pBuffer = pTLV->pData;
+ WORD wData;
+ pBuffer += 6;
+ unpackLEWord(&pBuffer, &wData); // get request type
+ switch (wData)
+ {
+ case CLI_OFFLINE_MESSAGE_REQ:
+ NetLog_Server("Offline messages request failed with error 0x%02x", wData, wErrorCode);
+ break;
+
+ case CLI_DELETE_OFFLINE_MSGS_REQ:
+ NetLog_Server("Deleting offline messages from server failed with error 0x%02x", wErrorCode);
+ icq_LogMessage(LOG_WARNING, "Deleting Offline Messages from server failed.\nYou will probably receive them again.");
+ break;
+
+ 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)
+ {
+ DWORD dwCookieUin;
+ fam15_cookie_data* pCookieData = NULL;
+ int foundCookie;
+
+ foundCookie = FindCookie(wCookie, &dwCookieUin, (void**)&pCookieData);
+ if (foundCookie && pCookieData)
+ {
+ HANDLE hContact = HContactFromUIN(dwCookieUin, NULL);
+ ICQBroadcastAck(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
+ 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);
+}
+
+
+
+static void handleExtensionServerInfo(unsigned char *buf, WORD wPackLen, WORD wFlags)
+{
+ WORD wBytesRemaining;
+ WORD wRequestType;
+ WORD wCookie;
+ DWORD dwMyUin;
+ oscar_tlv_chain* chain;
+ oscar_tlv* dataTlv;
+ unsigned char* databuf;
+
+
+ // 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 = getTLV(chain, 0x0001, 1);
+ if (dataTlv == NULL)
+ {
+ disposeChain(&chain);
+ NetLog_Server("Error: Broken snac 15/3 %d", 2);
+ return;
+ }
+ databuf = dataTlv->pData;
+ wPackLen -= 4;
+
+ _ASSERTE(dataTlv->wLen == wPackLen);
+ _ASSERTE(wPackLen >= 10);
+
+ if ((dataTlv->wLen == wPackLen) && (wPackLen >= 10))
+ {
+ 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_OFFLINE_MESSAGE: // This is an offline message
+ parseOfflineMessage(databuf, wPackLen);
+ break;
+
+ case SRV_END_OF_OFFLINE_MSGS: // This packets marks the end of offline messages
+ parseEndOfOfflineMessages(databuf, wPackLen);
+ break;
+
+ case SRV_META_INFO_REPLY: // SRV_META request replies
+ handleExtensionMetaResponse(databuf, wPackLen, wCookie, wFlags);
+ break;
+ }
+ }
+ }
+ else
+ {
+ NetLog_Server("Error: Broken snac 15/3 %d", 3);
+ }
+
+ if (chain)
+ disposeChain(&chain);
+}
+
+
+
+static void parseOfflineMessage(unsigned char *databuf, WORD wPacketLen)
+{
+ _ASSERTE(wPacketLen >= 14);
+ if (wPacketLen >= 14)
+ {
+ DWORD dwUin;
+ DWORD dwTimestamp;
+ WORD wYear;
+ WORD wMsgLen;
+ BYTE nMonth;
+ BYTE nDay;
+ BYTE nHour;
+ BYTE nMinute;
+ BYTE bType;
+ BYTE bFlags;
+
+
+ unpackLEDWord(&databuf, &dwUin);
+ unpackLEWord(&databuf, &wYear);
+ unpackByte(&databuf, &nMonth);
+ unpackByte(&databuf, &nDay);
+ unpackByte(&databuf, &nHour);
+ unpackByte(&databuf, &nMinute);
+ unpackByte(&databuf, &bType);
+ unpackByte(&databuf, &bFlags);
+ unpackLEWord(&databuf, &wMsgLen);
+ wPacketLen -=14;
+
+
+ NetLog_Server("Offline message time: %u-%u-%u %u:%u", wYear, nMonth, nDay, nHour, nMinute);
+ NetLog_Server("Offline message type %u from %u", bType, dwUin);
+
+ if (wMsgLen == wPacketLen || bType == MTYPE_PLUGIN)
+ {
+ struct tm *sentTm;
+
+ // Hack around the timezone problem
+ // This is probably broken in some countries
+ // but I'll leave it like this for now (todo)
+ time(&dwTimestamp);
+ sentTm = gmtime(&dwTimestamp);
+ sentTm->tm_sec = 28800;
+ sentTm->tm_min = nMinute;
+ sentTm->tm_hour = nHour;
+ sentTm->tm_mday = nDay;
+ sentTm->tm_mon = nMonth - 1;
+ sentTm->tm_year = wYear - 1900;
+ mktime(sentTm);
+
+ // I *guess* server runs in US time-8 hours.
+ // It might be UK time or something.
+ // More observations reqd at changeover.
+ if ((sentTm->tm_mon > 3 && sentTm->tm_mon < 9)
+ || (sentTm->tm_mon == 3
+ && (sentTm->tm_mday > 7
+ || (sentTm->tm_wday != 0 && sentTm->tm_mday > sentTm->tm_wday)
+ || (sentTm->tm_wday == 0 && sentTm->tm_hour >= 2)))
+ || (sentTm->tm_mon == 9
+ && (sentTm->tm_mday < 25
+ || (sentTm->tm_wday != 0 && sentTm->tm_mday < 25 + sentTm->tm_wday)
+ || (sentTm->tm_wday == 0 && sentTm->tm_hour <= 2))))
+ sentTm->tm_hour--;
+
+ sentTm->tm_sec -= 28800 + _timezone;
+ { // _daylight global variable is reversed in southern hemisphere. Silly.
+ TIME_ZONE_INFORMATION tzinfo;
+ if (GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT)
+ sentTm->tm_hour++;
+ }
+ dwTimestamp = mktime(sentTm);
+
+ // :NOTE:
+ // This is a check for the problem with offline messages being marked
+ // with the wrong year by the server. It can cause other problems when
+ // the internal system clock is incorrect but I think this is the most
+ // generic fix.
+ if (dwTimestamp > (unsigned long)time(NULL))
+ dwTimestamp = time(NULL);
+
+ { // Check if the time is not behind last user event, if yes, get current time
+ HANDLE hContact = HContactFromUIN(dwUin, NULL);
+
+ if (hContact)
+ { // we have contact
+ HANDLE hEvent = (HANDLE)CallService(MS_DB_EVENT_FINDLAST, (WPARAM)hContact, 0);
+
+ if (hEvent)
+ { // contact has events
+ DBEVENTINFO dbei;
+ DWORD dummy;
+
+ dbei.cbSize = sizeof (DBEVENTINFO);
+ dbei.pBlob = (char*)&dummy;
+ dbei.cbBlob = 2;
+ if (!CallService(MS_DB_EVENT_GET, (WPARAM)hEvent, (LPARAM)&dbei))
+ { // got that event, if newer than ts then reset to current time
+ if (dwTimestamp<dbei.timestamp) dwTimestamp = time(NULL);
+ }
+ }
+ }
+ }
+
+ // Handle the actual message
+ if (bType == MTYPE_PLUGIN)
+ parseOfflineGreeting(databuf, wPacketLen, wMsgLen, dwUin, dwTimestamp, bFlags);
+ else
+ handleMessageTypes(dwUin, dwTimestamp, 0, 0, 0, 0, bType, bFlags, 0, wPacketLen, wMsgLen, databuf, FALSE);
+
+ // Success
+ return;
+ }
+ }
+
+ // Failure
+ NetLog_Server("Error: Broken offline message");
+}
+
+
+
+static void parseOfflineGreeting(BYTE* pDataBuf, WORD wLen, WORD wMsgLen, DWORD dwUin, DWORD dwTimestamp, BYTE bFlags)
+{
+ WORD wInfoLen;
+ DWORD dwPluginNameLen;
+ DWORD dwLengthToEnd;
+ DWORD dwDataLen;
+ DWORD q1,q2,q3,q4;
+ WORD qt;
+ char* szPluginName;
+ int typeId;
+
+ NetLog_Server("Parsing Greeting message through server");
+
+ pDataBuf += wMsgLen; // Message
+ wLen -= wMsgLen;
+
+ //
+ unpackLEWord(&pDataBuf, &wInfoLen);
+
+ unpackDWord(&pDataBuf, &q1); // get data GUID & function id
+ unpackDWord(&pDataBuf, &q2);
+ unpackDWord(&pDataBuf, &q3);
+ unpackDWord(&pDataBuf, &q4);
+ unpackLEWord(&pDataBuf, &qt);
+ wLen -= 20;
+
+ unpackLEDWord(&pDataBuf, &dwPluginNameLen);
+ wLen -= 4;
+
+ if (dwPluginNameLen > wLen)
+ { // check for malformed plugin name
+ dwPluginNameLen = wLen;
+ NetLog_Server("Warning: malformed size of plugin name.");
+ }
+ szPluginName = (char *)_alloca(dwPluginNameLen + 1);
+ memcpy(szPluginName, pDataBuf, dwPluginNameLen);
+ szPluginName[dwPluginNameLen] = '\0';
+ wLen -= (WORD)dwPluginNameLen;
+
+ pDataBuf += dwPluginNameLen + 15;
+
+ typeId = TypeGUIDToTypeId(q1, q2, q3, q4, qt);
+ if (!typeId)
+ NetLog_Server("Error: Unknown type {%08x-%08x-%08x-%08x:%04x}: %s", q1,q2,q3,q4,qt, szPluginName);
+
+ if (wLen > 8)
+ {
+ // Length of remaining data
+ unpackLEDWord(&pDataBuf, &dwLengthToEnd);
+
+ // Length of message
+ unpackLEDWord(&pDataBuf, &dwDataLen);
+ wLen -= 8;
+
+ if (dwDataLen > wLen)
+ dwDataLen = wLen;
+
+ if (typeId)
+ handleMessageTypes(dwUin, dwTimestamp, 0, 0, 0, 0, typeId, bFlags, 0, dwLengthToEnd, (WORD)dwDataLen, pDataBuf, FALSE);
+ else
+ NetLog_Server("Unsupported plugin message type '%s'", szPluginName);
+ }
+}
+
+
+
+static void parseEndOfOfflineMessages(unsigned char *databuf, WORD wPacketLen)
+{
+ BYTE bMissedMessages = 0;
+ icq_packet packet;
+
+ if (wPacketLen == 1)
+ {
+ unpackByte(&databuf, &bMissedMessages);
+ NetLog_Server("End of offline msgs, %u dropped", bMissedMessages);
+ }
+ else
+ {
+ NetLog_Server("Error: Malformed end of offline msgs");
+ }
+
+ // Send 'got offline msgs'
+ // This will delete the messages stored on server
+ serverPacketInit(&packet, 24);
+ packFNACHeader(&packet, ICQ_EXTENSIONS_FAMILY, ICQ_META_CLI_REQ);
+ packWord(&packet, 1); // TLV Type
+ packWord(&packet, 10); // TLV Length
+ packLEWord(&packet, 8); // Data length
+ packLEDWord(&packet, 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);
+}
+
+
+
+static void handleExtensionMetaResponse(unsigned char *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:
+ case META_SET_FULLINFO_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_SHORT_USERINFO:
+ case META_BASIC_USERINFO:
+ case META_WORK_USERINFO:
+ case META_MORE_USERINFO:
+ case META_NOTES_USERINFO:
+ case META_EMAIL_USERINFO:
+ case META_INTERESTS_USERINFO:
+ case META_AFFILATIONS_USERINFO:
+ case META_HPAGECAT_USERINFO:
+ parseUserInfoRequestReplies(databuf, wPacketLen, wCookie, wFlags, 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
+ {
+ char *pszInfo;
+
+ // Terminate buffer
+ pszInfo = (char *)_alloca(wPacketLen + 1);
+ if (wPacketLen > 0)
+ memcpy(pszInfo, databuf, wPacketLen);
+ pszInfo[wPacketLen] = 0;
+
+ ICQBroadcastAck(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;
+
+ ICQBroadcastAck(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;
+
+ default:
+ NetLog_Server("Warning: Ignored 15/03 replysubtype x%x", wReplySubtype);
+// _ASSERTE(0);
+ break;
+ }
+
+ // Success
+ return;
+ }
+
+ // Failure
+ NetLog_Server("Warning: Broken 15/03 ExtensionMetaResponse");
+}
+
+
+
+static void ReleaseSearchCookie(DWORD dwCookie, search_cookie *pCookie)
+{
+ if (pCookie)
+ {
+ FreeCookie(dwCookie);
+ if (pCookie->dwMainId)
+ {
+ if (pCookie->dwStatus)
+ {
+ SAFE_FREE(&pCookie);
+ ICQBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)dwCookie, 0);
+ }
+ else
+ pCookie->dwStatus = 1;
+ }
+ else
+ {
+ SAFE_FREE(&pCookie);
+ ICQBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)dwCookie, 0);
+ }
+ }
+ else
+ ICQBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)dwCookie, 0);
+}
+
+
+
+static void parseSearchReplies(unsigned char *databuf, WORD wPacketLen, WORD wCookie, WORD wReplySubtype, BYTE bResultCode)
+{
+ BYTE bParsingOK = FALSE; // For debugging purposes only
+ BOOL bLastUser = FALSE;
+ search_cookie* pCookie;
+
+ if (!FindCookie(wCookie, NULL, &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;
+ 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;
+
+ // Nick
+ if (wPacketLen < 2)
+ break;
+ unpackLEWord(&databuf, &wLen);
+ wPacketLen -= 2;
+ if (wLen > 0)
+ {
+ if (wPacketLen < wLen || (databuf[wLen-1] != 0))
+ break;
+ sr.hdr.nick = 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 = 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 = 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 = databuf;
+ databuf += wLen;
+ }
+ else
+ {
+ sr.hdr.email = NULL;
+ }
+
+ // Authentication needed flag
+ if (wPacketLen < 1)
+ break;
+ unpackByte(&databuf, &sr.auth);
+
+ sr.uid = NULL; // icq contact
+ // Finally, broadcast the result
+ ICQBroadcastAck(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);
+ }
+}
+
+
+
+static void parseUserInfoRequestReplies(unsigned char *databuf, WORD wPacketLen, WORD wCookie, WORD wFlags, WORD wReplySubtype, BYTE bResultCode)
+{
+ BOOL bMoreDataFollows;
+ DWORD dwCookieUin;
+ fam15_cookie_data* pCookieData = NULL;
+ HANDLE hContact = INVALID_HANDLE_VALUE;
+ int foundCookie;
+ BOOL bOK = TRUE;
+
+
+ foundCookie = FindCookie(wCookie, &dwCookieUin, (void**)&pCookieData);
+ if (foundCookie && pCookieData)
+ {
+ if (pCookieData->bRequestType == REQUESTTYPE_OWNER)
+ hContact = NULL; // this is here for situation when we have own uin in clist
+ else
+ hContact = HContactFromUIN(dwCookieUin, NULL);
+ }
+ else
+ {
+ NetLog_Server("Warning: Ignoring unrequested 15/03 user info reply type 0x%x", wReplySubtype);
+
+ return;
+ }
+
+ if (bResultCode != 0x0A)
+ {
+ NetLog_Server("Warning: Got 15/03 user info failure reply type 0x%x", wReplySubtype);
+ }
+
+ // Check if this is the last packet for this request
+ bMoreDataFollows = wFlags&0x0001;
+
+
+ switch (wReplySubtype)
+ {
+
+ case META_BASIC_USERINFO:
+ NetLog_Server("SNAC(0x15,0x3): META_%s_USERINFO for %u", "BASIC", dwCookieUin);
+ if (bResultCode == 0x0A)
+ {
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "Nick", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "FirstName", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "LastName", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "e-mail", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "City", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "State", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "Phone", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "Fax", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "Street", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "Cellular", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "ZIP", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingWord(hContact, "Country", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingByte(hContact, "Timezone", &databuf, &wPacketLen);
+
+ if (bOK && (wPacketLen >= 3))
+ {
+ if (hContact == NULL)
+ { // auth flag is the same for normal contacts also
+ ICQWriteContactSettingByte(hContact, "Auth", (BYTE)!(*databuf));
+ databuf += 1;
+
+ // webaware is also the same, but gives different values
+ ICQWriteContactSettingByte(hContact, "WebAware", (*databuf));
+ databuf += 1;
+
+ ICQWriteContactSettingByte(hContact, "PublishPrimaryEmail", (BYTE)!(*databuf));
+ databuf += 1;
+ }
+ else
+ databuf += 3;
+
+ wPacketLen -= 3;
+
+ if (wPacketLen >= 1 && (!hContact || dwCookieUin == dwLocalUIN))
+ { // owner or owner contact contains one more unknown byte value
+ databuf += 1; // OMG!
+ wPacketLen -= 1;
+ }
+ }
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "ZIP", &databuf, &wPacketLen);
+ }
+ break;
+
+ case META_WORK_USERINFO:
+ NetLog_Server("SNAC(0x15,0x3): META_%s_USERINFO for %u", "WORK", dwCookieUin);
+ if (bResultCode == 0x0A)
+ {
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "CompanyCity", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "CompanyState", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "CompanyPhone", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "CompanyFax", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "CompanyStreet", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "CompanyZIP", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingWord(hContact, "CompanyCountry", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "Company", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "CompanyDepartment",&databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "CompanyPosition", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingWord(hContact, "CompanyOccupation",&databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "CompanyHomepage", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "CompanyZIP", &databuf, &wPacketLen);
+ }
+ break;
+
+ case META_MORE_USERINFO:
+ NetLog_Server("SNAC(0x15,0x3): META_%s_USERINFO for %u", "MORE", dwCookieUin);
+ if (bResultCode == 0x0A)
+ {
+ if (bOK) bOK = writeDbInfoSettingWord(hContact, "Age", &databuf, &wPacketLen);
+ if (bOK && (wPacketLen >= 1))
+ {
+ if (*databuf)
+ ICQWriteContactSettingByte(hContact, "Gender", (BYTE)(*databuf == 1 ? 'F' : 'M'));
+ else
+ // Undefined gender
+ ICQDeleteContactSetting(hContact, "Gender");
+ databuf += 1;
+ wPacketLen -= 1;
+ }
+ else
+ bOK = FALSE;
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "Homepage", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingWord(hContact, "BirthYear", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingByte(hContact, "BirthMonth", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingByte(hContact, "BirthDay", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingByteWithTable(hContact, "Language1", languageField, &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingByteWithTable(hContact, "Language2", languageField, &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingByteWithTable(hContact, "Language3", languageField, &databuf, &wPacketLen);
+
+ if (bOK && (wPacketLen >= 2))
+ {
+ databuf += 2;
+ wPacketLen -= 2;
+ }
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "OriginCity", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "OriginState", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingWord(hContact, "OriginCountry", &databuf, &wPacketLen);
+
+ if (bOK) bOK = writeDbInfoSettingByte(hContact, "MaritalStatus", &databuf, &wPacketLen);
+
+ if (bOK)
+ {
+ if (hContact == NULL)
+ bOK = writeDbInfoSettingByte(hContact, "AllowSpam", &databuf, &wPacketLen);
+ else
+ {
+ databuf++;
+ wPacketLen--;
+ }
+ }
+ if (bOK) bOK = writeDbInfoSettingWord(hContact, "InfoCP", &databuf, &wPacketLen);
+ }
+ break;
+
+ case META_NOTES_USERINFO:
+ NetLog_Server("SNAC(0x15,0x3): META_%s_USERINFO for %u", "NOTES", dwCookieUin);
+ if (bResultCode == 0x0A)
+ {
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "About", &databuf, &wPacketLen);
+ }
+ break;
+
+ case META_EMAIL_USERINFO:
+ NetLog_Server("SNAC(0x15,0x3): META_%s_USERINFO for %u", "EMAIL", dwCookieUin);
+ if (bResultCode == 0x0A)
+ {
+ int nCount = 0;
+ char pszDatabaseKey[33];
+ WORD wEmailLength;
+
+
+ // This value used to be a e-mail counter. Either that was wrong or
+ // Mirabilis changed the behaviour again. It usually says NULL now so
+ // I use the packet byte count to extract the e-mails instead.
+ databuf++;
+ wPacketLen--;
+
+ while (wPacketLen > 4)
+ {
+
+ // Don't publish flag
+ databuf += 1;
+ wPacketLen -= 1;
+
+ // E-mail length
+ unpackLEWord(&databuf, &wEmailLength);
+ wPacketLen -= 2;
+
+ // Check for buffer overflows
+ if ((wEmailLength > wPacketLen) || (databuf[wEmailLength-1] != 0))
+ break;
+
+ // Rewind buffer pointer for writeDbInfoSettingString().
+ databuf -= 2;
+ wPacketLen += 2;
+
+ if (wEmailLength > 1)
+ {
+ null_snprintf(pszDatabaseKey, 33, "e-mail%d", nCount);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, pszDatabaseKey, &databuf, &wPacketLen);
+
+ // Stop on parsing errors
+ if (!bOK)
+ break;
+
+ // Increase counter
+ nCount++;
+ }
+ else
+ {
+ databuf += wEmailLength;
+ wPacketLen -= wEmailLength;
+ }
+ }
+
+ // Delete the next key (this may not exist but that is OK)
+ // :TODO:
+ // We should probably continue to enumerate some keys here just in case
+ // many e-mails were deleted. But it is not that important.
+ if (bOK)
+ {
+ // We only delete e-mails when the parsing was successful since nCount
+ // may be incorrect otherwise
+ null_snprintf(pszDatabaseKey, 33, "e-mail%d", nCount);
+ ICQDeleteContactSetting(hContact, pszDatabaseKey);
+ }
+ }
+ break;
+
+ case META_INTERESTS_USERINFO:
+ NetLog_Server("SNAC(0x15,0x3): META_%s_USERINFO for %u", "INTERESTS", dwCookieUin);
+ if (bResultCode == 0x0A)
+ {
+ int i, count;
+ char idstr[33];
+
+ wPacketLen--;
+ count = *databuf++;
+ // 4 is the maximum allowed personal interests, if count is
+ // higher it's likely a parsing error
+ _ASSERTE(count <= 4);
+ for (i = 0; i < 4; i++)
+ {
+ if (i < count)
+ {
+ null_snprintf(idstr, 33, "Interest%dCat", i);
+ if (bOK) bOK = writeDbInfoSettingWordWithTable(hContact, idstr, interestsField, &databuf, &wPacketLen);
+
+ null_snprintf(idstr, 33, "Interest%dText", i);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, idstr, &databuf, &wPacketLen);
+
+ if (!bOK)
+ break;
+ }
+ else
+ {
+ // Delete older entries if the count has decreased since last update
+ null_snprintf(idstr, 33, "Interest%dCat", i);
+ ICQDeleteContactSetting(hContact, idstr);
+
+ null_snprintf(idstr, 33, "Interest%dText", i);
+ ICQDeleteContactSetting(hContact, idstr);
+ }
+ }
+ }
+ break;
+
+ case META_AFFILATIONS_USERINFO:
+ NetLog_Server("SNAC(0x15,0x3): META_%s_USERINFO for %u", "AFFILATIONS", dwCookieUin);
+ if (bResultCode == 0x0A)
+ {
+ int i;
+ int count;
+ char idstr[33];
+
+ wPacketLen--;
+ count = *databuf++;
+ // 3 is the maximum allowed backgrounds, if count is
+ // higher it's likely a parsing error
+ _ASSERTE(count <= 3);
+ for (i = 0; i < 3; i++)
+ {
+ if (i < count)
+ {
+ null_snprintf(idstr, 33, "Past%d", i);
+ if (bOK) bOK = writeDbInfoSettingWordWithTable(hContact, idstr, pastField, &databuf, &wPacketLen);
+
+ null_snprintf(idstr, 33, "Past%dText", i);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, idstr, &databuf, &wPacketLen);
+
+ if (!bOK)
+ break;
+ }
+ else
+ {
+ // Delete older entries if the count has decreased since last update
+ null_snprintf(idstr, 33, "Past%d", i);
+ ICQDeleteContactSetting(hContact, idstr);
+
+ null_snprintf(idstr, 33, "Past%dText", i);
+ ICQDeleteContactSetting(hContact, idstr);
+ }
+ }
+
+ wPacketLen--;
+ count = *databuf++;
+ // 3 is the maximum allowed affiliations, if count is
+ // higher it's likely a parsing error
+ _ASSERTE(count <= 3);
+ for (i = 0; i < 3; i++)
+ {
+ if (i < count)
+ {
+ null_snprintf(idstr, 33, "Affiliation%d", i);
+ if (bOK) bOK = writeDbInfoSettingWordWithTable(hContact, idstr, affiliationField, &databuf, &wPacketLen);
+
+ null_snprintf(idstr, 33, "Affiliation%dText", i);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, idstr, &databuf, &wPacketLen);
+
+ if (!bOK)
+ break;
+ }
+ else
+ {
+ // Delete older entries if the count has decreased since last update
+ null_snprintf(idstr, 33, "Affiliation%d", i);
+ ICQDeleteContactSetting(hContact, idstr);
+
+ null_snprintf(idstr, 33, "Affiliation%dText", i);
+ ICQDeleteContactSetting(hContact, idstr);
+ }
+ }
+
+ }
+ break;
+
+ // This is either a auto update reply or a GetInfo Minimal reply
+ case META_SHORT_USERINFO:
+ NetLog_Server("SNAC(0x15,0x3): META_%s_USERINFO for %u", "SHORT", dwCookieUin);
+ if (bResultCode == 0xA)
+ {
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "Nick", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "FirstName", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "LastName", &databuf, &wPacketLen);
+ if (bOK) bOK = writeDbInfoSettingString(hContact, "e-mail", &databuf, &wPacketLen);
+ }
+ break;
+
+ case META_HPAGECAT_USERINFO:
+ NetLog_Server("SNAC(0x15,0x3): META_%s_USERINFO for %u", "HPAGECAT", dwCookieUin);
+ break;
+
+ default:
+ NetLog_Server("Warning: Ignored 15/03 user info reply type x%x", wReplySubtype);
+// _ASSERTE(0);
+ break;
+ }
+
+ if (!bOK)
+ {
+ NetLog_Server("Error: Failed parsing 15/03 user info reply type x%x", wReplySubtype);
+ }
+
+ // :TRICKY: * Dont change the following section unless you really understand it *
+ // I have now switched to only send one GETINFO ack instead of 8. The multiple ack
+ // sending originated in a incorrect assumption in the old code and that is long
+ // gone now. The ack will be sent when the last packet has arrived
+ // or when an error has occured. I'm not sure if a error packet will be marked
+ // as the last one but it probably is. Doesn't matter anyway.
+ // The cookie will be freed for all "last packets" but the ack will only be sent if the
+ // request originated from a PS_GETINFO call
+ if (((pCookieData->bRequestType == REQUESTTYPE_USERDETAILED) ||
+ (pCookieData->bRequestType == REQUESTTYPE_USERMINIMAL))
+ &&
+ ((bResultCode != 0x0A) || !bMoreDataFollows))
+ {
+ ICQBroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE)1 ,0);
+ }
+
+ // Free cookie
+ if (!bMoreDataFollows || bResultCode != 0x0A)
+ {
+ ReleaseCookie(wCookie);
+
+ // 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.
+ ICQWriteContactSettingDword(hContact, "InfoTS", time(NULL));
+ icq_DequeueUser(dwCookieUin);
+ }
+
+ // :NOTE:
+ // bResultcode can be xA (success), x14 or x32 (failure). I dont know the difference
+ // between the two failures.
+}
+
+
+
+static void parseUserInfoUpdateAck(unsigned char *databuf, WORD wPacketLen, WORD wCookie, WORD wReplySubtype, BYTE bResultCode)
+{
+ switch (wReplySubtype)
+ {
+ case META_SET_PASSWORD_ACK: // Set user password server ack
+ case META_SET_FULLINFO_ACK: // Server ack for set fullinfo command
+
+ if (bResultCode == 0xA)
+ ICQBroadcastAck(NULL, ACKTYPE_SETINFO, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0);
+ else
+ ICQBroadcastAck(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;
+ }
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/fam_17signon.c b/miranda-wine/protocols/IcqOscarJ/fam_17signon.c
new file mode 100644
index 0000000..7ab9ba9
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/fam_17signon.c
@@ -0,0 +1,198 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/fam_17signon.c,v $
+// Revision : $Revision: 3316 $
+// Last change on : $Date: 2006-07-12 20:26:25 +0400 (Срд, 12 Июл 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+
+static void handleAuthKeyResponse(BYTE *buf, WORD wPacketLen, serverthread_info *info);
+
+
+void handleAuthorizationFam(unsigned char *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, unsigned char* encrypted)
+{
+ unsigned int i;
+ unsigned char table[] =
+ {
+ 0xf3, 0x26, 0x81, 0xc4,
+ 0x39, 0x86, 0xdb, 0x92,
+ 0x71, 0xa3, 0xb9, 0xe6,
+ 0x53, 0x7a, 0x95, 0x7c
+ };
+
+ for (i = 0; szPassword[i]; i++)
+ {
+ encrypted[i] = (szPassword[i] ^ table[i % 16]);
+ }
+}
+
+
+
+void sendClientAuth(const char* szKey, WORD wKeyLen, BOOL bSecure)
+{
+ char szUin[UINMAXLEN];
+ WORD wUinLen;
+ icq_packet packet;
+
+ wUinLen = strlennull(strUID(dwLocalUIN, szUin));
+
+ packet.wLen = 65 + sizeof(CLIENT_ID_STRING) + wUinLen + wKeyLen;
+
+ if (bSecure)
+ {
+ serverPacketInit(&packet, (WORD)(packet.wLen + 10));
+ packFNACHeaderFull(&packet, ICQ_AUTHORIZATION_FAMILY, ICQ_SIGNON_LOGIN_REQUEST, 0, 0);
+ }
+ else
+ {
+ write_flap(&packet, ICQ_LOGIN_CHAN);
+ packDWord(&packet, 0x00000001);
+ }
+ packTLV(&packet, 0x0001, wUinLen, 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
+ char hash[20];
+
+ icq_encryptPassword(szKey, hash);
+ packTLV(&packet, 0x0002, wKeyLen, hash);
+ }
+
+ // Pack client identification details. We identify ourselves as icq5.1 english
+ packTLV(&packet, 0x0003, (WORD)sizeof(CLIENT_ID_STRING)-1, CLIENT_ID_STRING); // Client ID string
+ packTLVWord(&packet, 0x0016, 0x010a); // Client ID
+ packTLVWord(&packet, 0x0017, 0x0014); // Client major version
+ packTLVWord(&packet, 0x0018, 0x0034); // Client minor version
+ packTLVWord(&packet, 0x0019, 0x0000); // Client lesser version
+ packTLVWord(&packet, 0x001a, 0x0bb8); // Client build number
+ packTLVDWord(&packet, 0x0014, 0x0000043d); // Client distribution number
+ packTLV(&packet, 0x000f, 0x0002, "en"); // Client language
+ packTLV(&packet, 0x000e, 0x0002, "us"); // Client country
+
+ sendServPacket(&packet);
+}
+
+
+
+static void handleAuthKeyResponse(BYTE *buf, WORD wPacketLen, serverthread_info *info)
+{
+ WORD wKeyLen;
+ char szKey[64] = {0};
+ md5_state_t state;
+ 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, "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, "Secure login failed.\nInvalid key length.");
+ SetCurrentStatus(ID_STATUS_OFFLINE);
+ return;
+ }
+
+ unpackString(&buf, szKey, wKeyLen);
+
+ {
+ char *pwd = info->szAuthKey;
+
+ md5_init(&state);
+ md5_append(&state, (const md5_byte_t*)pwd, info->wAuthKeyLen);
+ md5_finish(&state, digest);
+ }
+
+ md5_init(&state);
+ md5_append(&state, szKey, wKeyLen);
+ md5_append(&state, digest, 16);
+ md5_append(&state, CLIENT_MD5_STRING, sizeof(CLIENT_MD5_STRING)-1);
+ md5_finish(&state, digest);
+
+#ifdef _DEBUG
+ NetLog_Server("Sending ICQ_SIGNON_LOGIN_REQUEST to login server");
+#endif
+ sendClientAuth(digest, 0x10, TRUE);
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/families.h b/miranda-wine/protocols/IcqOscarJ/families.h
new file mode 100644
index 0000000..e878b9c
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/families.h
@@ -0,0 +1,90 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/families.h,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Declaration for handlers of Channel 2 SNAC Families
+//
+// -----------------------------------------------------------------------------
+
+#ifndef __FAMILIES_H
+#define __FAMILIES_H
+
+
+typedef struct snac_header_s
+{
+ BOOL bValid;
+ WORD wFamily;
+ WORD wSubtype;
+ WORD wFlags;
+ DWORD dwRef;
+ WORD wVersion;
+} snac_header;
+
+
+/*---------* Functions *---------------*/
+
+void handleServiceFam(unsigned char *pBuffer, WORD wBufferLength, snac_header* pSnacHeader, serverthread_info *info);
+void handleLocationFam(unsigned char *pBuffer, WORD wBufferLength, snac_header* pSnacHeader);
+void handleBuddyFam(unsigned char *pBuffer, WORD wBufferLength, snac_header* pSnacHeader);
+void handleMsgFam(unsigned char *pBuffer, WORD wBufferLength, snac_header* pSnacHeader);
+void handleBosFam(unsigned char *pBuffer, WORD wBufferLength, snac_header* pSnacHeader);
+void handleLookupFam(unsigned char *pBuffer, WORD wBufferLength, snac_header* pSnacHeader);
+void handleStatusFam(unsigned char *pBuffer, WORD wBufferLength, snac_header* pSnacHeader);
+void handleServClistFam(unsigned char *pBuffer, WORD wBufferLength, snac_header* pSnacHeader, serverthread_info *info);
+void handleIcqExtensionsFam(unsigned char *pBuffer, WORD wBufferLength, snac_header* pSnacHeader);
+void handleAuthorizationFam(unsigned char *pBuffer, WORD wBufferLength, snac_header* pSnacHeader, serverthread_info *info);
+
+void sendClientAuth(const char* szKey, WORD wKeyLen, BOOL bSecure);
+void handleLoginReply(unsigned char *buf, WORD datalen, serverthread_info *info);
+
+void handleServUINSettings(int nPort, serverthread_info *info);
+int TypeGUIDToTypeId(DWORD dwGuid1, DWORD dwGuid2, DWORD dwGuid3, DWORD dwGuid4, WORD wType);
+int getPluginTypeIdLen(int nTypeID);
+void packPluginTypeId(icq_packet *packet, int nTypeID);
+
+void handleMessageTypes(DWORD dwUin, DWORD dwTimestamp, DWORD dwMsgID, DWORD dwMsgID2, WORD wCookie, WORD wVersion, int type, int flags, WORD wAckType, DWORD dwDataLen, WORD wMsgLen, char *pMsg, BOOL bThruDC);
+
+#define BUL_ALLCONTACTS 0
+#define BUL_VISIBLE 1
+#define BUL_INVISIBLE 2
+#define BUL_TEMPVISIBLE 4
+void sendEntireListServ(WORD wFamily, WORD wSubtype, int listType);
+void updateServVisibilityCode(BYTE bCode);
+void updateServAvatarHash(char* pHash, int size);
+void sendAddStart(int bImport);
+void sendAddEnd(void);
+void sendTypingNotification(HANDLE hContact, WORD wMTNCode);
+
+void makeContactTemporaryVisible(HANDLE hContact);
+void clearTemporaryVisibleList();
+
+
+#endif /* __FAMILIES_H */
diff --git a/miranda-wine/protocols/IcqOscarJ/forkthread.c b/miranda-wine/protocols/IcqOscarJ/forkthread.c
new file mode 100644
index 0000000..e6244ea
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/forkthread.c
@@ -0,0 +1,121 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/forkthread.c,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Miranda Friendly thread wrapper
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+
+struct FORK_ARG {
+ HANDLE hEvent;
+ void (__cdecl *threadcode)(void*);
+ unsigned (__stdcall *threadcodeex)(void*);
+ void *arg;
+};
+
+
+void __cdecl forkthread_r(struct FORK_ARG *fa)
+{
+ void (*callercode)(void*) = fa->threadcode;
+ void *arg = fa->arg;
+
+ CallService(MS_SYSTEM_THREAD_PUSH,0,0);
+ SetEvent(fa->hEvent);
+
+ callercode(arg);
+
+ CallService(MS_SYSTEM_THREAD_POP,0,0);
+
+ return;
+}
+
+
+unsigned long forkthread(void (__cdecl *threadcode)(void*), unsigned long stacksize, void *arg)
+{
+ unsigned long rc;
+ struct FORK_ARG fa;
+
+ fa.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
+ fa.threadcode = threadcode;
+ fa.arg = arg;
+
+ rc = _beginthread(forkthread_r, stacksize, &fa);
+
+ if ((unsigned long)-1L != rc)
+ {
+ WaitForSingleObject(fa.hEvent, INFINITE);
+ }
+ CloseHandle(fa.hEvent);
+
+ return rc;
+}
+
+
+unsigned long __stdcall forkthreadex_r(struct FORK_ARG *fa)
+{
+ unsigned (__stdcall * threadcode) (void *) = fa->threadcodeex;
+ void *arg = fa->arg;
+ unsigned long rc;
+
+ CallService(MS_SYSTEM_THREAD_PUSH,0,0);
+ SetEvent(fa->hEvent);
+
+ rc = threadcode(arg);
+
+ CallService(MS_SYSTEM_THREAD_POP,0,0);
+
+ return rc;
+}
+
+
+unsigned long forkthreadex(void *sec, unsigned stacksize, unsigned (__stdcall *threadcode)(void*),
+ void *arg, unsigned cf, unsigned *thraddr)
+{
+ unsigned long rc;
+ struct FORK_ARG fa;
+
+ fa.threadcodeex = threadcode;
+ fa.arg = arg;
+ fa.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
+
+ rc = _beginthreadex(sec,stacksize,forkthreadex_r,&fa,0,thraddr);
+ if (rc)
+ {
+ WaitForSingleObject(fa.hEvent,INFINITE);
+ }
+ CloseHandle(fa.hEvent);
+
+ return rc;
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/forkthread.h b/miranda-wine/protocols/IcqOscarJ/forkthread.h
new file mode 100644
index 0000000..a4550a7
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/forkthread.h
@@ -0,0 +1,73 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/forkthread.h,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// A safe version of _beginthread()
+//
+// A new thread is created and the source thread is paused until
+// internal code to call MS_SYSTEM_THREAD_PUSH is made in the context
+// if the new thread.
+//
+// The source thread is then released and then the user supplied
+// code is called, when that function returns -- MS_SYSTEM_THREAD_POP
+// is called and then the thread returns.
+//
+// This insures that Miranda will not exit whilst new threads
+// are trying to be born; and the unwind wait stack will ensure
+// that Miranda will wait for all created threads to return as well.
+//
+// Caveats:
+//
+// The function must be reimplemented across MT plugins, since thread
+// creation depends on CRT which can not be shared.
+// -----------------------------------------------------------------------------
+
+
+
+typedef struct {
+ HANDLE hThread;
+ DWORD dwThreadId;
+} pthread_t;
+
+unsigned long forkthread (
+ void (__cdecl *threadcode)(void*),
+ unsigned long stacksize,
+ void *arg
+);
+
+unsigned long forkthreadex(
+ void *sec,
+ unsigned stacksize,
+ unsigned (__stdcall *threadcode)(void*),
+ void *arg,
+ unsigned cf,
+ unsigned *thraddr
+);
diff --git a/miranda-wine/protocols/IcqOscarJ/globals.h b/miranda-wine/protocols/IcqOscarJ/globals.h
new file mode 100644
index 0000000..20daa6c
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/globals.h
@@ -0,0 +1,90 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/globals.h,v $
+// Revision : $Revision: 3545 $
+// Last change on : $Date: 2006-08-19 03:42:44 +0400 (Сбт, 19 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Contains global variables declarations.
+//
+// -----------------------------------------------------------------------------
+
+
+#ifndef __GLOBALS_H
+#define __GLOBALS_H
+
+typedef char uid_str[MAX_PATH];
+
+// from init.c
+HINSTANCE hInst;
+char gpszICQProtoName[MAX_PATH];
+
+HANDLE ghServerNetlibUser;
+HANDLE ghDirectNetlibUser;
+
+// from init.h
+BYTE gbGatewayMode;
+BYTE gbSecureLogin;
+BYTE gbAimEnabled;
+BYTE gbUtfEnabled;
+WORD gwAnsiCodepage;
+BYTE gbDCMsgEnabled;
+BYTE gbTempVisListEnabled;
+BYTE gbSsiEnabled;
+BYTE gbAvatarsEnabled;
+BYTE gbXStatusEnabled;
+BYTE gbOverRate;
+DWORD gtLastRequest;
+DWORD MIRANDA_VERSION;
+
+// from icqosc_svcs.c
+int gnCurrentStatus;
+DWORD dwLocalUIN;
+
+char gpszPassword[16];
+BYTE gbRememberPwd;
+
+BYTE gbUnicodeAPI;
+BYTE gbUnicodeCore;
+BYTE gbUtfLangpack;
+
+// from fam_04message.c
+typedef struct icq_mode_messages_s
+{
+ char* szAway;
+ char* szNa;
+ char* szDnd;
+ char* szOccupied;
+ char* szFfc;
+} icq_mode_messages;
+
+icq_mode_messages modeMsgs;
+CRITICAL_SECTION modeMsgsMutex;
+
+
+#endif /* __GLOBALS_H */
diff --git a/miranda-wine/protocols/IcqOscarJ/guids.h b/miranda-wine/protocols/IcqOscarJ/guids.h
new file mode 100644
index 0000000..20f37cd
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/guids.h
@@ -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,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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/guids.h,v $
+// Revision : $Revision: 3474 $
+// Last change on : $Date: 2006-08-08 03:05:47 +0400 (Втр, 08 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Contains helper functions to handle oscar message GUIDs.
+//
+// -----------------------------------------------------------------------------
+
+
+#ifndef __GUIDS_H
+#define __GUIDS_H
+
+
+typedef DWORD plugin_guid[4];
+
+// Message Capability GUIDs
+static plugin_guid MCAP_TLV2711_FMT = {MCAP_TLV2711_FMT_s};
+static plugin_guid MCAP_REVERSE_REQ = {MCAP_REVERSE_REQ_s};
+static plugin_guid MCAP_OSCAR_FT = {MCAP_OSCAR_FT_s};
+
+// Plugin GUIDs
+static plugin_guid PSIG_MESSAGE = {PSIG_MESSAGE_s};
+static plugin_guid PSIG_INFO_PLUGIN = {PSIG_INFO_PLUGIN_s};
+static plugin_guid PSIG_STATUS_PLUGIN = {PSIG_STATUS_PLUGIN_s};
+
+// Plugin Message GUIDs
+static plugin_guid PMSG_QUERY_INFO = {PMSG_QUERY_INFO_s};
+static plugin_guid PMSG_QUERY_STATUS = {PMSG_QUERY_STATUS_s};
+
+// Message GUIDs
+static plugin_guid MGTYPE_MESSAGE = {MGTYPE_MESSAGE_s};
+static plugin_guid MGTYPE_STATUSMSGEXT = {MGTYPE_STATUSMSGEXT_s};
+static plugin_guid MGTYPE_FILE = {MGTYPE_FILE_s};
+static plugin_guid MGTYPE_WEBURL = {MGTYPE_WEBURL_s};
+static plugin_guid MGTYPE_CONTACTS = {MGTYPE_CONTACTS_s};
+static plugin_guid MGTYPE_GREETING_CARD = {MGTYPE_GREETING_CARD_s};
+static plugin_guid MGTYPE_CHAT = {MGTYPE_CHAT_s};
+static plugin_guid MGTYPE_XTRAZ_SCRIPT = {MGTYPE_XTRAZ_SCRIPT_s};
+
+
+// make GUID checks easy
+static BOOL CompareGUIDs(DWORD q1,DWORD q2,DWORD q3,DWORD q4, 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, plugin_guid guid)
+{
+ packDWord(packet, guid[0]);
+ packDWord(packet, guid[1]);
+ packDWord(packet, guid[2]);
+ packDWord(packet, guid[3]);
+}
+
+
+// capabilities
+typedef unsigned char capstr[0x10];
+
+capstr* MatchCap(char* buf, int bufsize, const capstr* cap, int capsize);
+
+
+#endif /* __GUIDS_H */
diff --git a/miranda-wine/protocols/IcqOscarJ/i18n.c b/miranda-wine/protocols/IcqOscarJ/i18n.c
new file mode 100644
index 0000000..9648429
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/i18n.c
@@ -0,0 +1,477 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/i18n.c,v $
+// Revision : $Revision: 3663 $
+// Last change on : $Date: 2006-08-31 00:18:59 +0400 (Чтв, 31 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// 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 IsUSASCII(const unsigned char* pBuffer, int nSize)
+{
+ BOOL bResult = TRUE;
+ int nIndex;
+
+ for (nIndex = 0; nIndex < nSize; nIndex++)
+ {
+ if (pBuffer[nIndex] > 0x7F)
+ {
+ bResult = FALSE;
+ break;
+ }
+ }
+
+ return bResult;
+}
+
+// Returns true if the unicode buffer only contains 7-bit characters.
+BOOL IsUnicodeAscii(const wchar_t* pBuffer, int nSize)
+{
+ BOOL bResult = TRUE;
+ int nIndex;
+
+
+ for (nIndex = 0; nIndex < nSize; nIndex++)
+ {
+ if (pBuffer[nIndex] > 0x7F)
+ {
+ bResult = FALSE;
+ break;
+ }
+ }
+
+ return bResult;
+}
+
+
+// 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 UTF8_IsValid(const unsigned char* pszInput)
+{
+ int nb, i;
+ const unsigned char* c = pszInput;
+
+
+ for (c = 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;
+
+ for (i = 1; i<=nb; i++) // we this forward, do not cross end of string
+ if ((*(c + i) & 0xc0) != 0x80)
+ return 0;
+ }
+
+ return 1;
+}
+
+
+// returns ansi string in all cases
+char* 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((char**)&from);
+
+ return temp;
+}
+
+
+/*
+ * The following UTF8 routines are
+ *
+ * Copyright (C) 2001 Peter Harris <peter.harris@hummingbird.com>
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ *
+ * 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.
+ */
+unsigned char *make_utf8_string(const wchar_t *unicode)
+{
+ int size = 0;
+ int index = 0;
+ int out_index = 0;
+ unsigned char* out;
+ unsigned short c;
+
+
+ /* first calculate the size of the target string */
+ c = unicode[index++];
+ while (c)
+ {
+ if (c < 0x0080)
+ size += 1;
+ else if (c < 0x0800)
+ size += 2;
+ else
+ size += 3;
+ c = unicode[index++];
+ }
+
+ out = (unsigned char*)SAFE_MALLOC(size + 1);
+ if (out == NULL)
+ return NULL;
+ index = 0;
+
+ c = unicode[index++];
+ while (c)
+ {
+ if (c < 0x080)
+ {
+ out[out_index++] = (unsigned char)c;
+ }
+ else if (c < 0x800)
+ {
+ out[out_index++] = 0xc0 | (c >> 6);
+ out[out_index++] = 0x80 | (c & 0x3f);
+ }
+ else
+ {
+ out[out_index++] = 0xe0 | (c >> 12);
+ out[out_index++] = 0x80 | ((c >> 6) & 0x3f);
+ out[out_index++] = 0x80 | (c & 0x3f);
+ }
+ c = unicode[index++];
+ }
+ out[out_index] = 0x00;
+
+ return out;
+}
+
+
+
+wchar_t *make_unicode_string(const unsigned char *utf8)
+{
+ int size = 0, index = 0, out_index = 0;
+ wchar_t *out;
+ unsigned char c;
+
+ /* first calculate the size of the target string */
+ 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++];
+ }
+
+ out = (wchar_t*)SAFE_MALLOC((size + 1) * sizeof(wchar_t));
+ if (out == NULL)
+ return NULL;
+ index = 0;
+
+ c = utf8[index++];
+ while (c)
+ {
+ if((c & 0x80) == 0)
+ {
+ out[out_index++] = c;
+ }
+ else if((c & 0xe0) == 0xe0)
+ {
+ out[out_index] = (c & 0x1F) << 12;
+ c = utf8[index++];
+ out[out_index] |= (c & 0x3F) << 6;
+ c = utf8[index++];
+ out[out_index++] |= (c & 0x3F);
+ }
+ else
+ {
+ out[out_index] = (c & 0x3F) << 6;
+ c = utf8[index++];
+ out[out_index++] |= (c & 0x3F);
+ }
+ c = utf8[index++];
+ }
+ out[out_index] = 0;
+
+ return out;
+}
+
+
+
+int utf8_encode(const char *from, char **to)
+{
+ wchar_t *unicode;
+ int wchars, err;
+
+
+ wchars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from,
+ strlennull(from), NULL, 0);
+
+ if (wchars == 0)
+ {
+ fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+ return -1;
+ }
+
+ unicode = (wchar_t*)_alloca((wchars + 1) * sizeof(unsigned short));
+ unicode[wchars] = 0;
+
+ err = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from,
+ strlennull(from), unicode, wchars);
+ if(err != wchars)
+ {
+ fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+ 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 *ansi_to_utf8(const char *szAnsi)
+{
+ char *szUtf = NULL;
+
+ if (strlennull(szAnsi))
+ {
+ utf8_encode(szAnsi, &szUtf);
+
+ return szUtf;
+ }
+ else
+ return null_strdup("");
+}
+
+
+
+char *ansi_to_utf8_codepage(const char *szAnsi, WORD wCp)
+{
+ wchar_t *unicode;
+ int wchars = strlennull(szAnsi);
+
+ unicode = (wchar_t*)_alloca((wchars + 1) * sizeof(wchar_t));
+ ZeroMemory(unicode, (wchars + 1)*sizeof(wchar_t));
+
+ MultiByteToWideChar(wCp, MB_PRECOMPOSED, szAnsi, wchars, unicode, wchars);
+
+ return make_utf8_string(unicode);
+}
+
+
+
+// Returns 0 on error, 1 on success
+int utf8_decode(const char *from, char **to)
+{
+ 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)
+ {
+ WCHAR *wszTemp = NULL;
+ int inlen = strlennull(from);
+
+ wszTemp = (WCHAR *)_alloca(sizeof(WCHAR) * (inlen + 1));
+
+ // Convert the UTF-8 string to UCS
+ if (MultiByteToWideChar(CP_UTF8, 0, from, -1, wszTemp, inlen + 1))
+ {
+ // Convert the UCS string to local ANSI codepage
+ *to = (char*)SAFE_MALLOC(inlen+1);
+ if (WideCharToMultiByte(CP_ACP, 0, wszTemp, -1, *to, inlen+1, NULL, NULL))
+ {
+ nResult = 1;
+ }
+ else
+ {
+ SAFE_FREE(&(*to));
+ }
+ }
+ }
+ else
+ {
+ wchar_t *unicode;
+ int chars;
+ int err;
+
+ unicode = make_unicode_string(from);
+ if(unicode == NULL)
+ {
+ fprintf(stderr, "Out of memory processing string from UTF8 to UNICODE16\n");
+ return 0;
+ }
+
+ chars = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, unicode, -1, NULL, 0, NULL, NULL);
+
+ if(chars == 0)
+ {
+ fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+ SAFE_FREE(&unicode);
+ return 0;
+ }
+
+ *to = (char*)SAFE_MALLOC((chars + 1)*sizeof(unsigned char));
+ if(*to == NULL)
+ {
+ fprintf(stderr, "Out of memory processing string to local charset\n");
+ SAFE_FREE(&unicode);
+ return 0;
+ }
+
+ err = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, unicode, -1, *to, chars, NULL, NULL);
+ if (err != chars)
+ {
+ fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+ SAFE_FREE(&unicode);
+ SAFE_FREE(to);
+ return 0;
+ }
+
+ SAFE_FREE(&unicode);
+
+ nResult = 1;
+ }
+
+ return nResult;
+}
+
+
+
+// Returns 0 on error, 1 on success
+int 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;
+
+ // Use the native conversion routines when available
+ if (bHasCP_UTF8)
+ {
+ WCHAR *wszTemp = NULL;
+ int inlen = strlennull(from);
+
+ wszTemp = (WCHAR *)_alloca(sizeof(WCHAR) * (inlen + 1));
+
+ // Convert the UTF-8 string to UCS
+ if (MultiByteToWideChar(CP_UTF8, 0, from, -1, wszTemp, inlen + 1))
+ {
+ // Convert the UCS string to local ANSI codepage
+ if (WideCharToMultiByte(CP_ACP, 0, wszTemp, -1, to, to_size, NULL, NULL))
+ {
+ nResult = 1;
+ }
+ }
+ }
+ else
+ {
+ wchar_t *unicode = make_unicode_string(from);
+
+ if (unicode == NULL)
+ {
+ fprintf(stderr, "Out of memory processing string from UTF8 to UNICODE16\n");
+ return 0;
+ }
+
+ WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, unicode, -1, to, to_size, NULL, NULL);
+
+ SAFE_FREE(&unicode);
+
+ nResult = 1;
+ }
+
+ return nResult;
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/i18n.h b/miranda-wine/protocols/IcqOscarJ/i18n.h
new file mode 100644
index 0000000..0c8adf4
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/i18n.h
@@ -0,0 +1,55 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/i18n.h,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Helper functions to convert text messages between different character sets.
+//
+// -----------------------------------------------------------------------------
+
+
+
+BOOL IsUSASCII(const unsigned char *pBuffer, int nSize);
+BOOL IsUnicodeAscii(const wchar_t *pBuffer, int nSize);
+int UTF8_IsValid(const unsigned char* pszInput);
+
+char* detect_decode_utf8(const char *from);
+
+wchar_t *make_unicode_string(const unsigned char *utf8);
+
+unsigned char *make_utf8_string(const wchar_t *unicode);
+
+int utf8_encode(const char *from, char **to);
+char *ansi_to_utf8(const char *szAnsi);
+char *ansi_to_utf8_codepage(const char *szAnsi, WORD wCp);
+int utf8_decode(const char *from, char **to);
+int utf8_decode_static(const char *from, char *to, int to_size);
+
+void InitI18N(void);
diff --git a/miranda-wine/protocols/IcqOscarJ/iconlib.c b/miranda-wine/protocols/IcqOscarJ/iconlib.c
new file mode 100644
index 0000000..cd4b6d7
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/iconlib.c
@@ -0,0 +1,126 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/iconlib.c,v $
+// Revision : $Revision: 3343 $
+// Last change on : $Date: 2006-07-19 03:36:21 +0400 (Срд, 19 Июл 2006) $
+// Last change by : $Author: rainwater $
+//
+// DESCRIPTION:
+//
+// Support for IcoLib plug-in
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+#include "m_icolib.h"
+
+
+static int bIcoReady = 0;
+static int bIcoUtf = 0;
+
+
+void InitIconLib()
+{ // check plugin presence, init variables
+ bIcoReady = ServiceExists(MS_SKIN2_GETICON);
+ if (bIcoReady)
+ {
+ SKINICONDESC sid = {0};
+
+ if (CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid) >= PLUGIN_MAKE_VERSION(0,0,1,0))
+ bIcoUtf = 1;
+ }
+}
+
+
+
+int IconLibInstalled()
+{
+ return bIcoReady;
+}
+
+
+
+void IconLibDefine(const char* desc, const char* section, const char* ident, HICON icon, const char* def_file, int def_idx)
+{
+ if (bIcoReady)
+ {
+ SKINICONDESC sid = {0};
+ char szTemp[MAX_PATH + 128];
+
+ if (bIcoUtf)
+ {
+ sid.cbSize = SKINICONDESC_SIZE;
+ sid.pwszSection = make_unicode_string(section);
+ sid.pwszDescription = make_unicode_string(desc);
+ sid.flags = SIDF_UNICODE;
+ }
+ else
+ {
+ sid.cbSize = SKINICONDESC_SIZE_V3;
+ utf8_decode(section, &sid.pszSection);
+ utf8_decode(desc, &sid.pszDescription);
+ }
+ null_snprintf(szTemp, sizeof(szTemp), "%s_%s", gpszICQProtoName, ident);
+ sid.pszName = szTemp;
+ sid.pszDefaultFile = (char*)def_file;
+ sid.iDefaultIndex = def_idx;
+ sid.hDefaultIcon = icon;
+ sid.cx = sid.cy = 16;
+
+ CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid);
+
+ SAFE_FREE(&sid.pwszSection);
+ SAFE_FREE(&sid.pwszDescription);
+ }
+}
+
+
+
+HICON IconLibProcess(HICON icon, const char* ident)
+{
+ if (bIcoReady)
+ {
+ char szTemp[MAX_PATH + 128];
+ HICON hNew;
+
+ null_snprintf(szTemp, sizeof(szTemp), "%s_%s", gpszICQProtoName, ident);
+ hNew = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)szTemp);
+ if (hNew) return hNew;
+ }
+
+ return icon;
+}
+
+
+
+HANDLE IconLibHookIconsChanged(MIRANDAHOOK hook)
+{
+ if (bIcoReady)
+ {
+ return HookEvent(ME_SKIN2_ICONSCHANGED, hook);
+ }
+ return NULL;
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/iconlib.h b/miranda-wine/protocols/IcqOscarJ/iconlib.h
new file mode 100644
index 0000000..e2f1266
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/iconlib.h
@@ -0,0 +1,50 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/iconlib.h,v $
+// Revision : $Revision: 3343 $
+// Last change on : $Date: 2006-07-19 03:36:21 +0400 (Срд, 19 Июл 2006) $
+// Last change by : $Author: rainwater $
+//
+// DESCRIPTION:
+//
+// Headers for IconLib Plugin support
+//
+// -----------------------------------------------------------------------------
+
+#ifndef __ICONLIB_H
+#define __ICONLIB_H
+
+
+void InitIconLib();
+
+int IconLibInstalled();
+
+void IconLibDefine(const char* desc, const char* section, const char* ident, HICON icon, const char* def_file, int def_idx);
+HICON IconLibProcess(HICON icon, const char* ident);
+HANDLE IconLibHookIconsChanged(MIRANDAHOOK hook);
+
+
+#endif /* __ICONLIB_H */
diff --git a/miranda-wine/protocols/IcqOscarJ/icons_pack/ICONS.rc b/miranda-wine/protocols/IcqOscarJ/icons_pack/ICONS.rc
new file mode 100644
index 0000000..5e797a9
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icons_pack/ICONS.rc
@@ -0,0 +1,78 @@
+//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"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ IDS_IDENTIFY "# Custom Status Icons #"
+END
+
+
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/auth_ask.ico b/miranda-wine/protocols/IcqOscarJ/icos/auth_ask.ico
new file mode 100644
index 0000000..51da3d8
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/auth_ask.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/auth_grant.ico b/miranda-wine/protocols/IcqOscarJ/icos/auth_grant.ico
new file mode 100644
index 0000000..761644a
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/auth_grant.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/auth_revoke.ico b/miranda-wine/protocols/IcqOscarJ/icos/auth_revoke.ico
new file mode 100644
index 0000000..5cf89a9
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/auth_revoke.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/icq.ico b/miranda-wine/protocols/IcqOscarJ/icos/icq.ico
new file mode 100644
index 0000000..6b46a08
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/icq.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus01.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus01.ico
new file mode 100644
index 0000000..b29cfd3
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus01.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus02.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus02.ico
new file mode 100644
index 0000000..b43efbd
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus02.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus03.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus03.ico
new file mode 100644
index 0000000..819b070
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus03.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus04.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus04.ico
new file mode 100644
index 0000000..946de46
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus04.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus05.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus05.ico
new file mode 100644
index 0000000..762e104
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus05.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus06.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus06.ico
new file mode 100644
index 0000000..d733952
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus06.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus07.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus07.ico
new file mode 100644
index 0000000..801d231
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus07.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus08.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus08.ico
new file mode 100644
index 0000000..68051e5
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus08.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus09.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus09.ico
new file mode 100644
index 0000000..07cebb4
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus09.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus10.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus10.ico
new file mode 100644
index 0000000..0c99c1c
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus10.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus11.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus11.ico
new file mode 100644
index 0000000..311c165
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus11.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus12.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus12.ico
new file mode 100644
index 0000000..42adff4
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus12.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus13.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus13.ico
new file mode 100644
index 0000000..05c5f67
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus13.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus14.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus14.ico
new file mode 100644
index 0000000..4d98556
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus14.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus15.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus15.ico
new file mode 100644
index 0000000..ef8040b
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus15.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus16.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus16.ico
new file mode 100644
index 0000000..dd0a602
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus16.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus17.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus17.ico
new file mode 100644
index 0000000..2d7be75
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus17.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus18.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus18.ico
new file mode 100644
index 0000000..b3d6dd1
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus18.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus19.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus19.ico
new file mode 100644
index 0000000..db4d011
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus19.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus20.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus20.ico
new file mode 100644
index 0000000..fd3ef57
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus20.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus21.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus21.ico
new file mode 100644
index 0000000..2704aa7
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus21.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus22.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus22.ico
new file mode 100644
index 0000000..96e7739
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus22.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus23.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus23.ico
new file mode 100644
index 0000000..8a2ad77
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus23.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus24.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus24.ico
new file mode 100644
index 0000000..8a01165
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus24.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus25.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus25.ico
new file mode 100644
index 0000000..8e6d3f9
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus25.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus26.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus26.ico
new file mode 100644
index 0000000..fe7114d
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus26.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus27.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus27.ico
new file mode 100644
index 0000000..6a84272
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus27.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus28.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus28.ico
new file mode 100644
index 0000000..d78aadc
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus28.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus29.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus29.ico
new file mode 100644
index 0000000..4f2739c
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus29.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus30.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus30.ico
new file mode 100644
index 0000000..fe31759
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus30.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus31.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus31.ico
new file mode 100644
index 0000000..4898abb
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus31.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icos/xstatus32.ico b/miranda-wine/protocols/IcqOscarJ/icos/xstatus32.ico
new file mode 100644
index 0000000..082287f
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icos/xstatus32.ico
Binary files differ
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_advsearch.c b/miranda-wine/protocols/IcqOscarJ/icq_advsearch.c
new file mode 100644
index 0000000..0ffd6ed
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_advsearch.c
@@ -0,0 +1,211 @@
+// ---------------------------------------------------------------------------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, 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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_advsearch.c,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+
+static void InitComboBox(HWND hwndCombo,struct fieldnames_t *names)
+{
+ int iItem;
+ int i;
+
+ iItem = ComboBoxAddStringUtf(hwndCombo, "", 0);
+ SendMessage(hwndCombo, CB_SETCURSEL, iItem, 0);
+
+ for (i = 0; ; i++)
+ {
+ if (names[i].text == NULL)
+ break;
+
+ iItem = ComboBoxAddStringUtf(hwndCombo, names[i].text, names[i].code);
+ }
+}
+
+
+
+BOOL CALLBACK AdvancedSearchDlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch(message)
+ {
+ case WM_INITDIALOG:
+ ICQTranslateDialog(hwndDlg);
+ InitComboBox(GetDlgItem(hwndDlg, IDC_GENDER), genderField);
+ InitComboBox(GetDlgItem(hwndDlg, IDC_AGERANGE), agesField);
+ InitComboBox(GetDlgItem(hwndDlg, IDC_MARITALSTATUS), maritalField);
+ InitComboBox(GetDlgItem(hwndDlg, IDC_WORKFIELD), workField);
+ InitComboBox(GetDlgItem(hwndDlg, IDC_ORGANISATION), affiliationField);
+ InitComboBox(GetDlgItem(hwndDlg, IDC_LANGUAGE), languageField);
+
+ {
+ struct CountryListEntry *countries;
+ int countryCount;
+ int i;
+ int iItem;
+ HWND hCombo;
+
+ CallService(MS_UTILS_GETCOUNTRYLIST, (WPARAM)&countryCount, (LPARAM)&countries);
+
+ hCombo = GetDlgItem(hwndDlg, IDC_COUNTRY);
+ iItem = ComboBoxAddStringUtf(hCombo, "", 0);
+ SendMessage(hCombo, CB_SETCURSEL, iItem, 0);
+ for (i = 0; i < countryCount; i++)
+ {
+ if (countries[i].id == 0 || countries[i].id == 0xFFFF)
+ continue;
+ iItem = ComboBoxAddStringUtf(hCombo, countries[i].szName, countries[i].id);
+ }
+ }
+
+ 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];
+
+ GetDlgItemText(hwndDlg, idControl, str, sizeof(str));
+
+ ppackTLVLNTS(buf, buflen, str, wType, 0);
+}
+
+
+
+static void searchPackTLVWordLNTS(PBYTE *buf, int *buflen, HWND hwndDlg, UINT idControl, WORD w, WORD wType)
+{
+ char str[512];
+
+ GetDlgItemText(hwndDlg, idControl, str, sizeof(str));
+
+ ppackTLVWordLNTS(buf, buflen, w, str, wType, 0);
+}
+
+
+
+static PBYTE createAdvancedSearchStructureTLV(HWND hwndDlg, int *length)
+{
+ PBYTE buf = NULL;
+ int buflen = 0;
+ WORD w;
+
+ 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);
+
+ ppackTLVDWord(&buf, &buflen, (DWORD)getCurItemData(hwndDlg, IDC_AGERANGE), TLV_AGERANGE, 0);
+ ppackTLVByte(&buf, &buflen, (BYTE)getCurItemData(hwndDlg, IDC_GENDER), TLV_GENDER, 0);
+ ppackTLVByte(&buf, &buflen, (BYTE)getCurItemData(hwndDlg, IDC_MARITALSTATUS), TLV_MARITAL, 0);
+ ppackTLVWord(&buf, &buflen, (WORD)getCurItemData(hwndDlg, IDC_LANGUAGE), TLV_LANGUAGE, 0);
+ ppackTLVWord(&buf, &buflen, (WORD)getCurItemData(hwndDlg, IDC_COUNTRY), TLV_COUNTRY, 0);
+ ppackTLVWord(&buf, &buflen, (WORD)getCurItemData(hwndDlg, IDC_WORKFIELD), TLV_OCUPATION, 0);
+
+ 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);;
+ searchPackTLVWordLNTS(&buf, &buflen, hwndDlg, IDC_HOMEPAGEKEY, w, TLV_HOMEPAGE);
+
+ ppackTLVByte(&buf, &buflen, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_ONLINEONLY), 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/miranda-wine/protocols/IcqOscarJ/icq_advsearch.h b/miranda-wine/protocols/IcqOscarJ/icq_advsearch.h
new file mode 100644
index 0000000..7d889a8
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_advsearch.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,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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_advsearch.h,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+
+
+BOOL CALLBACK AdvancedSearchDlgProc(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam);
+PBYTE createAdvancedSearchStructure(HWND hwndDlg,int *length);
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_avatar.c b/miranda-wine/protocols/IcqOscarJ/icq_avatar.c
new file mode 100644
index 0000000..332760b
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_avatar.c
@@ -0,0 +1,1275 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_avatar.c,v $
+// Revision : $Revision: 3474 $
+// Last change on : $Date: 2006-08-08 03:05:47 +0400 (Втр, 08 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Manages Avatar connection, provides internal service for handling avatars
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+BOOL AvatarsReady = FALSE; // states if avatar connection established and ready for requests
+
+
+typedef struct avatarthreadstartinfo_t
+{
+ HANDLE hConnection; // handle to the connection
+ char* pCookie;
+ WORD wCookieLen;
+ HANDLE hAvatarPacketRecver;
+ int stopThread; // horrible, but simple - signal for thread to stop
+ WORD wLocalSequence;
+ CRITICAL_SECTION localSeqMutex;
+ int pendingLogin;
+ int paused;
+ HANDLE runContact[4];
+ DWORD runTime[4];
+ int runCount;
+} avatarthreadstartinfo;
+
+typedef struct avatarrequest_t
+{
+ int type;
+ DWORD dwUin;
+ char *szUid;
+ HANDLE hContact;
+ char *hash;
+ unsigned int hashlen;
+ char *szFile;
+ char *pData;
+ unsigned int cbData;
+ WORD wRef;
+ void *pNext; // invalid, but reused - spare realloc
+} avatarrequest;
+
+avatarthreadstartinfo* currentAvatarThread;
+int pendingAvatarsStart = 1;
+static avatarrequest* pendingRequests = NULL;
+
+extern CRITICAL_SECTION cookieMutex;
+
+static int sendAvatarPacket(icq_packet* pPacket, avatarthreadstartinfo* atsi /*= currentAvatarThread*/);
+
+static DWORD __stdcall icq_avatarThread(avatarthreadstartinfo *atsi);
+int handleAvatarPackets(unsigned char* buf, int buflen, avatarthreadstartinfo* atsi);
+
+void handleAvatarLogin(unsigned char *buf, WORD datalen, avatarthreadstartinfo *atsi);
+void handleAvatarData(unsigned char *pBuffer, WORD wBufferLength, avatarthreadstartinfo *atsi);
+
+void handleAvatarServiceFam(unsigned char* pBuffer, WORD wBufferLength, snac_header* pSnacHeader, avatarthreadstartinfo *atsi);
+void handleAvatarFam(unsigned char *pBuffer, WORD wBufferLength, snac_header* pSnacHeader, avatarthreadstartinfo *atsi);
+
+
+char* loadMyAvatarFileName()
+{
+ DBVARIANT dbvFile = {0};
+
+ if (!ICQGetContactSetting(NULL, "AvatarFile", &dbvFile))
+ {
+ char tmp[MAX_PATH];;
+
+ CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM)dbvFile.pszVal, (LPARAM)tmp);
+ ICQFreeVariant(&dbvFile);
+ return null_strdup(tmp);
+ }
+ return NULL;
+}
+
+
+
+void storeMyAvatarFileName(char* szFile)
+{
+ char tmp[MAX_PATH];
+
+ CallService(MS_UTILS_PATHTORELATIVE, (WPARAM)szFile, (LPARAM)tmp);
+ ICQWriteContactSettingString(NULL, "AvatarFile", tmp);
+}
+
+
+
+void GetFullAvatarFileName(int dwUin, char* szUid, int dwFormat, char* pszDest, int cbLen)
+{
+ GetAvatarFileName(dwUin, szUid, pszDest, cbLen);
+ AddAvatarExt(dwFormat, pszDest);
+}
+
+
+
+void GetAvatarFileName(int dwUin, char* szUid, char* pszDest, int cbLen)
+{
+ int tPathLen;
+
+ CallService(MS_DB_GETPROFILEPATH, cbLen, (LPARAM)pszDest);
+
+ tPathLen = strlennull(pszDest);
+ tPathLen += null_snprintf(pszDest + tPathLen, MAX_PATH-tPathLen, "\\%s\\", gpszICQProtoName);
+ CreateDirectory(pszDest, NULL);
+
+ if (dwUin != 0)
+ {
+ ltoa(dwUin, pszDest + tPathLen, 10);
+ }
+ else if (szUid)
+ {
+ strcpy(pszDest + tPathLen, szUid);
+ }
+ else
+ {
+ char szBuf[MAX_PATH];
+
+ if (CallService(MS_DB_GETPROFILENAME, 250 - tPathLen, (LPARAM)szBuf))
+ strcpy(pszDest + tPathLen, "avatar" );
+ else
+ {
+ char* szLastDot = strstr(szBuf, ".");
+ if (szLastDot) while (strstr(szLastDot+1, ".")) szLastDot = strstr(szLastDot+1, ".");
+ if (szLastDot) szLastDot[0] = '\0';
+ strcpy(pszDest + tPathLen, szBuf);
+ strcat(pszDest + tPathLen, "_avt");
+ }
+ }
+}
+
+
+
+void AddAvatarExt(int dwFormat, char* pszDest)
+{
+ if (dwFormat == PA_FORMAT_JPEG)
+ strcat(pszDest, ".jpg");
+ else if (dwFormat == PA_FORMAT_GIF)
+ strcat(pszDest, ".gif");
+ else if (dwFormat == PA_FORMAT_PNG)
+ strcat(pszDest, ".png");
+ else if (dwFormat == PA_FORMAT_BMP)
+ strcat(pszDest, ".bmp");
+ else if (dwFormat == PA_FORMAT_XML)
+ strcat(pszDest, ".xml");
+ else if (dwFormat == PA_FORMAT_SWF)
+ strcat(pszDest, ".swf");
+ else
+ strcat(pszDest, ".dat");
+}
+
+
+
+int DetectAvatarFormatBuffer(char* pBuffer)
+{
+ if (!strncmp(pBuffer, "%PNG", 4))
+ {
+ return PA_FORMAT_PNG;
+ }
+ if (!strncmp(pBuffer, "GIF8", 4))
+ {
+ return PA_FORMAT_GIF;
+ }
+ if (!strnicmp(pBuffer, "<?xml", 5))
+ {
+ return PA_FORMAT_XML;
+ }
+ if ((((DWORD*)pBuffer)[0] == 0xE0FFD8FFul) || (((DWORD*)pBuffer)[0] == 0xE1FFD8FFul))
+ {
+ return PA_FORMAT_JPEG;
+ }
+ if (!strncmp(pBuffer, "BM", 2))
+ {
+ return PA_FORMAT_BMP;
+ }
+ return PA_FORMAT_UNKNOWN;
+}
+
+
+
+int DetectAvatarFormat(char* szFile)
+{
+ char pBuf[32];
+
+ int src = _open(szFile, _O_BINARY | _O_RDONLY);
+
+ if (src != -1)
+ {
+ _read(src, pBuf, 32);
+ _close(src);
+
+ return DetectAvatarFormatBuffer(pBuf);
+ }
+ else
+ return PA_FORMAT_UNKNOWN;
+}
+
+
+
+int IsAvatarSaved(HANDLE hContact, char* pHash)
+{
+ DBVARIANT dbvSaved = {0};
+
+ if (!ICQGetContactSetting(hContact, "AvatarSaved", &dbvSaved))
+ {
+ if ((dbvSaved.cpbVal != 0x14) || memcmp(dbvSaved.pbVal, pHash, 0x14))
+ { // the hashes is different
+ ICQFreeVariant(&dbvSaved);
+
+ return 2;
+ }
+ ICQFreeVariant(&dbvSaved);
+
+ return 0; // hash is there and is the same - Success
+ }
+ return 1; // saved Avatar hash is missing
+}
+
+
+
+void StartAvatarThread(HANDLE hConn, char* cookie, WORD cookieLen) // called from event
+{
+ avatarthreadstartinfo* atsi = NULL;
+ pthread_t tid;
+
+ if (!hConn)
+ {
+ atsi = currentAvatarThread;
+ if (atsi && atsi->pendingLogin) // this is not safe...
+ {
+ NetLog_Server("Avatar, Multiple start thread attempt, ignored.");
+ SAFE_FREE(&cookie);
+ return;
+ }
+ pendingAvatarsStart = 0;
+ NetLog_Server("Avatar: Connect failed");
+
+ EnterCriticalSection(&cookieMutex); // wait for ready queue, reused cs
+ { // check if any upload request is not in the queue
+ avatarrequest* ar;
+ void** par = &pendingRequests;
+ int bYet = 0;
+ ar = pendingRequests;
+ while (ar)
+ {
+ if (ar->type == 2)
+ { // we found it, return error
+ void *tmp;
+
+ if (!bYet)
+ {
+ icq_LogMessage(LOG_WARNING, "Error uploading avatar to server, server temporarily unavailable.");
+ }
+ bYet = 1;
+ SAFE_FREE(&ar->pData); // remove upload request from queue
+ tmp = ar;
+ ar = ar->pNext;
+ *par = ar;
+ SAFE_FREE(&tmp);
+ continue;
+ }
+ par = &ar->pNext;
+ ar = ar->pNext;
+ }
+ }
+ LeaveCriticalSection(&cookieMutex);
+
+ SAFE_FREE(&cookie);
+
+ return;
+ }
+ atsi = currentAvatarThread;
+ if (atsi && atsi->pendingLogin) // this is not safe...
+ {
+ NetLog_Server("Avatar, Multiple start thread attempt, ignored.");
+ NetLib_SafeCloseHandle(&hConn, FALSE);
+ SAFE_FREE(&cookie);
+ return;
+ }
+
+ AvatarsReady = FALSE; // the old connection should not be used anymore
+
+ atsi = (avatarthreadstartinfo*)SAFE_MALLOC(sizeof(avatarthreadstartinfo));
+ atsi->pendingLogin = 1;
+ // Randomize sequence
+ atsi->wLocalSequence = (WORD)RandRange(0, 0x7fff);
+ atsi->hConnection = hConn;
+ atsi->pCookie = cookie;
+ atsi->wCookieLen = cookieLen;
+ currentAvatarThread = atsi; // we store only current thread
+ tid.hThread = (HANDLE)forkthreadex(NULL, 0, icq_avatarThread, atsi, 0, &tid.dwThreadId);
+ CloseHandle(tid.hThread);
+
+ return;
+}
+
+
+
+void StopAvatarThread()
+{
+ AvatarsReady = FALSE; // the connection are about to close
+
+ if (currentAvatarThread)
+ {
+ currentAvatarThread->stopThread = 1; // make the thread stop
+ currentAvatarThread = NULL; // the thread will finish in background
+ }
+ return;
+}
+
+
+
+static void NetLog_Hash(const char* pszIdent, unsigned char* pHash)
+{
+ NetLog_Server("%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]);
+}
+
+
+
+// handle Contact's avatar hash
+void handleAvatarContactHash(DWORD dwUIN, char* szUID, HANDLE hContact, unsigned char* pHash, unsigned int nHashLen, WORD wOldStatus)
+{
+ DBVARIANT dbv;
+ BOOL bJob = FALSE;
+ char szAvatar[MAX_PATH];
+ int dwPaFormat;
+
+ if (nHashLen >= 0x14)
+ {
+ // check if it is really avatar (it can be also AIM's online message)
+ if (pHash[0] != 0 || (pHash[1] != 1 && pHash[1] != 8)) return;
+
+ if (nHashLen == 0x18 && pHash[3] == 0)
+ { // icq probably set two avatars, get something from that
+ memcpy(pHash, pHash+4, 0x14);
+ }
+
+ if (gbAvatarsEnabled)
+ { // check settings, should we request avatar immediatelly
+ BYTE bAutoLoad = ICQGetContactSettingByte(NULL, "AvatarsAutoLoad", DEFAULT_LOAD_AVATARS);
+
+ if (ICQGetContactSetting(hContact, "AvatarHash", &dbv))
+ { // we not found old hash, i.e. get new avatar
+ int fileState = IsAvatarSaved(hContact, pHash);
+
+ // check saved hash and file, if equal only store hash
+ if (!fileState)
+ { // hashes are the same
+ dwPaFormat = ICQGetContactSettingByte(hContact, "AvatarType", PA_FORMAT_UNKNOWN);
+
+ GetFullAvatarFileName(dwUIN, szUID, dwPaFormat, szAvatar, MAX_PATH);
+ if (access(szAvatar, 0) == 0)
+ { // the file is there, link to contactphoto, save hash
+ NetLog_Server("Avatar is known, hash stored, linked to file.");
+
+ ICQWriteContactSettingBlob(hContact, "AvatarHash", pHash, 0x14);
+
+ if (dwPaFormat != PA_FORMAT_UNKNOWN && dwPaFormat != PA_FORMAT_XML)
+ LinkContactPhotoToFile(hContact, szAvatar);
+ else // the format is not supported unlink
+ LinkContactPhotoToFile(hContact, NULL);
+
+ ICQBroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, (LPARAM)NULL);
+ }
+ else // the file is lost, request avatar again
+ bJob = TRUE;
+ }
+ else
+ { // the hash is not the one we want, request avatar
+ if (fileState == 2)
+ { // the hash is different, unlink contactphoto
+ LinkContactPhotoToFile(hContact, NULL);
+ }
+ bJob = TRUE;
+ }
+ }
+ else
+ { // we found hash check if it changed or not
+ NetLog_Hash("Old", dbv.pbVal);
+ if ((dbv.cpbVal != 0x14) || memcmp(dbv.pbVal, pHash, 0x14))
+ { // the hash is different, request new avatar
+ LinkContactPhotoToFile(hContact, NULL); // unlink photo
+ bJob = TRUE;
+ }
+ else
+ { // the hash does not changed, check if we have correct file
+ int fileState = IsAvatarSaved(hContact, pHash);
+
+ // we should have file, check if the file really exists
+ if (!fileState)
+ {
+ dwPaFormat = ICQGetContactSettingByte(hContact, "AvatarType", PA_FORMAT_UNKNOWN);
+ if (dwPaFormat == PA_FORMAT_UNKNOWN)
+ { // we do not know the format, get avatar again
+ bJob = TRUE;
+ }
+ else
+ {
+ GetFullAvatarFileName(dwUIN, szUID, dwPaFormat, szAvatar, MAX_PATH);
+ if (access(szAvatar, 0) == 0)
+ { // the file exists, so try to update photo setting
+ if (dwPaFormat != PA_FORMAT_XML && dwPaFormat != PA_FORMAT_UNKNOWN)
+ {
+ LinkContactPhotoToFile(hContact, szAvatar);
+ }
+ }
+ else // the file was lost, get it again
+ bJob = TRUE;
+ }
+ }
+ else
+ { // the hash is not the one we want, request avatar
+ if (fileState == 2)
+ { // the hash is different, unlink contactphoto
+ LinkContactPhotoToFile(hContact, NULL);
+ }
+ bJob = TRUE;
+ }
+ }
+ ICQFreeVariant(&dbv);
+ }
+
+ if (bJob)
+ {
+ NetLog_Hash("New", pHash);
+ NetLog_Server("User has Avatar, new hash stored.");
+
+ ICQWriteContactSettingBlob(hContact, "AvatarHash", pHash, 0x14);
+
+ ICQBroadcastAck(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, szAvatar, MAX_PATH);
+ GetAvatarData(hContact, dwUIN, szUID, pHash, 0x14 /*nHashLen*/, szAvatar);
+ } // avatar request sent or added to queue
+ }
+ else
+ {
+ NetLog_Server("User has Avatar.");
+ }
+ }
+ }
+ else if (wOldStatus == ID_STATUS_OFFLINE)
+ { // if user were offline, and now hash not found, clear the hash
+ ICQDeleteContactSetting(hContact, "AvatarHash"); // TODO: need more testing
+ }
+}
+
+
+
+static avatarrequest* CreateAvatarRequest(int type)
+{
+ avatarrequest *ar;
+
+ ar = (avatarrequest*)SAFE_MALLOC(sizeof(avatarrequest));
+ if (ar)
+ ar->type = type;
+
+ return ar;
+}
+
+
+
+// request avatar data from server
+int GetAvatarData(HANDLE hContact, DWORD dwUin, char* szUid, char* hash, unsigned int hashlen, char* file)
+{
+ avatarthreadstartinfo* atsi;
+
+ atsi = currentAvatarThread; // we take avatar thread - horrible, but realiable
+ if (AvatarsReady && !atsi->paused) // check if we are ready
+ {
+ icq_packet packet;
+ BYTE nUinLen;
+ DWORD dwCookie;
+ avatarcookie* ack;
+ int i;
+ DWORD dwNow = GetTickCount();
+
+ EnterCriticalSection(&cookieMutex); // reused...
+ for(i = 0; i < atsi->runCount;)
+ { // look for timeouted requests
+ if (atsi->runTime[i] < dwNow)
+ { // found outdated, remove
+ atsi->runContact[i] = atsi->runContact[atsi->runCount - 1];
+ atsi->runTime[i] = atsi->runTime[atsi->runCount - 1];
+ atsi->runCount--;
+ }
+ else
+ i++;
+ }
+
+ for(i = 0; i < atsi->runCount; i++)
+ {
+ if (atsi->runContact[i] == hContact)
+ {
+ LeaveCriticalSection(&cookieMutex);
+ NetLog_Server("Ignoring duplicate get %d avatar request.", dwUin);
+
+ return 0;
+ }
+ }
+
+ if (atsi->runCount < 4)
+ { // 4 concurent requests at most
+ atsi->runContact[atsi->runCount] = hContact;
+ atsi->runTime[atsi->runCount] = GetTickCount() + 30000; // 30sec to complete request
+ atsi->runCount++;
+ LeaveCriticalSection(&cookieMutex);
+
+ nUinLen = getUIDLen(dwUin, szUid);
+
+ ack = (avatarcookie*)SAFE_MALLOC(sizeof(avatarcookie));
+ if (!ack) return 0; // out of memory, go away
+ ack->dwUin = 1; //dwUin; // I should be damned for this - only to identify get request
+ ack->hContact = hContact;
+ ack->hash = (char*)SAFE_MALLOC(hashlen);
+ memcpy(ack->hash, hash, hashlen); // copy the data
+ ack->hashlen = hashlen;
+ ack->szFile = null_strdup(file); // we duplicate the string
+ dwCookie = AllocateCookie(CKT_AVATAR, ICQ_AVATAR_GET_REQUEST, dwUin, ack);
+
+ serverPacketInit(&packet, (WORD)(12 + nUinLen + hashlen));
+ packFNACHeaderFull(&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, (unsigned short)hashlen);
+
+ if (sendAvatarPacket(&packet, atsi))
+ {
+ NetLog_Server("Request to get %d avatar image sent.", dwUin);
+
+ return dwCookie;
+ }
+ FreeCookie(dwCookie); // sending failed, free resources
+ SAFE_FREE(&ack->szFile);
+ SAFE_FREE(&ack->hash);
+ SAFE_FREE(&ack);
+ }
+ else
+ LeaveCriticalSection(&cookieMutex);
+ }
+ // we failed to send request, or avatar thread not ready
+ EnterCriticalSection(&cookieMutex); // wait for ready queue, reused cs
+ { // check if any request for this user is not already in the queue
+ avatarrequest* ar;
+ int bYet = 0;
+ ar = pendingRequests;
+ while (ar)
+ {
+ if (ar->hContact == hContact)
+ { // we found it, return error
+ LeaveCriticalSection(&cookieMutex);
+ NetLog_Server("Ignoring duplicate get %d avatar request.", dwUin);
+
+ if (!AvatarsReady && !pendingAvatarsStart)
+ {
+ icq_requestnewfamily(ICQ_AVATAR_FAMILY, StartAvatarThread);
+ pendingAvatarsStart = 1;
+ }
+ return 0;
+ }
+ ar = ar->pNext;
+ }
+ // add request to queue, processed after successful login
+ ar = CreateAvatarRequest(1); // get avatar
+ if (!ar)
+ { // out of memory, go away
+ LeaveCriticalSection(&cookieMutex);
+ return 0;
+ }
+ ar->dwUin = dwUin;
+ ar->szUid = null_strdup(szUid);
+ ar->hContact = hContact;
+ ar->hash = (char*)SAFE_MALLOC(hashlen);
+ memcpy(ar->hash, hash, hashlen); // copy the data
+ ar->hashlen = hashlen;
+ ar->szFile = null_strdup(file); // duplicate the string
+ ar->pNext = pendingRequests;
+ pendingRequests = ar;
+ }
+ LeaveCriticalSection(&cookieMutex);
+
+ NetLog_Server("Request to get %d avatar image added to queue.", dwUin);
+
+ if (!AvatarsReady && !pendingAvatarsStart)
+ {
+ icq_requestnewfamily(0x10, StartAvatarThread);
+ pendingAvatarsStart = 1;
+ }
+
+ return -1; // we added to queue
+}
+
+
+
+// upload avatar data to server
+int SetAvatarData(HANDLE hContact, WORD wRef, char* data, unsigned int datalen)
+{
+ avatarthreadstartinfo* atsi;
+
+ atsi = currentAvatarThread; // we take avatar thread - horrible, but realiable
+ if (AvatarsReady && !atsi->paused) // check if we are ready
+ {
+ icq_packet packet;
+ DWORD dwCookie;
+ avatarcookie* ack;
+
+ ack = (avatarcookie*)SAFE_MALLOC(sizeof(avatarcookie));
+ if (!ack) return 0; // out of memory, go away
+ ack->hContact = hContact;
+ ack->cbData = datalen;
+
+ dwCookie = AllocateCookie(CKT_AVATAR, ICQ_AVATAR_UPLOAD_REQUEST, 0, ack);
+
+ serverPacketInit(&packet, (WORD)(14 + datalen));
+ packFNACHeaderFull(&packet, ICQ_AVATAR_FAMILY, ICQ_AVATAR_UPLOAD_REQUEST, 0, dwCookie);
+ packWord(&packet, wRef); // unknown, probably reference
+ packWord(&packet, (WORD)datalen);
+ packBuffer(&packet, data, (unsigned short)datalen);
+
+ if (sendAvatarPacket(&packet, atsi))
+ {
+ NetLog_Server("Upload avatar packet sent.");
+
+ return dwCookie;
+ }
+ ReleaseCookie(dwCookie); // failed to send, free resources
+ }
+ // we failed to send request, or avatar thread not ready
+ EnterCriticalSection(&cookieMutex); // wait for ready queue, reused cs
+ { // check if any request for this user is not already in the queue
+ avatarrequest* ar;
+ int bYet = 0;
+ ar = pendingRequests;
+ while (ar)
+ {
+ if (ar->hContact == hContact)
+ { // we found it, return error
+ LeaveCriticalSection(&cookieMutex);
+ NetLog_Server("Ignoring duplicate upload avatar request.");
+
+ if (!AvatarsReady && !pendingAvatarsStart)
+ {
+ icq_requestnewfamily(0x10, StartAvatarThread);
+ pendingAvatarsStart = 1;
+ }
+ return 0;
+ }
+ ar = ar->pNext;
+ }
+ // add request to queue, processed after successful login
+ ar = CreateAvatarRequest(2); // upload avatar
+ if (!ar)
+ { // out of memory, go away
+ LeaveCriticalSection(&cookieMutex);
+ return 0;
+ }
+ ar->hContact = hContact;
+ ar->pData = (char*)SAFE_MALLOC(datalen);
+ if (!ar->pData)
+ { // alloc failed
+ LeaveCriticalSection(&cookieMutex);
+ SAFE_FREE(&ar);
+ return 0;
+ }
+ memcpy(ar->pData, data, datalen); // copy the data
+ ar->cbData = datalen;
+ ar->wRef = wRef;
+ ar->pNext = pendingRequests;
+ pendingRequests = ar;
+ }
+ LeaveCriticalSection(&cookieMutex);
+
+ NetLog_Server("Request to upload avatar image added to queue.");
+
+ if (!AvatarsReady && !pendingAvatarsStart)
+ {
+ pendingAvatarsStart = 1;
+ icq_requestnewfamily(0x10, StartAvatarThread);
+ }
+
+ return -1; // we added to queue
+}
+
+
+
+static DWORD __stdcall icq_avatarThread(avatarthreadstartinfo *atsi)
+{
+ // This is the "infinite" loop that receives the packets from the ICQ avatar server
+ {
+ int recvResult;
+ NETLIBPACKETRECVER packetRecv = {0};
+ DWORD wLastKeepAlive = 0; // we send keep-alive at most one per 30secs
+
+ InitializeCriticalSection(&atsi->localSeqMutex);
+
+ atsi->hAvatarPacketRecver = (HANDLE)CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)atsi->hConnection, 8192);
+ packetRecv.cbSize = sizeof(packetRecv);
+ packetRecv.dwTimeout = 60000; // timeout every minute - for stopThread to work
+ while(!atsi->stopThread)
+ {
+ recvResult = CallService(MS_NETLIB_GETMOREPACKETS,(WPARAM)atsi->hAvatarPacketRecver, (LPARAM)&packetRecv);
+
+ if (recvResult == 0)
+ {
+ NetLog_Server("Clean closure of avatar socket");
+ break;
+ }
+
+ if (recvResult == SOCKET_ERROR)
+ {
+ if (GetLastError() == ERROR_TIMEOUT)
+ { // timeout, check if we should be still running
+ if (Miranda_Terminated())
+ atsi->stopThread = 1; // we must stop here, cause due to a hack in netlib, we always get timeout, even if the connection is already dead
+#ifdef _DEBUG
+ else
+ NetLog_Server("Avatar Thread is Idle.");
+#endif
+ if (GetTickCount() > wLastKeepAlive)
+ { // limit frequency (HACK: on some systems select() does not work well)
+ if (ICQGetContactSettingByte(NULL, "KeepAlive", 0))
+ { // send keep-alive packet
+ icq_packet packet;
+
+ packet.wLen = 0;
+ write_flap(&packet, ICQ_PING_CHAN);
+ sendAvatarPacket(&packet, atsi);
+ }
+ wLastKeepAlive = GetTickCount() + 57000;
+ }
+ else
+ { // this is bad, the system does not handle select() properly
+#ifdef _DEBUG
+ NetLog_Server("Avatar Thread is Forcing Idle.");
+#endif
+ SleepEx(500, TRUE); // wait some time, can we do anything else ??
+ }
+ continue;
+ }
+ NetLog_Server("Abortive closure of avatar socket");
+ break;
+ }
+
+ // Deal with the packet
+ packetRecv.bytesUsed = handleAvatarPackets(packetRecv.buffer, packetRecv.bytesAvailable, atsi);
+
+ if ((AvatarsReady == TRUE) && (packetRecv.bytesAvailable == packetRecv.bytesUsed) && !atsi->paused) // no packets pending
+ { // process request queue
+ EnterCriticalSection(&cookieMutex);
+
+ while (pendingRequests && atsi->runCount < 3) // pick up an request and send it - happens immediatelly after login
+ { // do not fill queue to top, leave one place free
+ avatarrequest* reqdata = pendingRequests;
+ pendingRequests = reqdata->pNext;
+
+#ifdef _DEBUG
+ NetLog_Server("Picked up the %d request from queue.", reqdata->dwUin);
+#endif
+ switch (reqdata->type)
+ {
+ case 1: // get avatar
+ GetAvatarData(reqdata->hContact, reqdata->dwUin, reqdata->szUid, reqdata->hash, reqdata->hashlen, reqdata->szFile);
+
+ SAFE_FREE(&reqdata->szUid);
+ SAFE_FREE(&reqdata->szFile);
+ SAFE_FREE(&reqdata->hash); // as soon as it will be copied
+ break;
+ case 2: // set avatar
+ SetAvatarData(reqdata->hContact, reqdata->wRef, reqdata->pData, reqdata->cbData);
+
+ SAFE_FREE(&reqdata->pData);
+ break;
+ }
+ SAFE_FREE(&reqdata);
+ }
+
+ LeaveCriticalSection(&cookieMutex);
+ }
+ }
+ NetLib_SafeCloseHandle(&atsi->hAvatarPacketRecver, FALSE); // Close the packet receiver
+ }
+ NetLib_SafeCloseHandle(&atsi->hConnection, FALSE); // Close the connection
+
+ DeleteCriticalSection(&atsi->localSeqMutex);
+
+ SAFE_FREE(&atsi->pCookie);
+ if (currentAvatarThread == atsi) // if we stoped by error or unexpectedly, clear global variable
+ {
+ AvatarsReady = FALSE; // we are not ready
+ pendingAvatarsStart = 0;
+ currentAvatarThread = NULL; // this is horrible, rewrite
+ }
+ SAFE_FREE(&atsi);
+
+ NetLog_Server("%s thread ended.", "Avatar");
+
+ return 0;
+}
+
+
+
+int handleAvatarPackets(unsigned char* buf, int buflen, avatarthreadstartinfo* atsi)
+{
+ 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("Avatar FLAP: Channel %u, Seq %u, Length %u bytes", channel, sequence, datalen);
+#endif
+
+ switch (channel)
+ {
+ case ICQ_LOGIN_CHAN:
+ handleAvatarLogin(buf, datalen, atsi);
+ break;
+
+ case ICQ_DATA_CHAN:
+ handleAvatarData(buf, datalen, atsi);
+ break;
+
+ default:
+ NetLog_Server("Warning: Unhandled %s FLAP Channel: Channel %u, Seq %u, Length %u bytes", "Avatar", channel, sequence, datalen);
+ break;
+ }
+
+ /* Increase pointers so we can check for more FLAPs */
+ buf += datalen;
+ buflen -= (datalen + 6);
+ bytesUsed += (datalen + 6);
+ }
+
+ return bytesUsed;
+}
+
+
+
+static int sendAvatarPacket(icq_packet* pPacket, avatarthreadstartinfo* atsi)
+{
+ int lResult = 0;
+
+ // This critsec makes sure that the sequence order doesn't get screwed up
+ EnterCriticalSection(&atsi->localSeqMutex);
+
+ if (atsi->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.
+ atsi->wLocalSequence++;
+
+ // Pack sequence number
+ pPacket->pData[2] = ((atsi->wLocalSequence & 0xff00) >> 8);
+ pPacket->pData[3] = (atsi->wLocalSequence & 0x00ff);
+
+ for (nRetries = 3; nRetries >= 0; nRetries--)
+ {
+ nSendResult = Netlib_Send(atsi->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
+ }
+ }
+ else
+ {
+ NetLog_Server("Error: Failed to send packet (no connection)");
+ }
+
+ LeaveCriticalSection(&atsi->localSeqMutex);
+
+ SAFE_FREE(&pPacket->pData);
+
+ return lResult;
+}
+
+
+
+void handleAvatarLogin(unsigned char *buf, WORD datalen, avatarthreadstartinfo *atsi)
+{
+ icq_packet packet;
+
+ if (*(DWORD*)buf == 0x1000000)
+ { // here check if we received SRV_HELLO
+ atsi->wLocalSequence = (WORD)RandRange(0, 0xffff);
+
+ serverCookieInit(&packet, atsi->pCookie, atsi->wCookieLen);
+ sendAvatarPacket(&packet, atsi);
+
+#ifdef _DEBUG
+ NetLog_Server("Sent CLI_IDENT to %s server", "avatar");
+#endif
+
+ SAFE_FREE(&atsi->pCookie);
+ atsi->wCookieLen = 0;
+ }
+ else
+ {
+ NetLog_Server("Invalid Avatar Server response, Ch1.");
+ }
+}
+
+
+
+void handleAvatarData(unsigned char *pBuffer, WORD wBufferLength, avatarthreadstartinfo *atsi)
+{
+ snac_header snacHeader = {0};
+
+ if (!unpackSnacHeader(&snacHeader, &pBuffer, &wBufferLength) || !snacHeader.bValid)
+ {
+ NetLog_Server("Error: Failed to parse SNAC header");
+ }
+ else
+ {
+#ifdef _DEBUG
+ NetLog_Server(" Received SNAC(x%02X,x%02X)", snacHeader.wFamily, snacHeader.wSubtype);
+#endif
+
+ switch (snacHeader.wFamily)
+ {
+
+ case ICQ_SERVICE_FAMILY:
+ handleAvatarServiceFam(pBuffer, wBufferLength, &snacHeader, atsi);
+ break;
+
+ case ICQ_AVATAR_FAMILY:
+ handleAvatarFam(pBuffer, wBufferLength, &snacHeader, atsi);
+ break;
+
+ default:
+ NetLog_Server("Ignoring SNAC(x%02X,x%02X) - FAMILYx%02X not implemented", snacHeader.wFamily, snacHeader.wSubtype, snacHeader.wFamily);
+ break;
+ }
+ }
+}
+
+
+
+void handleAvatarServiceFam(unsigned char* pBuffer, WORD wBufferLength, snac_header* pSnacHeader, avatarthreadstartinfo *atsi)
+{
+ icq_packet packet;
+
+ switch (pSnacHeader->wSubtype)
+ {
+
+ case ICQ_SERVER_READY:
+#ifdef _DEBUG
+ NetLog_Server("Avatar 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);
+ sendAvatarPacket(&packet, atsi);
+ 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);
+ sendAvatarPacket(&packet, atsi);
+ break;
+
+ case ICQ_SERVER_RATE_INFO:
+#ifdef _DEBUG
+ NetLog_Server("Server sent Rate Info");
+ NetLog_Server("Sending Rate Info Ack");
+#endif
+ /* Don't really care about this now, just send the ack */
+ serverPacketInit(&packet, 20); // TODO: add rate management to request queue (0.5+)
+ packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_RATE_ACK);
+ packDWord(&packet, 0x00010002);
+ packDWord(&packet, 0x00030004);
+ packWord(&packet, 0x0005);
+ sendAvatarPacket(&packet, atsi);
+
+ // send cli_ready
+ serverPacketInit(&packet, 26);
+ packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_READY);
+ packDWord(&packet, 0x00010004);
+ packDWord(&packet, 0x001008E4);
+ packDWord(&packet, 0x00100001);
+ packDWord(&packet, 0x001008E4);
+ sendAvatarPacket(&packet, atsi);
+
+ AvatarsReady = TRUE; // we are ready to process requests
+ pendingAvatarsStart = 0;
+ atsi->pendingLogin = 0;
+
+ NetLog_Server(" *** Yeehah, avatar login sequence complete");
+ break;
+
+/* case ICQ_SERVER_PAUSE:
+ NetLog_Server("Avatar server is going down in a few seconds... (Flags: %u, Ref: %u)", pSnacHeader->wFlags, pSnacHeader->dwRef);
+ // This is the list of groups that we want to have on the next server
+ serverPacketInit(&packet, 14);
+ packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_PAUSE_ACK);
+ packWord(&packet,ICQ_SERVICE_FAMILY);
+ packWord(&packet,ICQ_AVATAR_FAMILY);
+ sendAvatarPacket(&packet, atsi);
+#ifdef _DEBUG
+ NetLog_Server("Sent server pause ack");
+#endif
+ break; // TODO: avatar migration is not working, should be ?*/
+
+ 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 handleAvatarFam(unsigned char *pBuffer, WORD wBufferLength, snac_header* pSnacHeader, avatarthreadstartinfo *atsi)
+{
+ switch (pSnacHeader->wSubtype)
+ {
+ case ICQ_AVATAR_GET_REPLY: // received avatar data, store to file
+ { // handle new avatar, notify
+ avatarcookie* ac;
+
+ if (FindCookie(pSnacHeader->dwRef, NULL, &ac))
+ {
+ BYTE len;
+ WORD datalen;
+ int out;
+ char* szMyFile = (char*)_alloca(strlennull(ac->szFile)+10);
+ PROTO_AVATAR_INFORMATION ai;
+ int i;
+
+ EnterCriticalSection(&cookieMutex);
+ for(i = 0; i < atsi->runCount; i++)
+ { // look for our record
+ if (atsi->runContact[i] == ac->hContact)
+ { // found remove
+ atsi->runContact[i] = atsi->runContact[atsi->runCount - 1];
+ atsi->runTime[i] = atsi->runTime[atsi->runCount - 1];
+ atsi->runCount--;
+ break;
+ }
+ }
+ LeaveCriticalSection(&cookieMutex);
+
+ strcpy(szMyFile, ac->szFile);
+
+ ai.cbSize = sizeof ai;
+ ai.format = PA_FORMAT_JPEG; // this is for error only
+ ai.hContact = ac->hContact;
+ strcpy(ai.filename, ac->szFile);
+ AddAvatarExt(PA_FORMAT_JPEG, ai.filename);
+
+ FreeCookie(pSnacHeader->dwRef);
+ unpackByte(&pBuffer, &len);
+ if (wBufferLength < ((ac->hashlen)<<1)+4+len)
+ {
+ NetLog_Server("Received invalid avatar reply.");
+
+ ICQBroadcastAck(ac->hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, (HANDLE)&ai, 0);
+
+ SAFE_FREE(&ac->szFile);
+ SAFE_FREE(&ac->hash);
+ SAFE_FREE(&ac);
+
+ break;
+ }
+
+ pBuffer += len;
+ pBuffer += (ac->hashlen<<1) + 1;
+ unpackWord(&pBuffer, &datalen);
+
+ wBufferLength -= 4 + len + (ac->hashlen<<1);
+ if (datalen > wBufferLength)
+ {
+ datalen = wBufferLength;
+ NetLog_Server("Avatar reply broken, trying to do my best.");
+ }
+
+ if (datalen > 4)
+ { // store to file...
+ int dwPaFormat;
+
+ NetLog_Server("Received user avatar, storing (%d bytes).", datalen);
+
+ dwPaFormat = DetectAvatarFormatBuffer(pBuffer);
+ ICQWriteContactSettingByte(ac->hContact, "AvatarType", (BYTE)dwPaFormat);
+ ai.format = dwPaFormat; // set the format
+ AddAvatarExt(dwPaFormat, szMyFile);
+ strcpy(ai.filename, szMyFile);
+
+ out = _open(szMyFile, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE);
+ if (out)
+ {
+ DBVARIANT dbv;
+
+ _write(out, pBuffer, datalen);
+ _close(out);
+
+ if (dwPaFormat != PA_FORMAT_XML && dwPaFormat != PA_FORMAT_UNKNOWN)
+ LinkContactPhotoToFile(ac->hContact, szMyFile); // this should not be here, but no other simple solution available
+
+ if (!ac->hContact) // our avatar, set filename
+ storeMyAvatarFileName(szMyFile);
+ else
+ { // contact's avatar set hash
+ if (!ICQGetContactSetting(ac->hContact, "AvatarHash", &dbv))
+ {
+ if (ICQWriteContactSettingBlob(ac->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 (ICQWriteContactSettingBlob(ac->hContact, "AvatarSaved", ac->hash, ac->hashlen) ||
+ ICQWriteContactSettingBlob(ac->hContact, "AvatarHash", ac->hash, ac->hashlen))
+ {
+ NetLog_Server("Failed to save avatar hash to DB");
+ }
+ }
+ }
+
+ ICQBroadcastAck(ac->hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, (HANDLE)&ai, 0);
+ }
+ }
+ else
+ { // the avatar is empty
+ NetLog_Server("Received empty avatar, nothing written.", datalen);
+
+ ICQBroadcastAck(ac->hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, (HANDLE)&ai, 0);
+ }
+ SAFE_FREE(&ac->szFile);
+ SAFE_FREE(&ac->hash);
+ SAFE_FREE(&ac);
+ }
+ 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))
+ {
+ avatarcookie* ac;
+ if (FindCookie(pSnacHeader->dwRef, NULL, &ac))
+ {
+ // here we store the local hash
+ 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);
+ icq_LogMessage(LOG_WARNING, "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;
+ avatarcookie *ack;
+
+ if (FindCookie(pSnacHeader->dwRef, NULL, &ack))
+ {
+ if (ack->dwUin)
+ {
+ NetLog_Server("Error: Avatar request failed");
+ SAFE_FREE(&ack->szFile);
+ SAFE_FREE(&ack->hash);
+ }
+ else
+ {
+ NetLog_Server("Error: Avatar upload failed");
+ }
+ ReleaseCookie(pSnacHeader->dwRef);
+ }
+
+ if (wBufferLength >= 2)
+ unpackWord(&pBuffer, &wError);
+ else
+ wError = 0;
+
+ 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/miranda-wine/protocols/IcqOscarJ/icq_avatar.h b/miranda-wine/protocols/IcqOscarJ/icq_avatar.h
new file mode 100644
index 0000000..e974ce6
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_avatar.h
@@ -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 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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_avatar.h,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#ifndef __ICQ_AVATAR_H
+#define __ICQ_AVATAR_H
+
+extern BOOL AvatarsReady;
+
+void handleAvatarContactHash(DWORD dwUIN, char* szUID, HANDLE hContact, unsigned char* pHash, unsigned int nHashLen, WORD wOldStatus);
+
+char* loadMyAvatarFileName();
+void storeMyAvatarFileName(char* szFile);
+
+void GetFullAvatarFileName(int dwUin, char* szUid, int dwFormat, char* pszDest, int cbLen);
+void GetAvatarFileName(int dwUin, char* szUid, char* pszDest, int cbLen);
+void AddAvatarExt(int dwFormat, char* pszDest);
+
+int DetectAvatarFormat(char* szFile);
+
+int IsAvatarSaved(HANDLE hContact, char* pHash);
+
+int GetAvatarData(HANDLE hContact, DWORD dwUin, char* szUid, char* hash, unsigned int hashlen, char* file);
+int SetAvatarData(HANDLE hContact, WORD wRef, char* data, unsigned int datalen);
+
+void StartAvatarThread(HANDLE hConn, char* cookie, WORD cookieLen);
+void StopAvatarThread();
+
+
+#endif /* __ICQ_AVATAR_H */
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_clients.c b/miranda-wine/protocols/IcqOscarJ/icq_clients.c
new file mode 100644
index 0000000..8f8cf80
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_clients.c
@@ -0,0 +1,665 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_clients.c,v $
+// Revision : $Revision: 3663 $
+// Last change on : $Date: 2006-08-31 00:18:59 +0400 (Чтв, 31 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Provides capability & signature based client detection
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+capstr* MatchCap(char* buf, int bufsize, const capstr* cap, int capsize)
+{
+ while (bufsize>0) // search the buffer for a capability
+ {
+ if (!memcmp(buf, cap, capsize))
+ {
+ return (capstr*)buf; // give found capability for version info
+ }
+ else
+ {
+ buf += 0x10;
+ bufsize -= 0x10;
+ }
+ }
+ return 0;
+}
+
+
+
+static void 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);
+}
+
+
+
+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, char* szPlug, int v, int m)
+{
+ if (!v) // this is not Miranda
+ return NULL;
+ else
+ {
+ 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, " ");
+ }
+ strcat(szStr, "(");
+ strcat(szStr, szPlug);
+ strcat(szStr, " v");
+ verToStr(szStr, v);
+ strcat(szStr, ")");
+ }
+ }
+
+ return szStr;
+}
+
+
+
+char* MirandaVersionToString(char* szStr, int v, int m)
+{
+ return MirandaVersionToStringEx(szStr, "ICQ", v, m);
+}
+
+
+const capstr capMirandaIm = {'M', 'i', 'r', 'a', 'n', 'd', 'a', 'M', 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 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 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 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 capQip = {0x56, 0x3F, 0xC8, 0x09, 0x0B, 0x6F, 0x41, 'Q', 'I', 'P', ' ', '2', '0', '0', '5', 'a'};
+const capstr capIm2 = {0x74, 0xED, 0xC3, 0x36, 0x44, 0xDF, 0x48, 0x5B, 0x8B, 0x1C, 0x67, 0x1A, 0x1F, 0x86, 0x09, 0x9F}; // IM2 Ext Msg
+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 capstr capAimIcon = {0x09, 0x46, 0x13, 0x46, 0x4c, 0x7f, 0x11, 0xd1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}; // CAP_AIM_BUDDYICON
+const capstr capAimDirect = {0x09, 0x46, 0x13, 0x45, 0x4c, 0x7f, 0x11, 0xd1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}; // CAP_AIM_DIRECTIM
+const capstr capIsIcq = {0x09, 0x46, 0x13, 0x44, 0x4c, 0x7f, 0x11, 0xd1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00};
+const capstr capIcqLite = {0x17, 0x8C, 0x2D, 0x9B, 0xDA, 0xA5, 0x45, 0xBB, 0x8D, 0xDB, 0xF3, 0xBD, 0xBD, 0x53, 0xA1, 0x0A};
+const capstr capAimChat = {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};
+
+
+char* cliLibicq2k = "libicq2000";
+char* cliLicqVer = "Licq ";
+char* cliCentericq = "Centericq";
+char* cliLibicqUTF = "libicq2000 (Unicode)";
+char* cliTrillian = "Trillian";
+char* cliQip = "QIP 200%c%c";
+char* cliIM2 = "IM2";
+char* cliSpamBot = "Spam Bot";
+
+
+char* detectUserClient(HANDLE hContact, DWORD dwUin, WORD wVersion, DWORD dwFT1, DWORD dwFT2, DWORD dwFT3, DWORD dwOnlineSince, DWORD dwDirectCookie, DWORD dwWebPort, BYTE* caps, WORD wLen, BYTE* bClientId, char* szClientBuf)
+{
+ LPSTR szClient = NULL;
+
+ *bClientId = 1; // 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, dwFT2, 0);
+ *bClientId = 2;
+ }
+ }
+ else if ((dwFT1 & 0xFF7F0000) == 0x7D000000)
+ { // This is probably an Licq client
+ DWORD ver = dwFT1 & 0xFFFF;
+
+ makeClientVersion(szClientBuf, cliLicqVer, ver / 1000, (ver / 10) % 100, ver % 10, 0);
+ if (dwFT1 & 0x00800000)
+ strcat(szClientBuf, "/SSL");
+
+ szClient = szClientBuf;
+ }
+ 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;
+
+ makeClientVersion(szClientBuf, "Alicq ", ver1, ver2, ver3, 0);
+
+ szClient = szClientBuf;
+ }
+ 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 == 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;
+ }
+
+ { // capabilities based detection
+ capstr* capId;
+
+ if (dwUin && caps)
+ {
+ // check capabilities for client identification
+ if (capId = MatchCap(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, iver, mver);
+
+ *bClientId = 2;
+ }
+ else if (MatchCap(caps, wLen, &capTrillian, 0x10) || MatchCap(caps, wLen, &capTrilCrypt, 0x10))
+ { // this is Trillian, check for new version
+ if (CheckContactCapabilities(hContact, CAPF_RTF))
+ szClient = "Trillian v3";
+ else
+ szClient = cliTrillian;
+ }
+ else if ((capId = MatchCap(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
+ {
+ null_snprintf(szClientBuf, 64, "SIM %u.%u", (unsigned)hiVer, loVer);
+ szClient = szClientBuf;
+ }
+ }
+ else if (capId = MatchCap(caps, wLen, &capSim, 0xC))
+ {
+ unsigned ver1 = (*capId)[0xC];
+ unsigned ver2 = (*capId)[0xD];
+ unsigned ver3 = (*capId)[0xE];
+
+ makeClientVersion(szClientBuf, "SIM ", ver1, ver2, ver3, 0);
+ if ((*capId)[0xF] & 0x80)
+ strcat(szClientBuf,"/Win32");
+ else if ((*capId)[0xF] & 0x40)
+ strcat(szClientBuf,"/MacOS X");
+
+ szClient = szClientBuf;
+ }
+ else if (capId = MatchCap(caps, wLen, &capLicq, 0xC))
+ {
+ unsigned ver1 = (*capId)[0xC];
+ unsigned ver2 = (*capId)[0xD] % 100;
+ unsigned ver3 = (*capId)[0xE];
+
+ makeClientVersion(szClientBuf, cliLicqVer, ver1, ver2, ver3, 0);
+ if ((*capId)[0xF])
+ strcat(szClientBuf,"/SSL");
+
+ szClient = szClientBuf;
+ }
+ else if (capId = MatchCap(caps, wLen, &capKopete, 0xC))
+ {
+ unsigned ver1 = (*capId)[0xC];
+ unsigned ver2 = (*capId)[0xD];
+ unsigned ver3 = (*capId)[0xE];
+ unsigned ver4 = (*capId)[0xF];
+
+ makeClientVersion(szClientBuf, "Kopete ", ver1, ver2, ver3, ver4);
+
+ szClient = szClientBuf;
+ }
+ else if (capId = MatchCap(caps, wLen, &capmIcq, 0xC))
+ {
+ unsigned ver1 = (*capId)[0xC];
+ unsigned ver2 = (*capId)[0xD];
+ unsigned ver3 = (*capId)[0xE];
+ unsigned ver4 = (*capId)[0xF];
+
+ makeClientVersion(szClientBuf, "mICQ ", ver1, ver2, ver3, ver4);
+
+ szClient = szClientBuf;
+ }
+ else if (MatchCap(caps, wLen, &capIm2, 0x10))
+ { // IM2 v2 provides also Aim Icon cap
+ szClient = cliIM2;
+ }
+ else if (capId = MatchCap(caps, wLen, &capAndRQ, 9))
+ {
+ unsigned ver1 = (*capId)[0xC];
+ unsigned ver2 = (*capId)[0xB];
+ unsigned ver3 = (*capId)[0xA];
+ unsigned ver4 = (*capId)[9];
+
+ makeClientVersion(szClientBuf, "&RQ ", ver1, ver2, ver3, ver4);
+
+ szClient = szClientBuf;
+ }
+ else if (capId = MatchCap(caps, wLen, &capRAndQ, 9))
+ {
+ unsigned ver1 = (*capId)[0xC];
+ unsigned ver2 = (*capId)[0xB];
+ unsigned ver3 = (*capId)[0xA];
+ unsigned ver4 = (*capId)[9];
+
+ makeClientVersion(szClientBuf, "R&Q ", ver1, ver2, ver3, ver4);
+
+ szClient = szClientBuf;
+ }
+ else if (capId = MatchCap(caps, wLen, &capQip, 0xE))
+ {
+ char v1 = (*capId)[0xE];
+ char v2 = (*capId)[0xF];
+
+ null_snprintf(szClientBuf, 64, cliQip, v1, v2);
+ szClient = szClientBuf;
+ }
+ else if (capId = MatchCap(caps, wLen, &capmChat, 0xA))
+ {
+ strcpy(szClientBuf, "mChat ");
+ strncat(szClientBuf, (*capId) + 0xA, 6);
+ szClient = szClientBuf;
+ }
+ else if (capId = MatchCap(caps, wLen, &capJimm, 5))
+ {
+ strcpy(szClientBuf, "Jimm ");
+ strncat(szClientBuf, (*capId) + 5, 11);
+ szClient = szClientBuf;
+ }
+ else if (MatchCap(caps, wLen, &capMacIcq, 0x10))
+ {
+ szClient = "ICQ for Mac";
+ }
+ else if (MatchCap(caps, wLen, &capUim, 0x10))
+ {
+ szClient = "uIM";
+ }
+ 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 && (MatchCap(caps, wLen, &capComm20012, 0x10) || CheckContactCapabilities(hContact, CAPF_SRV_RELAY)))
+ { // try to determine 2001-2003 versions
+ if (MatchCap(caps, wLen, &capIs2001, 0x10))
+ {
+ if (!dwFT1 && !dwFT2 && !dwFT3)
+ if (CheckContactCapabilities(hContact, CAPF_RTF))
+ szClient = "TICQClient"; // possibly also older GnomeICU
+ else
+ szClient = "ICQ for Pocket PC";
+ else
+ {
+ *bClientId = 0;
+ szClient = "ICQ 2001";
+ }
+ }
+ else if (MatchCap(caps, wLen, &capIs2002, 0x10))
+ {
+ *bClientId = 0;
+ 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 = 0;
+ szClient = "ICQ 2002/2003a";
+ }
+ }
+ else if (CheckContactCapabilities(hContact, CAPF_SRV_RELAY | CAPF_UTF | CAPF_TYPING))
+ {
+ if (!dwFT1 && !dwFT2 && !dwFT3)
+ {
+ szClient = "PreludeICQ";
+ }
+ }
+ }
+ else if (wVersion == 9)
+ { // try to determine lite versions
+ if (CheckContactCapabilities(hContact, CAPF_XTRAZ))
+ {
+ *bClientId = 0;
+ if (CheckContactCapabilities(hContact, CAPF_AIM_FILE))
+ {
+ if (MatchCap(caps, wLen, &captZers, 0x10))
+ { // capable of tZers ?
+ strcpy(szClientBuf, "icq5.1");
+ }
+ else
+ {
+ strcpy(szClientBuf, "icq5");
+ }
+ if (MatchCap(caps, wLen, &capRambler, 0x10))
+ {
+ strcat(szClientBuf, " (Rambler)");
+ }
+ else if (MatchCap(caps, wLen, &capAbv, 0x10))
+ {
+ strcat(szClientBuf, " (Abv)");
+ }
+ else if (MatchCap(caps, wLen, &capNetvigator, 0x10))
+ {
+ strcat(szClientBuf, " (Netvigator)");
+ }
+ szClient = szClientBuf;
+ }
+ else if (!MatchCap(caps, wLen, &capIsIcq, 0x10))
+ szClient = "pyICQ";
+ else
+ szClient = "ICQ Lite v4";
+ }
+ }
+ 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 = 0;
+ szClient = "ICQ 2000";
+ }
+ }
+ else if (CheckContactCapabilities(hContact, CAPF_TYPING))
+ szClient = "Icq2Go! (Java)";
+ 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 == 0)
+ { // capability footprint based detection - not really reliable
+ if (!dwFT1 && !dwFT2 && !dwFT3 && !dwWebPort && !dwDirectCookie)
+ { // DC info is empty
+ if (CheckContactCapabilities(hContact, CAPF_TYPING) && MatchCap(caps, wLen, &capIs2001, 0x10) &&
+ MatchCap(caps, wLen, &capIs2002, 0x10) && MatchCap(caps, wLen, &capComm20012, 0x10))
+ szClient = cliSpamBot;
+ else if (MatchCap(caps, wLen, &capAimIcon, 0x10) && MatchCap(caps, wLen, &capAimDirect, 0x10) &&
+ CheckContactCapabilities(hContact, CAPF_AIM_FILE | CAPF_UTF))
+ { // detect libgaim
+ if (CheckContactCapabilities(hContact, CAPF_SRV_RELAY))
+ szClient = "Adium X"; // yeah, AFAIK only Adium has this fixed
+ else
+ szClient = "libgaim";
+ }
+ else if (MatchCap(caps, wLen, &capAimIcon, 0x10) && MatchCap(caps, wLen, &capAimDirect, 0x10) &&
+ MatchCap(caps, wLen, &capAimChat, 0x10) && CheckContactCapabilities(hContact, CAPF_AIM_FILE) && wLen == 0x40)
+ szClient = "libgaim"; // Gaim 1.5.1 most probably
+ else if (MatchCap(caps, wLen, &capAimChat, 0x10) && CheckContactCapabilities(hContact, CAPF_AIM_FILE) && wLen == 0x20)
+ szClient = "Easy Message";
+ else if (MatchCap(caps, wLen, &capAimIcon, 0x10) && CheckContactCapabilities(hContact, CAPF_UTF) && wLen == 0x20)
+ szClient = "Meebo";
+ else if (MatchCap(caps, wLen, &capAimIcon, 0x10) && MatchCap(caps, wLen, &capIcqLite, 0x10) && CheckContactCapabilities(hContact, CAPF_UTF | CAPF_XTRAZ))
+ szClient = "PyICQ-t Jabber Transport";
+ else if (MatchCap(caps, wLen, &capIsIcq, 0x10) && CheckContactCapabilities(hContact, CAPF_UTF | CAPF_SRV_RELAY | CAPF_TYPING) && wLen == 0x40)
+ szClient = "Agile Messenger"; // Smartphone 2002
+ }
+ }
+ }
+ }
+ else if (!dwUin)
+ { // detect AIM clients
+ if (caps)
+ {
+ if (capId = MatchCap(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, "AimOscar", aver, mver);
+ }
+ else if (capId = MatchCap(caps, wLen, &capSim, 0xC))
+ { // Sim is universal
+ unsigned ver1 = (*capId)[0xC];
+ unsigned ver2 = (*capId)[0xD];
+ unsigned ver3 = (*capId)[0xE];
+
+ makeClientVersion(szClientBuf, "SIM ", ver1, ver2, ver3, 0);
+ if ((*capId)[0xF] & 0x80)
+ strcat(szClientBuf,"/Win32");
+ else if ((*capId)[0xF] & 0x40)
+ strcat(szClientBuf,"/MacOS X");
+
+ szClient = szClientBuf;
+ }
+ else if (capId = MatchCap(caps, wLen, &capKopete, 0xC))
+ {
+ unsigned ver1 = (*capId)[0xC];
+ unsigned ver2 = (*capId)[0xD];
+ unsigned ver3 = (*capId)[0xE];
+ unsigned ver4 = (*capId)[0xF];
+
+ makeClientVersion(szClientBuf, "Kopete ", ver1, ver2, ver3, ver4);
+
+ szClient = szClientBuf;
+ }
+ else if (MatchCap(caps, wLen, &capIm2, 0x10))
+ { // IM2 extensions
+ szClient = cliIM2;
+ }
+ else
+ szClient = "AIM";
+ }
+ else
+ szClient = "AIM";
+ }
+ }
+
+ if (!szClient)
+ {
+ NetLog_Server("No client identification, put default ICQ client for protocol.");
+
+ *bClientId = 0;
+
+ 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";
+ }
+ }
+ else
+ {
+ NetLog_Server("Client identified as %s", szClient);
+ }
+
+ if (szClient)
+ {
+ char* szExtra = NULL;
+
+ if (MatchCap(caps, wLen, &capSimpLite, 0x10))
+ szExtra = " + SimpLite";
+ else if (MatchCap(caps, wLen, &capSimpPro, 0x10))
+ szExtra = " + SimpPro";
+
+ if (szExtra)
+ {
+ if (szClient != szClientBuf)
+ {
+ strcpy(szClientBuf, szClient);
+ szClient = szClientBuf;
+ }
+ strcat(szClient, szExtra);
+ }
+ }
+ return szClient;
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_constants.h b/miranda-wine/protocols/IcqOscarJ/icq_constants.h
new file mode 100644
index 0000000..3704284
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_constants.h
@@ -0,0 +1,552 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_constants.h,v $
+// Revision : $Revision: 3663 $
+// Last change on : $Date: 2006-08-31 00:18:59 +0400 (Чтв, 31 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// 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
+
+
+
+/* Some default settings */
+#define DEFAULT_SERVER_PORT 5190
+#define DEFAULT_SERVER_HOST "login.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_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_CAPS 0
+#define DEFAULT_AVATARS_ENABLED 1
+#define DEFAULT_LOAD_AVATARS 1
+#define DEFAULT_LINK_AVATARS 1
+#define DEFAULT_XSTATUS_ENABLED 1
+#define DEFAULT_XSTATUS_AUTO 1
+#define DEFAULT_XSTATUS_RESET 0
+#define DEFAULT_KILLSPAM_ENABLED 1
+
+#define DEFAULT_SLOWSEND 1
+#define DEFAULT_ONLYSERVERACKS 0
+
+#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
+
+// Database setting names
+#define DBSETTING_CAPABILITIES "caps"
+#define DBSETTING_XSTATUSID "XStatusId"
+#define DBSETTING_XSTATUSNAME "XStatusName"
+#define DBSETTING_XSTATUSMSG "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
+
+
+
+// Ascii Capability IDs
+#define CAP_RTFMSGS "{97B12751-243C-4334-AD22-D6ABF73F1492}"
+#define CAP_UTF8MSGS "{0946134E-4C7F-11D1-8222-444553540000}"
+
+// Binary Capability IDs
+#define BINARY_CAP_SIZE 16
+#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_TYPING 0x56, 0x3f, 0xc8, 0x09, 0x0b, 0x6f, 0x41, 0xbd, 0x9f, 0x79, 0x42, 0x26, 0x09, 0xdf, 0xa2, 0xf3
+#define CAP_XTRAZ 0x1A, 0x09, 0x3C, 0x6C, 0xD7, 0xFD, 0x4E, 0xC5, 0x9D, 0x51, 0xA6, 0x47, 0x4E, 0x34, 0xF5, 0xA0
+#define CAP_AIM_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_TYPING 0x00000008
+#define CAPF_XTRAZ 0x00000010
+#define CAPF_AIM_FILE 0x00000040
+
+
+// Message Capability IDs
+#define MCAP_TLV2711_FMT_s 0x09461349, 0x4c7f11d1, 0x82224445, 0x53540000
+#define MCAP_REVERSE_REQ_s 0x09461344, 0x4c7f11d1, 0x82224445, 0x53540000
+#define MCAP_OSCAR_FT_s 0x09461343, 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_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_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_XTRAZ_SCRIPT_s 0x3b60b3ef, 0xd82a6c45, 0xa4e09c5a, 0x5e67e865
+
+// Message Plugin Sub-Type IDs
+#define MGTYPE_STANDARD_SEND 0x00
+#define MGTYPE_CONTACTS_REQUEST 0x02
+#define MGTYPE_SCRIPT_INVITATION 0x01
+#define MGTYPE_SCRIPT_DATA 0x02
+#define MGTYPE_SCRIPT_USER_REMOVE 0x04
+#define MGTYPE_SCRIPT_NOTIFY 0x08
+
+
+
+/* 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_AVATAR_FAMILY 0x0010
+#define ICQ_LISTS_FAMILY 0x0013
+#define ICQ_EXTENSIONS_FAMILY 0x0015
+#define ICQ_AUTHORIZATION_FAMILY 0x0017
+
+/* 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
+
+/* Subtypes for Buddy Family 0x0003 */
+#define ICQ_USER_CLI_REQBUDDY 0x0002
+#define ICQ_USER_SRV_REPLYBUDDY 0x0003
+#define ICQ_USER_ADDTOLIST 0x0004
+#define ICQ_USER_REMOVEFROMLIST 0x0005
+#define ICQ_USER_NOTIFY_REJECTED 0x000a
+#define ICQ_USER_ONLINE 0x000b
+#define ICQ_USER_OFFLINE 0x000c
+
+/* 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_MTN 0x0014
+
+/* 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_REQ 0x0002
+#define ICQ_META_SRV_REPLY 0x0003
+
+/* 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
+
+// Reply types for SNAC 15/02 & 15/03
+#define CLI_OFFLINE_MESSAGE_REQ 0x003C
+#define CLI_DELETE_OFFLINE_MSGS_REQ 0x003E
+#define SRV_OFFLINE_MESSAGE 0x0041
+#define SRV_END_OF_OFFLINE_MSGS 0x0042
+#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_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
+
+// 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_UNKNOWN1 0x0009 // Unknown. 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: from "0" and incrementing by one)
+
+#define SSI_TLV_AWAITING_AUTH 0x0066 // Contact not authorised in list
+#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_EMAIL 0x0137 // Custom contact email
+#define SSI_TLV_PHONE 0x013A // Custom contact SMS number
+#define SSI_TLV_COMMENT 0x013C // User comment
+
+
+
+// Internal Constants
+#define ICQ_PLUG_VERSION 0x80030801
+#define ICQ_VERSION 8
+#define DC_TYPE DC_NORMAL // Used for DC settings
+#define MAX_NICK_SIZE 32
+#define MAX_CONTACTSSEND 15
+#define MAX_MESSAGESNACSIZE 8000
+#define CLIENTRATELIMIT 0
+#define UPDATE_THRESHOLD 1209600 // Two weeks
+#define COOKIE_TIMEOUT 3600 // One hour
+#define WEBFRONTPORT 0x50
+#define CLIENTFEATURES 0x3
+#define URL_FORGOT_PASSWORD "https://www.icq.com/password/"
+#define URL_REGISTER "http://lite.icq.com/register"
+#define FLAP_MARKER 0x2a
+#define CLIENT_ID_STRING "ICQBasic"
+#define CLIENT_MD5_STRING "AOL Instant Messenger (SM)"
+#define UNIQUEIDSETTING "UIN"
+#define UINMAXLEN 11 // DWORD string max len + 1
+
+#endif /* __ICQ_CONSTANTS_H */
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_db.c b/miranda-wine/protocols/IcqOscarJ/icq_db.c
new file mode 100644
index 0000000..2340f0b
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_db.c
@@ -0,0 +1,350 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_db.c,v $
+// Revision : $Revision: 3709 $
+// Last change on : $Date: 2006-09-06 02:09:00 +0400 (Срд, 06 Сен 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Internal Database API
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+static BOOL bUtfReadyDB = FALSE;
+
+void InitDB()
+{
+ bUtfReadyDB = ServiceExists(MS_DB_CONTACT_GETSETTING_STR);
+ if (!bUtfReadyDB)
+ NetLog_Server("Warning: DB module does not support Unicode.");
+}
+
+
+
+void ICQCreateResidentSetting(const char* szSetting)
+{
+ char pszSetting[2*MAX_PATH];
+
+ strcpy(pszSetting, gpszICQProtoName);
+ strcat(pszSetting, "/");
+ strcat(pszSetting, szSetting);
+ CallService(MS_DB_SETSETTINGRESIDENT, 1, (WPARAM)pszSetting);
+}
+
+
+
+BYTE ICQGetContactSettingByte(HANDLE hContact, const char* szSetting, BYTE bDef)
+{
+ return DBGetContactSettingByte(hContact, gpszICQProtoName, szSetting, bDef);
+}
+
+
+
+WORD ICQGetContactSettingWord(HANDLE hContact, const char* szSetting, WORD wDef)
+{
+ return DBGetContactSettingWord(hContact, gpszICQProtoName, szSetting, wDef);
+}
+
+
+
+DWORD ICQGetContactSettingDword(HANDLE hContact, const char* szSetting, DWORD dwDef)
+{
+ DBVARIANT dbv;
+ DBCONTACTGETSETTING cgs;
+ DWORD dwRes;
+
+ cgs.szModule = gpszICQProtoName;
+ cgs.szSetting = szSetting;
+ cgs.pValue = &dbv;
+ if (CallService(MS_DB_CONTACT_GETSETTING,(WPARAM)hContact,(LPARAM)&cgs))
+ 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;
+}
+
+
+
+DWORD ICQGetContactSettingUIN(HANDLE hContact)
+{
+ return ICQGetContactSettingDword(hContact, UNIQUEIDSETTING, 0);
+}
+
+
+
+int ICQGetContactSettingUID(HANDLE hContact, DWORD *pdwUin, uid_str* ppszUid)
+{
+ DBVARIANT dbv;
+ int iRes = 1;
+
+ *pdwUin = 0;
+ if (ppszUid) *ppszUid[0] = '\0';
+
+ if (!ICQGetContactSetting(hContact, UNIQUEIDSETTING, &dbv))
+ {
+ if (dbv.type == DBVT_DWORD)
+ {
+ *pdwUin = dbv.dVal;
+ iRes = 0;
+ }
+ else if (dbv.type == DBVT_ASCIIZ)
+ {
+ if (ppszUid && gbAimEnabled)
+ {
+ strcpy(*ppszUid, dbv.pszVal);
+ iRes = 0;
+ }
+ else
+ NetLog_Server("AOL screennames not accepted");
+ }
+ ICQFreeVariant(&dbv);
+ }
+ return iRes;
+}
+
+
+
+int ICQGetContactSetting(HANDLE hContact, const char* szSetting, DBVARIANT *dbv)
+{
+ return DBGetContactSetting(hContact, gpszICQProtoName, szSetting, dbv);
+}
+
+
+
+char* UniGetContactSettingUtf(HANDLE hContact, const char *szModule,const char* szSetting, char* szDef)
+{
+ DBVARIANT dbv = {DBVT_DELETED};
+ char* szRes;
+
+ if (bUtfReadyDB)
+ {
+ if (DBGetContactSettingStringUtf(hContact, szModule, szSetting, &dbv))
+ return null_strdup(szDef);
+
+ szRes = null_strdup(dbv.pszVal);
+ ICQFreeVariant(&dbv);
+ }
+ else
+ { // old DB, we need to convert the string to UTF-8
+ if (DBGetContactSetting(hContact, szModule, szSetting, &dbv))
+ return null_strdup(szDef);
+
+ szRes = ansi_to_utf8(dbv.pszVal);
+
+ ICQFreeVariant(&dbv);
+ }
+ return szRes;
+}
+
+
+
+char* ICQGetContactSettingUtf(HANDLE hContact, const char* szSetting, char* szDef)
+{
+ return UniGetContactSettingUtf(hContact, gpszICQProtoName, szSetting, szDef);
+}
+
+
+
+WORD ICQGetContactStatus(HANDLE hContact)
+{
+ return ICQGetContactSettingWord(hContact, "Status", ID_STATUS_OFFLINE);
+}
+
+
+
+// (c) by George Hazan
+int ICQGetContactStaticString(HANDLE hContact, const char* valueName, char* dest, int dest_len)
+{
+ DBVARIANT dbv;
+ DBCONTACTGETSETTING sVal;
+
+ dbv.pszVal = dest;
+ dbv.cchVal = dest_len;
+ dbv.type = DBVT_ASCIIZ;
+
+ sVal.pValue = &dbv;
+ sVal.szModule = gpszICQProtoName;
+ sVal.szSetting = valueName;
+
+ if (CallService(MS_DB_CONTACT_GETSETTINGSTATIC, (WPARAM)hContact, (LPARAM)&sVal) != 0)
+ {
+ dbv.pszVal = dest;
+ dbv.cchVal = dest_len;
+ dbv.type = DBVT_UTF8;
+
+ if (CallService(MS_DB_CONTACT_GETSETTINGSTATIC, (WPARAM)hContact, (LPARAM)&sVal) != 0)
+ return 1; // this is here due to DB module bug...
+ }
+
+ return (dbv.type != DBVT_ASCIIZ);
+}
+
+
+
+int ICQDeleteContactSetting(HANDLE hContact, const char* szSetting)
+{
+ return DBDeleteContactSetting(hContact, gpszICQProtoName, szSetting);
+}
+
+
+
+int ICQWriteContactSettingByte(HANDLE hContact, const char* szSetting, BYTE bValue)
+{
+ return DBWriteContactSettingByte(hContact, gpszICQProtoName, szSetting, bValue);
+}
+
+
+
+int ICQWriteContactSettingWord(HANDLE hContact, const char* szSetting, WORD wValue)
+{
+ return DBWriteContactSettingWord(hContact, gpszICQProtoName, szSetting, wValue);
+}
+
+
+
+int ICQWriteContactSettingDword(HANDLE hContact, const char* szSetting, DWORD dwValue)
+{
+ return DBWriteContactSettingDword(hContact, gpszICQProtoName, szSetting, dwValue);
+}
+
+
+
+int ICQWriteContactSettingString(HANDLE hContact, const char* szSetting, char* szValue)
+{
+ return DBWriteContactSettingString(hContact, gpszICQProtoName, szSetting, szValue);
+}
+
+
+
+int UniWriteContactSettingUtf(HANDLE hContact, const char *szModule, const char* szSetting, char* szValue)
+{
+ if (bUtfReadyDB)
+ return DBWriteContactSettingStringUtf(hContact, szModule, szSetting, szValue);
+ else
+ { // old DB, we need to convert the string to Ansi
+ int size = strlennull(szValue) + 2;
+ char* szAnsi = (char*)_alloca(size);
+
+ if (utf8_decode_static(szValue, szAnsi, size))
+ return DBWriteContactSettingString(hContact, szModule, szSetting, szAnsi);
+ // failed to convert - give error
+
+ return 1;
+ }
+}
+
+
+
+int ICQWriteContactSettingUtf(HANDLE hContact, const char* szSetting, char* szValue)
+{
+ return UniWriteContactSettingUtf(hContact, gpszICQProtoName, szSetting, szValue);
+}
+
+
+
+int ICQWriteContactSettingBlob(HANDLE hContact,const char *szSetting,const char *val, const int cbVal)
+{
+ DBCONTACTWRITESETTING cws;
+
+ cws.szModule=gpszICQProtoName;
+ cws.szSetting=szSetting;
+ cws.value.type=DBVT_BLOB;
+ cws.value.pbVal=(char*)val;
+ cws.value.cpbVal = cbVal;
+ return CallService(MS_DB_CONTACT_WRITESETTING,(WPARAM)hContact,(LPARAM)&cws);
+}
+
+
+
+int ICQFreeVariant(DBVARIANT* dbv)
+{
+ return DBFreeVariant(dbv);
+}
+
+
+
+int IsICQContact(HANDLE hContact)
+{
+ char* szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+
+ return !strcmpnull(szProto, gpszICQProtoName);
+}
+
+
+
+HANDLE ICQAddEvent(HANDLE hContact, WORD wType, DWORD dwTime, DWORD flags, DWORD cbBlob, PBYTE pBlob)
+{
+ DBEVENTINFO dbei = {0};
+
+ dbei.cbSize = sizeof(dbei);
+ dbei.szModule = gpszICQProtoName;
+ 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 ICQFindFirstContact()
+{
+ HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+
+ if (IsICQContact(hContact))
+ {
+ return hContact;
+ }
+ return ICQFindNextContact(hContact);
+}
+
+
+
+HANDLE ICQFindNextContact(HANDLE hContact)
+{
+ hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0);
+
+ while (hContact != NULL)
+ {
+ if (IsICQContact(hContact))
+ {
+ return hContact;
+ }
+ hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0);
+ }
+ return hContact;
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_db.h b/miranda-wine/protocols/IcqOscarJ/icq_db.h
new file mode 100644
index 0000000..4f20ddd
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_db.h
@@ -0,0 +1,77 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_db.h,v $
+// Revision : $Revision: 3709 $
+// Last change on : $Date: 2006-09-06 02:09:00 +0400 (Срд, 06 Сен 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#ifndef __ICQ_DB_H
+#define __ICQ_DB_H
+
+void InitDB();
+
+void ICQCreateResidentSetting(const char* szSetting);
+
+BYTE ICQGetContactSettingByte(HANDLE hContact, const char* szSetting, BYTE bDef);
+WORD ICQGetContactSettingWord(HANDLE hContact, const char* szSetting, WORD wDef);
+DWORD ICQGetContactSettingDword(HANDLE hContact, const char* szSetting, DWORD dwDef);
+DWORD ICQGetContactSettingUIN(HANDLE hContact);
+int ICQGetContactSettingUID(HANDLE hContact, DWORD *pdwUin, uid_str* ppszUid);
+int ICQGetContactSetting(HANDLE hContact, const char* szSetting, DBVARIANT *dbv);
+char* ICQGetContactSettingUtf(HANDLE hContact, const char* szSetting, char* szDef);
+
+WORD ICQGetContactStatus(HANDLE hContact);
+
+int ICQGetContactStaticString(HANDLE hContact, const char* valueName, char* dest, int dest_len);
+
+int ICQDeleteContactSetting(HANDLE hContact, const char* szSetting);
+
+int ICQWriteContactSettingByte(HANDLE hContact, const char* szSetting, BYTE bValue);
+int ICQWriteContactSettingWord(HANDLE hContact, const char* szSetting, WORD wValue);
+int ICQWriteContactSettingDword(HANDLE hContact, const char* szSetting, DWORD dwValue);
+int ICQWriteContactSettingString(HANDLE hContact, const char* szSetting, char* szValue);
+int ICQWriteContactSettingUtf(HANDLE hContact, const char* szSetting, char* szValue);
+
+int ICQWriteContactSettingBlob(HANDLE hContact,const char *szSetting,const char *val, const int cbVal);
+
+char* UniGetContactSettingUtf(HANDLE hContact, const char *szModule,const char* szSetting, char* szDef);
+int UniWriteContactSettingUtf(HANDLE hContact, const char *szModule,const char* szSetting, char* szValue);
+
+int ICQFreeVariant(DBVARIANT* dbv);
+
+HANDLE ICQAddEvent(HANDLE hContact, WORD wType, DWORD dwTime, DWORD flags, DWORD cbBlob, PBYTE pBlob);
+
+int IsICQContact(HANDLE hContact);
+HANDLE ICQFindFirstContact();
+HANDLE ICQFindNextContact(HANDLE hContact);
+
+#endif /* __ICQ_DB_H */
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_direct.c b/miranda-wine/protocols/IcqOscarJ/icq_direct.c
new file mode 100644
index 0000000..1f505cc
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_direct.c
@@ -0,0 +1,1347 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_direct.c,v $
+// Revision : $Revision: 3663 $
+// Last change on : $Date: 2006-08-31 00:18:59 +0400 (Чтв, 31 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+
+typedef struct directthreadstartinfo_t
+{
+ 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
+} directthreadstartinfo;
+
+static unsigned char client_check_data[] = {
+ "As part of this software beta version Mirabilis is "
+ "granting a limited access to the ICQ network, "
+ "servers, directories, listings, information and databases (\""
+ "ICQ Services and Information\"). The "
+ "ICQ Service and Information may databases (\""
+ "ICQ Services and Information\"). The "
+ "ICQ Service and Information may\0"
+};
+
+static directconnect** directConnList = NULL;
+static int directConnSize = 0;
+static int directConnCount = 0;
+static int mutexesInited = 0;
+static CRITICAL_SECTION directConnListMutex;
+static CRITICAL_SECTION expectedFileRecvMutex;
+static int expectedFileRecvCount = 0;
+static filetransfer** expectedFileRecv = NULL;
+
+extern WORD wListenPort;
+extern DWORD dwLocalDirectConnCookie;
+
+static void handleDirectPacket(directconnect* dc, PBYTE buf, WORD wLen);
+static DWORD __stdcall icq_directThread(directthreadstartinfo* dtsi);
+static void sendPeerInit_v78(directconnect* dc);
+static int DecryptDirectPacket(directconnect* dc, PBYTE buf, WORD wLen);
+static void sendPeerInitAck(directconnect* dc);
+static void sendPeerMsgInit(directconnect* dc, DWORD dwSeq);
+static void sendPeerFileInit(directconnect* dc);
+
+
+
+void InitDirectConns(void)
+{
+ if (!mutexesInited)
+ {
+ mutexesInited = 1;
+ InitializeCriticalSection(&directConnListMutex);
+ InitializeCriticalSection(&expectedFileRecvMutex);
+ }
+ directConnCount = 0;
+ directConnSize = 0;
+}
+
+
+
+void UninitDirectConns(void)
+{
+ CloseContactDirectConns(NULL);
+
+ for(;;)
+ {
+ if (!directConnCount)
+ break;
+
+ Sleep(10); /* yeah, ugly */
+ }
+
+ DeleteCriticalSection(&directConnListMutex);
+ DeleteCriticalSection(&expectedFileRecvMutex);
+
+ SAFE_FREE((void**)&directConnList);
+}
+
+
+
+void CloseContactDirectConns(HANDLE hContact)
+{
+ int i;
+
+ EnterCriticalSection(&directConnListMutex);
+
+ for (i = 0; i < directConnCount; i++)
+ {
+ if (!hContact || directConnList[i]->hContact == hContact)
+ {
+ HANDLE hConnection = directConnList[i]->hConnection;
+ int sck = CallService(MS_NETLIB_GETSOCKET, (WPARAM)hConnection, 0);
+
+ directConnList[i]->hConnection = NULL; // do not allow reuse
+ if (sck!=INVALID_SOCKET) shutdown(sck, 2); // close gracefully
+ NetLib_SafeCloseHandle(&hConnection, FALSE);
+ }
+ }
+
+ LeaveCriticalSection(&directConnListMutex);
+}
+
+
+
+static void ResizeDirectList(int nSize)
+{
+ if ((directConnSize < nSize) || ((directConnSize > nSize + 6) && nSize))
+ {
+ if (directConnSize < nSize)
+ directConnSize += 4;
+ else
+ directConnSize -= 4;
+
+ directConnList = (directconnect**)realloc(directConnList, sizeof(directconnect*) * directConnSize);
+ }
+}
+
+
+
+static void AddDirectConnToList(directconnect* dc)
+{
+ EnterCriticalSection(&directConnListMutex);
+
+ ResizeDirectList(directConnCount + 1);
+ directConnList[directConnCount] = dc;
+ directConnCount++;
+
+ LeaveCriticalSection(&directConnListMutex);
+}
+
+
+
+static RemoveDirectConnFromList(directconnect* dc)
+{
+ int i;
+
+ EnterCriticalSection(&directConnListMutex);
+
+ for (i = 0; i < directConnCount; i++)
+ {
+ if (directConnList[i] == dc)
+ {
+ directConnCount--;
+ directConnList[i] = directConnList[directConnCount];
+ ResizeDirectList(directConnCount);
+ break;
+ }
+ }
+
+ LeaveCriticalSection(&directConnListMutex);
+}
+
+
+
+directconnect* FindFileTransferDC(filetransfer* ft)
+{
+ int i;
+ directconnect* dc = NULL;
+
+ EnterCriticalSection(&directConnListMutex);
+
+ for (i = 0; i < directConnCount; i++)
+ {
+ if (directConnList[i] && directConnList[i]->ft == ft)
+ {
+ dc = directConnList[i];
+ break;
+ }
+ }
+
+ LeaveCriticalSection(&directConnListMutex);
+ return dc;
+}
+
+
+
+void AddExpectedFileRecv(filetransfer* ft)
+{
+ EnterCriticalSection(&expectedFileRecvMutex);
+
+ expectedFileRecv = (filetransfer** )realloc(expectedFileRecv, sizeof(filetransfer *) * (expectedFileRecvCount + 1));
+ expectedFileRecv[expectedFileRecvCount++] = ft;
+
+ LeaveCriticalSection(&expectedFileRecvMutex);
+}
+
+
+
+filetransfer *FindExpectedFileRecv(DWORD dwUin, DWORD dwTotalSize)
+{
+ int i;
+ filetransfer* pFt = NULL;
+
+
+ EnterCriticalSection(&expectedFileRecvMutex);
+
+ for (i = 0; i < expectedFileRecvCount; i++)
+ {
+ if (expectedFileRecv[i]->dwUin == dwUin && expectedFileRecv[i]->dwTotalSize == dwTotalSize)
+ {
+ pFt = expectedFileRecv[i];
+ expectedFileRecvCount--;
+ memmove(expectedFileRecv + i, expectedFileRecv + i + 1, sizeof(filetransfer*) * (expectedFileRecvCount - i));
+ expectedFileRecv = (filetransfer**)realloc(expectedFileRecv, sizeof(filetransfer*) * expectedFileRecvCount);
+
+ // Filereceive found, exit loop
+ break;
+ }
+ }
+
+ LeaveCriticalSection(&expectedFileRecvMutex);
+
+ return pFt;
+}
+
+
+
+int sendDirectPacket(directconnect* dc, icq_packet* pkt)
+{
+ int nResult;
+
+ 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(&pkt->pData);
+
+ return nResult;
+}
+
+
+
+directthreadstartinfo* CreateDTSI(HANDLE hContact, HANDLE hConnection, int type)
+{
+ directthreadstartinfo* dtsi;
+
+ 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 IsDirectConnectionOpen(HANDLE hContact, int type)
+{
+ int i;
+ BOOL bIsOpen = FALSE, bIsCreated = FALSE;
+
+
+ EnterCriticalSection(&directConnListMutex);
+
+ for (i = 0; i < directConnCount; i++)
+ {
+ if (directConnList[i] && (directConnList[i]->type == type))
+ {
+ if (directConnList[i]->hContact == hContact)
+ if (directConnList[i]->initialised)
+ {
+ // Connection is OK
+ bIsOpen = TRUE;
+ // we are going to use the conn, so prevent timeout
+ directConnList[i]->packetPending = 1;
+ break;
+ }
+ else
+ bIsCreated = TRUE; // we found pending connection
+ }
+ }
+
+ LeaveCriticalSection(&directConnListMutex);
+
+ if (!bIsCreated && !bIsOpen && type == DIRECTCONN_STANDARD && gbDCMsgEnabled == 2)
+ { // do not try to open DC to offline contact
+ if (ICQGetContactStatus(hContact) == ID_STATUS_OFFLINE) return FALSE;
+
+ // 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)
+{
+ pthread_t tid;
+
+ // Start a new thread for the incomming connection
+ tid.hThread = (HANDLE)forkthreadex(NULL, 0, icq_directThread, CreateDTSI(NULL, hNewConnection, -1), 0, &tid.dwThreadId);
+ CloseHandle(tid.hThread);
+}
+
+
+
+// Opens direct connection of specified type to specified contact
+void OpenDirectConnection(HANDLE hContact, int type, void* pvExtra)
+{
+ pthread_t tid;
+ directthreadstartinfo* dtsi;
+
+ // Create a new connection
+ dtsi = CreateDTSI(hContact, NULL, type);
+ dtsi->pvExtra = pvExtra;
+
+ tid.hThread = (HANDLE)forkthreadex(NULL, 0, icq_directThread, dtsi, 0, &tid.dwThreadId);
+ CloseHandle(tid.hThread);
+}
+
+
+
+// Safely close NetLib connection - do not corrupt direct connection list
+void CloseDirectConnection(directconnect *dc)
+{
+ EnterCriticalSection(&directConnListMutex);
+
+ NetLib_SafeCloseHandle(&dc->hConnection, FALSE);
+#ifdef _DEBUG
+ if (dc->hConnection)
+ NetLog_Direct("Direct conn closed (%p)", dc->hConnection);
+#endif
+
+ LeaveCriticalSection(&directConnListMutex);
+}
+
+
+
+// This should be called only if connection already exists
+int SendDirectMessage(HANDLE hContact, icq_packet *pkt)
+{
+ int i;
+
+ EnterCriticalSection(&directConnListMutex);
+
+ for (i = 0; i < directConnCount; i++)
+ {
+ if (directConnList[i] == NULL)
+ continue;
+
+ if (directConnList[i]->hContact == hContact)
+ {
+ if (directConnList[i]->initialised)
+ {
+ // This connection can be reused, send packet and exit
+ NetLog_Direct("Sending direct message");
+
+ if (pkt->pData[2] == 2)
+ EncryptDirectPacket(directConnList[i], pkt);
+
+ sendDirectPacket(directConnList[i], pkt);
+ directConnList[i]->packetPending = 0; // packet done
+
+ LeaveCriticalSection(&directConnListMutex);
+
+ return TRUE; // Success
+ }
+ break; // connection not ready, use server instead
+ }
+ }
+
+ LeaveCriticalSection(&directConnListMutex);
+
+ return FALSE; // connection pending, we failed, use server instead
+}
+
+
+// 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
+static DWORD __stdcall icq_directThread(directthreadstartinfo *dtsi)
+{
+ directconnect dc = {0};
+ NETLIBPACKETRECVER packetRecv={0};
+ HANDLE hPacketRecver;
+ BOOL bFirstPacket = TRUE;
+ DWORD dwReqMsgID1;
+ DWORD dwReqMsgID2;
+
+
+ srand(time(NULL));
+ AddDirectConnToList(&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 = ICQGetContactSettingDword(dtsi->hContact, "IP", 0);
+ dc.dwRemoteInternalIP = ICQGetContactSettingDword(dtsi->hContact, "RealIP", 0);
+ dc.dwRemotePort = ICQGetContactSettingWord(dtsi->hContact, "UserPort", 0);
+ dc.dwRemoteUin = ICQGetContactSettingUIN(dtsi->hContact);
+ dc.wVersion = ICQGetContactSettingWord(dtsi->hContact, "Version", 0);
+ dc.dwConnCookie = ICQGetContactSettingDword(dtsi->hContact, "DirectCookie", 0);
+
+ if (!dc.dwRemoteExternalIP && !dc.dwRemoteInternalIP)
+ { // we do not have any ip, do not try to connect
+ RemoveDirectConnFromList(&dc);
+ SAFE_FREE(&dtsi);
+ return 0;
+ }
+
+ 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)
+ {
+ reverse_cookie *pCookie = (reverse_cookie*)dtsi->pvExtra;
+
+ dwReqMsgID1 = pCookie->pMessage.dwMsgID1;
+ dwReqMsgID2 = pCookie->pMessage.dwMsgID2;
+ dc.dwReqId = (DWORD)pCookie->ft;
+ SAFE_FREE(&pCookie);
+ }
+ }
+ else
+ {
+ dc.type = DIRECTCONN_STANDARD;
+ }
+
+ SAFE_FREE(&dtsi);
+
+ // Load local IP information
+ dc.dwLocalExternalIP = ICQGetContactSettingDword(NULL, "IP", 0);
+ dc.dwLocalInternalIP = ICQGetContactSettingDword(NULL, "RealIP", 0);
+
+ // Create outgoing DC
+ if (!dc.incoming)
+ {
+ NETLIBOPENCONNECTION nloc = {0};
+ IN_ADDR addr;
+
+
+ nloc.cbSize = sizeof(nloc);
+ nloc.flags = 0;
+ if (dc.dwRemoteExternalIP == dc.dwLocalExternalIP)
+ addr.S_un.S_addr = htonl(dc.dwRemoteInternalIP);
+ else
+ addr.S_un.S_addr = htonl(dc.dwRemoteExternalIP);
+
+ if (!addr.S_un.S_addr)
+ { // IP to connect to is empty, go away
+ RemoveDirectConnFromList(&dc);
+ return 0;
+ }
+ nloc.szHost = inet_ntoa(addr);
+ nloc.wPort = (WORD)dc.dwRemotePort;
+ NetLog_Direct("%sConnecting to %s:%u", dc.type==DIRECTCONN_REVERSE?"Reverse ":"", nloc.szHost, nloc.wPort);
+
+ dc.hConnection = NetLib_OpenConnection(ghDirectNetlibUser, &nloc);
+ if (dc.hConnection == NULL)
+ {
+ if (dc.type != DIRECTCONN_REVERSE)
+ { // try reverse connect
+ reverse_cookie *pCookie = (reverse_cookie*)SAFE_MALLOC(sizeof(reverse_cookie));
+ DWORD dwCookie;
+
+ NetLog_Direct("connect() failed (%d), trying reverse.", GetLastError());
+
+ if (pCookie)
+ { // ini cookie
+ pCookie->pMessage.bMessageType = MTYPE_REVERSE_REQUEST;
+ pCookie->pMessage.dwMsgID1 = time(NULL);
+ pCookie->pMessage.dwMsgID2 = RandRange(0, 0x00FF);
+ pCookie->hContact = dc.hContact;
+ pCookie->dwUin = dc.dwRemoteUin;
+ pCookie->type = dc.type;
+ pCookie->ft = dc.ft;
+ dwCookie = AllocateCookie(CKT_REVERSEDIRECT, 0, dc.dwRemoteUin, pCookie);
+ icq_sendReverseReq(&dc, dwCookie, (message_cookie_data*)pCookie);
+ RemoveDirectConnFromList(&dc);
+
+ return 0;
+ }
+ else
+ NetLog_Direct("Reverse failed (%s)", "malloc failed");
+ }
+ else // we failed reverse connection
+ { // announce we failed
+ icq_sendReverseFailed(&dc, dwReqMsgID1, dwReqMsgID2, dc.dwReqId);
+ }
+ NetLog_Direct("connect() failed (%d)", GetLastError());
+ RemoveDirectConnFromList(&dc);
+ if (dc.type == DIRECTCONN_FILE)
+ ICQBroadcastAck(dc.ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, dc.ft, 0);
+
+ return 0;
+ }
+
+ 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);
+ RemoveDirectConnFromList(&dc);
+
+ return 0;
+ }
+ }
+
+ 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
+ {
+ int i;
+
+ for (i = 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;
+ }
+
+ 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, FALSE);
+ CloseDirectConnection(&dc);
+
+ if (dc.ft)
+ {
+ if (dc.ft->fileId != -1)
+ {
+ _close(dc.ft->fileId);
+ ICQBroadcastAck(dc.ft->hContact, ACKTYPE_FILE, dc.ft->dwBytesDone==dc.ft->dwTotalSize ? ACKRESULT_SUCCESS : ACKRESULT_FAILED, dc.ft, 0);
+ }
+ else if (dc.ft->hConnection)
+ ICQBroadcastAck(dc.ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, dc.ft, 0);
+
+ SafeReleaseFileTransfer(&dc.ft);
+ _chdir("\\"); /* so we don't leave a subdir handle open so it can't be deleted */
+ }
+
+ RemoveDirectConnFromList(&dc);
+
+ return 0;
+}
+
+
+
+static void 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)
+ {
+ reverse_cookie* pCookie;
+ DWORD dwCookieUin;
+
+ dc->incoming = 0;
+
+ if (FindCookie(dc->dwReqId, &dwCookieUin, &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 = 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(&pCookie);
+ break;
+ }
+ else
+ {
+ SAFE_FREE(&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 != 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 (dwCookie != ICQGetContactSettingDword(hContact, "DirectCookie", 0))
+ {
+ 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)
+ reverse_cookie* pCookie;
+ DWORD dwCookieUin;
+
+ if (FindCookie(dc->dwReqId, &dwCookieUin, &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->dwConnCookie = dwCookie;
+ ICQWriteContactSettingDword(dc->hContact, "IP", dc->dwRemoteExternalIP);
+ ICQWriteContactSettingDword(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;
+ }
+ }
+ }
+ 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 (!gbDCMsgEnabled)
+ { // 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;
+}
+
+
+
+static 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 += wsprintf(pszBuf, "%08X: ", line);
+
+ for (col = 0; col<colsInLine; col++)
+ pszBuf += wsprintf(pszBuf, "%02X%c", buf[line+col], (col&3)==3 && col!=15?'-':' ');
+
+ for (; col<16; col++)
+ {
+ lstrcpy(pszBuf," ");
+ pszBuf+=3;
+ }
+
+ *pszBuf++ = ' ';
+ for (col = 0; col<colsInLine; col++)
+ *pszBuf++ = buf[line+col]<' ' ? '.' : (char)buf[line+col];
+ if(wLen-line<=16) break;
+ *pszBuf++='\n';
+ }
+ *pszBuf='\0';
+
+ CallService(MS_NETLIB_LOG,(WPARAM)ghDirectNetlibUser, (LPARAM)szBuf);
+ }
+#endif
+
+ return 1;
+}
+
+
+
+/*
+void startHandshake_v6(const char *szHost, DWORD dwPort, DWORD dwUin)
+{
+ icq_packet packet;
+ DWORD dwSessionId;
+
+ dwSessionId = rand();
+
+ directPacketInit(&packet, 44);
+ packByte(&packet, 0xff); // Ident
+ packLEDWord(&packet, ICQ_VERSION); // Our version
+ packLEDWord(&packet, dwUin);
+
+ packWord(&packet, 0);
+
+ packLEDWord(&packet, dwListenPort);
+ packLEDWord(&packet, dwLocalUin);
+ packDWord(&packet, dwExternalIP);
+ packDWord(&packet, dwInteralIP);
+ packByte(&packet, nTCPFlag);
+ packLEDWord(&packet, dwSessionId);
+ packLEDWord(&packet, dwListenPort);
+ packLEDWord(&packet, dwSessionId);
+ packLEDWord(&packet, WEBFRONTPORT);
+ packLEDWord(&packet, 0x00000003);
+}
+*/
+
+
+
+// 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.
+static void 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, 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->dwConnCookie); // 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.
+static void 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.
+static void 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.
+static void sendPeerFileInit(directconnect* dc)
+{
+ icq_packet packet;
+ DBVARIANT dbv;
+ char* szNick;
+ int nNickLen;
+
+ dbv.type = DBVT_DELETED;
+ if (ICQGetContactSetting(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, 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/miranda-wine/protocols/IcqOscarJ/icq_direct.h b/miranda-wine/protocols/IcqOscarJ/icq_direct.h
new file mode 100644
index 0000000..8bf65a4
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_direct.h
@@ -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,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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_direct.h,v $
+// Revision : $Revision: 3663 $
+// Last change on : $Date: 2006-08-31 00:18:59 +0400 (Чтв, 31 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#ifndef __ICQ_DIRECT_H
+#define __ICQ_DIRECT_H
+
+typedef struct {
+ BYTE ft_magic;
+ message_cookie_data pMessage;
+ 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 **files;
+ 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 ?
+} filetransfer;
+
+#define DIRECTCONN_STANDARD 0
+#define DIRECTCONN_FILE 1
+#define DIRECTCONN_CHAT 2
+#define DIRECTCONN_REVERSE 10
+#define DIRECTCONN_CLOSING 15
+
+typedef struct {
+ HANDLE hContact;
+ HANDLE hConnection;
+ int type;
+ WORD wVersion;
+ int incoming;
+ int wantIdleTime;
+ int packetPending;
+ DWORD dwRemotePort;
+ DWORD dwRemoteUin;
+ DWORD dwRemoteExternalIP;
+ DWORD dwRemoteInternalIP;
+ DWORD dwLocalExternalIP;
+ DWORD dwLocalInternalIP;
+ DWORD dwConnCookie;
+ int initialised;
+ int handshake;
+ DWORD dwThreadId;
+ filetransfer *ft;
+ DWORD dwReqId; // Reverse Connect request cookie
+} directconnect;
+
+void OpenDirectConnection(HANDLE hContact, int type, void *pvExtra);
+int IsDirectConnectionOpen(HANDLE hContact, int type);
+void CloseDirectConnection(directconnect *dc);
+void CloseContactDirectConns(HANDLE hContact);
+int SendDirectMessage(HANDLE hContact, icq_packet *pkt);
+int sendDirectPacket(directconnect *dc, icq_packet *pkt);
+void icq_newConnectionReceived(HANDLE hNewConnection, DWORD dwRemoteIP, void *pExtra);
+void InitDirectConns(void);
+void UninitDirectConns(void);
+directconnect* FindFileTransferDC(filetransfer* ft);
+void handleDirectMessage(directconnect *dc, PBYTE buf, WORD wLen);
+void EncryptDirectPacket(directconnect *dc, icq_packet *p);
+void icq_AcceptFileTransfer(HANDLE hContact, filetransfer *ft);
+void icq_CancelFileTransfer(HANDLE hContact, filetransfer *ft);
+void icq_sendFileResume(filetransfer *ft, int action, const char *szFilename);
+void icq_InitFileSend(filetransfer *ft);
+void AddExpectedFileRecv(filetransfer *ft);
+filetransfer *FindExpectedFileRecv(DWORD dwUin, DWORD dwTotalSize);
+void handleFileTransferPacket(directconnect *dc, PBYTE buf, WORD wLen);
+void handleFileTransferIdle(directconnect *dc);
+
+
+void handleDirectCancel(directconnect *dc, PBYTE buf, WORD wLen, WORD wCommand, DWORD dwCookie, WORD wMessageType, WORD wStatus, WORD wFlags, char* pszText);
+
+// Handles all types of file transfer replies
+void handleFileAck(PBYTE buf, WORD wLen, DWORD dwUin, DWORD dwCookie, WORD wStatus, char* pszText);
+
+// Handle a received file transfer request (direct & server)
+void handleFileRequest(PBYTE buf, WORD wLen, DWORD dwUin, DWORD dwCookie, DWORD dwID1, DWORD dwID2, char* pszDescription, int nVersion, BOOL bDC);
+
+
+#endif /* __ICQ_DIRECT_H */
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_directmsg.c b/miranda-wine/protocols/IcqOscarJ/icq_directmsg.c
new file mode 100644
index 0000000..3c94ce5
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_directmsg.c
@@ -0,0 +1,418 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_directmsg.c,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+
+extern WORD wListenPort;
+
+void icq_sendAwayMsgReplyDirect(directconnect *dc, WORD wCookie, BYTE msgType, const char **szMsg);
+
+void handleDirectGreetingMessage(directconnect *dc, PBYTE buf, WORD wLen, WORD wCommand, WORD wCookie, BYTE bMsgType, BYTE bMsgFlags, WORD wStatus, WORD wFlags, char* pszText);
+
+
+
+void 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 = _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, szMsg);
+ }
+ break;
+
+ case MTYPE_PLUGIN: // Greeting
+ handleDirectGreetingMessage(dc, buf, wLen, wCommand, wCookie, bMsgType, bMsgFlags, wStatus, wFlags, pszText);
+ break;
+
+ default:
+ {
+ buf -= wTextLen;
+ wLen += wTextLen;
+
+ handleMessageTypes(dc->dwRemoteUin, time(NULL), 0, 0, wCookie, dc->wVersion, (int)bMsgType, (int)bMsgFlags, 0, (DWORD)wLen, wTextLen, buf, TRUE);
+
+ // Send acknowledgement
+ if (bMsgType == MTYPE_PLAIN || bMsgType == MTYPE_URL || bMsgType == MTYPE_CONTACTS)
+ {
+ icq_sendDirectMsgAck(dc, wCookie, bMsgType, bMsgFlags, CAP_RTFMSGS);
+ }
+ break;
+ }
+ }
+ else if (wCommand == DIRECT_ACK)
+ {
+ if (bMsgFlags == 3)
+ { // this is status reply
+ buf -= wTextLen;
+ wLen += wTextLen;
+
+ handleMessageTypes(dc->dwRemoteUin, time(NULL), 0, 0, wCookie, dc->wVersion, (int)bMsgType, (int)bMsgFlags, 2, (DWORD)wLen, wTextLen, buf, TRUE);
+ }
+ else
+ {
+ DWORD dwCookieUin;
+ message_cookie_data* pCookieData = NULL;
+
+ if (!FindCookie(wCookie, &dwCookieUin, &pCookieData))
+ {
+ NetLog_Direct("Received an unexpected direct ack");
+ }
+ else if (dwCookieUin != dc->dwRemoteUin)
+ {
+ NetLog_Direct("Direct UIN does not match Cookie UIN(%u != %u)", dc->dwRemoteUin, dwCookieUin);
+ 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 ?
+ ICQBroadcastAck(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 handleDirectGreetingMessage(directconnect* dc, PBYTE buf, WORD wLen, WORD wCommand, WORD wCookie, BYTE bMsgType, BYTE bMsgFlags, WORD wStatus, WORD wFlags, char* pszText)
+{
+ DWORD dwMsgTypeLen;
+ DWORD dwLengthToEnd;
+ DWORD dwDataLength;
+ char* szMsgType = NULL;
+ char* pszFileName = NULL;
+ int typeId;
+ WORD wPacketCommand;
+ DWORD q1,q2,q3,q4;
+ 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
+
+ // The command in this packet.
+ unpackLEWord(&buf, &wPacketCommand); // TODO: this is most probably length...
+ wLen -= 2;
+
+ // Data type GUID
+ unpackDWord(&buf, &q1);
+ unpackDWord(&buf, &q2);
+ unpackDWord(&buf, &q3);
+ unpackDWord(&buf, &q4);
+ wLen -= 16;
+
+ // Data type function id
+ unpackLEWord(&buf, &qt);
+ wLen -= 2;
+
+ // A text string
+ // "ICQ Chat" for chat request, "File" for file request,
+ // "File Transfer" for file request grant/refusal. This text is
+ // displayed in the requester opened by Windows.
+ unpackLEDWord(&buf, &dwMsgTypeLen);
+ wLen -= 4;
+ if (dwMsgTypeLen == 0 || dwMsgTypeLen>256)
+ {
+ NetLog_Direct("Error: Sanity checking failed (%d) in handleDirectGreetingMessage, len is %u", 1, dwMsgTypeLen);
+ return;
+ }
+ szMsgType = (char *)_alloca(dwMsgTypeLen + 1);
+ memcpy(szMsgType, buf, dwMsgTypeLen);
+ szMsgType[dwMsgTypeLen] = '\0';
+ typeId = TypeGUIDToTypeId(q1,q2,q3,q4,qt);
+ if (!typeId)
+ NetLog_Direct("Error: Unknown type {%04x%04x%04x%04x-%02x}: %s", q1,q2,q3,q4,qt,szMsgType);
+
+ buf += dwMsgTypeLen;
+ wLen -= (WORD)dwMsgTypeLen;
+
+ NetLog_Direct("PEER_MSG_GREETING, command: %u, type: %s, typeID: %u", typeId, szMsgType, typeId);
+
+ // Unknown
+ buf += 15;
+ wLen -= 15;
+
+ // 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 = _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 = _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)
+ {
+ if (typeId == MTYPE_URL || typeId == MTYPE_CONTACTS)
+ {
+ icq_sendDirectMsgAck(dc, wCookie, (BYTE)typeId, 0, CAP_RTFMSGS);
+ }
+ handleMessageTypes(dc->dwRemoteUin, time(NULL), 0, 0, wCookie, dc->wVersion, typeId, 0, 0, dwLengthToEnd, (WORD)dwDataLength, buf, TRUE);
+ }
+ else if (typeId == MTYPE_STATUSMSGEXT && wCommand == DIRECT_ACK)
+ { // especially for icq2003b
+ char* szMsg;
+
+ NetLog_Direct("This is extended status reply");
+ szMsg = _alloca(dwDataLength+1);
+ unpackString(&buf, szMsg, (WORD)dwDataLength);
+ szMsg[dwDataLength] = '\0';
+
+ handleMessageTypes(dc->dwRemoteUin, time(NULL), 0, 0, wCookie, dc->wVersion, (int)(qt + 0xE7), 3, 2, (DWORD)wLen, (WORD)dwDataLength, szMsg, TRUE);
+ }
+ else if (typeId && wCommand == DIRECT_ACK)
+ {
+ DWORD dwCookieUin;
+ message_cookie_data* pCookieData = NULL;
+
+ if (!FindCookie(wCookie, &dwCookieUin, &pCookieData))
+ {
+ NetLog_Direct("Received an unexpected direct ack");
+ }
+ else if (dwCookieUin != dc->dwRemoteUin)
+ {
+ NetLog_Direct("Direct UIN does not match Cookie UIN(%u != %u)", dc->dwRemoteUin, dwCookieUin);
+ 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(dwCookieUin, dc->hContact, wCookie, szMsg, dwDataLength);
+ }
+ break;
+
+ default:
+ NetLog_Direct("Skipped packet from direct connection");
+ break;
+ }
+
+ if (ackType != -1)
+ { // was a good ack to broadcast ?
+ ICQBroadcastAck(dc->hContact, ackType, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0);
+ }
+ // Release cookie
+ ReleaseCookie(wCookie);
+ }
+ }
+ else
+ {
+ NetLog_Direct("Unsupported plugin message type '%s'", szMsgType);
+ }
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_fieldnames.c b/miranda-wine/protocols/IcqOscarJ/icq_fieldnames.c
new file mode 100644
index 0000000..efb162a
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_fieldnames.c
@@ -0,0 +1,280 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_fieldnames.c,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+
+struct fieldnames_t interestsField[]={
+ {100, "Art"},
+ {101, "Cars"},
+ {102, "Celebrity Fans"},
+ {103, "Collections"},
+ {104, "Computers"},
+ {105, "Culture & Literature"},
+ {106, "Fitness"},
+ {107, "Games"},
+ {108, "Hobbies"},
+ {109, "ICQ - Providing Help"},
+ {110, "Internet"},
+ {111, "Lifestyle"},
+ {112, "Movies/TV"},
+ {113, "Music"},
+ {114, "Outdoor Activities"},
+ {115, "Parenting"},
+ {116, "Pets/Animals"},
+ {117, "Religion"},
+ {118, "Science/Technology"},
+ {119, "Skills"},
+ {120, "Sports"},
+ {121, "Web Design"},
+ {122, "Nature and Environment"},
+ {123, "News & Media"},
+ {124, "Government"},
+ {125, "Business & Economy"},
+ {126, "Mystics"},
+ {127, "Travel"},
+ {128, "Astronomy"},
+ {129, "Space"},
+ {130, "Clothing"},
+ {131, "Parties"},
+ {132, "Women"},
+ {133, "Social science"},
+ {134, "60's"},
+ {135, "70's"},
+ {136, "80's"},
+ {137, "50's"},
+ {138, "Finance and corporate"},
+ {139, "Entertainment"},
+ {140, "Consumer electronics"},
+ {141, "Retail stores"},
+ {142, "Health and beauty"},
+ {143, "Media"},
+ {144, "Household products"},
+ {145, "Mail order catalog"},
+ {146, "Business services"},
+ {147, "Audio and visual"},
+ {148, "Sporting and athletic"},
+ {149, "Publishing"},
+ {150, "Home automation"},
+ {-1, NULL}};
+
+struct fieldnames_t languageField[]={
+ {1, "Arabic"},
+ {2, "Bhojpuri"},
+ {3, "Bulgarian"},
+ {4, "Burmese"},
+ {5, "Cantonese"},
+ {6, "Catalan"},
+ {7, "Chinese"},
+ {8, "Croatian"},
+ {9, "Czech"},
+ {10, "Danish"},
+ {11, "Dutch"},
+ {12, "English"},
+ {13, "Esperanto"},
+ {14, "Estonian"},
+ {15, "Farci"},
+ {16, "Finnish"},
+ {17, "French"},
+ {18, "Gaelic"},
+ {19, "German"},
+ {20, "Greek"},
+ {21, "Hebrew"},
+ {22, "Hindi"},
+ {23, "Hungarian"},
+ {24, "Icelandic"},
+ {25, "Indonesian"},
+ {26, "Italian"},
+ {27, "Japanese"},
+ {28, "Khmer"},
+ {29, "Korean"},
+ {30, "Lao"},
+ {31, "Latvian"},
+ {32, "Lithuanian"},
+ {33, "Malay"},
+ {34, "Norwegian"},
+ {35, "Polish"},
+ {36, "Portuguese"},
+ {37, "Romanian"},
+ {38, "Russian"},
+ {39, "Serbo-Croatian"},
+ {40, "Slovak"},
+ {41, "Slovenian"},
+ {42, "Somali"},
+ {43, "Spanish"},
+ {44, "Swahili"},
+ {45, "Swedish"},
+ {46, "Tagalog"},
+ {47, "Tatar"},
+ {48, "Thai"},
+ {49, "Turkish"},
+ {50, "Ukrainian"},
+ {51, "Urdu"},
+ {52, "Vietnamese"},
+ {53, "Yiddish"},
+ {54, "Yoruba"},
+ {55, "Afrikaans"},
+ {56, "Bosnian"},
+ {57, "Persian"},
+ {58, "Albanian"},
+ {59, "Armenian"},
+ {60, "Punjabi"},
+ {61, "Chamorro"},
+ {62, "Mongolian"},
+ {63, "Mandarin"},
+ {64, "Taiwaness"},
+ {65, "Macedonian"},
+ {66, "Sindhi"},
+ {67, "Welsh"},
+ {68, "Azerbaijani"},
+ {69, "Kurdish"},
+ {70, "Gujarati"},
+ {71, "Tamil"},
+ {72, "Belorussian"},
+ {-1, NULL}};
+
+struct fieldnames_t pastField[]={
+ {300, "Elementary School"},
+ {301, "High School"},
+ {302, "College"},
+ {303, "University"},
+ {304, "Military"},
+ {305, "Past Work Place"},
+ {306, "Past Organization"},
+ {399, "Other"},
+ {-1, NULL}};
+
+struct fieldnames_t genderField[]={
+ {1, "Female"},
+ {2, "Male"},
+ {-1, NULL}};
+
+struct fieldnames_t workField[]={
+ {1, "Academic"},
+ {2, "Administrative"},
+ {3, "Art/Entertainment"},
+ {4, "College Student"},
+ {5, "Computers"},
+ {6, "Community & Social"},
+ {7, "Education"},
+ {8, "Engineering"},
+ {9, "Financial Services"},
+ {10, "Government"},
+ {11, "High School Student"},
+ {12, "Home"},
+ {13, "ICQ - Providing Help"},
+ {14, "Law"},
+ {15, "Managerial"},
+ {16, "Manufacturing"},
+ {17, "Medical/Health"},
+ {18, "Military"},
+ {19, "Non-Government Organization"},
+ {20, "Professional"},
+ {21, "Retail"},
+ {22, "Retired"},
+ {23, "Science & Research"},
+ {24, "Sports"},
+ {25, "Technical"},
+ {26, "University Student"},
+ {27, "Web building"},
+ {99, "Other services"},
+ {-1, NULL}};
+
+struct fieldnames_t affiliationField[]={
+ {200, "Alumni Org."},
+ {201, "Charity Org."},
+ {202, "Club/Social Org."},
+ {203, "Community Org."},
+ {204, "Cultural Org."},
+ {205, "Fan Clubs"},
+ {206, "Fraternity/Sorority"},
+ {207, "Hobbyists Org."},
+ {208, "International Org."},
+ {209, "Nature and Environment Org."},
+ {210, "Professional Org."},
+ {211, "Scientific/Technical Org."},
+ {212, "Self Improvement Group"},
+ {213, "Spiritual/Religious Org."},
+ {214, "Sports Org."},
+ {215, "Support Org."},
+ {216, "Trade and Business Org."},
+ {217, "Union"},
+ {218, "Volunteer Org."},
+ {299, "Other"},
+ {-1, NULL}};
+
+struct fieldnames_t agesField[]={
+ {0x0011000D, "13-17"},
+ {0x00160012, "18-22"},
+ {0x001D0017, "23-29"},
+ {0x0027001E, "30-39"},
+ {0x00310028, "40-49"},
+ {0x003B0032, "50-59"},
+ {0x2710003C, "60-above"},
+ {-1, NULL}};
+
+struct fieldnames_t maritalField[]={
+ {10, "Single"},
+ {11, "Close relationships"},
+ {12, "Engaged"},
+ {20, "Married"},
+ {30, "Divorced"},
+ {31, "Separated"},
+ {40, "Widowed"},
+ {-1, NULL}};
+
+
+
+char *LookupFieldNameUtf(struct fieldnames_t *table, int code, char *str)
+{
+ int i;
+
+ if (code != 0)
+ {
+ for(i = 0; table[i].code != -1 && table[i].text; i++)
+ {
+ if (table[i].code == code)
+ return ICQTranslateUtfStatic(table[i].text, str);
+ }
+
+ // Tried to get unexisting field name, you have an
+ // error in the data or in the table
+ _ASSERT(FALSE);
+ }
+
+ return NULL;
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_fieldnames.h b/miranda-wine/protocols/IcqOscarJ/icq_fieldnames.h
new file mode 100644
index 0000000..76c6833
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_fieldnames.h
@@ -0,0 +1,51 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_fieldnames.h,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+struct fieldnames_t {
+ int code;
+ char *text;
+};
+
+extern struct fieldnames_t interestsField[];
+extern struct fieldnames_t languageField[];
+extern struct fieldnames_t pastField[];
+extern struct fieldnames_t genderField[];
+extern struct fieldnames_t agesField[];
+extern struct fieldnames_t workField[];
+extern struct fieldnames_t affiliationField[];
+extern struct fieldnames_t maritalField[];
+
+char *LookupFieldNameUtf(struct fieldnames_t *table, int code, char *str);
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_filerequests.c b/miranda-wine/protocols/IcqOscarJ/icq_filerequests.c
new file mode 100644
index 0000000..d9fdb80
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_filerequests.c
@@ -0,0 +1,236 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_filerequests.c,v $
+// Revision : $Revision: 3478 $
+// Last change on : $Date: 2006-08-09 04:12:18 +0400 (Срд, 09 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+
+extern WORD wListenPort;
+
+void handleFileAck(PBYTE buf, WORD wLen, DWORD dwUin, DWORD dwCookie, WORD wStatus, char* pszText)
+{
+ char* pszFileName = NULL;
+ DWORD dwFileSize;
+ DWORD dwCookieUin;
+ WORD wPort;
+ WORD wFilenameLength;
+ filetransfer* ft;
+
+
+ // Find the filetransfer that belongs to this response
+ if (!FindCookie(dwCookie, &dwCookieUin, &ft))
+ {
+ NetLog_Direct("Error: Received unexpected file transfer request response");
+ return;
+ }
+
+ FreeCookie(dwCookie);
+
+ if (dwCookieUin != dwUin)
+ {
+ 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);
+ ICQBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_DENIED, (HANDLE)ft, 0);
+
+ FreeCookie(dwCookie);
+
+ 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)
+ {
+ pszFileName = _alloca(wFilenameLength+1);
+ unpackString(&buf, pszFileName, wFilenameLength);
+ pszFileName[wFilenameLength] = '\0';
+ }
+ wLen = wLen - 2 - wFilenameLength;
+
+ // Total filesize
+ unpackLEDWord(&buf, &dwFileSize);
+ wLen -= 4;
+
+ NetLog_Direct("File transfer ack from %u, port %u, name %s, size %u", dwUin, ft->dwRemotePort, pszFileName, dwFileSize);
+
+ ICQBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, (HANDLE)ft, 0);
+
+ OpenDirectConnection(ft->hContact, DIRECTCONN_FILE, ft);
+}
+
+
+
+filetransfer *CreateFileTransfer(HANDLE hContact, DWORD dwUin, int nVersion)
+{
+ filetransfer *ft;
+
+ ft = (filetransfer*)SAFE_MALLOC(sizeof(filetransfer));
+ if (ft)
+ {
+ ft->dwUin = dwUin;
+ ft->hContact = hContact;
+ ft->nVersion = nVersion;
+ ft->pMessage.bMessageType = MTYPE_FILEREQ;
+ ft->pMessage.dwMsgID1 = time(NULL);
+ ft->pMessage.dwMsgID2 = RandRange(0, 0x00FF);
+ }
+ return ft;
+}
+
+// pszDescription points to a string with the reason
+// buf points to the first data after the string
+void handleFileRequest(PBYTE buf, WORD wLen, DWORD dwUin, DWORD dwCookie, DWORD dwID1, DWORD dwID2, char* pszDescription, int nVersion, BOOL bDC)
+{
+ char* pszFileName = NULL;
+ DWORD dwFileSize;
+ WORD wFilenameLength;
+ BOOL bEmptyDesc = FALSE;
+
+
+ if (strlennull(pszDescription) == 0)
+ {
+ pszDescription = ICQTranslate("No description given");
+ bEmptyDesc = TRUE;
+ }
+
+ // Empty port+pad
+ buf += 4;
+ wLen -= 4;
+
+
+ // Filename
+ unpackLEWord(&buf, &wFilenameLength);
+ if (wFilenameLength > 0)
+ {
+ pszFileName = _alloca(wFilenameLength + 1);
+ unpackString(&buf, pszFileName, wFilenameLength);
+ pszFileName[wFilenameLength] = '\0';
+ }
+ else
+ {
+ NetLog_Direct("Ignoring malformed file send request");
+ return;
+ }
+
+ wLen = wLen - 2 - wFilenameLength;
+
+ // Total filesize
+ unpackLEDWord(&buf, &dwFileSize);
+ wLen -= 4;
+
+ {
+ CCSDATA ccs;
+ PROTORECVEVENT pre;
+ char* szBlob;
+ filetransfer* ft;
+ int bAdded;
+ HANDLE hContact = HContactFromUIN(dwUin, &bAdded);
+
+ // Initialize a filetransfer struct
+ ft = CreateFileTransfer(hContact, dwUin, nVersion);
+ ft->dwCookie = dwCookie;
+ ft->szFilename = null_strdup(pszFileName);
+ ft->szDescription = null_strdup(pszDescription);
+ ft->fileId = -1;
+ ft->dwTotalSize = dwFileSize;
+ ft->pMessage.dwMsgID1 = dwID1;
+ ft->pMessage.dwMsgID2 = dwID2;
+ ft->bDC = bDC;
+ ft->bEmptyDesc = bEmptyDesc;
+
+
+ // Send chain event
+ szBlob = (char*)_alloca(sizeof(DWORD) + strlennull(pszFileName) + strlennull(pszDescription) + 2);
+ *(PDWORD)szBlob = (DWORD)ft;
+ strcpy(szBlob + sizeof(DWORD), pszFileName);
+ strcpy(szBlob + sizeof(DWORD) + strlennull(pszFileName) + 1, pszDescription);
+ ccs.szProtoService = PSR_FILE;
+ ccs.hContact = hContact;
+ ccs.wParam = 0;
+ ccs.lParam = (LPARAM)&pre;
+ pre.flags = 0;
+ pre.timestamp = time(NULL);
+ pre.szMessage = szBlob;
+ pre.lParam = 0;
+
+ CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs);
+ }
+}
+
+
+
+void 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 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 */
+
+ NetLib_SafeCloseHandle(&ft->hConnection, FALSE);
+
+ ICQBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0);
+
+ /* FIXME: Do not free ft, or anything therein, it is freed inside DC thread ! */
+ #ifdef _DEBUG
+ NetLog_Direct("icq_CancelFileTransfer: OK");
+ #endif
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_filetransfer.c b/miranda-wine/protocols/IcqOscarJ/icq_filetransfer.c
new file mode 100644
index 0000000..0addf79
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_filetransfer.c
@@ -0,0 +1,575 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_filetransfer.c,v $
+// Revision : $Revision: 3663 $
+// Last change on : $Date: 2006-08-31 00:18:59 +0400 (Чтв, 31 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// 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->sending = ft->sending;
+ if (ft->sending)
+ pfts->files = ft->files;
+ else
+ pfts->files = NULL; /* FIXME */
+ pfts->totalFiles = ft->dwFileCount;
+ pfts->currentFileNumber = ft->iCurrentFile;
+ pfts->totalBytes = ft->dwTotalSize;
+ pfts->totalProgress = ft->dwBytesDone;
+ pfts->workingDir = ft->szSavePath;
+ pfts->currentFile = ft->szThisFile;
+ pfts->currentFileSize = ft->dwThisFileSize;
+ pfts->currentFileTime = ft->dwThisFileDate;
+ pfts->currentFileProgress = ft->dwFileBytesDone;
+}
+
+
+
+static void file_sendTransferSpeed(directconnect* dc)
+{
+ icq_packet packet;
+
+ directPacketInit(&packet, 5);
+ packByte(&packet, PEER_FILE_SPEED); /* Ident */
+ packLEDWord(&packet, dc->ft->dwTransferSpeed);
+ sendDirectPacket(dc, &packet);
+}
+
+
+
+static void file_sendNick(directconnect* dc)
+{
+ icq_packet packet;
+ char* szNick;
+ WORD wNickLen;
+ DBVARIANT dbv;
+
+
+ dbv.type = DBVT_DELETED;
+ if (ICQGetContactSetting(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, szNick, (WORD)(wNickLen + 1));
+ sendDirectPacket(dc, &packet);
+ ICQFreeVariant(&dbv);
+}
+
+
+
+static void file_sendNextFile(directconnect* dc)
+{
+ icq_packet packet;
+ struct _stat statbuf;
+ char *pszThisFileName;
+ char szThisSubDir[MAX_PATH];
+ WORD wThisFileNameLen, wThisSubDirLen;
+
+
+ if (dc->ft->iCurrentFile >= (int)dc->ft->dwFileCount)
+ {
+ ICQBroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, dc->ft, 0);
+ CloseDirectConnection(dc);
+ dc->ft->hConnection = NULL;
+ return;
+ }
+
+ dc->ft->szThisFile = null_strdup(dc->ft->files[dc->ft->iCurrentFile]);
+ if (_stat(dc->ft->szThisFile, &statbuf))
+ {
+ icq_LogMessage(LOG_ERROR, "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.");
+ CloseDirectConnection(dc);
+ dc->ft->hConnection = NULL;
+ return;
+ }
+
+ szThisSubDir[0] = '\0';
+
+ if (((pszThisFileName = strrchr(dc->ft->szThisFile, '\\')) == NULL) &&
+ ((pszThisFileName = strrchr(dc->ft->szThisFile, '/')) == NULL))
+ {
+ pszThisFileName = dc->ft->szThisFile;
+ }
+ else
+ {
+ int i;
+ int len;
+
+
+ /* find an earlier subdirectory to be used as a container */
+ for (i = dc->ft->iCurrentFile - 1; i >= 0; i--)
+ {
+ len = strlennull(dc->ft->files[i]);
+ if (!_strnicmp(dc->ft->files[i], dc->ft->szThisFile, len) &&
+ (dc->ft->szThisFile[len] == '\\' || dc->ft->szThisFile[len] == '/'))
+ {
+ char* pszLastBackslash;
+
+ if (((pszLastBackslash = strrchr(dc->ft->files[i], '\\')) == NULL) &&
+ ((pszLastBackslash = strrchr(dc->ft->files[i], '/')) == NULL))
+ {
+ strcpy(szThisSubDir, dc->ft->files[i]);
+ }
+ else
+ {
+ len = pszLastBackslash - dc->ft->files[i] + 1;
+ strncpy(szThisSubDir, dc->ft->szThisFile + len,
+ pszThisFileName - dc->ft->szThisFile - len);
+ szThisSubDir[pszThisFileName - dc->ft->szThisFile - len] = '\0';
+ }
+ }
+ }
+ pszThisFileName++; // skip backslash
+ }
+
+ if (statbuf.st_mode&_S_IFDIR)
+ {
+ dc->ft->currentIsDir = 1;
+ }
+ else
+ {
+ dc->ft->currentIsDir = 0;
+ dc->ft->fileId = _open(dc->ft->szThisFile, _O_BINARY | _O_RDONLY);
+ if (dc->ft->fileId == -1)
+ {
+ icq_LogMessage(LOG_ERROR, "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.");
+ CloseDirectConnection(dc);
+ dc->ft->hConnection = NULL;
+ return;
+ }
+
+ }
+ dc->ft->dwThisFileSize = statbuf.st_size;
+ dc->ft->dwThisFileDate = statbuf.st_mtime;
+ dc->ft->dwFileBytesDone = 0;
+
+ wThisFileNameLen = strlennull(pszThisFileName);
+ wThisSubDirLen = strlennull(szThisSubDir);
+
+ 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, pszThisFileName, (WORD)(wThisFileNameLen + 1));
+ packLEWord(&packet, (WORD)(wThisSubDirLen + 1));
+ packBuffer(&packet, szThisSubDir, (WORD)(wThisSubDirLen + 1));
+ packLEDWord(&packet, dc->ft->dwThisFileSize);
+ packLEDWord(&packet, statbuf.st_mtime);
+ packLEDWord(&packet, dc->ft->dwTransferSpeed);
+
+ sendDirectPacket(dc, &packet);
+
+ ICQBroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, dc->ft, 0);
+}
+
+
+
+static void file_sendResume(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 */
+ sendDirectPacket(dc, &packet);
+}
+
+
+
+static void file_sendData(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);
+ 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);
+ ICQBroadcastAck(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(dc); /* this will close the socket if no more files */
+ }
+}
+
+
+
+void handleFileTransferIdle(directconnect* dc)
+{
+ file_sendData(dc);
+}
+
+
+
+void icq_sendFileResume(filetransfer* ft, int action, const char* szFilename)
+{
+ int openFlags;
+ directconnect *dc;
+
+
+ if (ft->hConnection == NULL)
+ return;
+
+ dc = FindFileTransferDC(ft);
+ if (!dc) return; // something is broken...
+
+ 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 = _open(ft->szThisFile, openFlags, _S_IREAD | _S_IWRITE);
+ if (ft->fileId == -1)
+ {
+ icq_LogMessage(LOG_ERROR, "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_SafeCloseHandle(&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(dc);
+
+ ICQBroadcastAck(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 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(dc);
+ file_sendNick(dc);
+ }
+ ICQBroadcastAck(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(dc);
+ break;
+
+ case PEER_FILE_NEXTFILE:
+ if (wLen < 20)
+ return;
+ buf++; /* id */
+ {
+ WORD wThisFilenameLen, wSubdirLen;
+ BYTE isDirectory;
+ char *szFullPath;
+
+ unpackByte(&buf, &isDirectory);
+ unpackLEWord(&buf, &wThisFilenameLen);
+ if (wLen < 19 + wThisFilenameLen)
+ return;
+ SAFE_FREE(&dc->ft->szThisFile);
+ dc->ft->szThisFile = (char *)SAFE_MALLOC(wThisFilenameLen + 1);
+ memcpy(dc->ft->szThisFile, buf, wThisFilenameLen);
+ dc->ft->szThisFile[wThisFilenameLen] = '\0';
+ buf += wThisFilenameLen;
+
+ unpackLEWord(&buf, &wSubdirLen);
+ if (wLen < 18 + wThisFilenameLen + wSubdirLen)
+ return;
+ SAFE_FREE(&dc->ft->szThisSubdir);
+ dc->ft->szThisSubdir = (char *)SAFE_MALLOC(wSubdirLen + 1);
+ memcpy(dc->ft->szThisSubdir, buf, wSubdirLen);
+ dc->ft->szThisSubdir[wSubdirLen] = '\0';
+ buf += wSubdirLen;
+
+ unpackLEDWord(&buf, &dc->ft->dwThisFileSize);
+ unpackLEDWord(&buf, &dc->ft->dwThisFileDate);
+ unpackLEDWord(&buf, &dc->ft->dwTransferSpeed);
+
+ /* no cheating with paths */
+ if (strstr(dc->ft->szThisFile, "..\\") || strstr(dc->ft->szThisFile, "../") ||
+ strstr(dc->ft->szThisFile, ":\\") || strstr(dc->ft->szThisFile, ":/") ||
+ dc->ft->szThisFile[0] == '\\' || dc->ft->szThisFile[0] == '/')
+ {
+ NetLog_Direct("Invalid path information");
+ break;
+ }
+ if (strstr(dc->ft->szThisSubdir, "..\\") || strstr(dc->ft->szThisSubdir, "../") ||
+ strstr(dc->ft->szThisSubdir, ":\\") || strstr(dc->ft->szThisSubdir, ":/") ||
+ dc->ft->szThisSubdir[0] == '\\' || dc->ft->szThisSubdir[0] == '/')
+ {
+ NetLog_Direct("Invalid path information");
+ break;
+ }
+
+ 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)
+ {
+ _mkdir(dc->ft->szThisFile);
+ dc->ft->fileId = -1;
+ }
+ else
+ {
+ /* file resume */
+ PROTOFILETRANSFERSTATUS pfts = {0};
+
+ file_buildProtoFileTransferStatus(dc->ft, &pfts);
+ if (ICQBroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, dc->ft, (LPARAM)&pfts))
+ break; /* UI supports resume: it will call PS_FILERESUME */
+
+ dc->ft->fileId = _open(dc->ft->szThisFile, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE);
+ if (dc->ft->fileId == -1)
+ {
+ icq_LogMessage(LOG_ERROR, "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(dc);
+ ICQBroadcastAck(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);
+ ICQBroadcastAck(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 */
+ ICQBroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, dc->ft, 0);
+ }
+ }
+ break;
+
+ default:
+ NetLog_Direct("Unknown file transfer packet ignored.");
+ break;
+ }
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_firstrun.c b/miranda-wine/protocols/IcqOscarJ/icq_firstrun.c
new file mode 100644
index 0000000..3d6de95
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_firstrun.c
@@ -0,0 +1,129 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_firstrun.c,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+BOOL CALLBACK icq_FirstRunDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+
+void icq_FirstRunCheck()
+{
+ if (ICQGetContactSettingByte(NULL, "FirstRun", 0))
+ return;
+
+ DialogBox(hInst, MAKEINTRESOURCE(IDD_ICQACCOUNT), NULL, icq_FirstRunDlgProc);
+}
+
+
+
+BOOL CALLBACK icq_FirstRunDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+
+ case WM_INITDIALOG:
+ {
+ char* pszPwd;
+ DWORD dwUIN;
+ char pszUIN[20];
+
+
+ ICQTranslateDialog(hwndDlg);
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM) LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICQ)));
+
+ dwUIN = ICQGetContactSettingUIN(NULL);
+
+ if (dwUIN)
+ {
+ null_snprintf(pszUIN, 20, "%u", dwUIN);
+ SetDlgItemText(hwndDlg, IDC_UIN, pszUIN);
+ }
+
+ SendDlgItemMessage(hwndDlg, IDC_PW, EM_LIMITTEXT, 10, 0);
+ pszPwd = GetUserPassword(FALSE);
+ if (pszPwd)
+ {
+ SetDlgItemText(hwndDlg, IDC_PW, pszPwd);
+ }
+ }
+ 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 IDOK:
+ {
+ char str[128];
+ DWORD dwUIN;
+
+ GetDlgItemText(hwndDlg, IDC_UIN, str, sizeof(str));
+ dwUIN = atoi(str);
+ ICQWriteContactSettingDword(NULL, UNIQUEIDSETTING, dwUIN);
+ GetDlgItemText(hwndDlg, IDC_PW, str, sizeof(str));
+ strcpy(gpszPassword, str);
+ CallService(MS_DB_CRYPT_ENCODESTRING, sizeof(str), (LPARAM) str);
+ ICQWriteContactSettingString(NULL, "Password", str);
+ }
+ // fall through
+
+ case IDCANCEL:
+ {
+ // Mark first run as completed
+ ICQWriteContactSettingByte(NULL, "FirstRun", 1);
+ EndDialog(hwndDlg, IDCANCEL);
+ }
+ break;
+
+ }
+ }
+ break;
+ }
+
+ return FALSE;
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_http.c b/miranda-wine/protocols/IcqOscarJ/icq_http.c
new file mode 100644
index 0000000..8d5a0d6
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_http.c
@@ -0,0 +1,228 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_http.c,v $
+// Revision : $Revision: 3545 $
+// Last change on : $Date: 2006-08-19 03:42:44 +0400 (Сбт, 19 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// 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 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); /* 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(responseBytes < 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;
+ int serverNameLen;
+
+ serverNameLen = strlennull(nloc->szHost);
+
+ packet.wLen = (WORD)(serverNameLen + 4);
+ write_httphdr(&packet, HTTP_PACKETTYPE_LOGIN, GetGatewayIndex(hConn));
+ packWord(&packet, (WORD)serverNameLen);
+ packBuffer(&packet, nloc->szHost, (WORD)serverNameLen);
+ packWord(&packet, nloc->wPort);
+ Netlib_Send(hConn, packet.pData, packet.wLen, MSG_DUMPPROXY|MSG_NOHTTPGATEWAYWRAP);
+ SAFE_FREE(&packet.pData);
+
+ return 1;
+}
+
+
+
+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);
+ curResult = Netlib_Send(hConn, packet.pData, packet.wLen, flags);
+ SAFE_FREE(&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)
+ NetLog_Server("Gateway Connection #%d Established.", dwPackSeq);
+ else
+ NetLog_Server("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
+ NetLog_Server("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, 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/miranda-wine/protocols/IcqOscarJ/icq_http.h b/miranda-wine/protocols/IcqOscarJ/icq_http.h
new file mode 100644
index 0000000..751a8fb
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_http.h
@@ -0,0 +1,55 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_http.h,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// 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/miranda-wine/protocols/IcqOscarJ/icq_infoupdate.c b/miranda-wine/protocols/IcqOscarJ/icq_infoupdate.c
new file mode 100644
index 0000000..fb71ec2
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_infoupdate.c
@@ -0,0 +1,355 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_infoupdate.c,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+#define LISTSIZE 100
+static CRITICAL_SECTION listmutex;
+static HANDLE hQueueEvent = NULL;
+static HANDLE hDummyEvent = NULL;
+static int nUserCount = 0;
+static int bPendingUsers = 0;
+static BOOL bEnabled = TRUE;
+static BOOL bPaused = FALSE;
+static BOOL bRunning = FALSE;
+static DWORD tLast;
+static HANDLE hInfoThread = NULL;
+static DWORD dwUpdateThreshold;
+typedef struct s_userinfo {
+ DWORD dwUin;
+ HANDLE hContact;
+} userinfo;
+static userinfo userList[LISTSIZE];
+
+
+// Retrieve users' info
+unsigned __stdcall icq_InfoUpdateThread(void* arg);
+
+
+
+void icq_InitInfoUpdate(void)
+{
+ int i;
+
+ // Create wait objects
+ hQueueEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ hDummyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+ if (hQueueEvent && hDummyEvent)
+ {
+ // Init mutexes
+ InitializeCriticalSection(&listmutex);
+
+ // Init list
+ for (i = 0; i<LISTSIZE; i++)
+ {
+ userList[i].dwUin = 0;
+ userList[i].hContact = NULL;
+ }
+
+ dwUpdateThreshold = ICQGetContactSettingByte(NULL, "InfoUpdate", UPDATE_THRESHOLD/(3600*24))*3600*24;
+
+ hInfoThread = (HANDLE)forkthreadex(NULL, 0, icq_InfoUpdateThread, 0, 0, (DWORD*)&hInfoThread);
+ }
+
+ bPendingUsers = 0;
+}
+
+// Returns TRUE if user was queued
+// Returns FALSE if the list was full
+BOOL icq_QueueUser(HANDLE hContact)
+{
+ if (nUserCount < LISTSIZE)
+ {
+ int i, nChecked = 0, nFirstFree = -1;
+ BOOL bFound = FALSE;
+
+ EnterCriticalSection(&listmutex);
+
+ // Check if in list
+ for (i = 0; (i<LISTSIZE && nChecked<nUserCount); i++)
+ {
+ if (userList[i].hContact)
+ {
+ nChecked++;
+ if (userList[i].hContact == hContact)
+ {
+ bFound = TRUE;
+ break;
+ }
+ }
+ else if (nFirstFree == -1)
+ {
+ nFirstFree = i;
+ }
+ }
+ if (nFirstFree == -1)
+ nFirstFree = i;
+
+ // Add to list
+ if (!bFound)
+ {
+ DWORD dwUin = ICQGetContactSettingUIN(hContact);
+
+ if (dwUin)
+ {
+ userList[nFirstFree].dwUin = dwUin;
+ userList[nFirstFree].hContact = hContact;
+ nUserCount++;
+#ifdef _DEBUG
+ NetLog_Server("Queued user %u, place %u, count %u", userList[nFirstFree].dwUin, nFirstFree, nUserCount);
+#endif
+ // Notify worker thread
+ if (hQueueEvent)
+ SetEvent(hQueueEvent);
+ }
+ }
+
+ LeaveCriticalSection(&listmutex);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
+void icq_DequeueUser(DWORD dwUin)
+{
+ if (nUserCount > 0)
+ {
+ int i, nChecked = 0;
+ // Check if in list
+ EnterCriticalSection(&listmutex);
+ for (i = 0; (i<LISTSIZE && nChecked<nUserCount); i++)
+ {
+ if (userList[i].dwUin)
+ {
+ nChecked++;
+ // Remove from list
+ if (userList[i].dwUin == dwUin)
+ {
+#ifdef _DEBUG
+ NetLog_Server("Dequeued user %u", userList[i].dwUin);
+#endif
+ userList[i].dwUin = 0;
+ userList[i].hContact = NULL;
+ nUserCount--;
+ break;
+ }
+ }
+ }
+ LeaveCriticalSection(&listmutex);
+ }
+}
+
+
+
+void icq_RescanInfoUpdate()
+{
+ HANDLE hContact = NULL;
+ DWORD dwCurrentTime = 0;
+ BOOL bOldEnable = bEnabled;
+
+ bPendingUsers = 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 */
+ bEnabled = 0; // freeze thread
+ // Queue all outdated users
+ dwCurrentTime = time(NULL);
+ hContact = ICQFindFirstContact();
+
+ while (hContact != NULL)
+ {
+ if ((dwCurrentTime - ICQGetContactSettingDword(hContact, "InfoTS", 0)) > dwUpdateThreshold)
+ {
+ // Queue user
+ if (!icq_QueueUser(hContact))
+ { // The queue is full, pause queuing contacts
+ bPendingUsers = 1;
+ break;
+ }
+ }
+ hContact = ICQFindNextContact(hContact);
+ }
+ icq_EnableUserLookup(bOldEnable); // wake up thread
+}
+
+
+
+void icq_EnableUserLookup(BOOL bEnable)
+{
+ bEnabled = bEnable;
+
+ if (bEnabled) bPaused = FALSE;
+
+ // Notify worker thread
+ if (bEnabled && hQueueEvent)
+ SetEvent(hQueueEvent);
+}
+
+
+
+void icq_PauseUserLookup()
+{
+ bPaused = TRUE;
+ tLast = GetTickCount();
+
+#ifdef _DEBUG
+ NetLog_Server("Pausing Auto-info update thread...");
+#endif
+}
+
+
+
+unsigned __stdcall icq_InfoUpdateThread(void* arg)
+{
+ int i;
+ DWORD dwWait;
+
+ bRunning = TRUE;
+
+ while (bRunning)
+ {
+ // Wait for a while
+ ResetEvent(hQueueEvent);
+
+ if (!nUserCount && bPendingUsers) // whole queue processed, check if more users needs updating
+ icq_RescanInfoUpdate();
+
+ if ((nUserCount > 0) && bEnabled && icqOnline)
+ dwWait = WaitForSingleObjectEx(hDummyEvent, 3000, TRUE);
+ else
+ { // we need to slow down the process or icq will kick us
+ dwWait = WaitForSingleObjectEx(hDummyEvent, 1000, TRUE);
+ while (bRunning && dwWait == WAIT_TIMEOUT)
+ { // wait for new work or until we should end
+ dwWait = WaitForSingleObjectEx(hQueueEvent, 10000, TRUE);
+ }
+ }
+ if (!bRunning) 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 (!bEnabled) continue; // we can't send requests now
+
+ if (bPaused)
+ { // pause for 30sec
+ if (GetTickCount()-tLast>30000)
+ {
+ bPaused = FALSE;
+#ifdef _DEBUG
+ NetLog_Server("Resuming auto-info update thread...");
+#endif
+ }
+ continue;
+ }
+ tLast = GetTickCount();
+
+#ifdef _DEBUG
+ NetLog_Server("Users %u", nUserCount);
+#endif
+ if (nUserCount && icqOnline)
+ {
+ EnterCriticalSection(&listmutex);
+ for (i = 0; i<LISTSIZE; i++)
+ {
+ if (userList[i].hContact)
+ {
+ // Check TS again, maybe it has been updated while we slept
+ if ((time(NULL) - ICQGetContactSettingDword(userList[i].hContact, "InfoTS", 0)) > dwUpdateThreshold) {
+#ifdef _DEBUG
+ NetLog_Server("Request info for user %u", userList[i].dwUin);
+#endif
+ sendUserInfoAutoRequest(userList[i].dwUin);
+
+ // Dequeue user and go back to sleep
+ userList[i].dwUin = 0;
+ userList[i].hContact = NULL;
+ nUserCount--;
+ break;
+ }
+ else
+ {
+#ifdef _DEBUG
+ NetLog_Server("Dequeued absolete user %u", userList[i].dwUin);
+#endif
+ // Dequeue user and find another one
+ userList[i].dwUin = 0;
+ userList[i].hContact = NULL;
+ nUserCount--;
+ // continue for loop
+ }
+ }
+ }
+ LeaveCriticalSection(&listmutex);
+ }
+ break;
+
+ default:
+ // Something strange happened. Exit
+ bRunning = FALSE;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+
+
+// Clean up before exit
+void icq_InfoUpdateCleanup(void)
+{
+ bRunning = FALSE;
+ SetEvent(hDummyEvent); // break timeout
+ SetEvent(hQueueEvent); // break queue loop
+ if (hInfoThread) WaitForSingleObjectEx(hInfoThread, INFINITE, TRUE);
+ // Uninit mutex
+ DeleteCriticalSection(&listmutex);
+ CloseHandle(hQueueEvent);
+ CloseHandle(hDummyEvent);
+ CloseHandle(hInfoThread);
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_infoupdate.h b/miranda-wine/protocols/IcqOscarJ/icq_infoupdate.h
new file mode 100644
index 0000000..4bfa82f
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_infoupdate.h
@@ -0,0 +1,58 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_infoupdate.h,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+
+
+// Queues all outdated users
+void icq_InitInfoUpdate(void);
+
+// Queue one UIN to the list for updating
+BOOL icq_QueueUser(HANDLE hContact);
+
+// Remove one UIN from the list
+void icq_DequeueUser(DWORD dwUin);
+
+// Add all outdated contacts to the list
+void icq_RescanInfoUpdate();
+
+// Clean up on exit
+void icq_InfoUpdateCleanup(void);
+
+// Enable/disable user info lookups
+void icq_EnableUserLookup(BOOL bEnable);
+
+// Pause user info lookup for 30sec
+void icq_PauseUserLookup();
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_opts.c b/miranda-wine/protocols/IcqOscarJ/icq_opts.c
new file mode 100644
index 0000000..8219602
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_opts.c
@@ -0,0 +1,862 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_opts.c,v $
+// Revision : $Revision: 3545 $
+// Last change on : $Date: 2006-08-19 03:42:44 +0400 (Сбт, 19 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+#include <win2k.h>
+#include <uxtheme.h>
+
+
+static BOOL CALLBACK DlgProcIcqMain(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+static BOOL CALLBACK DlgProcIcqOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+static BOOL CALLBACK DlgProcIcqContactsOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+static BOOL CALLBACK DlgProcIcqFeaturesOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+static BOOL CALLBACK DlgProcIcqPrivacyOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+
+static const char* szLogLevelDescr[] = {"Display all problems", "Display problems causing possible loss of data", "Display explanations for disconnection", "Display problems requiring user intervention"};
+
+static BOOL (WINAPI *pfnEnableThemeDialogTexture)(HANDLE, DWORD) = 0;
+
+
+static void AddUniPageUtf(const char* szService, OPTIONSDIALOGPAGE *op, WPARAM wParam, const char *szGroup, const char *szTitle)
+{
+ char str[MAX_PATH];
+ char *pszTitle;
+
+ if (strstr(szTitle, "%s"))
+ {
+ char *lTitle = ICQTranslateUtfStatic(szTitle, str);
+ int size = strlennull(lTitle) + strlennull(gpszICQProtoName);
+
+ pszTitle = (char*)_alloca(size);
+ null_snprintf(pszTitle, size, lTitle, gpszICQProtoName);
+ }
+ else
+ pszTitle = (char*)ICQTranslateUtfStatic(szTitle, str);
+
+ if (gbUnicodeCore)
+ {
+ wchar_t *utitle, *ugroup;
+
+ utitle = make_unicode_string(pszTitle);
+ if (szGroup)
+ ugroup = make_unicode_string(ICQTranslateUtfStatic(szGroup, str));
+ else
+ ugroup = NULL;
+ op->pszTitle = (char*)utitle; // this is union with ptszTitle
+ op->pszGroup = (char*)ugroup;
+ op->flags |= ODPF_UNICODE;
+ CallService(szService, wParam, (LPARAM)op);
+ SAFE_FREE(&utitle);
+ SAFE_FREE(&ugroup);
+ }
+ else
+ {
+ char *title, *group, *tmp;
+ int size;
+
+ size = strlennull(pszTitle) + 2;
+ title = (char*)_alloca(size);
+ utf8_decode_static(pszTitle, title, size);
+ if (szGroup)
+ {
+ tmp = ICQTranslateUtfStatic(szGroup, str);
+ size = strlennull(tmp) + 2;
+ group = (char*)_alloca(size);
+ utf8_decode_static(tmp, group, size);
+ }
+ else
+ group = NULL;
+ op->pszTitle = title;
+ op->pszGroup = group;
+ CallService(szService, wParam, (LPARAM)op);
+ }
+}
+
+
+
+void AddOptionsPageUtf(OPTIONSDIALOGPAGE *op, WPARAM wParam, const char *szGroup, const char *szTitle)
+{
+ AddUniPageUtf(MS_OPT_ADDPAGE, op, wParam, szGroup, szTitle);
+}
+
+
+
+void AddUserInfoPageUtf(OPTIONSDIALOGPAGE *op, WPARAM wParam, const char *szTitle)
+{
+ AddUniPageUtf(MS_USERINFO_ADDPAGE, op, wParam, NULL, szTitle);
+}
+
+
+HWND hOptBasic = 0, hOptContacts = 0, hOptFeatures = 0, hOptPrivacy = 0;
+
+static void TabOptions_AddItemUtf(HWND hTabCtrl, const char* szTitle, HWND hPage)
+{
+ TCITEM tci = {0};
+ RECT rcClient;
+ char* szTitleUtf;
+ int iTotal;
+
+ GetClientRect(GetParent(hTabCtrl), &rcClient);
+
+ szTitleUtf = ICQTranslateUtf(szTitle);
+
+ iTotal = TabCtrl_GetItemCount(hTabCtrl);
+
+ tci.mask = TCIF_PARAM|TCIF_TEXT;
+ tci.lParam = (LPARAM)hPage;
+ if (gbUnicodeAPI)
+ {
+ tci.pszText = (char*)make_unicode_string(szTitleUtf);
+ SendMessageW(hTabCtrl, TCM_INSERTITEMW, iTotal, (WPARAM)&tci);
+ }
+ else
+ {
+ utf8_decode(szTitleUtf, &tci.pszText);
+ SendMessageA(hTabCtrl, TCM_INSERTITEMA, iTotal, (WPARAM)&tci);
+ }
+ SAFE_FREE(&tci.pszText);
+ SAFE_FREE(&szTitleUtf);
+
+ MoveWindow(hPage, 3, 24, rcClient.right - 6, rcClient.bottom - 28, 1);
+}
+
+static void SetOptionsDlgToType(HWND hwnd, int iExpert)
+{
+ HWND hwndTab = GetDlgItem(hwnd, IDC_OPTIONSTAB), hwndEnum;
+
+ if (!hOptBasic)
+ {
+ hOptBasic = CreateDialogUtf(hInst, MAKEINTRESOURCE(IDD_OPT_ICQ), hwnd, DlgProcIcqOpts);
+ if (pfnEnableThemeDialogTexture)
+ pfnEnableThemeDialogTexture(hOptBasic, ETDT_ENABLETAB);
+ }
+
+ hwndEnum = GetWindow(hOptBasic, GW_CHILD);
+
+ while (hwndEnum)
+ { // too bad
+ ShowWindow(hwndEnum, iExpert ? SW_SHOW : SW_HIDE);
+ hwndEnum = GetWindow(hwndEnum, GW_HWNDNEXT);
+ }
+
+ if (!iExpert)
+ {
+ hwndEnum = GetDlgItem(hOptBasic, IDC_STICQGROUP);
+ ShowWindow(hwndEnum, SW_SHOW);
+ hwndEnum = GetWindow(hwndEnum, GW_HWNDNEXT);
+ do {
+ ShowWindow(hwndEnum, SW_SHOW);
+ hwndEnum = GetWindow(hwndEnum, GW_HWNDNEXT);
+ } while(hwndEnum && hwndEnum != GetDlgItem(hOptBasic, IDC_NEWUINLINK));
+ }
+ ShowWindow(hwndEnum, SW_SHOW);
+ TabCtrl_DeleteAllItems(hwndTab);
+
+ TabOptions_AddItemUtf(hwndTab, "Account", hOptBasic);
+
+ if (!hOptContacts)
+ {
+ hOptContacts = CreateDialogUtf(hInst, MAKEINTRESOURCE(IDD_OPT_ICQCONTACTS), hwnd, DlgProcIcqContactsOpts);
+ if (pfnEnableThemeDialogTexture)
+ pfnEnableThemeDialogTexture(hOptContacts, ETDT_ENABLETAB);
+ }
+
+ if (!hOptFeatures)
+ {
+ hOptFeatures = CreateDialogUtf(hInst, MAKEINTRESOURCE(IDD_OPT_ICQFEATURES), hwnd, DlgProcIcqFeaturesOpts);
+ if (pfnEnableThemeDialogTexture)
+ pfnEnableThemeDialogTexture(hOptFeatures, ETDT_ENABLETAB);
+ }
+
+ if (!hOptPrivacy)
+ {
+ hOptPrivacy = CreateDialogUtf(hInst, MAKEINTRESOURCE(IDD_OPT_ICQPRIVACY), hwnd, DlgProcIcqPrivacyOpts);
+ if (pfnEnableThemeDialogTexture)
+ pfnEnableThemeDialogTexture(hOptPrivacy, ETDT_ENABLETAB);
+ }
+
+ ShowWindow(hOptContacts, SW_HIDE);
+ ShowWindow(hOptPrivacy, SW_HIDE);
+ if (hOptFeatures)
+ ShowWindow(hOptFeatures, SW_HIDE);
+ ShowWindow(hOptBasic, SW_SHOW);
+
+ TabOptions_AddItemUtf(hwndTab, "Contacts", hOptContacts);
+ if (iExpert)
+ TabOptions_AddItemUtf(hwndTab, "Features", hOptFeatures);
+ TabOptions_AddItemUtf(hwndTab, "Privacy", hOptPrivacy);
+
+ TabCtrl_SetCurSel(hwndTab, 0);
+}
+
+
+int IcqOptInit(WPARAM wParam, LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = {0};
+ HMODULE hUxTheme = 0;
+
+ if (IsWinVerXPPlus())
+ {
+ hUxTheme = GetModuleHandle("uxtheme.dll");
+
+ if (hUxTheme)
+ pfnEnableThemeDialogTexture = (BOOL (WINAPI *)(HANDLE, DWORD))GetProcAddress(hUxTheme, "EnableThemeDialogTexture");
+ }
+
+ odp.cbSize = sizeof(odp);
+ odp.position = -800000000;
+ odp.hInstance = hInst;
+ odp.pszTemplate = MAKEINTRESOURCE(IDD_OPT_ICQMAIN);
+ odp.pfnDlgProc = DlgProcIcqMain;
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.nIDBottomSimpleControl = 0;
+ AddOptionsPageUtf(&odp, wParam, "Network", gpszICQProtoName);
+
+ InitPopupOpts(wParam);
+
+ return 0;
+}
+
+
+
+static void LoadDBCheckState(HWND hwndDlg, int idCtrl, const char* szSetting, BYTE bDef)
+{
+ CheckDlgButton(hwndDlg, idCtrl, ICQGetContactSettingByte(NULL, szSetting, bDef));
+}
+
+
+
+static void StoreDBCheckState(HWND hwndDlg, int idCtrl, const char* szSetting)
+{
+ ICQWriteContactSettingByte(NULL, szSetting, (BYTE)IsDlgButtonChecked(hwndDlg, idCtrl));
+}
+
+
+
+static void OptDlgChanged(HWND hwndDlg)
+{
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+}
+
+
+// tabbed options page wrapper
+
+static BOOL CALLBACK DlgProcIcqMain(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static int iInit = TRUE;
+
+ switch(msg)
+ {
+ case WM_INITDIALOG:
+ {
+ int iExpert;
+
+ iInit = TRUE;
+ iExpert = SendMessage(GetParent(hwnd), PSM_ISEXPERT, 0, 0);
+ SetOptionsDlgToType(hwnd, iExpert);
+ iInit = FALSE;
+ return FALSE;
+ }
+
+ case WM_DESTROY:
+ hOptBasic = hOptContacts = hOptFeatures = hOptPrivacy = 0;
+ break;
+
+ case PSM_CHANGED: // used so tabs dont have to call SendMessage(GetParent(GetParent(hwnd)), PSM_CHANGED, 0, 0);
+ if (!iInit) OptDlgChanged(hwnd);
+ break;
+
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom)
+ {
+ case 0:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case PSN_APPLY:
+ {
+ TCITEM tci;
+ int i,count;
+
+ tci.mask = TCIF_PARAM;
+ count = TabCtrl_GetItemCount(GetDlgItem(hwnd,IDC_OPTIONSTAB));
+ for (i=0; i<count; i++)
+ {
+ TabCtrl_GetItem(GetDlgItem(hwnd,IDC_OPTIONSTAB),i,&tci);
+ SendMessage((HWND)tci.lParam,WM_NOTIFY,0,lParam);
+ }
+ break;
+ }
+
+ case PSN_EXPERTCHANGED:
+ {
+ int iExpert = SendMessage(GetParent(hwnd), PSM_ISEXPERT, 0, 0);
+
+ SetOptionsDlgToType(hwnd, iExpert);
+ break;
+ }
+ }
+ break;
+
+ case IDC_OPTIONSTAB:
+ {
+ HWND hTabCtrl = GetDlgItem(hwnd, IDC_OPTIONSTAB);
+
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case TCN_SELCHANGING:
+ {
+ TCITEM tci;
+
+ tci.mask = TCIF_PARAM;
+ TabCtrl_GetItem(hTabCtrl, TabCtrl_GetCurSel(hTabCtrl), &tci);
+ ShowWindow((HWND)tci.lParam, SW_HIDE);
+ }
+ break;
+
+ case TCN_SELCHANGE:
+ {
+ TCITEM tci;
+
+ tci.mask = TCIF_PARAM;
+ TabCtrl_GetItem(hTabCtrl, TabCtrl_GetCurSel(hTabCtrl), &tci);
+ ShowWindow((HWND)tci.lParam,SW_SHOW);
+ }
+ break;
+ }
+ break;
+ }
+ }
+ break;
+ }
+ return FALSE;
+}
+
+
+// standalone option pages
+
+static BOOL CALLBACK DlgProcIcqOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ char pszPwd[16];
+ char szServer[MAX_PATH];
+
+ ICQTranslateDialog(hwndDlg);
+
+ SetDlgItemInt(hwndDlg, IDC_ICQNUM, ICQGetContactSettingUIN(NULL), FALSE);
+
+ if (!ICQGetContactStaticString(NULL, "Password", pszPwd, sizeof(pszPwd)))
+ {
+ CallService(MS_DB_CRYPT_DECODESTRING, strlennull(pszPwd) + 1, (LPARAM)pszPwd);
+
+ //bit of a security hole here, since it's easy to extract a password from an edit box
+ SetDlgItemText(hwndDlg, IDC_PASSWORD, pszPwd);
+ }
+
+ if (!ICQGetContactStaticString(NULL, "OscarServer", szServer, MAX_PATH))
+ {
+ SetDlgItemText(hwndDlg, IDC_ICQSERVER, szServer);
+ }
+ else
+ {
+ SetDlgItemText(hwndDlg, IDC_ICQSERVER, DEFAULT_SERVER_HOST);
+ }
+
+ SetDlgItemInt(hwndDlg, IDC_ICQPORT, ICQGetContactSettingWord(NULL, "OscarPort", DEFAULT_SERVER_PORT), FALSE);
+ LoadDBCheckState(hwndDlg, IDC_KEEPALIVE, "KeepAlive", 1);
+ LoadDBCheckState(hwndDlg, IDC_SECURE, "SecureLogin", DEFAULT_SECURE_LOGIN);
+ SendDlgItemMessage(hwndDlg, IDC_LOGLEVEL, TBM_SETRANGE, FALSE, MAKELONG(0, 3));
+ SendDlgItemMessage(hwndDlg, IDC_LOGLEVEL, TBM_SETPOS, TRUE, 3-ICQGetContactSettingByte(NULL, "ShowLogLevel", LOG_WARNING));
+ SetDlgItemTextUtf(hwndDlg, IDC_LEVELDESCR, ICQTranslateUtfStatic(szLogLevelDescr[3-SendDlgItemMessage(hwndDlg, IDC_LOGLEVEL, TBM_GETPOS, 0, 0)], szServer));
+ ShowWindow(GetDlgItem(hwndDlg, IDC_RECONNECTREQD), SW_HIDE);
+ LoadDBCheckState(hwndDlg, IDC_NOERRMULTI, "IgnoreMultiErrorBox", 0);
+
+ return TRUE;
+ }
+
+ case WM_HSCROLL:
+ {
+ char str[MAX_PATH];
+
+ SetDlgItemTextUtf(hwndDlg, IDC_LEVELDESCR, ICQTranslateUtfStatic(szLogLevelDescr[3-SendDlgItemMessage(hwndDlg, IDC_LOGLEVEL,TBM_GETPOS, 0, 0)], str));
+ 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:
+ SetDlgItemText(hwndDlg, IDC_ICQSERVER, DEFAULT_SERVER_HOST);
+ SetDlgItemInt(hwndDlg, IDC_ICQPORT, DEFAULT_SERVER_PORT, FALSE);
+ OptDlgChanged(hwndDlg);
+ return TRUE;
+ }
+
+ if (icqOnline && LOWORD(wParam) != IDC_NOERRMULTI)
+ {
+ char szClass[80];
+
+
+ GetClassName((HWND)lParam, szClass, sizeof(szClass));
+
+ if (lstrcmpi(szClass, "EDIT") || HIWORD(wParam) == EN_CHANGE)
+ ShowWindow(GetDlgItem(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];
+
+ ICQWriteContactSettingDword(NULL, UNIQUEIDSETTING, (DWORD)GetDlgItemInt(hwndDlg, IDC_ICQNUM, NULL, FALSE));
+ GetDlgItemText(hwndDlg, IDC_PASSWORD, str, sizeof(str));
+ if (strlennull(str))
+ {
+ strcpy(gpszPassword, str);
+ gbRememberPwd = TRUE;
+ }
+ else
+ {
+ gbRememberPwd = ICQGetContactSettingByte(NULL, "RememberPass", 0);
+ }
+ CallService(MS_DB_CRYPT_ENCODESTRING, sizeof(str), (LPARAM)str);
+ ICQWriteContactSettingString(NULL, "Password", str);
+ GetDlgItemText(hwndDlg,IDC_ICQSERVER, str, sizeof(str));
+ ICQWriteContactSettingString(NULL, "OscarServer", str);
+ ICQWriteContactSettingWord(NULL, "OscarPort", (WORD)GetDlgItemInt(hwndDlg, IDC_ICQPORT, NULL, FALSE));
+ StoreDBCheckState(hwndDlg, IDC_KEEPALIVE, "KeepAlive");
+ StoreDBCheckState(hwndDlg, IDC_SECURE, "SecureLogin");
+ StoreDBCheckState(hwndDlg, IDC_NOERRMULTI, "IgnoreMultiErrorBox");
+ ICQWriteContactSettingByte(NULL, "ShowLogLevel", (BYTE)(3-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 BOOL CALLBACK DlgProcIcqPrivacyOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+
+ case WM_INITDIALOG:
+ {
+ int nDcType;
+ int nAddAuth;
+
+ nDcType = ICQGetContactSettingByte(NULL, "DCType", 0);
+ nAddAuth = ICQGetContactSettingByte(NULL, "Auth", 1);
+
+ ICQTranslateDialog(hwndDlg);
+ if (!icqOnline)
+ {
+ icq_EnableMultipleControls(hwndDlg, icqPrivacyControls, sizeof(icqPrivacyControls)/sizeof(icqPrivacyControls[0]), FALSE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_STATIC_NOTONLINE), SW_SHOW);
+ }
+ else
+ {
+ ShowWindow(GetDlgItem(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(hwndDlg, IDC_WEBAWARE, "WebAware", 0);
+ LoadDBCheckState(hwndDlg, IDC_PUBLISHPRIMARY, "PublishPrimaryEmail", 0);
+ LoadDBCheckState(hwndDlg, IDC_STATUSMSG_CLIST, "StatusMsgReplyCList", 0);
+ LoadDBCheckState(hwndDlg, IDC_STATUSMSG_VISIBLE, "StatusMsgReplyVisible", 0);
+ if (!ICQGetContactSettingByte(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(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(hwndDlg, IDC_WEBAWARE, "WebAware");
+ StoreDBCheckState(hwndDlg, IDC_PUBLISHPRIMARY, "PublishPrimaryEmail");
+ StoreDBCheckState(hwndDlg, IDC_STATUSMSG_CLIST, "StatusMsgReplyCList");
+ StoreDBCheckState(hwndDlg, IDC_STATUSMSG_VISIBLE, "StatusMsgReplyVisible");
+ if (IsDlgButtonChecked(hwndDlg, IDC_DCALLOW_AUTH))
+ ICQWriteContactSettingByte(NULL, "DCType", 2);
+ else if (IsDlgButtonChecked(hwndDlg, IDC_DCALLOW_CLIST))
+ ICQWriteContactSettingByte(NULL, "DCType", 1);
+ else
+ ICQWriteContactSettingByte(NULL, "DCType", 0);
+ StoreDBCheckState(hwndDlg, IDC_ADD_AUTH, "Auth");
+
+ if (icqOnline)
+ {
+ PBYTE buf=NULL;
+ int buflen=0;
+
+ ppackTLVLNTSBytefromDB(&buf, &buflen, "e-mail", (BYTE)!ICQGetContactSettingByte(NULL, "PublishPrimaryEmail", 0), TLV_EMAIL);
+ ppackTLVLNTSBytefromDB(&buf, &buflen, "e-mail0", 0, TLV_EMAIL);
+ ppackTLVLNTSBytefromDB(&buf, &buflen, "e-mail1", 0, TLV_EMAIL);
+
+ ppackTLVByte(&buf, &buflen, (BYTE)!ICQGetContactSettingByte(NULL, "Auth", 1), TLV_AUTH, 1);
+
+ ppackTLVByte(&buf, &buflen, (BYTE)ICQGetContactSettingByte(NULL, "WebAware", 0), TLV_WEBAWARE, 1);
+
+ icq_changeUserDetailsServ(META_SET_FULLINFO_REQ, buf, (WORD)buflen);
+
+ SAFE_FREE(&buf);
+
+ // Send a status packet to notify the server about the webaware setting
+ {
+ WORD wStatus;
+
+ wStatus = MirandaStatusToIcq(gnCurrentStatus);
+
+ if (gnCurrentStatus == ID_STATUS_INVISIBLE)
+ {
+ if (gbSsiEnabled)
+ updateServVisibilityCode(3);
+ icq_setstatus(wStatus);
+ // Tell who is on our visible list
+ icq_sendEntireVisInvisList(0);
+ }
+ else
+ {
+ icq_setstatus(wStatus);
+ if (gbSsiEnabled)
+ updateServVisibilityCode(4);
+ // Tell who is on our invisible list
+ icq_sendEntireVisInvisList(1);
+ }
+ }
+ }
+ return TRUE;
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+static HWND hCpCombo;
+
+struct CPTABLE {
+ WORD cpId;
+ char *cpName;
+};
+
+struct CPTABLE cpTable[] = {
+ { 874, "Thai" },
+ { 932, "Japanese" },
+ { 936, "Simplified Chinese" },
+ { 949, "Korean" },
+ { 950, "Traditional Chinese" },
+ { 1250, "Central European" },
+ { 1251, "Cyrillic" },
+ { 1252, "Latin I" },
+ { 1253, "Greek" },
+ { 1254, "Turkish" },
+ { 1255, "Hebrew" },
+ { 1256, "Arabic" },
+ { 1257, "Baltic" },
+ { 1258, "Vietnamese" },
+ { 1361, "Korean (Johab)" },
+ { -1, NULL}
+};
+
+static BOOL CALLBACK FillCpCombo(LPCSTR str)
+{
+ int i;
+ UINT cp;
+
+ cp = atoi(str);
+ for (i=0; cpTable[i].cpName != NULL && cpTable[i].cpId!=cp; i++);
+ if (cpTable[i].cpName != NULL)
+ {
+ 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,IDC_XSTATUSRESET};
+static const UINT icqAimControls[] = {IDC_AIMENABLE};
+static BOOL CALLBACK DlgProcIcqFeaturesOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ BYTE bData;
+ int sCodePage;
+ int i;
+
+ ICQTranslateDialog(hwndDlg);
+ bData = ICQGetContactSettingByte(NULL, "UtfEnabled", DEFAULT_UTF_ENABLED);
+ CheckDlgButton(hwndDlg, IDC_UTFENABLE, bData?TRUE:FALSE);
+ CheckDlgButton(hwndDlg, IDC_UTFALL, bData==2?TRUE:FALSE);
+ icq_EnableMultipleControls(hwndDlg, icqUnicodeControls, sizeof(icqUnicodeControls)/sizeof(icqUnicodeControls[0]), bData?TRUE:FALSE);
+ LoadDBCheckState(hwndDlg, IDC_TEMPVISIBLE, "TempVisListEnabled",DEFAULT_TEMPVIS_ENABLED);
+ LoadDBCheckState(hwndDlg, IDC_SLOWSEND, "SlowSend", DEFAULT_SLOWSEND);
+ LoadDBCheckState(hwndDlg, IDC_ONLYSERVERACKS, "OnlyServerAcks", DEFAULT_ONLYSERVERACKS);
+ bData = ICQGetContactSettingByte(NULL, "DirectMessaging", DEFAULT_DCMSG_ENABLED);
+ CheckDlgButton(hwndDlg, IDC_DCENABLE, bData?TRUE:FALSE);
+ CheckDlgButton(hwndDlg, IDC_DCPASSIVE, bData==1?TRUE:FALSE);
+ icq_EnableMultipleControls(hwndDlg, icqDCMsgControls, sizeof(icqDCMsgControls)/sizeof(icqDCMsgControls[0]), bData?TRUE:FALSE);
+ bData = ICQGetContactSettingByte(NULL, "XStatusEnabled", DEFAULT_XSTATUS_ENABLED);
+ CheckDlgButton(hwndDlg, IDC_XSTATUSENABLE, bData);
+ icq_EnableMultipleControls(hwndDlg, icqXStatusControls, sizeof(icqXStatusControls)/sizeof(icqXStatusControls[0]), bData);
+ LoadDBCheckState(hwndDlg, IDC_XSTATUSAUTO, "XStatusAuto", DEFAULT_XSTATUS_AUTO);
+ LoadDBCheckState(hwndDlg, IDC_XSTATUSRESET, "XStatusReset", DEFAULT_XSTATUS_RESET);
+ LoadDBCheckState(hwndDlg, IDC_KILLSPAMBOTS, "KillSpambots", DEFAULT_KILLSPAM_ENABLED);
+ LoadDBCheckState(hwndDlg, IDC_AIMENABLE, "AimEnabled", DEFAULT_AIM_ENABLED);
+ icq_EnableMultipleControls(hwndDlg, icqAimControls, sizeof(icqAimControls)/sizeof(icqAimControls[0]), icqOnline?FALSE:TRUE);
+
+ hCpCombo = GetDlgItem(hwndDlg, IDC_UTFCODEPAGE);
+ sCodePage = ICQGetContactSettingWord(NULL, "AnsiCodePage", CP_ACP);
+ ComboBoxAddStringUtf(GetDlgItem(hwndDlg, IDC_UTFCODEPAGE), "System default codepage", 0);
+ EnumSystemCodePagesA(FillCpCombo, CP_INSTALLED);
+ if(sCodePage == 0)
+ SendDlgItemMessage(hwndDlg, IDC_UTFCODEPAGE, CB_SETCURSEL, (WPARAM)0, 0);
+ else
+ {
+ for (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)/sizeof(icqUnicodeControls[0]), IsDlgButtonChecked(hwndDlg, IDC_UTFENABLE));
+ break;
+ case IDC_DCENABLE:
+ icq_EnableMultipleControls(hwndDlg, icqDCMsgControls, sizeof(icqDCMsgControls)/sizeof(icqDCMsgControls[0]), IsDlgButtonChecked(hwndDlg, IDC_DCENABLE));
+ break;
+ case IDC_XSTATUSENABLE:
+ icq_EnableMultipleControls(hwndDlg, icqXStatusControls, sizeof(icqXStatusControls)/sizeof(icqXStatusControls[0]), IsDlgButtonChecked(hwndDlg, IDC_XSTATUSENABLE));
+ break;
+ }
+ OptDlgChanged(hwndDlg);
+ break;
+
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case PSN_APPLY:
+ if (IsDlgButtonChecked(hwndDlg, IDC_UTFENABLE))
+ gbUtfEnabled = IsDlgButtonChecked(hwndDlg, IDC_UTFALL)?2:1;
+ else
+ gbUtfEnabled = 0;
+ {
+ int i = SendDlgItemMessage(hwndDlg, IDC_UTFCODEPAGE, CB_GETCURSEL, 0, 0);
+ gwAnsiCodepage = (WORD)SendDlgItemMessage(hwndDlg, IDC_UTFCODEPAGE, CB_GETITEMDATA, (WPARAM)i, 0);
+ ICQWriteContactSettingWord(NULL, "AnsiCodePage", gwAnsiCodepage);
+ }
+ ICQWriteContactSettingByte(NULL, "UtfEnabled", gbUtfEnabled);
+ gbTempVisListEnabled = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_TEMPVISIBLE);
+ ICQWriteContactSettingByte(NULL, "TempVisListEnabled", gbTempVisListEnabled);
+ StoreDBCheckState(hwndDlg, IDC_SLOWSEND, "SlowSend");
+ StoreDBCheckState(hwndDlg, IDC_ONLYSERVERACKS, "OnlyServerAcks");
+ if (IsDlgButtonChecked(hwndDlg, IDC_DCENABLE))
+ gbDCMsgEnabled = IsDlgButtonChecked(hwndDlg, IDC_DCPASSIVE)?1:2;
+ else
+ gbDCMsgEnabled = 0;
+ ICQWriteContactSettingByte(NULL, "DirectMessaging", gbDCMsgEnabled);
+ gbXStatusEnabled = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_XSTATUSENABLE);
+ ICQWriteContactSettingByte(NULL, "XStatusEnabled", gbXStatusEnabled);
+ StoreDBCheckState(hwndDlg, IDC_XSTATUSAUTO, "XStatusAuto");
+ StoreDBCheckState(hwndDlg, IDC_XSTATUSRESET, "XStatusReset");
+ StoreDBCheckState(hwndDlg, IDC_KILLSPAMBOTS , "KillSpambots");
+ StoreDBCheckState(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_LINKAVATARS};
+static BOOL CALLBACK DlgProcIcqContactsOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ ICQTranslateDialog(hwndDlg);
+ LoadDBCheckState(hwndDlg, IDC_ENABLE, "UseServerCList", DEFAULT_SS_ENABLED);
+ LoadDBCheckState(hwndDlg, IDC_ADDSERVER, "ServerAddRemove", DEFAULT_SS_ADDSERVER);
+ LoadDBCheckState(hwndDlg, IDC_LOADFROMSERVER, "LoadServerDetails", DEFAULT_SS_LOAD);
+ LoadDBCheckState(hwndDlg, IDC_SAVETOSERVER, "StoreServerDetails", DEFAULT_SS_STORE);
+ LoadDBCheckState(hwndDlg, IDC_ENABLEAVATARS, "AvatarsEnabled", DEFAULT_AVATARS_ENABLED);
+ LoadDBCheckState(hwndDlg, IDC_AUTOLOADAVATARS, "AvatarsAutoLoad", DEFAULT_LOAD_AVATARS);
+ LoadDBCheckState(hwndDlg, IDC_LINKAVATARS, "AvatarsAutoLink", DEFAULT_LINK_AVATARS);
+
+ icq_EnableMultipleControls(hwndDlg, icqContactsControls, sizeof(icqContactsControls)/sizeof(icqContactsControls[0]),
+ ICQGetContactSettingByte(NULL, "UseServerCList", DEFAULT_SS_ENABLED)?TRUE:FALSE);
+ icq_EnableMultipleControls(hwndDlg, icqAvatarControls, sizeof(icqAvatarControls)/sizeof(icqAvatarControls[0]),
+ ICQGetContactSettingByte(NULL, "AvatarsEnabled", DEFAULT_AVATARS_ENABLED)?TRUE:FALSE);
+
+ if (icqOnline)
+ {
+ ShowWindow(GetDlgItem(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:
+ ShowUploadContactsDialog();
+ return TRUE;
+ case IDC_ENABLE:
+ icq_EnableMultipleControls(hwndDlg, icqContactsControls, sizeof(icqContactsControls)/sizeof(icqContactsControls[0]), IsDlgButtonChecked(hwndDlg, IDC_ENABLE));
+ if (icqOnline)
+ ShowWindow(GetDlgItem(hwndDlg, IDC_RECONNECTREQD), SW_SHOW);
+ else
+ EnableDlgItem(hwndDlg, IDC_UPLOADNOW, FALSE);
+ break;
+ case IDC_ENABLEAVATARS:
+ icq_EnableMultipleControls(hwndDlg, icqAvatarControls, sizeof(icqAvatarControls)/sizeof(icqAvatarControls[0]), IsDlgButtonChecked(hwndDlg, IDC_ENABLEAVATARS));
+ break;
+ }
+ OptDlgChanged(hwndDlg);
+ break;
+
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case PSN_APPLY:
+ StoreDBCheckState(hwndDlg, IDC_ENABLE, "UseServerCList");
+ StoreDBCheckState(hwndDlg, IDC_ADDSERVER, "ServerAddRemove");
+ StoreDBCheckState(hwndDlg, IDC_LOADFROMSERVER, "LoadServerDetails");
+ StoreDBCheckState(hwndDlg, IDC_SAVETOSERVER, "StoreServerDetails");
+ StoreDBCheckState(hwndDlg, IDC_ENABLEAVATARS, "AvatarsEnabled");
+ StoreDBCheckState(hwndDlg, IDC_AUTOLOADAVATARS, "AvatarsAutoLoad");
+ StoreDBCheckState(hwndDlg, IDC_LINKAVATARS, "AvatarsAutoLink");
+
+ return TRUE;
+ }
+ break;
+ }
+ return FALSE;
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_opts.h b/miranda-wine/protocols/IcqOscarJ/icq_opts.h
new file mode 100644
index 0000000..085aa19
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_opts.h
@@ -0,0 +1,42 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_opts.h,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+
+
+int IcqOptInit(WPARAM, LPARAM);
+
+void AddUserInfoPageUtf(OPTIONSDIALOGPAGE *op, WPARAM wParam, const char *szTitle);
+void AddOptionsPageUtf(OPTIONSDIALOGPAGE *op, WPARAM wParam, const char *szGroup, const char *szTitle);
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_packet.c b/miranda-wine/protocols/IcqOscarJ/icq_packet.c
new file mode 100644
index 0000000..b9b7972
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_packet.c
@@ -0,0 +1,711 @@
+// ---------------------------------------------------------------------------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, 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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_packet.c,v $
+// Revision : $Revision: 3663 $
+// Last change on : $Date: 2006-08-31 00:18:59 +0400 (Чтв, 31 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+
+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);
+
+ 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);
+
+ write_flap(pPacket, ICQ_LOGIN_CHAN);
+ packDWord(pPacket, 0x00000001);
+ packTLV(pPacket, 0x06, wCookieSize, pCookie);
+}
+
+
+
+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 packTLV(icq_packet* pPacket, WORD wType, WORD wLength, 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);
+}
+
+
+
+// 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)
+{ // TODO: invent something more clever
+ if (dwUin >= 1000000000) return 10;
+ if (dwUin >= 100000000) return 9;
+ if (dwUin >= 10000000) return 8;
+ if (dwUin >= 1000000) return 7;
+ if (dwUin >= 100000) return 6;
+ if (dwUin >= 10000) return 5;
+ if (dwUin >= 1000) return 4;
+ if (dwUin >= 100) return 3;
+ if (dwUin >= 10) return 2;
+ return 1;
+}
+
+
+
+int __fastcall getUIDLen(DWORD dwUin, char* szUid)
+{
+ if (dwUin)
+ return getUINLen(dwUin);
+ else
+ return strlennull(szUid);
+}
+
+
+
+void __fastcall packUIN(icq_packet* pPacket, DWORD dwUin)
+{
+ unsigned char pszUin[UINMAXLEN];
+ BYTE nUinLen = getUINLen(dwUin);
+
+ ltoa(dwUin, pszUin, 10);
+
+ packByte(pPacket, nUinLen); // Length of user id
+ packBuffer(pPacket, pszUin, nUinLen); // Receiving user's id
+}
+
+
+
+void __fastcall packUID(icq_packet* pPacket, DWORD dwUin, char* szUid)
+{
+ if (dwUin)
+ packUIN(pPacket, dwUin);
+ else
+ {
+ BYTE nLen = strlennull(szUid);
+ packByte(pPacket, nLen);
+ packBuffer(pPacket, szUid, nLen);
+ }
+}
+
+
+
+void packFNACHeader(icq_packet* pPacket, WORD wFamily, WORD wSubtype)
+{
+ packWord(pPacket, wFamily); // Family type
+ packWord(pPacket, wSubtype); // Family subtype
+ packDWord(pPacket, 0); // SNAC flags // SNAC request id (sequence)
+ packWord(pPacket, wSubtype); // SNAC request id (command)
+}
+
+
+
+void packFNACHeaderFull(icq_packet* pPacket, WORD wFamily, WORD wSubtype, WORD wFlags, DWORD dwSeq)
+{
+ WORD wSeq = (WORD)dwSeq & 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, wSeq); // SNAC request id (sequence)
+ packWord(pPacket, (WORD)(dwSeq>>0x10)); // SNAC request id (command)
+}
+
+
+
+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);
+}
+
+
+
+void ppackByte(PBYTE *buf,int *buflen,BYTE b)
+{
+ *buf=(PBYTE)realloc(*buf,1+*buflen);
+ *(*buf+*buflen)=b;
+ ++*buflen;
+}
+
+
+
+void ppackLEWord(PBYTE *buf,int *buflen,WORD w)
+{
+ *buf=(PBYTE)realloc(*buf,2+*buflen);
+ *(PWORD)(*buf+*buflen)=w;
+ *buflen+=2;
+}
+
+
+
+void ppackLEDWord(PBYTE *buf, int *buflen, DWORD d)
+{
+ *buf = (PBYTE)realloc(*buf, 4 + *buflen);
+ *(PDWORD)(*buf + *buflen) = d;
+ *buflen += 4;
+}
+
+
+
+/*void ppackLNTS(PBYTE *buf, int *buflen, const char *str)
+{
+ WORD len = strlennull(str);
+ ppackWord(buf, buflen, len);
+ *buf = (PBYTE)realloc(*buf, *buflen + len);
+ memcpy(*buf + *buflen, str, len);
+ *buflen += len;
+}*/
+
+
+
+void ppackLELNTS(PBYTE *buf, int *buflen, const char *str)
+{
+ WORD len = strlennull(str);
+ ppackLEWord(buf, buflen, len);
+ *buf = (PBYTE)realloc(*buf, *buflen + len);
+ memcpy(*buf + *buflen, str, len);
+ *buflen += len;
+}
+
+
+
+void ppackLELNTSfromDB(PBYTE *buf, int *buflen, const char *szSetting)
+{
+ DBVARIANT dbv;
+
+ if (ICQGetContactSetting(NULL, szSetting, &dbv))
+ {
+ ppackLEWord(buf, buflen, 0);
+ }
+ else
+ {
+ ppackLELNTS(buf, buflen, dbv.pszVal);
+ ICQFreeVariant(&dbv);
+ }
+}
+
+
+
+// *** TLV based (!!! WORDs and DWORDs are LE !!!)
+void ppackTLVByte(PBYTE *buf, int *buflen, BYTE b, WORD wType, BYTE always)
+{
+ if (!always && !b) return;
+
+ *buf = (PBYTE)realloc(*buf, 5 + *buflen);
+ *(PWORD)(*buf + *buflen) = wType;
+ *(PWORD)(*buf + *buflen + 2) = 1;
+ *(*buf + *buflen + 4) = b;
+ *buflen += 5;
+}
+
+
+
+void ppackTLVWord(PBYTE *buf, int *buflen, WORD w, WORD wType, BYTE always)
+{
+ if (!always && !w) return;
+
+ *buf = (PBYTE)realloc(*buf, 6 + *buflen);
+ *(PWORD)(*buf + *buflen) = wType;
+ *(PWORD)(*buf + *buflen + 2) = 2;
+ *(PWORD)(*buf + *buflen + 4) = w;
+ *buflen += 6;
+}
+
+
+
+void ppackTLVDWord(PBYTE *buf, int *buflen, DWORD d, WORD wType, BYTE always)
+{
+ if (!always && !d) return;
+
+ *buf = (PBYTE)realloc(*buf, 8 + *buflen);
+ *(PWORD)(*buf + *buflen) = wType;
+ *(PWORD)(*buf + *buflen + 2) = 4;
+ *(PDWORD)(*buf + *buflen + 4) = d;
+ *buflen += 8;
+}
+
+
+
+void packTLVLNTS(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 ppackTLVLNTS(PBYTE *buf, int *buflen, const char *str, WORD wType, BYTE always)
+{
+ int len = strlennull(str) + 1;
+
+ if (!always && len < 2) return;
+
+ *buf = (PBYTE)realloc(*buf, 6 + *buflen + len);
+ packTLVLNTS(buf, buflen, str, wType);
+}
+
+
+
+void ppackTLVWordLNTS(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)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 ppackTLVLNTSByte(PBYTE *buf, int *buflen, const char *str, BYTE b, WORD wType)
+{
+ int len = strlennull(str) + 1;
+
+ *buf = (PBYTE)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 ppackTLVLNTSfromDB(PBYTE *buf, int *buflen, const char *szSetting, WORD wType)
+{
+ char szTmp[1024];
+ char *str = "";
+
+ if (!ICQGetContactStaticString(NULL, szSetting, szTmp, sizeof(szTmp)))
+ str = szTmp;
+
+ ppackTLVLNTS(buf, buflen, str, wType, 1);
+}
+
+
+
+void ppackTLVWordLNTSfromDB(PBYTE *buf, int *buflen, WORD w, const char *szSetting, WORD wType)
+{
+ char szTmp[1024];
+ char *str = "";
+
+ if (!ICQGetContactStaticString(NULL, szSetting, szTmp, sizeof(szTmp)))
+ str = szTmp;
+
+ ppackTLVWordLNTS(buf, buflen, w, str, wType, 1);
+}
+
+
+
+void ppackTLVLNTSBytefromDB(PBYTE *buf, int *buflen, const char *szSetting, BYTE b, WORD wType)
+{
+ char szTmp[1024];
+ char *str = "";
+
+ if (!ICQGetContactStaticString(NULL, szSetting, szTmp, sizeof(szTmp)))
+ str = szTmp;
+
+ ppackTLVLNTSByte(buf, buflen, str, b, wType);
+}
+
+
+
+void __fastcall unpackByte(BYTE** pSource, BYTE* byDestination)
+{
+ if (byDestination)
+ {
+ *byDestination = *(*pSource)++;
+ }
+ else
+ {
+ *pSource += 1;
+ }
+}
+
+
+
+void __fastcall unpackWord(BYTE** pSource, WORD* wDestination)
+{
+ unsigned char *tmp = *pSource;
+
+ if (wDestination)
+ {
+ *wDestination = *tmp++ << 8;
+ *wDestination |= *tmp++;
+
+ *pSource = tmp;
+ }
+ else
+ {
+ *pSource += 2;
+ }
+}
+
+
+
+void __fastcall unpackDWord(BYTE** pSource, DWORD* dwDestination)
+{
+ unsigned char *tmp = *pSource;
+
+ if (dwDestination)
+ {
+ *dwDestination = *tmp++ << 24;
+ *dwDestination |= *tmp++ << 16;
+ *dwDestination |= *tmp++ << 8;
+ *dwDestination |= *tmp++;
+
+ *pSource = tmp;
+ }
+ else
+ {
+ *pSource += 4;
+ }
+}
+
+
+
+void __fastcall unpackLEWord(unsigned char **buf, WORD *w)
+{
+ unsigned char *tmp = *buf;
+
+ if (w)
+ {
+ *w = (*tmp++);
+ *w |= ((*tmp++) << 8);
+ }
+ else
+ tmp += 2;
+
+ *buf = tmp;
+}
+
+
+
+void __fastcall unpackLEDWord(unsigned char **buf, DWORD *dw)
+{
+ unsigned char *tmp = *buf;
+
+ if (dw)
+ {
+ *dw = (*tmp++);
+ *dw |= ((*tmp++) << 8);
+ *dw |= ((*tmp++) << 16);
+ *dw |= ((*tmp++) << 24);
+ }
+ else
+ tmp += 4;
+
+ *buf = tmp;
+}
+
+
+
+void unpackString(unsigned char **buf, char *string, WORD len)
+{
+ unsigned char *tmp = *buf;
+
+ if (string)
+ {
+ while (len) /* Can have 0x00 so go by len */
+ {
+ *string++ = *tmp++;
+ len--;
+ }
+ }
+ else
+ tmp += len;
+
+ *buf = tmp;
+}
+
+
+
+void unpackWideString(unsigned char **buf, WCHAR *string, WORD len)
+{
+ unsigned char *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(unsigned char **buf, int buflen, WORD type, WORD *ttype, WORD *tlen, char **tlv)
+{
+ WORD wType, wLen;
+ unsigned char *tmp = *buf;
+
+NextTLV:
+ // Unpack type and length
+ unpackWord(&tmp, &wType);
+ unpackWord(&tmp, &wLen);
+ buflen -= 4;
+
+ if (wType != type && buflen >= wLen + 4)
+ { // Not the right TLV, try next
+ buflen -= wLen;
+ tmp += wLen;
+ goto NextTLV;
+ }
+ // Check buffer size
+ if (wLen > buflen) wLen = buflen;
+
+ // Make sure we have a good pointer
+ if (tlv)
+ {
+ // Unpack and save value
+ *tlv = (char *)SAFE_MALLOC(wLen + 1); // Add 1 for \0
+ unpackString(&tmp, *tlv, wLen);
+ *(*tlv + wLen) = '\0';
+ }
+ else
+ {
+ *tmp += wLen;
+ }
+
+ // Save type and length
+ if (ttype)
+ *ttype = wType;
+ if (tlen)
+ *tlen = wLen;
+
+ // Increase source pointer
+ *buf = tmp;
+}
+
+
+
+BOOL unpackUID(unsigned char** ppBuf, WORD* pwLen, DWORD *pdwUIN, uid_str* ppszUID)
+{
+ BYTE nUIDLen;
+ char szUIN[UINMAXLEN+1];
+
+ // Sender UIN
+ unpackByte(ppBuf, &nUIDLen);
+ *pwLen -= 1;
+
+ if ((nUIDLen > *pwLen) || (nUIDLen == 0))
+ return FALSE;
+
+ if (nUIDLen <= UINMAXLEN)
+ { // it can be uin, check
+ unpackString(ppBuf, szUIN, nUIDLen);
+ szUIN[nUIDLen] = '\0';
+ *pwLen -= nUIDLen;
+
+ if (IsStringUIN(szUIN))
+ {
+ *pdwUIN = atoi(szUIN);
+ return TRUE;
+ }
+ else if (!ppszUID || !gbAimEnabled)
+ {
+ NetLog_Server("Malformed UIN in packet");
+ return FALSE;
+ }
+ else
+ { // go back
+ *ppBuf -= nUIDLen;
+ *pwLen += nUIDLen;
+ }
+ }
+ else if (!ppszUID || ! gbAimEnabled)
+ {
+ NetLog_Server("Malformed UIN in packet");
+ return FALSE;
+ }
+ if (!(*ppszUID)) 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/miranda-wine/protocols/IcqOscarJ/icq_packet.h b/miranda-wine/protocols/IcqOscarJ/icq_packet.h
new file mode 100644
index 0000000..9cfd428
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_packet.h
@@ -0,0 +1,114 @@
+// ---------------------------------------------------------------------------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, 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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_packet.h,v $
+// Revision : $Revision: 3663 $
+// Last change on : $Date: 2006-08-31 00:18:59 +0400 (Чтв, 31 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// 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 *--------------*/
+
+typedef struct icq_packet_s
+{
+ WORD wPlace;
+ BYTE nChannel;
+ WORD wSequence;
+ WORD wLen;
+ BYTE *pData;
+} icq_packet;
+
+/*---------* Functions *---------------*/
+
+void __fastcall init_generic_packet(icq_packet* pPacket, WORD wHeaderLen);
+void write_httphdr(icq_packet *d, WORD wType, DWORD dwSeq);
+void __fastcall write_flap(icq_packet *, BYTE);
+void __fastcall serverPacketInit(icq_packet *, WORD);
+void __fastcall directPacketInit(icq_packet *, DWORD);
+
+void __fastcall serverCookieInit(icq_packet *, BYTE *, WORD);
+
+void __fastcall packByte(icq_packet *, BYTE);
+void __fastcall packWord(icq_packet *, WORD);
+void __fastcall packDWord(icq_packet *, DWORD);
+void packTLV(icq_packet* pPacket, WORD wType, WORD wLength, BYTE* pbyValue);
+void packTLVWord(icq_packet *d, unsigned short nType, WORD wData);
+void packTLVDWord(icq_packet *d, unsigned short nType, DWORD dwData);
+
+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, char* szUid);
+void __fastcall packUIN(icq_packet *pPacket, DWORD dwUin);
+void __fastcall packUID(icq_packet *pPacket, DWORD dwUin, char* szUid);
+void packFNACHeader(icq_packet *d, WORD wFamily, WORD wSubtype);
+void packFNACHeaderFull(icq_packet *d, WORD wFamily, WORD wSubtype, WORD wFlags, DWORD wSeq);
+
+void __fastcall packLEWord(icq_packet *, WORD);
+void __fastcall packLEDWord(icq_packet *, DWORD);
+
+void packTLVLNTS(PBYTE *buf, int *bufpos, const char *str, WORD wType);
+
+void ppackByte(PBYTE *buf,int *buflen,BYTE b);
+void ppackLEWord(PBYTE *buf,int *buflen,WORD w);
+void ppackLEDWord(PBYTE *buf,int *buflen,DWORD d);
+void ppackLELNTS(PBYTE *buf, int *buflen, const char *str);
+void ppackLELNTSfromDB(PBYTE *buf, int *buflen, const char *szSetting);
+
+void ppackTLVByte(PBYTE *buf, int *buflen, BYTE b, WORD wType, BYTE always);
+void ppackTLVWord(PBYTE *buf, int *buflen, WORD w, WORD wType, BYTE always);
+void ppackTLVDWord(PBYTE *buf, int *buflen, DWORD d, WORD wType, BYTE always);
+void ppackTLVLNTS(PBYTE *buf, int *buflen, const char *str, WORD wType, BYTE always);
+void ppackTLVWordLNTS(PBYTE *buf, int *buflen, WORD w, const char *str, WORD wType, BYTE always);
+void ppackTLVLNTSByte(PBYTE *buf, int *buflen, const char *str, BYTE b, WORD wType);
+
+void ppackTLVLNTSfromDB(PBYTE *buf, int *buflen, const char *szSetting, WORD wType);
+void ppackTLVWordLNTSfromDB(PBYTE *buf, int *buflen, WORD w, const char *szSetting, WORD wType);
+void ppackTLVLNTSBytefromDB(PBYTE *buf, int *buflen, const char *szSetting, BYTE b, WORD wType);
+
+void __fastcall unpackByte(unsigned char **, BYTE *);
+void __fastcall unpackWord(unsigned char **, WORD *);
+void __fastcall unpackDWord(unsigned char **, DWORD *);
+void unpackString(unsigned char **buf, char *string, WORD len);
+void unpackWideString(unsigned char **buf, WCHAR *string, WORD len);
+void unpackTypedTLV(unsigned char **, int, WORD, WORD *, WORD *, char **);
+BOOL unpackUID(unsigned char** ppBuf, WORD* pwLen, DWORD *pdwUIN, uid_str* ppszUID);
+
+void __fastcall unpackLEWord(unsigned char **, WORD *);
+void __fastcall unpackLEDWord(unsigned char **, DWORD *);
+
+#endif /* __ICQ_PACKET_H */
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_popups.c b/miranda-wine/protocols/IcqOscarJ/icq_popups.c
new file mode 100644
index 0000000..192c76c
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_popups.c
@@ -0,0 +1,279 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_popups.c,v $
+// Revision : $Revision: 3463 $
+// Last change on : $Date: 2006-08-05 17:01:41 +0400 (Сбт, 05 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// PopUp Plugin stuff
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+#include "m_popupw.h"
+
+
+static BOOL bPopUpService = FALSE;
+
+static BOOL CALLBACK DlgProcIcqPopupOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+
+void InitPopUps()
+{
+ if (ServiceExists(MS_POPUP_ADDPOPUPEX))
+ {
+ bPopUpService = TRUE;
+ }
+}
+
+
+
+void InitPopupOpts(WPARAM wParam)
+{
+ OPTIONSDIALOGPAGE odp = {0};
+
+ if (bPopUpService)
+ {
+ odp.cbSize = sizeof(odp);
+ odp.position = 100000000;
+ odp.hInstance = hInst;
+ odp.pszTemplate = MAKEINTRESOURCE(IDD_OPT_POPUPS);
+ odp.groupPosition = 900000000;
+ odp.pfnDlgProc = DlgProcIcqPopupOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.nIDBottomSimpleControl = 0;
+ AddOptionsPageUtf(&odp, wParam, "Popups", gpszICQProtoName);
+ }
+}
+
+
+static const UINT icqPopupsControls[] = {IDC_POPUPS_LOG_ENABLED,IDC_POPUPS_SPAM_ENABLED,IDC_PREVIEW,IDC_USEWINCOLORS,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};
+static BOOL CALLBACK DlgProcIcqPopupOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ BYTE bEnabled;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ ICQTranslateDialog(hwndDlg);
+ CheckDlgButton(hwndDlg, IDC_POPUPS_LOG_ENABLED, ICQGetContactSettingByte(NULL,"PopupsLogEnabled",DEFAULT_LOG_POPUPS_ENABLED));
+ CheckDlgButton(hwndDlg, IDC_POPUPS_SPAM_ENABLED, ICQGetContactSettingByte(NULL,"PopupsSpamEnabled",DEFAULT_SPAM_POPUPS_ENABLED));
+ SendDlgItemMessage(hwndDlg, IDC_POPUP_LOG0_TEXTCOLOR, CPM_SETCOLOUR, 0, ICQGetContactSettingDword(NULL,"Popups0TextColor",DEFAULT_LOG0_TEXT_COLORS));
+ SendDlgItemMessage(hwndDlg, IDC_POPUP_LOG0_BACKCOLOR, CPM_SETCOLOUR, 0, ICQGetContactSettingDword(NULL,"Popups0BackColor",DEFAULT_LOG0_BACK_COLORS));
+ SetDlgItemInt(hwndDlg, IDC_POPUP_LOG0_TIMEOUT, ICQGetContactSettingDword(NULL,"Popups0Timeout",DEFAULT_LOG0_TIMEOUT),FALSE);
+ SendDlgItemMessage(hwndDlg, IDC_POPUP_LOG1_TEXTCOLOR, CPM_SETCOLOUR, 0, ICQGetContactSettingDword(NULL,"Popups1TextColor",DEFAULT_LOG1_TEXT_COLORS));
+ SendDlgItemMessage(hwndDlg, IDC_POPUP_LOG1_BACKCOLOR, CPM_SETCOLOUR, 0, ICQGetContactSettingDword(NULL,"Popups1BackColor",DEFAULT_LOG1_BACK_COLORS));
+ SetDlgItemInt(hwndDlg, IDC_POPUP_LOG1_TIMEOUT, ICQGetContactSettingDword(NULL,"Popups1Timeout",DEFAULT_LOG1_TIMEOUT),FALSE);
+ SendDlgItemMessage(hwndDlg, IDC_POPUP_LOG2_TEXTCOLOR, CPM_SETCOLOUR, 0, ICQGetContactSettingDword(NULL,"Popups2TextColor",DEFAULT_LOG2_TEXT_COLORS));
+ SendDlgItemMessage(hwndDlg, IDC_POPUP_LOG2_BACKCOLOR, CPM_SETCOLOUR, 0, ICQGetContactSettingDword(NULL,"Popups2BackColor",DEFAULT_LOG2_BACK_COLORS));
+ SetDlgItemInt(hwndDlg, IDC_POPUP_LOG2_TIMEOUT, ICQGetContactSettingDword(NULL,"Popups2Timeout",DEFAULT_LOG2_TIMEOUT),FALSE);
+ SendDlgItemMessage(hwndDlg, IDC_POPUP_LOG3_TEXTCOLOR, CPM_SETCOLOUR, 0, ICQGetContactSettingDword(NULL,"Popups3TextColor",DEFAULT_LOG3_TEXT_COLORS));
+ SendDlgItemMessage(hwndDlg, IDC_POPUP_LOG3_BACKCOLOR, CPM_SETCOLOUR, 0, ICQGetContactSettingDword(NULL,"Popups3BackColor",DEFAULT_LOG3_BACK_COLORS));
+ SetDlgItemInt(hwndDlg, IDC_POPUP_LOG3_TIMEOUT, ICQGetContactSettingDword(NULL,"Popups3Timeout",DEFAULT_LOG3_TIMEOUT),FALSE);
+ SendDlgItemMessage(hwndDlg, IDC_POPUP_SPAM_TEXTCOLOR, CPM_SETCOLOUR, 0, ICQGetContactSettingDword(NULL,"PopupsSpamTextColor",DEFAULT_SPAM_TEXT_COLORS));
+ SendDlgItemMessage(hwndDlg, IDC_POPUP_SPAM_BACKCOLOR, CPM_SETCOLOUR, 0, ICQGetContactSettingDword(NULL,"PopupsSpamBackColor",DEFAULT_SPAM_BACK_COLORS));
+ SetDlgItemInt(hwndDlg, IDC_POPUP_SPAM_TIMEOUT, ICQGetContactSettingDword(NULL,"PopupsSpamTimeout",DEFAULT_SPAM_TIMEOUT),FALSE);
+ bEnabled = ICQGetContactSettingByte(NULL,"PopupsWinColors",DEFAULT_POPUPS_WIN_COLORS);
+ CheckDlgButton(hwndDlg, IDC_USEWINCOLORS, bEnabled);
+ icq_EnableMultipleControls(hwndDlg, icqPopupColorControls, sizeof(icqPopupColorControls)/sizeof(icqPopupColorControls[0]), bEnabled);
+ CheckDlgButton(hwndDlg, IDC_USESYSICONS, ICQGetContactSettingByte(NULL,"PopupsSysIcons",DEFAULT_POPUPS_SYS_ICONS));
+ bEnabled = ICQGetContactSettingByte(NULL,"PopupsEnabled",DEFAULT_POPUPS_ENABLED);
+ CheckDlgButton(hwndDlg, IDC_POPUPS_ENABLED, bEnabled);
+ icq_EnableMultipleControls(hwndDlg, icqPopupsControls, sizeof(icqPopupsControls)/sizeof(icqPopupsControls[0]), bEnabled);
+ icq_EnableMultipleControls(hwndDlg, icqPopupColorControls, sizeof(icqPopupColorControls)/sizeof(icqPopupColorControls[0]), bEnabled);
+
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDC_PREVIEW:
+ {
+ ShowPopUpMsg(NULL, "Popup Title", "Sample Note", LOG_NOTE);
+ ShowPopUpMsg(NULL, "Popup Title", "Sample Warning", LOG_WARNING);
+ ShowPopUpMsg(NULL, "Popup Title", "Sample Error", LOG_ERROR);
+ ShowPopUpMsg(NULL, "Popup Title", "Sample Fatal", LOG_FATAL);
+ ShowPopUpMsg(NULL, "Popup Title", "Sample Spambot", POPTYPE_SPAM);
+ }
+ return FALSE;
+
+ case IDC_POPUPS_ENABLED:
+ bEnabled = IsDlgButtonChecked(hwndDlg,IDC_POPUPS_ENABLED);
+ icq_EnableMultipleControls(hwndDlg, icqPopupsControls, sizeof(icqPopupsControls)/sizeof(icqPopupsControls[0]), bEnabled);
+ icq_EnableMultipleControls(hwndDlg, icqPopupColorControls, sizeof(icqPopupColorControls)/sizeof(icqPopupColorControls[0]), bEnabled & IsDlgButtonChecked(hwndDlg,IDC_POPUPS_ENABLED));
+ break;
+
+ case IDC_USEWINCOLORS:
+ bEnabled = IsDlgButtonChecked(hwndDlg,IDC_POPUPS_ENABLED);
+ icq_EnableMultipleControls(hwndDlg, icqPopupColorControls, sizeof(icqPopupColorControls)/sizeof(icqPopupColorControls[0]), bEnabled);
+ break;
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case PSN_APPLY:
+ ICQWriteContactSettingByte(NULL,"PopupsEnabled",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_POPUPS_ENABLED));
+ ICQWriteContactSettingByte(NULL,"PopupsLogEnabled",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_POPUPS_LOG_ENABLED));
+ ICQWriteContactSettingByte(NULL,"PopupsSpamEnabled",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_POPUPS_SPAM_ENABLED));
+ ICQWriteContactSettingDword(NULL,"Popups0TextColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_LOG0_TEXTCOLOR,CPM_GETCOLOUR,0,0));
+ ICQWriteContactSettingDword(NULL,"Popups0BackColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_LOG0_BACKCOLOR,CPM_GETCOLOUR,0,0));
+ ICQWriteContactSettingDword(NULL,"Popups0Timeout",GetDlgItemInt(hwndDlg, IDC_POPUP_LOG0_TIMEOUT, NULL, FALSE));
+ ICQWriteContactSettingDword(NULL,"Popups1TextColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_LOG1_TEXTCOLOR,CPM_GETCOLOUR,0,0));
+ ICQWriteContactSettingDword(NULL,"Popups1BackColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_LOG1_BACKCOLOR,CPM_GETCOLOUR,0,0));
+ ICQWriteContactSettingDword(NULL,"Popups1Timeout",GetDlgItemInt(hwndDlg, IDC_POPUP_LOG1_TIMEOUT, NULL, FALSE));
+ ICQWriteContactSettingDword(NULL,"Popups2TextColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_LOG2_TEXTCOLOR,CPM_GETCOLOUR,0,0));
+ ICQWriteContactSettingDword(NULL,"Popups2BackColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_LOG2_BACKCOLOR,CPM_GETCOLOUR,0,0));
+ ICQWriteContactSettingDword(NULL,"Popups2Timeout",GetDlgItemInt(hwndDlg, IDC_POPUP_LOG2_TIMEOUT, NULL, FALSE));
+ ICQWriteContactSettingDword(NULL,"Popups3TextColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_LOG3_TEXTCOLOR,CPM_GETCOLOUR,0,0));
+ ICQWriteContactSettingDword(NULL,"Popups3BackColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_LOG3_BACKCOLOR,CPM_GETCOLOUR,0,0));
+ ICQWriteContactSettingDword(NULL,"Popups3Timeout",GetDlgItemInt(hwndDlg, IDC_POPUP_LOG3_TIMEOUT, NULL, FALSE));
+ ICQWriteContactSettingDword(NULL,"PopupsSpamTextColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_SPAM_TEXTCOLOR,CPM_GETCOLOUR,0,0));
+ ICQWriteContactSettingDword(NULL,"PopupsSpamBackColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_SPAM_BACKCOLOR,CPM_GETCOLOUR,0,0));
+ ICQWriteContactSettingDword(NULL,"PopupsSpamTimeout",GetDlgItemInt(hwndDlg, IDC_POPUP_SPAM_TIMEOUT, NULL, FALSE));
+ ICQWriteContactSettingByte(NULL,"PopupsWinColors",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_USEWINCOLORS));
+ ICQWriteContactSettingByte(NULL,"PopupsSysIcons",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_USESYSICONS));
+
+ return TRUE;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+
+
+int ShowPopUpMsg(HANDLE hContact, const char* szTitle, const char* szMsg, BYTE bType)
+{
+ if (bPopUpService && ICQGetContactSettingByte(NULL, "PopupsEnabled", DEFAULT_POPUPS_ENABLED))
+ {
+ POPUPDATAEX ppd = {0};
+ POPUPDATAW ppdw = {0};
+ LPCTSTR rsIcon;
+ HINSTANCE hIcons = NULL;
+ 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 (!ICQGetContactSettingByte(NULL, "PopupsSysIcons", DEFAULT_POPUPS_SYS_ICONS))
+ {
+ hIcons = hInst;
+ rsIcon = MAKEINTRESOURCE(IDI_ICQ);
+ }
+ ppd.lchIcon = (HICON)LoadImage(hIcons, rsIcon, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED);
+ strcpy(szSetting, szPrefix);
+ strcat(szSetting, "TextColor");
+ ppd.colorText = ICQGetContactSettingDword(NULL, szSetting, ppd.colorText);
+ strcpy(szSetting, szPrefix);
+ strcat(szSetting, "BackColor");
+ ppd.colorBack = ICQGetContactSettingDword(NULL, szSetting, ppd.colorBack);
+ strcpy(szSetting, szPrefix);
+ strcat(szSetting, "Timeout");
+ ppd.iSeconds = ICQGetContactSettingDword(NULL, szSetting, ppd.iSeconds);
+
+ if (gbUnicodeAPI && ServiceExists(MS_POPUP_ADDPOPUPW))
+ { // call unicode popup module - only on unicode OS otherwise it will not work properly :(
+ // due to Popup Plug bug in ADDPOPUPW implementation
+ wchar_t *tmp;
+ char str[MAX_SECONDLINE];
+
+ tmp = make_unicode_string(ICQTranslateUtfStatic(szTitle, str));
+ memmove(ppdw.lpwzContactName, tmp, wcslen(tmp)*sizeof(wchar_t));
+ SAFE_FREE(&tmp);
+ tmp = make_unicode_string(ICQTranslateUtfStatic(szMsg, str));
+ memmove(ppdw.lpwzText, tmp, wcslen(tmp)*sizeof(wchar_t));
+ SAFE_FREE(&tmp);
+ 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_SECONDLINE];
+
+ utf8_decode_static(ICQTranslateUtfStatic(szTitle, str), ppd.lpzContactName, MAX_CONTACTNAME);
+ utf8_decode_static(ICQTranslateUtfStatic(szMsg, str), 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/miranda-wine/protocols/IcqOscarJ/icq_popups.h b/miranda-wine/protocols/IcqOscarJ/icq_popups.h
new file mode 100644
index 0000000..f031aba
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_popups.h
@@ -0,0 +1,50 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_popups.h,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// 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);
+
+int ShowPopUpMsg(HANDLE hContact, const char* szTitle, const char* szMsg, BYTE bType);
+
+
+#endif /* __ICQ_POPUPS_H */
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_rates.c b/miranda-wine/protocols/IcqOscarJ/icq_rates.c
new file mode 100644
index 0000000..db47512
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_rates.c
@@ -0,0 +1,330 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_rates.c,v $
+// Revision : $Revision: 3343 $
+// Last change on : $Date: 2006-07-19 03:36:21 +0400 (Срд, 19 Июл 2006) $
+// Last change by : $Author: rainwater $
+//
+// DESCRIPTION:
+//
+// Rate Management stuff
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+// links to functions that are under Rate Control
+extern DWORD sendXStatusDetailsRequest(HANDLE hContact, int bForced);
+
+static int rGroupXtrazRequest = 4500; // represents higher limits for ICQ Rate Group #3
+static int tGroupXtrazRequest;
+static int rGroupMsgResponse = 6000; // dtto #1
+static int tGroupMsgResponse;
+
+static CRITICAL_SECTION ratesMutex; // we need to be thread safe
+
+static rate_record **pendingList1; // rate queue for xtraz requests
+static int pendingListSize1;
+
+static rate_record **pendingList2; // rate queue for msg responses
+static int pendingListSize2;
+
+
+
+typedef struct rate_delay_args_s
+{
+ int nDelay;
+ void (*delaycode)();
+} rate_delay_args;
+
+void __cdecl rateDelayThread(rate_delay_args* pArgs)
+{
+ SleepEx(pArgs->nDelay, TRUE);
+ pArgs->delaycode();
+
+ SAFE_FREE(&pArgs);
+ return;
+}
+
+
+
+void InitDelay(int nDelay, void (*delaycode)())
+{
+ rate_delay_args* pArgs;
+
+//#ifdef _DEBUG
+ NetLog_Server("Delay %dms", nDelay);
+//#endif
+
+ pArgs = (rate_delay_args*)SAFE_MALLOC(sizeof(rate_delay_args)); // This will be freed in the new thread
+
+ pArgs->nDelay = nDelay;
+ pArgs->delaycode = delaycode;
+
+ forkthread(rateDelayThread, 0, pArgs);
+}
+
+
+
+static void RatesTimer1()
+{
+ rate_record *item;
+ int nLev;
+
+ if (!pendingList1) return;
+
+ EnterCriticalSection(&ratesMutex);
+ // take from queue, execute
+ item = pendingList1[0];
+ if (pendingListSize1 > 1)
+ { // we need to keep order
+ memmove(&pendingList1[0], &pendingList1[1], (pendingListSize1 - 1)*sizeof(rate_record*));
+ }
+ else
+ SAFE_FREE((void**)&pendingList1);
+ pendingListSize1--;
+ nLev = rGroupXtrazRequest*19/20 + (GetTickCount() - tGroupXtrazRequest)/20;
+ rGroupXtrazRequest = nLev < 4500 ? nLev : 4500;
+ tGroupXtrazRequest = GetTickCount();
+ if (pendingListSize1 && icqOnline)
+ { // in queue remains some items, setup timer
+ int nDelay = (3800 - rGroupXtrazRequest)*20;
+
+ if (nDelay < 10) nDelay = 10;
+ InitDelay(nDelay, RatesTimer1);
+ }
+ if (!icqOnline)
+ {
+ int i;
+
+ for (i=0; i<pendingListSize1; i++) SAFE_FREE(&pendingList1[i]);
+ SAFE_FREE((void**)&pendingList1);
+ pendingListSize1 = 0;
+ }
+ LeaveCriticalSection(&ratesMutex);
+
+ if (icqOnline)
+ {
+ NetLog_Server("Rates: Resuming Xtraz request.");
+ if (item->bType = RIT_XSTATUS_REQUEST)
+ sendXStatusDetailsRequest(item->hContact, FALSE);
+ }
+ else
+ NetLog_Server("Rates: Discarding request.");
+ SAFE_FREE(&item);
+}
+
+
+
+static void putItemToQueue1(rate_record *item, int nLev)
+{
+ int nDelay = (3800 - nLev)*20;
+
+ if (!icqOnline) return;
+
+ NetLog_Server("Rates: Delaying operation.");
+
+ if (pendingListSize1)
+ { // something already in queue, check duplicity
+ rate_record *tmp;
+ int i;
+
+ for (i = 0; i < pendingListSize1; i++)
+ { // TODO: make this more universal - for more xtraz msg types
+ if (pendingList1[i]->hContact == item->hContact)
+ return; // request xstatus from same contact, do it only once
+ }
+ pendingListSize1++;
+ pendingList1 = (rate_record**)realloc(pendingList1, pendingListSize1*sizeof(rate_record*));
+ tmp = (rate_record*)SAFE_MALLOC(sizeof(rate_record));
+ memcpy(tmp, item, sizeof(rate_record));
+ pendingList1[pendingListSize1 - 1] = tmp;
+ }
+ else
+ {
+ rate_record *tmp;
+
+ pendingListSize1++;
+ pendingList1 = (rate_record**)SAFE_MALLOC(sizeof(rate_record*));
+ tmp = (rate_record*)SAFE_MALLOC(sizeof(rate_record));
+ memcpy(tmp, item, sizeof(rate_record));
+ pendingList1[0] = tmp;
+
+ if (nDelay < 10) nDelay = 10;
+ if (nDelay < item->nMinDelay) nDelay = item->nMinDelay;
+ InitDelay(nDelay, RatesTimer1);
+ }
+}
+
+
+
+static void RatesTimer2()
+{
+ rate_record *item;
+ int nLev;
+
+ if (!pendingList2) return;
+
+ EnterCriticalSection(&ratesMutex);
+ // take from queue, execute
+ item = pendingList2[0];
+ if (pendingListSize2 > 1)
+ { // we need to keep order
+ memmove(&pendingList2[0], &pendingList2[1], (pendingListSize2 - 1)*sizeof(rate_record*));
+ }
+ else
+ SAFE_FREE((void**)&pendingList2);
+ pendingListSize2--;
+ nLev = rGroupMsgResponse*79/80 + (GetTickCount() - tGroupMsgResponse)/80;
+ rGroupMsgResponse = nLev < 6000 ? nLev : 6000;
+ tGroupMsgResponse = GetTickCount();
+ if (pendingListSize2 && icqOnline)
+ { // in queue remains some items, setup timer
+ int nDelay = (4500 - rGroupMsgResponse)*80;
+
+ if (nDelay < 10) nDelay = 10;
+ InitDelay(nDelay, RatesTimer2);
+ }
+ if (!icqOnline)
+ {
+ int i;
+
+ for (i=0; i<pendingListSize2; i++) SAFE_FREE(&pendingList2[i]);
+ SAFE_FREE((void**)&pendingList2);
+ pendingListSize2 = 0;
+ }
+ LeaveCriticalSection(&ratesMutex);
+
+ if (icqOnline)
+ {
+ NetLog_Server("Rates: Resuming message response.");
+ if (item->bType == RIT_AWAYMSG_RESPONSE)
+ {
+ icq_sendAwayMsgReplyServ(item->dwUin, item->dwMid1, item->dwMid2, item->wCookie, item->wVersion, item->msgType, MirandaStatusToAwayMsg(AwayMsgTypeToStatus(item->msgType)));
+ }
+ else if (item->bType == RIT_XSTATUS_RESPONSE)
+ {
+ SendXtrazNotifyResponse(item->dwUin, item->dwMid1, item->dwMid2, item->wCookie, item->szData, strlennull(item->szData), item->bThruDC);
+ }
+ }
+ else
+ NetLog_Server("Rates: Discarding response.");
+ SAFE_FREE(&item->szData);
+ SAFE_FREE(&item);
+}
+
+
+
+static void putItemToQueue2(rate_record *item, int nLev)
+{
+ int nDelay = (4500 - nLev)*80;
+ rate_record *tmp;
+
+ if (!icqOnline) return;
+
+ NetLog_Server("Rates: Delaying operation.");
+
+ pendingListSize2++;
+ pendingList2 = (rate_record**)realloc(pendingList2, pendingListSize2*sizeof(rate_record*));
+ tmp = (rate_record*)SAFE_MALLOC(sizeof(rate_record));
+ memcpy(tmp, item, sizeof(rate_record));
+ tmp->szData = null_strdup(item->szData);
+ pendingList2[pendingListSize2 - 1] = tmp;
+
+ if (pendingListSize2 == 1)
+ { // queue was empty setup timer
+ if (nDelay < 10) nDelay = 10;
+ InitDelay(nDelay, RatesTimer2);
+ }
+}
+
+
+
+int handleRateItem(rate_record *item, BOOL bAllowDelay)
+{
+ int tNow = GetTickCount();
+
+ EnterCriticalSection(&ratesMutex);
+
+ if (item->rate_group == 0x101)
+ { // xtraz request
+ int nLev = rGroupXtrazRequest*19/20 + (tNow - tGroupXtrazRequest)/20;
+
+ if ((nLev < 3800 || item->nMinDelay) && bAllowDelay)
+ { // limit reached or min delay configured, add to queue
+ putItemToQueue1(item, nLev);
+ LeaveCriticalSection(&ratesMutex);
+ return 1;
+ }
+ else
+ {
+ rGroupXtrazRequest = nLev < 4500 ? nLev : 4500;
+ tGroupXtrazRequest = tNow;
+ }
+ }
+ else if (item->rate_group == 0x102)
+ { // msg response
+ int nLev = rGroupMsgResponse*79/80 + (tNow - tGroupMsgResponse)/80;
+
+ if (nLev < 4500)
+ { // limit reached or min delay configured, add to queue
+ putItemToQueue2(item, nLev);
+ LeaveCriticalSection(&ratesMutex);
+ return 1;
+ }
+ else
+ {
+ rGroupMsgResponse = nLev < 6000 ? nLev : 6000;
+ tGroupMsgResponse = tNow;
+ }
+ }
+ LeaveCriticalSection(&ratesMutex);
+
+ return 0;
+}
+
+
+
+void InitRates()
+{
+ InitializeCriticalSection(&ratesMutex);
+
+ pendingListSize1 = 0;
+ pendingList1 = NULL;
+ pendingListSize2 = 0;
+ pendingList2 = NULL;
+
+ tGroupXtrazRequest = tGroupMsgResponse = GetTickCount();
+}
+
+
+
+void UninitRates()
+{
+ SAFE_FREE((void**)&pendingList1);
+ SAFE_FREE((void**)&pendingList2);
+ DeleteCriticalSection(&ratesMutex);
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_rates.h b/miranda-wine/protocols/IcqOscarJ/icq_rates.h
new file mode 100644
index 0000000..0265c4f
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_rates.h
@@ -0,0 +1,68 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_rates.h,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#ifndef __ICQ_RATES_H
+#define __ICQ_RATES_H
+
+
+#define RIT_AWAYMSG_RESPONSE 0x01 // response to status msg request
+
+#define RIT_XSTATUS_REQUEST 0x10 // schedule xstatus details requests
+#define RIT_XSTATUS_RESPONSE 0x11 // response to xstatus details request
+
+typedef struct rate_record_s
+{
+ BYTE bType; // type of request
+ int rate_group;
+ int nMinDelay;
+ HANDLE hContact;
+ DWORD dwUin;
+ DWORD dwMid1;
+ DWORD dwMid2;
+ WORD wCookie;
+ WORD wVersion;
+ BOOL bThruDC;
+ char *szData;
+ BYTE msgType;
+} rate_record;
+
+// Level 2 of rate management
+int handleRateItem(rate_record *item, BOOL bAllowDelay);
+
+void InitRates();
+void UninitRates();
+
+#endif /* __ICQ_RATES_H */
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_server.c b/miranda-wine/protocols/IcqOscarJ/icq_server.c
new file mode 100644
index 0000000..b1a4c63
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_server.c
@@ -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,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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_server.c,v $
+// Revision : $Revision: 3663 $
+// Last change on : $Date: 2006-08-31 00:18:59 +0400 (Чтв, 31 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Manages main server connection, low-level communication
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+
+extern void handleXStatusCaps(HANDLE hContact, char* caps, int capsize);
+
+extern CRITICAL_SECTION connectionHandleMutex;
+extern WORD wLocalSequence;
+extern CRITICAL_SECTION localSeqMutex;
+HANDLE hServerConn;
+WORD wListenPort;
+WORD wLocalSequence;
+DWORD dwLocalDirectConnCookie;
+HANDLE hServerPacketRecver;
+static pthread_t serverThreadId;
+HANDLE hDirectBoundPort;
+
+static int handleServerPackets(unsigned char* buf, int len, serverthread_info* info);
+
+
+static DWORD __stdcall icq_serverThread(serverthread_start_info* infoParam)
+{
+ serverthread_info info = {0};
+
+ info.isLoginServer = 1;
+ info.wAuthKeyLen = infoParam->wPassLen;
+ strncpy(info.szAuthKey, infoParam->szPass, info.wAuthKeyLen);
+ // store server port
+ info.wServerPort = infoParam->nloc.wPort;
+
+ srand(time(NULL));
+
+ dwLocalDirectConnCookie = rand() ^ (rand() << 16);
+
+ ResetSettingsOnConnect();
+
+ // Connect to the login server
+ NetLog_Server("Authenticating to server");
+ {
+ NETLIBOPENCONNECTION nloc = infoParam->nloc;
+
+ hServerConn = NetLib_OpenConnection(ghServerNetlibUser, &nloc);
+
+ SAFE_FREE((void**)&nloc.szHost);
+ }
+ SAFE_FREE(&infoParam);
+
+
+ // Login error
+ if (hServerConn == NULL)
+ {
+ DWORD dwError = GetLastError();
+
+ hServerConn = NULL;
+
+ SetCurrentStatus(ID_STATUS_OFFLINE);
+
+ icq_LogUsingErrorCode(LOG_ERROR, dwError, "Unable to connect to ICQ login server");
+
+ return 0;
+ }
+
+
+ // Initialize direct connection ports
+ {
+ DWORD dwInternalIP;
+ BYTE bConstInternalIP = ICQGetContactSettingByte(NULL, "ConstRealIP", 0);
+
+ hDirectBoundPort = NetLib_BindPort(icq_newConnectionReceived, NULL, &wListenPort, &dwInternalIP);
+ if (hDirectBoundPort == NULL)
+ {
+ icq_LogUsingErrorCode(LOG_WARNING, GetLastError(), "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) ICQDeleteContactSetting(NULL, "RealIP");
+ }
+ else if (!bConstInternalIP)
+ ICQWriteContactSettingDword(NULL, "RealIP", dwInternalIP);
+ }
+
+
+ // This is the "infinite" loop that receives the packets from the ICQ server
+ {
+ int recvResult;
+ NETLIBPACKETRECVER packetRecv = {0};
+
+ hServerPacketRecver = (HANDLE)CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)hServerConn, 8192);
+ packetRecv.cbSize = sizeof(packetRecv);
+ packetRecv.dwTimeout = INFINITE;
+ while(hServerConn)
+ {
+ 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)hServerPacketRecver, (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;
+ }
+
+ // Deal with the packet
+ packetRecv.bytesUsed = handleServerPackets(packetRecv.buffer, packetRecv.bytesAvailable, &info);
+ }
+
+ // Close the packet receiver (connection may still be open)
+ NetLib_SafeCloseHandle(&hServerPacketRecver, FALSE);
+
+ // Close DC port
+ NetLib_SafeCloseHandle(&hDirectBoundPort, FALSE);
+ }
+
+ // Time to shutdown
+ icq_serverDisconnect(FALSE);
+ if (gnCurrentStatus != ID_STATUS_OFFLINE)
+ {
+ if (!info.bLoggedIn)
+ {
+ icq_LogMessage(LOG_FATAL, "Connection failed.\nLogin sequence failed for unknown reason.\nTry again later.");
+ }
+
+ SetCurrentStatus(ID_STATUS_OFFLINE);
+ }
+
+ // Close all open DC connections
+ CloseContactDirectConns(NULL);
+
+ // Offline all contacts
+ {
+ HANDLE hContact;
+
+ hContact= ICQFindFirstContact();
+
+ while (hContact)
+ {
+ DWORD dwUIN;
+ uid_str szUID;
+
+ if (!ICQGetContactSettingUID(hContact, &dwUIN, &szUID))
+ {
+ if (ICQGetContactStatus(hContact) != ID_STATUS_OFFLINE)
+ {
+ ICQWriteContactSettingWord(hContact, "Status", ID_STATUS_OFFLINE);
+
+ handleXStatusCaps(hContact, NULL, 0);
+ }
+ }
+
+ hContact = ICQFindNextContact(hContact);
+ }
+ }
+ ICQWriteContactSettingDword(NULL, "LogonTS", 0); // clear logon time
+
+ FlushServerIDs(); // clear server IDs list
+ FlushPendingOperations(); // clear pending operations list
+ FlushGroupRenames(); // clear group rename in progress list
+
+ NetLog_Server("%s thread ended.", "Server");
+
+ return 0;
+}
+
+
+
+void icq_serverDisconnect(BOOL bBlock)
+{
+ EnterCriticalSection(&connectionHandleMutex);
+
+ if (hServerConn)
+ {
+ int sck = CallService(MS_NETLIB_GETSOCKET, (WPARAM)hServerConn, (LPARAM)0);
+ if (sck!=INVALID_SOCKET) shutdown(sck, 2); // close gracefully
+ NetLib_SafeCloseHandle(&hServerConn, TRUE);
+ LeaveCriticalSection(&connectionHandleMutex);
+
+ // Not called from network thread?
+ if (bBlock && GetCurrentThreadId() != serverThreadId.dwThreadId)
+ {
+ while (WaitForSingleObjectEx(serverThreadId.hThread, INFINITE, TRUE) != WAIT_OBJECT_0);
+ CloseHandle(serverThreadId.hThread);
+ }
+ else
+ CloseHandle(serverThreadId.hThread);
+ }
+ else
+ LeaveCriticalSection(&connectionHandleMutex);
+
+ StopKeepAlive(); // signal keep-alive thread to stop
+}
+
+
+
+static int handleServerPackets(unsigned char* 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 %s FLAP Channel: Channel %u, Seq %u, Length %u bytes", "Server", channel, sequence, datalen);
+ break;
+ }
+
+ /* Increase pointers so we can check for more FLAPs */
+ buf += datalen;
+ len -= (datalen + 6);
+ bytesUsed += (datalen + 6);
+ }
+
+ return bytesUsed;
+}
+
+
+
+void sendServPacket(icq_packet* pPacket)
+{
+ // This critsec makes sure that the sequence order doesn't get screwed up
+ EnterCriticalSection(&localSeqMutex);
+
+ if (hServerConn)
+ {
+ 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(hServerConn, (const char *)pPacket->pData, pPacket->wLen, 0);
+
+ if (nSendResult != SOCKET_ERROR)
+ break;
+
+ Sleep(1000);
+ }
+
+
+ // Send error
+ if (nSendResult == SOCKET_ERROR)
+ {
+ icq_LogUsingErrorCode(LOG_ERROR, GetLastError(), "Your connection with the ICQ server was abortively closed");
+ icq_serverDisconnect(FALSE);
+
+ if (gnCurrentStatus != ID_STATUS_OFFLINE)
+ {
+ SetCurrentStatus(ID_STATUS_OFFLINE);
+ }
+ }
+ }
+ else
+ {
+ NetLog_Server("Error: Failed to send packet (no connection)");
+ }
+
+ LeaveCriticalSection(&localSeqMutex);
+
+ SAFE_FREE(&pPacket->pData);
+}
+
+
+
+void icq_login(const char* szPassword)
+{
+ DBVARIANT dbvServer = {DBVT_DELETED};
+ char szServer[MAX_PATH];
+ serverthread_start_info* stsi;
+ DWORD dwUin;
+
+
+ dwUin = ICQGetContactSettingUIN(NULL);
+ stsi = (serverthread_start_info*)SAFE_MALLOC(sizeof(serverthread_start_info));
+ stsi->nloc.cbSize = sizeof(NETLIBOPENCONNECTION);
+
+ // Server host name
+ if (ICQGetContactStaticString(NULL, "OscarServer", szServer, MAX_PATH))
+ stsi->nloc.szHost = null_strdup(DEFAULT_SERVER_HOST);
+ else
+ stsi->nloc.szHost = null_strdup(szServer);
+
+ // Server port
+ stsi->nloc.wPort = (WORD)ICQGetContactSettingWord(NULL, "OscarPort", DEFAULT_SERVER_PORT);
+ if (stsi->nloc.wPort == 0)
+ stsi->nloc.wPort = RandRange(1024, 65535);
+
+ // User password
+ stsi->wPassLen = strlennull(szPassword);
+ if (stsi->wPassLen > 9) stsi->wPassLen = 9;
+ strncpy(stsi->szPass, szPassword, stsi->wPassLen);
+ stsi->szPass[stsi->wPassLen] = '\0';
+
+ // Randomize sequence
+ wLocalSequence = (WORD)RandRange(0, 0x7fff);
+
+ dwLocalUIN = dwUin;
+
+ serverThreadId.hThread = (HANDLE)forkthreadex(NULL, 0, icq_serverThread, stsi, 0, &serverThreadId.dwThreadId);
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_server.h b/miranda-wine/protocols/IcqOscarJ/icq_server.h
new file mode 100644
index 0000000..66af397
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_server.h
@@ -0,0 +1,67 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_server.h,v $
+// Revision : $Revision: 3463 $
+// Last change on : $Date: 2006-08-05 17:01:41 +0400 (Сбт, 05 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Declarations for server thread
+//
+// -----------------------------------------------------------------------------
+
+#ifndef __ICQ_SERVER_H
+#define __ICQ_SERVER_H
+
+typedef struct serverthread_start_info_s {
+ NETLIBOPENCONNECTION nloc;
+ WORD wPassLen;
+ char szPass[20];
+} serverthread_start_info;
+
+typedef struct serverthread_info_s {
+ int bLoggedIn;
+ int isLoginServer;
+ BYTE szAuthKey[20];
+ WORD wAuthKeyLen;
+ WORD wServerPort;
+ char *newServer;
+ BYTE* cookieData;
+ int cookieDataLen;
+ int newServerReady;
+ int isMigrating;
+ int bReinitRecver;
+} serverthread_info;
+
+/*---------* Functions *---------------*/
+
+void icq_serverDisconnect(BOOL bBlock);
+void sendServPacket(icq_packet *);
+void icq_login(const char *szPassword);
+
+
+#endif /* __ICQ_SERVER_H */
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_servlist.c b/miranda-wine/protocols/IcqOscarJ/icq_servlist.c
new file mode 100644
index 0000000..567ff62
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_servlist.c
@@ -0,0 +1,1925 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_servlist.c,v $
+// Revision : $Revision: 3119 $
+// Last change on : $Date: 2006-06-12 01:24:04 +0400 (Пнд, 12 Июн 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Functions that handles list of used server IDs, sends low-level packets for SSI information
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+
+extern BOOL bIsSyncingCL;
+
+static HANDLE hHookSettingChanged = NULL;
+static HANDLE hHookContactDeleted = NULL;
+static DWORD* pwIDList = NULL;
+static int nIDListCount = 0;
+static int nIDListSize = 0;
+
+
+
+// cookie struct for pending records
+typedef struct ssipendingitem_t
+{
+ HANDLE hContact;
+ char* szGroupPath;
+ GROUPADDCALLBACK ofCallback;
+ servlistcookie* pCookie;
+} ssipendingitem;
+
+static CRITICAL_SECTION servlistMutex;
+static int nPendingCount = 0;
+static int nPendingSize = 0;
+static ssipendingitem** pdwPendingList = NULL;
+static int nJustAddedCount = 0;
+static int nJustAddedSize = 0;
+static HANDLE* pdwJustAddedList = NULL;
+static WORD* pwGroupRenameList = NULL;
+static int nGroupRenameCount = 0;
+static int nGroupRenameSize = 0;
+
+static DWORD updateServContact(HANDLE hContact);
+
+
+// Add running group rename operation
+void AddGroupRename(WORD wGroupID)
+{
+ EnterCriticalSection(&servlistMutex);
+ if (nGroupRenameCount >= nGroupRenameSize)
+ {
+ nGroupRenameSize += 10;
+ pwGroupRenameList = (WORD*)realloc(pwGroupRenameList, nGroupRenameSize * sizeof(WORD));
+ }
+
+ pwGroupRenameList[nGroupRenameCount] = wGroupID;
+ nGroupRenameCount++;
+ LeaveCriticalSection(&servlistMutex);
+}
+
+
+// Remove running group rename operation
+void RemoveGroupRename(WORD wGroupID)
+{
+ int i, j;
+
+ EnterCriticalSection(&servlistMutex);
+ if (pwGroupRenameList)
+ {
+ for (i = 0; i<nGroupRenameCount; i++)
+ {
+ if (pwGroupRenameList[i] == wGroupID)
+ { // we found it, so remove
+ for (j = i+1; j<nGroupRenameCount; j++)
+ {
+ pwGroupRenameList[j-1] = pwGroupRenameList[j];
+ }
+ nGroupRenameCount--;
+ }
+ }
+ }
+ LeaveCriticalSection(&servlistMutex);
+}
+
+
+// Returns true if dwID is reserved
+BOOL IsGroupRenamed(WORD wGroupID)
+{
+ int i;
+
+ EnterCriticalSection(&servlistMutex);
+ if (pwGroupRenameList)
+ {
+ for (i = 0; i<nGroupRenameCount; i++)
+ {
+ if (pwGroupRenameList[i] == wGroupID)
+ {
+ LeaveCriticalSection(&servlistMutex);
+ return TRUE;
+ }
+ }
+ }
+ LeaveCriticalSection(&servlistMutex);
+
+ return FALSE;
+}
+
+
+void FlushGroupRenames()
+{
+ EnterCriticalSection(&servlistMutex);
+ SAFE_FREE(&pwGroupRenameList);
+ nGroupRenameCount = 0;
+ nGroupRenameSize = 0;
+ LeaveCriticalSection(&servlistMutex);
+}
+
+
+// used for adding new contacts to list - sync with visible items
+void AddJustAddedContact(HANDLE hContact)
+{
+ EnterCriticalSection(&servlistMutex);
+ if (nJustAddedCount >= nJustAddedSize)
+ {
+ nJustAddedSize += 10;
+ pdwJustAddedList = (HANDLE*)realloc(pdwJustAddedList, nJustAddedSize * sizeof(HANDLE));
+ }
+
+ pdwJustAddedList[nJustAddedCount] = hContact;
+ nJustAddedCount++;
+ LeaveCriticalSection(&servlistMutex);
+}
+
+
+// was the contact added during this serv-list load
+BOOL IsContactJustAdded(HANDLE hContact)
+{
+ int i;
+
+ EnterCriticalSection(&servlistMutex);
+ if (pdwJustAddedList)
+ {
+ for (i = 0; i<nJustAddedCount; i++)
+ {
+ if (pdwJustAddedList[i] == hContact)
+ {
+ LeaveCriticalSection(&servlistMutex);
+ return TRUE;
+ }
+ }
+ }
+ LeaveCriticalSection(&servlistMutex);
+
+ return FALSE;
+}
+
+
+void FlushJustAddedContacts()
+{
+ EnterCriticalSection(&servlistMutex);
+ SAFE_FREE((void**)&pdwJustAddedList);
+ nJustAddedSize = 0;
+ nJustAddedCount = 0;
+ LeaveCriticalSection(&servlistMutex);
+}
+
+
+
+// Used for event-driven adding of contacts, before it is completed this is used
+static BOOL AddPendingOperation(HANDLE hContact, const char* szGroup, servlistcookie* cookie, GROUPADDCALLBACK ofEvent)
+{
+ BOOL bRes = TRUE;
+ ssipendingitem* pItem = NULL;
+ int i;
+
+ EnterCriticalSection(&servlistMutex);
+ if (pdwPendingList)
+ {
+ for (i = 0; i<nPendingCount; i++)
+ {
+ if (pdwPendingList[i]->hContact == hContact)
+ { // we need the last item for this contact
+ pItem = pdwPendingList[i];
+ }
+ }
+ }
+
+ if (pItem) // we found a pending operation, so link our data
+ {
+ pItem->ofCallback = ofEvent;
+ pItem->pCookie = cookie;
+ pItem->szGroupPath = null_strdup(szGroup); // we need to duplicate the string
+ bRes = FALSE;
+
+ NetLog_Server("Operation postponed.");
+ }
+
+ if (nPendingCount >= nPendingSize) // add new
+ {
+ nPendingSize += 10;
+ pdwPendingList = (ssipendingitem**)realloc(pdwPendingList, nPendingSize * sizeof(ssipendingitem*));
+ }
+
+ pdwPendingList[nPendingCount] = (ssipendingitem*)SAFE_MALLOC(sizeof(ssipendingitem));
+ pdwPendingList[nPendingCount]->hContact = hContact;
+
+ nPendingCount++;
+ LeaveCriticalSection(&servlistMutex);
+
+ return bRes;
+}
+
+
+
+// Check if any pending operation is in progress
+// If yes, get its data and remove it from queue
+void RemovePendingOperation(HANDLE hContact, int nResult)
+{
+ int i, j;
+ ssipendingitem* pItem = NULL;
+
+ EnterCriticalSection(&servlistMutex);
+ if (pdwPendingList)
+ {
+ for (i = 0; i<nPendingCount; i++)
+ {
+ if (pdwPendingList[i]->hContact == hContact)
+ {
+ pItem = pdwPendingList[i];
+ for (j = i+1; j<nPendingCount; j++)
+ {
+ pdwPendingList[j-1] = pdwPendingList[j];
+ }
+ nPendingCount--;
+ if (nResult) // we succeded, go on, resume operation
+ {
+ LeaveCriticalSection(&servlistMutex);
+
+ if (pItem->ofCallback)
+ {
+ NetLog_Server("Resuming postponed operation.");
+
+ makeGroupId(pItem->szGroupPath, pItem->ofCallback, pItem->pCookie);
+ }
+ else if ((int)pItem->pCookie == 1)
+ {
+ NetLog_Server("Resuming postponed update.");
+
+ updateServContact(hContact);
+ }
+
+ SAFE_FREE(&pItem->szGroupPath); // free the string
+ SAFE_FREE(&pItem);
+ return;
+ } // else remove all pending operations for this contact
+ NetLog_Server("Purging postponed operation.");
+ if ((pItem->pCookie) && ((int)pItem->pCookie != 1))
+ SAFE_FREE(&pItem->pCookie->szGroupName); // do not leak nick name on error
+ SAFE_FREE(&pItem->szGroupPath);
+ SAFE_FREE(&pItem);
+ }
+ }
+ }
+ LeaveCriticalSection(&servlistMutex);
+ return;
+}
+
+
+
+// Remove All pending operations
+void FlushPendingOperations()
+{
+ int i;
+
+ EnterCriticalSection(&servlistMutex);
+
+ for (i = 0; i<nPendingCount; i++)
+ {
+ SAFE_FREE((void**)&pdwPendingList[i]);
+ }
+ SAFE_FREE((void**)&pdwPendingList);
+ nPendingCount = 0;
+ nPendingSize = 0;
+
+ LeaveCriticalSection(&servlistMutex);
+}
+
+
+
+// Add a server ID to the list of reserved IDs.
+// To speed up the process, no checks is done, if
+// you try to reserve an ID twice, it will be added again.
+// You should call CheckServerID before reserving an ID.
+void ReserveServerID(WORD wID, int bGroupId)
+{
+ EnterCriticalSection(&servlistMutex);
+ if (nIDListCount >= nIDListSize)
+ {
+ nIDListSize += 100;
+ pwIDList = (DWORD*)realloc(pwIDList, nIDListSize * sizeof(DWORD));
+ }
+
+ pwIDList[nIDListCount] = wID | bGroupId << 0x18;
+ nIDListCount++;
+ LeaveCriticalSection(&servlistMutex);
+}
+
+
+
+// Remove a server ID from the list of reserved IDs.
+// Used for deleting contacts and other modifications.
+void FreeServerID(WORD wID, int bGroupId)
+{
+ int i, j;
+ DWORD dwId = wID | bGroupId << 0x18;
+
+ EnterCriticalSection(&servlistMutex);
+ if (pwIDList)
+ {
+ for (i = 0; i<nIDListCount; i++)
+ {
+ if (pwIDList[i] == dwId)
+ { // we found it, so remove
+ for (j = i+1; j<nIDListCount; j++)
+ {
+ pwIDList[j-1] = pwIDList[j];
+ }
+ nIDListCount--;
+ }
+ }
+ }
+ LeaveCriticalSection(&servlistMutex);
+}
+
+
+// Returns true if dwID is reserved
+BOOL CheckServerID(WORD wID, unsigned int wCount)
+{
+ int i;
+
+ EnterCriticalSection(&servlistMutex);
+ if (pwIDList)
+ {
+ for (i = 0; i<nIDListCount; i++)
+ {
+ if (((pwIDList[i] & 0xFFFF) >= wID) && ((pwIDList[i] & 0xFFFF) <= wID + wCount))
+ {
+ LeaveCriticalSection(&servlistMutex);
+ return TRUE;
+ }
+ }
+ }
+ LeaveCriticalSection(&servlistMutex);
+
+ return FALSE;
+}
+
+
+
+void FlushServerIDs()
+{
+ EnterCriticalSection(&servlistMutex);
+ SAFE_FREE(&pwIDList);
+ nIDListCount = 0;
+ nIDListSize = 0;
+ LeaveCriticalSection(&servlistMutex);
+}
+
+
+
+static int GroupReserveIdsEnumProc(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))
+ { // 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;
+ }
+ ReserveServerID((WORD)strtoul(szSetting, NULL, 0x10), SSIT_GROUP);
+#ifdef _DEBUG
+ NetLog_Server("Loaded group %u:'%s'", strtoul(szSetting, NULL, 0x10), val);
+#endif
+ }
+ return 0;
+}
+
+
+
+int ReserveServerGroups()
+{
+ DBCONTACTENUMSETTINGS dbces;
+ int nStart = nIDListCount;
+
+ char szModule[MAX_PATH+9];
+
+ strcpy(szModule, gpszICQProtoName);
+ strcat(szModule, "SrvGroups");
+
+ dbces.pfnEnumProc = &GroupReserveIdsEnumProc;
+ dbces.szModule = szModule;
+ dbces.lParam = (LPARAM)szModule;
+
+ CallService(MS_DB_CONTACT_ENUMSETTINGS, (WPARAM)NULL, (LPARAM)&dbces);
+
+ return nIDListCount - nStart;
+}
+
+
+
+// Load all known server IDs from DB to list
+void LoadServerIDs()
+{
+ HANDLE hContact;
+ WORD wSrvID;
+ int nGroups = 0, nContacts = 0, nPermits = 0, nDenys = 0, nIgnores = 0;
+
+ EnterCriticalSection(&servlistMutex);
+ if (wSrvID = ICQGetContactSettingWord(NULL, "SrvAvatarID", 0))
+ ReserveServerID(wSrvID, SSIT_ITEM);
+ if (wSrvID = ICQGetContactSettingWord(NULL, "SrvVisibilityID", 0))
+ ReserveServerID(wSrvID, SSIT_ITEM);
+
+ nGroups = ReserveServerGroups();
+
+ hContact = ICQFindFirstContact();
+
+ while (hContact)
+ { // search all our contacts, reserve their server IDs
+ if (wSrvID = ICQGetContactSettingWord(hContact, "ServerId", 0))
+ {
+ ReserveServerID(wSrvID, SSIT_ITEM);
+ nContacts++;
+ }
+ if (wSrvID = ICQGetContactSettingWord(hContact, "SrvDenyId", 0))
+ {
+ ReserveServerID(wSrvID, SSIT_ITEM);
+ nDenys++;
+ }
+ if (wSrvID = ICQGetContactSettingWord(hContact, "SrvPermitId", 0))
+ {
+ ReserveServerID(wSrvID, SSIT_ITEM);
+ nPermits++;
+ }
+ if (wSrvID = ICQGetContactSettingWord(hContact, "SrvIgnoreId", 0))
+ {
+ ReserveServerID(wSrvID, SSIT_ITEM);
+ nIgnores++;
+ }
+
+ hContact = ICQFindNextContact(hContact);
+ }
+ LeaveCriticalSection(&servlistMutex);
+
+ NetLog_Server("Loaded SSI: %d contacts, %d groups, %d permit, %d deny, %d ignore items.", nContacts, nGroups, nPermits, nDenys, nIgnores);
+
+ return;
+}
+
+
+
+WORD GenerateServerId(int bGroupId)
+{
+ 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, 0))
+ break;
+ }
+
+ ReserveServerID(wId, bGroupId);
+
+ return wId;
+}
+
+
+
+// Generate server ID with wCount IDs free after it, for sub-groups.
+WORD GenerateServerIdPair(int bGroupId, 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, bGroupId);
+
+ return wId;
+}
+
+
+/***********************************************
+ *
+ * --- Low-level packet sending functions ---
+ *
+ */
+
+
+static DWORD icq_sendServerItem(DWORD dwCookie, WORD wAction, WORD wGroupId, WORD wItemId, const char *szName, BYTE *pTLVs, int nTlvLength, WORD wItemType)
+{ // 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));
+ packFNACHeaderFull(&packet, ICQ_LISTS_FAMILY, wAction, 0, dwCookie);
+ packWord(&packet, (WORD)nNameLen);
+ if (nNameLen)
+ packBuffer(&packet, szName, (WORD)nNameLen);
+ packWord(&packet, wGroupId);
+ packWord(&packet, wItemId);
+ packWord(&packet, wItemType);
+ packWord(&packet, wTLVlen);
+ if (wTLVlen)
+ packBuffer(&packet, pTLVs, wTLVlen);
+
+ // Send the packet and return the cookie
+ sendServPacket(&packet);
+
+ return dwCookie;
+}
+
+
+
+DWORD icq_sendServerContact(HANDLE hContact, DWORD dwCookie, WORD wAction, WORD wGroupId, WORD wContactId)
+{
+ DWORD dwUin;
+ uid_str szUid;
+ icq_packet pBuffer;
+ char *szNick = NULL, *szNote = NULL;
+ BYTE *pData = NULL;
+ int nNickLen, nNoteLen, nDataLen;
+ WORD wTLVlen;
+ BYTE bAuth;
+
+ // Prepare UID
+ if (ICQGetContactSettingUID(hContact, &dwUin, &szUid))
+ {
+ NetLog_Server("Buddy upload failed (UID missing).");
+ return 0;
+ }
+
+ bAuth = ICQGetContactSettingByte(hContact, "Auth", 0);
+ szNick = UniGetContactSettingUtf(hContact, "CList", "MyHandle", NULL);
+ szNote = UniGetContactSettingUtf(hContact, "UserInfo", "MyNotes", NULL);
+
+ {
+ DBVARIANT dbv;
+
+ if (!DBGetContactSetting(hContact, gpszICQProtoName, "ServerData", &dbv))
+ { // read additional server item data
+ nDataLen = dbv.cpbVal;
+ pData = (BYTE*)_alloca(nDataLen);
+ memcpy(pData, dbv.pbVal, nDataLen);
+
+ ICQFreeVariant(&dbv);
+ }
+ else
+ {
+ pData = NULL;
+ nDataLen = 0;
+ }
+ }
+
+ nNickLen = strlennull(szNick);
+ nNoteLen = strlennull(szNote);
+
+ // Build the packet
+ wTLVlen = (nNickLen?4+nNickLen:0) + (nNoteLen?4+nNoteLen:0) + (bAuth?4:0) + nDataLen;
+
+ // 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, szNick); // Nickname TLV
+
+ if (nNoteLen)
+ packTLV(&pBuffer, SSI_TLV_COMMENT, (WORD)nNoteLen, szNote); // Comment TLV
+
+ if (pData)
+ packBuffer(&pBuffer, pData, (WORD)nDataLen);
+
+ if (bAuth) // icq5 gives this as last TLV
+ packDWord(&pBuffer, 0x00660000); // "Still waiting for auth" TLV
+
+ return icq_sendServerItem(dwCookie, wAction, wGroupId, wContactId, strUID(dwUin, szUid), pBuffer.pData, wTLVlen, SSI_ITEM_BUDDY);
+}
+
+
+
+DWORD icq_sendSimpleItem(DWORD dwCookie, WORD wAction, DWORD dwUin, char* szUID, WORD wGroupId, WORD wItemId, WORD wItemType)
+{ // for privacy items
+ return icq_sendServerItem(dwCookie, wAction, wGroupId, wItemId, strUID(dwUin, szUID), NULL, 0, wItemType);
+}
+
+
+
+DWORD icq_sendGroupUtf(DWORD dwCookie, WORD wAction, WORD wGroupId, const char *szName, void *pContent, int cbContent)
+{
+ 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, pContent); // Groups TLV
+
+ return icq_sendServerItem(dwCookie, wAction, wGroupId, 0, szName, pBuffer.pData, wTLVlen, SSI_ITEM_GROUP);
+}
+
+
+
+DWORD icq_modifyServerPrivacyItem(HANDLE hContact, DWORD dwUin, char* szUid, WORD wAction, DWORD dwOperation, WORD wItemId, WORD wType)
+{
+ servlistcookie* ack;
+ DWORD dwCookie;
+
+ if (!(ack = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie))))
+ { // cookie failed, use old fake
+ dwCookie = GenerateCookie(wAction);
+ }
+ else
+ {
+ ack->dwAction = dwOperation; // remove privacy item
+ ack->dwUin = dwUin;
+ ack->hContact = hContact;
+ ack->wContactId = wItemId;
+
+ dwCookie = AllocateCookie(CKT_SERVERLIST, wAction, dwUin, ack);
+ }
+ return icq_sendSimpleItem(dwCookie, wAction, dwUin, szUid, 0, wItemId, wType);
+}
+
+
+
+DWORD 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 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 ---
+ *
+ */
+
+static int GroupNamesEnumProc(const char *szSetting,LPARAM lParam)
+{ // if we got pointer, store setting name, return zero
+ if (lParam)
+ {
+ char** block = (char**)SAFE_MALLOC(2*sizeof(char*));
+ block[1] = null_strdup(szSetting);
+ block[0] = ((char**)lParam)[0];
+ ((char**)lParam)[0] = (char*)block;
+ }
+ return 0;
+}
+
+
+
+void DeleteModuleEntries(const char* szModule)
+{
+ DBCONTACTENUMSETTINGS dbces;
+ char** list = NULL;
+
+ dbces.pfnEnumProc = &GroupNamesEnumProc;
+ dbces.szModule = szModule;
+ dbces.lParam = (LPARAM)&list;
+ CallService(MS_DB_CONTACT_ENUMSETTINGS, (WPARAM)NULL, (LPARAM)&dbces);
+ while (list)
+ {
+ void* bet;
+
+ DBDeleteContactSetting(NULL, szModule, list[1]);
+ SAFE_FREE(&list[1]);
+ bet = list;
+ list = (char**)list[0];
+ SAFE_FREE(&bet);
+ }
+}
+
+
+
+int IsServerGroupsDefined()
+{
+ int iRes = 1;
+
+ if (ICQGetContactSettingDword(NULL, "Version", 0) < 0x00030608)
+ { // group cache & linking data too old, flush, reload from server
+ char szModule[MAX_PATH+9];
+
+ strcpy(szModule, gpszICQProtoName);
+ strcat(szModule, "Groups"); // flush obsolete linking data
+ DeleteModuleEntries(szModule);
+
+ iRes = 0; // no groups defined, or older version
+ }
+ // store our current version
+ ICQWriteContactSettingDword(NULL, "Version", ICQ_PLUG_VERSION & 0x00FFFFFF);
+
+ return iRes;
+}
+
+
+
+void FlushSrvGroupsCache()
+{
+ char szModule[MAX_PATH+9];
+
+ strcpy(szModule, gpszICQProtoName);
+ strcat(szModule, "SrvGroups");
+ DeleteModuleEntries(szModule);
+}
+
+
+
+// Look thru DB and collect all ContactIDs from a group
+void* collectBuddyGroup(WORD wGroupID, int *count)
+{
+ WORD* buf = NULL;
+ int cnt = 0;
+ HANDLE hContact;
+ WORD wItemID;
+
+ hContact = ICQFindFirstContact();
+
+ while (hContact)
+ { // search all contacts
+ if (wGroupID == ICQGetContactSettingWord(hContact, "SrvGroupId", 0))
+ { // add only buddys from specified group
+ wItemID = ICQGetContactSettingWord(hContact, "ServerId", 0);
+
+ if (wItemID)
+ { // valid ID, add
+ cnt++;
+ buf = (WORD*)realloc(buf, cnt*sizeof(WORD));
+ buf[cnt-1] = wItemID;
+ }
+ }
+
+ hContact = ICQFindNextContact(hContact);
+ }
+
+ *count = cnt<<1; // we return size in bytes
+ return buf;
+}
+
+
+
+// Look thru DB and collect all GroupIDs
+void* collectGroups(int *count)
+{
+ WORD* buf = NULL;
+ int cnt = 0;
+ int i;
+ HANDLE hContact;
+ WORD wGroupID;
+
+ hContact = ICQFindFirstContact();
+
+ while (hContact)
+ { // search all contacts
+ if (wGroupID = ICQGetContactSettingWord(hContact, "SrvGroupId", 0))
+ { // add only valid IDs
+ for (i = 0; i<cnt; i++)
+ { // check for already added ids
+ if (buf[i] == wGroupID) break;
+ }
+
+ if (i == cnt)
+ { // not preset, add
+ cnt++;
+ buf = (WORD*)realloc(buf, cnt*sizeof(WORD));
+ buf[i] = wGroupID;
+ }
+ }
+
+ hContact = ICQFindNextContact(hContact);
+ }
+
+ *count = cnt<<1;
+ return buf;
+}
+
+
+
+static int GroupLinksEnumProc(const char *szSetting,LPARAM lParam)
+{ // check link target, add if match
+ if (DBGetContactSettingWord(NULL, ((char**)lParam)[2], szSetting, 0) == (WORD)((char**)lParam)[1])
+ {
+ char** block = (char**)SAFE_MALLOC(2*sizeof(char*));
+ block[1] = null_strdup(szSetting);
+ block[0] = ((char**)lParam)[0];
+ ((char**)lParam)[0] = (char*)block;
+ }
+ return 0;
+}
+
+
+
+void removeGroupPathLinks(WORD wGroupID)
+{ // remove miranda grouppath links targeting to this groupid
+ DBCONTACTENUMSETTINGS dbces;
+ char szModule[MAX_PATH+6];
+ char* pars[3];
+
+ strcpy(szModule, gpszICQProtoName);
+ strcat(szModule, "Groups");
+
+ pars[0] = NULL;
+ pars[1] = (char*)wGroupID;
+ pars[2] = szModule;
+
+ dbces.pfnEnumProc = &GroupLinksEnumProc;
+ dbces.szModule = szModule;
+ dbces.lParam = (LPARAM)pars;
+
+ if (!CallService(MS_DB_CONTACT_ENUMSETTINGS, (WPARAM)NULL, (LPARAM)&dbces))
+ { // we found some links, remove them
+ char** list = (char**)pars[0];
+ while (list)
+ {
+ void* bet;
+
+ DBDeleteContactSetting(NULL, szModule, list[1]);
+ SAFE_FREE(&list[1]);
+ bet = list;
+ list = (char**)list[0];
+ SAFE_FREE(&bet);
+ }
+ }
+ return;
+}
+
+
+
+char* getServerGroupNameUtf(WORD wGroupID)
+{
+ char szModule[MAX_PATH+9];
+ char szGroup[16];
+
+ strcpy(szModule, gpszICQProtoName);
+ strcat(szModule, "SrvGroups");
+ _itoa(wGroupID, szGroup, 0x10);
+
+ if (!CheckServerID(wGroupID, 0))
+ { // check if valid id, if not give empty and remove
+ NetLog_Server("Removing group %u from cache...", wGroupID);
+ DBDeleteContactSetting(NULL, szModule, szGroup);
+ return NULL;
+ }
+
+ return UniGetContactSettingUtf(NULL, szModule, szGroup, NULL);
+}
+
+
+
+void setServerGroupNameUtf(WORD wGroupID, const char* szGroupNameUtf)
+{
+ char szModule[MAX_PATH+9];
+ char szGroup[16];
+
+ strcpy(szModule, gpszICQProtoName);
+ strcat(szModule, "SrvGroups");
+ _itoa(wGroupID, szGroup, 0x10);
+
+ if (szGroupNameUtf)
+ UniWriteContactSettingUtf(NULL, szModule, szGroup, (char*)szGroupNameUtf);
+ else
+ {
+ DBDeleteContactSetting(NULL, szModule, szGroup);
+ removeGroupPathLinks(wGroupID);
+ }
+ return;
+}
+
+
+
+WORD getServerGroupIDUtf(const char* szPath)
+{
+ char szModule[MAX_PATH+6];
+ WORD wGroupId;
+
+ strcpy(szModule, gpszICQProtoName);
+ strcat(szModule, "Groups");
+
+ wGroupId = DBGetContactSettingWord(NULL, szModule, szPath, 0);
+
+ if (wGroupId && !CheckServerID(wGroupId, 0))
+ { // known, check if still valid, if not remove
+ NetLog_Server("Removing group \"%s\" from cache...", szPath);
+ DBDeleteContactSetting(NULL, szModule, szPath);
+ wGroupId = 0;
+ }
+
+ return wGroupId;
+}
+
+
+
+void setServerGroupIDUtf(const char* szPath, WORD wGroupID)
+{
+ char szModule[MAX_PATH+6];
+
+ strcpy(szModule, gpszICQProtoName);
+ strcat(szModule, "Groups");
+
+ if (wGroupID)
+ DBWriteContactSettingWord(NULL, szModule, szPath, wGroupID);
+ else
+ DBDeleteContactSetting(NULL, szModule, szPath);
+
+ return;
+}
+
+
+
+// copied from groups.c - horrible, but only possible as this is not available as service
+int GroupNameExistsUtf(const char *name,int skipGroup)
+{
+ char idstr[33];
+ char* szGroup = NULL;
+ int i;
+
+ if (name == NULL) return 1; // no group always exists
+ for(i=0;;i++)
+ {
+ if(i==skipGroup) continue;
+ itoa(i,idstr,10);
+ szGroup = UniGetContactSettingUtf(NULL, "CListGroups", idstr, "");
+ if (!strlennull(szGroup)) break;
+ if (!strcmpnull(szGroup+1, name))
+ { // caution, this can be false - with ansi clist
+ SAFE_FREE(&szGroup);
+ return 1;
+ }
+ SAFE_FREE(&szGroup);
+ }
+ SAFE_FREE(&szGroup);
+ return 0;
+}
+
+
+
+// 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<nNameLen)
+ {
+ if (szGroupName[i] != '>')
+ return i;
+
+ i++;
+ }
+ return -1;
+}
+
+
+
+int countGroupLevel(WORD wGroupId)
+{
+ char* szGroupName = getServerGroupNameUtf(wGroupId);
+ int cnt = -1;
+
+ if (szGroupName)
+ cnt = countGroupNameLevel(szGroupName);
+
+ return cnt;
+}
+
+
+
+static int countClistGroupLevel(const char *szClistName)
+{
+ int nNameLen = strlennull(szClistName);
+ int i, level = 0;
+
+ for (i = 0; i < nNameLen; i++)
+ if (szClistName[i] == '\\') level++;
+
+ return level;
+}
+
+
+
+int CreateCListGroup(const char* szGroupName)
+{
+ int hGroup;
+ CLIST_INTERFACE *clint = NULL;
+
+ if (ServiceExists(MS_CLIST_RETRIEVE_INTERFACE))
+ clint = (CLIST_INTERFACE*)CallService(MS_CLIST_RETRIEVE_INTERFACE, 0, 0);
+
+ hGroup = CallService(MS_CLIST_GROUPCREATE, 0, 0);
+
+ if (gbUnicodeCore && clint && clint->version >= 1)
+ { // we've got unicode interface, use it
+ wchar_t* usTmp = make_unicode_string(szGroupName);
+
+ clint->pfnRenameGroup(hGroup, (TCHAR*)usTmp);
+ SAFE_FREE(&usTmp);
+ }
+ else
+ { // old ansi version - no other way
+ int size = strlennull(szGroupName) + 2;
+ char* szTmp = (char*)_alloca(size);
+
+ utf8_decode_static(szGroupName, szTmp, size);
+ CallService(MS_CLIST_GROUPRENAME, hGroup, (LPARAM)szTmp);
+ }
+
+ return hGroup;
+}
+
+
+
+// demangle group path
+char* makeGroupPathUtf(WORD wGroupId)
+{
+ char* szGroup = NULL;
+
+ if (szGroup = getServerGroupNameUtf(wGroupId))
+ { // this groupid is not valid
+ while (strstr(szGroup, "\\")!=NULL) *strstr(szGroup, "\\") = '_'; // remove invalid char
+ if (getServerGroupIDUtf(szGroup) == wGroupId)
+ { // this grouppath is known and is for this group, set user group
+ return szGroup;
+ }
+ else
+ {
+ if (strlennull(szGroup) && (szGroup[0] == '>'))
+ { // it is probably a sub-group
+ WORD wId = wGroupId-1;
+ int level = countGroupLevel(wGroupId);
+ int levnew = countGroupLevel(wId);
+ char* szTempGroup;
+
+ if (level == -1)
+ { // this is just an ordinary group
+ int hGroup;
+
+ if (!GroupNameExistsUtf(szGroup, -1))
+ { // if the group does not exist, create it
+ hGroup = CreateCListGroup(szGroup);
+ }
+ setServerGroupIDUtf(szGroup, wGroupId); // set grouppath id
+ return szGroup;
+ }
+ while ((levnew >= level) && (levnew != -1))
+ { // we look for parent group
+ wId--;
+ levnew = countGroupLevel(wId);
+ }
+ if (levnew == -1)
+ { // that was not a sub-group, it was just a group starting with >
+ if (!GroupNameExistsUtf(szGroup, -1))
+ { // if the group does not exist, create it
+ int hGroup = CreateCListGroup(szGroup);
+ }
+ setServerGroupIDUtf(szGroup, wGroupId); // set grouppath id
+ return szGroup;
+ }
+
+ szTempGroup = makeGroupPathUtf(wId);
+
+ szTempGroup = realloc(szTempGroup, strlennull(szGroup)+strlennull(szTempGroup)+2);
+ strcat(szTempGroup, "\\");
+ strcat(szTempGroup, szGroup+level);
+ SAFE_FREE(&szGroup);
+ szGroup = szTempGroup;
+
+ if (getServerGroupIDUtf(szGroup) == wGroupId)
+ { // known path, give
+ return szGroup;
+ }
+ else
+ { // unknown path, create
+ if (!GroupNameExistsUtf(szGroup, -1))
+ { // if the group does not exist, create it
+ int hGroup = CreateCListGroup(szGroup);
+ }
+ setServerGroupIDUtf(szGroup, wGroupId); // set grouppath id
+ return szGroup;
+ }
+ }
+ else
+ { // create that group
+ int hGroup;
+
+ if (!GroupNameExistsUtf(szGroup, -1))
+ { // if the group does not exist, create it
+ hGroup = CreateCListGroup(szGroup);
+ }
+ setServerGroupIDUtf(szGroup, wGroupId); // set grouppath id
+ return szGroup;
+ }
+ }
+ }
+ return NULL;
+}
+
+
+
+// this is the second pard of recursive event-driven procedure
+void madeMasterGroupId(WORD wGroupID, LPARAM lParam)
+{
+ servlistcookie* clue = (servlistcookie*)lParam;
+ char* szGroup = clue->szGroupName;
+ GROUPADDCALLBACK ofCallback = clue->ofCallback;
+ servlistcookie* param = (servlistcookie*)clue->lParam;
+ int level;
+
+ if (wGroupID) // if we got an id count level
+ level = countGroupLevel(wGroupID);
+ else
+ level = -1;
+
+ SAFE_FREE(&clue);
+
+ if (level == -1)
+ { // something went wrong, give the id and go away
+ if (ofCallback) ofCallback(wGroupID, (LPARAM)param);
+
+ SAFE_FREE(&szGroup);
+ return;
+ }
+ level++; // we are a sub
+
+ // check if on that id is not group of the same or greater level, if yes, try next
+ while (CheckServerID((WORD)(wGroupID+1),0) && (countGroupLevel((WORD)(wGroupID+1)) >= level))
+ {
+ wGroupID++;
+ }
+
+ if (!CheckServerID((WORD)(wGroupID+1), 0))
+ { // the next id is free, so create our group with that id
+ servlistcookie* ack;
+ DWORD dwCookie;
+ char* szSubGroup = (char*)SAFE_MALLOC(strlennull(szGroup)+level+1);
+
+ if (szSubGroup)
+ {
+ int i;
+
+ for (i=0; i<level; i++)
+ {
+ szSubGroup[i] = '>';
+ }
+ strcpy(szSubGroup+level, szGroup);
+ szSubGroup[strlennull(szGroup)+level] = '\0';
+
+ if (ack = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie)))
+ { // we have cookie good, go on
+ ReserveServerID((WORD)(wGroupID+1), SSIT_GROUP);
+
+ ack->wGroupId = wGroupID+1;
+ ack->szGroupName = szSubGroup; // we need that name
+ ack->dwAction = SSA_GROUP_ADD;
+ ack->ofCallback = ofCallback;
+ ack->lParam = (LPARAM)param;
+ dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_ADDTOLIST, 0, ack);
+
+ sendAddStart(0);
+ icq_sendGroupUtf(dwCookie, ICQ_LISTS_ADDTOLIST, ack->wGroupId, szSubGroup, NULL, 0);
+
+ SAFE_FREE(&szGroup);
+ return;
+ }
+ SAFE_FREE(&szSubGroup);
+ }
+ }
+ // we failed to create sub-group give parent groupid
+ if (ofCallback) ofCallback(wGroupID, (LPARAM)param);
+
+ SAFE_FREE(&szGroup);
+ return;
+}
+
+
+
+// create group with this path, a bit complex task
+// this supposes that all server groups are known
+WORD makeGroupId(const char* szGroupPath, GROUPADDCALLBACK ofCallback, servlistcookie* lParam)
+{
+ WORD wGroupID = 0;
+ char* szGroup = (char*)szGroupPath;
+
+ if (!szGroup || szGroup[0]=='\0') szGroup = DEFAULT_SS_GROUP;
+
+ if (wGroupID = getServerGroupIDUtf(szGroup))
+ {
+ if (ofCallback) ofCallback(wGroupID, (LPARAM)lParam);
+ return wGroupID; // if the path is known give the id
+ }
+
+ if (!strstr(szGroup, "\\"))
+ { // a root group can be simply created without problems
+ servlistcookie* ack;
+ DWORD dwCookie;
+
+ if (ack = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie)))
+ { // we have cookie good, go on
+ ack->wGroupId = GenerateServerId(SSIT_GROUP);
+ ack->szGroupName = null_strdup(szGroup); // we need that name
+ ack->dwAction = SSA_GROUP_ADD;
+ ack->ofCallback = ofCallback;
+ ack->lParam = (LPARAM)lParam;
+ dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_ADDTOLIST, 0, ack);
+
+ sendAddStart(0);
+ icq_sendGroupUtf(dwCookie, ICQ_LISTS_ADDTOLIST, ack->wGroupId, szGroup, NULL, 0);
+
+ return 0;
+ }
+ }
+ else
+ { // this is a sub-group
+ char* szSub = null_strdup(szGroup); // create subgroup, recursive, event-driven, possibly relocate
+ servlistcookie* ack;
+ char *szLast;
+
+ if (strstr(szSub, "\\") != NULL)
+ { // determine parent group
+ szLast = strstr(szSub, "\\")+1;
+
+ while (strstr(szLast, "\\") != NULL)
+ szLast = strstr(szLast, "\\")+1; // look for last backslash
+ szLast[-1] = '\0';
+ }
+ // make parent group id
+ ack = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie));
+ if (ack)
+ {
+ WORD wRes;
+ ack->lParam = (LPARAM)lParam;
+ ack->ofCallback = ofCallback;
+ ack->szGroupName = null_strdup(szLast); // groupname
+ wRes = makeGroupId(szSub, madeMasterGroupId, ack);
+ SAFE_FREE(&szSub);
+
+ return wRes;
+ }
+
+ SAFE_FREE(&szSub);
+ }
+
+ if (strstr(szGroup, "\\") != NULL)
+ { // we failed to get grouppath, trim it by one group
+ WORD wRes;
+ char *szLast = null_strdup(szGroup);
+ char *szLess = szLast;
+
+ while (strstr(szLast, "\\") != NULL)
+ szLast = strstr(szLast, "\\")+1; // look for last backslash
+ szLast[-1] = '\0';
+ wRes = makeGroupId(szLess, ofCallback, lParam);
+ SAFE_FREE(&szLess);
+
+ return wRes;
+ }
+
+ wGroupID = 0; // everything failed, let callback handle error
+ if (ofCallback) ofCallback(wGroupID, (LPARAM)lParam);
+
+ return wGroupID;
+}
+
+
+/*****************************************
+ *
+ * --- Server-List Operations ---
+ *
+ */
+
+void addServContactReady(WORD wGroupID, LPARAM lParam)
+{
+ WORD wItemID;
+ DWORD dwUin;
+ uid_str szUid;
+ servlistcookie* ack;
+ DWORD dwCookie;
+
+ ack = (servlistcookie*)lParam;
+
+ if (!ack || !wGroupID) // something went wrong
+ {
+ if (ack) RemovePendingOperation(ack->hContact, 0);
+ return;
+ }
+
+ wItemID = ICQGetContactSettingWord(ack->hContact, "ServerId", 0);
+
+ if (wItemID)
+ { // Only add the contact if it doesnt already have an ID
+ RemovePendingOperation(ack->hContact, 0);
+ NetLog_Server("Failed to add contact to server side list (%s)", "already there");
+ return;
+ }
+
+ // Get UID
+ if (ICQGetContactSettingUID(ack->hContact, &dwUin, &szUid))
+ { // Could not do anything without uid
+ RemovePendingOperation(ack->hContact, 0);
+ NetLog_Server("Failed to add contact to server side list (%s)", "no UID");
+ return;
+ }
+
+ wItemID = GenerateServerId(SSIT_ITEM);
+
+ ack->dwAction = SSA_CONTACT_ADD;
+ ack->dwUin = dwUin;
+ ack->wGroupId = wGroupID;
+ ack->wContactId = wItemID;
+
+ dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_ADDTOLIST, dwUin, ack);
+
+ sendAddStart(0);
+ icq_sendServerContact(ack->hContact, dwCookie, ICQ_LISTS_ADDTOLIST, wGroupID, wItemID);
+}
+
+
+
+// Called when contact should be added to server list, if group does not exist, create one
+DWORD addServContact(HANDLE hContact, const char *pszNick, const char *pszGroup)
+{
+ servlistcookie* ack;
+
+ if (!(ack = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie))))
+ { // Could not do anything without cookie
+ NetLog_Server("Failed to add contact to server side list (%s)", "malloc failed");
+ return 0;
+ }
+ else
+ {
+ ack->hContact = hContact;
+
+ if (AddPendingOperation(hContact, pszGroup, ack, addServContactReady))
+ makeGroupId(pszGroup, addServContactReady, ack);
+
+ return 1;
+ }
+}
+
+
+
+// Called when contact should be removed from server list, remove group if it remain empty
+DWORD removeServContact(HANDLE hContact)
+{
+ WORD wGroupID;
+ WORD wItemID;
+ DWORD dwUin;
+ uid_str szUid;
+ servlistcookie* ack;
+ DWORD dwCookie;
+
+ // Get the contact's group ID
+ if (!(wGroupID = ICQGetContactSettingWord(hContact, "SrvGroupId", 0)))
+ {
+ // Could not find a usable group ID
+ NetLog_Server("Failed to remove contact from server side list (%s)", "no group ID");
+ return 0;
+ }
+
+ // Get the contact's item ID
+ if (!(wItemID = ICQGetContactSettingWord(hContact, "ServerId", 0)))
+ {
+ // Could not find usable item ID
+ NetLog_Server("Failed to remove contact from server side list (%s)", "no item ID");
+ return 0;
+ }
+
+ // Get UID
+ if (ICQGetContactSettingUID(hContact, &dwUin, &szUid))
+ {
+ // Could not do anything without uid
+ NetLog_Server("Failed to remove contact from server side list (%s)", "no UID");
+ return 0;
+ }
+
+ if (!(ack = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie))))
+ { // Could not do anything without cookie
+ NetLog_Server("Failed to remove contact from server side list (%s)", "malloc failed");
+ return 0;
+ }
+ else
+ {
+ ack->dwAction = SSA_CONTACT_REMOVE;
+ ack->dwUin = dwUin;
+ ack->hContact = hContact;
+ ack->wGroupId = wGroupID;
+ ack->wContactId = wItemID;
+
+ dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_REMOVEFROMLIST, dwUin, ack);
+ }
+
+ sendAddStart(0);
+ icq_sendServerContact(hContact, dwCookie, ICQ_LISTS_REMOVEFROMLIST, wGroupID, wItemID);
+
+ return 0;
+}
+
+
+
+void moveServContactReady(WORD wNewGroupID, LPARAM lParam)
+{
+ WORD wItemID;
+ WORD wGroupID;
+ DWORD dwUin;
+ uid_str szUid;
+ servlistcookie* ack;
+ DWORD dwCookie, dwCookie2;
+
+ ack = (servlistcookie*)lParam;
+
+ if (!ack || !wNewGroupID) // something went wrong
+ {
+ if (ack) RemovePendingOperation(ack->hContact, 0);
+ return;
+ }
+
+ if (!ack->hContact) return; // we do not move us, caused our uin was wrongly added to list
+
+ wItemID = ICQGetContactSettingWord(ack->hContact, "ServerId", 0);
+ wGroupID = ICQGetContactSettingWord(ack->hContact, "SrvGroupId", 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
+ addServContactReady(wNewGroupID, lParam);
+ return;
+ }
+
+ if (!wGroupID)
+ { // Only move the contact if it had an GroupID
+ RemovePendingOperation(ack->hContact, 0);
+ NetLog_Server("Failed to move contact to group on server side list (%s)", "no Group");
+ return;
+ }
+
+ if (wGroupID == wNewGroupID)
+ { // Only move the contact if it had different GroupID
+ RemovePendingOperation(ack->hContact, 1);
+ NetLog_Server("Contact not moved to group on server side list (same Group)");
+ return;
+ }
+
+ // Get UID
+ if (ICQGetContactSettingUID(ack->hContact, &dwUin, &szUid))
+ { // Could not do anything without uin
+ RemovePendingOperation(ack->hContact, 0);
+ NetLog_Server("Failed to move contact to group on server side list (%s)", "no UID");
+ return;
+ }
+
+ ack->szGroupName = NULL;
+ ack->dwAction = SSA_CONTACT_SET_GROUP;
+ ack->dwUin = dwUin;
+ ack->wGroupId = wGroupID;
+ ack->wContactId = wItemID;
+ ack->wNewContactId = GenerateServerId(SSIT_ITEM); // icq5 recreates also this, imitate
+ ack->wNewGroupId = wNewGroupID;
+ ack->lParam = 0; // we use this as a sign
+
+ dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_REMOVEFROMLIST, dwUin, ack);
+ dwCookie2 = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_ADDTOLIST, dwUin, ack);
+
+ sendAddStart(0);
+ // imitate icq5, previously here was different order, but AOL changed and it ceased to work
+ icq_sendServerContact(ack->hContact, dwCookie, ICQ_LISTS_REMOVEFROMLIST, wGroupID, wItemID);
+ icq_sendServerContact(ack->hContact, dwCookie2, ICQ_LISTS_ADDTOLIST, wNewGroupID, ack->wNewContactId);
+}
+
+
+
+// Called when contact should be moved from one group to another, create new, remove empty
+DWORD moveServContactGroup(HANDLE hContact, const char *pszNewGroup)
+{
+ servlistcookie* ack;
+
+ if (!GroupNameExistsUtf(pszNewGroup, -1) && (pszNewGroup != NULL) && (pszNewGroup[0]!='\0'))
+ { // the contact moved to non existing group, do not do anything: MetaContact hack
+ NetLog_Server("Contact not moved - probably hiding by MetaContacts.");
+ return 0;
+ }
+
+ if (!ICQGetContactSettingWord(hContact, "ServerId", 0))
+ { // the contact is not stored on the server, check if we should try to add
+ if (!ICQGetContactSettingByte(NULL, "ServerAddRemove", DEFAULT_SS_ADDSERVER) ||
+ DBGetContactSettingByte(hContact, "CList", "Hidden", 0))
+ return 0;
+ }
+
+ if (!(ack = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie))))
+ { // Could not do anything without cookie
+ NetLog_Server("Failed to add contact to server side list (%s)", "malloc failed");
+ return 0;
+ }
+ else
+ {
+ ack->hContact = hContact;
+
+ if (AddPendingOperation(hContact, pszNewGroup, ack, moveServContactReady))
+ makeGroupId(pszNewGroup, moveServContactReady, ack);
+ return 1;
+ }
+}
+
+
+
+// Is called when a contact' details has been changed locally to update
+// the server side details.
+static DWORD updateServContact(HANDLE hContact)
+{
+ WORD wGroupID;
+ WORD wItemID;
+ DWORD dwUin;
+ uid_str szUid;
+ servlistcookie* ack;
+ DWORD dwCookie;
+
+ // Get the contact's group ID
+ if (!(wGroupID = ICQGetContactSettingWord(hContact, "SrvGroupId", 0)))
+ {
+ // Could not find a usable group ID
+ NetLog_Server("Failed to update contact's details on server side list (%s)", "no group ID");
+ RemovePendingOperation(hContact, 0);
+ return 0;
+ }
+
+ // Get the contact's item ID
+ if (!(wItemID = ICQGetContactSettingWord(hContact, "ServerId", 0)))
+ {
+ // Could not find usable item ID
+ NetLog_Server("Failed to update contact's details on server side list (%s)", "no item ID");
+ RemovePendingOperation(hContact, 0);
+ return 0;
+ }
+
+ // Get UID
+ if (ICQGetContactSettingUID(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");
+ RemovePendingOperation(hContact, 0);
+ return 0;
+ }
+
+ if (!(ack = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie))))
+ {
+ // Could not allocate cookie - use old fake
+ NetLog_Server("Failed to allocate cookie");
+ dwCookie = GenerateCookie(ICQ_LISTS_UPDATEGROUP);
+ }
+ else
+ {
+ ack->dwAction = SSA_CONTACT_UPDATE;
+ ack->wContactId = wItemID;
+ ack->wGroupId = wGroupID;
+ ack->dwUin = dwUin;
+ ack->hContact = hContact;
+
+ dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, dwUin, 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);
+
+ return dwCookie;
+}
+
+
+
+void renameServGroup(WORD wGroupId, char* szGroupName)
+{
+ servlistcookie* ack;
+ DWORD dwCookie;
+ char* szGroup, *szLast;
+ int level = countGroupLevel(wGroupId);
+ int i;
+ void* groupData;
+ DWORD groupSize;
+
+ if (IsGroupRenamed(wGroupId)) return; // the group was already renamed
+
+ if (level == -1) return; // we failed to prepare group
+
+ szLast = szGroupName;
+ i = level;
+ while (i)
+ { // find correct part of grouppath
+ szLast = strstr(szLast, "\\")+1;
+ i--;
+ }
+ szGroup = (char*)SAFE_MALLOC(strlennull(szLast)+1+level);
+ if (!szGroup) return;
+
+ for (i=0;i<level;i++)
+ { // create level prefix
+ szGroup[i] = '>';
+ }
+ strcat(szGroup, szLast);
+ // truncate other possible sub-groups
+ szLast = strstr(szGroup, "\\");
+ if (szLast)
+ szLast[0] = '\0';
+
+ if (!(ack = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie))))
+ { // cookie failed, use old fake
+ dwCookie = GenerateCookie(ICQ_LISTS_UPDATEGROUP);
+ }
+ if (groupData = collectBuddyGroup(wGroupId, &groupSize))
+ {
+ ack->dwAction = SSA_GROUP_RENAME;
+ ack->wGroupId = wGroupId;
+ ack->szGroupName = szGroup; // we need this name
+
+ dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, 0, ack);
+
+ AddGroupRename(wGroupId);
+
+ icq_sendGroupUtf(dwCookie, ICQ_LISTS_UPDATEGROUP, wGroupId, szGroup, groupData, groupSize);
+ SAFE_FREE(&groupData);
+ }
+}
+
+
+/*****************************************
+ *
+ * --- Miranda Contactlist Hooks ---
+ *
+ */
+
+
+
+static int ServListDbSettingChanged(WPARAM wParam, LPARAM lParam)
+{
+ DBCONTACTWRITESETTING* cws = (DBCONTACTWRITESETTING*)lParam;
+
+ // We can't upload changes to NULL contact
+ if ((HANDLE)wParam == NULL)
+ return 0;
+
+ if (!strcmpnull(cws->szModule, "ContactPhoto"))
+ { // contact photo changed ?
+ ContactPhotoSettingChanged((HANDLE)wParam);
+ }
+
+ // TODO: Queue changes that occur while offline
+ if (!icqOnline || !gbSsiEnabled || bIsSyncingCL)
+ return 0;
+
+ { // only our contacts will be handled
+ if (IsICQContact((HANDLE)wParam))
+ ;// our contact, fine; otherwise return
+ else
+ return 0;
+ }
+
+ if (!strcmpnull(cws->szModule, "CList"))
+ {
+ // Has a temporary contact just been added permanently?
+ if (!strcmpnull(cws->szSetting, "NotOnList") &&
+ (cws->value.type == DBVT_DELETED || (cws->value.type == DBVT_BYTE && cws->value.bVal == 0)) &&
+ ICQGetContactSettingByte(NULL, "ServerAddRemove", DEFAULT_SS_ADDSERVER) &&
+ !DBGetContactSettingByte((HANDLE)wParam, "CList", "Hidden", 0))
+ {
+ DWORD dwUin;
+ uid_str szUid;
+
+ // Does this contact have a UID?
+ if (!ICQGetContactSettingUID((HANDLE)wParam, &dwUin, &szUid))
+ {
+ char *pszNick;
+ char *pszGroup;
+
+ // Read nick name from DB
+ pszNick = UniGetContactSettingUtf((HANDLE)wParam, "CList", "MyHandle", NULL);
+
+ // Read group from DB
+ pszGroup = UniGetContactSettingUtf((HANDLE)wParam, "CList", "Group", NULL);
+
+ addServContact((HANDLE)wParam, pszNick, pszGroup);
+
+ SAFE_FREE(&pszNick);
+ SAFE_FREE(&pszGroup);
+ }
+ }
+
+ // Has contact been renamed?
+ if (!strcmpnull(cws->szSetting, "MyHandle") &&
+ ICQGetContactSettingByte(NULL, "StoreServerDetails", DEFAULT_SS_STORE))
+ {
+ if (AddPendingOperation((HANDLE)wParam, NULL, (servlistcookie*)1, NULL))
+ updateServContact((HANDLE)wParam);
+ }
+
+ // Has contact been moved to another group?
+ if (!strcmpnull(cws->szSetting, "Group") &&
+ ICQGetContactSettingByte(NULL, "StoreServerDetails", DEFAULT_SS_STORE))
+ { // Test if group was not renamed...
+ WORD wGroupId = ICQGetContactSettingWord((HANDLE)wParam, "SrvGroupId", 0);
+ char* szGroup = makeGroupPathUtf(wGroupId);
+ char* szNewGroup;
+ int bRenamed = 0;
+ int bMoved = 1;
+
+ // Read group from DB
+ szNewGroup = UniGetContactSettingUtf((HANDLE)wParam, "CList", "Group", NULL);
+
+ if (szNewGroup && wGroupId && !GroupNameExistsUtf(szGroup, -1))
+ { // if we moved from non-existing group, it can be rename
+ if (!getServerGroupIDUtf(szNewGroup))
+ { // the target group is not known - it is probably rename
+ if (getServerGroupIDUtf(szGroup))
+ { // source group not known -> already renamed
+ if (countClistGroupLevel(szNewGroup) == countGroupLevel(wGroupId))
+ { // renamed groups can be only in the same level, if not it is move
+ if (!IsGroupRenamed(wGroupId))
+ { // is rename in progress ?
+ bRenamed = 1; // TODO: we should really check if group was not moved to sub-group
+ NetLog_Server("Group %x renamed to ""%s"".", wGroupId, szNewGroup);
+ }
+ else // if rename in progress do not move contacts
+ bMoved = 0;
+ }
+ }
+ }
+ }
+ SAFE_FREE(&szGroup);
+
+ if (bRenamed)
+ renameServGroup(wGroupId, szNewGroup);
+ else if (bMoved) // TODO: this is bad, we badly need rate management
+ moveServContactGroup((HANDLE)wParam, szNewGroup);
+
+ SAFE_FREE(&szNewGroup);
+ }
+ }
+
+ if (!strcmpnull(cws->szModule, "UserInfo"))
+ {
+ if (!strcmpnull(cws->szSetting, "MyNotes") &&
+ ICQGetContactSettingByte(NULL, "StoreServerDetails", DEFAULT_SS_STORE))
+ {
+ if (AddPendingOperation((HANDLE)wParam, NULL, (servlistcookie*)1, NULL))
+ updateServContact((HANDLE)wParam);
+ }
+ }
+
+ return 0;
+}
+
+
+
+static int ServListDbContactDeleted(WPARAM wParam, LPARAM lParam)
+{
+ DeleteFromCache((HANDLE)wParam);
+
+ if (!icqOnline || !gbSsiEnabled)
+ return 0;
+
+ { // we need all server contacts on local buddy list
+ WORD wContactID;
+ WORD wGroupID;
+ WORD wVisibleID;
+ WORD wInvisibleID;
+ WORD wIgnoreID;
+ DWORD dwUIN;
+ uid_str szUID;
+
+ wContactID = ICQGetContactSettingWord((HANDLE)wParam, "ServerId", 0);
+ wGroupID = ICQGetContactSettingWord((HANDLE)wParam, "SrvGroupId", 0);
+ wVisibleID = ICQGetContactSettingWord((HANDLE)wParam, "SrvPermitId", 0);
+ wInvisibleID = ICQGetContactSettingWord((HANDLE)wParam, "SrvDenyId", 0);
+ wIgnoreID = ICQGetContactSettingWord((HANDLE)wParam, "SrvIgnoreId", 0);
+ if (ICQGetContactSettingUID((HANDLE)wParam, &dwUIN, &szUID))
+ return 0;
+
+ // Close all opened peer connections
+ CloseContactDirectConns((HANDLE)wParam);
+
+ if ((wGroupID && wContactID) || wVisibleID || wInvisibleID || wIgnoreID)
+ {
+ if (wContactID)
+ { // delete contact from server
+ removeServContact((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;
+}
+
+
+
+void InitServerLists(void)
+{
+ InitializeCriticalSection(&servlistMutex);
+
+ hHookSettingChanged = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, ServListDbSettingChanged);
+ hHookContactDeleted = HookEvent(ME_DB_CONTACT_DELETED, ServListDbContactDeleted);
+}
+
+
+
+void UninitServerLists(void)
+{
+ if (hHookSettingChanged)
+ UnhookEvent(hHookSettingChanged);
+
+ if (hHookContactDeleted)
+ UnhookEvent(hHookContactDeleted);
+
+ FlushServerIDs();
+ FlushPendingOperations();
+
+ DeleteCriticalSection(&servlistMutex);
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_servlist.h b/miranda-wine/protocols/IcqOscarJ/icq_servlist.h
new file mode 100644
index 0000000..f203a1f
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_servlist.h
@@ -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,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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_servlist.h,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// 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_PRE_ADD 0x14 // add contact to new group, group added
+#define SSA_CONTACT_ADD 0x10 // add contact w/o auth
+#define SSA_CONTACT_ADD_AUTH 0x11 // add contact with auth
+#define SSA_CONTACT_SET_GROUP 0x12 // move to group
+#define SSA_CONTACT_REMOVE 0x13 // delete contact
+#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
+
+typedef void (*GROUPADDCALLBACK)(WORD wGroupId, LPARAM lParam);
+
+// cookie struct for SSI actions
+typedef struct servlistcookie_t
+{
+ DWORD dwUin;
+ HANDLE hContact;
+ WORD wContactId;
+ WORD wGroupId;
+ char* szGroupName;
+ WORD wNewContactId;
+ WORD wNewGroupId;
+ int dwAction;
+ GROUPADDCALLBACK ofCallback;
+ LPARAM lParam;
+} servlistcookie;
+
+
+void InitServerLists(void);
+void UninitServerLists(void);
+
+void* collectGroups(int *count);
+void* collectBuddyGroup(WORD wGroupID, int *count);
+char* getServerGroupNameUtf(WORD wGroupID);
+void setServerGroupNameUtf(WORD wGroupID, const char* szGroupNameUtf);
+WORD getServerGroupIDUtf(const char* szPath);
+void setServerGroupIDUtf(const char* szPath, WORD wGroupID);
+int IsServerGroupsDefined();
+char* makeGroupPathUtf(WORD wGroupId);
+WORD makeGroupId(const char* szGroupPath, GROUPADDCALLBACK ofCallback, servlistcookie* lParam);
+void removeGroupPathLinks(WORD wGroupID);
+int countGroupLevel(WORD wGroupId);
+
+void FlushSrvGroupsCache();
+
+DWORD icq_sendServerContact(HANDLE hContact, DWORD dwCookie, WORD wAction, WORD wGroupId, WORD wContactId);
+DWORD icq_sendSimpleItem(DWORD dwCookie, WORD wAction, DWORD dwUin, char* szUID, WORD wGroupId, WORD wItemId, WORD wItemType);
+DWORD icq_sendGroupUtf(DWORD dwCookie, WORD wAction, WORD wGroupId, const char *szName, void *pContent, int cbContent);
+
+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);
+
+// id type groups
+#define SSIT_ITEM 0
+#define SSIT_GROUP 1
+
+WORD GenerateServerId(int bGroupId);
+WORD GenerateServerIdPair(int bGroupId, int wCount);
+void ReserveServerID(WORD wID, int bGroupId);
+void FreeServerID(WORD wID, int bGroupId);
+BOOL CheckServerID(WORD wID, unsigned int wCount);
+void FlushServerIDs();
+void LoadServerIDs();
+
+void FlushPendingOperations();
+void RemovePendingOperation(HANDLE hContact, int nResult);
+void AddGroupRename(WORD wGroupID);
+void RemoveGroupRename(WORD wGroupID);
+void FlushGroupRenames();
+
+void AddJustAddedContact(HANDLE hContact);
+BOOL IsContactJustAdded(HANDLE hContact);
+void FlushJustAddedContacts();
+
+#endif /* __ICQ_SERVLIST_H */
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_uploadui.c b/miranda-wine/protocols/IcqOscarJ/icq_uploadui.c
new file mode 100644
index 0000000..20ef120
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_uploadui.c
@@ -0,0 +1,1075 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_uploadui.c,v $
+// Revision : $Revision: 3250 $
+// Last change on : $Date: 2006-06-30 02:08:42 +0400 (Птн, 30 Июн 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// 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;
+
+// Selects the "All contacts" checkbox if all other list entries
+// are selected, deselects it if not.
+static void UpdateAllContactsCheckmark(HWND hwndList, HANDLE phItemAll)
+{
+ int check = 1;
+ HANDLE hContact;
+ HANDLE hItem;
+
+ hContact = ICQFindFirstContact();
+
+ while (hContact)
+ {
+ 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 = ICQFindNextContact(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, HANDLE phItemAll)
+{
+ int bAll = 1;
+ HANDLE hContact;
+ HANDLE hItem;
+
+ bListInit = 1; // lock CLC events
+
+ hContact = ICQFindFirstContact();
+ while (hContact)
+ {
+ hItem = (HANDLE)SendMessage(hwndList, CLM_FINDCONTACT, (WPARAM)hContact, 0);
+ if (hItem)
+ {
+ if (ICQGetContactSettingWord(hContact, "ServerId", 0))
+ SendMessage(hwndList, CLM_SETCHECKMARK, (WPARAM)hItem, 1);
+ else
+ bAll = 0;
+ }
+ hContact = ICQFindNextContact(hContact);
+ }
+
+ // Update the "All contacts" checkmark
+ if (phItemAll)
+ SendMessage(hwndList, CLM_SETCHECKMARK, (WPARAM)phItemAll, bAll);
+
+ bListInit = 0;
+
+ return bAll;
+}
+
+
+
+static void DeleteOtherContactsFromControl(HWND hCtrl)
+{
+ HANDLE hContact;
+ HANDLE hItem;
+
+ hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact)
+ {
+ hItem = (HANDLE)SendMessage(hCtrl, CLM_FINDCONTACT, (WPARAM)hContact, 0);
+ if (hItem)
+ {
+ if (!IsICQContact(hContact))
+ SendMessage(hCtrl, CLM_DELETEITEM, (WPARAM)hItem, 0);
+ }
+ hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0);
+ }
+}
+
+
+
+static void AppendToUploadLog(HWND hwndDlg, const char *fmt, ...)
+{
+ va_list va;
+ char szText[1024];
+ char*pszText = NULL;
+ 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)
+{
+ if (gbUnicodeAPI)
+ {
+ wchar_t str[MAX_PATH];
+ char *ustr;
+
+ SendDlgItemMessageW(hwndDlg, IDC_LOG, LB_GETTEXT, SendDlgItemMessage(hwndDlg, IDC_LOG, LB_GETCOUNT, 0, 0)-1, (LPARAM)str);
+ ustr = make_utf8_string(str);
+ strcpy(szBuf, ustr);
+ SAFE_FREE(&ustr);
+ }
+ else
+ {
+ char str[MAX_PATH];
+ char *ustr=NULL;
+
+ SendDlgItemMessageA(hwndDlg, IDC_LOG, LB_GETTEXT, SendDlgItemMessage(hwndDlg, IDC_LOG, LB_GETCOUNT, 0, 0)-1, (LPARAM)str);
+ utf8_encode(str, &ustr);
+ strcpy(szBuf, ustr);
+ SAFE_FREE(&ustr);
+ }
+}
+
+
+
+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*)realloc(pwGroupIds, (cbGroupIds+1)*sizeof(WORD));
+ pwGroupIds[cbGroupIds] = (WORD)strtoul(szSetting, NULL, 0x10);
+ cbGroupIds++;
+ }
+ return 0;
+}
+
+
+
+static void enumServerGroups()
+{
+ DBCONTACTENUMSETTINGS dbces;
+
+ char szModule[MAX_PATH+9];
+
+ strcpy(szModule, gpszICQProtoName);
+ 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(WORD wAction, WORD wGroupId, char* szItemName)
+{
+ DWORD dwCookie;
+ servlistcookie* ack;
+
+ if (ack = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie)))
+ { // we have cookie good, go on
+ ack->wGroupId = wGroupId;
+ ack->dwAction = SSA_SERVLIST_ACK;
+ dwCookie = AllocateCookie(CKT_SERVERLIST, wAction, 0, ack);
+ ack->lParam = dwCookie;
+
+ icq_sendGroupUtf(dwCookie, wAction, ack->wGroupId, szItemName, NULL, 0);
+
+ return dwCookie;
+ }
+ return 0;
+}
+
+static DWORD sendUploadBuddy(HANDLE hContact, WORD wAction, DWORD dwUin, char *szUID, WORD wContactId, WORD wGroupId, WORD wItemType)
+{
+ DWORD dwCookie;
+ servlistcookie* ack;
+
+ if (ack = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie)))
+ { // we have cookie good, go on
+ ack->hContact = hContact;
+ ack->wContactId = wContactId;
+ ack->wGroupId = wGroupId;
+ ack->dwAction = SSA_SERVLIST_ACK;
+ ack->dwUin = dwUin;
+ dwCookie = AllocateCookie(CKT_SERVERLIST, wAction, dwUin, ack);
+ ack->lParam = dwCookie;
+
+ if (wItemType == SSI_ITEM_BUDDY)
+ icq_sendServerContact(hContact, dwCookie, wAction, ack->wGroupId, ack->wContactId);
+ else
+ icq_sendSimpleItem(dwCookie, wAction, dwUin, szUID, ack->wGroupId, ack->wContactId, wItemType);
+
+ return dwCookie;
+ }
+ return 0;
+}
+
+static char* getServerResultDesc(int wCode)
+{
+ switch (wCode)
+ {
+ case 0: return "OK";
+ case 2: return "NOT FOUND";
+ case 3: return "ALREADY EXISTS";
+ case 0xA: return "INVALID DATA";
+ case 0xC: return "LIST FULL";
+ default: return "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 BOOL CALLBACK DlgProcUploadList(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ 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:
+ {
+ char str[MAX_PATH];
+
+ ICQTranslateDialog(hwndDlg);
+ working = 0;
+ hProtoAckHook = NULL;
+ currentState = STATE_READY;
+
+ AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic("Select contacts you want to store on server.", str));
+ AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic("Ready...", str));
+ }
+ 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, gpszICQProtoName))
+ 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);
+ DeleteLastUploadLogLine(hwndDlg);
+ AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic("Server rate warning -> slowing down the process.", str));
+ 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)
+ {
+ ICQWriteContactSettingByte(hCurrentContact, "Auth", 0);
+ ICQWriteContactSettingWord(hCurrentContact, "ServerId", wNewContactId);
+ ICQWriteContactSettingWord(hCurrentContact, "SrvGroupId", wNewGroupId);
+ break;
+ }
+ else
+ { // If the server refused to add the contact without authorization,
+ // we try again _with_ authorization TLV
+ DWORD dwUIN;
+ uid_str szUID;
+
+ ICQWriteContactSettingByte(hCurrentContact, "Auth", 1);
+
+ if (!ICQGetContactSettingUID(hCurrentContact, &dwUIN, &szUID))
+ {
+ currentAction = ACTION_ADDBUDDYAUTH;
+ currentSequence = sendUploadBuddy(hCurrentContact, ICQ_LISTS_ADDTOLIST, dwUIN, szUID, wNewContactId, wNewGroupId, SSI_ITEM_BUDDY);
+ }
+
+ return FALSE;
+ }
+
+ case ACTION_ADDBUDDYAUTH:
+ if (ack->result == ACKRESULT_SUCCESS)
+ {
+ ICQWriteContactSettingWord(hCurrentContact, "ServerId", wNewContactId);
+ ICQWriteContactSettingWord(hCurrentContact, "SrvGroupId", wNewGroupId);
+ }
+ else
+ {
+ ICQDeleteContactSetting(hCurrentContact, "Auth");
+ FreeServerID(wNewContactId, SSIT_ITEM);
+ }
+
+ break;
+
+ case ACTION_REMOVEBUDDY:
+ if (ack->result == ACKRESULT_SUCCESS)
+ { // clear obsolete settings
+ FreeServerID(wNewContactId, SSIT_ITEM);
+ ICQDeleteContactSetting(hCurrentContact, "ServerId");
+ ICQDeleteContactSetting(hCurrentContact, "SrvGroupId");
+ ICQDeleteContactSetting(hCurrentContact, "Auth");
+ }
+ break;
+
+ case ACTION_ADDGROUP:
+ if (ack->result == ACKRESULT_SUCCESS)
+ {
+ void* groupData;
+ int groupSize;
+ servlistcookie* ack;
+
+ setServerGroupNameUtf(wNewGroupId, szNewGroupName); // add group to list
+ setServerGroupIDUtf(szNewGroupName, wNewGroupId); // grouppath is known
+
+ groupData = collectGroups(&groupSize);
+ groupData = realloc(groupData, groupSize+2);
+ *(((WORD*)groupData)+(groupSize>>1)) = wNewGroupId; // add this new group id
+ groupSize += 2;
+
+ ack = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie));
+ if (ack)
+ {
+ DWORD dwCookie; // we do not use this
+
+ ack->dwAction = SSA_SERVLIST_ACK;
+ dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, 0, ack);
+
+ icq_sendGroupUtf(dwCookie, ICQ_LISTS_UPDATEGROUP, 0, ack->szGroupName, groupData, groupSize);
+ }
+ SAFE_FREE(&groupData);
+ }
+ else
+ FreeServerID(wNewGroupId, SSIT_GROUP);
+
+ SAFE_FREE(&szNewGroupName);
+ break;
+
+ case ACTION_REMOVEGROUP:
+ if (ack->result == ACKRESULT_SUCCESS)
+ {
+ void* groupData;
+ int groupSize;
+ servlistcookie* ack;
+
+ FreeServerID(wNewGroupId, SSIT_GROUP);
+ setServerGroupNameUtf(wNewGroupId, NULL); // remove group from list
+ removeGroupPathLinks(wNewGroupId); // grouppath is known
+
+ groupData = collectGroups(&groupSize);
+
+ ack = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie));
+ if (ack)
+ {
+ DWORD dwCookie; // we do not use this
+
+ ack->dwAction = SSA_SERVLIST_ACK;
+ dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, 0, ack);
+
+ icq_sendGroupUtf(dwCookie, ICQ_LISTS_UPDATEGROUP, 0, ack->szGroupName, groupData, groupSize);
+ }
+ SAFE_FREE(&groupData);
+ }
+ break;
+
+ case ACTION_UPDATESTATE:
+ // do nothing
+ break;
+
+ case ACTION_MOVECONTACT:
+ if (ack->result == ACKRESULT_SUCCESS)
+ {
+ FreeServerID(ICQGetContactSettingWord(hCurrentContact, "ServerId", 0), SSIT_ITEM);
+ ICQWriteContactSettingWord(hCurrentContact, "ServerId", wNewContactId);
+ ICQWriteContactSettingWord(hCurrentContact, "SrvGroupId", wNewGroupId);
+ dwUploadDelay *= 2; // we double the delay here (2 packets)
+ }
+ break;
+
+ case ACTION_ADDVISIBLE:
+ if (ack->result == ACKRESULT_SUCCESS)
+ {
+ ICQWriteContactSettingWord(hCurrentContact, "SrvPermitId", wNewContactId);
+ }
+ else
+ FreeServerID(wNewContactId, SSIT_ITEM);
+ break;
+
+ case ACTION_ADDINVISIBLE:
+ if (ack->result == ACKRESULT_SUCCESS)
+ {
+ ICQWriteContactSettingWord(hCurrentContact, "SrvDenyId", wNewContactId);
+ }
+ else
+ FreeServerID(wNewContactId, SSIT_ITEM);
+ break;
+
+ case ACTION_REMOVEVISIBLE:
+ if (ack->result == ACKRESULT_SUCCESS)
+ {
+ FreeServerID(wNewContactId, SSIT_ITEM);
+ ICQWriteContactSettingWord(hCurrentContact, "SrvPermitId", 0);
+ }
+ break;
+
+ case ACTION_REMOVEINVISIBLE:
+ if (ack->result == ACKRESULT_SUCCESS)
+ {
+ FreeServerID(wNewContactId, SSIT_ITEM);
+ ICQWriteContactSettingWord(hCurrentContact, "SrvDenyId", 0);
+ }
+ break;
+ }
+
+ // Update the log window
+ GetLastUploadLogLine(hwndDlg, szLastLogLine);
+ DeleteLastUploadLogLine(hwndDlg);
+ AppendToUploadLog(hwndDlg, "%s%s", szLastLogLine,
+ ICQTranslateUtfStatic(getServerResultDesc(ack->lParam), str));
+
+ 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 = ICQFindFirstContact();
+ 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 = ICQFindNextContact(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 = ICQGetContactSettingWord(hContact, "ServerId", 0) != 0;
+
+ bUidOk = !ICQGetContactSettingUID(hContact, &dwUin, &szUid);
+
+ // Is this one out of sync?
+ if (bUidOk && (isChecked != isOnServer))
+ {
+ // Only upload custom nicks
+ pszNick = UniGetContactSettingUtf(hContact, "CList", "MyHandle", NULL);
+
+ if (isChecked)
+ { // Queue for uploading
+ pszGroup = UniGetContactSettingUtf(hContact, "CList", "Group", NULL);
+ 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 = getServerGroupIDUtf(pszGroup);
+ if (!wNewGroupId && strstr(pszGroup, "\\") != NULL)
+ { // if it is sub-group, take master parent
+ strstr(pszGroup, "\\")[0] = '\0';
+ wNewGroupId = getServerGroupIDUtf(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("Adding group \"%s\"...", str), pszGroup);
+
+ wNewGroupId = GenerateServerId(SSIT_GROUP);
+ szNewGroupName = pszGroup;
+ currentAction = ACTION_ADDGROUP;
+ currentSequence = sendUploadGroup(ICQ_LISTS_ADDTOLIST, wNewGroupId, pszGroup);
+ SAFE_FREE(&pszNick);
+
+ return FALSE;
+ }
+
+ SAFE_FREE(&pszGroup);
+
+ if (pszNick)
+ AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic("Uploading %s...", str), pszNick);
+ else
+ AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic("Uploading %s...", str), strUID(dwUin, szUid));
+
+ currentAction = ACTION_ADDBUDDY;
+
+ if (wNewGroupId)
+ {
+ wNewContactId = GenerateServerId(SSIT_ITEM);
+
+ currentSequence = sendUploadBuddy(hCurrentContact, ICQ_LISTS_ADDTOLIST, dwUin, szUid,
+ wNewContactId, wNewGroupId, SSI_ITEM_BUDDY);
+ SAFE_FREE(&pszNick);
+
+ return FALSE;
+ }
+ else
+ {
+ char szLastLogLine[256];
+ // Update the log window with the failure and continue with next contact
+ GetLastUploadLogLine(hwndDlg, szLastLogLine);
+ DeleteLastUploadLogLine(hwndDlg);
+ AppendToUploadLog(hwndDlg, "%s%s", szLastLogLine, ICQTranslateUtfStatic("FAILED", str));
+ AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic("No upload group available", str));
+ NetLog_Server("Upload failed, no group");
+ currentState = STATE_READY;
+ }
+ }
+ else
+ { // Queue for deletion
+ if (pszNick)
+ AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic("Deleting %s...", str), pszNick);
+ else
+ AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic("Deleting %s...", str), strUID(dwUin, szUid));
+
+ wNewGroupId = ICQGetContactSettingWord(hContact, "SrvGroupId", 0);
+ wNewContactId = ICQGetContactSettingWord(hContact, "ServerId", 0);
+ currentAction = ACTION_REMOVEBUDDY;
+ currentSequence = sendUploadBuddy(hContact, ICQ_LISTS_REMOVEFROMLIST, dwUin, szUid,
+ wNewContactId, wNewGroupId, SSI_ITEM_BUDDY);
+ }
+ SAFE_FREE(&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 = ICQGetContactSettingWord(hContact, "SrvGroupId", 0);
+
+ pszGroup = UniGetContactSettingUtf(hContact, "CList", "Group", NULL);
+ if (!strlennull(pszGroup)) pszGroup = null_strdup(DEFAULT_SS_GROUP);
+ wNewGroupId = getServerGroupIDUtf(pszGroup);
+ if (!wNewGroupId && strstr(pszGroup, "\\") != NULL)
+ { // if it is sub-group, take master parent
+ strstr(pszGroup, "\\")[0] = '\0';
+ wNewGroupId = getServerGroupIDUtf(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("Adding group \"%s\"...", str), pszGroup);
+
+ wNewGroupId = GenerateServerId(SSIT_GROUP);
+ szNewGroupName = pszGroup;
+ currentAction = ACTION_ADDGROUP;
+ currentSequence = sendUploadGroup(ICQ_LISTS_ADDTOLIST, wNewGroupId, pszGroup);
+
+ return FALSE;
+ }
+ if (wNewGroupId && (wNewGroupId != wCurrentGroupId))
+ { // we have a group the contact should be in, move it
+ WORD wCurrentContactId = ICQGetContactSettingWord(hContact, "ServerId", 0);
+ BYTE bAuth = ICQGetContactSettingByte(hContact, "Auth", 0);
+
+ pszNick = UniGetContactSettingUtf(hContact, "CList", "MyHandle", NULL);
+
+ if (pszNick)
+ AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic("Moving %s to group \"%s\"...", str), pszNick, pszGroup);
+ else
+ AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic("Moving %s to group \"%s\"...", str), strUID(dwUin, szUid), pszGroup);
+
+ currentAction = ACTION_MOVECONTACT;
+ wNewContactId = GenerateServerId(SSIT_ITEM);
+ sendUploadBuddy(hContact, ICQ_LISTS_REMOVEFROMLIST, dwUin, szUid, wCurrentContactId, wCurrentGroupId, SSI_ITEM_BUDDY);
+ currentSequence = sendUploadBuddy(hContact, ICQ_LISTS_ADDTOLIST, dwUin, szUid, wNewContactId, wNewGroupId, SSI_ITEM_BUDDY);
+ SAFE_FREE(&pszNick);
+ SAFE_FREE(&pszGroup);
+
+ break;
+ }
+ SAFE_FREE(&pszGroup);
+ }
+ }
+ hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0);
+ }
+ 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 = ICQFindFirstContact();
+ 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 = ICQFindNextContact(hContact);
+ }
+
+ while (hContact)
+ {
+ WORD wApparentMode = ICQGetContactSettingWord(hContact, "ApparentMode", 0);
+ WORD wDenyId = ICQGetContactSettingWord(hContact, "SrvDenyId", 0);
+ WORD wPermitId = ICQGetContactSettingWord(hContact, "SrvPermitId", 0);
+ WORD wIgnoreId = ICQGetContactSettingWord(hContact, "SrvIgnoreId", 0);
+
+ hCurrentContact = hContact;
+ ICQGetContactSettingUID(hContact, &dwUin, &szUid);
+
+ if (wApparentMode == ID_STATUS_ONLINE)
+ { // contact is on the visible list
+ if (wPermitId == 0)
+ {
+ currentAction = ACTION_ADDVISIBLE;
+ wNewContactId = GenerateServerId(SSIT_ITEM);
+ AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic("Adding %s to visible list...", str), strUID(dwUin, szUid));
+ currentSequence = sendUploadBuddy(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 = GenerateServerId(SSIT_ITEM);
+ AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic("Adding %s to invisible list...", str), strUID(dwUin, szUid));
+ currentSequence = sendUploadBuddy(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("Deleting %s from visible list...", str), strUID(dwUin, szUid));
+ currentSequence = sendUploadBuddy(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("Deleting %s from invisible list...", str), strUID(dwUin, szUid));
+ currentSequence = sendUploadBuddy(hContact, ICQ_LISTS_REMOVEFROMLIST, dwUin, szUid, wNewContactId, 0, SSI_ITEM_DENY);
+ break;
+ }
+ }
+ hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0);
+ }
+ if (!hContact)
+ {
+ currentState = STATE_CONSOLIDATE;
+ AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic("Cleaning groups", str));
+ EnableDlgItem(hwndDlg, IDCANCEL, FALSE);
+ enumServerGroups();
+ 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 = collectBuddyGroup(wNewGroupId, &groupSize))
+ { // the group is still not empty, just update it
+ char* pszGroup = getServerGroupNameUtf(wNewGroupId);
+ servlistcookie* ack = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie));
+
+ ack->dwAction = SSA_SERVLIST_ACK;
+ ack->wGroupId = wNewGroupId;
+ currentSequence = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, 0, ack);
+ ack->lParam = currentSequence;
+ currentAction = ACTION_UPDATESTATE;
+ AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic("Updating group \"%s\"...", str), pszGroup);
+
+ icq_sendGroupUtf(currentSequence, ICQ_LISTS_UPDATEGROUP, wNewGroupId, pszGroup, groupData, groupSize);
+
+ SAFE_FREE(&pszGroup);
+ }
+ else // the group is empty, delete it if it does not have sub-groups
+ {
+ if (!CheckServerID((WORD)(wNewGroupId+1), 0) || countGroupLevel((WORD)(wNewGroupId+1)) == 0)
+ { // is next id an sub-group, if yes, we cannot delete this group
+ char* pszGroup = getServerGroupNameUtf(wNewGroupId);
+ currentAction = ACTION_REMOVEGROUP;
+ AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic("Deleting group \"%s\"...", str), pszGroup);
+ currentSequence = sendUploadGroup(ICQ_LISTS_REMOVEFROMLIST, wNewGroupId, pszGroup);
+ SAFE_FREE(&pszGroup);
+ }
+ else // update empty group
+ {
+ char* pszGroup = getServerGroupNameUtf(wNewGroupId);
+ servlistcookie* ack = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie));
+
+ ack->dwAction = SSA_SERVLIST_ACK;
+ ack->wGroupId = wNewGroupId;
+ currentSequence = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, 0, ack);
+ ack->lParam = currentSequence;
+ currentAction = ACTION_UPDATESTATE;
+ AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic("Updating group \"%s\"...", str), pszGroup);
+
+ icq_sendGroupUtf(currentSequence, ICQ_LISTS_UPDATEGROUP, wNewGroupId, pszGroup, 0, 0);
+
+ SAFE_FREE(&pszGroup);
+ }
+ }
+ SAFE_FREE(&groupData); // free the memory
+ }
+ else
+ { // all groups processed
+ SAFE_FREE(&pwGroupIds);
+ currentState = STATE_READY;
+ }
+ break;
+ }
+
+ if (currentState == STATE_READY)
+ {
+ // All contacts are in sync
+ AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic("All operations complete", str));
+ EnableDlgItem(hwndDlg, IDCANCEL, TRUE);
+ SetDlgItemTextUtf(hwndDlg, IDCANCEL, ICQTranslateUtfStatic("Close", str));
+ sendAddEnd();
+ working = 0;
+// SendMessage(hwndList, CLM_SETGREYOUTFLAGS,0,0);
+ UpdateCheckmarks(hwndList, 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 (gnCurrentStatus == ID_STATUS_OFFLINE || gnCurrentStatus == ID_STATUS_CONNECTING)
+ {
+ char str[MAX_PATH];
+
+ AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic("You have to be online to sychronize the server-list !", str));
+ break;
+ }
+ working = 1;
+ hCurrentContact = NULL;
+ currentState = STATE_REGROUP;
+ currentAction = ACTION_NONE;
+ icq_ShowMultipleControls(hwndDlg, settingsControls, sizeof(settingsControls)/sizeof(settingsControls[0]), 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);
+ sendAddStart(1);
+ 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:
+ {
+ int i;
+
+ SendMessage(hClist, CLM_SETLEFTMARGIN, 2, 0);
+ SendMessage(hClist, CLM_SETBKBITMAP, 0, (LPARAM)(HBITMAP)NULL);
+ SendMessage(hClist, CLM_SETBKCOLOR, GetSysColor(COLOR_WINDOW), 0);
+ SendMessage(hClist, CLM_SETGREYOUTFLAGS, working?0xFFFFFFFF:0, 0);
+ for (i=0; i<=FONTID_MAX; i++)
+ SendMessage(hClist, CLM_SETTEXTCOLOR, i, GetSysColor(COLOR_WINDOWTEXT));
+ if (CallService(MS_CLUI_GETCAPS, 0, 0) & CLUIF_HIDEEMPTYGROUPS) // hide empty groups
+ SendMessage(hClist, CLM_SETHIDEEMPTYGROUPS, (WPARAM) TRUE, 0);
+ }
+ break;
+
+ case CLN_NEWCONTACT:
+ case CLN_CONTACTMOVED:
+ {
+ // Delete non-icq contacts
+ DeleteOtherContactsFromControl(hClist);
+ if (hItemAll)
+ UpdateAllContactsCheckmark(hClist, hItemAll);
+ }
+ break;
+
+ case CLN_LISTREBUILT:
+ {
+ int bCheck;
+
+ // Delete non-icq contacts
+ DeleteOtherContactsFromControl(hClist);
+
+ if (!bListInit) // do not enter twice
+ bCheck = UpdateCheckmarks(hClist, NULL);
+
+ if (!hItemAll) // Add the "All contacts" item
+ {
+ CLCINFOITEM cii = {0};
+
+ cii.cbSize = sizeof(cii);
+ cii.flags = CLCIIF_GROUPFONT | CLCIIF_CHECKBOX;
+ cii.pszText = ICQTranslate("** 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 = ICQFindFirstContact();
+ while (hContact)
+ {
+ hItem = (HANDLE)SendMessage(hClist, CLM_FINDCONTACT, (WPARAM)hContact, 0);
+ if (hItem)
+ SendMessage(hClist, CLM_SETCHECKMARK, (WPARAM)hItem, check);
+ hContact = ICQFindNextContact(hContact);
+ }
+ }
+ else
+ {
+ UpdateAllContactsCheckmark(hClist, hItemAll);
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ break;
+
+ case WM_CLOSE:
+ DestroyWindow(hwndDlg);
+ break;
+
+ case WM_DESTROY:
+ if (hProtoAckHook)
+ UnhookEvent(hProtoAckHook);
+ if (working)
+ sendAddEnd();
+ hwndUploadContacts = NULL;
+ working = 0;
+ break;
+ }
+
+ return FALSE;
+}
+
+
+
+void ShowUploadContactsDialog(void)
+{
+ if (hwndUploadContacts == NULL)
+ {
+ hItemAll = NULL;
+ hwndUploadContacts = CreateDialogUtf(hInst, MAKEINTRESOURCE(IDD_ICQUPLOADLIST), NULL, DlgProcUploadList);
+ }
+
+ SetForegroundWindow(hwndUploadContacts);
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_uploadui.h b/miranda-wine/protocols/IcqOscarJ/icq_uploadui.h
new file mode 100644
index 0000000..ccd97bc
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_uploadui.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,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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_uploadui.h,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+
+
+void ShowUploadContactsDialog(void);
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_xstatus.c b/miranda-wine/protocols/IcqOscarJ/icq_xstatus.c
new file mode 100644
index 0000000..7308b8b
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_xstatus.c
@@ -0,0 +1,1245 @@
+// ---------------------------------------------------------------------------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 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_xstatus.c,v $
+// Revision : $Revision: 3529 $
+// Last change on : $Date: 2006-08-18 02:30:37 +0400 (Птн, 18 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Support for Custom Statuses
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+#include "m_cluiframes.h"
+
+
+extern void setUserInfo();
+
+extern HANDLE hxstatusiconchanged;
+
+int bHideXStatusUI = 0;
+static int bStatusMenu = 0;
+static int bXStatusMenuBuilt = 0;
+static HANDLE hHookExtraIconsRebuild = NULL;
+static HANDLE hHookStatusBuild = NULL;
+static HANDLE hHookExtraIconsApply = NULL;
+static HMODULE hXStatusIconsDLL = NULL;
+static HANDLE hXStatusIcons[32];
+static HANDLE hXStatusItems[33];
+
+void CListShowMenuItem(HANDLE hMenuItem, BYTE bShow);
+void CListSetMenuItemIcon(HANDLE hMenuItem, HICON hIcon);
+
+
+DWORD sendXStatusDetailsRequest(HANDLE hContact, int bForced)
+{
+ char *szNotify;
+ int nNotifyLen;
+ DWORD dwCookie;
+
+ nNotifyLen = 94 + UINMAXLEN;
+ szNotify = (char*)_alloca(nNotifyLen);
+ nNotifyLen = null_snprintf(szNotify, nNotifyLen, "<srv><id>cAwaySrv</id><req><id>AwayStat</id><trans>1</trans><senderId>%d</senderId></req></srv>", dwLocalUIN);
+
+ dwCookie = SendXtrazNotifyRequest(hContact, "<Q><PluginID>srvMng</PluginID></Q>", szNotify, bForced);
+
+ return dwCookie;
+}
+
+
+
+static DWORD requestXStatusDetails(HANDLE hContact, BOOL bAllowDelay)
+{
+ rate_record rr = {0};
+
+ if (!validateStatusMessageRequest(hContact, MTYPE_SCRIPT_NOTIFY))
+ return 0; // apply privacy rules
+
+ // 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
+
+ rr.hContact = hContact;
+ rr.bType = RIT_XSTATUS_REQUEST;
+ rr.rate_group = 0x101; // request
+ rr.nMinDelay = 1000; // delay at least 1s
+
+ if (!handleRateItem(&rr, bAllowDelay))
+ return sendXStatusDetailsRequest(hContact, !bAllowDelay);
+
+ return -1; // delayed
+}
+
+
+
+static HANDLE LoadXStatusIconLibrary(char* path, const char* sub)
+{
+ char* p = strrchr(path, '\\');
+ HANDLE hLib;
+
+ strcpy(p, sub);
+ strcat(p, "\\xstatus_ICQ.dll");
+ if (hLib = LoadLibrary(path)) return hLib;
+ strcpy(p, sub);
+ strcat(p, "\\xstatus_icons.dll");
+ if (hLib = LoadLibrary(path)) return hLib;
+ strcpy(p, "\\");
+ return hLib;
+}
+
+
+
+static char* InitXStatusIconLibrary(char* buf)
+{
+ char path[2*MAX_PATH];
+
+ // get miranda's exe path
+ GetModuleFileNameA(NULL, path, MAX_PATH);
+
+ hXStatusIconsDLL = LoadXStatusIconLibrary(path, "\\Icons");
+ if (!hXStatusIconsDLL) // TODO: add "Custom Folders" support
+ hXStatusIconsDLL = LoadXStatusIconLibrary(path, "\\Plugins");
+
+ if (hXStatusIconsDLL)
+ {
+ strcpy(buf, path);
+
+ if (LoadStringA(hXStatusIconsDLL, IDS_IDENTIFY, path, sizeof(path)) == 0 || strcmp(path, "# Custom Status Icons #"))
+ {
+ FreeLibrary(hXStatusIconsDLL);
+ hXStatusIconsDLL = NULL;
+ }
+ else
+ return buf;
+ }
+ *buf = '\0';
+
+ return buf;
+}
+
+
+
+HICON LoadDefaultXStatusIcon(int bStatus)
+{
+ if (hXStatusIconsDLL)
+ return LoadImage(hXStatusIconsDLL, MAKEINTRESOURCE(IDI_XSTATUS1 + bStatus - 1), IMAGE_ICON, 0, 0, 0);
+ else
+ return NULL;
+}
+
+
+
+HICON GetXStatusIcon(int bStatus)
+{
+ char szTemp[64];
+
+ null_snprintf(szTemp, sizeof(szTemp), "xstatus%d", bStatus - 1);
+
+ if (IconLibInstalled())
+ return IconLibProcess(NULL, szTemp);
+
+ return LoadDefaultXStatusIcon(bStatus);
+}
+
+
+
+static void setContactExtraIcon(HANDLE hContact, HANDLE hIcon)
+{
+ IconExtraColumn iec;
+
+ iec.cbSize = sizeof(iec);
+ iec.hImage = hIcon;
+ iec.ColumnType = EXTRA_ICON_ADV1;
+ CallService(MS_CLIST_EXTRA_SET_ICON, (WPARAM)hContact, (LPARAM)&iec);
+
+ NotifyEventHooks(hxstatusiconchanged, (WPARAM)hContact, (LPARAM)hIcon);
+}
+
+
+
+static int CListMW_ExtraIconsRebuild(WPARAM wParam, LPARAM lParam)
+{
+ int i;
+
+ if (gbXStatusEnabled && ServiceExists(MS_CLIST_EXTRA_ADD_ICON))
+ {
+ for (i = 0; i < 32; i++)
+ {
+ HICON hXIcon = LoadDefaultXStatusIcon(i + 1);
+ char szTemp[64];
+
+ null_snprintf(szTemp, sizeof(szTemp), "xstatus%d", i);
+ hXStatusIcons[i] = (HANDLE)CallService(MS_CLIST_EXTRA_ADD_ICON, (WPARAM)IconLibProcess(hXIcon, szTemp), 0);
+ DestroyIcon(hXIcon);
+ }
+ }
+
+ return 0;
+}
+
+
+
+static int CListMW_ExtraIconsApply(WPARAM wParam, LPARAM lParam)
+{
+ if (gbXStatusEnabled && ServiceExists(MS_CLIST_EXTRA_SET_ICON))
+ {
+ if (IsICQContact((HANDLE)wParam))
+ { // only apply icons to our contacts, do not mess others
+ DWORD bXStatus = ICQGetContactSettingByte((HANDLE)wParam, DBSETTING_XSTATUSID, 0);
+
+ if (bXStatus > 0 && bXStatus < 33)
+ {
+ setContactExtraIcon((HANDLE)wParam, hXStatusIcons[bXStatus-1]);
+ }
+ else
+ {
+ setContactExtraIcon((HANDLE)wParam, (HANDLE)-1);
+ }
+ }
+ }
+ return 0;
+}
+
+
+
+static int CListMW_BuildStatusItems(WPARAM wParam, LPARAM lParam)
+{
+ InitXStatusItems(TRUE);
+ return 0;
+}
+
+
+
+void InitXStatusEvents()
+{
+ if (!hHookStatusBuild)
+ if (bStatusMenu = ServiceExists(MS_CLIST_ADDSTATUSMENUITEM))
+ hHookStatusBuild = HookEvent(ME_CLIST_PREBUILDSTATUSMENU, CListMW_BuildStatusItems);
+
+ if (!hHookExtraIconsRebuild)
+ hHookExtraIconsRebuild = HookEvent(ME_CLIST_EXTRA_LIST_REBUILD, CListMW_ExtraIconsRebuild);
+
+ if (!hHookExtraIconsApply)
+ hHookExtraIconsApply = HookEvent(ME_CLIST_EXTRA_IMAGE_APPLY, CListMW_ExtraIconsApply);
+}
+
+
+
+void UninitXStatusEvents()
+{
+ if (hHookStatusBuild)
+ UnhookEvent(hHookStatusBuild);
+
+ if (hHookExtraIconsRebuild)
+ UnhookEvent(hHookExtraIconsRebuild);
+
+ if (hHookExtraIconsApply)
+ UnhookEvent(hHookExtraIconsApply);
+}
+
+
+
+const capstr capXStatus[32] = {
+ {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}};
+
+const char* nameXStatus[32] = {
+ "Angry",
+ "Taking a bath",
+ "Tired",
+ "Party",
+ "Drinking beer",
+ "Thinking",
+ "Eating",
+ "Watching TV",
+ "Meeting",
+ "Coffee",
+ "Listening to music",
+ "Business",
+ "Shooting",
+ "Having fun",
+ "On the phone",
+ "Gaming",
+ "Studying",
+ "Shopping",
+ "Feeling sick",
+ "Sleeping",
+ "Surfing",
+ "Browsing",
+ "Working",
+ "Typing",
+ "Picnic",
+ "Cooking",
+ "Smoking",
+ "I'm high",
+ "On WC",
+ "To be or not to be",
+ "Watching pro7 on TV",
+ "Love"};
+
+
+void handleXStatusCaps(HANDLE hContact, char* caps, int capsize)
+{
+ HANDLE hIcon = (HANDLE)-1;
+
+ if (!gbXStatusEnabled) return;
+
+ if (caps)
+ {
+ int i;
+
+ for (i = 0; i<32; i++)
+ {
+ if (MatchCap(caps, capsize, (const capstr*)capXStatus[i], 0x10))
+ {
+ char str[MAX_PATH];
+
+ ICQWriteContactSettingByte(hContact, DBSETTING_XSTATUSID, (BYTE)(i+1));
+ ICQWriteContactSettingUtf(hContact, DBSETTING_XSTATUSNAME, ICQTranslateUtfStatic(nameXStatus[i], str));
+
+ if (ICQGetContactSettingByte(NULL, "XStatusAuto", DEFAULT_XSTATUS_AUTO))
+ requestXStatusDetails(hContact, TRUE);
+
+ hIcon = hXStatusIcons[i];
+
+ break;
+ }
+ }
+ }
+ if (hIcon == (HANDLE)-1)
+ {
+ ICQDeleteContactSetting(hContact, DBSETTING_XSTATUSID);
+ ICQDeleteContactSetting(hContact, DBSETTING_XSTATUSNAME);
+ ICQDeleteContactSetting(hContact, DBSETTING_XSTATUSMSG);
+ }
+
+ if (gbXStatusEnabled != 10)
+ {
+ setContactExtraIcon(hContact, hIcon);
+ }
+}
+
+
+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_t *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_t) * (wcslen(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 CallWindowProcUtf(OldMessageEditProc,hwnd,msg,wParam,lParam);
+}
+
+
+typedef struct SetXStatusData_s {
+ BYTE bAction;
+ BYTE bXStatus;
+ HANDLE hContact;
+ HANDLE hEvent;
+ DWORD iEvent;
+ int countdown;
+ char *okButtonFormat;
+ HICON hDlgIcon;
+} SetXStatusData;
+
+typedef struct InitXStatusData_s {
+ BYTE bAction;
+ BYTE bXStatus;
+ HANDLE hContact;
+} InitXStatusData;
+
+#define HM_PROTOACK (WM_USER+10)
+static BOOL CALLBACK SetXStatusDlgProc(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ SetXStatusData *dat = (SetXStatusData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ char str[MAX_PATH];
+
+ switch(message)
+ {
+ case HM_PROTOACK:
+ {
+ ACKDATA *ack = (ACKDATA*)lParam;
+ char *szText;
+
+ if (ack->type != ICQACKTYPE_XSTATUS_RESPONSE) break;
+ if (ack->hContact != dat->hContact) break;
+ if ((DWORD)ack->hProcess != dat->iEvent) break;
+
+ ShowWindow(GetDlgItem(hwndDlg, IDC_RETRXSTATUS), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_XMSG), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_XTITLE), SW_SHOW);
+ SetDlgItemTextUtf(hwndDlg,IDOK,ICQTranslateUtfStatic("Close", str));
+ UnhookEvent(dat->hEvent); dat->hEvent = NULL;
+ szText = ICQGetContactSettingUtf(dat->hContact, DBSETTING_XSTATUSNAME, "");
+ SetDlgItemTextUtf(hwndDlg, IDC_XTITLE, szText);
+ SAFE_FREE(&szText);
+ szText = ICQGetContactSettingUtf(dat->hContact, DBSETTING_XSTATUSMSG, "");
+ SetDlgItemTextUtf(hwndDlg, IDC_XMSG, szText);
+ SAFE_FREE(&szText);
+
+ break;
+ }
+ case WM_INITDIALOG:
+ {
+ InitXStatusData *init = (InitXStatusData*)lParam;
+
+ ICQTranslateDialog(hwndDlg);
+ dat = (SetXStatusData*)SAFE_MALLOC(sizeof(SetXStatusData));
+ SetWindowLong(hwndDlg,GWL_USERDATA,(LONG)dat);
+ dat->bAction = init->bAction;
+
+ if (!init->bAction)
+ { // set our xStatus
+ char szSetting[64];
+ char* szValue;
+
+ dat->bXStatus = init->bXStatus;
+ SendDlgItemMessage(hwndDlg, IDC_XTITLE, EM_LIMITTEXT, 256, 0);
+ SendDlgItemMessage(hwndDlg, IDC_XMSG, EM_LIMITTEXT, 1024, 0);
+ OldMessageEditProc = (WNDPROC)SetWindowLongUtf(GetDlgItem(hwndDlg,IDC_XTITLE),GWL_WNDPROC,(LONG)MessageEditSubclassProc);
+ OldMessageEditProc = (WNDPROC)SetWindowLongUtf(GetDlgItem(hwndDlg,IDC_XMSG),GWL_WNDPROC,(LONG)MessageEditSubclassProc);
+ dat->okButtonFormat = GetDlgItemTextUtf(hwndDlg,IDOK);
+
+ dat->countdown=5;
+ SendMessage(hwndDlg, WM_TIMER, 0, 0);
+ SetTimer(hwndDlg,1,1000,0);
+
+ sprintf(szSetting, "XStatus%dName", dat->bXStatus);
+ szValue = ICQGetContactSettingUtf(NULL, szSetting, "");
+ SetDlgItemTextUtf(hwndDlg, IDC_XTITLE, szValue);
+ SAFE_FREE(&szValue);
+
+ sprintf(szSetting, "XStatus%dMsg", dat->bXStatus);
+ szValue = ICQGetContactSettingUtf(NULL, szSetting, "");
+ SetDlgItemTextUtf(hwndDlg, IDC_XMSG, szValue);
+ SAFE_FREE(&szValue);
+ }
+ else
+ { // retrieve contact's xStatus
+ dat->hContact = init->hContact;
+ dat->bXStatus = ICQGetContactSettingByte(dat->hContact, DBSETTING_XSTATUSID, 0);
+ dat->okButtonFormat = NULL;
+ SendMessage(GetDlgItem(hwndDlg, IDC_XTITLE), EM_SETREADONLY, 1, 0);
+ SendMessage(GetDlgItem(hwndDlg, IDC_XMSG), EM_SETREADONLY, 1, 0);
+ if (!ICQGetContactSettingByte(NULL, "XStatusAuto", DEFAULT_XSTATUS_AUTO))
+ {
+ SetDlgItemTextUtf(hwndDlg,IDOK,ICQTranslateUtfStatic("Cancel", str));
+ dat->hEvent = HookEventMessage(ME_PROTO_ACK, hwndDlg, HM_PROTOACK);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_RETRXSTATUS), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_XMSG), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_XTITLE), SW_HIDE);
+ dat->iEvent = requestXStatusDetails(dat->hContact, FALSE);
+ }
+ else
+ {
+ char *szText;
+
+ SetDlgItemTextUtf(hwndDlg,IDOK,ICQTranslateUtfStatic("Close", str));
+ dat->hEvent = NULL;
+ szText = ICQGetContactSettingUtf(dat->hContact, DBSETTING_XSTATUSNAME, "");
+ SetDlgItemTextUtf(hwndDlg, IDC_XTITLE, szText);
+ SAFE_FREE(&szText);
+ szText = ICQGetContactSettingUtf(dat->hContact, DBSETTING_XSTATUSMSG, "");
+ SetDlgItemTextUtf(hwndDlg, IDC_XMSG, szText);
+ SAFE_FREE(&szText);
+ }
+ }
+
+ if (dat->bXStatus)
+ {
+ HICON iXStatus = GetXStatusIcon(dat->bXStatus);
+
+ dat->hDlgIcon = iXStatus;
+ }
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)dat->hDlgIcon);
+
+ {
+ char *format;
+ char buf[MAX_PATH];
+
+ format = GetWindowTextUtf(hwndDlg);
+ null_snprintf(str, sizeof(str), format, dat->bXStatus?ICQTranslateUtfStatic(nameXStatus[dat->bXStatus-1], buf):"");
+ 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("OK", str));
+ }
+ break;
+ }
+ break;
+
+ case WM_DESTROY:
+ if (!dat->bAction)
+ { // set our xStatus
+ char szSetting[64];
+ char* szValue;
+
+ szValue = GetDlgItemTextUtf(hwndDlg,IDC_XMSG);
+ sprintf(szSetting, "XStatus%dMsg", dat->bXStatus);
+ ICQWriteContactSettingUtf(NULL, szSetting, szValue);
+ ICQWriteContactSettingUtf(NULL, DBSETTING_XSTATUSMSG, szValue);
+ SAFE_FREE(&szValue);
+ szValue = GetDlgItemTextUtf(hwndDlg,IDC_XTITLE);
+ sprintf(szSetting, "XStatus%dName", dat->bXStatus);
+ ICQWriteContactSettingUtf(NULL, szSetting, szValue);
+ ICQWriteContactSettingUtf(NULL, DBSETTING_XSTATUSNAME, szValue);
+ SAFE_FREE(&szValue);
+
+ setUserInfo();
+
+ SetWindowLongUtf(GetDlgItem(hwndDlg,IDC_XMSG),GWL_WNDPROC,(LONG)OldMessageEditProc);
+ SetWindowLongUtf(GetDlgItem(hwndDlg,IDC_XTITLE),GWL_WNDPROC,(LONG)OldMessageEditProc);
+ }
+ if (dat->hEvent) UnhookEvent(dat->hEvent);
+ SAFE_FREE(&dat->okButtonFormat);
+ if (dat->hDlgIcon && !IconLibInstalled())
+ DestroyIcon(dat->hDlgIcon); // release dialog icon
+ SAFE_FREE(&dat);
+ break;
+
+ case WM_CLOSE:
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ return FALSE;
+}
+
+
+
+static void setXStatusEx(BYTE bXStatus, BYTE bQuiet)
+{
+ CLISTMENUITEM mi = {0};
+ BYTE bOldXStatus = ICQGetContactSettingByte(NULL, DBSETTING_XSTATUSID, 0);
+
+ mi.cbSize = sizeof(mi);
+
+ if (bOldXStatus <= 32)
+ {
+ mi.flags = CMIM_FLAGS;
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hXStatusItems[bOldXStatus], (LPARAM)&mi);
+ }
+
+ ICQWriteContactSettingByte(NULL, DBSETTING_XSTATUSID, bXStatus);
+ mi.flags = CMIM_FLAGS | (bXStatus?CMIF_CHECKED:0);
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hXStatusItems[bXStatus], (LPARAM)&mi);
+
+ if (bXStatus)
+ {
+ char szSetting[64];
+ char str[MAX_PATH];
+ char* szUtf;
+
+ sprintf(szSetting, "XStatus%dName", bXStatus);
+ szUtf = ICQGetContactSettingUtf(NULL, szSetting, ICQTranslateUtfStatic(nameXStatus[bXStatus-1], str));
+ ICQWriteContactSettingUtf(NULL, DBSETTING_XSTATUSNAME, szUtf);
+ SAFE_FREE(&szUtf);
+
+ sprintf(szSetting, "XStatus%dMsg", bXStatus);
+ szUtf = ICQGetContactSettingUtf(NULL, szSetting, "");
+ ICQWriteContactSettingUtf(NULL, DBSETTING_XSTATUSMSG, szUtf);
+ SAFE_FREE(&szUtf);
+
+ sprintf(szSetting, "XStatus%dStat", bXStatus);
+ if (!bQuiet && !ICQGetContactSettingByte(NULL, szSetting, 0))
+ {
+ InitXStatusData init;
+
+ init.bAction = 0; // set
+ init.bXStatus = bXStatus;
+ DialogBoxUtf(FALSE, hInst, MAKEINTRESOURCEA(IDD_SETXSTATUS),NULL,SetXStatusDlgProc,(LPARAM)&init);
+ }
+ else
+ setUserInfo();
+ }
+ else
+ {
+ ICQDeleteContactSetting(NULL, DBSETTING_XSTATUSNAME);
+ ICQDeleteContactSetting(NULL, DBSETTING_XSTATUSMSG);
+
+ setUserInfo();
+ }
+}
+
+
+
+static void __fastcall setXStatus(BYTE bXStatus)
+{ // for menu commands
+ setXStatusEx(bXStatus, 0);
+}
+
+static int menuXStatus0(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(0); return 0;
+}
+
+static int menuXStatus1(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(1); return 0;
+}
+
+static int menuXStatus2(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(2); return 0;
+}
+
+static int menuXStatus3(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(3); return 0;
+}
+
+static int menuXStatus4(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(4); return 0;
+}
+
+static int menuXStatus5(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(5); return 0;
+}
+
+static int menuXStatus6(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(6); return 0;
+}
+
+static int menuXStatus7(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(7); return 0;
+}
+
+static int menuXStatus8(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(8); return 0;
+}
+
+static int menuXStatus9(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(9); return 0;
+}
+
+static int menuXStatus10(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(10); return 0;
+}
+
+static int menuXStatus11(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(11); return 0;
+}
+
+static int menuXStatus12(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(12); return 0;
+}
+
+static int menuXStatus13(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(13); return 0;
+}
+
+static int menuXStatus14(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(14); return 0;
+}
+
+static int menuXStatus15(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(15); return 0;
+}
+
+static int menuXStatus16(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(16); return 0;
+}
+
+static int menuXStatus17(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(17); return 0;
+}
+
+static int menuXStatus18(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(18); return 0;
+}
+
+static int menuXStatus19(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(19); return 0;
+}
+
+static int menuXStatus20(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(20); return 0;
+}
+
+static int menuXStatus21(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(21); return 0;
+}
+
+static int menuXStatus22(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(22); return 0;
+}
+
+static int menuXStatus23(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(23); return 0;
+}
+
+static int menuXStatus24(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(24); return 0;
+}
+
+static int menuXStatus25(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(25); return 0;
+}
+
+static int menuXStatus26(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(26); return 0;
+}
+
+static int menuXStatus27(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(27); return 0;
+}
+
+static int menuXStatus28(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(28); return 0;
+}
+
+static int menuXStatus29(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(29); return 0;
+}
+
+static int menuXStatus30(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(30); return 0;
+}
+static int menuXStatus31(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(31); return 0;
+}
+static int menuXStatus32(WPARAM wParam,LPARAM lParam)
+{
+ setXStatus(32); return 0;
+}
+
+
+void InitXStatusItems(BOOL bAllowStatus)
+{
+ CLISTMENUITEM mi;
+ int i = 0;
+ char srvFce[MAX_PATH + 64];
+ char szItem[MAX_PATH + 64];
+ HANDLE hXStatusRoot;
+
+ BYTE bXStatus = ICQGetContactSettingByte(NULL, DBSETTING_XSTATUSID, 0);
+
+ if (!gbXStatusEnabled) return;
+
+ if (bStatusMenu && !bAllowStatus) return;
+
+ null_snprintf(szItem, sizeof(szItem), ICQTranslate("%s Custom Status"), gpszICQProtoName);
+ mi.cbSize = sizeof(mi);
+ mi.pszPopupName = szItem;
+ mi.popupPosition= 500084000;
+ mi.position = 2000040000;
+
+ for(i = 0; i <= 32; i++)
+ {
+ char szTemp[64];
+ HICON hIIcon = (i > 0) ? LoadDefaultXStatusIcon(i) : NULL;
+
+ null_snprintf(srvFce, sizeof(srvFce), "%s/menuXStatus%d", gpszICQProtoName, i);
+
+ null_snprintf(szTemp, sizeof(szTemp), "xstatus%d", i-1);
+ mi.hIcon = IconLibProcess(hIIcon, szTemp);
+ mi.position++;
+
+ if (!bXStatusMenuBuilt)
+ {
+ switch(i)
+ {
+ case 0: CreateServiceFunction(srvFce, menuXStatus0); break;
+ case 1: CreateServiceFunction(srvFce, menuXStatus1); break;
+ case 2: CreateServiceFunction(srvFce, menuXStatus2); break;
+ case 3: CreateServiceFunction(srvFce, menuXStatus3); break;
+ case 4: CreateServiceFunction(srvFce, menuXStatus4); break;
+ case 5: CreateServiceFunction(srvFce, menuXStatus5); break;
+ case 6: CreateServiceFunction(srvFce, menuXStatus6); break;
+ case 7: CreateServiceFunction(srvFce, menuXStatus7); break;
+ case 8: CreateServiceFunction(srvFce, menuXStatus8); break;
+ case 9: CreateServiceFunction(srvFce, menuXStatus9); break;
+ case 10: CreateServiceFunction(srvFce, menuXStatus10); break;
+ case 11: CreateServiceFunction(srvFce, menuXStatus11); break;
+ case 12: CreateServiceFunction(srvFce, menuXStatus12); break;
+ case 13: CreateServiceFunction(srvFce, menuXStatus13); break;
+ case 14: CreateServiceFunction(srvFce, menuXStatus14); break;
+ case 15: CreateServiceFunction(srvFce, menuXStatus15); break;
+ case 16: CreateServiceFunction(srvFce, menuXStatus16); break;
+ case 17: CreateServiceFunction(srvFce, menuXStatus17); break;
+ case 18: CreateServiceFunction(srvFce, menuXStatus18); break;
+ case 19: CreateServiceFunction(srvFce, menuXStatus19); break;
+ case 20: CreateServiceFunction(srvFce, menuXStatus20); break;
+ case 21: CreateServiceFunction(srvFce, menuXStatus21); break;
+ case 22: CreateServiceFunction(srvFce, menuXStatus22); break;
+ case 23: CreateServiceFunction(srvFce, menuXStatus23); break;
+ case 24: CreateServiceFunction(srvFce, menuXStatus24); break;
+ case 25: CreateServiceFunction(srvFce, menuXStatus25); break;
+ case 26: CreateServiceFunction(srvFce, menuXStatus26); break;
+ case 27: CreateServiceFunction(srvFce, menuXStatus27); break;
+ case 28: CreateServiceFunction(srvFce, menuXStatus28); break;
+ case 29: CreateServiceFunction(srvFce, menuXStatus29); break;
+ case 30: CreateServiceFunction(srvFce, menuXStatus30); break;
+ case 31: CreateServiceFunction(srvFce, menuXStatus31); break;
+ case 32: CreateServiceFunction(srvFce, menuXStatus32); break;
+ }
+ }
+
+ mi.flags = bXStatus == i?CMIF_CHECKED:0;
+ mi.pszName = ICQTranslate(i?nameXStatus[i-1]:"None");
+ mi.pszService = srvFce;
+ mi.pszContactOwner = gpszICQProtoName;
+
+ if (bStatusMenu)
+ hXStatusItems[i] = (HANDLE)CallService(MS_CLIST_ADDSTATUSMENUITEM, (WPARAM)&hXStatusRoot, (LPARAM)&mi);
+ else
+ hXStatusItems[i] = (HANDLE)CallService(MS_CLIST_ADDMAINMENUITEM, 0, (LPARAM)&mi);
+ if (i) DestroyIcon(hIIcon);
+ }
+
+ bXStatusMenuBuilt = 1;
+}
+
+
+
+void InitXStatusIcons()
+{
+ char szSection[MAX_PATH + 64];
+ char str[MAX_PATH], prt[MAX_PATH];
+ char lib[2*MAX_PATH] = {0};
+ char* icon_lib;
+ int i;
+
+ if (!gbXStatusEnabled) return;
+
+ icon_lib = InitXStatusIconLibrary(lib);
+
+ null_snprintf(szSection, sizeof(szSection), ICQTranslateUtfStatic("%s/Custom Status", str), ICQTranslateUtfStatic(gpszICQProtoName, prt));
+
+ for (i = 0; i < 32; i++)
+ {
+ char szTemp[64];
+
+ null_snprintf(szTemp, sizeof(szTemp), "xstatus%d", i);
+ IconLibDefine(ICQTranslateUtfStatic(nameXStatus[i], str), szSection, szTemp, NULL, icon_lib, -(IDI_XSTATUS1+i));
+ }
+
+ if (bXStatusMenuBuilt)
+ ChangedIconsXStatus();
+}
+
+
+
+void ChangedIconsXStatus()
+{ // reload icons
+ int i;
+
+ if (!gbXStatusEnabled) return;
+
+ for (i = 1; i < 33; i++)
+ {
+ HICON hIcon = GetXStatusIcon(i);
+
+ CListSetMenuItemIcon(hXStatusItems[i], hIcon);
+ if (!IconLibInstalled())
+ DestroyIcon(hIcon); // if not IconLib resource release
+ }
+}
+
+
+
+int IcqShowXStatusDetails(WPARAM wParam, LPARAM lParam)
+{
+ InitXStatusData init;
+
+ init.bAction = 1; // retrieve
+ init.hContact = (HANDLE)wParam;
+ DialogBoxUtf(FALSE, hInst, MAKEINTRESOURCEA(IDD_SETXSTATUS), NULL, SetXStatusDlgProc, (LPARAM)&init);
+
+ return 0;
+}
+
+
+
+int IcqSetXStatus(WPARAM wParam, LPARAM lParam)
+{ // obsolete (TODO: remove in next version)
+ if (!gbXStatusEnabled) return 0;
+
+ if (wParam >= 0 && wParam <= 32)
+ {
+ setXStatusEx((BYTE)wParam, 1);
+
+ return wParam;
+ }
+ return 0;
+}
+
+
+
+int IcqGetXStatus(WPARAM wParam, LPARAM lParam)
+{ // obsolete (TODO: remove in next version)
+ BYTE status = ICQGetContactSettingByte(NULL, DBSETTING_XSTATUSID, 0);
+
+ if (!gbXStatusEnabled) return 0;
+
+ if (!icqOnline) return 0;
+
+ if (status < 1 || status > 32) status = 0;
+
+ if (wParam) *((char**)wParam) = DBSETTING_XSTATUSNAME;
+ if (lParam) *((char**)lParam) = DBSETTING_XSTATUSMSG;
+
+ return status;
+}
+
+
+
+int IcqSetXStatusEx(WPARAM wParam, LPARAM lParam)
+{
+ ICQ_CUSTOM_STATUS *pData = (ICQ_CUSTOM_STATUS*)lParam;
+
+ if (!gbXStatusEnabled) 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 <= 32)
+ {
+ setXStatusEx((BYTE)status, 1);
+ }
+ else
+ return 1; // Failure
+ }
+
+ if (pData->flags & (CSSF_MASK_NAME | CSSF_MASK_MESSAGE))
+ {
+ BYTE status = ICQGetContactSettingByte(NULL, DBSETTING_XSTATUSID, 0);
+
+ if (status < 1 || status > 32) return 1; // Failure
+
+ if (pData->flags & CSSF_MASK_NAME)
+ { // set custom status name
+ if (pData->flags & CSSF_UNICODE)
+ {
+ char* utf = make_utf8_string(pData->pwszName);
+
+ ICQWriteContactSettingUtf(NULL, DBSETTING_XSTATUSNAME, utf);
+ SAFE_FREE(&utf);
+ }
+ else
+ ICQWriteContactSettingString(NULL, DBSETTING_XSTATUSNAME, pData->pszName);
+ }
+ if (pData->flags & CSSF_MASK_MESSAGE)
+ { // set custom status message
+ if (pData->flags & CSSF_UNICODE)
+ {
+ char* utf = make_utf8_string(pData->pwszMessage);
+
+ ICQWriteContactSettingUtf(NULL, DBSETTING_XSTATUSMSG, utf);
+ SAFE_FREE(&utf);
+ }
+ else
+ ICQWriteContactSettingString(NULL, DBSETTING_XSTATUSMSG, pData->pszMessage);
+ }
+ }
+
+ if (pData->flags & CSSF_DISABLE_UI)
+ { // hide menu items
+ int n;
+
+ bHideXStatusUI = (*pData->wParam) ? 0 : 1;
+
+ for (n = 0; n<=32; n++)
+ CListShowMenuItem(hXStatusItems[n], (BYTE)!bHideXStatusUI);
+ }
+
+ return 0; // Success
+}
+
+
+
+int IcqGetXStatusEx(WPARAM wParam, LPARAM lParam)
+{
+ ICQ_CUSTOM_STATUS *pData = (ICQ_CUSTOM_STATUS*)lParam;
+ HANDLE hContact = (HANDLE)wParam;
+
+ if (!gbXStatusEnabled) return 1;
+
+ if (pData->cbSize < sizeof(ICQ_CUSTOM_STATUS)) return 1; // Failure
+
+ if (pData->flags & CSSF_MASK_STATUS)
+ { // fill status member
+ *pData->status = ICQGetContactSettingByte(NULL, DBSETTING_XSTATUSID, 0);
+ }
+
+ if (pData->flags & CSSF_MASK_NAME)
+ { // fill status name member
+ if (pData->flags & CSSF_DEFAULT_NAME)
+ {
+ int status = *pData->wParam;
+
+ if (status < 1 || status > 32) return 1; // Failure
+
+ if (pData->flags & CSSF_UNICODE)
+ {
+ char *text = (char*)nameXStatus[status -1];
+
+ MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, text, strlennull(text), pData->pwszName, MAX_PATH);
+ }
+ else
+ strcpy(pData->pszName, nameXStatus[status - 1]);
+ }
+ else
+ {
+ if (pData->flags & CSSF_UNICODE)
+ {
+ char* str = ICQGetContactSettingUtf(hContact, DBSETTING_XSTATUSNAME, "");
+ wchar_t* wstr = make_unicode_string(str);
+
+ wcscpy(pData->pwszName, wstr);
+ SAFE_FREE(&str);
+ SAFE_FREE(&wstr);
+ }
+ else
+ {
+ DBVARIANT dbv = {0};
+
+ ICQGetContactSetting(hContact, DBSETTING_XSTATUSNAME, &dbv);
+ strcpy(pData->pszName, dbv.pszVal);
+
+ ICQFreeVariant(&dbv);
+ }
+ }
+ }
+
+ if (pData->flags & CSSF_MASK_MESSAGE)
+ { // fill status message member
+ if (pData->flags & CSSF_UNICODE)
+ {
+ char* str = ICQGetContactSettingUtf(hContact, DBSETTING_XSTATUSMSG, "");
+ wchar_t* wstr = make_unicode_string(str);
+
+ wcscpy(pData->pwszMessage, wstr);
+ SAFE_FREE(&str);
+ SAFE_FREE(&wstr);
+ }
+ else
+ {
+ DBVARIANT dbv = {0};
+
+ ICQGetContactSetting(hContact, DBSETTING_XSTATUSMSG, &dbv);
+ strcpy(pData->pszMessage, dbv.pszVal);
+
+ ICQFreeVariant(&dbv);
+ }
+ }
+
+ if (pData->flags & CSSF_DISABLE_UI)
+ {
+ if (pData->wParam) *pData->wParam = !bHideXStatusUI;
+ }
+
+ if (pData->flags & CSSF_STATUSES_COUNT)
+ {
+ if (pData->wParam) *pData->wParam = 32;
+ }
+
+ if (pData->flags & CSSF_STR_SIZES)
+ {
+ DBVARIANT dbv = {0};
+
+ if (pData->wParam)
+ {
+ if (!ICQGetContactSetting(hContact, DBSETTING_XSTATUSNAME, &dbv))
+ {
+ *pData->wParam = strlennull(dbv.pszVal);
+ ICQFreeVariant(&dbv);
+ }
+ else
+ *pData->wParam = 0;
+ }
+ if (pData->lParam)
+ {
+ if (!ICQGetContactSetting(hContact, DBSETTING_XSTATUSMSG, &dbv))
+ {
+ *pData->lParam = strlennull(dbv.pszVal);
+ ICQFreeVariant(&dbv);
+ }
+ else
+ *pData->lParam = 0;
+ }
+ }
+
+ return 0; // Success
+}
+
+
+
+int IcqGetXStatusIcon(WPARAM wParam, LPARAM lParam)
+{
+ if (!gbXStatusEnabled) return 0;
+
+ if (!wParam)
+ wParam = ICQGetContactSettingByte(NULL, DBSETTING_XSTATUSID, 0);
+
+ if (wParam >= 1 && wParam <= 32)
+ {
+ HICON icon = GetXStatusIcon((BYTE)wParam);
+
+ if (IconLibInstalled())
+ icon = CopyIcon(icon);
+
+ return (int)icon;
+ }
+ return 0;
+}
+
+
+
+int IcqRequestXStatusDetails(WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hContact = (HANDLE)wParam;
+
+ if (!gbXStatusEnabled) return 0;
+
+ if (hContact && !ICQGetContactSettingByte(NULL, "XStatusAuto", DEFAULT_XSTATUS_AUTO) &&
+ ICQGetContactSettingByte(hContact, DBSETTING_XSTATUSID, 0))
+ { // user has xstatus, no auto-retrieve details, valid contact, request details
+ return requestXStatusDetails(hContact, TRUE);
+ }
+ return 0;
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_xtraz.c b/miranda-wine/protocols/IcqOscarJ/icq_xtraz.c
new file mode 100644
index 0000000..08a9b93
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_xtraz.c
@@ -0,0 +1,454 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_xtraz.c,v $
+// Revision : $Revision: 3343 $
+// Last change on : $Date: 2006-07-19 03:36:21 +0400 (Срд, 19 Июл 2006) $
+// Last change by : $Author: rainwater $
+//
+// DESCRIPTION:
+//
+// Internal Xtraz API
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+extern HANDLE hsmsgrequest;
+
+
+void handleXtrazNotify(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szMsg, int nMsgLen, BOOL bThruDC)
+{
+ char *szWork, *szEnd, *szNotify, *szQuery;
+ int nNotifyLen, nQueryLen;
+ HANDLE hContact;
+
+ szNotify = strstr(szMsg, "<NOTIFY>");
+ szQuery = strstr(szMsg, "<QUERY>");
+
+ hContact = HContactFromUIN(dwUin, NULL);
+ if (hContact) // user sent us xtraz, he supports it
+ SetContactCapabilities(hContact, CAPF_XTRAZ);
+
+ if (szNotify && szQuery)
+ { // valid request
+ szNotify += 8;
+ szQuery += 7;
+ szEnd = strstr(szMsg, "</NOTIFY>");
+ if (!szEnd) szEnd = szMsg + nMsgLen;
+ nNotifyLen = (szEnd - szNotify);
+ szEnd = strstr(szMsg, "</QUERY>");
+ if (!szEnd) szEnd = szNotify;
+ szNotify = DemangleXml(szNotify, nNotifyLen);
+ nQueryLen = (szEnd - szQuery);
+ szQuery = DemangleXml(szQuery, nQueryLen);
+ szWork = strstr(szQuery, "<PluginID>");
+ szEnd = strstr(szQuery, "</PluginID>");
+#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 (!stricmp(szWork, "srvMng") && strstr(szNotify, "AwayStat"))
+ {
+ char* szSender = strstr(szNotify, "<senderId>");
+ char* szEndSend = strstr(szNotify, "</senderId>");
+
+ if (szSender && szEndSend)
+ {
+ szSender += 10;
+ *szEndSend = '\0';
+
+ if ((DWORD)atoi(szSender) == dwUin)
+ {
+ char *szResponse;
+ int nResponseLen;
+ char *szXName, *szXMsg;
+ BYTE dwXId = ICQGetContactSettingByte(NULL, DBSETTING_XSTATUSID, 0);
+
+ if (dwXId && validateStatusMessageRequest(hContact, MTYPE_SCRIPT_NOTIFY))
+ { // apply privacy rules
+ NotifyEventHooks(hsmsgrequest, (WPARAM)MTYPE_SCRIPT_NOTIFY, (LPARAM)dwUin);
+
+ szXName = ICQGetContactSettingUtf(NULL, DBSETTING_XSTATUSNAME, "");
+ szXMsg = ICQGetContactSettingUtf(NULL, DBSETTING_XSTATUSMSG, "");
+
+ nResponseLen = 212 + strlennull(szXName) + strlennull(szXMsg) + UINMAXLEN + 2;
+ szResponse = (char*)_alloca(nResponseLen + 1);
+ // send response
+ nResponseLen = null_snprintf(szResponse, nResponseLen,
+ "<ret event='OnRemoteNotification'>"
+ "<srv><id>cAwaySrv</id>"
+ "<val srv_id='cAwaySrv'><Root>"
+ "<CASXtraSetAwayMessage></CASXtraSetAwayMessage>"
+ "<uin>%d</uin>"
+ "<index>%d</index>"
+ "<title>%s</title>"
+ "<desc>%s</desc></Root></val></srv></ret>",
+ dwLocalUIN, dwXId, szXName, szXMsg);
+
+ SAFE_FREE(&szXName);
+ SAFE_FREE(&szXMsg);
+
+ if (gbXStatusEnabled)
+ {
+ rate_record rr = {0};
+
+ rr.bType = RIT_XSTATUS_RESPONSE;
+ rr.dwUin = dwUin;
+ rr.dwMid1 = dwMID;
+ rr.dwMid2 = dwMID2;
+ rr.wCookie = wCookie;
+ rr.szData = szResponse;
+ rr.bThruDC = bThruDC;
+ rr.rate_group = 0x102;
+ if (bThruDC || !handleRateItem(&rr, TRUE))
+ SendXtrazNotifyResponse(dwUin, dwMID, dwMID2, wCookie, szResponse, nResponseLen, bThruDC);
+ }
+ else
+ NetLog_Server("Error: XStatus Disabled");
+ }
+ 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 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 = strstr(szMsg, "<RES>");
+ szEnd = strstr(szMsg, "</RES>");
+
+ 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
+
+ ICQBroadcastAck(hContact, ICQACKTYPE_XTRAZNOTIFY_RESPONSE, ACKRESULT_SUCCESS, (HANDLE)wCookie, (LPARAM)szRes);
+
+NextVal:
+ szNode = strstr(szRes, "<val srv_id='");
+ if (szNode) szEnd = strstr(szNode, ">"); else szEnd = NULL;
+
+ if (szNode && szEnd)
+ {
+ *(szEnd-1) = '\0';
+ szNode += 13;
+ szWork = szEnd + 1;
+
+ if (!stricmp(szNode, "cAwaySrv"))
+ {
+ szNode = strstr(szWork, "<uin>");
+ szEnd = strstr(szWork, "</uin>");
+
+ if (szNode && szEnd)
+ {
+ szNode += 5;
+ *szEnd = '\0';
+
+ if ((DWORD)atoi(szNode) == dwUin)
+ {
+ *szEnd = ' ';
+ szNode = strstr(szWork, "<index>");
+ szEnd = strstr(szWork, "</index>");
+
+ if (szNode && szEnd)
+ {
+ szNode += 7;
+ *szEnd = '\0';
+ if (atoi(szNode) != ICQGetContactSettingByte(hContact, DBSETTING_XSTATUSID, 0))
+ { // this is strange - but go on
+ NetLog_Server("Warning: XStatusIds do not match!");
+ }
+ *szEnd = ' ';
+ }
+ szNode = strstr(szWork, "<title>");
+ szEnd = strstr(szWork, "</title>");
+
+ if (szNode && szEnd)
+ { // we got XStatus title, save it
+ szNode += 7;
+ *szEnd = '\0';
+ ICQWriteContactSettingUtf(hContact, DBSETTING_XSTATUSNAME, szNode);
+ *szEnd = ' ';
+ }
+ szNode = strstr(szWork, "<desc>");
+ szEnd = strstr(szWork, "</desc>");
+
+ if (szNode && szEnd)
+ { // we got XStatus mode msg, save it
+ szNode += 6;
+ *szEnd = '\0';
+ ICQWriteContactSettingUtf(hContact, DBSETTING_XSTATUSMSG, szNode);
+ }
+ ICQBroadcastAck(hContact, ICQACKTYPE_XSTATUS_RESPONSE, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0);
+ }
+ else
+ NetLog_Server("Error: Invalid sender information");
+ }
+ else
+ NetLog_Server("Error: Missing sender information");
+ }
+ else
+ {
+ char *szSrvEnd = strstr(szEnd, "</srv>");
+
+ if (szSrvEnd && strstr(szSrvEnd, "<val srv_id='"))
+ { // check all values !
+ szRes = szSrvEnd + 6; // after first value
+ goto NextVal;
+ }
+ // no next val, we were unable to handle packet, write error
+ NetLog_Server("Error: Unknown serverId \"%s\" in Xtraz response", szNode);
+ }
+ }
+ else
+ NetLog_Server("Error: Missing serverId in Xtraz response");
+
+ SAFE_FREE(&szMem);
+ }
+ else
+ NetLog_Server("Error: Invalid Xtraz Notify response");
+}
+
+
+
+static char* getXmlPidItem(const char* szData, int nLen)
+{
+ char *szPid, *szEnd;
+
+ szPid = strstr(szData, "<PID>");
+ szEnd = strstr(szData, "</PID>");
+
+ if (szPid && szEnd)
+ {
+ szPid += 5;
+
+ return DemangleXml(szPid, szEnd - szPid);
+ }
+ return NULL;
+}
+
+
+
+void 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 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 = strstr(szMsg, "<InD>");
+ szEnd = strstr(szMsg, "</InD>");
+ 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 = strstr(szUrl, ".html");
+ if (szWork)
+ {
+ strcpy(szWork, ".php");
+ strcat(szWork, szWork+5);
+ }
+ while (szWork = strstr(szUrl, "&amp;"))
+ { // unescape &amp; code
+ strcpy(szWork+1, szWork+5);
+ }
+ szWork = (char*)_alloca(nDataLen + MAX_PATH);
+ ICQTranslateUtfStatic("Greeting card:", szWork);
+ strcat(szWork, "\r\nhttp://www.icq.com/friendship/pages/view_page_");
+ strcat(szWork, szNum);
+
+ // Create message to notify user
+ {
+ CCSDATA ccs;
+ PROTORECVEVENT pre;
+ int bAdded;
+
+ ccs.szProtoService = PSR_MESSAGE;
+ ccs.hContact = HContactFromUIN(dwUin, &bAdded);
+ ccs.wParam = 0;
+ ccs.lParam = (LPARAM)&pre;
+ pre.flags = 0;
+ pre.timestamp = time(NULL);
+ pre.szMessage = szWork;
+ pre.lParam = 0;
+
+ CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs);
+ }
+ }
+ 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 SendXtrazNotifyRequest(HANDLE hContact, char* szQuery, char* szNotify, int bForced)
+{
+ char *szQueryBody;
+ char *szNotifyBody;
+ DWORD dwUin;
+ int nBodyLen;
+ char *szBody;
+ DWORD dwCookie;
+ message_cookie_data* pCookieData;
+
+ if (ICQGetContactSettingUID(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, "<N><QUERY>%s</QUERY><NOTIFY>%s</NOTIFY></N>", szQueryBody, szNotifyBody);
+ SAFE_FREE(&szQueryBody);
+ SAFE_FREE(&szNotifyBody);
+
+ // Set up the ack type
+ pCookieData = CreateMessageCookie(MTYPE_SCRIPT_NOTIFY, ACKTYPE_CLIENT);
+ dwCookie = AllocateCookie(CKT_MESSAGE, 0, dwUin, (void*)pCookieData);
+
+ // have we a open DC, send through that
+ if (gbDCMsgEnabled && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD))
+ icq_sendXtrazRequestDirect(dwUin, hContact, dwCookie, szBody, nBodyLen, MTYPE_SCRIPT_NOTIFY);
+ else
+ icq_sendXtrazRequestServ(dwUin, dwCookie, szBody, nBodyLen, pCookieData);
+
+ return dwCookie;
+}
+
+
+
+void 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, "<NR><RES>%s</RES></NR>", szResBody);
+ SAFE_FREE(&szResBody);
+
+ // Was request received thru DC and have we a open DC, send through that
+ if (bThruDC && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD))
+ icq_sendXtrazResponseDirect(dwUin, hContact, wCookie, szBody, nBodyLen, MTYPE_SCRIPT_NOTIFY);
+ else
+ icq_sendXtrazResponseServ(dwUin, dwMID, dwMID2, wCookie, szBody, nBodyLen, MTYPE_SCRIPT_NOTIFY);
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/icq_xtraz.h b/miranda-wine/protocols/IcqOscarJ/icq_xtraz.h
new file mode 100644
index 0000000..129de5b
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icq_xtraz.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,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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icq_xtraz.h,v $
+// Revision : $Revision: 3343 $
+// Last change on : $Date: 2006-07-19 03:36:21 +0400 (Срд, 19 Июл 2006) $
+// Last change by : $Author: rainwater $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#ifndef __ICQ_XTRAZ_H
+#define __ICQ_XTRAZ_H
+
+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);
+
+// custom status support
+void InitXStatusItems(BOOL bAllowStatus);
+void InitXStatusEvents();
+void UninitXStatusEvents();
+
+void InitXStatusIcons();
+void ChangedIconsXStatus();
+HICON GetXStatusIcon(int bStatus);
+
+void handleXStatusCaps(HANDLE hContact, char* caps, int capsize);
+
+int IcqShowXStatusDetails(WPARAM wParam, LPARAM lParam);
+
+// custom status public services
+int IcqSetXStatus(WPARAM wParam, LPARAM lParam);
+int IcqGetXStatus(WPARAM wParam, LPARAM lParam);
+int IcqSetXStatusEx(WPARAM wParam, LPARAM lParam);
+int IcqGetXStatusEx(WPARAM wParam, LPARAM lParam);
+int IcqGetXStatusIcon(WPARAM wParam, LPARAM lParam);
+int IcqRequestXStatusDetails(WPARAM wParam, LPARAM lParam);
+
+#endif /* __ICQ_XTRAZ_H */
diff --git a/miranda-wine/protocols/IcqOscarJ/icqosc_svcs.c b/miranda-wine/protocols/IcqOscarJ/icqosc_svcs.c
new file mode 100644
index 0000000..470045c
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icqosc_svcs.c
@@ -0,0 +1,2316 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icqosc_svcs.c,v $
+// Revision : $Revision: 3663 $
+// Last change on : $Date: 2006-08-31 00:18:59 +0400 (Чтв, 31 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// High-level code for exported API services
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+
+int gbIdleAllow;
+int icqGoingOnlineStatus;
+
+extern WORD wListenPort;
+
+extern char* calcMD5Hash(char* szFile);
+extern filetransfer *CreateFileTransfer(HANDLE hContact, DWORD dwUin, int nVersion);
+
+
+int IcqGetCaps(WPARAM wParam, LPARAM lParam)
+{
+ int nReturn = 0;
+
+
+ switch (wParam)
+ {
+
+ 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 (!gbAimEnabled)
+ nReturn |= PF1_NUMERICUSERID;
+ if (gbSsiEnabled && ICQGetContactSettingByte(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;
+ break;
+
+ case PFLAGNUM_3:
+ nReturn = PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | PF2_HEAVYDND |
+ PF2_FREECHAT;
+ break;
+
+ case PFLAGNUM_4:
+ nReturn = PF4_SUPPORTIDLE;
+ if (gbAvatarsEnabled)
+ nReturn |= PF4_AVATARS;
+#ifdef DBG_CAPMTN
+ nReturn |= PF4_SUPPORTTYPING;
+#endif
+ break;
+
+ case PFLAG_UNIQUEIDTEXT:
+ nReturn = (int)ICQTranslate("User ID");
+ break;
+
+ case PFLAG_UNIQUEIDSETTING:
+ nReturn = (int)UNIQUEIDSETTING;
+ break;
+
+ case PFLAG_MAXCONTACTSPERPACKET:
+ nReturn = MAX_CONTACTSSEND;
+ break;
+
+ case PFLAG_MAXLENOFMESSAGE:
+ nReturn = MAX_MESSAGESNACSIZE-102;
+ }
+
+ return nReturn;
+}
+
+
+
+int IcqGetName(WPARAM wParam, LPARAM lParam)
+{
+ if (lParam)
+ {
+ strncpy((char *)lParam, ICQTranslate(gpszICQProtoName), wParam);
+
+ return 0; // Success
+ }
+
+ return 1; // Failure
+}
+
+
+
+int IcqLoadIcon(WPARAM wParam, LPARAM lParam)
+{
+ UINT id;
+
+
+ switch (wParam & 0xFFFF)
+ {
+ case PLI_PROTOCOL:
+ id = IDI_ICQ;
+ break;
+
+ default:
+ return 0; // Failure
+ }
+
+ return (int)LoadImage(hInst, MAKEINTRESOURCE(id), IMAGE_ICON, GetSystemMetrics(wParam&PLIF_SMALL?SM_CXSMICON:SM_CXICON), GetSystemMetrics(wParam&PLIF_SMALL?SM_CYSMICON:SM_CYICON), 0);
+}
+
+
+
+int IcqSetPassword(WPARAM wParam, LPARAM lParam)
+{
+ char *pwd = (char*)lParam;
+ int len = strlennull(pwd);
+
+ if (len && len <= 8)
+ {
+ strcpy(gpszPassword, pwd);
+ gbRememberPwd = 1;
+ }
+ return 0;
+}
+
+
+
+int IcqIdleChanged(WPARAM wParam, LPARAM lParam)
+{
+ int bIdle = (lParam&IDF_ISIDLE);
+ int bPrivacy = (lParam&IDF_PRIVACY);
+
+ if (bPrivacy) return 0;
+
+ ICQWriteContactSettingDword(NULL, "IdleTS", bIdle ? time(0) : 0);
+
+ if (gbTempVisListEnabled) // remove temporary visible users
+ clearTemporaryVisibleList();
+
+ icq_setidle(bIdle ? 1 : 0);
+
+ return 0;
+}
+
+
+
+int IcqGetAvatarInfo(WPARAM wParam, LPARAM lParam)
+{
+ PROTO_AVATAR_INFORMATION* pai = (PROTO_AVATAR_INFORMATION*)lParam;
+ DWORD dwUIN;
+ uid_str szUID;
+ DBVARIANT dbv;
+ int dwPaFormat;
+
+ if (!gbAvatarsEnabled) return GAIR_NOAVATAR;
+
+ if (ICQGetContactSetting(pai->hContact, "AvatarHash", &dbv) || dbv.cpbVal != 0x14)
+ return GAIR_NOAVATAR; // we did not found avatar hash or hash invalid - no avatar available
+
+ if (ICQGetContactSettingUID(pai->hContact, &dwUIN, &szUID))
+ {
+ ICQFreeVariant(&dbv);
+
+ return GAIR_NOAVATAR; // we do not support avatars for invalid contacts
+ }
+
+ dwPaFormat = ICQGetContactSettingByte(pai->hContact, "AvatarType", PA_FORMAT_UNKNOWN);
+ if (dwPaFormat != PA_FORMAT_UNKNOWN)
+ { // we know the format, test file
+ GetFullAvatarFileName(dwUIN, szUID, dwPaFormat, pai->filename, MAX_PATH);
+
+ pai->format = dwPaFormat;
+
+ if (!IsAvatarSaved(pai->hContact, dbv.pbVal))
+ { // hashes are the same
+ if (access(pai->filename, 0) == 0)
+ {
+ ICQFreeVariant(&dbv);
+
+ return GAIR_SUCCESS; // we have found the avatar file, whoala
+ }
+ }
+ }
+
+ if (IsAvatarSaved(pai->hContact, dbv.pbVal))
+ { // 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
+ GetAvatarFileName(dwUIN, szUID, pai->filename, MAX_PATH);
+ GetAvatarData(pai->hContact, dwUIN, szUID, dbv.pbVal, dbv.cpbVal, pai->filename);
+ ICQFreeVariant(&dbv);
+
+ return GAIR_WAITFOR;
+ }
+ }
+ ICQFreeVariant(&dbv);
+
+ return GAIR_NOAVATAR;
+}
+
+
+
+int IcqGetMaxAvatarSize(WPARAM wParam, LPARAM lParam)
+{
+ if (wParam) *((int*)wParam) = 64;
+ if (lParam) *((int*)lParam) = 64;
+
+ return 0;
+}
+
+
+
+int IcqAvatarFormatSupported(WPARAM wParam, LPARAM lParam)
+{
+ if (lParam == PA_FORMAT_JPEG || lParam == PA_FORMAT_GIF)
+ return -2;
+ else
+ return 0;
+}
+
+
+
+int IcqGetMyAvatar(WPARAM wParam, LPARAM lParam)
+{
+ char* file;
+
+ if (!gbAvatarsEnabled) return -2;
+
+ if (!wParam) return -3;
+
+ file = loadMyAvatarFileName();
+ if (file) strncpy((char*)wParam, file, (int)lParam);
+ SAFE_FREE(&file);
+ if (!access((char*)wParam, 0)) return 0;
+ return -1;
+}
+
+
+
+int IcqSetMyAvatar(WPARAM wParam, LPARAM lParam)
+{
+ char* szFile = (char*)lParam;
+ int iRet = -1;
+
+ if (!gbAvatarsEnabled || !gbSsiEnabled) return -2;
+
+ if (szFile)
+ { // set file for avatar
+ char szMyFile[MAX_PATH+1];
+ int dwPaFormat = DetectAvatarFormat(szFile);
+ char* hash;
+ HBITMAP avt;
+
+ if (dwPaFormat != PA_FORMAT_XML)
+ { // if it should be image, check if it is valid
+ avt = (HBITMAP)CallService(MS_UTILS_LOADBITMAP, 0, (WPARAM)szFile);
+ if (!avt) return iRet;
+ DeleteObject(avt);
+ }
+ GetFullAvatarFileName(0, NULL, dwPaFormat, szMyFile, MAX_PATH);
+ if (!CopyFile(szFile, szMyFile, FALSE))
+ {
+ NetLog_Server("Failed to copy our avatar to local storage.");
+ return iRet;
+ }
+
+ hash = calcMD5Hash(szMyFile);
+ if (hash)
+ {
+ char* ihash = (char*)_alloca(0x14);
+ // upload hash to server
+ ihash[0] = 0; //unknown
+ ihash[1] = dwPaFormat == PA_FORMAT_XML ? 8 : 1; //hash type
+ ihash[2] = 1; //hash status
+ ihash[3] = 0x10; //hash len
+ memcpy(ihash+4, hash, 0x10);
+ updateServAvatarHash(ihash, 0x14);
+
+ if (ICQWriteContactSettingBlob(NULL, "AvatarHash", ihash, 0x14))
+ {
+ NetLog_Server("Failed to save avatar hash.");
+ }
+
+ storeMyAvatarFileName(szMyFile);
+ iRet = 0;
+
+ SAFE_FREE(&hash);
+ }
+ }
+ else
+ { // delete user avatar
+ BYTE bEmptyAvatar[9] = {0x00, 0x01, 0x00,0x05,0x02,0x01,0xD2,0x04,0x72};
+
+ ICQDeleteContactSetting(NULL, "AvatarFile");
+ ICQDeleteContactSetting(NULL, "AvatarHash");
+ updateServAvatarHash(bEmptyAvatar, 9); // clear hash on server
+ iRet = 0;
+ }
+
+ return iRet;
+}
+
+
+
+void updateAimAwayMsg()
+{
+ char** szMsg = MirandaStatusToAwayMsg(gnCurrentStatus);
+
+ EnterCriticalSection(&modeMsgsMutex);
+ if (szMsg)
+ icq_sendSetAimAwayMsgServ(*szMsg);
+ LeaveCriticalSection(&modeMsgsMutex);
+}
+
+
+
+int IcqSetStatus(WPARAM wParam, LPARAM lParam)
+{
+ int nNewStatus = MirandaStatusToSupported(wParam);
+
+ // check if netlib handles are ready
+ if (!ghServerNetlibUser)
+ return 0;
+
+ if (gbTempVisListEnabled) // remove temporary visible users
+ clearTemporaryVisibleList();
+
+ if (nNewStatus != gnCurrentStatus)
+ {
+ if (ICQGetContactSettingByte(NULL, "XStatusReset", DEFAULT_XSTATUS_RESET))
+ { // clear custom status on status change
+ IcqSetXStatus(0, 0);
+ }
+
+ // New status is OFFLINE
+ if (nNewStatus == ID_STATUS_OFFLINE)
+ {
+ // for quick logoff
+ icqGoingOnlineStatus = nNewStatus;
+
+ // Send disconnect packet
+ icq_sendCloseConnection();
+
+ icq_serverDisconnect(FALSE);
+
+ SetCurrentStatus(ID_STATUS_OFFLINE);
+
+ NetLog_Server("Logged off.");
+ }
+ else
+ {
+ switch (gnCurrentStatus)
+ {
+
+ // We are offline and need to connect
+ case ID_STATUS_OFFLINE:
+ {
+ char *pszPwd;
+
+ // Update user connection settings
+ UpdateGlobalSettings();
+
+ // Read UIN from database
+ dwLocalUIN = ICQGetContactSettingUIN(NULL);
+ if (dwLocalUIN == 0)
+ {
+ SetCurrentStatus(ID_STATUS_OFFLINE);
+
+ icq_LogMessage(LOG_FATAL, "You have not entered a ICQ number.\nConfigure this in Options->Network->ICQ and try again.");
+ return 0;
+ }
+
+ // Set status to 'Connecting'
+ icqGoingOnlineStatus = nNewStatus;
+ SetCurrentStatus(ID_STATUS_CONNECTING);
+
+ // Read password from database
+ 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:
+ {
+ icqGoingOnlineStatus = nNewStatus;
+ break;
+ }
+
+ // We are already connected so we should just change status
+ default:
+ {
+ SetCurrentStatus(nNewStatus);
+
+ if (gnCurrentStatus == ID_STATUS_INVISIBLE)
+ {
+ if (gbSsiEnabled)
+ updateServVisibilityCode(3);
+ icq_setstatus(MirandaStatusToIcq(gnCurrentStatus));
+ // Tell whos on our visible list
+ icq_sendEntireVisInvisList(0);
+ if (gbAimEnabled)
+ updateAimAwayMsg();
+ }
+ else
+ {
+ icq_setstatus(MirandaStatusToIcq(gnCurrentStatus));
+ if (gbSsiEnabled)
+ updateServVisibilityCode(4);
+ // Tell whos on our invisible list
+ icq_sendEntireVisInvisList(1);
+ if (gbAimEnabled)
+ updateAimAwayMsg();
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+
+int IcqGetStatus(WPARAM wParam, LPARAM lParam)
+{
+ return gnCurrentStatus;
+}
+
+
+
+int IcqSetAwayMsg(WPARAM wParam, LPARAM lParam)
+{
+ char** ppszMsg = NULL;
+ char* szNewUtf = NULL;
+
+
+ EnterCriticalSection(&modeMsgsMutex);
+
+ ppszMsg = MirandaStatusToAwayMsg(wParam);
+ if (!ppszMsg)
+ {
+ LeaveCriticalSection(&modeMsgsMutex);
+ return 1; // Failure
+ }
+
+ // Prepare UTF-8 status message
+ szNewUtf = ansi_to_utf8((char*)lParam);
+
+ if (strcmpnull(szNewUtf, *ppszMsg))
+ {
+ // Free old message
+ SAFE_FREE(ppszMsg);
+
+ // Set new message
+ *ppszMsg = szNewUtf;
+ szNewUtf = NULL;
+
+ if (gbAimEnabled && (gnCurrentStatus == (int)wParam))
+ icq_sendSetAimAwayMsgServ(*ppszMsg);
+ }
+ SAFE_FREE(&szNewUtf);
+
+ LeaveCriticalSection(&modeMsgsMutex);
+
+ return 0; // Success
+}
+
+
+
+static HANDLE HContactFromAuthEvent(WPARAM hEvent)
+{
+ DBEVENTINFO dbei;
+ DWORD body[2];
+
+ ZeroMemory(&dbei, sizeof(dbei));
+ dbei.cbSize = sizeof(dbei);
+ dbei.cbBlob = sizeof(DWORD)*2;
+ dbei.pBlob = (PBYTE)&body;
+
+ if (CallService(MS_DB_EVENT_GET, hEvent, (LPARAM)&dbei))
+ return INVALID_HANDLE_VALUE;
+
+ if (dbei.eventType != EVENTTYPE_AUTHREQUEST)
+ return INVALID_HANDLE_VALUE;
+
+ if (strcmpnull(dbei.szModule, gpszICQProtoName))
+ return INVALID_HANDLE_VALUE;
+
+ return (HANDLE)body[1]; // this is bad - needs new auth system
+}
+
+
+
+int IcqAuthAllow(WPARAM wParam, LPARAM lParam)
+{
+ if (icqOnline && wParam)
+ {
+ DWORD uin;
+ uid_str uid;
+ HANDLE hContact;
+
+ hContact = HContactFromAuthEvent(wParam);
+ if (hContact == INVALID_HANDLE_VALUE)
+ return 1;
+
+ if (ICQGetContactSettingUID(hContact, &uin, &uid))
+ return 1;
+
+ icq_sendAuthResponseServ(uin, uid, 1, "");
+
+ return 0; // Success
+ }
+
+ return 1; // Failure
+}
+
+
+
+int IcqAuthDeny(WPARAM wParam, LPARAM lParam)
+{
+ if (icqOnline && wParam)
+ {
+ DWORD uin;
+ uid_str uid;
+ HANDLE hContact;
+
+
+ hContact = HContactFromAuthEvent(wParam);
+ if (hContact == INVALID_HANDLE_VALUE)
+ return 1;
+
+ if (ICQGetContactSettingUID(hContact, &uin, &uid))
+ return 1;
+
+ icq_sendAuthResponseServ(uin, uid, 0, (char *)lParam);
+
+ return 0; // Success
+ }
+
+ return 1; // Failure
+}
+
+
+
+static int cheekySearchId = -1;
+static DWORD cheekySearchUin;
+static char* cheekySearchUid;
+static VOID CALLBACK CheekySearchTimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
+{
+ ICQSEARCHRESULT isr = {0};
+
+ KillTimer(hwnd, idEvent);
+
+ isr.hdr.cbSize = sizeof(isr);
+ if (cheekySearchUin)
+ {
+ isr.hdr.nick = "";
+ isr.uid = NULL;
+ }
+ else
+ {
+ isr.hdr.nick = cheekySearchUid;
+ isr.uid = cheekySearchUid;
+ }
+ isr.hdr.firstName = "";
+ isr.hdr.lastName = "";
+ isr.hdr.email = "";
+ isr.uin = cheekySearchUin;
+
+ ICQBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)cheekySearchId, (LPARAM)&isr);
+ ICQBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)cheekySearchId, 0);
+
+ cheekySearchId = -1;
+}
+
+
+int IcqBasicSearch(WPARAM wParam, LPARAM lParam)
+{
+ if (lParam)
+ {
+ char* pszSearch = (char*)lParam;
+ DWORD dwUin;
+
+ if (strlennull(pszSearch))
+ {
+ char pszUIN[255];
+ int nHandle = 0;
+ unsigned int i, j;
+
+ if (!gbAimEnabled)
+ {
+ for (i=j=0; (i<strlennull(pszSearch)) && (j<255); i++)
+ { // we take only numbers
+ if ((pszSearch[i]>=0x30) && (pszSearch[i]<=0x39))
+ {
+ pszUIN[j] = pszSearch[i];
+ j++;
+ }
+ }
+ }
+ else
+ {
+ for (i=j=0; (i<strlennull(pszSearch)) && (j<255); i++)
+ { // we remove spaces and slashes
+ if ((pszSearch[i]!=0x20) && (pszSearch[i]!='-'))
+ {
+ pszUIN[j] = pszSearch[i];
+ j++;
+ }
+ }
+ }
+ pszUIN[j] = 0;
+
+ if (strlennull(pszUIN))
+ {
+ 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);
+ SetTimer(NULL, 0, 10, CheekySearchTimerProc); // The caller needs to get this return value before the results
+ nHandle = cheekySearchId;
+ }
+ else if (icqOnline)
+ {
+ nHandle = SearchByUin(dwUin);
+ }
+
+ // Success
+ return nHandle;
+ }
+ }
+ }
+
+ // Failure
+ return 0;
+}
+
+
+int IcqSearchByEmail(WPARAM wParam, LPARAM lParam)
+{
+ if (lParam && icqOnline && (strlennull((char*)lParam) > 0))
+ {
+ DWORD dwSearchId, dwSecId;
+
+ // Success
+ dwSearchId = SearchByEmail((char *)lParam);
+ if (gbAimEnabled)
+ dwSecId = icq_searchAimByEmail((char *)lParam, dwSearchId);
+ else
+ dwSecId = 0;
+ if (dwSearchId)
+ return dwSearchId;
+ else
+ return dwSecId;
+ }
+
+ return 0; // Failure
+}
+
+
+int IcqSearchByDetails(WPARAM wParam, LPARAM lParam)
+{
+ if (lParam && icqOnline)
+ {
+ PROTOSEARCHBYNAME *psbn=(PROTOSEARCHBYNAME*)lParam;
+
+
+ if (psbn->pszNick || psbn->pszFirstName || psbn->pszLastName)
+ {
+ // Success
+ return SearchByNames(psbn->pszNick, psbn->pszFirstName, psbn->pszLastName);
+ }
+ }
+
+ return 0; // Failure
+}
+
+
+int IcqCreateAdvSearchUI(WPARAM wParam, LPARAM lParam)
+{
+ if (lParam && hInst)
+ {
+ // Success
+ return (int)CreateDialogUtf(hInst, MAKEINTRESOURCE(IDD_ICQADVANCEDSEARCH), (HWND)lParam, AdvancedSearchDlgProc);
+ }
+
+ return 0; // Failure
+}
+
+
+int IcqSearchByAdvanced(WPARAM wParam, LPARAM lParam)
+{
+ if (icqOnline && IsWindow((HWND)lParam))
+ {
+ int nDataLen;
+ BYTE* bySearchData;
+
+ if (bySearchData = createAdvancedSearchStructure((HWND)lParam, &nDataLen))
+ {
+ int result;
+
+ result = icq_sendAdvancedSearchServ(bySearchData, nDataLen);
+ SAFE_FREE(&bySearchData);
+
+ return result; // Success
+ }
+ }
+
+ return 0; // Failure
+}
+
+
+
+// TODO: Adding needs some more work in general
+static HANDLE AddToListByUIN(DWORD dwUin, DWORD dwFlags)
+{
+ HANDLE hContact;
+ int bAdded;
+
+ hContact = HContactFromUIN(dwUin, &bAdded);
+
+ if (hContact)
+ {
+ if ((!dwFlags & PALF_TEMPORARY) && DBGetContactSettingByte(hContact, "CList", "NotOnList", 1))
+ {
+ DBDeleteContactSetting(hContact, "CList", "NotOnList");
+ SetContactHidden(hContact, 0);
+ }
+
+ return hContact; // Success
+ }
+
+ return NULL; // Failure
+}
+
+
+static HANDLE AddToListByUID(char *szUID, DWORD dwFlags)
+{
+ HANDLE hContact;
+ int bAdded;
+
+ hContact = HContactFromUID(0, szUID, &bAdded);
+
+ if (hContact)
+ {
+ if ((!dwFlags & PALF_TEMPORARY) && DBGetContactSettingByte(hContact, "CList", "NotOnList", 1))
+ {
+ DBDeleteContactSetting(hContact, "CList", "NotOnList");
+ SetContactHidden(hContact, 0);
+ }
+
+ return hContact; // Success
+ }
+
+ return NULL; // Failure
+}
+
+
+
+int IcqAddToList(WPARAM wParam, LPARAM lParam)
+{
+ if (lParam)
+ { // this should be only from search
+ ICQSEARCHRESULT *isr = (ICQSEARCHRESULT*)lParam;
+
+ if (isr->hdr.cbSize == sizeof(ICQSEARCHRESULT))
+ {
+ if (!isr->uin)
+ return (int)AddToListByUID(isr->hdr.nick, wParam);
+ else
+ return (int)AddToListByUIN(isr->uin, wParam);
+ }
+ }
+
+ return 0; // Failure
+}
+
+
+
+int IcqAddToListByEvent(WPARAM wParam, LPARAM lParam)
+{
+ DBEVENTINFO dbei = {0};
+ DWORD uin = 0;
+ uid_str uid = {0};
+
+
+ dbei.cbSize = sizeof(dbei);
+
+ if ((dbei.cbBlob = CallService(MS_DB_EVENT_GETBLOBSIZE, lParam, 0)) == -1)
+ return 0;
+
+ dbei.pBlob = (PBYTE)_alloca(dbei.cbBlob + 1);
+ dbei.pBlob[dbei.cbBlob] = '\0';
+
+ if (CallService(MS_DB_EVENT_GET, lParam, (LPARAM)&dbei))
+ return 0; // failed to get event
+
+ if (strcmpnull(dbei.szModule, gpszICQProtoName))
+ return 0; // this event is not ours
+
+ if (dbei.eventType == EVENTTYPE_CONTACTS)
+ {
+ int i, ci = HIWORD(wParam);
+ char* pbOffset, *pbEnd;
+
+ for (i = 0, pbOffset = (char*)dbei.pBlob, pbEnd = pbOffset + dbei.cbBlob; i <= ci; i++)
+ {
+ pbOffset += strlennull((char*)pbOffset) + 1; // Nick
+ if (pbOffset >= pbEnd) break;
+ if (i == ci)
+ { // we found the contact, get uid
+ if (IsStringUIN((char*)pbOffset))
+ uin = atoi((char*)pbOffset);
+ else
+ {
+ uin = 0;
+ strcpy(uid, (char*)pbOffset);
+ }
+ }
+ pbOffset += strlennull((char*)pbOffset) + 1; // Uin
+ if (pbOffset >= pbEnd) break;
+ }
+ }
+ else if (dbei.eventType != EVENTTYPE_AUTHREQUEST && dbei.eventType != EVENTTYPE_ADDED)
+ {
+ return 0;
+ }
+ else // auth req or added event
+ {
+ HANDLE hContact = ((HANDLE*)dbei.pBlob)[1]; // this sucks - awaiting new auth system
+
+ if (ICQGetContactSettingUID(hContact, &uin, &uid))
+ return 0;
+ }
+
+ if (uin != 0)
+ {
+ return (int)AddToListByUIN(uin, LOWORD(wParam)); // Success
+ }
+ else if (strlennull(uid))
+ { // add aim contact
+ return (int)AddToListByUID(uid, LOWORD(wParam)); // Success
+ }
+
+ return 0; // Failure
+}
+
+
+
+int IcqSetNickName(WPARAM wParam, LPARAM lParam)
+{
+ if (icqOnline)
+ {
+ ICQWriteContactSettingString(NULL, "Nick", (char*)lParam);
+
+ return IcqChangeInfoEx(CIXT_BASIC, 0);
+ }
+
+ return 0; // Failure
+}
+
+
+
+int IcqChangeInfoEx(WPARAM wParam, LPARAM lParam)
+{
+ if (icqOnline && wParam)
+ {
+ PBYTE buf = NULL;
+ int buflen = 0;
+ BYTE b;
+
+ // userinfo
+ ppackTLVWord(&buf, &buflen, (WORD)GetACP(), TLV_CODEPAGE, 0);
+
+ if (wParam & CIXT_CONTACT)
+ { // contact information
+ b = !ICQGetContactSettingByte(NULL, "PublishPrimaryEmail", 0);
+ ppackTLVLNTSBytefromDB(&buf, &buflen, "e-mail", b, TLV_EMAIL);
+ ppackTLVLNTSBytefromDB(&buf, &buflen, "e-mail0", 0, TLV_EMAIL);
+ ppackTLVLNTSBytefromDB(&buf, &buflen, "e-mail1", 0, TLV_EMAIL);
+
+ ppackTLVByte(&buf, &buflen, ICQGetContactSettingByte(NULL, "AllowSpam", 0), TLV_ALLOWSPAM, 1);
+
+ ppackTLVLNTSfromDB(&buf, &buflen, "Phone", TLV_PHONE);
+ ppackTLVLNTSfromDB(&buf, &buflen, "Fax", TLV_FAX);
+ ppackTLVLNTSfromDB(&buf, &buflen, "Cellular", TLV_MOBILE);
+ ppackTLVLNTSfromDB(&buf, &buflen, "CompanyPhone", TLV_WORKPHONE);
+ ppackTLVLNTSfromDB(&buf, &buflen, "CompanyFax", TLV_WORKFAX);
+ }
+
+ if (wParam & CIXT_BASIC)
+ { // upload basic user info
+ ppackTLVLNTSfromDB(&buf, &buflen, "Nick", TLV_NICKNAME);
+ ppackTLVLNTSfromDB(&buf, &buflen, "FirstName", TLV_FIRSTNAME);
+ ppackTLVLNTSfromDB(&buf, &buflen, "LastName", TLV_LASTNAME);
+ ppackTLVLNTSfromDB(&buf, &buflen, "About", TLV_ABOUT);
+ }
+
+ if (wParam & CIXT_MORE)
+ {
+ ppackTLVWord(&buf, &buflen, ICQGetContactSettingWord(NULL, "Age", 0), TLV_AGE, 1);
+ b = ICQGetContactSettingByte(NULL, "Gender", 0);
+ ppackTLVByte(&buf, &buflen, (BYTE)(b ? (b == 'M' ? 2 : 1) : 0), TLV_GENDER, 1);
+ ppackLEWord(&buf, &buflen, TLV_BIRTH);
+ ppackLEWord(&buf, &buflen, 0x06);
+ ppackLEWord(&buf, &buflen, ICQGetContactSettingWord(NULL, "BirthYear", 0));
+ ppackLEWord(&buf, &buflen, (WORD)ICQGetContactSettingByte(NULL, "BirthMonth", 0));
+ ppackLEWord(&buf, &buflen, (WORD)ICQGetContactSettingByte(NULL, "BirthDay", 0));
+
+ ppackTLVWord(&buf, &buflen, (WORD)StringToListItemId("Language1", 0), TLV_LANGUAGE, 1);
+ ppackTLVWord(&buf, &buflen, (WORD)StringToListItemId("Language2", 0), TLV_LANGUAGE, 1);
+ ppackTLVWord(&buf, &buflen, (WORD)StringToListItemId("Language3", 0), TLV_LANGUAGE, 1);
+
+ ppackTLVByte(&buf, &buflen, ICQGetContactSettingByte(NULL, "MaritalStatus", 0), TLV_MARITAL, 1);
+ }
+
+ if (wParam & CIXT_WORK)
+ {
+ ppackTLVLNTSfromDB(&buf, &buflen, "CompanyDepartment", TLV_DEPARTMENT);
+ ppackTLVLNTSfromDB(&buf, &buflen, "CompanyPosition", TLV_POSITION);
+ ppackTLVLNTSfromDB(&buf, &buflen, "Company", TLV_COMPANY);
+ ppackTLVLNTSfromDB(&buf, &buflen, "CompanyStreet", TLV_WORKSTREET);
+ ppackTLVLNTSfromDB(&buf, &buflen, "CompanyState", TLV_WORKSTATE);
+ ppackTLVLNTSfromDB(&buf, &buflen, "CompanyCity", TLV_WORKCITY);
+ ppackTLVLNTSfromDB(&buf, &buflen, "CompanyHomepage", TLV_WORKURL);
+ ppackTLVLNTSfromDB(&buf, &buflen, "CompanyZIP", TLV_WORKZIPCODE);
+ ppackTLVWord(&buf, &buflen, ICQGetContactSettingWord(NULL, "CompanyCountry", 0), TLV_WORKCOUNTRY, 1);
+ ppackTLVWord(&buf, &buflen, ICQGetContactSettingWord(NULL, "CompanyOccupation", 0), TLV_OCUPATION, 1);
+ }
+
+ if (wParam & CIXT_LOCATION)
+ {
+ ppackTLVLNTSfromDB(&buf, &buflen, "City", TLV_CITY);
+ ppackTLVLNTSfromDB(&buf, &buflen, "State", TLV_STATE);
+ ppackTLVWord(&buf, &buflen, ICQGetContactSettingWord(NULL, "Country", 0), TLV_COUNTRY, 1);
+ ppackTLVLNTSfromDB(&buf, &buflen, "OriginCity", TLV_ORGCITY);
+ ppackTLVLNTSfromDB(&buf, &buflen, "OriginState", TLV_ORGSTATE);
+ ppackTLVWord(&buf, &buflen, ICQGetContactSettingWord(NULL, "OriginCountry", 0), TLV_ORGCOUNTRY, 1);
+ ppackTLVLNTSfromDB(&buf, &buflen, "Street", TLV_STREET);
+ ppackTLVLNTSfromDB(&buf, &buflen, "ZIP", TLV_ZIPCODE);
+
+ ppackTLVLNTSfromDB(&buf, &buflen, "Homepage", TLV_URL);
+
+ ppackTLVByte(&buf, &buflen, ICQGetContactSettingByte(NULL, "Timezone", 0), TLV_TIMEZONE, 1);
+ }
+
+ if (wParam & CIXT_BACKGROUND)
+ {
+ WORD w;
+
+ w = StringToListItemId("Interest0Cat", 0);
+ ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Interest0Text", TLV_INTERESTS);
+ w = StringToListItemId("Interest1Cat", 0);
+ ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Interest1Text", TLV_INTERESTS);
+ w = StringToListItemId("Interest2Cat", 0);
+ ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Interest2Text", TLV_INTERESTS);
+ w = StringToListItemId("Interest3Cat", 0);
+ ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Interest3Text", TLV_INTERESTS);
+
+ 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);
+ }
+
+ return icq_changeUserDetailsServ(META_SET_FULLINFO_REQ, buf, (WORD)buflen);
+ }
+
+ return 0; // Failure
+}
+
+
+
+static int messageRate = 0;
+static DWORD lastMessageTick = 0;
+int IcqGetInfo(WPARAM wParam, LPARAM lParam)
+{
+ if (lParam && icqOnline)
+ { // TODO: add checking for SGIF_ONOPEN, otherwise max one per 10sec
+ CCSDATA* ccs = (CCSDATA*)lParam;
+ DWORD dwUin;
+ uid_str szUid;
+
+ if (ICQGetContactSettingUID(ccs->hContact, &dwUin, &szUid))
+ {
+ return 0; // Invalid contact
+ }
+
+ messageRate -= (GetTickCount() - lastMessageTick)/10;
+ if (messageRate<0) // TODO: this is bad, needs centralising
+ messageRate = 0;
+ lastMessageTick = GetTickCount();
+ messageRate += 67; // max 1.5 msgs/sec when rate is high
+
+ // server kicks if 100 msgs sent instantly, so send max 50 instantly
+ if (messageRate < 67*50)
+ {
+ if (dwUin)
+ icq_sendGetInfoServ(dwUin, (ccs->wParam & SGIF_MINIMAL) != 0);
+ else
+ icq_sendGetAimProfileServ(ccs->hContact, szUid);
+
+ return 0; // Success
+ }
+ }
+
+ return 1; // Failure
+}
+
+
+
+int IcqFileAllow(WPARAM wParam, LPARAM lParam)
+{
+ if (lParam)
+ {
+ CCSDATA* ccs = (CCSDATA*)lParam;
+ DWORD dwUin;
+ uid_str szUid;
+
+ if (ICQGetContactSettingUID(ccs->hContact, &dwUin, &szUid))
+ return 0; // Invalid contact
+
+ if (icqOnline && ccs->hContact && ccs->lParam && ccs->wParam)
+ { // approve old fashioned file transfer
+ basic_filetransfer* ft = ((basic_filetransfer *)ccs->wParam);
+
+ if (dwUin && ft->ft_magic == FT_MAGIC_ICQ)
+ {
+ filetransfer* ft = ((filetransfer *)ccs->wParam);
+
+ ft->szSavePath = null_strdup((char *)ccs->lParam);
+ AddExpectedFileRecv(ft);
+
+ // Was request received thru DC and have we a open DC, send through that
+ if (ft->bDC && IsDirectConnectionOpen(ccs->hContact, DIRECTCONN_STANDARD))
+ icq_sendFileAcceptDirect(ccs->hContact, ft);
+ else
+ icq_sendFileAcceptServ(dwUin, ft, 0);
+
+ return ccs->wParam; // Success
+ }
+ else if (ft->ft_magic == FT_MAGIC_OSCAR)
+ { // approve oscar file transfer
+ return oftFileAllow(ccs->hContact, ccs->wParam, ccs->lParam);
+ }
+ }
+ }
+
+ return 0; // Failure
+}
+
+
+
+int IcqFileDeny(WPARAM wParam, LPARAM lParam)
+{
+ int nReturnValue = 1;
+
+ if (lParam)
+ {
+ CCSDATA *ccs = (CCSDATA *)lParam;
+ DWORD dwUin;
+ uid_str szUid;
+
+ if (ICQGetContactSettingUID(ccs->hContact, &dwUin, &szUid))
+ return 1; // Invalid contact
+
+ if (icqOnline && ccs->wParam && ccs->hContact)
+ {
+ basic_filetransfer *ft = (basic_filetransfer*)ccs->wParam;
+
+ if (dwUin && ft->ft_magic == FT_MAGIC_ICQ)
+ { // deny old fashioned file transfer
+ filetransfer *ft = (filetransfer*)ccs->wParam;
+ // Was request received thru DC and have we a open DC, send through that
+ if (ft->bDC && IsDirectConnectionOpen(ccs->hContact, DIRECTCONN_STANDARD))
+ icq_sendFileDenyDirect(ccs->hContact, ft, (char*)ccs->lParam);
+ else
+ icq_sendFileDenyServ(dwUin, ft, (char*)ccs->lParam, 0);
+
+ nReturnValue = 0; // Success
+ }
+ else if (ft->ft_magic == FT_MAGIC_OSCAR)
+ { // deny oscar file transfer
+ return oftFileDeny(ccs->hContact, ccs->wParam, ccs->lParam);
+ }
+ }
+ /* FIXME: ft leaks (but can get double freed?) */
+ }
+
+ return nReturnValue;
+}
+
+
+
+int IcqFileCancel(WPARAM wParam, LPARAM lParam)
+{
+ if (lParam /*&& icqOnline*/)
+ {
+ CCSDATA* ccs = (CCSDATA*)lParam;
+ DWORD dwUin;
+ uid_str szUid;
+
+ if (ICQGetContactSettingUID(ccs->hContact, &dwUin, &szUid))
+ return 1; // Invalid contact
+
+ if (ccs->hContact && ccs->wParam)
+ {
+ basic_filetransfer *ft = (basic_filetransfer *)ccs->wParam;
+
+ if (dwUin && ft->ft_magic == FT_MAGIC_ICQ)
+ { // cancel old fashioned file transfer
+ filetransfer * ft = (filetransfer * ) ccs->wParam;
+
+ icq_CancelFileTransfer(ccs->hContact, ft);
+
+ return 0; // Success
+ }
+ else if (ft->ft_magic = FT_MAGIC_OSCAR)
+ { // cancel oscar file transfer
+ return oftFileCancel(ccs->hContact, ccs->wParam, ccs->lParam);
+ }
+ }
+ }
+
+ return 1; // Failure
+}
+
+
+
+int IcqFileResume(WPARAM wParam, LPARAM lParam)
+{
+ if (icqOnline && wParam)
+ {
+ PROTOFILERESUME *pfr = (PROTOFILERESUME*)lParam;
+ basic_filetransfer *ft = (basic_filetransfer *)wParam;
+
+ if (ft->ft_magic == FT_MAGIC_ICQ)
+ {
+ icq_sendFileResume((filetransfer *)wParam, pfr->action, pfr->szFilename);
+ }
+ else if (ft->ft_magic == FT_MAGIC_OSCAR)
+ {
+ oftFileResume((oscar_filetransfer *)wParam, pfr->action, pfr->szFilename);
+ }
+ else
+ return 1; // Failure
+
+ return 0; // Success
+ }
+
+ return 1; // Failure
+}
+
+
+
+int IcqSendSms(WPARAM wParam, LPARAM lParam)
+{
+ if (icqOnline && wParam && lParam)
+ return icq_sendSMSServ((const char *)wParam, (const char *)lParam);
+
+ return 0; // Failure
+}
+
+
+
+// Maybe we should be saving these up for batch changing, but I can't be bothered yet
+int IcqSetApparentMode(WPARAM wParam, LPARAM lParam)
+{
+ if (lParam)
+ {
+ CCSDATA* ccs = (CCSDATA*)lParam;
+ DWORD uin;
+ uid_str uid;
+
+ if (ICQGetContactSettingUID(ccs->hContact, &uin, &uid))
+ return 1; // Invalid contact
+
+ if (ccs->hContact)
+ {
+ // Only 3 modes are supported
+ if (ccs->wParam == 0 || ccs->wParam == ID_STATUS_ONLINE || ccs->wParam == ID_STATUS_OFFLINE)
+ {
+ int oldMode = ICQGetContactSettingWord(ccs->hContact, "ApparentMode", 0);
+
+ // Don't send redundant updates
+ if ((int)ccs->wParam != oldMode)
+ {
+ ICQWriteContactSettingWord(ccs->hContact, "ApparentMode", (WORD)ccs->wParam);
+
+ // 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
+ icq_sendChangeVisInvis(ccs->hContact, uin, uid, oldMode==ID_STATUS_OFFLINE, 0);
+ if (ccs->wParam != 0) // Add to new list
+ icq_sendChangeVisInvis(ccs->hContact, uin, uid, ccs->wParam==ID_STATUS_OFFLINE, 1);
+ }
+
+ return 0; // Success
+ }
+ }
+ }
+ }
+
+ return 1; // Failure
+}
+
+
+
+int IcqGetAwayMsg(WPARAM wParam,LPARAM lParam)
+{
+ if (lParam && icqOnline)
+ {
+ CCSDATA* ccs = (CCSDATA*)lParam;
+ DWORD dwUin;
+ uid_str szUID;
+ WORD wStatus;
+
+ if (ICQGetContactSettingUID(ccs->hContact, &dwUin, &szUID))
+ return 0; // Invalid contact
+
+ wStatus = ICQGetContactStatus(ccs->hContact);
+
+ if (dwUin)
+ {
+ int wMessageType = 0;
+
+ switch(wStatus)
+ {
+
+ 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 (gbDCMsgEnabled && IsDirectConnectionOpen(ccs->hContact, DIRECTCONN_STANDARD))
+ {
+ int iRes = icq_sendGetAwayMsgDirect(ccs->hContact, wMessageType);
+ if (iRes) return iRes; // we succeded, return
+ }
+ return icq_sendGetAwayMsgServ(dwUin, wMessageType,
+ (WORD)(ICQGetContactSettingWord(ccs->hContact, "Version", 0)==9?9:ICQ_VERSION)); // Success
+ }
+ }
+ else
+ {
+ if (wStatus == ID_STATUS_AWAY)
+ {
+ return icq_sendGetAimAwayMsgServ(szUID, MTYPE_AUTOAWAY);
+ }
+ }
+ }
+
+ return 0; // Failure
+}
+
+
+
+static message_cookie_data* CreateMsgCookieData(BYTE bMsgType, HANDLE hContact, DWORD dwUin)
+{
+ BYTE bAckType;
+ WORD wStatus = ICQGetContactStatus(hContact);
+
+ if (!ICQGetContactSettingByte(NULL, "SlowSend", DEFAULT_SLOWSEND))
+ bAckType = ACKTYPE_NONE;
+ else if ((!dwUin) || (!CheckContactCapabilities(hContact, CAPF_SRV_RELAY)) ||
+ (wStatus == ID_STATUS_OFFLINE) || ICQGetContactSettingByte(NULL, "OnlyServerAcks", DEFAULT_ONLYSERVERACKS))
+ bAckType = ACKTYPE_SERVER;
+ else
+ bAckType = ACKTYPE_CLIENT;
+
+ return CreateMessageCookie(bMsgType, bAckType);
+}
+
+
+
+int IcqSendMessage(WPARAM wParam, LPARAM lParam)
+{
+ if (lParam)
+ {
+ CCSDATA* ccs = (CCSDATA*)lParam;
+
+ if (ccs->hContact && ccs->lParam)
+ {
+ WORD wRecipientStatus;
+ DWORD dwCookie;
+ DWORD dwUin;
+ uid_str szUID;
+ char* pszText;
+
+ if (ICQGetContactSettingUID(ccs->hContact, &dwUin, &szUID))
+ { // Invalid contact
+ dwCookie = GenerateCookie(0);
+ icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_FAILED, ACKTYPE_MESSAGE, ICQTranslate("The receiver has an invalid user ID."));
+ return dwCookie;
+ }
+
+ if (dwUin && gbTempVisListEnabled && gnCurrentStatus == ID_STATUS_INVISIBLE)
+ makeContactTemporaryVisible(ccs->hContact); // make us temporarily visible to contact
+
+ pszText = (char*)ccs->lParam;
+
+ wRecipientStatus = ICQGetContactStatus(ccs->hContact);
+
+ // Failure scenarios
+ if (!icqOnline)
+ {
+ dwCookie = GenerateCookie(0);
+ icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_FAILED, ACKTYPE_MESSAGE, ICQTranslate("You cannot send messages when you are offline."));
+ }
+ else if ((wRecipientStatus == ID_STATUS_OFFLINE) && (strlennull(pszText) > 450))
+ {
+ dwCookie = GenerateCookie(0);
+ icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_FAILED, ACKTYPE_MESSAGE, ICQTranslate("Messages to offline contacts must be shorter than 450 characters."));
+ }
+ // Looks OK
+ else
+ {
+ message_cookie_data* pCookieData;
+
+ if (wRecipientStatus != ID_STATUS_OFFLINE && gbUtfEnabled==2 && !IsUSASCII(pszText, strlennull(pszText))
+ && CheckContactCapabilities(ccs->hContact, CAPF_UTF) && ICQGetContactSettingByte(ccs->hContact, "UnicodeSend", 1))
+ { // text contains national chars and we should send all this as Unicode, so do it
+ char* pszUtf = NULL;
+ int nStrSize = MultiByteToWideChar(CP_ACP, 0, pszText, strlennull(pszText), (wchar_t*)pszUtf, 0);
+ int nRes;
+
+ pszUtf = (char*)SAFE_MALLOC((nStrSize + 2)*sizeof(wchar_t));
+ // we omit ansi string - not used...
+ MultiByteToWideChar(CP_ACP, 0, pszText, strlennull(pszText), (wchar_t*)(pszUtf+1), nStrSize);
+ *(WORD*)(pszUtf + 1 + nStrSize*sizeof(wchar_t)) = '\0'; // trailing zeros
+
+ ccs->lParam = (LPARAM)pszUtf; // yeah, this is quite a hack, BE AWARE OF THAT !!!
+ ccs->wParam |= PREF_UNICODE;
+
+ nRes = IcqSendMessageW(wParam, lParam);
+ ccs->lParam = (LPARAM)pszText;
+
+ SAFE_FREE(&pszUtf); // release memory
+
+ return nRes;
+ }
+
+ if (!dwUin)
+ { // prepare AIM Html message
+ char *mng = MangleXml(pszText, strlennull(pszText));
+ char *tmp = (char*)SAFE_MALLOC(strlennull(mng) + 28);
+
+ strcpy(tmp, "<HTML><BODY>");
+ strcat(tmp, mng);
+ SAFE_FREE(&mng);
+ strcat(tmp, "</BODY></HTML>");
+ pszText = tmp;
+ }
+
+ // Set up the ack type
+ pCookieData = CreateMsgCookieData(MTYPE_PLAIN, ccs->hContact, dwUin);
+
+#ifdef _DEBUG
+ NetLog_Server("Send message - Message cap is %u", CheckContactCapabilities(ccs->hContact, CAPF_SRV_RELAY));
+ NetLog_Server("Send message - Contact status is %u", wRecipientStatus);
+#endif
+ if (dwUin && gbDCMsgEnabled && IsDirectConnectionOpen(ccs->hContact, DIRECTCONN_STANDARD))
+ {
+ int iRes = icq_SendDirectMessage(dwUin, ccs->hContact, pszText, strlennull(pszText), 1, pCookieData, NULL);
+ if (iRes) return iRes; // we succeded, return
+ }
+
+ if ((!dwUin || !CheckContactCapabilities(ccs->hContact, CAPF_SRV_RELAY)) || (wRecipientStatus == ID_STATUS_OFFLINE))
+ {
+ dwCookie = icq_SendChannel1Message(dwUin, szUID, ccs->hContact, pszText, pCookieData);
+ }
+ else
+ {
+ WORD wPriority;
+
+ if (wRecipientStatus == ID_STATUS_ONLINE || wRecipientStatus == ID_STATUS_FREECHAT)
+ wPriority = 0x0001;
+ else
+ wPriority = 0x0021;
+
+ dwCookie = icq_SendChannel2Message(dwUin, pszText, strlennull(pszText), wPriority, pCookieData, NULL);
+ }
+
+ // This will stop the message dialog from waiting for the real message delivery ack
+ if (pCookieData->nAckType == ACKTYPE_NONE)
+ {
+ icq_SendProtoAck(ccs->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);
+ }
+ if (!dwUin) SAFE_FREE(&pszText);
+ }
+
+ return dwCookie; // Success
+ }
+ }
+
+ return 0; // Failure
+}
+
+
+
+static char* convertMsgToUserSpecificAnsi(HANDLE hContact, const char* szMsg)
+{ // this needs valid "Unicode" buffer from SRMM !!!
+ WORD wCP = ICQGetContactSettingWord(hContact, "CodePage", gwAnsiCodepage);
+ int nMsgLen = strlennull(szMsg);
+ wchar_t* usMsg = (wchar_t*)(szMsg + nMsgLen + 1);
+ char* szAnsi = NULL;
+
+ if (wCP != CP_ACP)
+ {
+ int nStrSize = WideCharToMultiByte(wCP, 0, usMsg, nMsgLen, szAnsi, 0, NULL, NULL);
+
+ szAnsi = (char*)SAFE_MALLOC(nStrSize + 1);
+ WideCharToMultiByte(wCP, 0, usMsg, nMsgLen, szAnsi, nStrSize, NULL, NULL);
+ szAnsi[nStrSize] = '\0';
+ }
+ return szAnsi;
+}
+
+
+
+int IcqSendMessageW(WPARAM wParam, LPARAM lParam)
+{
+ if (lParam)
+ {
+ CCSDATA* ccs = (CCSDATA*)lParam;
+
+ if (ccs->hContact && ccs->lParam)
+ {
+ WORD wRecipientStatus;
+ DWORD dwCookie;
+ DWORD dwUin;
+ uid_str szUID;
+ wchar_t* pszText;
+ // TODO: this was not working, removed check
+ if (!gbUtfEnabled || /*(ccs->wParam & PREF_UNICODE == PREF_UNICODE) ||*/
+ (!CheckContactCapabilities(ccs->hContact, CAPF_UTF)) || (!ICQGetContactSettingByte(ccs->hContact, "UnicodeSend", 1)))
+ { // send as unicode only if marked as unicode & unicode enabled
+ char* szAnsi = convertMsgToUserSpecificAnsi(ccs->hContact, (char*)ccs->lParam);
+ int nRes;
+
+ if (szAnsi) ccs->lParam = (LPARAM)szAnsi;
+ nRes = IcqSendMessage(wParam, lParam);
+ SAFE_FREE(&szAnsi);
+
+ return nRes;
+ }
+
+ if (ICQGetContactSettingUID(ccs->hContact, &dwUin, &szUID))
+ { // Invalid contact
+ dwCookie = GenerateCookie(0);
+ icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_FAILED, ACKTYPE_MESSAGE, ICQTranslate("The receiver has an invalid user ID."));
+ return dwCookie;
+ }
+
+ if (dwUin && gbTempVisListEnabled && gnCurrentStatus == ID_STATUS_INVISIBLE)
+ makeContactTemporaryVisible(ccs->hContact); // make us temporarily visible to contact
+
+ pszText = (wchar_t*)((char*)ccs->lParam+strlennull((char*)ccs->lParam)+1); // get the UTF-16 part
+
+ wRecipientStatus = ICQGetContactStatus(ccs->hContact);
+
+ // Failure scenarios
+ if (!icqOnline)
+ {
+ dwCookie = GenerateCookie(0);
+ icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_FAILED, ACKTYPE_MESSAGE, ICQTranslate("You cannot send messages when you are offline."));
+ }
+ // Looks OK
+ else
+ {
+ message_cookie_data* pCookieData;
+ BOOL plain_ascii = IsUnicodeAscii(pszText, wcslen(pszText));
+
+ if ((wRecipientStatus == ID_STATUS_OFFLINE) || plain_ascii)
+ { // send as plain if no special char or user offline
+ char* szAnsi;
+ int nRes;
+
+ if (!plain_ascii)
+ {
+ szAnsi = convertMsgToUserSpecificAnsi(ccs->hContact, (char*)ccs->lParam);
+ if (szAnsi) ccs->lParam = (LPARAM)szAnsi;
+ }
+ nRes = IcqSendMessage(wParam, lParam);
+ if (!plain_ascii)
+ SAFE_FREE(&szAnsi);
+
+ return nRes;
+ };
+
+ // Set up the ack type
+ pCookieData = CreateMsgCookieData(MTYPE_PLAIN, ccs->hContact, dwUin);
+
+#ifdef _DEBUG
+ NetLog_Server("Send unicode message - Message cap is %u", CheckContactCapabilities(ccs->hContact, CAPF_SRV_RELAY));
+ NetLog_Server("Send unicode message - Contact status is %u", wRecipientStatus);
+#endif
+ if (dwUin && gbDCMsgEnabled && IsDirectConnectionOpen(ccs->hContact, DIRECTCONN_STANDARD))
+ {
+ char* utf8msg = make_utf8_string(pszText);
+ int iRes;
+
+ iRes = icq_SendDirectMessage(dwUin, ccs->hContact, utf8msg, strlennull(utf8msg), 1, pCookieData, CAP_UTF8MSGS);
+ SAFE_FREE(&utf8msg);
+
+ if (iRes) return iRes; // we succeded, return
+ }
+
+ if (!dwUin || !CheckContactCapabilities(ccs->hContact, CAPF_SRV_RELAY))
+ {
+ char* utmp;
+ char* mng;
+ char* tmp;
+
+ if (!dwUin)
+ {
+ utmp = make_utf8_string(pszText);
+ mng = MangleXml(utmp, strlennull(utmp));
+ SAFE_FREE(&utmp);
+ tmp = (char*)SAFE_MALLOC(strlennull(mng) + 28);
+ strcpy(tmp, "<HTML><BODY>");
+ strcat(tmp, mng);
+ SAFE_FREE(&mng);
+ strcat(tmp, "</BODY></HTML>");
+ pszText = make_unicode_string(tmp);
+ SAFE_FREE(&tmp);
+ }
+
+ dwCookie = icq_SendChannel1MessageW(dwUin, szUID, ccs->hContact, pszText, pCookieData);
+
+ if (!dwUin) SAFE_FREE(&pszText);
+ }
+ else
+ {
+ WORD wPriority;
+ char* utf8msg;
+
+ if (wRecipientStatus == ID_STATUS_ONLINE || wRecipientStatus == ID_STATUS_FREECHAT)
+ wPriority = 0x0001;
+ else
+ wPriority = 0x0021;
+
+ utf8msg = make_utf8_string(pszText);
+ dwCookie = icq_SendChannel2Message(dwUin, utf8msg, strlennull(utf8msg), wPriority, pCookieData, CAP_UTF8MSGS);
+
+ SAFE_FREE(&utf8msg);
+ }
+
+ // This will stop the message dialog from waiting for the real message delivery ack
+ if (pCookieData->nAckType == ACKTYPE_NONE)
+ {
+ icq_SendProtoAck(ccs->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);
+ }
+
+ }
+ return dwCookie; // Success
+ }
+ }
+ return 0; // Failure
+}
+
+
+
+int IcqSendUrl(WPARAM wParam, LPARAM lParam)
+{
+ if (lParam)
+ {
+ CCSDATA* ccs = (CCSDATA*)lParam;
+
+ if (ccs->hContact && ccs->lParam)
+ {
+ DWORD dwCookie;
+ WORD wRecipientStatus;
+ DWORD dwUin;
+
+ if (ICQGetContactSettingUID(ccs->hContact, &dwUin, NULL))
+ { // Invalid contact
+ dwCookie = GenerateCookie(0);
+ icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_FAILED, ACKTYPE_URL, ICQTranslate("The receiver has an invalid user ID."));
+ return dwCookie;
+ }
+
+ wRecipientStatus = ICQGetContactStatus(ccs->hContact);
+
+ // Failure
+ if (!icqOnline)
+ {
+ dwCookie = GenerateCookie(0);
+ icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_FAILED, ACKTYPE_URL, ICQTranslate("You cannot send messages when you are offline."));
+ }
+ // Looks OK
+ else
+ {
+ message_cookie_data* pCookieData;
+ char* szDesc;
+ char* szUrl;
+ char* szBody;
+ int nBodyLen;
+ int nDescLen;
+ int nUrlLen;
+
+
+ // Set up the ack type
+ pCookieData = CreateMsgCookieData(MTYPE_URL, ccs->hContact, dwUin);
+
+ // Format the body
+ szUrl = (char*)ccs->lParam;
+ nUrlLen = strlennull(szUrl);
+ szDesc = (char *)ccs->lParam + 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, szUrl);
+
+
+ if (gbDCMsgEnabled && IsDirectConnectionOpen(ccs->hContact, DIRECTCONN_STANDARD))
+ {
+ int iRes = icq_SendDirectMessage(dwUin, ccs->hContact, szBody, nBodyLen, 1, pCookieData, NULL);
+ if (iRes) return iRes; // we succeded, return
+ }
+
+ // Select channel and send
+ if (!CheckContactCapabilities(ccs->hContact, CAPF_SRV_RELAY) ||
+ wRecipientStatus == ID_STATUS_OFFLINE)
+ {
+ dwCookie = icq_SendChannel4Message(dwUin, 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, szBody, nBodyLen, wPriority, pCookieData, NULL);
+ }
+
+ // This will stop the message dialog from waiting for the real message delivery ack
+ if (pCookieData->nAckType == ACKTYPE_NONE)
+ {
+ icq_SendProtoAck(ccs->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
+}
+
+
+
+int IcqSendContacts(WPARAM wParam, LPARAM lParam)
+{
+ if (lParam)
+ {
+ CCSDATA* ccs = (CCSDATA*)lParam;
+
+ if (ccs->hContact && ccs->lParam)
+ {
+ int nContacts;
+ int i;
+ HANDLE* hContactsList = (HANDLE*)ccs->lParam;
+ DWORD dwUin;
+ WORD wRecipientStatus;
+ DWORD dwCookie;
+
+ if (ICQGetContactSettingUID(ccs->hContact, &dwUin, NULL))
+ { // Invalid contact
+ dwCookie = GenerateCookie(0);
+ icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_FAILED, ACKTYPE_CONTACTS, ICQTranslate("The receiver has an invalid user ID."));
+ return dwCookie;
+ }
+
+ wRecipientStatus = ICQGetContactStatus(ccs->hContact);
+ nContacts = HIWORD(ccs->wParam);
+
+ // Failures
+ if (!icqOnline)
+ {
+ dwCookie = GenerateCookie(0);
+ icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_FAILED, ACKTYPE_CONTACTS, ICQTranslate("You cannot send messages when you are offline."));
+ }
+ else if (!hContactsList || (nContacts < 1) || (nContacts > MAX_CONTACTSSEND))
+ {
+ dwCookie = GenerateCookie(0);
+ icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_FAILED, ACKTYPE_CONTACTS, ICQTranslate("Bad data (internal error #1)"));
+ }
+ // OK
+ else
+ {
+ int nBodyLength;
+ char szUin[UINMAXLEN];
+ char szCount[17];
+ struct icq_contactsend_s* contacts = NULL;
+ uid_str szUid;
+
+
+ // 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.
+ if (contacts = (struct icq_contactsend_s*)SAFE_MALLOC(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 (ICQGetContactSettingUID(hContactsList[i], &contacts[i].uin, &szUid))
+ break; // Abort if invalid contact
+ contacts[i].uid = contacts[i].uin?NULL:null_strdup(szUid);
+ 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)
+ {
+ message_cookie_data* pCookieData;
+ 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);
+ strncpy(pBuffer, szCount, nBodyLength);
+ pBuffer += strlennull(pBuffer);
+ *pBuffer++ = (char)0xFE;
+ for (i = 0; i < nContacts; i++)
+ {
+ if (contacts[i].uin)
+ {
+ _itoa(contacts[i].uin, szUin, 10);
+ strcpy(pBuffer, szUin);
+ }
+ else
+ strcpy(pBuffer, contacts[i].uid);
+ pBuffer += strlennull(pBuffer);
+ *pBuffer++ = (char)0xFE;
+ strcpy(pBuffer, contacts[i].szNick);
+ pBuffer += strlennull(pBuffer);
+ *pBuffer++ = (char)0xFE;
+ }
+
+ // Set up the ack type
+ pCookieData = CreateMsgCookieData(MTYPE_CONTACTS, ccs->hContact, dwUin);
+
+ if (gbDCMsgEnabled && IsDirectConnectionOpen(ccs->hContact, DIRECTCONN_STANDARD))
+ {
+ int iRes = icq_SendDirectMessage(dwUin, ccs->hContact, pBody, nBodyLength, 1, pCookieData, NULL);
+
+ if (iRes)
+ {
+ SAFE_FREE(&pBody);
+
+ for(i = 0; i < nContacts; i++)
+ { // release memory
+ SAFE_FREE(&contacts[i].szNick);
+ SAFE_FREE(&contacts[i].uid);
+ }
+
+ SAFE_FREE(&contacts);
+
+ return iRes; // we succeded, return
+ }
+ }
+
+ // Select channel and send
+ if (!CheckContactCapabilities(ccs->hContact, CAPF_SRV_RELAY) ||
+ wRecipientStatus == ID_STATUS_OFFLINE)
+ {
+ dwCookie = icq_SendChannel4Message(dwUin, 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, pBody, nBodyLength, wPriority, pCookieData, NULL);
+ }
+
+ // This will stop the message dialog from waiting for the real message delivery ack
+ if (pCookieData->nAckType == ACKTYPE_NONE)
+ {
+ icq_SendProtoAck(ccs->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(&pBody);
+ }
+ else
+ {
+ dwCookie = GenerateCookie(0);
+ icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_FAILED, ACKTYPE_CONTACTS, ICQTranslate("Bad data (internal error #2)"));
+ }
+
+ for(i = 0; i < nContacts; i++)
+ {
+ SAFE_FREE(&contacts[i].szNick);
+ SAFE_FREE(&contacts[i].uid);
+ }
+
+ SAFE_FREE(&contacts);
+ }
+ else
+ {
+ dwCookie = 0;
+ }
+ }
+
+ return dwCookie;
+ }
+ }
+
+ // Exit with Failure
+ return 0;
+}
+
+
+
+int IcqSendFile(WPARAM wParam, LPARAM lParam)
+{
+ if (lParam && icqOnline)
+ {
+ CCSDATA* ccs = (CCSDATA*)lParam;
+
+ if (ccs->hContact && ccs->lParam && ccs->wParam)
+ {
+ HANDLE hContact = ccs->hContact;
+ char** files = (char**)ccs->lParam;
+ char* pszDesc = (char*)ccs->wParam;
+ DWORD dwUin;
+
+ if (ICQGetContactSettingUID(hContact, &dwUin, NULL))
+ return 0; // Invalid contact
+
+ if (dwUin)
+ {
+ if (ICQGetContactStatus(hContact) != ID_STATUS_OFFLINE)
+ {
+ WORD wClientVersion;
+
+ wClientVersion = ICQGetContactSettingWord(ccs->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; files[ft->dwFileCount]; ft->dwFileCount++);
+ ft->files = (char **)SAFE_MALLOC(sizeof(char *) * ft->dwFileCount);
+ ft->dwTotalSize = 0;
+ for (i = 0; i < (int)ft->dwFileCount; i++)
+ {
+ ft->files[i] = null_strdup(files[i]);
+
+ if (_stat(files[i], &statbuf))
+ NetLog_Server("IcqSendFile() was passed invalid filename(s)");
+ else
+ ft->dwTotalSize += statbuf.st_size;
+ }
+ ft->szDescription = null_strdup(pszDesc);
+ ft->dwTransferSpeed = 100;
+ ft->sending = 1;
+ ft->fileId = -1;
+ ft->iCurrentFile = 0;
+ ft->dwCookie = AllocateCookie(CKT_FILE, 0, dwUin, ft);
+ ft->hConnection = NULL;
+
+ // Send file transfer request
+ {
+ char szFiles[64];
+ char* pszFiles;
+
+
+ NetLog_Server("Init file send");
+
+ if (ft->dwFileCount == 1)
+ {
+ pszFiles = strrchr(ft->files[0], '\\');
+ if (pszFiles)
+ pszFiles++;
+ else
+ pszFiles = ft->files[0];
+ }
+ else
+ {
+ null_snprintf(szFiles, 64, ICQTranslate("%d Files"), ft->dwFileCount);
+ pszFiles = szFiles;
+ }
+
+ // Send packet
+ {
+ if (ft->nVersion == 7)
+ {
+ if (gbDCMsgEnabled && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD))
+ {
+ int iRes = icq_sendFileSendDirectv7(ft, pszFiles);
+ if (iRes) return (int)(HANDLE)ft; // Success
+ }
+ NetLog_Server("Sending v%u file transfer request through server", 7);
+ icq_sendFileSendServv7(ft, pszFiles);
+ }
+ else
+ {
+ if (gbDCMsgEnabled && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD))
+ {
+ int iRes = icq_sendFileSendDirectv8(ft, pszFiles);
+ if (iRes) return (int)(HANDLE)ft; // Success
+ }
+ NetLog_Server("Sending v%u file transfer request through server", 8);
+ icq_sendFileSendServv8(ft, pszFiles, ACKTYPE_NONE);
+ }
+ }
+ }
+
+ return (int)(HANDLE)ft; // Success
+ }
+ }
+ }
+ }
+ }
+
+ return 0; // Failure
+}
+
+
+int IcqSendAuthRequest(WPARAM wParam, LPARAM lParam)
+{
+ if (lParam && icqOnline)
+ {
+ CCSDATA* ccs = (CCSDATA*)lParam;
+ DWORD dwUin;
+ uid_str szUid;
+
+ if (ccs->hContact)
+ {
+ if (ICQGetContactSettingUID(ccs->hContact, &dwUin, &szUid))
+ return 1; // Invalid contact
+
+ if (dwUin && ccs->lParam)
+ {
+ char *text = (char *)ccs->lParam;
+ char *utf;
+
+ utf = ansi_to_utf8(text); // Miranda is ANSI only here
+
+ icq_sendAuthReqServ(dwUin, szUid, utf);
+
+ SAFE_FREE(&utf);
+
+ return 0; // Success
+ }
+ }
+ }
+
+ return 1; // Failure
+}
+
+
+
+int IcqSendYouWereAdded(WPARAM wParam, LPARAM lParam)
+{
+ if (lParam && icqOnline)
+ {
+ CCSDATA* ccs = (CCSDATA*)lParam;
+
+ if (ccs->hContact)
+ {
+ DWORD dwUin, dwMyUin;
+
+ if (ICQGetContactSettingUID(ccs->hContact, &dwUin, NULL))
+ return 1; // Invalid contact
+
+ dwMyUin = ICQGetContactSettingUIN(NULL);
+
+ if (dwUin)
+ {
+ icq_sendYouWereAddedServ(dwUin, dwMyUin);
+
+ return 0; // Success
+ }
+ }
+ }
+
+ return 1; // Failure
+}
+
+
+
+int IcqGrantAuthorization(WPARAM wParam, LPARAM lParam)
+{
+ if (gnCurrentStatus != ID_STATUS_OFFLINE && gnCurrentStatus != ID_STATUS_CONNECTING && wParam != 0)
+ {
+ DWORD dwUin;
+ uid_str szUid;
+
+ if (ICQGetContactSettingUID((HANDLE)wParam, &dwUin, &szUid))
+ return 0; // Invalid contact
+
+ // send without reason, do we need any ?
+ icq_sendGrantAuthServ(dwUin, szUid, NULL);
+ }
+
+ return 0;
+}
+
+
+
+int IcqRevokeAuthorization(WPARAM wParam, LPARAM lParam)
+{
+ if (gnCurrentStatus != ID_STATUS_OFFLINE && gnCurrentStatus != ID_STATUS_CONNECTING && wParam != 0)
+ {
+ DWORD dwUin;
+ uid_str szUid;
+ char str[MAX_PATH], cap[MAX_PATH];
+
+ if (ICQGetContactSettingUID((HANDLE)wParam, &dwUin, &szUid))
+ return 0; // Invalid contact
+
+ if (MessageBoxUtf(NULL, ICQTranslateUtfStatic("Are you sure you want to revoke user's authorisation (this will remove you from his/her list on some clients) ?", str), ICQTranslateUtfStatic("Confirmation", cap), MB_ICONQUESTION | MB_YESNO) != IDYES)
+ return 0;
+
+ icq_sendRevokeAuthServ(dwUin, szUid);
+ }
+
+ return 0;
+}
+
+
+
+int IcqSendUserIsTyping(WPARAM wParam, LPARAM lParam)
+{
+ int nResult = 1;
+ HANDLE hContact = (HANDLE)wParam;
+
+
+ if (hContact && icqOnline)
+ {
+ if (CheckContactCapabilities(hContact, CAPF_TYPING))
+ {
+ switch (lParam)
+ {
+ case PROTOTYPE_SELFTYPING_ON:
+ sendTypingNotification(hContact, MTN_BEGUN);
+ nResult = 0;
+ break;
+
+ case PROTOTYPE_SELFTYPING_OFF:
+ sendTypingNotification(hContact, MTN_FINISHED);
+ nResult = 0;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ return nResult;
+}
+
+
+
+/*
+ ---------------------------------
+ | Receiving |
+ ---------------------------------
+*/
+
+static void ICQAddRecvEvent(HANDLE hContact, WORD wType, PROTORECVEVENT* pre, DWORD cbBlob, PBYTE pBlob)
+{
+ DWORD flags = (pre->flags & PREF_CREATEREAD) ? DBEF_READ : 0;
+
+ if (hContact)
+ SetContactHidden(hContact, 0);
+
+ ICQAddEvent(hContact, wType, pre->timestamp, flags, cbBlob, pBlob);
+}
+
+
+
+int IcqRecvAwayMsg(WPARAM wParam,LPARAM lParam)
+{
+ CCSDATA* ccs = (CCSDATA*)lParam;
+ PROTORECVEVENT* pre = (PROTORECVEVENT*)ccs->lParam;
+
+
+ ICQBroadcastAck(ccs->hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS,
+ (HANDLE)pre->lParam, (LPARAM)pre->szMessage);
+
+ return 0;
+}
+
+
+
+int IcqRecvMessage(WPARAM wParam, LPARAM lParam)
+{
+ CCSDATA* ccs = (CCSDATA*)lParam;
+ PROTORECVEVENT* pre = (PROTORECVEVENT*)ccs->lParam;
+ DWORD cbBlob;
+
+ cbBlob = strlennull(pre->szMessage) + 1;
+ if ( pre->flags & PREF_UNICODE )
+ cbBlob *= ( sizeof( wchar_t )+1 );
+
+ ICQAddRecvEvent(ccs->hContact, EVENTTYPE_MESSAGE, pre, cbBlob, (PBYTE)pre->szMessage);
+
+ // stop contact from typing - some clients do not sent stop notify
+ if (CheckContactCapabilities(ccs->hContact, CAPF_TYPING))
+ CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)ccs->hContact, PROTOTYPE_CONTACTTYPING_OFF);
+
+ return 0;
+}
+
+
+
+int IcqRecvUrl(WPARAM wParam, LPARAM lParam)
+{
+ CCSDATA* ccs = (CCSDATA*)lParam;
+ PROTORECVEVENT* pre = (PROTORECVEVENT*)ccs->lParam;
+ char* szDesc;
+ DWORD cbBlob;
+
+ szDesc = pre->szMessage + strlennull(pre->szMessage) + 1;
+
+ cbBlob = strlennull(pre->szMessage) + strlennull(szDesc) + 2;
+
+ ICQAddRecvEvent(ccs->hContact, EVENTTYPE_URL, pre, cbBlob, (PBYTE)pre->szMessage);
+
+ return 0;
+}
+
+
+
+int IcqRecvContacts(WPARAM wParam, LPARAM lParam)
+{
+ CCSDATA* ccs = (CCSDATA*)lParam;
+ PROTORECVEVENT* pre = (PROTORECVEVENT*)ccs->lParam;
+ ICQSEARCHRESULT** isrList = (ICQSEARCHRESULT**)pre->szMessage;
+ int i;
+ char szUin[UINMAXLEN];
+ DWORD cbBlob = 0;
+ PBYTE pBlob,pCurBlob;
+
+ for (i = 0; i < pre->lParam; i++)
+ {
+ cbBlob += strlennull(isrList[i]->hdr.nick) + 2; // both trailing zeros
+ if (isrList[i]->uin)
+ cbBlob += getUINLen(isrList[i]->uin);
+ else
+ cbBlob += strlennull(isrList[i]->uid);
+ }
+ pBlob = (PBYTE)_alloca(cbBlob);
+ for (i = 0, pCurBlob = pBlob; i < pre->lParam; i++)
+ {
+ strcpy(pCurBlob, isrList[i]->hdr.nick);
+ pCurBlob += strlennull(pCurBlob) + 1;
+ if (isrList[i]->uin)
+ {
+ _itoa(isrList[i]->uin, szUin, 10);
+ strcpy(pCurBlob, szUin);
+ }
+ else // aim contact
+ strcpy(pCurBlob, isrList[i]->uid);
+ pCurBlob += strlennull(pCurBlob) + 1;
+ }
+
+ ICQAddRecvEvent(ccs->hContact, EVENTTYPE_CONTACTS, pre, cbBlob, pBlob);
+
+ return 0;
+}
+
+
+
+int IcqRecvFile(WPARAM wParam, LPARAM lParam)
+{
+ CCSDATA* ccs = (CCSDATA*)lParam;
+ PROTORECVEVENT* pre = (PROTORECVEVENT*)ccs->lParam;
+ char* szDesc;
+ char* szFile;
+ DWORD cbBlob;
+
+ szFile = pre->szMessage + sizeof(DWORD);
+ szDesc = szFile + strlennull(szFile) + 1;
+
+ cbBlob = sizeof(DWORD) + strlennull(szFile) + strlennull(szDesc) + 2;
+
+ ICQAddRecvEvent(ccs->hContact, EVENTTYPE_FILE, pre, cbBlob, (PBYTE)pre->szMessage);
+
+ return 0;
+}
+
+
+
+int IcqRecvAuth(WPARAM wParam, LPARAM lParam)
+{
+ CCSDATA* ccs = (CCSDATA*)lParam;
+ PROTORECVEVENT* pre = (PROTORECVEVENT*)ccs->lParam;
+
+ SetContactHidden(ccs->hContact, 0);
+
+ ICQAddRecvEvent(NULL, EVENTTYPE_AUTHREQUEST, pre, pre->lParam, (PBYTE)pre->szMessage);
+
+ return 0;
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/icqosc_svcs.h b/miranda-wine/protocols/IcqOscarJ/icqosc_svcs.h
new file mode 100644
index 0000000..7d735aa
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icqosc_svcs.h
@@ -0,0 +1,95 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icqosc_svcs.h,v $
+// Revision : $Revision: 3484 $
+// Last change on : $Date: 2006-08-13 19:51:44 +0400 (Ð’Ñк, 13 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#ifndef __ICQOSC_SVCS_H
+#define __ICQOSC_SVCS_H
+
+/*---------* Functions *---------------*/
+
+int IcqGetCaps(WPARAM wParam, LPARAM lParam);
+int IcqGetName(WPARAM wParam, LPARAM lParam);
+int IcqLoadIcon(WPARAM wParam, LPARAM lParam);
+int IcqSetStatus(WPARAM wParam, LPARAM lParam);
+int IcqGetStatus(WPARAM wParam, LPARAM lParam);
+int IcqSetAwayMsg(WPARAM wParam, LPARAM lParam);
+int IcqGetAwayMsg(WPARAM wParam, LPARAM lParam);
+int IcqRecvAwayMsg(WPARAM wParam,LPARAM lParam);
+int IcqAuthAllow(WPARAM wParam, LPARAM lParam);
+int IcqAuthDeny(WPARAM wParam, LPARAM lParam);
+int IcqBasicSearch(WPARAM wParam, LPARAM lParam);
+int IcqSearchByEmail(WPARAM wParam, LPARAM lParam);
+int IcqSearchByDetails(WPARAM wParam, LPARAM lParam);
+int IcqCreateAdvSearchUI(WPARAM wParam, LPARAM lParam);
+int IcqSearchByAdvanced(WPARAM wParam, LPARAM lParam);
+int IcqAddToList(WPARAM wParam, LPARAM lParam);
+int IcqAddToListByEvent(WPARAM wParam, LPARAM lParam);
+int IcqSetNickName(WPARAM wParam, LPARAM lParam);
+int IcqChangeInfoEx(WPARAM wParam, LPARAM lParam);
+int IcqGetInfo(WPARAM wParam, LPARAM lParam);
+int IcqSendSms(WPARAM wParam, LPARAM lParam);
+int IcqSetApparentMode(WPARAM wParam, LPARAM lParam);
+int IcqSendMessage(WPARAM wParam, LPARAM lParam);
+int IcqSendMessageW(WPARAM wParam, LPARAM lParam);
+int IcqSendUrl(WPARAM wParam, LPARAM lParam);
+int IcqSendContacts(WPARAM wParam, LPARAM lParam);
+int IcqSendFile(WPARAM wParam, LPARAM lParam);
+int IcqFileAllow(WPARAM wParam, LPARAM lParam);
+int IcqFileDeny(WPARAM wParam, LPARAM lParam);
+int IcqFileCancel(WPARAM wParam, LPARAM lParam);
+int IcqFileResume(WPARAM wParam, LPARAM lParam);
+int IcqGrantAuthorization(WPARAM wParam, LPARAM lParam);
+int IcqRevokeAuthorization(WPARAM wParam, LPARAM lParam);
+int IcqSendAuthRequest(WPARAM,LPARAM);
+int IcqSendYouWereAdded(WPARAM,LPARAM);
+int IcqSendUserIsTyping(WPARAM wParam, LPARAM lParam);
+
+int IcqRecvMessage(WPARAM wParam, LPARAM lParam);
+int IcqRecvUrl(WPARAM wParam, LPARAM lParam);
+int IcqRecvContacts(WPARAM wParam, LPARAM lParam);
+int IcqRecvFile(WPARAM wParam, LPARAM lParam);
+int IcqRecvAuth(WPARAM wParam, LPARAM lParam);
+
+int IcqIdleChanged(WPARAM wParam, LPARAM lParam);
+
+int IcqGetAvatarInfo(WPARAM wParam, LPARAM lParam);
+int IcqGetMaxAvatarSize(WPARAM wParam, LPARAM lParam);
+int IcqAvatarFormatSupported(WPARAM wParam, LPARAM lParam);
+int IcqGetMyAvatar(WPARAM wParam, LPARAM lParam);
+int IcqSetMyAvatar(WPARAM wParam, LPARAM lParam);
+
+int IcqSetPassword(WPARAM wParam, LPARAM lParam);
+
+#endif /* __ICQOSC_SVCS_H */
diff --git a/miranda-wine/protocols/IcqOscarJ/icqoscar.c b/miranda-wine/protocols/IcqOscarJ/icqoscar.c
new file mode 100644
index 0000000..5ac674f
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icqoscar.c
@@ -0,0 +1,42 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icqoscar.c,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// 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/miranda-wine/protocols/IcqOscarJ/icqoscar.h b/miranda-wine/protocols/IcqOscarJ/icqoscar.h
new file mode 100644
index 0000000..4360425
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/icqoscar.h
@@ -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,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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icqoscar.h,v $
+// Revision : $Revision: 3529 $
+// Last change on : $Date: 2006-08-18 02:30:37 +0400 (Птн, 18 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Includes all header files that should be precompiled to speed up compilation.
+//
+// -----------------------------------------------------------------------------
+
+
+
+// Windows includes
+#include <windows.h>
+#include <commctrl.h>
+
+// Standard includes
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <io.h>
+#include <direct.h>
+#include <fcntl.h>
+#include <crtdbg.h>
+#include <process.h>
+#include <malloc.h>
+
+// Miranda IM SDK includes
+#include <newpluginapi.h> // This must be included first
+#include <m_clc.h>
+#include <m_clist.h>
+#include <m_clui.h>
+#include <m_database.h>
+#include <m_langpack.h>
+#include <m_message.h>
+#include <m_netlib.h>
+#include <m_protocols.h>
+#include <m_protomod.h>
+#include <m_protosvc.h>
+#include <m_options.h>
+#include <m_system.h>
+#include <m_userinfo.h>
+#include <m_utils.h>
+#include <m_idle.h>
+#include <m_popup.h>
+#include <m_clistint.h>
+
+// Project resources
+#include "resource.h"
+
+// ICQ plugin includes
+#include "globals.h"
+#include "icq_db.h"
+#include "i18n.h"
+#include "cookies.h"
+#include "capabilities.h"
+#include "icq_packet.h"
+#include "icq_direct.h"
+#include "oscar_filetransfer.h"
+#include "icq_server.h"
+#include "icqosc_svcs.h"
+#include "icq_xtraz.h"
+#include "icq_opts.h"
+#include "icq_servlist.h"
+#include "icq_http.h"
+#include "icq_fieldnames.h"
+#include "icq_constants.h"
+#include "guids.h"
+#include "icq_infoupdate.h"
+#include "icq_avatar.h"
+#include "init.h"
+#include "stdpackets.h"
+#include "directpackets.h"
+#include "tlv.h"
+#include "families.h"
+#include "utilities.h"
+#include "m_icq.h"
+#include "icq_advsearch.h"
+#include "icq_uploadui.h"
+#include "log.h"
+#include "channels.h"
+#include "forkthread.h"
+#include "UI/askauthentication.h"
+#include "UI/userinfotab.h"
+#include "UI/loginpassword.h"
+
+#include "icq_rates.h"
+
+#include "changeinfo/changeinfo.h"
+#include "icq_popups.h"
+#include "iconlib.h"
+
+#include "md5.h"
+
+// :TODO: This should not be here :p
+void icq_FirstRunCheck(void);
diff --git a/miranda-wine/protocols/IcqOscarJ/init.c b/miranda-wine/protocols/IcqOscarJ/init.c
new file mode 100644
index 0000000..3832c9e
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/init.c
@@ -0,0 +1,573 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/init.c,v $
+// Revision : $Revision: 3709 $
+// Last change on : $Date: 2006-09-06 02:09:00 +0400 (Срд, 06 Сен 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+#include "m_updater.h"
+
+
+PLUGINLINK* pluginLink;
+HANDLE hHookUserInfoInit = NULL;
+HANDLE hHookOptionInit = NULL;
+HANDLE hHookUserMenu = NULL;
+HANDLE hHookIdleEvent = NULL;
+HANDLE hHookIconsChanged = NULL;
+static HANDLE hUserMenuAuth = NULL;
+static HANDLE hUserMenuGrant = NULL;
+static HANDLE hUserMenuRevoke = NULL;
+static HANDLE hUserMenuXStatus = NULL;
+
+extern HANDLE hServerConn;
+CRITICAL_SECTION localSeqMutex;
+CRITICAL_SECTION connectionHandleMutex;
+HANDLE hsmsgrequest;
+HANDLE hxstatusiconchanged;
+
+extern int bHideXStatusUI;
+
+PLUGININFO pluginInfo = {
+ sizeof(PLUGININFO),
+ NULL,
+ PLUGIN_MAKE_VERSION(0,3,8,1),
+ "Support for ICQ network, enhanced.",
+ "Joe Kucera, Bio, Martin Öberg, Richard Hughes, Jon Keating, etc",
+ "jokusoftware@miranda-im.org",
+ "(C) 2000-2006 M.Öberg, R.Hughes, J.Keating, Bio, Angeli-Ka, J.Kucera",
+ "http://addons.miranda-im.org/details.php?action=viewfile&id=1683",
+ 0, //not transient
+ 0 //doesn't replace anything built-in
+};
+
+static char pluginName[64];
+
+static int OnSystemModulesLoaded(WPARAM wParam,LPARAM lParam);
+static int OnSystemPreShutdown(WPARAM wParam,LPARAM lParam);
+static int icq_PrebuildContactMenu(WPARAM wParam, LPARAM lParam);
+static int IconLibIconsChanged(WPARAM wParam, LPARAM lParam);
+
+
+
+PLUGININFO __declspec(dllexport) *MirandaPluginInfo(DWORD mirandaVersion)
+{
+ // Only load for 0.4.0.1 or greater
+ // Miranda IM v0.4.0.1 contained important DB bug fix
+ if (mirandaVersion < PLUGIN_MAKE_VERSION(0, 4, 0, 1))
+ {
+ return NULL;
+ }
+ else
+ {
+ // Are we running under Unicode Windows version ?
+ gbUnicodeAPI = (GetVersion() & 0x80000000) == 0;
+ strcpy(pluginName, "IcqOscarJ Protocol");
+ if (gbUnicodeAPI)
+ strcat(pluginName, " (Unicode)");
+ pluginInfo.shortName = pluginName;
+ MIRANDA_VERSION = mirandaVersion;
+ return &pluginInfo;
+ }
+}
+
+
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
+{
+ hInst = hinstDLL;
+
+ return TRUE;
+}
+
+
+
+static HANDLE ICQCreateServiceFunction(const char* szService, MIRANDASERVICE serviceProc)
+{
+ char str[MAX_PATH + 32];
+ strcpy(str, gpszICQProtoName);
+ strcat(str, szService);
+ return CreateServiceFunction(str, serviceProc);
+}
+
+
+
+int __declspec(dllexport) Load(PLUGINLINK *link)
+{
+ PROTOCOLDESCRIPTOR pd = {0};
+
+ pluginLink = link;
+
+ ghServerNetlibUser = NULL;
+
+ // Are we running under Unicode Windows version ?
+ gbUnicodeAPI = (GetVersion() & 0x80000000) == 0;
+ // Do we have new LangPack module ready ?
+ gbUtfLangpack = ServiceExists(MS_LANGPACK_GETCODEPAGE);
+ { // Are we running under unicode Miranda core ?
+ char szVer[MAX_PATH];
+
+ CallService(MS_SYSTEM_GETVERSIONTEXT, MAX_PATH, (LPARAM)szVer);
+ gbUnicodeCore = (strstr(szVer, "Unicode") != NULL);
+ }
+
+ srand(time(NULL));
+ _tzset();
+
+ // Get module name from DLL file name
+ {
+ char* str1;
+ char str2[MAX_PATH];
+ int nProtoNameLen;
+
+ GetModuleFileName(hInst, str2, MAX_PATH);
+ str1 = strrchr(str2, '\\');
+ nProtoNameLen = strlennull(str1);
+ if (str1 != NULL && (nProtoNameLen > 5))
+ {
+ strncpy(gpszICQProtoName, str1+1, nProtoNameLen-5);
+ gpszICQProtoName[nProtoNameLen-4] = 0;
+ }
+ CharUpper(gpszICQProtoName);
+ }
+
+ ZeroMemory(gpszPassword, sizeof(gpszPassword));
+
+ icq_FirstRunCheck();
+
+ HookEvent(ME_SYSTEM_MODULESLOADED, OnSystemModulesLoaded);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN, OnSystemPreShutdown);
+
+ InitializeCriticalSection(&connectionHandleMutex);
+ InitializeCriticalSection(&localSeqMutex);
+ InitializeCriticalSection(&modeMsgsMutex);
+
+ // Initialize core modules
+ InitDB(); // DB interface
+ InitCookies(); // cookie utils
+ InitCache(); // contacts cache
+ InitRates(); // rate management
+
+ // Register the module
+ pd.cbSize = sizeof(pd);
+ pd.szName = gpszICQProtoName;
+ pd.type = PROTOTYPE_PROTOCOL;
+ CallService(MS_PROTO_REGISTERMODULE, 0, (LPARAM)&pd);
+
+ // Initialize status message struct
+ ZeroMemory(&modeMsgs, sizeof(icq_mode_messages));
+
+ // Initialize temporary DB settings
+ ICQCreateResidentSetting("Status"); // NOTE: XStatus cannot be temporary
+ ICQCreateResidentSetting("TemporaryVisible");
+ ICQCreateResidentSetting("TickTS");
+ ICQCreateResidentSetting("IdleTS");
+ ICQCreateResidentSetting("LogonTS");
+
+ // Reset a bunch of session specific settings
+ ResetSettingsOnLoad();
+
+ // Setup services
+ ICQCreateServiceFunction(PS_GETCAPS, IcqGetCaps);
+ ICQCreateServiceFunction(PS_GETNAME, IcqGetName);
+ ICQCreateServiceFunction(PS_LOADICON, IcqLoadIcon);
+ ICQCreateServiceFunction(PS_SETSTATUS, IcqSetStatus);
+ ICQCreateServiceFunction(PS_GETSTATUS, IcqGetStatus);
+ ICQCreateServiceFunction(PS_SETAWAYMSG, IcqSetAwayMsg);
+ ICQCreateServiceFunction(PS_AUTHALLOW, IcqAuthAllow);
+ ICQCreateServiceFunction(PS_AUTHDENY, IcqAuthDeny);
+ ICQCreateServiceFunction(PS_BASICSEARCH, IcqBasicSearch);
+ ICQCreateServiceFunction(PS_SEARCHBYEMAIL, IcqSearchByEmail);
+ ICQCreateServiceFunction(MS_ICQ_SEARCHBYDETAILS, IcqSearchByDetails);
+ ICQCreateServiceFunction(PS_SEARCHBYNAME, IcqSearchByDetails);
+ ICQCreateServiceFunction(PS_CREATEADVSEARCHUI, IcqCreateAdvSearchUI);
+ ICQCreateServiceFunction(PS_SEARCHBYADVANCED, IcqSearchByAdvanced);
+ ICQCreateServiceFunction(MS_ICQ_SENDSMS, IcqSendSms);
+ ICQCreateServiceFunction(PS_ADDTOLIST, IcqAddToList);
+ ICQCreateServiceFunction(PS_ADDTOLISTBYEVENT, IcqAddToListByEvent);
+ ICQCreateServiceFunction(PS_FILERESUME, IcqFileResume);
+ ICQCreateServiceFunction(PS_SET_NICKNAME, IcqSetNickName);
+ ICQCreateServiceFunction(PSS_GETINFO, IcqGetInfo);
+ ICQCreateServiceFunction(PSS_MESSAGE, IcqSendMessage);
+ ICQCreateServiceFunction(PSS_MESSAGE"W", IcqSendMessageW);
+ ICQCreateServiceFunction(PSS_URL, IcqSendUrl);
+ ICQCreateServiceFunction(PSS_CONTACTS, IcqSendContacts);
+ ICQCreateServiceFunction(PSS_SETAPPARENTMODE, IcqSetApparentMode);
+ ICQCreateServiceFunction(PSS_GETAWAYMSG, IcqGetAwayMsg);
+ ICQCreateServiceFunction(PSS_FILEALLOW, IcqFileAllow);
+ ICQCreateServiceFunction(PSS_FILEDENY, IcqFileDeny);
+ ICQCreateServiceFunction(PSS_FILECANCEL, IcqFileCancel);
+ ICQCreateServiceFunction(PSS_FILE, IcqSendFile);
+ ICQCreateServiceFunction(PSR_AWAYMSG, IcqRecvAwayMsg);
+ ICQCreateServiceFunction(PSR_FILE, IcqRecvFile);
+ ICQCreateServiceFunction(PSR_MESSAGE, IcqRecvMessage);
+ ICQCreateServiceFunction(PSR_URL, IcqRecvUrl);
+ ICQCreateServiceFunction(PSR_CONTACTS, IcqRecvContacts);
+ ICQCreateServiceFunction(PSR_AUTH, IcqRecvAuth);
+ ICQCreateServiceFunction(PSS_AUTHREQUEST, IcqSendAuthRequest);
+ ICQCreateServiceFunction(PSS_ADDED, IcqSendYouWereAdded);
+ ICQCreateServiceFunction(PSS_USERISTYPING, IcqSendUserIsTyping);
+ ICQCreateServiceFunction(PS_GETAVATARINFO, IcqGetAvatarInfo);
+ // Session password API
+ ICQCreateServiceFunction(PS_ICQ_SETPASSWORD, IcqSetPassword);
+ // ChangeInfo API
+ ICQCreateServiceFunction(PS_CHANGEINFOEX, IcqChangeInfoEx);
+ // My Avatar API
+ ICQCreateServiceFunction(PS_ICQ_GETMYAVATARMAXSIZE, IcqGetMaxAvatarSize);
+ ICQCreateServiceFunction(PS_ICQ_ISAVATARFORMATSUPPORTED, IcqAvatarFormatSupported);
+ ICQCreateServiceFunction(PS_ICQ_GETMYAVATAR, IcqGetMyAvatar);
+ ICQCreateServiceFunction(PS_ICQ_SETMYAVATAR, IcqSetMyAvatar);
+ // Custom Status API
+ ICQCreateServiceFunction(PS_ICQ_SETCUSTOMSTATUS, IcqSetXStatus); // obsolete (remove in next version)
+ ICQCreateServiceFunction(PS_ICQ_GETCUSTOMSTATUS, IcqGetXStatus); // obsolete
+ ICQCreateServiceFunction(PS_ICQ_SETCUSTOMSTATUSEX, IcqSetXStatusEx);
+ ICQCreateServiceFunction(PS_ICQ_GETCUSTOMSTATUSEX, IcqGetXStatusEx);
+ ICQCreateServiceFunction(PS_ICQ_GETCUSTOMSTATUSICON, IcqGetXStatusIcon);
+ ICQCreateServiceFunction(PS_ICQ_REQUESTCUSTOMSTATUS, IcqRequestXStatusDetails);
+
+ {
+ char pszServiceName[MAX_PATH + 32];
+
+ strcpy(pszServiceName, gpszICQProtoName); strcat(pszServiceName, ME_ICQ_STATUSMSGREQ);
+ hsmsgrequest = CreateHookableEvent(pszServiceName);
+
+ strcpy(pszServiceName, gpszICQProtoName); strcat(pszServiceName, ME_ICQ_CUSTOMSTATUS_EXTRAICON_CHANGED);
+ hxstatusiconchanged = CreateHookableEvent(pszServiceName);
+ }
+
+ InitDirectConns();
+ InitOscarFileTransfer();
+ InitServerLists();
+ icq_InitInfoUpdate();
+
+ // Initialize charset conversion routines
+ InitI18N();
+
+ UpdateGlobalSettings();
+
+ gnCurrentStatus = ID_STATUS_OFFLINE;
+
+ ICQCreateServiceFunction(MS_REQ_AUTH, icq_RequestAuthorization);
+ ICQCreateServiceFunction(MS_GRANT_AUTH, IcqGrantAuthorization);
+ ICQCreateServiceFunction(MS_REVOKE_AUTH, IcqRevokeAuthorization);
+
+ ICQCreateServiceFunction(MS_XSTATUS_SHOWDETAILS, IcqShowXStatusDetails);
+
+ // This must be here - the events are called too early, WTF?
+ InitXStatusEvents();
+
+ return 0;
+}
+
+
+
+int __declspec(dllexport) Unload(void)
+{
+ if (gbXStatusEnabled) gbXStatusEnabled = 10; // block clist changing
+
+ UninitXStatusEvents();
+
+ UninitServerLists();
+ UninitOscarFileTransfer();
+ UninitDirectConns();
+
+ NetLib_SafeCloseHandle(&ghDirectNetlibUser, FALSE);
+ NetLib_SafeCloseHandle(&ghServerNetlibUser, FALSE);
+ UninitRates();
+ UninitCookies();
+ UninitCache();
+ DeleteCriticalSection(&modeMsgsMutex);
+ DeleteCriticalSection(&localSeqMutex);
+ DeleteCriticalSection(&connectionHandleMutex);
+ SAFE_FREE(&modeMsgs.szAway);
+ SAFE_FREE(&modeMsgs.szNa);
+ SAFE_FREE(&modeMsgs.szOccupied);
+ SAFE_FREE(&modeMsgs.szDnd);
+ SAFE_FREE(&modeMsgs.szFfc);
+
+ if (hHookIconsChanged)
+ UnhookEvent(hHookIconsChanged);
+
+ if (hHookUserInfoInit)
+ UnhookEvent(hHookUserInfoInit);
+
+ if (hHookOptionInit)
+ UnhookEvent(hHookOptionInit);
+
+ if (hsmsgrequest)
+ DestroyHookableEvent(hsmsgrequest);
+
+ if (hxstatusiconchanged)
+ DestroyHookableEvent(hxstatusiconchanged);
+
+ if (hHookUserMenu)
+ UnhookEvent(hHookUserMenu);
+
+ if (hHookIdleEvent)
+ UnhookEvent(hHookIdleEvent);
+
+ return 0;
+}
+
+
+
+static int OnSystemModulesLoaded(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBUSER nlu = {0};
+ char pszP2PName[MAX_PATH+3];
+ char pszGroupsName[MAX_PATH+10];
+ char pszSrvGroupsName[MAX_PATH+10];
+ char szBuffer[MAX_PATH+64];
+ char* modules[5] = {0,0,0,0,0};
+
+ strcpy(pszP2PName, gpszICQProtoName);
+ strcat(pszP2PName, "P2P");
+
+ strcpy(pszGroupsName, gpszICQProtoName);
+ strcat(pszGroupsName, "Groups");
+ strcpy(pszSrvGroupsName, gpszICQProtoName);
+ strcat(pszSrvGroupsName, "SrvGroups");
+ modules[0] = gpszICQProtoName;
+ modules[1] = pszP2PName;
+ modules[2] = pszGroupsName;
+ modules[3] = pszSrvGroupsName;
+ CallService("DBEditorpp/RegisterModule",(WPARAM)modules,(LPARAM)4);
+
+
+ null_snprintf(szBuffer, sizeof szBuffer, ICQTranslate("%s server connection"), gpszICQProtoName);
+ nlu.cbSize = sizeof(nlu);
+ nlu.flags = NUF_OUTGOING | NUF_HTTPGATEWAY;
+ nlu.szDescriptiveName = szBuffer;
+ nlu.szSettingsModule = gpszICQProtoName;
+ 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;
+
+ ghServerNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu);
+
+ null_snprintf(szBuffer, sizeof szBuffer, ICQTranslate("%s client-to-client connections"), gpszICQProtoName);
+ nlu.flags = NUF_OUTGOING | NUF_INCOMING;
+ nlu.szDescriptiveName = szBuffer;
+ nlu.szSettingsModule = pszP2PName;
+ nlu.minIncomingPorts = 1;
+ ghDirectNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu);
+
+ hHookOptionInit = HookEvent(ME_OPT_INITIALISE, IcqOptInit);
+ hHookUserInfoInit = HookEvent(ME_USERINFO_INITIALISE, OnDetailsInit);
+ hHookUserMenu = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, icq_PrebuildContactMenu);
+ hHookIdleEvent = HookEvent(ME_IDLE_CHANGED, IcqIdleChanged);
+
+ // Init extra optional modules
+ InitPopUps();
+ InitIconLib();
+
+ hHookIconsChanged = IconLibHookIconsChanged(IconLibIconsChanged);
+
+ {
+ char str[MAX_PATH], proto[MAX_PATH];
+
+ ICQTranslateUtfStatic(gpszICQProtoName, proto);
+
+ IconLibDefine(ICQTranslateUtfStatic("Request authorization", str), proto, "req_auth", LoadImage(hInst,MAKEINTRESOURCE(IDI_AUTH_ASK),IMAGE_ICON,0,0,LR_SHARED), NULL, 0);
+ IconLibDefine(ICQTranslateUtfStatic("Grant authorization", str), proto, "grant_auth", LoadImage(hInst,MAKEINTRESOURCE(IDI_AUTH_GRANT),IMAGE_ICON,0,0,LR_SHARED), NULL, 0);
+ IconLibDefine(ICQTranslateUtfStatic("Revoke authorization", str), proto, "revoke_auth", LoadImage(hInst,MAKEINTRESOURCE(IDI_AUTH_REVOKE),IMAGE_ICON,0,0,LR_SHARED), NULL, 0);
+ }
+
+ // Initialize IconLib icons
+ InitXStatusIcons();
+ InitXStatusEvents();
+ InitXStatusItems(FALSE);
+
+ {
+ CLISTMENUITEM mi;
+ char pszServiceName[MAX_PATH+30];
+
+ strcpy(pszServiceName, gpszICQProtoName);
+ strcat(pszServiceName, MS_REQ_AUTH);
+
+ ZeroMemory(&mi, sizeof(mi));
+ mi.cbSize = sizeof(mi);
+ mi.position = 1000030000;
+ mi.flags = 0;
+ mi.hIcon = IconLibProcess(LoadImage(hInst,MAKEINTRESOURCE(IDI_AUTH_ASK),IMAGE_ICON,0,0,LR_SHARED), "req_auth");
+ mi.pszContactOwner = gpszICQProtoName;
+ mi.pszName = ICQTranslate("Request authorization");
+ mi.pszService = pszServiceName;
+ hUserMenuAuth = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM)&mi);
+
+ strcpy(pszServiceName, gpszICQProtoName);
+ strcat(pszServiceName, MS_GRANT_AUTH);
+
+ mi.position = 1000029999;
+ mi.hIcon = IconLibProcess(LoadImage(hInst,MAKEINTRESOURCE(IDI_AUTH_GRANT),IMAGE_ICON,0,0,LR_SHARED), "grant_auth");
+ mi.pszName = ICQTranslate("Grant authorization");
+ hUserMenuGrant = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM)&mi);
+
+ strcpy(pszServiceName, gpszICQProtoName);
+ strcat(pszServiceName, MS_REVOKE_AUTH);
+
+ mi.position = 1000029998;
+ mi.hIcon = IconLibProcess(LoadImage(hInst,MAKEINTRESOURCE(IDI_AUTH_REVOKE),IMAGE_ICON,0,0,LR_SHARED), "revoke_auth");
+ mi.pszName = ICQTranslate("Revoke authorization");
+ hUserMenuRevoke = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM)&mi);
+
+ strcpy(pszServiceName, gpszICQProtoName);
+ strcat(pszServiceName, MS_XSTATUS_SHOWDETAILS);
+
+ mi.position = -2000004999;
+ mi.hIcon = NULL; // dynamically updated
+ mi.pszName = ICQTranslate("Show custom status details");
+ mi.flags=CMIF_NOTOFFLINE;
+ hUserMenuXStatus = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM)&mi);
+ }
+
+ {
+ // TODO: add beta builds support to devel builds :)
+
+ CallService(MS_UPDATE_REGISTERFL, 1683, (WPARAM)&pluginInfo);
+ }
+
+ return 0;
+}
+
+
+
+static int OnSystemPreShutdown(WPARAM wParam,LPARAM lParam)
+{ // all threads should be terminated here
+ if (hServerConn)
+ {
+ icq_sendCloseConnection();
+
+ icq_serverDisconnect(TRUE);
+ }
+
+ icq_InfoUpdateCleanup();
+
+ return 0;
+}
+
+
+
+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);
+}
+
+
+
+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);
+}
+
+
+
+static int icq_PrebuildContactMenu(WPARAM wParam, LPARAM lParam)
+{
+ BYTE bXStatus;
+
+ CListShowMenuItem(hUserMenuAuth, ICQGetContactSettingByte((HANDLE)wParam, "Auth", 0));
+ CListShowMenuItem(hUserMenuGrant, ICQGetContactSettingByte((HANDLE)wParam, "Grant", 0));
+ CListShowMenuItem(hUserMenuRevoke, (BYTE)(ICQGetContactSettingByte(NULL, "PrivacyItems", 0) && !ICQGetContactSettingByte((HANDLE)wParam, "Grant", 0)));
+
+ bXStatus = ICQGetContactSettingByte((HANDLE)wParam, DBSETTING_XSTATUSID, 0);
+ CListShowMenuItem(hUserMenuXStatus, (BYTE)(bHideXStatusUI ? 0 : bXStatus));
+ if (bXStatus && !bHideXStatusUI)
+ {
+ HICON iXStatus = GetXStatusIcon(bXStatus);
+ CListSetMenuItemIcon(hUserMenuXStatus, iXStatus);
+
+ if (iXStatus && !IconLibInstalled())
+ DestroyIcon(iXStatus); // release icon
+ }
+
+ return 0;
+}
+
+
+
+static int IconLibIconsChanged(WPARAM wParam, LPARAM lParam)
+{
+ CListSetMenuItemIcon(hUserMenuAuth, IconLibProcess(LoadImage(hInst,MAKEINTRESOURCE(IDI_AUTH_ASK),IMAGE_ICON,0,0,LR_SHARED), "req_auth"));
+ CListSetMenuItemIcon(hUserMenuGrant, IconLibProcess(LoadImage(hInst,MAKEINTRESOURCE(IDI_AUTH_GRANT),IMAGE_ICON,0,0,LR_SHARED), "grant_auth"));
+ CListSetMenuItemIcon(hUserMenuRevoke, IconLibProcess(LoadImage(hInst,MAKEINTRESOURCE(IDI_AUTH_REVOKE),IMAGE_ICON,0,0,LR_SHARED), "revoke_auth"));
+
+ ChangedIconsXStatus();
+
+ return 0;
+}
+
+
+
+void UpdateGlobalSettings()
+{
+ NETLIBUSERSETTINGS nlus = {0};
+
+ nlus.cbSize = sizeof(NETLIBUSERSETTINGS);
+ if (CallService(MS_NETLIB_GETUSERSETTINGS, (WPARAM)ghServerNetlibUser, (LPARAM)&nlus))
+ {
+ if (nlus.useProxy && nlus.proxyType == PROXYTYPE_HTTP)
+ gbGatewayMode = 1;
+ else
+ gbGatewayMode = 0;
+ }
+ else
+ gbGatewayMode = 0;
+
+ gbSecureLogin = ICQGetContactSettingByte(NULL, "SecureLogin", DEFAULT_SECURE_LOGIN);
+ gbAimEnabled = ICQGetContactSettingByte(NULL, "AimEnabled", DEFAULT_AIM_ENABLED);
+ gbUtfEnabled = ICQGetContactSettingByte(NULL, "UtfEnabled", DEFAULT_UTF_ENABLED);
+ gwAnsiCodepage = ICQGetContactSettingWord(NULL, "AnsiCodePage", DEFAULT_ANSI_CODEPAGE);
+ gbDCMsgEnabled = ICQGetContactSettingByte(NULL, "DirectMessaging", DEFAULT_DCMSG_ENABLED);
+ gbTempVisListEnabled = ICQGetContactSettingByte(NULL, "TempVisListEnabled", DEFAULT_TEMPVIS_ENABLED);
+ gbSsiEnabled = ICQGetContactSettingByte(NULL, "UseServerCList", DEFAULT_SS_ENABLED);
+ gbAvatarsEnabled = ICQGetContactSettingByte(NULL, "AvatarsEnabled", DEFAULT_AVATARS_ENABLED);
+ gbXStatusEnabled = ICQGetContactSettingByte(NULL, "XStatusEnabled", DEFAULT_XSTATUS_ENABLED);
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/init.h b/miranda-wine/protocols/IcqOscarJ/init.h
new file mode 100644
index 0000000..9b601ac
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/init.h
@@ -0,0 +1,50 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/init.h,v $
+// Revision : $Revision: 3663 $
+// Last change on : $Date: 2006-08-31 00:18:59 +0400 (Чтв, 31 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+
+void UpdateGlobalSettings(void);
+
+
+// Debug defines
+#define DBG_CAPCH2
+#define DBG_CAPUTF
+#undef DBG_CAPRTF
+#define DBG_CAPMTN
+#define DBG_CAPXTRAZ
+#undef DBG_CAPXTRAZ_MUC
+#define DBG_NEWCAPS
+#define DBG_OSCARFT
+
diff --git a/miranda-wine/protocols/IcqOscarJ/log.c b/miranda-wine/protocols/IcqOscarJ/log.c
new file mode 100644
index 0000000..d0bd070
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/log.c
@@ -0,0 +1,158 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/log.c,v $
+// Revision : $Revision: 3316 $
+// Last change on : $Date: 2006-07-12 20:26:25 +0400 (Срд, 12 Июл 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+static const char *szLevelDescr[] = {"ICQ Note", "ICQ Warning", "ICQ Error", "ICQ Fatal"};
+
+typedef struct {
+ char *szMsg;
+ char *szTitle;
+} LogMessageInfo;
+
+static BOOL bErrorVisible = FALSE;
+
+static void __cdecl icq_LogMessageThread(void* arg)
+{
+ LogMessageInfo *err = (LogMessageInfo*)arg;
+
+ if (!err) return;
+ bErrorVisible = TRUE;
+ if (err->szMsg&&err->szTitle)
+ MessageBoxUtf(NULL, err->szMsg, err->szTitle, MB_OK);
+ SAFE_FREE(&err->szMsg);
+ SAFE_FREE(&err->szTitle);
+ SAFE_FREE(&err);
+ bErrorVisible = FALSE;
+}
+
+
+
+void icq_LogMessage(int level, const char *szMsg)
+{
+ int displayLevel;
+
+ NetLog_Server("%s", szMsg);
+
+ displayLevel = ICQGetContactSettingByte(NULL, "ShowLogLevel", LOG_WARNING);
+ if (level >= displayLevel)
+ {
+ LogMessageInfo *lmi;
+
+ if (ICQGetContactSettingByte(NULL, "PopupsLogEnabled", DEFAULT_LOG_POPUPS_ENABLED))
+ {
+ if (!ShowPopUpMsg(NULL, szLevelDescr[level], szMsg, (BYTE)level))
+ return; // Popup showed successfuly
+ }
+ if (!bErrorVisible || !ICQGetContactSettingByte(NULL, "IgnoreMultiErrorBox", 0))
+ { // error not shown or allowed multi - show messagebox
+ lmi = (LogMessageInfo*)SAFE_MALLOC(sizeof(LogMessageInfo));
+ lmi->szMsg = ICQTranslateUtf(szMsg);
+ lmi->szTitle = ICQTranslateUtf(szLevelDescr[level]);
+ forkthread(icq_LogMessageThread, 0, lmi);
+ }
+ }
+}
+
+
+
+void icq_LogUsingErrorCode(int level, DWORD dwError, const char *szMsg)
+{
+ char szBuf[1024];
+ char str[1024];
+ char str2[64];
+ char szErrorMsg[256];
+ char* pszErrorMsg;
+ char* pszErrorMsgUtf = NULL;
+
+
+ switch(dwError)
+ {
+ case ERROR_TIMEOUT:
+ case WSAETIMEDOUT:
+ pszErrorMsg = "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 = "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 = "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 = "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 = "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 = "The server to which you are trying to connect does not exist. Check your spelling in M->Options->Network->ICQ.";
+ break;
+
+ default:
+ if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0, szErrorMsg, sizeof(szErrorMsg), NULL))
+ pszErrorMsg = szErrorMsg;
+ else
+ pszErrorMsg = "";
+ break;
+ }
+ utf8_encode(pszErrorMsg, &pszErrorMsgUtf);
+
+ null_snprintf(szBuf, sizeof(szBuf), "%s%s%s (%s %d)", szMsg?ICQTranslateUtfStatic(szMsg, str):"", szMsg?"\r\n\r\n":"", pszErrorMsgUtf, ICQTranslateUtfStatic("error", str2), dwError);
+ icq_LogMessage(level, szBuf);
+
+ SAFE_FREE(&pszErrorMsgUtf);
+}
+
+
+
+void icq_LogFatalParam(const char* szMsg, WORD wError)
+{
+ char str[MAX_PATH];
+ char buf[MAX_PATH];
+
+ null_snprintf(buf, MAX_PATH, ICQTranslateUtfStatic(szMsg, str), wError);
+ icq_LogMessage(LOG_FATAL, buf);
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/log.h b/miranda-wine/protocols/IcqOscarJ/log.h
new file mode 100644
index 0000000..e10e1bc
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/log.h
@@ -0,0 +1,51 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/log.h,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// 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.
+
+/*---------* Functions *---------------*/
+
+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);
+
+#endif /* __LOG_H */
diff --git a/miranda-wine/protocols/IcqOscarJ/m_cluiframes.h b/miranda-wine/protocols/IcqOscarJ/m_cluiframes.h
new file mode 100644
index 0000000..ebb89ef
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/m_cluiframes.h
@@ -0,0 +1,255 @@
+/*
+Miranda ICQ: the free icq client for MS Windows
+Copyright (C) 2000-2 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 hdrstop
+
+////////////////////////////////////
+//Extra Image Column Support +0.5.0.0
+
+//Extra columns type.
+//column arranged in this way
+//
+// [statusicon] ContactName [ADV1][ADV2][SMS][EMAIL][PROTO]
+//
+#define EXTRA_ICON_EMAIL 1
+#define EXTRA_ICON_PROTO 2
+#define EXTRA_ICON_SMS 3
+#define EXTRA_ICON_ADV1 4
+#define EXTRA_ICON_ADV2 5
+
+typedef struct
+{
+int cbSize; //must be sizeof(IconExtraColumn)
+int ColumnType;
+HANDLE hImage; //return value from MS_CLIST_EXTRA_ADD_ICON
+}IconExtraColumn,*pIconExtraColumn;
+
+
+//Set icon for contact at needed column
+//wparam=hContact
+//lparam=pIconExtraColumn
+//return 0 on success,-1 on failure
+//
+//See above for supported columns
+#define MS_CLIST_EXTRA_SET_ICON "CListFrames/SetIconForExraColumn"
+
+//Adding icon to extra image list.
+//Call this in ME_CLIST_EXTRA_LIST_REBUILD event
+//
+//wparam=hIcon
+//lparam=0
+//return hImage on success,-1 on failure
+#define MS_CLIST_EXTRA_ADD_ICON "CListFrames/AddIconToExtraImageList"
+
+
+
+#define ME_CLIST_EXTRA_LIST_REBUILD "CListFrames/OnExtraListRebuild"
+
+//called with wparam=hContact
+#define ME_CLIST_EXTRA_IMAGE_APPLY "CListFrames/OnExtraImageApply"
+
+
+///////////////////////////////////
+
+
+
+
+//
+//want show tooltip for statusbar
+//wparam=(char *)protocolname
+//lparam=0
+#define ME_CLIST_FRAMES_SB_SHOW_TOOLTIP "CListFrames/StatusBarShowToolTip"
+
+
+//want hide tooltip for statusbar
+//wparam=lparam=0
+
+#define ME_CLIST_FRAMES_SB_HIDE_TOOLTIP "CListFrames/StatusBarHideToolTip"
+
+//
+
+
+
+//adds a frame window
+//wParam=(CLISTFrame*)
+//lParam=0
+//returns an integer, the frame id.
+typedef struct tagCLISTFrame {
+ DWORD cbSize;
+ HWND hWnd ;
+ HICON hIcon;
+ int align; //al flags below
+ int height;
+ int Flags; //F_flags below
+ char *name; //frame window name,will be shown in menu
+ char *TBname; //titlebar caption
+ //COLORREF TBBackColour; //titlebar background colour
+} CLISTFrame;
+#define F_VISIBLE 1 //Frame visible
+#define F_SHOWTB 2 //Show TitleBar
+#define F_UNCOLLAPSED 4 //UnCollapse frame
+#define F_LOCKED 8 //Lock Frame
+#define F_NOBORDER 16 //Dont apply WS_BORDER style for window
+#define F_SHOWTBTIP 32 //Show titlebar tooltip
+
+
+// frame alignment
+#define alTop 0x00000001
+#define alBottom 0x00000002
+#define alClient 0x00000004 //only one alClient frame
+#define MS_CLIST_FRAMES_ADDFRAME "CListFrames/AddFrame"
+
+#define MS_CLIST_FRAMES_REMOVEFRAME "CListFrames/RemoveFrame"
+
+//shows all frames
+//wParam=lParam=0
+//returns 0 on success, -1 on failure
+#define MS_CLIST_FRAMES_SHOWALLFRAMES "CListFrames/ShowALLFrames"
+
+//shows the titlebars of all frames
+//wParam=lParam=0
+//returns 0 on success, -1 on failure
+#define MS_CLIST_FRAMES_SHOWALLFRAMESTB "CListFrames/ShowALLFramesTB"
+
+//hides the titlebars of all frames
+//wParam=lParam=0
+//returns 0 on success, -1 on failure
+#define MS_CLIST_FRAMES_HIDEALLFRAMESTB "CListFrames/HideALLFramesTB"
+
+//shows the frame if it is hidden,
+//hides the frame if it is shown
+//wParam=FrameId
+//lParam=0
+//returns 0 on success, -1 on failure
+#define MS_CLIST_FRAMES_SHFRAME "CListFrames/SHFrame"
+
+//shows the frame titlebar if it is hidden,
+//hides the frame titlebar if it is shown
+//wParam=FrameId
+//lParam=0
+//returns 0 on success, -1 on failure
+#define MS_CLIST_FRAMES_SHFRAMETITLEBAR "CListFrame/SHFrameTitleBar"
+
+//locks the frame if it is unlocked,
+//unlock the frame if it is locked
+//wParam=FrameId
+//lParam=0
+//returns 0 on success, -1 on failure
+#define MS_CLIST_FRAMES_ULFRAME "CListFrame/ULFrame"
+
+//collapses the frame if it is uncollapsed,
+//uncollapses the frame if it is collapsed
+//wParam=FrameId
+//lParam=0
+//returns 0 on success, -1 on failure
+#define MS_CLIST_FRAMES_UCOLLFRAME "CListFrame/UCOLLFrame"
+
+//trigger border flags
+//wparam=frameid
+//lparam=0
+#define MS_CLIST_FRAMES_SETUNBORDER "CListFrame/SetUnBorder"
+
+//redraws the frame
+//wParam=FrameId, -1 for all frames
+//lparam=FU_flags
+//returns a pointer to option, -1 on failure
+#define FU_TBREDRAW 1 //redraw titlebar
+#define FU_FMREDRAW 2 //redraw Frame
+#define FU_FMPOS 4 //update Frame position
+#define MS_CLIST_FRAMES_UPDATEFRAME "CListFrame/UpdateFrame"
+
+//gets the frame options
+//(HIWORD)wParam=FrameId
+//(LOWORD)wParam=FO_flag
+//lParam=0
+//returns a pointer to option, -1 on failure
+#define FO_FLAGS 0x0001 //return set of F_VISIBLE,F_SHOWTB,F_UNCOLLAPSED,F_LOCKED,F_NOBORDER,F_SHOWTBTIP
+#define FO_NAME 0x0002 //Change name
+#define FO_TBNAME 0x0003 //Change TB caption
+#define FO_TBSTYLE 0x0004 //Change TB style
+#define FO_TBEXSTYLE 0x0005 //Change TB exstyle
+#define FO_ICON 0x0006 //Change icon
+#define FO_HEIGHT 0x0007 //Change height
+#define FO_ALIGN 0x0008 //Change align
+#define FO_TBTIPNAME 0x0009 //Change TB tooltip
+#define FO_FLOATING 0x000a //Change floating mode
+
+#define MS_CLIST_FRAMES_GETFRAMEOPTIONS "CListFrame/GetFrameOptions"
+
+//sets the frame options
+//(HIWORLD)wParam=FrameId
+//(LOWORD)wParam=FO_flag
+//lParam=value
+//returns 0 on success, -1 on failure
+#define MS_CLIST_FRAMES_SETFRAMEOPTIONS "CListFrame/SetFrameOptions"
+
+
+//menu stuff
+
+//add a new item to the context frame menu
+//wParam=0
+//lParam=(LPARAM)(CLISTMENUITEM*)&mi
+//returns a handle to the new item
+//popupposition=frameid
+//contactowner=advanced parameter
+#define MS_CLIST_ADDCONTEXTFRAMEMENUITEM "CList/AddContextFrameMenuItem"
+
+//remove a item from context frame menu
+//wParam=hMenuItem returned by MS_CLIST_ADDCONTACTMENUITEM
+//lParam=0
+//returns 0 on success, nonzero on failure
+#define MS_CLIST_REMOVECONTEXTFRAMEMENUITEM "CList/RemoveContextFrameMenuItem"
+
+//builds the context menu for a frame
+//wparam=frameid
+//lParam=0
+//returns a HMENU on success, or NULL on failure
+#define MS_CLIST_MENUBUILDFRAMECONTEXT "CList/BuildContextFrameMenu"
+
+/*
+//the frame menu is about to be built
+wparam=frameid
+lparam=
+-1 for build from titlebar,
+ use
+ MS_CLIST_ADDCONTEXTFRAMEMENUITEM
+ MS_CLIST_REMOVECONTEXTFRAMEMENUITEM
+
+>0 for build in main menu,
+must be popupname=lparam to place your items in right popup of main menu.
+ use
+ MS_CLIST_ADDMAINMENUITEM
+ MS_CLIST_REMOVEMAINMENUITEM
+
+*/
+#define ME_CLIST_PREBUILDFRAMEMENU "CList/PreBuildFrameMenu"
+
+//needed by cluiframes module to add frames menu to main menu.
+//it just calls NotifyEventHooks(hPreBuildFrameMenuEvent,wParam,lParam);
+#define MS_CLIST_FRAMEMENUNOTIFY "CList/ContextFrameMenuNotify"
+
+
+//#define FONTID_STATUS 8
+//#define FONTID_FRAMETITLE 9
+
+//#undef FONTID_MAX
+//#define FONTID_MAX 9
+
+#define ME_CLIST_PREBUILDSTATUSMENU "CList/PreBuildStatusMenu"
+#define MS_CLIST_ADDSTATUSMENUITEM "CList/AddStatusMenuItem"
diff --git a/miranda-wine/protocols/IcqOscarJ/m_icolib.h b/miranda-wine/protocols/IcqOscarJ/m_icolib.h
new file mode 100644
index 0000000..a31abe2
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/m_icolib.h
@@ -0,0 +1,75 @@
+// ---------------------------------------------------------------------------80
+// Icons Library Manager plugin for Miranda Instant Messenger
+// __________________________________________________________
+//
+// Copyright © 2005 Denis Stanishevskiy // StDenis
+// Copyright © 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.
+//
+// -----------------------------------------------------------------------------
+
+#define SKINICONDESC_SIZE sizeof(SKINICONDESC)
+#define SKINICONDESC_SIZE_V1 0x18
+#define SKINICONDESC_SIZE_V2 0x1C
+#define SKINICONDESC_SIZE_V3 0x24
+
+typedef struct {
+ int cbSize;
+ union {
+ char *pszSection; // section name used to group icons
+ TCHAR *ptszSection;
+ wchar_t *pwszSection;
+ };
+ union {
+ char *pszDescription; // description for options dialog
+ TCHAR *ptszDescription;
+ wchar_t *pwszDescription;
+ };
+ char *pszName; // name to refer to icon when playing and in db
+ char *pszDefaultFile; // default icon file to use
+ int iDefaultIndex; // index of icon in default file
+ HICON hDefaultIcon; // handle to default icon
+ int cx,cy; // dimensions of icon
+ int flags;
+} SKINICONDESC;
+
+#define SIDF_UNICODE 0x100 // Section and Description are in UCS-2
+
+#if defined(_UNICODE)
+ #define SIDF_TCHAR SIDF_UNICODE
+#else
+ #define SIDF_TCHAR 0
+#endif
+
+//
+// Add a icon into options UI
+//
+// wParam = (WPARAM)0
+// lParam = (LPARAM)(SKINICONDESC*)sid;
+//
+#define MS_SKIN2_ADDICON "Skin2/Icons/AddIcon"
+
+//
+// Retrieve HICON with name specified in lParam
+// Returned HICON SHOULDN'T be destroyed, it is managed by IcoLib
+//
+
+#define MS_SKIN2_GETICON "Skin2/Icons/GetIcon"
+
+//
+// Icons change notification
+//
+#define ME_SKIN2_ICONSCHANGED "Skin2/IconsChanged"
diff --git a/miranda-wine/protocols/IcqOscarJ/m_icq.h b/miranda-wine/protocols/IcqOscarJ/m_icq.h
new file mode 100644
index 0000000..e0b94da
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/m_icq.h
@@ -0,0 +1,294 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/m_icq.h,v $
+// Revision : $Revision: 3484 $
+// Last change on : $Date: 2006-08-13 19:51:44 +0400 (Ð’Ñк, 13 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+
+
+// Note: In v0.3 the part before "/Servicename" is dynamic. It will be the name of the protocol.
+// Example: If the plugin was loaded from ICQ.dll, the service name is "ICQ/Servicename", and if
+// the dll was Icq2.dll, the service name will be "Icq2/Servicename". This behaviour is temporary
+// until proper multiaccounts are implemented.
+
+
+//start a search of all ICQ users by e-mail
+//wParam=0
+//lParam=(LPARAM)(const char*)email
+//returns a handle to the search on success, NULL on failure
+//Results are returned using the same scheme documented in PSS_BASICSEARCH
+//**DEPRECATED** in favour of PS_SEARCHBYEMAIL
+typedef struct { //extended search result structure, used for all searches
+ PROTOSEARCHRESULT hdr;
+ DWORD uin;
+ BYTE auth;
+ char* uid;
+} ICQSEARCHRESULT;
+#define MS_ICQ_SEARCHBYEMAIL "/SearchByEmail"
+
+//start a search of all ICQ users by details
+//wParam=0
+//lParam=(LPARAM)(ICQDETAILSSEARCH*)&ids
+//returns a handle to the search on success, NULL on failure
+//Results are returned using the same scheme documented in PSS_BASICSEARCH
+//**DEPRECATED** in favour of PS_SEARCHBYNAME
+typedef struct {
+ char *nick;
+ char *firstName;
+ char *lastName;
+} ICQDETAILSSEARCH;
+#define MS_ICQ_SEARCHBYDETAILS "/SearchByDetails"
+
+// Request authorization
+// wParam=(WPARAM)hContact
+#define MS_REQ_AUTH "/ReqAuth"
+
+// Grant authorization
+// wParam=(WPARAM)hContact;
+#define MS_GRANT_AUTH "/GrantAuth"
+
+// Revoke authorization
+// wParam=(WPARAM)hContact
+#define MS_REVOKE_AUTH "/RevokeAuth"
+
+// Display XStatus detail (internal use only)
+// wParam=(WPARAM)hContact;
+#define MS_XSTATUS_SHOWDETAILS "/ShowXStatusDetails"
+
+//Send an SMS via the ICQ network
+//wParam=(WPARAM)(const char*)szPhoneNumber
+//lParam=(LPARAM)(const char*)szMessage
+//Returns a HANDLE to the send on success, or NULL on failure
+//szPhoneNumber should be the full number with international code and preceeded
+//by a +
+
+//When the server acks the send, an ack will be broadcast:
+// type=ICQACKTYPE_SMS, result=ACKRESULT_SENTREQUEST, lParam=(LPARAM)(char*)szInfo
+//At this point the message is queued to be delivered. szInfo contains the raw
+//XML data of the ack. Here's what I got when I tried:
+//"<sms_response><source>airbornww.com</source><deliverable>Yes</deliverable><network>BT Cellnet, United Kingdom</network><message_id>[my uin]-1-1955988055-[destination phone#, without +]</message_id><messages_left>0</messages_left></sms_response>\r\n"
+
+//Now the hProcess has been deleted. The only way to track which receipt
+//corresponds with which response is to parse the <message_id> field.
+
+//At a (possibly much) later time the SMS will have been delivered. An ack will
+//be broadcast:
+// type=ICQACKTYPE_SMS, result=ACKRESULT_SUCCESS, hProcess=NULL, lParam=(LPARAM)(char*)szInfo
+//Note that the result will always be success even if the send failed, just to
+//save needing to have an attempt at an XML parser in the ICQ module.
+//Here's the szInfo for a success:
+//"<sms_delivery_receipt><message_id>[my uin]-1--1461632229-[dest phone#, without +]</message_id><destination>[dest phone#, without +]</destination><delivered>Yes</delivered><text>[first 20 bytes of message]</text><submition_time>Tue, 30 Oct 2001 22:35:16 GMT</submition_time><delivery_time>Tue, 30 Oct 2001 22:34:00 GMT</delivery_time></sms_delivery_receipt>"
+//And here's a failure:
+//"<sms_delivery_receipt><message_id>[my uin]-1-1955988055-[destination phone#, without leading +]</message_id><destination>[destination phone#, without leading +]</destination><delivered>No</delivered><submition_time>Tue, 23 Oct 2001 23:17:02 GMT</submition_time><error_code>999999</error_code><error><id>15</id><params><param>0</param><param>Multiple message submittion failed</param></params></error></sms_delivery_receipt>"
+
+//SMSes received from phones come through this same ack, again to avoid having
+//an XML parser in the protocol module. Here's one I got:
+//"<sms_message><source>MTN</source><destination_UIN>[UIN of recipient, ie this account]</destination_UIN><sender>[sending phone number, without +]</sender><senders_network>[contains one space, because I sent from ICQ]</senders_network><text>[body of the message]</text><time>Fri, 16 Nov 2001 03:12:33 GMT</time></sms_message>"
+#define ICQACKTYPE_SMS 1001
+#define ICQEVENTTYPE_SMS 2001 //database event type
+#define MS_ICQ_SENDSMS "/SendSMS"
+
+//e-mail express
+//db event added to NULL contact
+//blob format is:
+//ASCIIZ text, usually of the form "Subject: %s\r\n%s"
+//ASCIIZ from name
+//ASCIIZ from e-mail
+#define ICQEVENTTYPE_EMAILEXPRESS 2002 //database event type
+
+//www pager
+//db event added to NULL contact
+//blob format is:
+//ASCIIZ text, usually "Sender IP: xxx.xxx.xxx.xxx\r\n%s"
+//ASCIIZ from name
+//ASCIIZ from e-mail
+#define ICQEVENTTYPE_WEBPAGER 2003 //database event type
+
+//for server-side lists, used internally only
+//hProcess=dwSequence
+//lParam=server's error code, 0 for success
+#define ICQACKTYPE_SERVERCLIST 1003
+
+//for rate warning distribution (mainly upload dlg)
+//hProcess=Rate class ID
+//lParam=server's status code
+#define ICQACKTYPE_RATEWARNING 1004
+
+//received Xtraz Notify response
+//hProcess=dwSequence
+//lParam=contents of RES node
+#define ICQACKTYPE_XTRAZNOTIFY_RESPONSE 1005
+
+//received Custom Status details response
+//hProcess=dwSequence
+//lParam=0
+#define ICQACKTYPE_XSTATUS_RESPONSE 1006
+
+
+//Update user details on server
+//Permited operation types:
+#define CIXT_BASIC 0x0001
+#define CIXT_MORE 0x0002
+#define CIXT_WORK 0x0004
+#define CIXT_CONTACT 0x0008
+#define CIXT_LOCATION 0x0010
+#define CIXT_BACKGROUND 0x0020
+#define CIXT_FULL 0x003F
+//wParam=operationType
+#define PS_CHANGEINFOEX "/ChangeInfoEx"
+
+//Change nickname in White pages
+//lParam=(LPARAM)(const char*)szNewNickName
+#define PS_SET_NICKNAME "/SetNickname"
+
+//Set password for current session
+//lParam=(LPARAM)(const char*)szPassword
+#define PS_ICQ_SETPASSWORD "/SetPassword"
+
+//miranda/icqoscar/statusmsgreq event
+//called when our status message is requested
+//wParam=(BYTE)msgType
+//lParam=(DWORD)uin
+//msgType is one of the ICQ_MSGTYPE_GET###MSG constants in icq_constants.h
+//uin is the UIN of the contact requesting our status message
+#define ME_ICQ_STATUSMSGREQ "/StatusMsgReq"
+
+
+//set owner avatar
+//wParam=0
+//lParam=(const char *)Avatar file name
+//return=0 for success
+#define PS_ICQ_SETMYAVATAR "/SetMyAvatar"
+
+//get current owner avatar
+//wParam=(char *)Buffer to file name
+//lParam=(int)Buffer size
+//return=0 for success
+#define PS_ICQ_GETMYAVATAR "/GetMyAvatar"
+
+//get size limit for avatar image
+//wParam=(int *)max width of avatar - will be set
+//lParam=(int *)max height of avatar - will be set
+//return=0 for success
+#define PS_ICQ_GETMYAVATARMAXSIZE "/GetMyAvatarMaxSize"
+
+//check if image format supported for avatars
+//wParam = 0
+//lParam = PA_FORMAT_* // avatar format
+//return = 1 (supported) or 0 (not supported)
+#define PS_ICQ_ISAVATARFORMATSUPPORTED "/IsAvatarFormatSupported"
+
+
+/* Custom Status helper API *
+ - to set custom status message & title use PS_ICQ_GETCUSTOMSTATUS to obtain
+ DB settings and write values to them (UTF-8 strings best). (obsolete)
+ - use PS_ICQ_GETCUSTOMSTATUSEX and PS_ICQ_SETCUSTOMSTATUSEX for controling Custom Status
+ - custom messages for each user supported - ME_ICQ_STATUSMSGREQ with type MTYPE_SCRIPT_NOTIFY
+ */
+#define CSSF_MASK_STATUS 0x0001 // status member valid for set/get
+#define CSSF_MASK_NAME 0x0002 // pszName member valid for set/get
+#define CSSF_MASK_MESSAGE 0x0004 // pszMessage member valid for set/get
+#define CSSF_DISABLE_UI 0x0040 // disable default custom status UI, wParam = bEnable
+#define CSSF_DEFAULT_NAME 0x0080 // only with CSSF_MASK_NAME and get API to get default custom status name (wParam = status)
+#define CSSF_STATUSES_COUNT 0x0100 // returns number of custom statuses in wParam, only get API
+#define CSSF_STR_SIZES 0x0200 // returns sizes of custom status name & message (wParam & lParam members) in chars
+#define CSSF_UNICODE 0x1000 // strings are in UCS-2
+
+#if defined(_UNICODE)
+ #define CSSF_TCHAR CSSF_UNICODE
+#else
+ #define CSSF_TCHAR 0
+#endif
+
+
+typedef struct {
+ int cbSize; // size of the structure
+ int flags; // combination of CSSF_*
+ int *status; // custom status id
+ union {
+ char *pszName; // buffer for custom status name
+ TCHAR *ptszName;
+ WCHAR *pwszName;
+ };
+ union {
+ char *pszMessage; // buffer for custom status message
+ TCHAR *ptszMessage;
+ WCHAR *pwszMessage;
+ };
+ WPARAM *wParam; // extra params, see flags
+ LPARAM *lParam;
+} ICQ_CUSTOM_STATUS;
+
+
+// Sets owner current custom status (obsolete)
+//wParam = (int)N // custom status id (1-32)
+//lParam = 0
+//return = N (id of status set) or 0 (failed - probably bad params)
+#define PS_ICQ_SETCUSTOMSTATUS "/SetXStatus"
+
+// Sets owner current custom status
+//wParam = 0 // reserved
+//lParam = (ICQ_CUSTOM_STATUS*)pData // contains what to set and new values
+//return = 0 (for success)
+#define PS_ICQ_SETCUSTOMSTATUSEX "/SetXStatusEx"
+
+// Retrieves custom status details for specified hContact
+//wParam = (HANDLE)hContact
+//lParam = (ICQ_CUSTOM_STATUS*)pData // receives details (members must be prepared)
+//return = 0 (for success)
+#define PS_ICQ_GETCUSTOMSTATUSEX "/GetXStatusEx"
+
+// Retrieves specified custom status icon
+//wParam = (int)N // custom status id (1-32), 0 = my current custom status
+//lParam = 0
+//return = HICON // custom status icon (use DestroyIcon to release resources)
+#define PS_ICQ_GETCUSTOMSTATUSICON "/GetXStatusIcon"
+
+// Get Custom status DB field names & current owner custom status (obsolete)
+//wParam = (char**)szDBTitle // will receive title DB setting name (do not free)
+//lParam = (char**)szDBMsg // will receive message DB setting name
+//return = N // current custom status id if successful, 0 otherwise
+#define PS_ICQ_GETCUSTOMSTATUS "/GetXStatus"
+
+// Request Custom status details (messages) for specified contact
+//wParam = hContact // request custom status details for this contact
+//lParam = 0
+//return = (int)dwSequence // if successful it is sequence for ICQACKTYPE_XSTATUS_RESPONSE
+ // 0 failed to request (e.g. auto-request enabled)
+ // -1 delayed (rate control) - sequence unknown
+#define PS_ICQ_REQUESTCUSTOMSTATUS "/RequestXStatusDetails"
+
+// 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 ME_ICQ_CUSTOMSTATUS_EXTRAICON_CHANGED "/XStatusExtraIconChanged"
diff --git a/miranda-wine/protocols/IcqOscarJ/m_popupw.h b/miranda-wine/protocols/IcqOscarJ/m_popupw.h
new file mode 100644
index 0000000..c0cac41
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/m_popupw.h
@@ -0,0 +1,56 @@
+/*
+===============================================================================
+ PopUp plugin
+Plugin Name: PopUp
+Plugin authors: Luca Santarelli aka hrk (hrk@users.sourceforge.net)
+ Victor Pavlychko aka zazoo (nullbie@gmail.com)
+===============================================================================
+The purpose of this plugin is to give developers a common "platform/interface"
+to show PopUps. It is born from the source code of NewStatusNotify, another
+plugin I've made.
+
+Remember that users *must* have this plugin enabled, or they won't get any
+popup. Write this in the requirements, do whatever you wish ;-)... but tell
+them!
+===============================================================================
+*/
+#ifndef M_POPUPW_H
+#define M_POPUPW_H
+
+#ifndef MAX_CONTACTNAME
+ #define MAX_CONTACTNAME 2048
+#endif
+
+#ifndef MAX_SECONDLINE
+ #define MAX_SECONDLINE 2048
+#endif
+
+// Unicode Popup Info
+typedef struct {
+ HANDLE lchContact;
+ HICON lchIcon;
+ WCHAR lpwzContactName[MAX_CONTACTNAME];
+ WCHAR lpwzText[MAX_SECONDLINE];
+ COLORREF colorBack;
+ COLORREF colorText;
+ WNDPROC PluginWindowProc;
+ void * PluginData;
+ int iSeconds; //Custom delay time in seconds. -1 means "forever", 0 means "default time".
+ char cZero[16]; //some unused bytes which may come useful in the future.
+} POPUPDATAW, *LPPOPUPDATAW;
+
+// Create Popup
+#define MS_POPUP_ADDPOPUPW "PopUp/AddPopUpW"
+
+static int __inline PUAddPopUpW(POPUPDATAW* ppdp) {
+ return CallService(MS_POPUP_ADDPOPUPW, (WPARAM)ppdp,0);
+}
+
+// Change Text
+#define MS_POPUP_CHANGETEXTW "PopUp/ChangetextW"
+
+static int __inline PUChangeTextW(HWND hWndPopUp, LPCWSTR lpwzNewText) {
+ return (int)CallService(MS_POPUP_CHANGETEXTW, (WPARAM)hWndPopUp, (LPARAM)lpwzNewText);
+}
+
+#endif
diff --git a/miranda-wine/protocols/IcqOscarJ/m_updater.h b/miranda-wine/protocols/IcqOscarJ/m_updater.h
new file mode 100644
index 0000000..c83b8a4
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/m_updater.h
@@ -0,0 +1,117 @@
+#ifndef _M_UPDATER_H
+#define _M_UPDATER_H
+
+// if you set Update::szUpdateURL to the following value when registering, as well as setting your beta site and version data,
+// updater will ignore szVersionURL and pbVersionPrefix, and attempt to find the file listing URL's from the backend XML data.
+// for this to work, the plugin name in pluginInfo.shortName must match the file listing exactly (except for case)
+#define UPDATER_AUTOREGISTER "UpdaterAUTOREGISTER"
+
+typedef struct Update_tag {
+ int cbSize;
+ char *szComponentName; // component name as it will appear in the UI (will be translated before displaying)
+
+ char *szVersionURL; // URL where the current version can be found (NULL to disable)
+ BYTE *pbVersionPrefix; // bytes occuring in VersionURL before the version, used to locate the version information within the URL data
+ // (not that this URL could point at a binary file - dunno why, but it could :)
+ int cpbVersionPrefix; // number of bytes pionted to by pbVersionPrefix
+ char *szUpdateURL; // URL where dll/zip is located
+ // set to UPDATER_AUTOREGISTER if you want updater to find the file listing URLs (ensure plugin shortName matches file listing!)
+
+ char *szBetaVersionURL; // URL where the beta version can be found (NULL to disable betas)
+ BYTE *pbBetaVersionPrefix; // bytes occuring in VersionURL before the version, used to locate the version information within the URL data
+ int cpbBetaVersionPrefix; // number of bytes pionted to by pbVersionPrefix
+ char *szBetaUpdateURL; // URL where dll/zip is located
+
+ BYTE *pbVersion; // bytes of current version, used for comparison with those in VersionURL
+ int cpbVersion; // number of bytes pionted to by pbVersion
+
+ char *szBetaChangelogURL; // url for displaying changelog for beta versions
+} Update;
+
+// register a comonent with the updater
+//
+// wparam = 0
+// lparam = (LPARAM)&Update
+#define MS_UPDATE_REGISTER "Update/Register"
+
+// utility functions to create a version string from a DWORD or from pluginInfo
+// point buf at a buffer at least 16 chars wide - but note the version string returned may be shorter
+//
+__inline static char *CreateVersionString(DWORD version, char *buf) {
+ mir_snprintf(buf, 16, "%d.%d.%d.%d", (version >> 24) & 0xFF, (version >> 16) & 0xFF, (version >> 8) & 0xFF, version & 0xFF);
+ return buf;
+}
+
+__inline static char *CreateVersionStringPlugin(PLUGININFO *pluginInfo, char *buf) {
+ return CreateVersionString(pluginInfo->version, buf);
+}
+
+
+// register the 'easy' way - use this method if you have no beta URL and the plugin is on the miranda file listing
+// NOTE: the plugin 'short name' in pluginInfo must match the name of the plugin on the file listing, exactly (not including case)
+// AND the plugin version string on the file listing must be the string version of the version in pluginInfo (i.e. 0.0.0.1,
+// so no letters, brackets, etc.)
+//
+// wParam = (int)fileID - this is the file ID from the file listing (i.e. the number at the end of the download link)
+// lParam = (PLUGININFO*)&pluginInfo
+#define MS_UPDATE_REGISTERFL "Update/RegisterFL"
+
+// this event is fired when the startup process is complete, but NOT if a restart is imminent
+// it is designed for status managment plugins to use as a trigger for beggining their own startup process
+// wParam = lParam = 0 (unused)
+// (added in version 0.1.6.0)
+#define ME_UPDATE_STARTUPDONE "Update/StartupDone"
+
+// this service can be used to enable/disable Updater's global status control
+// it can be called from the StartupDone event handler
+// wParam = (BOOL)enable
+// lParam = 0
+// (added in version 0.1.6.0)
+#define MS_UPDATE_ENABLESTATUSCONTROL "Update/EnableStatusControl"
+
+// An description of usage of the above service and event:
+// Say you are a status control plugin that normally sets protocol or global statuses in your ModulesLoaded event handler.
+// In order to make yourself 'updater compatible', you would move the status control code from ModulesLoaded to another function,
+// say DoStartup. Then, in ModulesLoaded you would check for the existence of the MS_UPDATE_ENABLESTATUSCONTROL service.
+// If it does not exist, call DoStartup. If it does exist, hook the ME_UPDATE_STARTUPDONE event and call DoStartup from there. You may
+// also wish to call MS_UPDATE_ENABLESTATUSCONTROL with wParam == FALSE at this time, to disable Updater's own status control feature.
+
+#endif
+
+
+/////////////// Usage Example ///////////////
+
+#ifdef EXAMPLE_CODE
+
+// you need to #include "m_updater.h" and HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded) in your Load function...
+
+int OnModulesLoaded(WPARAM wParam, LPARAM lParam) {
+
+ Update update = {0}; // for c you'd use memset or ZeroMemory...
+ char szVersion[16];
+
+ update.cbSize = sizeof(Update);
+
+ update.szComponentName = pluginInfo.shortName;
+ update.pbVersion = (BYTE *)CreateVersionString(&pluginInfo, szVersion);
+ update.cpbVersion = strlen((char *)update.pbVersion);
+
+ // these are the three lines that matter - the archive, the page containing the version string, and the text (or data)
+ // before the version that we use to locate it on the page
+ // (note that if the update URL and the version URL point to standard file listing entries, the backend xml
+ // data will be used to check for updates rather than the actual web page - this is not true for beta urls)
+ update.szUpdateURL = "http://scottellis.com.au:81/test/updater.zip";
+ update.szVersionURL = "http://scottellis.com.au:81/test/updater_test.html";
+ update.pbVersionPrefix = (BYTE *)"Updater version ";
+
+ update.cpbVersionPrefix = strlen((char *)update.pbVersionPrefix);
+
+ CallService(MS_UPDATE_REGISTER, 0, (WPARAM)&update);
+
+ // Alternatively, to register a plugin with e.g. file ID 2254 on the file listing...
+ // CallService(MS_UPDATE_REGISTERFL, (WPARAM)2254, (LPARAM)&pluginInfo);
+
+ return 0;
+}
+
+#endif
diff --git a/miranda-wine/protocols/IcqOscarJ/md5.c b/miranda-wine/protocols/IcqOscarJ/md5.c
new file mode 100644
index 0000000..fb2fc84
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/md5.c
@@ -0,0 +1,352 @@
+/*
+ Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ L. Peter Deutsch
+ ghost@aladdin.com
+
+ */
+/* $Id: md5.c 2874 2006-05-16 21:38:00Z ghazan $ */
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.c is L. Peter Deutsch
+ <ghost@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
+ either statically or dynamically; added missing #include <string.h>
+ in library.
+ 2002-03-11 lpd Corrected argument list for main(), and added int return
+ type, in test program and T value program.
+ 2002-02-21 lpd Added missing #include <stdio.h> in test program.
+ 2000-07-03 lpd Patched to eliminate warnings about "constant is
+ unsigned in ANSI C, signed in traditional"; made test program
+ self-checking.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+ 1999-05-03 lpd Original version.
+ */
+
+// (C) 2005 Joe @ Whale - changed to compile with Miranda
+
+#include "icqoscar.h"
+
+
+#define T_MASK ((md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3 0x242070db
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6 0x4787c62a
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9 0x698098d8
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13 0x6b901122
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16 0x49b40821
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19 0x265e5a51
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22 0x02441453
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25 0x21e1cde6
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28 0x455a14ed
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31 0x676f02d9
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35 0x6d9d6122
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38 0x4bdecfa9
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41 0x289b7ec6
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44 0x04881d05
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47 0x1fa27cf8
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50 0x432aff97
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53 0x655b59c3
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57 0x6fa87e4f
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60 0x4e0811a1
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63 0x2ad7d2bb
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+//gfd*
+static void md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
+{
+ md5_word_t
+ a = pms->abcd[0], b = pms->abcd[1],
+ c = pms->abcd[2], d = pms->abcd[3];
+ md5_word_t t;
+ /* Define storage for little-endian or both types of CPUs. */
+ md5_word_t xbuf[16];
+ const md5_word_t *X;
+
+ {
+ /*
+ * Determine dynamically whether this is a big-endian or
+ * little-endian machine, since we can use a more efficient
+ * algorithm on the latter.
+ */
+ static const int w = 1;
+
+ if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
+ {
+ /*
+ * On little-endian machines, we can process properly aligned
+ * data without copying it.
+ */
+ if (!((data - (const md5_byte_t *)0) & 3)) {
+ /* data are properly aligned */
+ X = (const md5_word_t *)data;
+ } else {
+ /* not aligned */
+ memcpy(xbuf, data, 64);
+ X = xbuf;
+ }
+ }
+ else /* dynamic big-endian */
+ {
+ /*
+ * On big-endian machines, we must arrange the bytes in the
+ * right order.
+ */
+ const md5_byte_t *xp = data;
+ int i;
+
+ X = xbuf; /* (dynamic only) */
+ for (i = 0; i < 16; ++i, xp += 4)
+ xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+ }
+ }
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+ /* Round 1. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET1(a, b, c, d, k, s, Ti)\
+ t = a + F(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET1(a, b, c, d, 0, 7, T1);
+ SET1(d, a, b, c, 1, 12, T2);
+ SET1(c, d, a, b, 2, 17, T3);
+ SET1(b, c, d, a, 3, 22, T4);
+ SET1(a, b, c, d, 4, 7, T5);
+ SET1(d, a, b, c, 5, 12, T6);
+ SET1(c, d, a, b, 6, 17, T7);
+ SET1(b, c, d, a, 7, 22, T8);
+ SET1(a, b, c, d, 8, 7, T9);
+ SET1(d, a, b, c, 9, 12, T10);
+ SET1(c, d, a, b, 10, 17, T11);
+ SET1(b, c, d, a, 11, 22, T12);
+ SET1(a, b, c, d, 12, 7, T13);
+ SET1(d, a, b, c, 13, 12, T14);
+ SET1(c, d, a, b, 14, 17, T15);
+ SET1(b, c, d, a, 15, 22, T16);
+
+ /* Round 2. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET2(a, b, c, d, k, s, Ti)\
+ t = a + G(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET2(a, b, c, d, 1, 5, T17);
+ SET2(d, a, b, c, 6, 9, T18);
+ SET2(c, d, a, b, 11, 14, T19);
+ SET2(b, c, d, a, 0, 20, T20);
+ SET2(a, b, c, d, 5, 5, T21);
+ SET2(d, a, b, c, 10, 9, T22);
+ SET2(c, d, a, b, 15, 14, T23);
+ SET2(b, c, d, a, 4, 20, T24);
+ SET2(a, b, c, d, 9, 5, T25);
+ SET2(d, a, b, c, 14, 9, T26);
+ SET2(c, d, a, b, 3, 14, T27);
+ SET2(b, c, d, a, 8, 20, T28);
+ SET2(a, b, c, d, 13, 5, T29);
+ SET2(d, a, b, c, 2, 9, T30);
+ SET2(c, d, a, b, 7, 14, T31);
+ SET2(b, c, d, a, 12, 20, T32);
+
+ /* Round 3. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET3(a, b, c, d, k, s, Ti)\
+ t = a + H(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET3(a, b, c, d, 5, 4, T33);
+ SET3(d, a, b, c, 8, 11, T34);
+ SET3(c, d, a, b, 11, 16, T35);
+ SET3(b, c, d, a, 14, 23, T36);
+ SET3(a, b, c, d, 1, 4, T37);
+ SET3(d, a, b, c, 4, 11, T38);
+ SET3(c, d, a, b, 7, 16, T39);
+ SET3(b, c, d, a, 10, 23, T40);
+ SET3(a, b, c, d, 13, 4, T41);
+ SET3(d, a, b, c, 0, 11, T42);
+ SET3(c, d, a, b, 3, 16, T43);
+ SET3(b, c, d, a, 6, 23, T44);
+ SET3(a, b, c, d, 9, 4, T45);
+ SET3(d, a, b, c, 12, 11, T46);
+ SET3(c, d, a, b, 15, 16, T47);
+ SET3(b, c, d, a, 2, 23, T48);
+
+ /* Round 4. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET4(a, b, c, d, k, s, Ti)\
+ t = a + I(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET4(a, b, c, d, 0, 6, T49);
+ SET4(d, a, b, c, 7, 10, T50);
+ SET4(c, d, a, b, 14, 15, T51);
+ SET4(b, c, d, a, 5, 21, T52);
+ SET4(a, b, c, d, 12, 6, T53);
+ SET4(d, a, b, c, 3, 10, T54);
+ SET4(c, d, a, b, 10, 15, T55);
+ SET4(b, c, d, a, 1, 21, T56);
+ SET4(a, b, c, d, 8, 6, T57);
+ SET4(d, a, b, c, 15, 10, T58);
+ SET4(c, d, a, b, 6, 15, T59);
+ SET4(b, c, d, a, 13, 21, T60);
+ SET4(a, b, c, d, 4, 6, T61);
+ SET4(d, a, b, c, 11, 10, T62);
+ SET4(c, d, a, b, 2, 15, T63);
+ SET4(b, c, d, a, 9, 21, T64);
+
+ /* Then perform the following additions. (That is increment each
+ of the four registers by the value it had before this block
+ was started.) */
+ pms->abcd[0] += a;
+ pms->abcd[1] += b;
+ pms->abcd[2] += c;
+ pms->abcd[3] += d;
+}
+
+void md5_init(md5_state_t *pms)
+{
+ pms->count[0] = pms->count[1] = 0;
+ pms->abcd[0] = 0x67452301;
+ pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+ pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+ pms->abcd[3] = 0x10325476;
+}
+
+void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
+{
+ const md5_byte_t *p = data;
+ int left = nbytes;
+ int offset = (pms->count[0] >> 3) & 63;
+ md5_word_t nbits = (md5_word_t)(nbytes << 3);
+
+ if (nbytes <= 0)
+ return;
+
+ /* Update the message length. */
+ pms->count[1] += nbytes >> 29;
+ pms->count[0] += nbits;
+ if (pms->count[0] < nbits)
+ pms->count[1]++;
+
+ /* Process an initial partial block. */
+ if (offset)
+ {
+ int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+ memcpy(pms->buf + offset, p, copy);
+ if (offset + copy < 64)
+ return;
+ p += copy;
+ left -= copy;
+ md5_process(pms, pms->buf);
+ }
+
+ /* Process full blocks. */
+ for (; left >= 64; p += 64, left -= 64)
+ md5_process(pms, p);
+
+ /* Process a final partial block. */
+ if (left)
+ memcpy(pms->buf, p, left);
+}
+
+void md5_finish(md5_state_t *pms, md5_byte_t digest[16])
+{
+ static const md5_byte_t pad[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ md5_byte_t data[8];
+ int i;
+
+ /* Save the length before padding. */
+ for (i = 0; i < 8; ++i)
+ data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+ /* Pad to 56 bytes mod 64. */
+ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+ /* Append the length. */
+ md5_append(pms, data, 8);
+ for (i = 0; i < 16; ++i)
+ digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/md5.h b/miranda-wine/protocols/IcqOscarJ/md5.h
new file mode 100644
index 0000000..d3fd8bb
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/md5.h
@@ -0,0 +1,82 @@
+/*
+ Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ L. Peter Deutsch
+ ghost@aladdin.com
+
+ */
+/* $Id: md5.h 2874 2006-05-16 21:38:00Z ghazan $ */
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.h is L. Peter Deutsch
+ <ghost@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Removed support for non-ANSI compilers; removed
+ references to Ghostscript; clarified derivation from RFC 1321;
+ now handles byte order either statically or dynamically.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
+ added conditionalization for C++ compilation from Martin
+ Purschke <purschke@bnl.gov>.
+ 1999-05-03 lpd Original version.
+ */
+
+#ifndef md5_INCLUDED
+# define md5_INCLUDED
+
+/*
+ * This package supports both compile-time and run-time determination of CPU
+ * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
+ * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
+ * defined as non-zero, the code will be compiled to run only on big-endian
+ * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
+ * run on either big- or little-endian CPUs, but will run slightly less
+ * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
+ */
+
+typedef unsigned char md5_byte_t; /* 8-bit byte */
+typedef unsigned int md5_word_t; /* 32-bit word */
+
+/* Define the state of the MD5 Algorithm. */
+typedef struct md5_state_s {
+ md5_word_t count[2]; /* message length in bits, lsw first */
+ md5_word_t abcd[4]; /* digest buffer */
+ md5_byte_t buf[64]; /* accumulate block */
+} md5_state_t;
+
+/* Initialize the algorithm. */
+void md5_init(md5_state_t *pms);
+
+/* Append a string to the message. */
+void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
+
+/* Finish the message and return the digest. */
+void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
+
+#endif /* md5_INCLUDED */
diff --git a/miranda-wine/protocols/IcqOscarJ/oscar_filetransfer.c b/miranda-wine/protocols/IcqOscarJ/oscar_filetransfer.c
new file mode 100644
index 0000000..ce7cbdc
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/oscar_filetransfer.c
@@ -0,0 +1,1211 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/oscar_filetransfer.c,v $
+// Revision : $Revision: 3720 $
+// Last change on : $Date: 2006-09-07 00:56:27 +0400 (Чтв, 07 Сен 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+typedef struct {
+ int type;
+ int incoming;
+ HANDLE hContact;
+ HANDLE hConnection;
+ DWORD dwRemoteIP;
+ oscar_filetransfer *ft;
+ oscar_listener *listener;
+} oscarthreadstartinfo;
+
+
+// small utility function
+extern void NormalizeBackslash(char* path);
+
+
+static DWORD __stdcall oft_connectionThread(oscarthreadstartinfo *otsi);
+static void sendOscarPacket(oscar_connection *oc, icq_packet *packet);
+static int oft_handlePackets(oscar_connection *oc, unsigned char *buf, int len);
+static int oft_handleFileData(oscar_connection *oc, unsigned char *buf, int len);
+static void handleOFT2FramePacket(oscar_connection *oc, WORD datatype, BYTE *pBuffer, WORD wLen);
+static void sendOFT2FramePacket(oscar_connection *oc, WORD datatype);
+
+void oft_sendPeerInit(oscar_connection *oc);
+
+static CRITICAL_SECTION oftMutex;
+static int oftTransferCount = 0;
+static oscar_filetransfer** oftTransferList = NULL;
+
+static oscar_filetransfer* CreateOscarTransfer();
+static void SafeReleaseOscarTransfer(oscar_filetransfer *ft);
+static int IsValidOscarTransfer(void *ft);
+static oscar_filetransfer* FindOscarTransfer(HANDLE hContact, DWORD dwID1, DWORD dwID2);
+
+
+//
+// Utility functions
+/////////////////////////////
+
+
+static oscar_filetransfer* CreateOscarTransfer()
+{
+ oscar_filetransfer* ft = (oscar_filetransfer*)SAFE_MALLOC(sizeof(oscar_filetransfer));
+
+ EnterCriticalSection(&oftMutex);
+
+ oftTransferList = (oscar_filetransfer**)realloc(oftTransferList, sizeof(oscar_filetransfer*)*(oftTransferCount + 1));
+ oftTransferList[oftTransferCount++] = ft;
+
+ LeaveCriticalSection(&oftMutex);
+
+ return ft;
+}
+
+
+
+static void SafeReleaseOscarTransfer(oscar_filetransfer *ft)
+{
+ int i;
+
+ EnterCriticalSection(&oftMutex);
+
+ for (i = 0; i < oftTransferCount; i++)
+ {
+ if (oftTransferList[i] == ft)
+ {
+ oftTransferCount--;
+ SafeReleaseFileTransfer(&oftTransferList[i]);
+ oftTransferList[i] = oftTransferList[oftTransferCount];
+ oftTransferList = (oscar_filetransfer**)realloc(oftTransferList, sizeof(oscar_filetransfer*)*oftTransferCount);
+ break;
+ }
+ }
+
+ LeaveCriticalSection(&oftMutex);
+}
+
+
+
+static int IsValidOscarTransfer(void *ft)
+{
+ int i;
+
+ EnterCriticalSection(&oftMutex);
+
+ for (i = 0; i < oftTransferCount; i++)
+ {
+ if (oftTransferList[i] == ft)
+ {
+ LeaveCriticalSection(&oftMutex);
+
+ return 1;
+ }
+ }
+
+ LeaveCriticalSection(&oftMutex);
+
+ return 0;
+}
+
+
+
+static oscar_filetransfer* FindOscarTransfer(HANDLE hContact, DWORD dwID1, DWORD dwID2)
+{
+ int i;
+
+ EnterCriticalSection(&oftMutex);
+
+ for (i = 0; i < oftTransferCount; i++)
+ {
+ if (oftTransferList[i]->hContact == hContact && oftTransferList[i]->pMessage.dwMsgID1 == dwID1 && oftTransferList[i]->pMessage.dwMsgID2 == dwID2)
+ {
+ LeaveCriticalSection(&oftMutex);
+
+ return oftTransferList[i];
+ }
+ }
+
+ LeaveCriticalSection(&oftMutex);
+
+ return NULL;
+}
+
+
+
+// Release file transfer structure
+void SafeReleaseFileTransfer(void **ft)
+{
+ basic_filetransfer **bft = (basic_filetransfer**)ft;
+
+ 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->files)
+ {
+ int i;
+
+ for (i = 0; i < (int)ift->dwFileCount; i++)
+ SAFE_FREE(&ift->files[i]);
+ SAFE_FREE((char**)&ift->files);
+ }
+ SAFE_FREE(ft);
+ }
+ else
+ { // release oscar filetransfer structure and its contents
+ oscar_filetransfer *oft = (oscar_filetransfer*)(*bft);
+ // FIX ME: release all dynamic members
+ if (oft->listener)
+ ReleaseOscarListener((oscar_listener**)&oft->listener);
+ SAFE_FREE(&oft->rawFileName);
+ SAFE_FREE(&oft->szSavePath);
+ SAFE_FREE(&oft->szThisFile);
+ if (oft->files)
+ {
+ int i;
+
+ for (i = 0; i < oft->wFilesCount; i++)
+ SAFE_FREE(&oft->files[i]);
+ SAFE_FREE((char**)&oft->files);
+ }
+ SAFE_FREE(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;
+ int i;
+
+ checksum = (dwChecksum >> 16) & 0xffff;
+ for (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;
+}
+
+
+
+oscar_listener* CreateOscarListener(oscar_filetransfer *ft, NETLIBNEWCONNECTIONPROC_V2 handler)
+{
+ oscar_listener *listener = (oscar_listener*)SAFE_MALLOC(sizeof(oscar_listener));
+
+ listener->ft = ft;
+ if (listener->hBoundPort = NetLib_BindPort(handler, listener, &listener->wPort, NULL))
+ return listener; // Success
+
+ SAFE_FREE(&listener);
+
+ return NULL; // Failure
+}
+
+
+
+void ReleaseOscarListener(oscar_listener **pListener)
+{
+ oscar_listener *listener = *pListener;
+
+ if (listener)
+ { // Close listening port
+ if (listener->hBoundPort)
+ NetLib_SafeCloseHandle(&listener->hBoundPort, FALSE);
+ }
+ SAFE_FREE(pListener);
+}
+
+
+//
+// Miranda FT interface handlers & services
+/////////////////////////////
+
+void InitOscarFileTransfer()
+{
+ InitializeCriticalSection(&oftMutex);
+}
+
+
+
+void UninitOscarFileTransfer()
+{
+ DeleteCriticalSection(&oftMutex);
+}
+
+
+
+void handleRecvServMsgOFT(unsigned char *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwID1, DWORD dwID2, WORD wCommand)
+{
+ if (wCommand == 0)
+ { // this is OFT request
+ oscar_tlv_chain* chain = readIntoTLVChain(&buf, wLen, 0);
+
+ if (chain)
+ {
+ HANDLE hContact = HContactFromUID(dwUin, szUID, NULL);
+ WORD wAckType = getWordFromChain(chain, 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
+
+ ft->ft_magic = FT_MAGIC_OSCAR;
+ // init filetransfer structure
+ ft->pMessage.dwMsgID1 = dwID1;
+ ft->pMessage.dwMsgID2 = dwID2;
+ ft->bUseProxy = getTLV(chain, 0x10, 1) ? 1 : 0;
+ ft->dwProxyIP = getDWordFromChain(chain, 0x02, 1);
+ ft->dwRemoteExternalIP = getDWordFromChain(chain, 0x03, 1);
+ ft->dwRemoteInternalIP = getDWordFromChain(chain, 0x04, 1);
+ ft->dwRemotePort = getWordFromChain(chain, 0x05, 1);
+
+ { // User Message
+ oscar_tlv* tlv = getTLV(chain, 0x0C, 1);
+
+ if (tlv)
+ { // parse User Message
+ BYTE* tBuf = tlv->pData;
+
+ pszDescription = (char*)_alloca(tlv->wLen + 1);
+ unpackString(&tBuf, pszDescription, tlv->wLen);
+ pszDescription[tlv->wLen] = '\0';
+ { // apply User Message encoding
+ oscar_tlv *charset = getTLV(chain, 0x0D, 1);
+ char *str = pszDescription;
+ char *bTag,*eTag;
+
+ if (charset)
+ { // decode charset
+ char *szEnc = (char*)_alloca(charset->wLen + 1);
+
+ strncpy(szEnc, charset->pData, charset->wLen);
+ szEnc[charset->wLen] = '\0';
+ str = ApplyEncoding(pszDescription, szEnc);
+ }
+ // decode XML tags
+ str = DemangleXml(str, strlennull(str));
+ if (charset) SAFE_FREE(&pszDescription);
+ pszDescription = str;
+
+ bTag = strstr(str, "<FS>");
+ if (bTag)
+ { // take only <FS> - Description tag if present
+ eTag = strstr(bTag, "</FS>");
+ if (eTag)
+ {
+ *eTag = '\0';
+ pszDescription = null_strdup(bTag + 4);
+ SAFE_FREE(&str);
+ }
+ }
+ }
+
+ }
+ if (!strlennull(pszDescription)) pszDescription = ICQTranslate("No description given");
+ }
+ { // parse File Transfer Info block
+ oscar_tlv* tlv = getTLV(chain, 0x2711, 1);
+ BYTE* tBuf = tlv->pData;
+ WORD tLen = tlv->wLen;
+
+ tBuf += 2; // FT flag
+ unpackWord(&tBuf, &ft->wFilesCount);
+ unpackDWord(&tBuf, &ft->dwTotalSize);
+ tLen -= 8;
+ // Filename
+ wFilenameLength = tLen - 1;
+ pszFileName = (char*)_alloca(tLen);
+ unpackString(&tBuf, pszFileName, wFilenameLength);
+ pszFileName[wFilenameLength] = '\0';
+ { // apply Filename encoding
+ oscar_tlv* charset = getTLV(chain, 0x2712, 1);
+
+ if (charset)
+ {
+ char* szEnc = (char*)_alloca(charset->wLen + 1);
+
+ strncpy(szEnc, charset->pData, charset->wLen);
+ szEnc[charset->wLen] = '\0';
+ pszFileName = ApplyEncoding(pszFileName, szEnc);
+ }
+ else // needs to be alloced
+ pszFileName = null_strdup(pszFileName);
+ }
+ }
+ {
+ CCSDATA ccs;
+ PROTORECVEVENT pre;
+ char* szBlob;
+ int bAdded;
+ HANDLE hContact = HContactFromUID(dwUin, szUID, &bAdded);
+
+ ft->hContact = hContact;
+ ft->szFilename = pszFileName;
+ ft->szDescription = pszDescription;
+ ft->fileId = -1;
+
+ // Send chain event
+ szBlob = (char*)_alloca(sizeof(DWORD) + strlennull(pszFileName) + strlennull(pszDescription) + 2);
+ *(PDWORD)szBlob = (DWORD)ft;
+ strcpy(szBlob + sizeof(DWORD), pszFileName);
+ strcpy(szBlob + sizeof(DWORD) + strlennull(pszFileName) + 1, pszDescription);
+ ccs.szProtoService = PSR_FILE;
+ ccs.hContact = hContact;
+ ccs.wParam = 0;
+ ccs.lParam = (LPARAM)&pre;
+ pre.flags = 0;
+ pre.timestamp = time(NULL);
+ pre.szMessage = szBlob;
+ pre.lParam = 0;
+
+ CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs);
+ }
+ }
+ else if (wAckType == 2)
+ { // First attempt failed, reverse requested
+ }
+ else if (wAckType == 3)
+ { // Reverse attempt failed, trying proxy
+ }
+
+ disposeChain(&chain);
+ }
+ else
+ NetLog_Server("Error: Missing TLV chain in OFT request");
+ }
+ else
+ { // TODO: handle other commands / cancels
+ }
+}
+
+
+
+DWORD oftFileAllow(HANDLE hContact, WPARAM wParam, LPARAM lParam)
+{
+ oscar_filetransfer* ft = (oscar_filetransfer*)wParam;
+
+ ft->szSavePath = null_strdup((char *)lParam);
+
+ OpenOscarConnection(hContact, ft, ft->bUseProxy ? OCT_PROXY: OCT_NORMAL);
+
+ return wParam; // Success
+}
+
+
+
+DWORD oftFileDeny(HANDLE hContact, WPARAM wParam, LPARAM lParam)
+{
+ oscar_filetransfer* ft = (oscar_filetransfer*)wParam;
+ DWORD dwUin;
+ uid_str szUid;
+
+ if (ICQGetContactSettingUID(hContact, &dwUin, &szUid))
+ return 1; // Invalid contact
+
+ oft_sendFileDeny(dwUin, szUid, ft);
+
+ SafeReleaseOscarTransfer(ft);
+
+ return 0; // Success
+}
+
+
+
+DWORD oftFileCancel(HANDLE hContact, WPARAM wParam, LPARAM lParam)
+{
+ oscar_filetransfer* ft = (oscar_filetransfer*)wParam;
+ DWORD dwUin;
+ uid_str szUid;
+
+ if (ft->hContact != hContact)
+ return 1; // Bad contact or hTransfer
+
+ if (ICQGetContactSettingUID(hContact, &dwUin, &szUid))
+ return 1; // Invalid contact
+
+ oft_sendFileDeny(dwUin, szUid, ft);
+
+ ICQBroadcastAck(hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0);
+
+ if (ft->connection)
+ {
+ CloseOscarConnection((oscar_connection*)ft->connection);
+ }
+ // Release structure
+ SafeReleaseOscarTransfer(ft);
+
+ return 0; // Success
+}
+
+
+
+void oftFileResume(oscar_filetransfer *ft, int action, const char *szFilename)
+{
+ oscar_connection *oc;
+ int openFlags;
+
+ if (ft->connection == NULL)
+ return;
+
+ oc = (oscar_connection*)ft->connection;
+
+ switch (action)
+ {
+ case FILERESUME_RESUME: // FIX ME: this needs to request 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;
+ }
+
+ // TODO: unicode support
+ ft->fileId = _open(ft->szThisFile, openFlags, _S_IREAD | _S_IWRITE);
+ if (ft->fileId == -1)
+ {
+ icq_LogMessage(LOG_ERROR, "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.");
+
+ CloseOscarConnection(oc);
+ 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;
+
+ // Send "we are ready"
+ oc->status = OCS_DATA;
+
+ sendOFT2FramePacket(oc, OFT_TYPE_READY);
+ ICQBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0);
+
+ if (!ft->dwThisFileSize)
+ { // 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->sending = ft->sending;
+ if (ft->sending)
+ pfts->files = ft->files;
+ else
+ pfts->files = NULL; /* FIXME */
+ pfts->totalFiles = ft->wFilesCount;
+ pfts->currentFileNumber = ft->iCurrentFile;
+ pfts->totalBytes = ft->dwTotalSize;
+ pfts->totalProgress = ft->dwBytesDone;
+ pfts->workingDir = ft->szSavePath;
+ pfts->currentFile = ft->szThisFile;
+ pfts->currentFileSize = ft->dwThisFileSize;
+ pfts->currentFileTime = ft->dwThisFileDate;
+ pfts->currentFileProgress = ft->dwFileBytesDone;
+}
+
+
+
+void CloseOscarConnection(oscar_connection *oc)
+{
+ EnterCriticalSection(&oftMutex);
+
+ if (oc)
+ {
+ oc->type = OCT_CLOSING;
+
+ if (oc->hConnection)
+ { // we need this for Netlib handle consistency
+ NetLib_SafeCloseHandle(&oc->hConnection, FALSE);
+ }
+ }
+ LeaveCriticalSection(&oftMutex);
+}
+
+
+
+void OpenOscarConnection(HANDLE hContact, oscar_filetransfer *ft, int type)
+{
+ pthread_t tid;
+ oscarthreadstartinfo *otsi = (oscarthreadstartinfo*)SAFE_MALLOC(sizeof(oscarthreadstartinfo));
+
+ otsi->hContact = hContact;
+ otsi->type = type;
+ otsi->ft = ft;
+
+ tid.hThread = (HANDLE)forkthreadex(NULL, 0, oft_connectionThread, otsi, 0, &tid.dwThreadId);
+ CloseHandle(tid.hThread);
+}
+
+
+
+// This function is called from the Netlib when someone is connecting to our oscar_listener
+void oft_newConnectionReceived(HANDLE hNewConnection, DWORD dwRemoteIP, void *pExtra)
+{
+ pthread_t tid;
+ oscarthreadstartinfo *otsi = (oscarthreadstartinfo*)SAFE_MALLOC(sizeof(oscarthreadstartinfo));
+ oscar_listener* listener = (oscar_listener*)pExtra;
+
+ otsi->type = listener->ft->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
+ tid.hThread = (HANDLE)forkthreadex(NULL, 0, oft_connectionThread, otsi, 0, &tid.dwThreadId);
+ CloseHandle(tid.hThread);
+}
+
+
+
+static DWORD __stdcall 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;
+ }
+ else
+ { // FT is already over, kill listener
+ NetLog_Direct("Received unexpected connection, closing.");
+
+ CloseOscarConnection(&oc);
+ ReleaseOscarListener(&source);
+
+ return 0;
+ }
+ }
+ SAFE_FREE(&otsi);
+
+ if (oc.hContact)
+ { // Load contact information
+ ICQGetContactSettingUID(oc.hContact, &oc.dwUin, &oc.szUid);
+ }
+
+ // Load local IP information
+ oc.dwLocalExternalIP = ICQGetContactSettingDword(NULL, "IP", 0);
+ oc.dwLocalInternalIP = ICQGetContactSettingDword(NULL, "RealIP", 0);
+
+ if (!oc.incoming)
+ { // FIX ME: this needs more work for proxy & sending
+ if (oc.type == OCT_NORMAL)
+ { // create outgoing connection to peer
+ NETLIBOPENCONNECTION nloc = {0};
+ IN_ADDR addr = {0};
+
+ nloc.cbSize = sizeof(nloc);
+
+ // FIX ME: Just for testing reverse
+ if (oc.ft->dwRemoteExternalIP == oc.dwLocalExternalIP && oc.ft->dwRemoteInternalIP)
+ addr.S_un.S_addr = htonl(oc.ft->dwRemoteInternalIP);
+ else
+ addr.S_un.S_addr = htonl(oc.ft->dwRemoteExternalIP);
+
+ // Inform UI that we will attempt to connect
+ ICQBroadcastAck(oc.ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, oc.ft, 0);
+
+ if (!addr.S_un.S_addr)
+ { // 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;
+ oft_sendFileRedirect(oc.dwUin, oc.szUid, oc.ft, oc.dwLocalInternalIP, listener->wPort, FALSE);
+// FIX ME: FT UI should support this
+// ICQBroadcastAck(oc.ft->hContact, ACKTYPE_FILE, ACKRESULT_LISTENING, oc.ft, 0);
+ }
+ // FIX ME: try proxy
+ return 0;
+ }
+ nloc.szHost = inet_ntoa(addr);
+ nloc.wPort = (WORD)oc.ft->dwRemotePort;
+ NetLog_Direct("%sConnecting to %s:%u", oc.type==OCT_REVERSE?"Reverse ":"", nloc.szHost, nloc.wPort);
+
+ oc.hConnection = NetLib_OpenConnection(ghDirectNetlibUser, &nloc);
+ if (!oc.hConnection)
+ { // 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;
+ oft_sendFileRedirect(oc.dwUin, oc.szUid, oc.ft, oc.dwLocalInternalIP, listener->wPort, FALSE);
+// FIX ME: FT UI should support this
+// ICQBroadcastAck(oc.ft->hContact, ACKTYPE_FILE, ACKRESULT_LISTENING, oc.ft, 0);
+ }
+ // FIX ME: try proxy
+ return 0;
+ }
+ oc.ft->connection = &oc;
+ // acknowledge OFT - connection is ready
+ oft_sendFileAccept(oc.dwUin, oc.szUid, oc.ft);
+ }
+ }
+ if (!oc.hConnection)
+ { // one more sanity chech
+ NetLog_Direct("Error: No OFT connection.");
+ return 0;
+ }
+ // Connected, notify FT UI
+ ICQBroadcastAck(oc.ft->hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, oc.ft, 0);
+ // Init connection
+ if (oc.ft->sending)
+ oft_sendPeerInit(&oc); // only if sending file...
+
+ 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 : 60000;
+
+ 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 should want to send file data packets
+ }
+ else
+ {
+ NetLog_Direct("Connection timeouted, closing.");
+ break;
+ }
+ }
+ else
+ {
+ 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, FALSE);
+
+ CloseOscarConnection(&oc);
+
+ // FIX ME: Clean up, error handling
+ if (IsValidOscarTransfer(oc.ft))
+ {
+ oc.ft->connection = NULL; // release link
+ }
+
+ return 0;
+}
+
+
+
+static void 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(&packet->pData);
+}
+
+
+
+static int oft_handlePackets(oscar_connection *oc, unsigned char *buf, int len)
+{
+ BYTE *pBuf;
+ DWORD dwHead;
+ WORD datalen;
+ WORD datatype;
+ int bytesUsed = 0;
+
+ while (len > 0)
+ {
+ if (oc->status == OCS_DATA)
+ {
+ return oft_handleFileData(oc, buf, len);
+ }
+ if (len < 6)
+ break;
+
+ pBuf = buf;
+ unpackDWord(&pBuf, &dwHead);
+ if (dwHead != 0x4F465432)
+ { // bad packet
+ CloseOscarConnection(oc);
+ break;
+ }
+
+ unpackWord(&pBuf, &datalen);
+
+ if (len < datalen) // wait for whole packet
+ break;
+
+ 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;
+}
+
+
+
+static int oft_handleFileData(oscar_connection *oc, unsigned char *buf, int len)
+{
+ oscar_filetransfer *ft = oc->ft;
+ DWORD dwLen = len;
+ int bytesUsed = 0;
+
+ // do not accept more data than expected
+ if (ft->dwThisFileSize - ft->dwFileBytesDone < dwLen)
+ dwLen = ft->dwThisFileSize - ft->dwFileBytesDone;
+
+ if (ft->fileId == -1)
+ { // something went terribly bad
+ CloseOscarConnection(oc);
+ return 0;
+ }
+ _write(ft->fileId, buf, dwLen);
+ // update checksum
+ ft->dwRecvFileCheck = oft_calc_checksum(ft->dwFileBytesDone, buf, dwLen, ft->dwRecvFileCheck);
+ bytesUsed += dwLen;
+ ft->dwBytesDone += dwLen;
+ ft->dwFileBytesDone += dwLen;
+
+ if (GetTickCount() > ft->dwLastNotify + 700 || ft->dwFileBytesDone == ft->dwThisFileSize)
+ { // notify FT UI of our progress, at most every 700ms - do not be faster than Miranda
+ PROTOFILETRANSFERSTATUS pfts;
+
+ oft_buildProtoFileTransferStatus(ft, &pfts);
+ ICQBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&pfts);
+ oc->ft->dwLastNotify = GetTickCount();
+ }
+ if (ft->dwFileBytesDone == ft->dwThisFileSize)
+ {
+ /* EOF */
+ _close(ft->fileId);
+ ft->fileId = -1;
+
+ if (ft->dwRecvFileCheck != ft->dwThisFileCheck)
+ {
+ NetLog_Direct("Error: File checksums does not match!");
+ // FIX ME: here we should inform user and end transfer
+ }
+
+ 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;
+ CloseOscarConnection(oc); // close connection
+ NetLog_Direct("File Transfer completed successfully.");
+ ICQBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0);
+ // Release structure
+ SafeReleaseOscarTransfer(ft);
+ }
+ else
+ { // ack received file
+ sendOFT2FramePacket(oc, OFT_TYPE_DONE);
+ oc->status = OCS_NEGOTIATION;
+ }
+
+ }
+ return bytesUsed;
+}
+
+
+
+static void handleOFT2FramePacket(oscar_connection *oc, WORD datatype, BYTE *pBuffer, WORD wLen)
+{
+ DWORD dwID1;
+ DWORD dwID2;
+
+ if (wLen < 248)
+ {
+ NetLog_Direct("Error: Malformed OFT2 Frame, ignoring.");
+ return;
+ }
+
+ unpackLEDWord(&pBuffer, &dwID1);
+ wLen -= 4;
+ unpackLEDWord(&pBuffer, &dwID2);
+ wLen -= 4;
+
+ if (datatype == OFT_TYPE_REQUEST && !oc->ft->initalized)
+ { // first request does not contain MsgIDs we need to send them in ready packet
+ dwID1 = oc->ft->pMessage.dwMsgID1;
+ dwID2 = oc->ft->pMessage.dwMsgID2;
+ }
+
+ if (oc->ft->pMessage.dwMsgID1 != dwID1 || oc->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
+ oscar_filetransfer *ft = oc->ft;
+ char *szFullPath;
+
+ // Read Frame data
+ if (!ft->initalized)
+ {
+ unpackWord(&pBuffer, &ft->wEncrypt);
+ unpackWord(&pBuffer, &ft->wCompress);
+ unpackWord(&pBuffer, &ft->wFilesCount);
+ }
+ else
+ pBuffer += 6;
+ unpackWord(&pBuffer, &ft->wFilesLeft);
+ ft->iCurrentFile = ft->wFilesCount - oc->ft->wFilesLeft;
+ if (!ft->initalized)
+ unpackWord(&pBuffer, &ft->wPartsCount);
+ else
+ pBuffer += 2;
+ unpackWord(&pBuffer, &ft->wPartsLeft);
+ if (!ft->initalized)
+ unpackDWord(&pBuffer, &ft->dwTotalSize);
+ else
+ pBuffer += 4;
+ unpackDWord(&pBuffer, &ft->dwThisFileSize);
+ unpackDWord(&pBuffer, &ft->dwThisFileDate);
+ unpackDWord(&pBuffer, &ft->dwThisFileCheck);
+ unpackDWord(&pBuffer, &ft->dwRecvForkCheck);
+ unpackDWord(&pBuffer, &ft->dwThisForkSize);
+ unpackDWord(&pBuffer, &ft->dwThisFileCreation);
+ unpackDWord(&pBuffer, &ft->dwThisForkCheck);
+ unpackDWord(&pBuffer, &ft->dwBytesDone);
+ unpackDWord(&pBuffer, &ft->dwRecvFileCheck);
+ if (!ft->initalized)
+ unpackString(&pBuffer, ft->rawIDString, 32);
+ else
+ pBuffer += 32;
+ unpackByte(&pBuffer, &ft->bHeaderFlags);
+ unpackByte(&pBuffer, &ft->bNameOff);
+ unpackByte(&pBuffer, &ft->bSizeOff);
+ if (!ft->initalized)
+ {
+ unpackString(&pBuffer, ft->rawDummy, 69);
+ unpackString(&pBuffer, ft->rawMacInfo, 16);
+ }
+ else
+ pBuffer += 85;
+ unpackWord(&pBuffer, &ft->wEncoding);
+ unpackWord(&pBuffer, &ft->wSubEncoding);
+ ft->cbRawFileName = wLen - 184;
+ SAFE_FREE(&ft->rawFileName); // release previous buffers
+ SAFE_FREE(&ft->szThisFile);
+ ft->rawFileName = (char*)SAFE_MALLOC(ft->cbRawFileName);
+ unpackString(&pBuffer, ft->rawFileName, ft->cbRawFileName);
+ // Prepare file
+ if (ft->wEncoding == 2)
+ { // FIX ME: this is bad
+ ft->szThisFile = ApplyEncoding(ft->rawFileName, "unicode-2-0");
+ // FIX ME: need to convert dir markings
+ }
+ else
+ {
+ DWORD i;
+
+ ft->szThisFile = null_strdup(ft->rawFileName);
+
+ for (i = 0; i < strlennull(ft->szThisFile); i++)
+ { // convert dir markings to normal backslashes
+ if (ft->szThisFile[i] == 0x01) ft->szThisFile[i] = '\\';
+ }
+ }
+
+ ft->initalized = 1; // First Frame Processed
+
+ NetLog_Direct("File '%s', %d Bytes", ft->szThisFile, ft->dwThisFileSize);
+
+ { // Prepare Path Information
+ char* szFile = strrchr(ft->szThisFile, '\\');
+
+ SAFE_FREE(&ft->szThisSubdir); // release previous path
+ if (szFile)
+ {
+ char *szNewDir;
+
+ ft->szThisSubdir = ft->szThisFile;
+ szFile[0] = '\0'; // split that strings
+ ft->szThisFile = null_strdup(szFile + 1);
+ // no cheating with paths
+ if (strstr(ft->szThisSubdir, "..\\") || strstr(ft->szThisSubdir, "../") ||
+ strstr(ft->szThisSubdir, ":\\") || strstr(ft->szThisSubdir, ":/") ||
+ ft->szThisSubdir[0] == '\\' || ft->szThisSubdir[0] == '/')
+ {
+ NetLog_Direct("Invalid path information");
+ break;
+ }
+ szNewDir = (char*)_alloca(strlennull(ft->szSavePath)+strlennull(ft->szThisSubdir)+2);
+ strcpy(szNewDir, ft->szSavePath);
+ NormalizeBackslash(szNewDir);
+ strcat(szNewDir, ft->szThisSubdir);
+ _mkdir(szNewDir); // FIX ME: this will fail for multi sub-sub-sub-dirs at once
+ }
+ else
+ ft->szThisSubdir = null_strdup("");
+ }
+
+ /* no cheating with paths */
+ if (strstr(ft->szThisFile, "..\\") || strstr(ft->szThisFile, "../") ||
+ strstr(ft->szThisFile, ":\\") || strstr(ft->szThisFile, ":/") ||
+ ft->szThisFile[0] == '\\' || ft->szThisFile[0] == '/')
+ {
+ NetLog_Direct("Invalid path information");
+ break;
+ }
+ szFullPath = (char*)SAFE_MALLOC(strlennull(ft->szSavePath)+strlennull(ft->szThisSubdir)+strlennull(ft->szThisFile)+3);
+ strcpy(szFullPath, ft->szSavePath);
+ NormalizeBackslash(szFullPath);
+ strcat(szFullPath, ft->szThisSubdir);
+ NormalizeBackslash(szFullPath);
+ _chdir(szFullPath); // set current dir - not very useful
+ strcat(szFullPath, ft->szThisFile);
+ // we joined the full path to dest file
+ SAFE_FREE(&ft->szThisFile);
+ ft->szThisFile = szFullPath;
+
+ ft->dwFileBytesDone = 0;
+
+ {
+ /* file resume */
+ PROTOFILETRANSFERSTATUS pfts = {0};
+
+ oft_buildProtoFileTransferStatus(ft, &pfts);
+ if (ICQBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, ft, (LPARAM)&pfts))
+ break; /* UI supports resume: it will call PS_FILERESUME */
+
+ // TODO: Unicode support
+ ft->fileId = _open(ft->szThisFile, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE);
+ if (ft->fileId == -1)
+ { // FIX ME: this needs some UI interaction
+ icq_LogMessage(LOG_ERROR, "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.");
+ CloseOscarConnection(oc);
+ return;
+ }
+ }
+ // Send "we are ready"
+ oc->status = OCS_DATA;
+
+ sendOFT2FramePacket(oc, OFT_TYPE_READY);
+ ICQBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0);
+ if (!ft->dwThisFileSize)
+ { // if the file is empty we will not receive any data
+ BYTE buf;
+
+ oft_handleFileData(oc, &buf, 0);
+ }
+ return;
+ }
+ }
+}
+
+
+//
+// Direct packets
+/////////////////////////////
+
+static void oft_sendPeerInit(oscar_connection *oc)
+{
+ // prepare init frame
+
+ // sendOFT2FramePacket(oc, OFT_TYPE_REQUEST);
+}
+
+
+
+static void 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, ft->dwTotalSize);
+ packDWord(&packet, ft->dwThisFileSize);
+ 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, ft->dwBytesDone);
+ packDWord(&packet, ft->dwRecvFileCheck);
+ packBuffer(&packet, 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, ft->rawFileName, ft->cbRawFileName);
+
+ sendOscarPacket(oc, &packet);
+} \ No newline at end of file
diff --git a/miranda-wine/protocols/IcqOscarJ/oscar_filetransfer.h b/miranda-wine/protocols/IcqOscarJ/oscar_filetransfer.h
new file mode 100644
index 0000000..ddb0c59
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/oscar_filetransfer.h
@@ -0,0 +1,155 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/oscar_filetransfer.h,v $
+// Revision : $Revision: 3709 $
+// Last change on : $Date: 2006-09-06 02:09:00 +0400 (Срд, 06 Сен 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#ifndef __OSCAR_FILETRANSFER_H
+#define __OSCAR_FILETRANSFER_H
+
+
+void InitOscarFileTransfer();
+void UninitOscarFileTransfer();
+
+
+#define FT_MAGIC_ICQ 0x00
+#define FT_MAGIC_OSCAR 0x4F
+
+typedef struct {
+ BYTE ft_magic;
+ message_cookie_data pMessage;
+} basic_filetransfer;
+
+typedef struct {
+ BYTE ft_magic;
+ message_cookie_data pMessage;
+ HANDLE hContact;
+ int initalized;
+ int sending;
+ char **files; // sending only
+ int iCurrentFile;
+ int currentIsDir;
+ int bUseProxy;
+ DWORD dwProxyIP;
+ DWORD dwRemoteInternalIP;
+ DWORD dwRemoteExternalIP;
+ DWORD dwRemotePort;
+ char *szSavePath;
+ char *szDescription;
+ char *szFilename;
+ char *szThisFile;
+ char *szThisSubdir;
+ // OFT2 header data
+ WORD wEncrypt, wCompress;
+ WORD wFilesCount,wFilesLeft;
+ WORD wPartsCount, wPartsLeft;
+ DWORD dwTotalSize;
+ DWORD dwThisFileSize;
+ DWORD dwThisFileDate; // modification date
+ DWORD dwThisFileCheck;
+ DWORD dwRecvForkCheck, dwThisForkSize;
+ DWORD dwThisFileCreation; // creation date (not used)
+ DWORD dwThisForkCheck;
+ DWORD dwBytesDone;
+ DWORD dwRecvFileCheck;
+ char rawIDString[32];
+ BYTE bHeaderFlags;
+ BYTE bNameOff, bSizeOff;
+ BYTE rawDummy[69];
+ BYTE rawMacInfo[16];
+ WORD wEncoding, wSubEncoding;
+ WORD cbRawFileName;
+ char *rawFileName;
+ char *ThisFileName;
+ // helper data
+ DWORD dwFileBytesDone;
+ int fileId;
+ void* connection;
+ void* listener;
+ DWORD dwLastNotify;
+} oscar_filetransfer;
+
+#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);
+
+typedef struct {
+ HANDLE hContact;
+ HANDLE hConnection;
+ int status;
+ DWORD dwUin;
+ uid_str szUid;
+ DWORD dwLocalInternalIP;
+ DWORD dwLocalExternalIP;
+ int type;
+ int incoming;
+ oscar_filetransfer *ft;
+ int wantIdleTime;
+} oscar_connection;
+
+#define OCT_NORMAL 0
+#define OCT_REVERSE 1
+#define OCT_PROXY 2
+#define OCT_CLOSING 10
+
+#define OCS_READY 0
+#define OCS_CONNECTED 1
+#define OCS_NEGOTIATION 2
+#define OCS_DATA 4
+
+typedef struct {
+ WORD wPort;
+ HANDLE hBoundPort;
+ oscar_filetransfer* ft;
+} oscar_listener;
+
+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);
+
+void handleRecvServMsgOFT(unsigned char *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwID1, DWORD dwID2, WORD wCommand);
+
+DWORD oftFileAllow(HANDLE hContact, WPARAM wParam, LPARAM lParam);
+DWORD oftFileDeny(HANDLE hContact, WPARAM wParam, LPARAM lParam);
+DWORD oftFileCancel(HANDLE hContact, WPARAM wParam, LPARAM lParam);
+
+void oftFileResume(oscar_filetransfer *ft, int action, const char *szFilename);
+
+#endif /* __OSCAR_FILETRANSFER_H */ \ No newline at end of file
diff --git a/miranda-wine/protocols/IcqOscarJ/resource.h b/miranda-wine/protocols/IcqOscarJ/resource.h
new file mode 100644
index 0000000..475d26b
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/resource.h
@@ -0,0 +1,207 @@
+//{{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_INFO_AVATAR 106
+#define IDD_OPT_ICQMAIN 107
+#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_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 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_OPTIONSTAB 500
+#define IDC_LOG 1001
+#define IDI_EXPANDSTRINGEDIT 1001
+#define IDC_SAVEPASS 1004
+#define IDC_RETRXSTATUS 1005
+#define IDC_SECURE 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_AVATAR 1023
+#define IDC_SETAVATAR 1024
+#define IDC_DELETEAVATAR 1025
+#define IDC_AIMENABLE 1030
+#define IDC_CLIST 1035
+#define IDC_XSTATUSENABLE 1040
+#define IDC_XSTATUSAUTO 1041
+#define IDC_XSTATUSRESET 1042
+#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_LINKAVATARS 1531
+#define IDC_ADDSERVER 1532
+#define IDC_SAVETOSERVER 1533
+#define IDC_ENABLEAVATARS 1536
+#define IDC_AUTOLOADAVATARS 1537
+#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 111
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1026
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/miranda-wine/protocols/IcqOscarJ/resources.rc b/miranda-wine/protocols/IcqOscarJ/resources.rc
new file mode 100644
index 0000000..afb1a16
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/resources.rc
@@ -0,0 +1,716 @@
+//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_ICQ ICON DISCARDABLE "icos\\icq.ico"
+IDI_AUTH_ASK ICON DISCARDABLE "icos\\auth_ask.ico"
+IDI_AUTH_GRANT ICON DISCARDABLE "icos\\auth_grant.ico"
+IDI_AUTH_REVOKE ICON DISCARDABLE "icos\\auth_revoke.ico"
+IDI_EXPANDSTRINGEDIT ICON DISCARDABLE "changeinfo\\expandst.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ICQACCOUNT DIALOGEX 0, 0, 200, 101
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "ICQ Account Setup"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ EDITTEXT IDC_UIN,91,34,102,13,ES_AUTOHSCROLL
+ EDITTEXT IDC_PW,91,54,102,13,ES_PASSWORD | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,87,80,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,143,80,50,14
+ CONTROL "Create new account",IDC_REGISTER,"Hyperlink",WS_TABSTOP,
+ 7,82,74,10
+ LTEXT "Please enter your ICQ account details to continue:",
+ IDC_STATIC,7,9,186,20
+ LTEXT "ICQ number:",IDC_STATIC,21,37,65,8
+ LTEXT "Password:",IDC_STATIC,21,57,66,8
+END
+
+IDD_ASKAUTH DIALOGEX 0, 0, 186, 95
+STYLE DS_MODALFRAME | 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, 68
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Enter ICQ Password"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ EDITTEXT IDC_LOGINPW,17,16,122,14,ES_PASSWORD | ES_AUTOHSCROLL
+ CONTROL "Remember this session password",IDC_SAVEPASS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,19,33,120,10
+ DEFPUSHBUTTON "OK",IDOK,25,48,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,82,48,50,14
+ LTEXT "Enter a password for UIN %d:",IDC_INSTRUCTION,7,7,142,8
+END
+
+IDD_OPT_ICQMAIN DIALOGEX 0, 0, 318, 252
+STYLE DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "",IDC_OPTIONSTAB,"SysTabControl32",WS_TABSTOP,1,1,316,250
+END
+
+IDD_OPT_ICQ DIALOGEX 0, 0, 314, 236
+STYLE 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,306,95
+ RTEXT "ICQ number:",IDC_STATIC11,12,14,51,8
+ EDITTEXT IDC_ICQNUM,68,12,106,12,ES_AUTOHSCROLL | ES_NUMBER
+ 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,290,19
+ CONTROL "Retrieve a lost password or ICQ number",IDC_LOOKUPLINK,
+ "Hyperlink",WS_TABSTOP,12,78,290,8
+ CONTROL "Create a new ICQ account using the ICQ website",
+ IDC_NEWUINLINK,"Hyperlink",WS_TABSTOP,12,66,290,8
+ GROUPBOX "Connection settings",IDC_STATIC,4,96,306,136
+ LTEXT "Login Server:",IDC_STATIC,12,110,55,8
+ EDITTEXT IDC_ICQSERVER,68,108,106,12,ES_AUTOHSCROLL
+ LTEXT "Port:",IDC_STATIC,182,110,25,8
+ EDITTEXT IDC_ICQPORT,208,108,29,12,ES_AUTOHSCROLL
+ PUSHBUTTON "Default",IDC_RESETSERVER,244,108,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,125,290,19
+ CONTROL "Secure (MD5) login",IDC_SECURE,"Button",BS_AUTOCHECKBOX |
+ BS_TOP | WS_TABSTOP,12,154,290,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,168,290,18
+ CONTROL "Ignore concurrent error messages",IDC_NOERRMULTI,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,12,192,290,10
+ LTEXT "Show connection error messages:",IDC_STATIC,12,206,238,
+ 8
+ CONTROL "Slider1",IDC_LOGLEVEL,"msctls_trackbar32",TBS_BOTH |
+ TBS_NOTICKS | WS_TABSTOP,18,216,52,10
+ LTEXT "",IDC_LEVELDESCR,72,216,230,8,SS_NOPREFIX
+END
+
+IDD_OPT_ICQCONTACTS DIALOGEX 0, 0, 314, 228
+STYLE 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,306,
+ 99
+ 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,290,10
+ CONTROL "Add contacts to the server's list when I add them to mine",
+ IDC_ADDSERVER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,
+ 33,290,10
+ CONTROL "Update my contacts' details from the server *",
+ IDC_LOADFROMSERVER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 12,46,290,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,100,306,53
+ CONTROL "Enable avatar support",IDC_ENABLEAVATARS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,12,112,290,10
+ CONTROL "Load avatars automatically (like ICQ Lite)",
+ IDC_AUTOLOADAVATARS,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,12,124,290,10
+ CONTROL "Link avatars as contact photos (mToolTip photos)",
+ IDC_LINKAVATARS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,
+ 138,290,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,12,161,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,12,182,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,12,203,290,16
+END
+
+IDD_OPT_ICQFEATURES DIALOGEX 0, 0, 314, 236
+STYLE 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,306,94
+ CONTROL "Enable unicode messaging support",IDC_UTFENABLE,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,12,14,290,10
+ CONTROL "Send all messages in unicode if possible",IDC_UTFALL,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,26,290,10
+ RTEXT "Use this codepage for Ansi <-> Unicode translation :",
+ IDC_UTFSTATIC,12,40,174,10
+ COMBOBOX IDC_UTFCODEPAGE,190,38,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,290,10
+ CONTROL "Notify me when a message delivery has failed (recommended)",
+ IDC_SLOWSEND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,65,
+ 290,10
+ CONTROL "Use only server's acknowledgement (faster)",
+ IDC_ONLYSERVERACKS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 12,77,290,10
+ GROUPBOX "Peer-to-peer Messaging",IDC_STATIC,4,95,306,43
+ CONTROL "Enable peer-to-peer message connections",IDC_DCENABLE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,109,290,10
+ CONTROL "Passive mode, i.e. do not initiate new connections",
+ IDC_DCPASSIVE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,
+ 121,290,10
+ GROUPBOX "Extra Features",IDC_STATIC,4,139,306,93
+ CONTROL "Enable Custom status support",IDC_XSTATUSENABLE,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,12,153,145,10
+ CONTROL "Reset Custom status on status change",IDC_XSTATUSRESET,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,165,290,10
+ CONTROL "Auto-retrieve Custom status details",IDC_XSTATUSAUTO,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,177,290,10
+ CONTROL "Block known Spam Bots",IDC_KILLSPAMBOTS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,12,191,290,10
+ CONTROL "Enable AIM support",IDC_AIMENABLE,"Button",
+ BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,12,205,290,10
+ LTEXT "Note: The support is VERY limited, only messaging and status supported.",
+ IDC_STATIC,12,217,290,10,WS_DISABLED
+END
+
+IDD_OPT_ICQPRIVACY DIALOGEX 0, 0, 314, 240
+STYLE 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,7,7,300,78
+ LTEXT "Allowing direct connections will expose your IP address but may be necessary for some ICQ features to work properly.",
+ IDC_STATIC_DC2,13,19,292,17
+ CONTROL "Allow direct connections with any user",IDC_DCALLOW_ANY,
+ "Button",BS_AUTORADIOBUTTON,24,41,281,10
+ CONTROL "Allow direct connections with users on my contact list",
+ IDC_DCALLOW_CLIST,"Button",BS_AUTORADIOBUTTON,24,54,281,
+ 10
+ CONTROL "Allow direct connections only when I authorize or initiate them",
+ IDC_DCALLOW_AUTH,"Button",BS_AUTORADIOBUTTON |
+ WS_TABSTOP,24,67,281,10
+ GROUPBOX "Contact List Authorization",IDC_STATIC_CLIST,7,90,300,
+ 45,WS_GROUP
+ CONTROL "All users may add me to their Contact List",IDC_ADD_ANY,
+ "Button",BS_AUTORADIOBUTTON,24,104,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,24,
+ 118,281,10
+ CONTROL "Allow others to view my Online / Offline status from the web (Web Aware)",
+ IDC_WEBAWARE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,24,
+ 151,281,10
+ CONTROL "Allow others to view my primary e-mail address",
+ IDC_PUBLISHPRIMARY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 24,167,281,10
+ CONTROL "Only reply to status message requests from users on my contact list",
+ IDC_STATUSMSG_CLIST,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,24,183,281,10
+ CONTROL "Only reply to status message request from visible contacts",
+ IDC_STATUSMSG_VISIBLE,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,36,199,269,10
+ GROUPBOX "Misc Settings",IDC_STATIC,7,138,300,78
+ CTEXT "Some options are greyed out because they can only be changed when you are online.",
+ IDC_STATIC_NOTONLINE,7,222,300,8
+END
+
+IDD_OPT_POPUPS DIALOGEX 0, 0, 314, 251
+STYLE 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,81
+ 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,91,305,143
+ LTEXT "Back Color",IDC_STATIC,80,104,42,8
+ LTEXT "Text Color",IDC_STATIC,130,104,40,8
+ LTEXT "Timeout (*)",IDC_STATIC,182,104,60,8
+ LTEXT "Note",IDC_STATIC,12,116,60,8
+ CONTROL "",IDC_POPUP_LOG0_BACKCOLOR,"ColourPicker",WS_TABSTOP,80,
+ 115,39,10
+ CONTROL "",IDC_POPUP_LOG0_TEXTCOLOR,"ColourPicker",WS_TABSTOP,
+ 130,115,39,10
+ EDITTEXT IDC_POPUP_LOG0_TIMEOUT,182,114,34,12,ES_AUTOHSCROLL |
+ ES_NUMBER
+ LTEXT "Warning",IDC_STATIC,12,131,60,8
+ CONTROL "",IDC_POPUP_LOG1_BACKCOLOR,"ColourPicker",WS_TABSTOP,80,
+ 130,39,10
+ CONTROL "",IDC_POPUP_LOG1_TEXTCOLOR,"ColourPicker",WS_TABSTOP,
+ 130,130,39,10
+ EDITTEXT IDC_POPUP_LOG1_TIMEOUT,182,129,34,12,ES_AUTOHSCROLL |
+ ES_NUMBER
+ LTEXT "Error",IDC_STATIC,12,146,60,8
+ CONTROL "",IDC_POPUP_LOG2_BACKCOLOR,"ColourPicker",WS_TABSTOP,80,
+ 145,39,10
+ CONTROL "",IDC_POPUP_LOG2_TEXTCOLOR,"ColourPicker",WS_TABSTOP,
+ 130,145,39,10
+ EDITTEXT IDC_POPUP_LOG2_TIMEOUT,182,144,34,12,ES_AUTOHSCROLL |
+ ES_NUMBER
+ LTEXT "Fatal",IDC_STATIC,12,161,60,8
+ CONTROL "",IDC_POPUP_LOG3_BACKCOLOR,"ColourPicker",WS_TABSTOP,80,
+ 160,39,10
+ CONTROL "",IDC_POPUP_LOG3_TEXTCOLOR,"ColourPicker",WS_TABSTOP,
+ 130,160,39,10
+ EDITTEXT IDC_POPUP_LOG3_TIMEOUT,182,159,34,12,ES_AUTOHSCROLL |
+ ES_NUMBER
+ LTEXT "Spam detected",IDC_STATIC,12,176,60,8
+ CONTROL "",IDC_POPUP_SPAM_BACKCOLOR,"ColourPicker",WS_TABSTOP,80,
+ 175,39,10
+ CONTROL "",IDC_POPUP_SPAM_TEXTCOLOR,"ColourPicker",WS_TABSTOP,
+ 130,175,39,10
+ EDITTEXT IDC_POPUP_SPAM_TIMEOUT,182,174,34,12,ES_AUTOHSCROLL |
+ ES_NUMBER
+ CONTROL "&Use Windows colors",IDC_USEWINCOLORS,"Button",
+ BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,12,194,220,8
+ CONTROL "Use system &icons",IDC_USESYSICONS,"Button",
+ BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,12,207,220,8
+ DEFPUSHBUTTON "Previe&w",IDC_PREVIEW,247,203,52,12
+ LTEXT "(*) Timeouts require Popup v. 1.0.1.9 or later",
+ IDC_STATIC,12,221,232,8
+END
+
+IDD_INFO_ICQ DIALOGEX 0, 0, 222, 132
+STYLE 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_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",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,140,10
+END
+
+IDD_INFO_AVATAR DIALOGEX 0, 0, 222, 131
+STYLE DS_3DLOOK | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "",IDC_AVATAR,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ SS_SUNKEN,9,11,96,96
+ PUSHBUTTON "Set",IDC_SETAVATAR,9,112,45,13,NOT WS_VISIBLE
+ PUSHBUTTON "Delete",IDC_DELETEAVATAR,61,112,45,13,NOT WS_VISIBLE
+ LTEXT "Note: Only JPGs and GIFs\nImage size max 64x64\nFile size max 6kB",
+ IDC_STATIC,112,54,106,34,NOT WS_VISIBLE
+END
+
+IDD_ICQUPLOADLIST DIALOGEX 0, 0, 358, 241
+STYLE 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 | 0x2c8,5,14,155,
+ 222,WS_EX_CLIENTEDGE
+ DEFPUSHBUTTON "Synchronize",IDOK,238,222,56,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_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_STATIC,5,0,179,8
+ EDITTEXT IDC_XTITLE,5,9,179,13
+ LTEXT "Message:",IDC_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_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_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 DISCARDABLE
+BEGIN
+ IDD_ICQACCOUNT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 193
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 94
+ 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, 61
+ END
+
+ IDD_OPT_ICQ, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 310
+ VERTGUIDE, 12
+ VERTGUIDE, 174
+ VERTGUIDE, 302
+ TOPMARGIN, 4
+ HORZGUIDE, 120
+ END
+
+ IDD_OPT_ICQCONTACTS, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 310
+ VERTGUIDE, 12
+ VERTGUIDE, 302
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 224
+ END
+
+ IDD_OPT_ICQFEATURES, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 310
+ 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 DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""winres.h""\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 0,3,8,1
+ PRODUCTVERSION 0,6,0,0
+ 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\0"
+ VALUE "CompanyName", "\0"
+ VALUE "FileDescription", "ICQ protocol plugin for Miranda IM, enhanced\0"
+ VALUE "FileVersion", "0, 3, 8, 1\0"
+ VALUE "InternalName", "ICQJ protocol plugin for Miranda IM\0"
+ VALUE "LegalCopyright", "Copyright (C) 2000-2006 Joe Kucera, Angeli-Ka, Bio, Martin Öberg, Richard Hughes, Jon Keating\0"
+ VALUE "OriginalFilename", "ICQ.dll\0"
+ VALUE "ProductName", "ICQ Protocol Support\0"
+ VALUE "ProductVersion", "0, 6, 0, 0\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0, 1252
+ END
+END
+
+#endif // !_MAC
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/miranda-wine/protocols/IcqOscarJ/stdpackets.c b/miranda-wine/protocols/IcqOscarJ/stdpackets.c
new file mode 100644
index 0000000..4d0df1d
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/stdpackets.c
@@ -0,0 +1,1613 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/stdpackets.c,v $
+// Revision : $Revision: 3709 $
+// Last change on : $Date: 2006-09-06 02:09:00 +0400 (Срд, 06 Сен 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+
+extern int gbIdleAllow;
+extern WORD wListenPort;
+extern HANDLE hsmsgrequest;
+
+static DWORD sendTLVSearchPacket(BYTE bType, char *pSearchDataBuf, WORD wSearchType, WORD wInfoLen, BOOL bOnlineUsersOnly);
+
+
+
+/*****************************************************************************
+ *
+ * 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, char *szUID, WORD wFmt, WORD wLen)
+{
+ unsigned char nUinLen;
+
+ nUinLen = getUIDLen(dwUin, szUID);
+
+ serverPacketInit(p, (WORD)(21 + nUinLen + wLen));
+ packFNACHeaderFull(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, WORD wLen, WORD wType, WORD wSeq)
+{
+ serverPacketInit(p, (WORD)(24 + wLen));
+ packFNACHeaderFull(p, ICQ_EXTENSIONS_FAMILY, ICQ_META_CLI_REQ, 0, wSeq | ICQ_META_CLI_REQ<<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, dwLocalUIN); // My UIN
+ packLEWord(p, wType); // Request type
+ packWord(p, wSeq);
+}
+
+
+
+static void packServTLV5HeaderBasic(icq_packet *p, WORD wLen, DWORD ID1, DWORD ID2, WORD wCommand, 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_TLV2711_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, BOOL bEmpty)
+{
+ packTLVDWord(p, 0x03, bEmpty ? 0 : ICQGetContactSettingDword(NULL, "RealIP", 0)); // TLV: 0x03 DWORD IP
+ packTLVWord(p, 0x05, (WORD)(bEmpty ? 0 : wListenPort)); // TLV: 0x05 Listen port
+}
+
+
+
+static void packServChannel2Header(icq_packet *p, 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_TLV2711_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, FALSE);
+ }
+
+ packDWord(p, 0x000F0000); // TLV: 0x0F empty
+
+ packServTLV2711Header(p, (WORD)dwCookie, wVersion, bMsgType, bMsgFlags, (WORD)MirandaStatusToIcq(gnCurrentStatus), wPriority, wLen);
+}
+
+
+
+static void packServAdvancedMsgReply(icq_packet *p, DWORD dwUin, DWORD dwTimestamp, DWORD dwTimestamp2, WORD wCookie, BYTE bMsgType, BYTE bMsgFlags, WORD wLen)
+{
+ unsigned char nUinLen;
+
+ nUinLen = getUINLen(dwUin);
+
+ serverPacketInit(p, (WORD)(nUinLen + 74 + wLen));
+ packFNACHeaderFull(p, ICQ_MSG_FAMILY, ICQ_MSG_RESPONSE, 0, ICQ_MSG_RESPONSE<<0x10 | (wCookie & 0x7FFF));
+ packLEDWord(p, dwTimestamp); // Msg ID part 1
+ packLEDWord(p, dwTimestamp2); // Msg ID part 2
+ packWord(p, 0x02); // Channel
+ packUIN(p, dwUin); // Your UIN
+ packWord(p, 0x03); // Unknown
+ packLEWord(p, 0x1B); // Unknown
+ packByte(p, ICQ_VERSION); // 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 icq_sendCloseConnection()
+{
+ icq_packet packet;
+
+ packet.wLen = 0;
+ write_flap(&packet, ICQ_CLOSE_CHAN);
+ sendServPacket(&packet);
+}
+
+
+
+void icq_requestnewfamily(WORD wFamily, void (*familyhandler)(HANDLE hConn, char* cookie, WORD cookieLen))
+{
+ icq_packet packet;
+ DWORD dwIdent;
+ familyrequest_rec* request;
+
+ request = (familyrequest_rec*)SAFE_MALLOC(sizeof(familyrequest_rec));
+ request->wFamily = wFamily;
+ request->familyhandler = familyhandler;
+
+ dwIdent = AllocateCookie(CKT_SERVICEREQUEST, ICQ_CLIENT_NEW_SERVICE, 0, request); // generate and alloc cookie
+
+ serverPacketInit(&packet, 12);
+ packFNACHeaderFull(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_NEW_SERVICE, 0, dwIdent);
+ packWord(&packet, wFamily);
+
+ sendServPacket(&packet);
+}
+
+
+
+void icq_setidle(int bAllow)
+{
+ icq_packet packet;
+
+ if (bAllow!=gbIdleAllow)
+ {
+ /* 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);
+ }
+
+ sendServPacket(&packet);
+ gbIdleAllow = bAllow;
+ }
+}
+
+
+
+void icq_setstatus(WORD wStatus)
+{
+ icq_packet packet;
+
+ // Pack data in packet
+ serverPacketInit(&packet, 18);
+ 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
+
+ // Send packet
+ sendServPacket(&packet);
+}
+
+
+
+DWORD icq_SendChannel1Message(DWORD dwUin, char *szUID, HANDLE hContact, char *pszText, message_cookie_data *pCookieData)
+{
+ icq_packet packet;
+ WORD wMessageLen;
+ DWORD dwCookie;
+ WORD wPacketLength;
+
+
+ wMessageLen = strlennull(pszText);
+ dwCookie = AllocateCookie(CKT_MESSAGE, 0, dwUin, (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, 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 icq_SendChannel1MessageW(DWORD dwUin, char *szUID, HANDLE hContact, wchar_t *pszText, message_cookie_data *pCookieData)
+{
+ icq_packet packet;
+ WORD wMessageLen;
+ DWORD dwCookie;
+ WORD wPacketLength;
+ wchar_t* ppText;
+ int i;
+
+
+ wMessageLen = wcslen(pszText)*sizeof(wchar_t);
+ dwCookie = AllocateCookie(CKT_MESSAGE, 0, dwUin, (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; i<wMessageLen; i+=2, ppText++)
+ {
+ packWord(&packet, *ppText);
+ }
+
+ // 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 icq_SendChannel2Message(DWORD dwUin, const char *szMessage, int nBodyLen, WORD wPriority, message_cookie_data *pCookieData, char *szCap)
+{
+ icq_packet packet;
+ DWORD dwCookie;
+
+
+ dwCookie = AllocateCookie(CKT_MESSAGE, 0, dwUin, (void*)pCookieData);
+
+ // Pack the standard header
+ packServChannel2Header(&packet, 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, szMessage, (WORD)(nBodyLen+1)); // Message
+ packMsgColorInfo(&packet);
+
+ if (szCap)
+ {
+ packLEDWord(&packet, 0x00000026); // length of GUID
+ packBuffer(&packet, 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 icq_SendChannel4Message(DWORD dwUin, BYTE bMsgType, WORD wMsgLen, const char *szMsg, message_cookie_data *pCookieData)
+{
+ icq_packet packet;
+ WORD wPacketLength;
+ DWORD dwCookie;
+
+
+ dwCookie = AllocateCookie(CKT_MESSAGE, 0, dwUin, (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, dwLocalUIN); // My UIN
+ packByte(&packet, bMsgType); // Message type
+ packByte(&packet, 0); // Message flags
+ packLEWord(&packet, wMsgLen); // Message length
+ packBuffer(&packet, 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 sendOwnerInfoRequest(void)
+{
+ icq_packet packet;
+ DWORD dwCookie;
+ fam15_cookie_data *pCookieData = NULL;
+
+
+ pCookieData = SAFE_MALLOC(sizeof(fam15_cookie_data));
+ pCookieData->bRequestType = REQUESTTYPE_OWNER;
+ dwCookie = AllocateCookie(CKT_FAMILYSPECIAL, 0, dwLocalUIN, (void*)pCookieData);
+
+ packServIcqExtensionHeader(&packet, 6, 0x07D0, (WORD)dwCookie);
+ packLEWord(&packet, META_REQUEST_SELF_INFO);
+ packLEDWord(&packet, dwLocalUIN);
+
+ sendServPacket(&packet);
+}
+
+
+
+void sendUserInfoAutoRequest(DWORD dwUin)
+{
+ icq_packet packet;
+ DWORD dwCookie;
+ fam15_cookie_data *pCookieData = NULL;
+
+
+ pCookieData = SAFE_MALLOC(sizeof(fam15_cookie_data));
+ pCookieData->bRequestType = REQUESTTYPE_USERAUTO;
+ dwCookie = AllocateCookie(CKT_FAMILYSPECIAL, 0, dwUin, (void*)pCookieData);
+
+ packServIcqExtensionHeader(&packet, 6, 0x07D0, (WORD)dwCookie);
+ packLEWord(&packet, META_REQUEST_SHORT_INFO);
+ packLEDWord(&packet, dwUin);
+
+ sendServPacket(&packet);
+}
+
+
+
+DWORD icq_sendGetInfoServ(DWORD dwUin, int bMinimal)
+{
+ icq_packet packet;
+ DWORD dwCookie;
+ fam15_cookie_data *pCookieData = NULL;
+
+ // we request if we can or 10sec after last request
+ if (gbOverRate && (GetTickCount()-gtLastRequest)<10000) return 0;
+ gbOverRate = 0;
+ gtLastRequest = GetTickCount();
+
+ pCookieData = SAFE_MALLOC(sizeof(fam15_cookie_data));
+ dwCookie = AllocateCookie(CKT_FAMILYSPECIAL, 0, dwUin, (void*)pCookieData);
+
+ packServIcqExtensionHeader(&packet, 6, CLI_META_INFO_REQ, (WORD)dwCookie);
+ if (bMinimal)
+ {
+ pCookieData->bRequestType = REQUESTTYPE_USERMINIMAL;
+ packLEWord(&packet, META_REQUEST_SHORT_INFO);
+ }
+ else
+ {
+ pCookieData->bRequestType = REQUESTTYPE_USERDETAILED;
+ packLEWord(&packet, META_REQUEST_FULL_INFO);
+ }
+ packLEDWord(&packet, dwUin);
+
+ sendServPacket(&packet);
+
+ return dwCookie;
+}
+
+
+
+DWORD icq_sendGetAimProfileServ(HANDLE hContact, char* szUid)
+{
+ icq_packet packet;
+ DWORD dwCookie;
+ fam15_cookie_data *pCookieData = NULL;
+ BYTE bUIDlen = strlennull(szUid);
+
+ pCookieData = SAFE_MALLOC(sizeof(fam15_cookie_data));
+ dwCookie = AllocateCookie(CKT_FAMILYSPECIAL, ICQ_LOCATION_REQ_USER_INFO, 0, (void*)pCookieData);
+ pCookieData->bRequestType = REQUESTTYPE_PROFILE;
+ pCookieData->hContact = hContact;
+
+ serverPacketInit(&packet, (WORD)(13 + bUIDlen));
+ packFNACHeaderFull(&packet, ICQ_LOCATION_FAMILY, ICQ_LOCATION_REQ_USER_INFO, 0, dwCookie);
+ packWord(&packet, 0x01); // request profile info
+ packByte(&packet, bUIDlen);
+ packBuffer(&packet, szUid, bUIDlen);
+
+ sendServPacket(&packet);
+
+ return dwCookie;
+}
+
+
+
+DWORD icq_sendGetAwayMsgServ(DWORD dwUin, int type, WORD wVersion)
+{
+ icq_packet packet;
+ DWORD dwCookie;
+ message_cookie_data *pCookieData = NULL;
+
+ // we request if we can or 10sec after last request
+ if (gbOverRate && (GetTickCount()-gtLastRequest)<10000) return 0;
+ gbOverRate = 0;
+ gtLastRequest = GetTickCount();
+
+ pCookieData = CreateMessageCookie(MTYPE_AUTOAWAY, (BYTE)type);
+ dwCookie = AllocateCookie(CKT_MESSAGE, 0, dwUin, (void*)pCookieData);
+
+ packServChannel2Header(&packet, dwUin, 3, pCookieData->dwMsgID1, pCookieData->dwMsgID2, dwCookie, wVersion, (BYTE)type, 3, 1, 0, 0, 0);
+ packEmptyMsg(&packet); // Message
+ sendServPacket(&packet);
+
+ return dwCookie;
+}
+
+
+
+DWORD icq_sendGetAimAwayMsgServ(char *szUID, int type)
+{
+ icq_packet packet;
+ DWORD dwCookie;
+ message_cookie_data *pCookieData = NULL;
+ BYTE bUIDlen = strlennull(szUID);
+
+ pCookieData = CreateMessageCookie(MTYPE_AUTOAWAY, (byte)type);
+ dwCookie = AllocateCookie(CKT_MESSAGE, 0, 0, (void*)pCookieData);
+
+ serverPacketInit(&packet, (WORD)(13 + bUIDlen));
+ packFNACHeaderFull(&packet, ICQ_LOCATION_FAMILY, ICQ_LOCATION_REQ_USER_INFO, 0, dwCookie);
+ packWord(&packet, 0x03);
+ packByte(&packet, bUIDlen);
+ packBuffer(&packet, szUID, bUIDlen);
+
+ sendServPacket(&packet);
+
+ return dwCookie;
+}
+
+
+
+void icq_sendSetAimAwayMsgServ(char *szMsg)
+{
+ icq_packet packet;
+ DWORD dwCookie;
+ WORD wMsgLen = strlennull(szMsg);
+
+ dwCookie = GenerateCookie(ICQ_LOCATION_SET_USER_INFO);
+
+ if (wMsgLen > 0x1000) wMsgLen = 0x1000; // limit length
+ serverPacketInit(&packet, (WORD)(51 + wMsgLen));
+ packFNACHeaderFull(&packet, ICQ_LOCATION_FAMILY, ICQ_LOCATION_SET_USER_INFO, 0, dwCookie);
+ packTLV(&packet, 0x03, 0x21, "text/x-aolrtf; charset=\"utf-8\"");
+ packTLV(&packet, 0x04, wMsgLen, szMsg);
+
+ sendServPacket(&packet);
+}
+
+
+
+void icq_sendFileSendServv7(filetransfer* ft, const char *szFiles)
+{
+ icq_packet packet;
+ WORD wDescrLen,wFilesLen;
+
+ wDescrLen = strlennull(ft->szDescription);
+ wFilesLen = strlennull(szFiles);
+
+ packServChannel2Header(&packet, 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, ft->szDescription, (WORD)(wDescrLen + 1));
+ packLEDWord(&packet, 0); // unknown
+ packLEWord(&packet, (WORD)(wFilesLen + 1));
+ packBuffer(&packet, szFiles, (WORD)(wFilesLen + 1));
+ packLEDWord(&packet, ft->dwTotalSize);
+ packLEDWord(&packet, 0); // unknown
+
+ sendServPacket(&packet);
+}
+
+
+
+void icq_sendFileSendServv8(filetransfer* ft, const char *szFiles, int nAckType)
+{
+ icq_packet packet;
+ WORD wFlapLen;
+ WORD wDescrLen,wFilesLen;
+
+ wDescrLen = strlennull(ft->szDescription);
+ wFilesLen = strlennull(szFiles);
+
+ // 202 + UIN len + file description (no null) + file name (null included)
+ // Packet size = Flap length + 4
+ 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, FALSE);
+
+ // TLV(0x2711) header
+ packServTLV2711Header(&packet, (WORD)ft->dwCookie, ICQ_VERSION, MTYPE_PLUGIN, 0, (WORD)MirandaStatusToIcq(gnCurrentStatus), 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, ft->szDescription, wDescrLen);
+ packWord(&packet, 0x8c82); // Unknown (port?), seen 0x80F6
+ packWord(&packet, 0x0222); // Unknown, seen 0x2e01
+ packLEWord(&packet, (WORD)(wFilesLen + 1));
+ packBuffer(&packet, szFiles, (WORD)(wFilesLen + 1));
+ packLEDWord(&packet, ft->dwTotalSize);
+ packLEDWord(&packet, 0x0008c82); // Unknown, (seen 0xf680 ~33000)
+
+ // Pack request server ack TLV
+ if (nAckType == ACKTYPE_SERVER)
+ {
+ packDWord(&packet, 0x00030000); // TLV(3)
+ }
+
+ // Send the monster
+ sendServPacket(&packet);
+}
+
+
+
+/* also sends rejections */
+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)
+{
+ icq_packet packet;
+ WORD wFlapLen;
+ WORD wDescrLen,wFilesLen;
+
+ /* if !accepted, szDescr == szReason, szFiles = "" */
+
+ if (!accepted) szFiles = "";
+
+ wDescrLen = strlennull(szDescr);
+ wFilesLen = strlennull(szFiles);
+
+ // 202 + UIN len + file description (no null) + file name (null included)
+ // Packet size = Flap length + 4
+ 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, !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, szDescr, wDescrLen);
+ packWord(&packet, wPort); // Port
+ packWord(&packet, 0x00); // Unknown
+ packLEWord(&packet, (WORD)(wFilesLen + 1));
+ packBuffer(&packet, szFiles, (WORD)(wFilesLen + 1));
+ packLEDWord(&packet, dwTotalSize);
+ packLEDWord(&packet, (DWORD)wPort); // Unknown
+
+ // Pack request server ack TLV
+ if (nAckType == ACKTYPE_SERVER)
+ {
+ packDWord(&packet, 0x00030000); // TLV(3)
+ }
+
+ // Send the monster
+ sendServPacket(&packet);
+}
+
+
+
+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)
+{
+ icq_packet packet;
+ WORD wFlapLen;
+ WORD wDescrLen,wFilesLen;
+
+ /* if !accepted, szDescr == szReason, szFiles = "" */
+
+ if (!accepted) szFiles = "";
+
+ wDescrLen = strlennull(szDescr);
+ wFilesLen = strlennull(szFiles);
+
+ // 150 + UIN len + file description (with null) + file name (2 nulls)
+ // Packet size = Flap length + 4
+ 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, !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, szDescr, (WORD)(wDescrLen + 1));
+ packWord(&packet, wPort); // Port
+ packWord(&packet, 0x00); // Unknown
+ packLEWord(&packet, (WORD)(wFilesLen + 2));
+ packBuffer(&packet, szFiles, (WORD)(wFilesLen + 1));
+ packByte(&packet, 0);
+ packLEDWord(&packet, dwTotalSize);
+ packLEDWord(&packet, (DWORD)wPort); // Unknown
+
+ // Pack request server ack TLV
+ if (nAckType == ACKTYPE_SERVER)
+ {
+ packDWord(&packet, 0x00030000); // TLV(3)
+ }
+
+ // Send the monster
+ sendServPacket(&packet);
+}
+
+
+
+void 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 icq_sendFileDenyServ(DWORD dwUin, filetransfer* ft, 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 icq_sendAwayMsgReplyServ(DWORD dwUin, DWORD dwMsgID1, DWORD dwMsgID2, WORD wCookie, WORD wVersion, BYTE msgType, const char** szMsg)
+{
+ icq_packet packet;
+ WORD wMsgLen;
+ char* pszMsg;
+ HANDLE hContact;
+
+
+ hContact = HContactFromUIN(dwUin, NULL);
+
+ if (validateStatusMessageRequest(hContact, msgType))
+ {
+ NotifyEventHooks(hsmsgrequest, (WPARAM)msgType, (LPARAM)dwUin);
+
+ EnterCriticalSection(&modeMsgsMutex);
+
+ if (szMsg && *szMsg)
+ {
+ char* szAnsiMsg = NULL;
+
+ if (wVersion == 9 && ICQ_VERSION == 9)
+ pszMsg = (char*)*szMsg;
+ else
+ { // only v9 protocol supports UTF-8 mode messagees
+ wMsgLen = strlennull(*szMsg) + 1;
+ szAnsiMsg = (char*)_alloca(wMsgLen);
+ utf8_decode_static(*szMsg, szAnsiMsg, wMsgLen);
+ pszMsg = szAnsiMsg;
+ }
+
+ wMsgLen = strlennull(pszMsg);
+
+ // limit msg len to max snac size - we get disconnected if exceeded
+ if (wMsgLen > MAX_MESSAGESNACSIZE)
+ wMsgLen = MAX_MESSAGESNACSIZE;
+
+ packServAdvancedMsgReply(&packet, dwUin, dwMsgID1, dwMsgID2, wCookie, msgType, 3, (WORD)(wMsgLen + 3));
+ packLEWord(&packet, (WORD)(wMsgLen + 1));
+ packBuffer(&packet, pszMsg, wMsgLen);
+ packByte(&packet, 0);
+
+ sendServPacket(&packet);
+ }
+
+ LeaveCriticalSection(&modeMsgsMutex);
+ }
+}
+
+
+
+void icq_sendAdvancedMsgAck(DWORD dwUin, DWORD dwTimestamp, DWORD dwTimestamp2, WORD wCookie, BYTE bMsgType, BYTE bMsgFlags)
+{
+ icq_packet packet;
+
+ packServAdvancedMsgReply(&packet, dwUin, dwTimestamp, dwTimestamp2, wCookie, bMsgType, bMsgFlags, 11);
+ packEmptyMsg(&packet); // Status message
+ packMsgColorInfo(&packet);
+
+ sendServPacket(&packet);
+}
+
+
+
+// Searches
+
+DWORD SearchByUin(DWORD dwUin)
+{
+ DWORD dwCookie;
+ WORD wInfoLen;
+ icq_packet pBuffer; // I reuse the ICQ packet type as a generic buffer
+ // I should be ashamed! ;)
+
+ // Calculate data size
+ wInfoLen = 8;
+
+ // Initialize our handy data buffer
+ pBuffer.wPlace = 0;
+ pBuffer.pData = (BYTE *)_alloca(wInfoLen);
+ pBuffer.wLen = wInfoLen;
+
+ // Initialize our handy data buffer
+ packLEWord(&pBuffer, TLV_UIN);
+ packLEWord(&pBuffer, 0x0004);
+ packLEDWord(&pBuffer, dwUin);
+
+ // Send it off for further packing
+ dwCookie = sendTLVSearchPacket(SEARCHTYPE_UID, pBuffer.pData, META_SEARCH_UIN, wInfoLen, FALSE);
+
+ return dwCookie;
+}
+
+
+
+DWORD SearchByNames(char* pszNick, char* pszFirstName, char* pszLastName)
+{ // use generic TLV search like icq5 does
+ DWORD dwCookie;
+ WORD wInfoLen = 0;
+ WORD wNickLen,wFirstLen,wLastLen;
+ BYTE *pBuffer;
+ int pBufferPos;
+
+ wNickLen = strlennull(pszNick);
+ wFirstLen = strlennull(pszFirstName);
+ wLastLen = strlennull(pszLastName);
+
+ _ASSERTE(wFirstLen || wLastLen || wNickLen);
+
+
+ // Calculate data size
+ if (wFirstLen > 0)
+ wInfoLen = wFirstLen + 7;
+ if (wLastLen > 0)
+ wInfoLen += wLastLen + 7;
+ if (wNickLen > 0)
+ wInfoLen += wNickLen + 7;
+
+ // Initialize our handy data buffer
+ pBuffer = (BYTE*)_alloca(wInfoLen);
+ pBufferPos = 0;
+
+ // Pack the search details
+ if (wFirstLen > 0)
+ {
+ packTLVLNTS(&pBuffer, &pBufferPos, pszFirstName, TLV_FIRSTNAME);
+ }
+
+ if (wLastLen > 0)
+ {
+ packTLVLNTS(&pBuffer, &pBufferPos, pszLastName, TLV_LASTNAME);
+ }
+
+ if (wNickLen > 0)
+ {
+ packTLVLNTS(&pBuffer, &pBufferPos, pszNick, TLV_NICKNAME);
+ }
+
+ // Send it off for further packing
+ dwCookie = sendTLVSearchPacket(SEARCHTYPE_NAMES, pBuffer, META_SEARCH_GENERIC, wInfoLen, FALSE);
+
+ return dwCookie;
+}
+
+
+
+DWORD SearchByEmail(char* pszEmail)
+{
+ DWORD dwCookie;
+ 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
+ packTLVLNTS(&pBuffer, &pBufferPos, pszEmail, TLV_EMAIL);
+
+ // Send it off for further packing
+ dwCookie = sendTLVSearchPacket(SEARCHTYPE_EMAIL, pBuffer, META_SEARCH_EMAIL, wInfoLen, FALSE);
+ }
+
+ return dwCookie;
+}
+
+
+
+DWORD sendTLVSearchPacket(BYTE bType, char* pSearchDataBuf, WORD wSearchType, WORD wInfoLen, BOOL bOnlineUsersOnly)
+{
+ icq_packet packet;
+ DWORD dwCookie;
+ search_cookie* pCookie;
+
+ _ASSERTE(pSearchDataBuf);
+ _ASSERTE(wInfoLen >= 4);
+
+ pCookie = (search_cookie*)SAFE_MALLOC(sizeof(search_cookie));
+ if (pCookie)
+ {
+ pCookie->bSearchType = bType;
+ dwCookie = AllocateCookie(CKT_SEARCH, 0, 0, pCookie);
+ }
+ else
+ return 0;
+
+ // Pack headers
+ packServIcqExtensionHeader(&packet, (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, 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 icq_sendAdvancedSearchServ(BYTE* fieldsBuffer,int bufferLen)
+{
+ icq_packet packet;
+ DWORD dwCookie;
+ search_cookie* pCookie;
+
+ pCookie = (search_cookie*)SAFE_MALLOC(sizeof(search_cookie));
+ if (pCookie)
+ {
+ pCookie->bSearchType = SEARCHTYPE_DETAILS;
+ dwCookie = AllocateCookie(CKT_SEARCH, 0, 0, pCookie);
+ }
+ else
+ return 0;
+
+ packServIcqExtensionHeader(&packet, (WORD)(2 + bufferLen), CLI_META_INFO_REQ, (WORD)dwCookie);
+ packBuffer(&packet, (const char*)fieldsBuffer, (WORD)bufferLen);
+
+ sendServPacket(&packet);
+
+ return dwCookie;
+}
+
+
+
+DWORD icq_searchAimByEmail(char* pszEmail, DWORD dwSearchId)
+{
+ icq_packet packet;
+ DWORD dwCookie;
+ search_cookie* pCookie;
+ search_cookie* pMainCookie = NULL;
+ WORD wEmailLen;
+
+ if (!FindCookie(dwSearchId, NULL, &pCookie))
+ {
+ dwSearchId = 0;
+ pCookie = (search_cookie*)SAFE_MALLOC(sizeof(search_cookie));
+ 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));
+ packFNACHeaderFull(&packet, ICQ_LOOKUP_FAMILY, ICQ_LOOKUP_REQUEST, 0, dwCookie);
+ packBuffer(&packet, pszEmail, wEmailLen);
+
+ sendServPacket(&packet);
+
+ return dwCookie;
+}
+
+
+
+DWORD icq_changeUserDetailsServ(WORD type, const unsigned char *pData, WORD wDataLen)
+{
+ icq_packet packet;
+ DWORD dwCookie;
+
+ dwCookie = GenerateCookie(0);
+
+ packServIcqExtensionHeader(&packet, (WORD)(wDataLen + 2), CLI_META_INFO_REQ, (WORD)dwCookie);
+ packLEWord(&packet, type);
+ packBuffer(&packet, pData, wDataLen);
+
+ sendServPacket(&packet);
+
+ return dwCookie;
+}
+
+
+
+DWORD 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("<icq_sms_message><destination></destination><text></text><codepage>1252</codepage><encoding>utf8</encoding><senders_UIN>0000000000</senders_UIN><senders_name></senders_name><delivery_receipt>Yes</delivery_receipt><time>Sun, 00 Jan 0000 00:00:00 GMT</time></icq_sms_message>");
+
+ if (szBuffer = (char *)_alloca(nBufferSize))
+ {
+
+ wBufferLen = null_snprintf(szBuffer, nBufferSize,
+ "<icq_sms_message>"
+ "<destination>"
+ "%s" /* phone number */
+ "</destination>"
+ "<text>"
+ "%s" /* body */
+ "</text>"
+ "<codepage>"
+ "1252"
+ "</codepage>"
+ "<encoding>"
+ "utf8"
+ "</encoding>"
+ "<senders_UIN>"
+ "%u" /* my UIN */
+ "</senders_UIN>"
+ "<senders_name>"
+ "%s" /* my nick */
+ "</senders_name>"
+ "<delivery_receipt>"
+ "Yes"
+ "</delivery_receipt>"
+ "<time>"
+ "%s" /* time */
+ "</time>"
+ "</icq_sms_message>",
+ szPhoneNumber, szMsg, dwLocalUIN, szMyNick, szTime);
+
+ dwCookie = GenerateCookie(0);
+
+ packServIcqExtensionHeader(&packet, (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, szBuffer, (WORD)(1 + wBufferLen));
+
+ sendServPacket(&packet);
+ }
+ else
+ {
+ dwCookie = 0;
+ }
+
+ SAFE_FREE(&szMyNick);
+
+
+ return dwCookie;
+}
+
+
+
+void icq_sendGenericContact(DWORD dwUin, 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 icq_sendNewContact(DWORD dwUin, char* szUid)
+{
+ icq_sendGenericContact(dwUin, szUid, ICQ_BUDDY_FAMILY, ICQ_USER_ADDTOLIST);
+}
+
+
+
+void icq_sendRemoveContact(DWORD dwUin, char* szUid)
+{
+ icq_sendGenericContact(dwUin, szUid, ICQ_BUDDY_FAMILY, ICQ_USER_REMOVEFROMLIST);
+}
+
+
+// list==0: visible list
+// list==1: invisible list
+void 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 (gbSsiEnabled)
+ {
+ WORD wContactId;
+ char* szSetting;
+ WORD wType;
+
+ if (list == 0)
+ {
+ wType = SSI_ITEM_PERMIT;
+ szSetting = "SrvPermitId";
+ }
+ else
+ {
+ wType = SSI_ITEM_DENY;
+ szSetting = "SrvDenyId";
+ }
+
+ if (add)
+ {
+ // check if we should make the changes, this is 2nd level check
+ if (ICQGetContactSettingWord(hContact, szSetting, 0) != 0)
+ return;
+
+ // Add
+ wContactId = GenerateServerId(SSIT_ITEM);
+
+ icq_addServerPrivacyItem(hContact, dwUin, szUID, wContactId, wType);
+
+ ICQWriteContactSettingWord(hContact, szSetting, wContactId);
+ }
+ else
+ {
+ // Remove
+ wContactId = ICQGetContactSettingWord(hContact, szSetting, 0);
+
+ if (wContactId)
+ {
+ icq_removeServerPrivacyItem(hContact, dwUin, szUID, wContactId, wType);
+
+ ICQDeleteContactSetting(hContact, szSetting);
+ }
+ }
+ }
+
+ // Notify server that we have changed
+ // our client side visibility list
+ {
+ int nUinLen;
+ icq_packet packet;
+ WORD wSnac;
+
+ if (list && gnCurrentStatus == ID_STATUS_INVISIBLE)
+ return;
+
+ if (!list && gnCurrentStatus != 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 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 icq_sendRevokeAuthServ(DWORD dwUin, char *szUid)
+{
+ icq_sendGenericContact(dwUin, szUid, ICQ_LISTS_FAMILY, ICQ_LISTS_REVOKEAUTH);
+}
+
+
+
+void icq_sendGrantAuthServ(DWORD dwUin, char *szUid, char *szMsg)
+{
+ icq_packet packet;
+ unsigned char 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, (WORD)nMsglen);
+ packBuffer(&packet, szUtfMsg, nMsglen);
+ packWord(&packet, 0);
+
+ SAFE_FREE(&szUtfMsg);
+
+ sendServPacket(&packet);
+}
+
+
+
+void icq_sendAuthReqServ(DWORD dwUin, char *szUid, char *szMsg)
+{
+ icq_packet packet;
+ unsigned char 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, (WORD)nMsglen);
+ packBuffer(&packet, szMsg, nMsglen);
+ packWord(&packet, 0);
+
+ sendServPacket(&packet);
+}
+
+
+
+void icq_sendAuthResponseServ(DWORD dwUin, char* szUid, int auth, char *szReason)
+{
+ icq_packet p;
+ WORD nReasonlen;
+ unsigned char nUinlen;
+ char* szUtfReason = NULL;
+
+ nUinlen = getUIDLen(dwUin, szUid);
+
+ // Prepare custom utf-8 reason
+ szUtfReason = ansi_to_utf8(szReason);
+ nReasonlen = strlennull(szUtfReason);
+
+ serverPacketInit(&p, (WORD)(16 + nUinlen + nReasonlen));
+ packFNACHeader(&p, ICQ_LISTS_FAMILY, ICQ_LISTS_CLI_AUTHRESPONSE);
+ packUID(&p, dwUin, szUid);
+ packByte(&p, (BYTE)auth);
+ packWord(&p, nReasonlen);
+ packBuffer(&p, szUtfReason, nReasonlen);
+ packWord(&p, 0);
+
+ SAFE_FREE(&szUtfReason);
+
+ sendServPacket(&p);
+}
+
+
+
+void 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 icq_sendXtrazRequestServ(DWORD dwUin, DWORD dwCookie, char* szBody, int nBodyLen, message_cookie_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, szBody, (WORD)nBodyLen);
+
+ // Pack request server ack TLV
+ packDWord(&packet, 0x00030000); // TLV(3)
+
+ // Send the monster
+ sendServPacket(&packet);
+}
+
+
+
+void icq_sendXtrazResponseServ(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szBody, int nBodyLen, int nType)
+{
+ icq_packet packet;
+
+ packServAdvancedMsgReply(&packet, dwUin, dwMID, dwMID2, wCookie, MTYPE_PLUGIN, 0, (WORD)(getPluginTypeIdLen(nType) + 11 + nBodyLen));
+ //
+ packEmptyMsg(&packet);
+
+ packPluginTypeId(&packet, nType);
+
+ packLEDWord(&packet, nBodyLen + 4);
+ packLEDWord(&packet, nBodyLen);
+ packBuffer(&packet, szBody, (WORD)nBodyLen);
+
+ // Send the monster
+ sendServPacket(&packet);
+}
+
+
+
+void icq_sendReverseReq(directconnect *dc, DWORD dwCookie, message_cookie_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_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, 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 icq_sendReverseFailed(directconnect* dc, DWORD dwMsgID1, DWORD dwMsgID2, DWORD dwCookie)
+{
+ icq_packet packet;
+ int nUinLen = getUINLen(dc->dwRemoteUin);
+
+ serverPacketInit(&packet, (WORD)(nUinLen + 74));
+ packFNACHeaderFull(&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
+//
+static void 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_OSCAR_FT);
+
+ sendServPacket(&packet);
+}
+
+
+
+void oft_sendFileAccept(DWORD dwUin, char *szUid, oscar_filetransfer* ft)
+{
+ oft_sendFileReply(dwUin, szUid, ft, 0x02);
+}
+
+
+
+void oft_sendFileDeny(DWORD dwUin, char *szUid, oscar_filetransfer* ft)
+{
+ oft_sendFileReply(dwUin, szUid, ft, 0x01);
+}
+
+
+
+void 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_OSCAR_FT);
+ // Connection point data
+ packTLVWord(&packet, 0x0A, (WORD)(bProxy ? 0x03 : 0x02)); // 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);
+} \ No newline at end of file
diff --git a/miranda-wine/protocols/IcqOscarJ/stdpackets.h b/miranda-wine/protocols/IcqOscarJ/stdpackets.h
new file mode 100644
index 0000000..b426a82
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/stdpackets.h
@@ -0,0 +1,111 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/stdpackets.h,v $
+// Revision : $Revision: 3709 $
+// Last change on : $Date: 2006-09-06 02:09:00 +0400 (Срд, 06 Сен 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// 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);
+
+void icq_sendCloseConnection();
+
+void icq_requestnewfamily(WORD wFamily, void (*familyhandler)(HANDLE hConn, char* cookie, WORD cookieLen));
+
+void icq_setidle(int bAllow);
+void icq_setstatus(WORD wStatus);
+DWORD icq_sendGetInfoServ(DWORD, int);
+DWORD icq_sendGetAimProfileServ(HANDLE hContact, char *szUid);
+DWORD icq_sendGetAwayMsgServ(DWORD, int, WORD);
+DWORD icq_sendGetAimAwayMsgServ(char *szUID, int type);
+void icq_sendSetAimAwayMsgServ(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, char *szReason, int nAckType);
+
+DWORD icq_sendAdvancedSearchServ(BYTE *fieldsBuffer,int bufferLen);
+DWORD icq_changeUserDetailsServ(WORD, const unsigned char *, WORD);
+void icq_sendGenericContact(DWORD dwUin, char* szUid, WORD wFamily, WORD wSubType);
+void icq_sendNewContact(DWORD dwUin, char* szUid);
+void icq_sendRemoveContact(DWORD dwUin, 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, const char **);
+void icq_sendAdvancedMsgAck(DWORD, DWORD, DWORD, WORD, BYTE, BYTE);
+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, char* szUid, char *szMsg);
+void icq_sendAuthReqServ(DWORD dwUin, char* szUid, char *szMsg);
+void icq_sendAuthResponseServ(DWORD dwUin, char* szUid,int auth,char *szReason);
+void icq_sendYouWereAddedServ(DWORD,DWORD);
+
+void sendOwnerInfoRequest(void);
+void sendUserInfoAutoRequest(DWORD dwUin);
+
+DWORD icq_SendChannel1Message(DWORD dwUin, char *szUID, HANDLE hContact, char *pszText, message_cookie_data *pCookieData);
+DWORD icq_SendChannel1MessageW(DWORD dwUin, char *szUID, HANDLE hContact, wchar_t *pszText, message_cookie_data *pCookieData); // UTF-16
+DWORD icq_SendChannel2Message(DWORD dwUin, const char *szMessage, int nBodyLength, WORD wPriority, message_cookie_data *pCookieData, char *szCap);
+DWORD icq_SendChannel4Message(DWORD dwUin, BYTE bMsgType, WORD wMsgLen, const char *szMsg, message_cookie_data *pCookieData);
+
+void icq_sendReverseReq(directconnect *dc, DWORD dwCookie, message_cookie_data *pCookie);
+void icq_sendReverseFailed(directconnect* dc, DWORD dwMsgID1, DWORD dwMsgID2, DWORD dwCookie);
+
+void icq_sendXtrazRequestServ(DWORD dwUin, DWORD dwCookie, char* szBody, int nBodyLen, message_cookie_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(char *pszNick, char *pszFirstName, char *pszLastName);
+DWORD SearchByEmail(char *pszEmail);
+
+DWORD icq_searchAimByEmail(char* pszEmail, DWORD dwSearchId);
+
+void oft_sendFileAccept(DWORD dwUin, char *szUid, oscar_filetransfer* ft);
+void oft_sendFileDeny(DWORD dwUin, char *szUid, oscar_filetransfer* ft);
+void oft_sendFileRedirect(DWORD dwUin, char *szUid, oscar_filetransfer* ft, DWORD dwIP, WORD wPort, int bProxy);
+
+#endif /* __STDPACKETS_H */
diff --git a/miranda-wine/protocols/IcqOscarJ/tlv.c b/miranda-wine/protocols/IcqOscarJ/tlv.c
new file mode 100644
index 0000000..2a7a9bb
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/tlv.c
@@ -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,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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/tlv.c,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// 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(&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* getTLV(oscar_tlv_chain *list, WORD wType, WORD wIndex)
+{
+ int i = 0;
+
+ while (list)
+ {
+ if (list->tlv.wType == wType)
+ i++;
+ if (i >= wIndex)
+ return &list->tlv;
+ list = list->next;
+ }
+
+ return NULL;
+}
+
+WORD getLenFromChain(oscar_tlv_chain *list, WORD wType, WORD wIndex)
+{
+ oscar_tlv *tlv;
+ WORD wLen = 0;
+
+ tlv = getTLV(list, wType, wIndex);
+ if (tlv)
+ {
+ wLen = tlv->wLen;
+ }
+
+ return wLen;
+}
+
+/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+/* Values are returned in MSB format */
+/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+DWORD getDWordFromChain(oscar_tlv_chain *list, WORD wType, WORD wIndex)
+{
+ oscar_tlv *tlv;
+ DWORD dw = 0;
+
+ tlv = getTLV(list, 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 getWordFromChain(oscar_tlv_chain *list, WORD wType, WORD wIndex)
+{
+ oscar_tlv *tlv;
+ WORD w = 0;
+
+ tlv = getTLV(list, wType, wIndex);
+ if (tlv && tlv->wLen >= 2)
+ {
+ w |= (*((tlv->pData)+0) << 8);
+ w |= (*((tlv->pData)+1));
+ }
+
+ return w;
+}
+
+BYTE getByteFromChain(oscar_tlv_chain *list, WORD wType, WORD wIndex)
+{
+ oscar_tlv *tlv;
+ BYTE b = 0;
+
+ tlv = getTLV(list, wType, wIndex);
+ if (tlv && tlv->wLen)
+ {
+ b = *(tlv->pData);
+ }
+
+ return b;
+}
+
+BYTE* getStrFromChain(oscar_tlv_chain *list, WORD wType, WORD wIndex)
+{
+ oscar_tlv *tlv;
+ BYTE *str = NULL;
+
+ tlv = getTLV(list, wType, wIndex);
+ if (tlv)
+ {
+ str = (BYTE*)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 **list)
+{
+ oscar_tlv_chain *now;
+
+ if (!list || !*list)
+ return;
+
+ now = *list;
+
+ while (now)
+ {
+ oscar_tlv_chain *temp;
+
+ SAFE_FREE(&now->tlv.pData);
+
+ temp = now->next;
+ SAFE_FREE(&now);
+ now = temp;
+ }
+
+ *list = NULL;
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/tlv.h b/miranda-wine/protocols/IcqOscarJ/tlv.h
new file mode 100644
index 0000000..ccda3e0
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/tlv.h
@@ -0,0 +1,68 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/tlv.h,v $
+// Revision : $Revision: 2874 $
+// Last change on : $Date: 2006-05-17 01:38:00 +0400 (Срд, 17 Май 2006) $
+// Last change by : $Author: ghazan $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#ifndef __TLV_H
+#define __TLV_H
+
+/*---------* Structures *--------------*/
+
+typedef struct oscar_tlv_s
+{
+ WORD wType;
+ WORD wLen;
+ BYTE *pData;
+} oscar_tlv;
+
+typedef struct oscar_tlv_chain_s
+{
+ oscar_tlv tlv;
+ struct oscar_tlv_chain_s *next;
+} oscar_tlv_chain;
+
+/*---------* Functions *---------------*/
+
+oscar_tlv_chain* readIntoTLVChain(BYTE **buf, WORD wLen, int maxTlvs);
+oscar_tlv* getTLV(oscar_tlv_chain *, WORD, WORD);
+
+WORD getLenFromChain(oscar_tlv_chain* chain, WORD wType, WORD wIndex);
+DWORD getDWordFromChain(oscar_tlv_chain* chain, WORD wType, WORD wIndex);
+WORD getWordFromChain(oscar_tlv_chain* chain, WORD wType, WORD wIndex);
+BYTE getByteFromChain(oscar_tlv_chain* chain, WORD wType, WORD wIndex);
+BYTE *getStrFromChain(oscar_tlv_chain* chain, WORD wType, WORD wIndex);
+
+void disposeChain(oscar_tlv_chain** chain);
+
+#endif /* __TLV_H */
diff --git a/miranda-wine/protocols/IcqOscarJ/utilities.c b/miranda-wine/protocols/IcqOscarJ/utilities.c
new file mode 100644
index 0000000..e478bf0
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/utilities.c
@@ -0,0 +1,1875 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/utilities.c,v $
+// Revision : $Revision: 3663 $
+// Last change on : $Date: 2006-08-31 00:18:59 +0400 (Чтв, 31 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+
+typedef struct gateway_index_s
+{
+ HANDLE hConn;
+ DWORD dwIndex;
+} gateway_index;
+
+extern CRITICAL_SECTION cookieMutex;
+
+static gateway_index *gateways = NULL;
+static int gatewayCount = 0;
+
+static DWORD *spammerList = NULL;
+static int spammerListCount = 0;
+
+typedef struct icq_contacts_cache_s
+{
+ HANDLE hContact;
+ DWORD dwUin;
+} icq_contacts_cache;
+
+static icq_contacts_cache *contacts_cache = NULL;
+static int cacheCount = 0;
+static int cacheListSize = 0;
+static CRITICAL_SECTION cacheMutex;
+
+extern BYTE gbOverRate;
+extern DWORD gtLastRequest;
+extern BOOL bIsSyncingCL;
+
+
+void EnableDlgItem(HWND hwndDlg, UINT control, int state)
+{
+ EnableWindow(GetDlgItem(hwndDlg, control), state);
+}
+
+
+
+void icq_EnableMultipleControls(HWND hwndDlg, const UINT *controls, int cControls, int state)
+{
+ int i;
+
+ for (i = 0; i < cControls; i++)
+ EnableDlgItem(hwndDlg, controls[i], state);
+}
+
+
+
+void icq_ShowMultipleControls(HWND hwndDlg, const UINT *controls, int cControls, int state)
+{
+ int i;
+
+ for(i = 0; i < cControls; i++)
+ ShowWindow(GetDlgItem(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_FREECHAT:
+ case ID_STATUS_OFFLINE:
+ nSupportedStatus = nMirandaStatus;
+ 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)
+{
+ char* szRes = NULL;
+
+ if (gbUnicodeCore)
+ { // we can get unicode version, request, give utf-8
+ szRes = make_utf8_string((wchar_t *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, mirandaStatus, GCMDF_UNICODE));
+ }
+ else
+ { // we are ansi only, get it, convert to utf-8
+ utf8_encode(MirandaStatusToString(mirandaStatus), &szRes);
+ }
+ return szRes;
+}
+
+
+
+char**MirandaStatusToAwayMsg(int nStatus)
+{
+ switch (nStatus)
+ {
+
+ case ID_STATUS_AWAY:
+ return &modeMsgs.szAway;
+ break;
+
+ case ID_STATUS_NA:
+ return &modeMsgs.szNa;
+
+ case ID_STATUS_OCCUPIED:
+ return &modeMsgs.szOccupied;
+
+ case ID_STATUS_DND:
+ return &modeMsgs.szDnd;
+
+ case ID_STATUS_FREECHAT:
+ return &modeMsgs.szFfc;
+
+ default:
+ return NULL;
+ }
+}
+
+
+
+int AwayMsgTypeToStatus(int nMsgType)
+{
+ switch (nMsgType)
+ {
+ 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)
+{
+ int i;
+
+ EnterCriticalSection(&cookieMutex);
+
+ for (i = 0; i < gatewayCount; i++)
+ {
+ if (hConn == gateways[i].hConn)
+ {
+ gateways[i].dwIndex = dwIndex;
+
+ LeaveCriticalSection(&cookieMutex);
+
+ return;
+ }
+ }
+
+ gateways = (gateway_index *)realloc(gateways, sizeof(gateway_index) * (gatewayCount + 1));
+ gateways[gatewayCount].hConn = hConn;
+ gateways[gatewayCount].dwIndex = dwIndex;
+ gatewayCount++;
+
+ LeaveCriticalSection(&cookieMutex);
+
+ return;
+}
+
+
+
+DWORD GetGatewayIndex(HANDLE hConn)
+{
+ int i;
+
+ EnterCriticalSection(&cookieMutex);
+
+ for (i = 0; i < gatewayCount; i++)
+ {
+ if (hConn == gateways[i].hConn)
+ {
+ LeaveCriticalSection(&cookieMutex);
+
+ return gateways[i].dwIndex;
+ }
+ }
+
+ LeaveCriticalSection(&cookieMutex);
+
+ return 1; // this is default
+}
+
+
+
+void FreeGatewayIndex(HANDLE hConn)
+{
+ int i;
+
+
+ EnterCriticalSection(&cookieMutex);
+
+ for (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*)realloc(gateways, sizeof(gateway_index) * gatewayCount);
+
+ // Gateway found, exit loop
+ break;
+ }
+ }
+
+ LeaveCriticalSection(&cookieMutex);
+}
+
+
+
+void AddToSpammerList(DWORD dwUIN)
+{
+ EnterCriticalSection(&cookieMutex);
+
+ spammerList = (DWORD *)realloc(spammerList, sizeof(DWORD) * (spammerListCount + 1));
+ spammerList[spammerListCount] = dwUIN;
+ spammerListCount++;
+
+ LeaveCriticalSection(&cookieMutex);
+}
+
+
+
+BOOL IsOnSpammerList(DWORD dwUIN)
+{
+ int i;
+
+ EnterCriticalSection(&cookieMutex);
+
+ for (i = 0; i < spammerListCount; i++)
+ {
+ if (dwUIN == spammerList[i])
+ {
+ LeaveCriticalSection(&cookieMutex);
+
+ return TRUE;
+ }
+ }
+
+ LeaveCriticalSection(&cookieMutex);
+
+ return FALSE;
+}
+
+
+
+// ICQ contacts cache
+static void AddToCache(HANDLE hContact, DWORD dwUin)
+{
+ int i = 0;
+
+ if (!hContact || !dwUin)
+ return;
+
+ EnterCriticalSection(&cacheMutex);
+
+ if (cacheCount + 1 >= cacheListSize)
+ {
+ cacheListSize += 100;
+ contacts_cache = (icq_contacts_cache *)realloc(contacts_cache, sizeof(icq_contacts_cache) * cacheListSize);
+ }
+
+#ifdef _DEBUG
+ Netlib_Logf(ghServerNetlibUser, "Adding contact to cache: %u, position: %u", dwUin, cacheCount);
+#endif
+
+ contacts_cache[cacheCount].hContact = hContact;
+ contacts_cache[cacheCount].dwUin = dwUin;
+
+ cacheCount++;
+
+ LeaveCriticalSection(&cacheMutex);
+}
+
+
+
+void InitCache(void)
+{
+ HANDLE hContact;
+
+ InitializeCriticalSection(&cacheMutex);
+ cacheCount = 0;
+ cacheListSize = 0;
+ contacts_cache = NULL;
+
+ // build cache
+ EnterCriticalSection(&cacheMutex);
+
+ hContact = ICQFindFirstContact();
+
+ while (hContact)
+ {
+ DWORD dwUin;
+
+ dwUin = ICQGetContactSettingUIN(hContact);
+ if (dwUin) AddToCache(hContact, dwUin);
+
+ hContact = ICQFindNextContact(hContact);
+ }
+
+ LeaveCriticalSection(&cacheMutex);
+}
+
+
+
+void UninitCache(void)
+{
+ SAFE_FREE(&contacts_cache);
+
+ DeleteCriticalSection(&cacheMutex);
+}
+
+
+
+void DeleteFromCache(HANDLE hContact)
+{
+ int i;
+
+ if (cacheCount == 0)
+ return;
+
+ EnterCriticalSection(&cacheMutex);
+
+ for (i = cacheCount-1; i >= 0; i--)
+ if (contacts_cache[i].hContact == hContact)
+ {
+ cacheCount--;
+
+#ifdef _DEBUG
+ Netlib_Logf(ghServerNetlibUser, "Removing contact from cache: %u, position: %u", contacts_cache[i].dwUin, i);
+#endif
+ // move last contact to deleted position
+ if (i < cacheCount)
+ memcpy(&contacts_cache[i], &contacts_cache[cacheCount], sizeof(icq_contacts_cache));
+
+ // clear last contact position
+ ZeroMemory(&contacts_cache[cacheCount], sizeof(icq_contacts_cache));
+
+ break;
+ }
+
+ LeaveCriticalSection(&cacheMutex);
+}
+
+
+
+static HANDLE HandleFromCacheByUin(DWORD dwUin)
+{
+ int i;
+ HANDLE hContact = NULL;
+
+ if (cacheCount == 0)
+ return hContact;
+
+ EnterCriticalSection(&cacheMutex);
+
+ for (i = cacheCount-1; i >= 0; i--)
+ if (contacts_cache[i].dwUin == dwUin)
+ {
+ hContact = contacts_cache[i].hContact;
+ break;
+ }
+
+ LeaveCriticalSection(&cacheMutex);
+
+ return hContact;
+}
+
+
+
+HANDLE HContactFromUIN(DWORD uin, int *Added)
+{
+ HANDLE hContact;
+
+ if (Added) *Added = 0;
+
+ hContact = HandleFromCacheByUin(uin);
+ if (hContact) return hContact;
+
+ hContact = ICQFindFirstContact();
+ while (hContact != NULL)
+ {
+ DWORD dwUin;
+
+ dwUin = ICQGetContactSettingUIN(hContact);
+ if (dwUin == uin)
+ {
+ AddToCache(hContact, dwUin);
+ return hContact;
+ }
+
+ hContact = ICQFindNextContact(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", uin);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ if (CallService(MS_PROTO_ADDTOCONTACT, (WPARAM)hContact, (LPARAM)gpszICQProtoName) != 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", uin);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ ICQWriteContactSettingDword(hContact, UNIQUEIDSETTING, uin);
+
+ if (!bIsSyncingCL)
+ {
+ DBWriteContactSettingByte(hContact, "CList", "NotOnList", 1);
+ SetContactHidden(hContact, 1);
+
+ ICQWriteContactSettingWord(hContact, "Status", ID_STATUS_OFFLINE);
+
+ icq_QueueUser(hContact);
+
+ if (icqOnline)
+ {
+ icq_sendNewContact(uin, NULL);
+ }
+ }
+ AddToCache(hContact, uin);
+ *Added = 1;
+
+ return hContact;
+ }
+
+ // not in list, check that uin do not belong to us
+ if (ICQGetContactSettingUIN(NULL) == uin)
+ return NULL;
+
+ return INVALID_HANDLE_VALUE;
+}
+
+
+
+HANDLE HContactFromUID(DWORD dwUIN, char* pszUID, int *Added)
+{
+ HANDLE hContact;
+ DWORD dwUin;
+ uid_str szUid;
+
+ if (dwUIN)
+ return HContactFromUIN(dwUIN, Added);
+
+ if (Added) *Added = 0;
+
+ if (!gbAimEnabled) return INVALID_HANDLE_VALUE;
+
+ hContact = ICQFindFirstContact();
+ while (hContact != NULL)
+ {
+ if (!ICQGetContactSettingUID(hContact, &dwUin, &szUid))
+ {
+ if (!dwUin && !stricmp(szUid, pszUID))
+ {
+ if (strcmpnull(szUid, pszUID))
+ { // fix case in SN
+ ICQWriteContactSettingString(hContact, UNIQUEIDSETTING, pszUID);
+ }
+ return hContact;
+ }
+ }
+ hContact = ICQFindNextContact(hContact);
+ }
+
+ //not present: add
+ if (Added)
+ {
+ hContact = (HANDLE)CallService(MS_DB_CONTACT_ADD, 0, 0);
+ CallService(MS_PROTO_ADDTOCONTACT, (WPARAM)hContact, (LPARAM)gpszICQProtoName);
+
+ ICQWriteContactSettingString(hContact, UNIQUEIDSETTING, pszUID);
+
+ if (!bIsSyncingCL)
+ {
+ DBWriteContactSettingByte(hContact, "CList", "NotOnList", 1);
+ SetContactHidden(hContact, 1);
+
+ ICQWriteContactSettingWord(hContact, "Status", ID_STATUS_OFFLINE);
+
+ if (icqOnline)
+ {
+ icq_sendNewContact(0, pszUID);
+ }
+ }
+ *Added = 1;
+
+ return hContact;
+ }
+
+ return INVALID_HANDLE_VALUE;
+}
+
+
+
+char *NickFromHandle(HANDLE hContact)
+{
+ if (hContact == INVALID_HANDLE_VALUE)
+ return null_strdup(ICQTranslate("<invalid>"));
+
+ return null_strdup((char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, 0));
+}
+
+
+
+char *NickFromHandleUtf(HANDLE hContact)
+{
+ if (hContact == INVALID_HANDLE_VALUE)
+ return ICQTranslateUtf("<invalid>");
+
+ if (gbUnicodeCore)
+ return make_utf8_string((wchar_t*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_UNICODE));
+ else
+ {
+ unsigned char *utf = NULL;
+
+ utf8_encode((char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, 0), &utf);
+ return utf;
+ }
+}
+
+
+
+char *strUID(DWORD dwUIN, char *pszUID)
+{
+ if (dwUIN)
+ ltoa(dwUIN, pszUID, 10);
+
+ return pszUID;
+}
+
+
+
+void SetContactHidden(HANDLE hContact, BYTE bHidden)
+{
+ DBWriteContactSettingByte(hContact, "CList", "Hidden", bHidden);
+
+ if (!bHidden) // clear zero setting
+ DBDeleteContactSetting(hContact, "CList", "Hidden");
+}
+
+
+
+/* a strlennull() that likes NULL */
+size_t __fastcall strlennull(const char *string)
+{
+ if (string)
+ return strlen(string);
+
+ return 0;
+}
+
+
+/* a strcmp() that likes NULL */
+int __fastcall strcmpnull(const char *str1, const char *str2)
+{
+ if (str1 && str2)
+ return strcmp(str1, str2);
+
+ return 1;
+}
+
+
+
+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;
+}
+
+
+
+char* __fastcall null_strdup(const char *string)
+{
+ if (string)
+ return strdup(string);
+
+ return NULL;
+}
+
+
+
+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<len; i++)
+ {
+ if (!strnicmp(string+i, "&gt;", 4))
+ {
+ *szChar = '>';
+ szChar++;
+ i += 3;
+ }
+ else if (!strnicmp(string+i, "&lt;", 4))
+ {
+ *szChar = '<';
+ szChar++;
+ i += 3;
+ }
+ else if (!strnicmp(string+i, "&amp;", 5))
+ {
+ *szChar = '&';
+ szChar++;
+ i += 4;
+ }
+ else if (!strnicmp(string+i, "&quot;", 6))
+ {
+ *szChar = '"';
+ szChar++;
+ i += 5;
+ }
+ else
+ {
+ *szChar = string[i];
+ szChar++;
+ }
+ }
+ *szChar = '\0';
+
+ return szWork;
+}
+
+
+
+char *MangleXml(const char *string, int len)
+{
+ int i, l = 1;
+ char *szWork, *szChar;
+
+ for (i = 0; i<len; i++)
+ {
+ if (string[i]=='<' || string[i]=='>') l += 4; else if (string[i]=='&') l += 5; else l++;
+ }
+ szChar = szWork = (char*)SAFE_MALLOC(l + 1);
+ for (i = 0; i<len; i++)
+ {
+ if (string[i]=='<')
+ {
+ *(DWORD*)szChar = ';tl&';
+ szChar += 4;
+ }
+ else if (string[i]=='>')
+ {
+ *(DWORD*)szChar = ';tg&';
+ szChar += 4;
+ }
+ else if (string[i]=='&')
+ {
+ *(DWORD*)szChar = 'pma&';
+ szChar += 4;
+ *szChar = ';';
+ szChar++;
+ }
+ 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<len;i++)
+ {
+ if (!tag && string[i] == '<')
+ {
+ if ((i + 4 <= len) && (!strnicmp(string + i, "<br>", 4) || !strnicmp(string + i, "<br/>", 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(&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);
+ }
+ else if (!strnicmp(pszEncoding, "unicode-2-0", 11))
+ { // it is UCS-2 encoded
+ int wLen = wcslen((wchar_t*)string) + 1;
+ wchar_t *szStr = (wchar_t*)_alloca(wLen*2);
+ char *tmp = (char*)string;
+
+ unpackWideString(&tmp, szStr, (WORD)(wLen*2));
+
+ return make_utf8_string(szStr);
+ }
+ else if (!strnicmp(pszEncoding, "iso-8859-1", 10))
+ { // we use "Latin I" instead - it does the job
+ char *szRes = ansi_to_utf8_codepage(string, 1252);
+
+ return szRes;
+ }
+ }
+ if (string)
+ { // consider it CP_ACP
+ char *szRes = ansi_to_utf8(string);
+
+ return szRes;
+ }
+
+ return NULL;
+}
+
+
+
+void ResetSettingsOnListReload()
+{
+ HANDLE hContact;
+
+ // Reset a bunch of session specific settings
+ ICQWriteContactSettingWord(NULL, "SrvVisibilityID", 0);
+ ICQWriteContactSettingWord(NULL, "SrvAvatarID", 0);
+ ICQWriteContactSettingWord(NULL, "SrvRecordCount", 0);
+
+ hContact = ICQFindFirstContact();
+
+ while (hContact)
+ {
+ // All these values will be restored during the serv-list receive
+ ICQWriteContactSettingWord(hContact, "ServerId", 0);
+ ICQWriteContactSettingWord(hContact, "SrvGroupId", 0);
+ ICQWriteContactSettingWord(hContact, "SrvPermitId", 0);
+ ICQWriteContactSettingWord(hContact, "SrvDenyId", 0);
+ ICQWriteContactSettingByte(hContact, "Auth", 0);
+
+ hContact = ICQFindNextContact(hContact);
+ }
+
+ FlushSrvGroupsCache();
+}
+
+
+
+void ResetSettingsOnConnect()
+{
+ HANDLE hContact;
+
+ gbOverRate = 0; // init
+ gtLastRequest = 0;
+
+ // Reset a bunch of session specific settings
+ ICQWriteContactSettingByte(NULL, "SrvVisibility", 0);
+ ICQWriteContactSettingDword(NULL, "IdleTS", 0);
+
+ hContact = ICQFindFirstContact();
+
+ while (hContact)
+ {
+ ICQWriteContactSettingDword(hContact, "LogonTS", 0);
+ ICQWriteContactSettingDword(hContact, "IdleTS", 0);
+ ICQWriteContactSettingDword(hContact, "TickTS", 0);
+ ICQDeleteContactSetting(hContact, "TemporaryVisible");
+
+ // All these values will be restored during the login
+ if (ICQGetContactStatus(hContact) != ID_STATUS_OFFLINE)
+ ICQWriteContactSettingWord(hContact, "Status", ID_STATUS_OFFLINE);
+
+ hContact = ICQFindNextContact(hContact);
+ }
+}
+
+
+
+void ResetSettingsOnLoad()
+{
+ HANDLE hContact;
+
+ ICQWriteContactSettingDword(NULL, "IdleTS", 0);
+ ICQWriteContactSettingDword(NULL, "LogonTS", 0);
+
+ hContact = ICQFindFirstContact();
+
+ while (hContact)
+ {
+ ICQWriteContactSettingDword(hContact, "LogonTS", 0);
+ ICQWriteContactSettingDword(hContact, "IdleTS", 0);
+ ICQWriteContactSettingDword(hContact, "TickTS", 0);
+ if (ICQGetContactStatus(hContact) != ID_STATUS_OFFLINE)
+ {
+ ICQWriteContactSettingWord(hContact, "Status", ID_STATUS_OFFLINE);
+
+ ICQDeleteContactSetting(hContact, DBSETTING_XSTATUSID);
+ ICQDeleteContactSetting(hContact, DBSETTING_XSTATUSNAME);
+ ICQDeleteContactSetting(hContact, DBSETTING_XSTATUSMSG);
+ }
+ hContact = ICQFindNextContact(hContact);
+ }
+}
+
+
+
+int RandRange(int nLow, int nHigh)
+{
+ return nLow + (int)((nHigh-nLow+1)*rand()/(RAND_MAX+1.0));
+}
+
+
+
+BOOL IsStringUIN(char* pszString)
+{
+ int i;
+ int nLen = strlennull(pszString);
+
+
+ if (nLen > 0 && pszString[0] != '0')
+ {
+ for (i=0; i<nLen; i++)
+ {
+ if ((pszString[i] < '0') || (pszString[i] > '9'))
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
+void __cdecl icq_ProtocolAckThread(icq_ack_args* pArguments)
+{
+ ICQBroadcastAck(pArguments->hContact, pArguments->nAckType, pArguments->nAckResult, pArguments->hSequence, pArguments->pszMessage);
+
+ if (pArguments->nAckResult == ACKRESULT_SUCCESS)
+ NetLog_Server("Sent fake message ack");
+ else if (pArguments->nAckResult == ACKRESULT_FAILED)
+ NetLog_Server("Message delivery failed");
+
+ SAFE_FREE((char **)&pArguments->pszMessage);
+ SAFE_FREE(&pArguments);
+
+ return;
+}
+
+
+
+void icq_SendProtoAck(HANDLE hContact, DWORD dwCookie, int nAckResult, int nAckType, char* pszMessage)
+{
+ icq_ack_args* pArgs;
+
+
+ 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(icq_ProtocolAckThread, 0, pArgs);
+}
+
+
+
+void SetCurrentStatus(int nStatus)
+{
+ int nOldStatus = gnCurrentStatus;
+
+ gnCurrentStatus = nStatus;
+ ICQBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)nOldStatus, nStatus);
+}
+
+
+
+BOOL writeDbInfoSettingString(HANDLE hContact, const char* szSetting, char** buf, WORD* pwLength)
+{
+ WORD wLen;
+
+
+ if (*pwLength < 2)
+ return FALSE;
+
+ unpackLEWord(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 = ICQGetContactSettingWord(hContact, "InfoCodePage", ICQGetContactSettingWord(hContact, "InfoCP", CP_ACP));
+
+ if (wCp != CP_ACP)
+ {
+ char *szUtf = ansi_to_utf8_codepage(*buf, wCp);
+
+ if (szUtf)
+ {
+ ICQWriteContactSettingUtf(hContact, szSetting, szUtf);
+ SAFE_FREE(&szUtf);
+ }
+ else
+ ICQWriteContactSettingString(hContact, szSetting, *buf);
+ }
+ else
+ ICQWriteContactSettingString(hContact, szSetting, *buf);
+ }
+ else
+ ICQDeleteContactSetting(hContact, szSetting);
+
+ *buf += wLen;
+ *pwLength -= wLen;
+
+ return TRUE;
+}
+
+
+
+BOOL writeDbInfoSettingWord(HANDLE hContact, const char *szSetting, char **buf, WORD* pwLength)
+{
+ WORD wVal;
+
+
+ if (*pwLength < 2)
+ return FALSE;
+
+ unpackLEWord(buf, &wVal);
+ *pwLength -= 2;
+
+ if (wVal != 0)
+ ICQWriteContactSettingWord(hContact, szSetting, wVal);
+ else
+ ICQDeleteContactSetting(hContact, szSetting);
+
+ return TRUE;
+}
+
+
+
+BOOL writeDbInfoSettingWordWithTable(HANDLE hContact, const char *szSetting, struct fieldnames_t *table, char **buf, WORD* pwLength)
+{
+ WORD wVal;
+ char sbuf[MAX_PATH];
+ char *text;
+
+ if (*pwLength < 2)
+ return FALSE;
+
+ unpackLEWord(buf, &wVal);
+ *pwLength -= 2;
+
+ text = LookupFieldNameUtf(table, wVal, sbuf);
+ if (text)
+ ICQWriteContactSettingUtf(hContact, szSetting, text);
+ else
+ ICQDeleteContactSetting(hContact, szSetting);
+
+ return TRUE;
+}
+
+
+
+BOOL writeDbInfoSettingByte(HANDLE hContact, const char *pszSetting, char **buf, WORD* pwLength)
+{
+ BYTE byVal;
+
+ if (*pwLength < 1)
+ return FALSE;
+
+ unpackByte(buf, &byVal);
+ *pwLength -= 1;
+
+ if (byVal != 0)
+ ICQWriteContactSettingByte(hContact, pszSetting, byVal);
+ else
+ ICQDeleteContactSetting(hContact, pszSetting);
+
+ return TRUE;
+}
+
+
+
+BOOL writeDbInfoSettingByteWithTable(HANDLE hContact, const char *szSetting, struct fieldnames_t *table, char **buf, WORD* pwLength)
+{
+ BYTE byVal;
+ char sbuf[MAX_PATH];
+ char *text;
+
+ if (*pwLength < 1)
+ return FALSE;
+
+ unpackByte(buf, &byVal);
+ *pwLength -= 1;
+
+ text = LookupFieldNameUtf(table, byVal, sbuf);
+ if (text)
+ ICQWriteContactSettingUtf(hContact, szSetting, text);
+ else
+ ICQDeleteContactSetting(hContact, szSetting);
+
+ return TRUE;
+}
+
+
+
+// Returns the current GMT offset in seconds
+int GetGMTOffset(void)
+{
+ TIME_ZONE_INFORMATION tzinfo;
+ DWORD dwResult;
+ int nOffset = 0;
+
+
+ dwResult = GetTimeZoneInformation(&tzinfo);
+
+ switch(dwResult)
+ {
+
+ case TIME_ZONE_ID_STANDARD:
+ nOffset = -(tzinfo.Bias + tzinfo.StandardBias) * 60;
+ break;
+
+ case TIME_ZONE_ID_DAYLIGHT:
+ nOffset = -(tzinfo.Bias + tzinfo.DaylightBias) * 60;
+ break;
+
+ case TIME_ZONE_ID_UNKNOWN:
+ case TIME_ZONE_ID_INVALID:
+ default:
+ nOffset = 0;
+ break;
+
+ }
+
+ return nOffset;
+}
+
+
+
+BOOL validateStatusMessageRequest(HANDLE hContact, WORD byMessageType)
+{
+ // Privacy control
+ if (ICQGetContactSettingByte(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 (ICQGetContactSettingByte(NULL, "StatusMsgReplyVisible", 0))
+ {
+ WORD wStatus = ICQGetContactStatus(hContact);
+ if (wStatus == ID_STATUS_OFFLINE)
+ return FALSE;
+ }
+ }
+
+ // Dont send messages to people you are hiding from
+ if (hContact != INVALID_HANDLE_VALUE &&
+ ICQGetContactSettingWord(hContact, "ApparentMode", 0) == ID_STATUS_OFFLINE)
+ {
+ return FALSE;
+ }
+
+ // Dont respond to request for other statuses than your current one
+ if ((byMessageType == MTYPE_AUTOAWAY && gnCurrentStatus != ID_STATUS_AWAY) ||
+ (byMessageType == MTYPE_AUTOBUSY && gnCurrentStatus != ID_STATUS_OCCUPIED) ||
+ (byMessageType == MTYPE_AUTONA && gnCurrentStatus != ID_STATUS_NA) ||
+ (byMessageType == MTYPE_AUTODND && gnCurrentStatus != ID_STATUS_DND) ||
+ (byMessageType == MTYPE_AUTOFFC && gnCurrentStatus != ID_STATUS_FREECHAT))
+ {
+ return FALSE;
+ }
+
+ if (hContact != INVALID_HANDLE_VALUE && gnCurrentStatus==ID_STATUS_INVISIBLE &&
+ ICQGetContactSettingWord(hContact, "ApparentMode", 0) != ID_STATUS_ONLINE)
+ {
+ if (!ICQGetContactSettingByte(hContact, "TemporaryVisible", 0))
+ { // Allow request to temporary visible contacts
+ return FALSE;
+ }
+ }
+
+ // All OK!
+ return TRUE;
+}
+
+
+
+void __fastcall SAFE_FREE(void** p)
+{
+ if (*p)
+ {
+ free(*p);
+ *p = NULL;
+ }
+}
+
+
+
+void* __fastcall SAFE_MALLOC(size_t size)
+{
+ void* p = malloc(size);
+
+ if (p)
+ ZeroMemory(p, size);
+
+ return p;
+}
+
+
+static int bPhotoLock = 0;
+
+void LinkContactPhotoToFile(HANDLE hContact, char* szFile)
+{ // set contact photo if linked if no photo set link
+ if (ICQGetContactSettingByte(NULL, "AvatarsAutoLink", DEFAULT_LINK_AVATARS))
+ {
+ bPhotoLock = 1;
+ {
+ if (DBGetContactSettingByte(hContact, "ContactPhoto", "ICQLink", 0))
+ { // we are linked update DB
+ if (szFile)
+ {
+ DBDeleteContactSetting(hContact, "ContactPhoto", "File"); // delete that setting
+ DBDeleteContactSetting(hContact, "ContactPhoto", "Link");
+ if (DBWriteContactSettingString(hContact, "ContactPhoto", "File", szFile))
+ NetLog_Server("Avatar file could not be linked to ContactPhoto.");
+ }
+ else
+ { // no file, unlink
+ DBDeleteContactSetting(hContact, "ContactPhoto", "File");
+ DBDeleteContactSetting(hContact, "ContactPhoto", "ICQLink");
+ }
+ }
+ else if (szFile)
+ { // link only if file valid
+ DBVARIANT dbv;
+ if (DBGetContactSetting(hContact, "ContactPhoto", "File", &dbv))
+ {
+ if (DBGetContactSetting(hContact, "ContactPhoto", "Link", &dbv))
+ { // no photo defined
+ DBWriteContactSettingString(hContact, "ContactPhoto", "File", szFile);
+ DBWriteContactSettingByte(hContact, "ContactPhoto", "ICQLink", 1);
+ }
+ ICQFreeVariant(&dbv);
+ }
+ else
+ { // some file already defined, check if it is not the same, if yes, set link
+ if (!strcmpnull(dbv.pszVal, szFile))
+ {
+ DBWriteContactSettingByte(hContact, "ContactPhoto", "ICQLink", 1);
+ }
+ ICQFreeVariant(&dbv);
+ }
+ }
+ }
+ bPhotoLock = 0;
+ }
+}
+
+
+static int bNoChanging = 0;
+
+void ContactPhotoSettingChanged(HANDLE hContact)
+{ // the setting was changed - if it is done externaly unlink...
+ if (bNoChanging) return;
+ bNoChanging = 1;
+
+ if (!bPhotoLock && ICQGetContactSettingByte(NULL, "AvatarsAutoLink", DEFAULT_LINK_AVATARS))
+ DBDeleteContactSetting(hContact, "ContactPhoto", "ICQLink");
+
+ bNoChanging = 0;
+}
+
+
+
+HANDLE NetLib_OpenConnection(HANDLE hUser, NETLIBOPENCONNECTION* nloc)
+{
+ HANDLE hConnection = (HANDLE)CallService(MS_NETLIB_OPENCONNECTION, (WPARAM)hUser, (LPARAM)nloc);
+ if (!hConnection && (GetLastError() == 87))
+ { // this ensures, an old Miranda will be able to connect also
+ nloc->cbSize = NETLIBOPENCONNECTION_V1_SIZE;
+ hConnection = (HANDLE)CallService(MS_NETLIB_OPENCONNECTION, (WPARAM)hUser, (LPARAM)nloc);
+ }
+ return hConnection;
+}
+
+
+
+HANDLE NetLib_BindPort(NETLIBNEWCONNECTIONPROC_V2 pFunc, void* lParam, WORD* pwPort, DWORD* pdwIntIP)
+{
+ NETLIBBIND nlb = {0};
+ HANDLE hBoundPort;
+
+ nlb.cbSize = sizeof(NETLIBBIND);
+ nlb.pfnNewConnectionV2 = pFunc;
+ nlb.pExtra = lParam;
+ SetLastError(ERROR_INVALID_PARAMETER); // this must be here - NetLib does not set any error :((
+ hBoundPort = (HANDLE)CallService(MS_NETLIB_BINDPORT, (WPARAM)ghDirectNetlibUser, (LPARAM)&nlb);
+ if (!hBoundPort && (GetLastError() == ERROR_INVALID_PARAMETER))
+ { // this ensures older Miranda also can bind a port for a dc - pre 0.6
+ nlb.cbSize = NETLIBBIND_SIZEOF_V2;
+ hBoundPort = (HANDLE)CallService(MS_NETLIB_BINDPORT, (WPARAM)ghDirectNetlibUser, (LPARAM)&nlb);
+ }
+ if (pwPort) *pwPort = nlb.wPort;
+ if (pdwIntIP) *pdwIntIP = nlb.dwInternalIP;
+
+ return hBoundPort;
+}
+
+
+
+void NetLib_SafeCloseHandle(HANDLE *hConnection, int bServerConn)
+{
+ if (*hConnection)
+ {
+ Netlib_CloseHandle(*hConnection);
+ if (bServerConn)
+ FreeGatewayIndex(*hConnection);
+ *hConnection = NULL;
+ }
+}
+
+
+
+int 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)ghServerNetlibUser,(LPARAM)szText);
+}
+
+
+
+int 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)ghDirectNetlibUser,(LPARAM)szText);
+}
+
+
+
+int 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 = ghDirectNetlibUser;
+ else
+ hNetlib = ghServerNetlibUser;
+
+ return CallService(MS_NETLIB_LOG,(WPARAM)hNetlib,(LPARAM)szText);
+}
+
+
+
+int ICQBroadcastAck(HANDLE hContact,int type,int result,HANDLE hProcess,LPARAM lParam)
+{
+ ACKDATA ack={0};
+
+ ack.cbSize=sizeof(ACKDATA);
+ ack.szModule=gpszICQProtoName;
+ ack.hContact=hContact;
+ ack.type=type;
+ ack.result=result;
+ ack.hProcess=hProcess;
+ ack.lParam=lParam;
+ return CallService(MS_PROTO_BROADCASTACK,0,(LPARAM)&ack);
+}
+
+
+
+int __fastcall ICQTranslateDialog(HWND hwndDlg)
+{
+ LANGPACKTRANSLATEDIALOG lptd;
+
+ lptd.cbSize=sizeof(lptd);
+ lptd.flags=0;
+ lptd.hwndDlg=hwndDlg;
+ lptd.ignoreControls=NULL;
+ return CallService(MS_LANGPACK_TRANSLATEDIALOG,0,(LPARAM)&lptd);
+}
+
+
+
+char* __fastcall ICQTranslate(const char* src)
+{
+ return (char*)CallService(MS_LANGPACK_TRANSLATESTRING,0,(LPARAM)src);
+}
+
+
+
+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);
+ }
+
+ if (gbUtfLangpack)
+ { // we can use unicode translate
+ wchar_t* usrc = make_unicode_string(src);
+
+ szRes = make_utf8_string(TranslateW(usrc));
+
+ SAFE_FREE(&usrc);
+ }
+ else
+ {
+ int size = strlennull(src)+2;
+ char* asrc = (char*)_alloca(size);
+
+ utf8_decode_static(src, asrc, size);
+ utf8_encode(Translate(asrc), &szRes);
+ }
+ return szRes;
+}
+
+
+
+char* __fastcall ICQTranslateUtfStatic(const char* src, char* buf)
+{ // this takes UTF-8 strings only!!!
+ char* t;
+
+ if (strlennull(src))
+ {
+ t = ICQTranslateUtf(src);
+ strcpy(buf, t);
+ SAFE_FREE(&t);
+ }
+ else
+ buf[0] = '\0';
+
+ return buf;
+}
+
+
+
+char* GetUserPassword(BOOL bAlways)
+{
+ if (gpszPassword[0] != '\0' && (gbRememberPwd || bAlways))
+ return gpszPassword;
+
+ if (!ICQGetContactStaticString(NULL, "Password", gpszPassword, sizeof(gpszPassword)))
+ {
+ CallService(MS_DB_CRYPT_DECODESTRING, strlennull(gpszPassword) + 1, (LPARAM)gpszPassword);
+
+ if (!strlennull(gpszPassword)) return NULL;
+
+ gbRememberPwd = TRUE;
+
+ return gpszPassword;
+ }
+
+ return NULL;
+}
+
+
+
+WORD GetMyStatusFlags()
+{
+ WORD wFlags = 0;
+
+ // Webaware setting bit flag
+ if (ICQGetContactSettingByte(NULL, "WebAware", 0))
+ wFlags = STATUS_WEBAWARE;
+
+ // DC setting bit flag
+ switch (ICQGetContactSettingByte(NULL, "DCType", 0))
+ {
+ case 0:
+ break;
+
+ case 1:
+ wFlags = wFlags | STATUS_DCCONT;
+ break;
+
+ case 2:
+ wFlags = wFlags | STATUS_DCAUTH;
+ break;
+
+ default:
+ wFlags = wFlags | STATUS_DCDISABLED;
+ break;
+ }
+ return wFlags;
+}
+
+
+
+wchar_t *GetWindowTextUcs(HWND hWnd)
+{
+ wchar_t *utext;
+
+ if (gbUnicodeAPI)
+ {
+ int nLen = GetWindowTextLengthW(hWnd);
+
+ utext = (wchar_t*)SAFE_MALLOC((nLen+2)*sizeof(wchar_t));
+ GetWindowTextW(hWnd, utext, nLen + 1);
+ }
+ else
+ {
+ char *text;
+ int wchars, nLen = GetWindowTextLengthA(hWnd);
+
+ text = (char*)_alloca(nLen+2);
+ GetWindowTextA(hWnd, text, nLen + 1);
+
+ wchars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, text,
+ strlennull(text), NULL, 0);
+
+ utext = (wchar_t*)SAFE_MALLOC((wchars + 1)*sizeof(unsigned short));
+
+ MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, text,
+ strlennull(text), utext, wchars);
+ }
+ return utext;
+}
+
+
+
+void SetWindowTextUcs(HWND hWnd, wchar_t *text)
+{
+ if (gbUnicodeAPI)
+ {
+ SetWindowTextW(hWnd, text);
+ }
+ else
+ {
+ char *tmp = (char*)SAFE_MALLOC(wcslen(text) + 1);
+
+ WideCharToMultiByte(CP_ACP, 0, text, -1, tmp, wcslen(text)+1, NULL, NULL);
+ SetWindowTextA(hWnd, tmp);
+ SAFE_FREE(&tmp);
+ }
+}
+
+
+
+char* GetWindowTextUtf(HWND hWnd)
+{
+ if (gbUnicodeAPI)
+ {
+ wchar_t* usText;
+ int nLen = GetWindowTextLengthW(hWnd);
+
+ usText = (wchar_t*)_alloca((nLen+2)*sizeof(wchar_t));
+ GetWindowTextW(hWnd, usText, nLen + 1);
+ return make_utf8_string(usText);
+ }
+ else
+ {
+ char* szAnsi;
+ int nLen = GetWindowTextLengthA(hWnd);
+
+ szAnsi = (char*)_alloca(nLen+2);
+ GetWindowTextA(hWnd, szAnsi, nLen + 1);
+ return ansi_to_utf8(szAnsi);
+ }
+}
+
+
+
+char* GetDlgItemTextUtf(HWND hwndDlg, int iItem)
+{
+ return GetWindowTextUtf(GetDlgItem(hwndDlg, iItem));
+}
+
+
+
+void SetWindowTextUtf(HWND hWnd, const char* szText)
+{
+ if (gbUnicodeAPI)
+ {
+ wchar_t* usText = make_unicode_string(szText);
+
+ SetWindowTextW(hWnd, usText);
+ SAFE_FREE(&usText);
+ }
+ else
+ {
+ int size = strlennull(szText)+2;
+ char* szAnsi = (char*)_alloca(size);
+
+ if (utf8_decode_static(szText, szAnsi, size))
+ SetWindowTextA(hWnd, szAnsi);
+ }
+}
+
+
+
+void SetDlgItemTextUtf(HWND hwndDlg, int iItem, const char* szText)
+{
+ SetWindowTextUtf(GetDlgItem(hwndDlg, iItem), szText);
+}
+
+
+
+LONG SetWindowLongUtf(HWND hWnd, int nIndex, LONG dwNewLong)
+{
+ if (gbUnicodeAPI)
+ return SetWindowLongW(hWnd, nIndex, dwNewLong);
+ else
+ return SetWindowLongA(hWnd, nIndex, dwNewLong);
+}
+
+
+
+LRESULT CallWindowProcUtf(WNDPROC OldProc, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (gbUnicodeAPI)
+ return CallWindowProcW(OldProc,hWnd,msg,wParam,lParam);
+ else
+ return CallWindowProcA(OldProc,hWnd,msg,wParam,lParam);
+}
+
+
+
+static int ControlAddStringUtf(HWND ctrl, DWORD msg, const char* szString)
+{
+ char str[MAX_PATH];
+ char *szItem = ICQTranslateUtfStatic(szString, str);
+ int item;
+
+ if (gbUnicodeAPI)
+ {
+ wchar_t *wItem = make_unicode_string(szItem);
+
+ item = SendMessageW(ctrl, msg, 0, (LPARAM)wItem);
+ SAFE_FREE(&wItem);
+ }
+ else
+ {
+ int size = strlennull(szItem) + 2;
+ char *aItem = (char*)_alloca(size);
+
+ utf8_decode_static(szItem, aItem, size);
+ item = SendMessageA(ctrl, msg, 0, (LPARAM)aItem);
+ }
+ 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);
+}
+
+
+
+HWND DialogBoxUtf(BOOL bModal, HINSTANCE hInstance, const char* szTemplate, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam)
+{ // Unicode pump ready dialog box
+ if (gbUnicodeAPI)
+ {
+ if (bModal)
+ return (HANDLE)DialogBoxParamW(hInstance, (LPCWSTR)szTemplate, hWndParent, lpDialogFunc, dwInitParam);
+ else
+ return CreateDialogParamW(hInstance, (LPCWSTR)szTemplate, hWndParent, lpDialogFunc, dwInitParam);
+ }
+ else
+ {
+ if (bModal)
+ return (HANDLE)DialogBoxParamA(hInstance, szTemplate, hWndParent, lpDialogFunc, dwInitParam);
+ else
+ return CreateDialogParamA(hInstance, szTemplate, hWndParent, lpDialogFunc, dwInitParam);
+ }
+}
+
+
+
+HWND CreateDialogUtf(HINSTANCE hInstance, const char* lpTemplate, HWND hWndParent, DLGPROC lpDialogFunc)
+{
+ if (gbUnicodeAPI)
+ return CreateDialogW(hInstance, (LPCWSTR)lpTemplate, hWndParent, lpDialogFunc);
+ else
+ return CreateDialogA(hInstance, lpTemplate, hWndParent, lpDialogFunc);
+}
+
+
+
+int MessageBoxUtf(HWND hWnd, const char* szText, const char* szCaption, UINT uType)
+{
+ int res;
+ char str[1024];
+ char cap[MAX_PATH];
+
+ if (gbUnicodeAPI)
+ {
+ wchar_t *text = make_unicode_string(ICQTranslateUtfStatic(szText, str));
+ wchar_t *caption = make_unicode_string(ICQTranslateUtfStatic(szCaption, cap));
+ res = MessageBoxW(hWnd, text, caption, uType);
+ SAFE_FREE(&caption);
+ SAFE_FREE(&text);
+ }
+ else
+ {
+ int size = strlennull(szText) + 2, size2 = strlennull(szCaption) + 2;
+ char *text = (char*)_alloca(size);
+ char *caption = (char*)_alloca(size2);
+
+ utf8_decode_static(ICQTranslateUtfStatic(szText, str), text, size);
+ utf8_decode_static(ICQTranslateUtfStatic(szCaption, cap), caption, size2);
+ res = MessageBoxA(hWnd, text, caption, uType);
+ }
+ return res;
+}
diff --git a/miranda-wine/protocols/IcqOscarJ/utilities.h b/miranda-wine/protocols/IcqOscarJ/utilities.h
new file mode 100644
index 0000000..86392aa
--- /dev/null
+++ b/miranda-wine/protocols/IcqOscarJ/utilities.h
@@ -0,0 +1,157 @@
+// ---------------------------------------------------------------------------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.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/utilities.h,v $
+// Revision : $Revision: 3663 $
+// Last change on : $Date: 2006-08-31 00:18:59 +0400 (Чтв, 31 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#ifndef __UTILITIES_H
+#define __UTILITIES_H
+
+typedef struct icq_ack_args_s
+{
+ HANDLE hContact;
+ int nAckType;
+ int nAckResult;
+ HANDLE hSequence;
+ LPARAM pszMessage;
+} icq_ack_args;
+
+/*---------* Functions *---------------*/
+
+void EnableDlgItem(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);
+char**MirandaStatusToAwayMsg(int nStatus);
+
+int AwayMsgTypeToStatus(int nMsgType);
+
+void SetGatewayIndex(HANDLE hConn, DWORD dwIndex);
+DWORD GetGatewayIndex(HANDLE hConn);
+void FreeGatewayIndex(HANDLE hConn);
+
+void AddToSpammerList(DWORD dwUIN);
+BOOL IsOnSpammerList(DWORD dwUIN);
+
+void InitCache();
+void UninitCache();
+void DeleteFromCache(HANDLE hContact);
+HANDLE HContactFromUIN(DWORD dwUin, int *Added);
+HANDLE HContactFromUID(DWORD dwUIN, char *pszUID, int *Added);
+char *NickFromHandle(HANDLE hContact);
+char *NickFromHandleUtf(HANDLE hContact);
+char *strUID(DWORD dwUIN, char *pszUID);
+void SetContactHidden(HANDLE hContact, BYTE bHidden);
+
+size_t __fastcall strlennull(const char *string);
+int __fastcall strcmpnull(const char *str1, const char *str2);
+int null_snprintf(char *buffer, size_t count, const char* fmt, ...);
+char* __fastcall null_strdup(const char *string);
+
+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);
+
+
+void ResetSettingsOnListReload(void);
+void ResetSettingsOnConnect(void);
+void ResetSettingsOnLoad(void);
+int RandRange(int nLow, int nHigh);
+
+BOOL IsStringUIN(char* pszString);
+
+void __cdecl icq_ProtocolAckThread(icq_ack_args* pArguments);
+void icq_SendProtoAck(HANDLE hContact, DWORD dwCookie, int nAckResult, int nAckType, char* pszMessage);
+
+void SetCurrentStatus(int nStatus);
+
+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, struct fieldnames_t *table, char **buf, WORD* pwLength);
+BOOL writeDbInfoSettingByte(HANDLE hContact, const char *szSetting, char **buf, WORD* pwLength);
+BOOL writeDbInfoSettingByteWithTable(HANDLE hContact, const char *szSetting, struct fieldnames_t *table, char **buf, WORD* pwLength);
+
+int GetGMTOffset(void);
+
+BOOL validateStatusMessageRequest(HANDLE hContact, WORD byMessageType);
+
+#define icqOnline ((gnCurrentStatus != ID_STATUS_OFFLINE) && (gnCurrentStatus != ID_STATUS_CONNECTING))
+
+void __fastcall SAFE_FREE(void** p);
+void* __fastcall SAFE_MALLOC(size_t size);
+
+void LinkContactPhotoToFile(HANDLE hContact, char* szFile);
+void ContactPhotoSettingChanged(HANDLE hContact);
+
+HANDLE NetLib_OpenConnection(HANDLE hUser, NETLIBOPENCONNECTION* nloc);
+HANDLE NetLib_BindPort(NETLIBNEWCONNECTIONPROC_V2 pFunc, void* lParam, WORD* pwPort, DWORD* pdwIntIP);
+void NetLib_SafeCloseHandle(HANDLE *hConnection, int bServerConn);
+int NetLog_Server(const char *fmt,...);
+int NetLog_Direct(const char *fmt,...);
+int NetLog_Uni(BOOL bDC, const char *fmt,...);
+
+int ICQBroadcastAck(HANDLE hContact,int type,int result,HANDLE hProcess,LPARAM lParam);
+
+int __fastcall ICQTranslateDialog(HWND hwndDlg);
+char* __fastcall ICQTranslate(const char* src);
+char* __fastcall ICQTranslateUtf(const char* src);
+char* __fastcall ICQTranslateUtfStatic(const char* src, char* buf);
+
+char* GetUserPassword(BOOL bAlways);
+WORD GetMyStatusFlags();
+
+/* Unicode UI utility functions */
+wchar_t* GetWindowTextUcs(HWND hWnd);
+void SetWindowTextUcs(HWND hWnd, wchar_t *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);
+LONG SetWindowLongUtf(HWND hWnd, int nIndex, LONG dwNewLong);
+LRESULT CallWindowProcUtf(WNDPROC OldProc, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+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);
+HWND DialogBoxUtf(BOOL bModal, HINSTANCE hInstance, const char* szTemplate, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam);
+HWND CreateDialogUtf(HINSTANCE hInstance, const char* lpTemplate, HWND hWndParent, DLGPROC lpDialogFunc);
+
+#endif /* __UTILITIES_H */
diff --git a/miranda-wine/protocols/JabberG/icos/add2roster.ico b/miranda-wine/protocols/JabberG/icos/add2roster.ico
new file mode 100644
index 0000000..170e255
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/icos/add2roster.ico
Binary files differ
diff --git a/miranda-wine/protocols/JabberG/icos/addcontact.ico b/miranda-wine/protocols/JabberG/icos/addcontact.ico
new file mode 100644
index 0000000..2efc4dc
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/icos/addcontact.ico
Binary files differ
diff --git a/miranda-wine/protocols/JabberG/icos/block.ico b/miranda-wine/protocols/JabberG/icos/block.ico
new file mode 100644
index 0000000..a71ddd4
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/icos/block.ico
Binary files differ
diff --git a/miranda-wine/protocols/JabberG/icos/delete.ico b/miranda-wine/protocols/JabberG/icos/delete.ico
new file mode 100644
index 0000000..c541793
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/icos/delete.ico
Binary files differ
diff --git a/miranda-wine/protocols/JabberG/icos/grant.ico b/miranda-wine/protocols/JabberG/icos/grant.ico
new file mode 100644
index 0000000..08b6710
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/icos/grant.ico
Binary files differ
diff --git a/miranda-wine/protocols/JabberG/icos/group.ico b/miranda-wine/protocols/JabberG/icos/group.ico
new file mode 100644
index 0000000..3303179
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/icos/group.ico
Binary files differ
diff --git a/miranda-wine/protocols/JabberG/icos/jabber.ico b/miranda-wine/protocols/JabberG/icos/jabber.ico
new file mode 100644
index 0000000..27d618c
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/icos/jabber.ico
Binary files differ
diff --git a/miranda-wine/protocols/JabberG/icos/key.ico b/miranda-wine/protocols/JabberG/icos/key.ico
new file mode 100644
index 0000000..a82c4c4
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/icos/key.ico
Binary files differ
diff --git a/miranda-wine/protocols/JabberG/icos/open.ico b/miranda-wine/protocols/JabberG/icos/open.ico
new file mode 100644
index 0000000..c6d213b
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/icos/open.ico
Binary files differ
diff --git a/miranda-wine/protocols/JabberG/icos/pages.ico b/miranda-wine/protocols/JabberG/icos/pages.ico
new file mode 100644
index 0000000..af93fd2
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/icos/pages.ico
Binary files differ
diff --git a/miranda-wine/protocols/JabberG/icos/rename.ico b/miranda-wine/protocols/JabberG/icos/rename.ico
new file mode 100644
index 0000000..6dd597e
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/icos/rename.ico
Binary files differ
diff --git a/miranda-wine/protocols/JabberG/icos/request.ico b/miranda-wine/protocols/JabberG/icos/request.ico
new file mode 100644
index 0000000..b183e31
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/icos/request.ico
Binary files differ
diff --git a/miranda-wine/protocols/JabberG/icos/save.ico b/miranda-wine/protocols/JabberG/icos/save.ico
new file mode 100644
index 0000000..bf2fe98
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/icos/save.ico
Binary files differ
diff --git a/miranda-wine/protocols/JabberG/icos/user2room.ico b/miranda-wine/protocols/JabberG/icos/user2room.ico
new file mode 100644
index 0000000..8acddbb
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/icos/user2room.ico
Binary files differ
diff --git a/miranda-wine/protocols/JabberG/icos/write.ico b/miranda-wine/protocols/JabberG/icos/write.ico
new file mode 100644
index 0000000..b799ba2
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/icos/write.ico
Binary files differ
diff --git a/miranda-wine/protocols/JabberG/jabber.cpp b/miranda-wine/protocols/JabberG/jabber.cpp
new file mode 100644
index 0000000..378812a
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber.cpp
@@ -0,0 +1,350 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber.cpp,v $
+Revision : $Revision: 3611 $
+Last change on : $Date: 2006-08-27 23:36:15 +0400 (Ð’Ñк, 27 Ðвг 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include "jabber_ssl.h"
+#include "jabber_iq.h"
+#include "resource.h"
+#include "version.h"
+
+HINSTANCE hInst;
+PLUGINLINK *pluginLink;
+
+PLUGININFO pluginInfo = {
+ sizeof( PLUGININFO ),
+ #if defined( _UNICODE )
+ "Jabber Protocol (Unicode)",
+ #else
+ "Jabber Protocol",
+ #endif
+ __VERSION_DWORD,
+ "Jabber protocol plugin for Miranda IM ( "__DATE__" )",
+ "George Hazan",
+ "ghazan@miranda-im.org",
+ "( c ) 2002-05 Santithorn Bunchua, George Hazan",
+ "http://miranda-im.org/download/details.php?action=viewfile&id=437",
+ 0,
+ 0
+};
+
+MM_INTERFACE memoryManagerInterface;
+LIST_INTERFACE li;
+
+HANDLE hMainThread = NULL;
+DWORD jabberMainThreadId;
+char* jabberProtoName; // "JABBER"
+char* jabberModuleName; // "Jabber"
+CRITICAL_SECTION mutex;
+HANDLE hNetlibUser;
+// Main jabber server connection thread global variables
+struct ThreadData *jabberThreadInfo = NULL;
+BOOL jabberConnected = FALSE;
+time_t jabberLoggedInTime = 0;
+BOOL jabberOnline = FALSE;
+BOOL jabberChatDllPresent = FALSE;
+int jabberStatus = ID_STATUS_OFFLINE;
+int jabberDesiredStatus;
+BOOL modeMsgStatusChangePending = FALSE;
+BOOL jabberChangeStatusMessageOnly = FALSE;
+TCHAR* jabberJID = NULL;
+char* streamId = NULL;
+DWORD jabberLocalIP;
+UINT jabberCodePage;
+JABBER_MODEMSGS modeMsgs;
+//char* jabberModeMsg;
+CRITICAL_SECTION modeMsgMutex;
+char* jabberVcardPhotoFileName = NULL;
+char* jabberVcardPhotoType = NULL;
+BOOL jabberSendKeepAlive;
+
+// SSL-related global variable
+HMODULE hLibSSL = NULL;
+PVOID jabberSslCtx;
+
+const char xmlnsAdmin[] = "http://jabber.org/protocol/muc#admin";
+const char xmlnsOwner[] = "http://jabber.org/protocol/muc#owner";
+
+HWND hwndJabberAgents = NULL;
+HWND hwndJabberGroupchat = NULL;
+HWND hwndJabberJoinGroupchat = NULL;
+HWND hwndAgentReg = NULL;
+HWND hwndAgentRegInput = NULL;
+HWND hwndAgentManualReg = NULL;
+HWND hwndRegProgress = NULL;
+HWND hwndJabberVcard = NULL;
+HWND hwndMucVoiceList = NULL;
+HWND hwndMucMemberList = NULL;
+HWND hwndMucModeratorList = NULL;
+HWND hwndMucBanList = NULL;
+HWND hwndMucAdminList = NULL;
+HWND hwndMucOwnerList = NULL;
+HWND hwndJabberChangePassword = NULL;
+
+// Service and event handles
+HANDLE heventRawXMLIn;
+HANDLE heventRawXMLOut;
+
+int JabberOptInit( WPARAM wParam, LPARAM lParam );
+int JabberUserInfoInit( WPARAM wParam, LPARAM lParam );
+int JabberMsgUserTyping( WPARAM wParam, LPARAM lParam );
+void JabberMenuInit( void );
+int JabberSvcInit( void );
+int JabberSvcUninit( void );
+
+extern "C" BOOL WINAPI DllMain( HINSTANCE hModule, DWORD dwReason, LPVOID lpvReserved )
+{
+ #ifdef _DEBUG
+ _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
+ #endif
+ hInst = hModule;
+ return TRUE;
+}
+
+extern "C" __declspec( dllexport ) PLUGININFO *MirandaPluginInfo( DWORD mirandaVersion )
+{
+ if ( mirandaVersion < PLUGIN_MAKE_VERSION( 0,5,0,0 )) {
+ MessageBoxA( NULL, "The Jabber protocol plugin cannot be loaded. It requires Miranda IM 0.5 or later.", "Jabber Protocol Plugin", MB_OK|MB_ICONWARNING|MB_SETFOREGROUND|MB_TOPMOST );
+ return NULL;
+ }
+
+ return &pluginInfo;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// OnPreShutdown - prepares Miranda to be shut down
+
+static int OnPreShutdown( WPARAM wParam, LPARAM lParam )
+{
+ if ( hwndJabberAgents ) SendMessage( hwndJabberAgents, WM_CLOSE, 0, 0 );
+ if ( hwndJabberGroupchat ) SendMessage( hwndJabberGroupchat, WM_CLOSE, 0, 0 );
+ if ( hwndJabberJoinGroupchat ) SendMessage( hwndJabberJoinGroupchat, WM_CLOSE, 0, 0 );
+ if ( hwndAgentReg ) SendMessage( hwndAgentReg, WM_CLOSE, 0, 0 );
+ if ( hwndAgentRegInput ) SendMessage( hwndAgentRegInput, WM_CLOSE, 0, 0 );
+ if ( hwndRegProgress ) SendMessage( hwndRegProgress, WM_CLOSE, 0, 0 );
+ if ( hwndJabberVcard ) SendMessage( hwndJabberVcard, WM_CLOSE, 0, 0 );
+ if ( hwndMucVoiceList ) SendMessage( hwndMucVoiceList, WM_CLOSE, 0, 0 );
+ if ( hwndMucMemberList ) SendMessage( hwndMucMemberList, WM_CLOSE, 0, 0 );
+ if ( hwndMucModeratorList ) SendMessage( hwndMucModeratorList, WM_CLOSE, 0, 0 );
+ if ( hwndMucBanList ) SendMessage( hwndMucBanList, WM_CLOSE, 0, 0 );
+ if ( hwndMucAdminList ) SendMessage( hwndMucAdminList, WM_CLOSE, 0, 0 );
+ if ( hwndMucOwnerList ) SendMessage( hwndMucOwnerList, WM_CLOSE, 0, 0 );
+ if ( hwndJabberChangePassword ) SendMessage( hwndJabberChangePassword, WM_CLOSE, 0, 0 );
+
+ hwndJabberAgents = NULL;
+ hwndJabberGroupchat = NULL;
+ hwndJabberJoinGroupchat = NULL;
+ hwndAgentReg = NULL;
+ hwndAgentRegInput = NULL;
+ hwndAgentManualReg = NULL;
+ hwndRegProgress = NULL;
+ hwndJabberVcard = NULL;
+ hwndMucVoiceList = NULL;
+ hwndMucMemberList = NULL;
+ hwndMucModeratorList = NULL;
+ hwndMucBanList = NULL;
+ hwndMucAdminList = NULL;
+ hwndMucOwnerList = NULL;
+ hwndJabberChangePassword = NULL;
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// OnModulesLoaded - execute some code when all plugins are initialized
+
+int JabberGcEventHook( WPARAM, LPARAM );
+int JabberGcMenuHook( WPARAM, LPARAM );
+int JabberGcInit( WPARAM, LPARAM );
+
+static COLORREF crCols[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+HANDLE hChatEvent = NULL,
+ hChatMenu = NULL,
+ hChatMess = NULL,
+ hInitChat = NULL,
+ hEvInitChat = NULL,
+ hEvModulesLoaded = NULL,
+ hEvOptInit = NULL,
+ hEvPreShutdown = NULL,
+ hEvUserInfoInit = NULL;
+
+static int OnModulesLoaded( WPARAM wParam, LPARAM lParam )
+{
+ JabberWsInit();
+ JabberSslInit();
+ HookEvent( ME_USERINFO_INITIALISE, JabberUserInfoInit );
+
+ if ( ServiceExists( MS_GC_REGISTER )) {
+ jabberChatDllPresent = true;
+
+ GCREGISTER gcr = {0};
+ gcr.cbSize = sizeof( GCREGISTER );
+ gcr.dwFlags = GC_TYPNOTIF|GC_CHANMGR;
+ gcr.iMaxText = 0;
+ gcr.nColors = 16;
+ gcr.pColors = &crCols[0];
+ gcr.pszModuleDispName = jabberProtoName;
+ gcr.pszModule = jabberProtoName;
+ JCallService( MS_GC_REGISTER, NULL, ( LPARAM )&gcr );
+
+ hChatEvent = HookEvent( ME_GC_EVENT, JabberGcEventHook );
+ hChatMenu = HookEvent( ME_GC_BUILDMENU, JabberGcMenuHook );
+
+ char szEvent[ 200 ];
+ mir_snprintf( szEvent, sizeof szEvent, "%s\\ChatInit", jabberProtoName );
+ hInitChat = CreateHookableEvent( szEvent );
+ hEvInitChat = HookEvent( szEvent, JabberGcInit );
+ }
+
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// OnLoad - initialize the plugin instance
+
+extern "C" int __declspec( dllexport ) Load( PLUGINLINK *link )
+{
+ pluginLink = link;
+
+ // set the memory manager
+ memoryManagerInterface.cbSize = sizeof(MM_INTERFACE);
+ JCallService(MS_SYSTEM_GET_MMI,0,(LPARAM)&memoryManagerInterface);
+
+ // set the lists manager;
+ li.cbSize = sizeof( li );
+ if ( CallService(MS_SYSTEM_GET_LI,0,(LPARAM)&li) == CALLSERVICE_NOTFOUND ) {
+ MessageBoxA( NULL, "This plugin requires Miranda IM 0.5 or later", "Fatal error", MB_OK );
+ return 1;
+ }
+
+ if ( !ServiceExists( MS_DB_CONTACT_GETSETTING_STR )) {
+ MessageBoxA( NULL, "This plugin requires db3x plugin version 0.5.1.0 or later", "Jabber", MB_OK );
+ return 1;
+ }
+
+ char text[_MAX_PATH];
+ char* p, *q;
+
+ GetModuleFileNameA( hInst, text, sizeof( text ));
+ p = strrchr( text, '\\' );
+ p++;
+ q = strrchr( p, '.' );
+ *q = '\0';
+ jabberProtoName = mir_strdup( p );
+ _strupr( jabberProtoName );
+
+ mir_snprintf( text, sizeof( text ), "%s/Status", jabberProtoName );
+ JCallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )text );
+
+ jabberModuleName = mir_strdup( jabberProtoName );
+ _strlwr( jabberModuleName );
+ jabberModuleName[0] = toupper( jabberModuleName[0] );
+
+ JabberLog( "Setting protocol/module name to '%s/%s'", jabberProtoName, jabberModuleName );
+
+ DuplicateHandle( GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hMainThread, THREAD_SET_CONTEXT, FALSE, 0 );
+ jabberMainThreadId = GetCurrentThreadId();
+
+ hEvOptInit = HookEvent( ME_OPT_INITIALISE, JabberOptInit );
+ hEvModulesLoaded = HookEvent( ME_SYSTEM_MODULESLOADED, OnModulesLoaded );
+ hEvPreShutdown = HookEvent( ME_SYSTEM_PRESHUTDOWN, OnPreShutdown );
+
+ // Register protocol module
+ PROTOCOLDESCRIPTOR pd;
+ ZeroMemory( &pd, sizeof( PROTOCOLDESCRIPTOR ));
+ pd.cbSize = sizeof( PROTOCOLDESCRIPTOR );
+ pd.szName = jabberProtoName;
+ pd.type = PROTOTYPE_PROTOCOL;
+ JCallService( MS_PROTO_REGISTERMODULE, 0, ( LPARAM )&pd );
+
+ // Set all contacts to offline
+ HANDLE hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL ) {
+ char* szProto = ( char* )JCallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 );
+ if ( szProto != NULL && !strcmp( szProto, jabberProtoName ))
+ if ( JGetWord( hContact, "Status", ID_STATUS_OFFLINE ) != ID_STATUS_OFFLINE )
+ JSetWord( hContact, "Status", ID_STATUS_OFFLINE );
+
+ hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM ) hContact, 0 );
+ }
+
+ memset(( char* )&modeMsgs, 0, sizeof( JABBER_MODEMSGS ));
+ //jabberModeMsg = NULL;
+ jabberCodePage = JGetWord( NULL, "CodePage", CP_ACP );
+
+ InitializeCriticalSection( &mutex );
+ InitializeCriticalSection( &modeMsgMutex );
+
+ srand(( unsigned ) time( NULL ));
+ JabberSerialInit();
+ JabberIqInit();
+ JabberListInit();
+ JabberSvcInit();
+ JabberMenuInit();
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Unload - destroy the plugin instance
+
+extern "C" int __declspec( dllexport ) Unload( void )
+{
+ if ( hChatEvent ) UnhookEvent( hChatEvent );
+ if ( hChatMenu ) UnhookEvent( hChatMenu );
+ if ( hChatMess ) UnhookEvent( hChatMess );
+ if ( hEvInitChat ) UnhookEvent( hEvInitChat );
+ if ( hEvModulesLoaded ) UnhookEvent( hEvModulesLoaded );
+ if ( hEvOptInit ) UnhookEvent( hEvOptInit );
+ if ( hEvPreShutdown ) UnhookEvent( hEvPreShutdown );
+ if ( hEvUserInfoInit ) UnhookEvent( hEvUserInfoInit );
+
+ if ( hInitChat )
+ DestroyHookableEvent( hInitChat );
+
+ JabberSvcUninit();
+ JabberSslUninit();
+ JabberListUninit();
+ JabberIqUninit();
+ JabberSerialUninit();
+ JabberWsUninit();
+ DeleteCriticalSection( &modeMsgMutex );
+ DeleteCriticalSection( &mutex );
+ mir_free( modeMsgs.szOnline );
+ mir_free( modeMsgs.szAway );
+ mir_free( modeMsgs.szNa );
+ mir_free( modeMsgs.szDnd );
+ mir_free( modeMsgs.szFreechat );
+ mir_free( jabberModuleName );
+ mir_free( jabberProtoName );
+ if ( jabberVcardPhotoFileName ) {
+ DeleteFileA( jabberVcardPhotoFileName );
+ mir_free( jabberVcardPhotoFileName );
+ }
+ if ( jabberVcardPhotoType ) mir_free( jabberVcardPhotoType );
+ if ( streamId ) mir_free( streamId );
+
+ if ( hMainThread ) CloseHandle( hMainThread );
+ return 0;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber.h b/miranda-wine/protocols/JabberG/jabber.h
new file mode 100644
index 0000000..006c680
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber.h
@@ -0,0 +1,586 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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_H_
+#define _JABBER_H_
+
+#if defined(UNICODE) && !defined(_UNICODE)
+ #define _UNICODE
+#endif
+
+#include <malloc.h>
+
+#define NEWSTR_ALLOCA(A) (A==NULL)?NULL:strcpy((char*)alloca(strlen(A)+1),A)
+#define NEWTSTR_ALLOCA(A) (A==NULL)?NULL:_tcscpy((TCHAR*)alloca(sizeof(TCHAR)*(_tcslen(A)+1)),A)
+
+#if defined( _UNICODE )
+ #define TCHAR_STR_PARAM "%S"
+#else
+ #define TCHAR_STR_PARAM "%s"
+#endif
+
+#ifdef _DEBUG
+#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+#endif
+
+/*******************************************************************
+ * Global header files
+ *******************************************************************/
+#define _WIN32_WINNT 0x500
+#include <windows.h>
+#include <process.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <time.h>
+#include <limits.h>
+#include <newpluginapi.h>
+#include <m_system.h>
+#include <m_netlib.h>
+#include <m_protomod.h>
+#include <m_protosvc.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 <win2k.h>
+
+#include "jabber_xml.h"
+#include "jabber_byte.h"
+
+#if !defined(OPENFILENAME_SIZE_VERSION_400)
+ #define OPENFILENAME_SIZE_VERSION_400 sizeof(OPENFILENAME)
+#endif
+
+/*******************************************************************
+ * Global constants
+ *******************************************************************/
+#define JABBER_DEFAULT_PORT 5222
+#define JABBER_IQID "mir_"
+#define JABBER_MAX_JID_LEN 256
+
+// User-defined message
+#define WM_JABBER_REGDLG_UPDATE WM_USER + 100
+#define WM_JABBER_AGENT_REFRESH WM_USER + 101
+#define WM_JABBER_TRANSPORT_REFRESH WM_USER + 102
+#define WM_JABBER_REGINPUT_ACTIVATE WM_USER + 103
+#define WM_JABBER_REFRESH WM_USER + 104
+#define WM_JABBER_CHECK_ONLINE WM_USER + 105
+#define WM_JABBER_CHANGED WM_USER + 106
+#define WM_JABBER_ACTIVATE WM_USER + 107
+#define WM_JABBER_SET_FONT WM_USER + 108
+#define WM_JABBER_FLASHWND WM_USER + 109
+#define WM_JABBER_GC_MEMBER_ADD WM_USER + 110
+#define WM_JABBER_GC_FORCE_QUIT WM_USER + 111
+#define WM_JABBER_SHUTDOWN WM_USER + 112
+#define WM_JABBER_SMILEY WM_USER + 113
+#define WM_JABBER_JOIN WM_USER + 114
+#define WM_JABBER_ADD_TO_ROSTER WM_USER + 115
+// 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 flag
+#define JABBER_VCEMAIL_HOME 1
+#define JABBER_VCEMAIL_WORK 2
+#define JABBER_VCEMAIL_INTERNET 4
+#define JABBER_VCEMAIL_X400 8
+#define JABBER_VCTEL_HOME 1
+#define JABBER_VCTEL_WORK 2
+#define JABBER_VCTEL_VOICE 4
+#define JABBER_VCTEL_FAX 8
+#define JABBER_VCTEL_PAGER 16
+#define JABBER_VCTEL_MSG 32
+#define JABBER_VCTEL_CELL 64
+#define JABBER_VCTEL_VIDEO 128
+#define JABBER_VCTEL_BBS 256
+#define JABBER_VCTEL_MODEM 512
+#define JABBER_VCTEL_ISDN 1024
+#define JABBER_VCTEL_PCS 2048
+// 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
+#define IDC_STATIC ( -1 )
+// Icon list
+enum {
+ JABBER_IDI_GCOWNER = 0,
+ JABBER_IDI_GCADMIN,
+ JABBER_IDI_GCMODERATOR,
+ JABBER_IDI_GCVOICE,
+ JABBER_ICON_TOTAL
+};
+
+// Services and Events
+#define JE_RAWXMLIN "/RawXMLIn"
+#define JE_RAWXMLOUT "/RawXMLOut"
+
+#define JS_SENDXML "/SendXML"
+
+/*******************************************************************
+ * Global data structures and data type definitions
+ *******************************************************************/
+typedef HANDLE JABBER_SOCKET;
+
+enum JABBER_SESSION_TYPE
+{
+ JABBER_SESSION_NORMAL,
+ JABBER_SESSION_REGISTER
+};
+
+struct ThreadData {
+ HANDLE hThread;
+ JABBER_SESSION_TYPE type;
+
+ TCHAR username[128];
+ char password[128];
+ char server[128];
+ char manualHost[128];
+ TCHAR resource[128];
+ TCHAR fullJID[256];
+ WORD port;
+ JABBER_SOCKET s;
+ BOOL useSSL;
+
+ char newPassword[128];
+
+ HWND reg_hwndDlg;
+ BOOL reg_done, bIsSessionAvailable;
+};
+
+struct JABBER_MODEMSGS
+{
+ char* szOnline;
+ char* szAway;
+ char* szNa;
+ char* szDnd;
+ char* szFreechat;
+};
+
+struct JABBER_REG_ACCOUNT
+{
+ TCHAR username[128];
+ TCHAR password[128];
+ char server[128];
+ char manualHost[128];
+ WORD port;
+ BOOL useSSL;
+};
+
+typedef enum { FT_SI, FT_OOB, FT_BYTESTREAM } JABBER_FT_TYPE;
+typedef enum { FT_CONNECTING, FT_INITIALIZING, FT_RECEIVING, FT_DONE, FT_ERROR, FT_DENIED } JABBER_FILE_STATE;
+
+struct filetransfer
+{
+ filetransfer();
+ ~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;
+ WCHAR* wszFileName;
+
+ // For type == FT_BYTESTREAM
+ JABBER_BYTE_TRANSFER *jbt;
+
+ // Used by file receiving only
+ char* httpHostName;
+ WORD httpPort;
+ char* httpPath;
+
+ // Used by file sending only
+ HANDLE hFileEvent;
+ long *fileSize;
+ char* szDescription;
+};
+
+struct JABBER_SEARCH_RESULT
+{
+ PROTOSEARCHRESULT hdr;
+ TCHAR jid[256];
+};
+
+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_TYPE type;
+ TCHAR* roomJid; // filled-in by the WM_JABBER_REFRESH code
+ XmlNode *iqNode;
+
+ TCHAR* type2str( void ) const;
+};
+
+typedef void ( *JABBER_FORM_SUBMIT_FUNC )( XmlNode* values, void *userdata );
+typedef void ( __cdecl *JABBER_THREAD_FUNC )( void * );
+
+#include "jabber_list.h"
+
+/*******************************************************************
+ * Global variables
+ *******************************************************************/
+extern HINSTANCE hInst;
+extern HANDLE hMainThread;
+extern DWORD jabberMainThreadId;
+extern char* jabberProtoName;
+extern char* jabberModuleName;
+extern HANDLE hNetlibUser;
+extern HMODULE hLibSSL;
+extern PVOID jabberSslCtx;
+
+extern struct ThreadData *jabberThreadInfo;
+extern TCHAR* jabberJID;
+extern char* streamId;
+extern DWORD jabberLocalIP;
+extern BOOL jabberConnected;
+extern BOOL jabberOnline;
+extern int jabberStatus;
+extern int jabberDesiredStatus;
+extern time_t jabberLoggedInTime;
+
+extern CRITICAL_SECTION modeMsgMutex;
+extern JABBER_MODEMSGS modeMsgs;
+extern BOOL modeMsgStatusChangePending;
+
+extern BOOL jabberChangeStatusMessageOnly;
+extern BOOL jabberSendKeepAlive;
+extern BOOL jabberChatDllPresent;
+
+extern HWND hwndJabberAgents;
+extern HWND hwndAgentReg;
+extern HWND hwndAgentRegInput;
+extern HWND hwndAgentManualReg;
+extern HWND hwndRegProgress;
+extern HWND hwndJabberVcard;
+extern HWND hwndJabberChangePassword;
+extern HWND hwndJabberGroupchat;
+extern HWND hwndJabberJoinGroupchat;
+extern HWND hwndMucVoiceList;
+extern HWND hwndMucMemberList;
+extern HWND hwndMucModeratorList;
+extern HWND hwndMucBanList;
+extern HWND hwndMucAdminList;
+extern HWND hwndMucOwnerList;
+
+extern const char xmlnsOwner[], xmlnsAdmin[];
+// Service and event handles
+extern HANDLE heventRawXMLIn;
+extern HANDLE heventRawXMLOut;
+
+/*******************************************************************
+ * Function declarations
+ *******************************************************************/
+
+//---- jabber_bitmap.cpp ----------------------------------------------
+
+HBITMAP __stdcall JabberBitmapToAvatar( HBITMAP hBitmap );
+int __stdcall JabberEnterBitmapName( char* szDest );
+
+//---- jabber_chat.cpp ----------------------------------------------
+
+void JabberGcLogCreate( JABBER_LIST_ITEM* item );
+void JabberGcLogUpdateMemberStatus( JABBER_LIST_ITEM* item, TCHAR* nick, int action, XmlNode* reason );
+void JabberGcQuit( JABBER_LIST_ITEM* jid, int code, XmlNode* reason );
+
+//---- jabber_file.c ------------------------------------------------
+
+void __cdecl JabberFileReceiveThread( filetransfer* ft );
+void __cdecl JabberFileServerThread( filetransfer* ft );
+
+//---- jabber_form.c ------------------------------------------------
+
+void JabberFormCreateUI( HWND hwndStatic, XmlNode *xNode, int *formHeight );
+void JabberFormCreateDialog( XmlNode *xNode, TCHAR* defTitle, JABBER_FORM_SUBMIT_FUNC pfnSubmit, void *userdata );
+
+XmlNode* JabberFormGetData( HWND hwndStatic, XmlNode *xNode );
+
+//---- jabber_ft.c --------------------------------------------------
+
+void JabberFtCancel( filetransfer* ft );
+void JabberFtInitiate( TCHAR* jid, filetransfer* ft );
+void JabberFtHandleSiRequest( XmlNode *iqNode );
+void JabberFtAcceptSiRequest( filetransfer* ft );
+BOOL JabberFtHandleBytestreamRequest( XmlNode *iqNode );
+
+//---- jabber_groupchat.c -------------------------------------------
+
+int JabberMenuHandleGroupchat( WPARAM wParam, LPARAM lParam );
+void JabberGroupchatJoinRoom( const TCHAR* server, const TCHAR* room, const TCHAR* nick, const TCHAR* password );
+void JabberGroupchatProcessPresence( XmlNode *node, void *userdata );
+void JabberGroupchatProcessMessage( XmlNode *node, void *userdata );
+void JabberGroupchatProcessInvite( TCHAR* roomJid, TCHAR* from, TCHAR* reason, TCHAR* password );
+
+//---- jabber_libstr.c ----------------------------------------------
+
+void __stdcall replaceStr( char*& dest, const char* src );
+void __stdcall replaceStr( WCHAR*& dest, const WCHAR* src );
+char* __stdcall rtrim( char *string );
+#if defined( _UNICODE )
+ TCHAR* __stdcall rtrim( TCHAR *string );
+#endif
+
+//---- jabber_misc.c ------------------------------------------------
+
+void JabberAddContactToRoster( const TCHAR* jid, const TCHAR* nick, const TCHAR* grpName, JABBER_SUBSCRIPTION subscription );
+void JabberChatDllError( void );
+int JabberCompareJids( const TCHAR* jid1, const TCHAR* jid2 );
+void JabberContactListCreateGroup( TCHAR* groupName );
+void JabberDBAddAuthRequest( TCHAR* jid, TCHAR* nick );
+HANDLE JabberDBCreateContact( TCHAR* jid, TCHAR* nick, BOOL temporary, BOOL stripResource );
+ULONG JabberForkThread( void ( __cdecl *threadcode )( void* ), unsigned long stacksize, void *arg );
+void JabberGetAvatarFileName( HANDLE hContact, char* pszDest, int cbLen );
+void JabberSetServerStatus( int iNewStatus );
+char* EscapeChatTags(char* pszText);
+char* UnEscapeChatTags(char* str_in);
+
+//---- jabber_svc.c -------------------------------------------------
+
+void JabberEnableMenuItems( BOOL bEnable );
+
+//---- jabber_std.cpp ----------------------------------------------
+
+#if defined( _DEBUG )
+ #define JCallService CallService
+#else
+ int __stdcall JCallService( const char* szSvcName, WPARAM wParam, LPARAM lParam );
+#endif
+
+HANDLE __stdcall JCreateServiceFunction( const char* szService, MIRANDASERVICE serviceProc );
+HANDLE __stdcall JCreateHookableEvent( const char* szService );
+void __stdcall JDeleteSetting( HANDLE hContact, const char* valueName );
+DWORD __stdcall JGetByte( const char* valueName, int parDefltValue );
+DWORD __stdcall JGetByte( HANDLE hContact, const char* valueName, int parDefltValue );
+char* __stdcall JGetContactName( HANDLE hContact );
+DWORD __stdcall JGetDword( HANDLE hContact, const char* valueName, DWORD parDefltValue );
+int __stdcall JGetStaticString( const char* valueName, HANDLE hContact, char* dest, int dest_len );
+int __stdcall JGetStringUtf( HANDLE hContact, char* valueName, DBVARIANT* dbv );
+int __stdcall JGetStringT( HANDLE hContact, char* valueName, DBVARIANT* dbv );
+WORD __stdcall JGetWord( HANDLE hContact, const char* valueName, int parDefltValue );
+void __fastcall JFreeVariant( DBVARIANT* dbv );
+int __stdcall JSendBroadcast( HANDLE hContact, int type, int result, HANDLE hProcess, LPARAM lParam );
+DWORD __stdcall JSetByte( const char* valueName, int parValue );
+DWORD __stdcall JSetByte( HANDLE hContact, const char* valueName, int parValue );
+DWORD __stdcall JSetDword( HANDLE hContact, const char* valueName, DWORD parValue );
+DWORD __stdcall JSetString( HANDLE hContact, const char* valueName, const char* parValue );
+DWORD __stdcall JSetStringT( HANDLE hContact, const char* valueName, const TCHAR* parValue );
+DWORD __stdcall JSetStringUtf( HANDLE hContact, const char* valueName, const char* parValue );
+DWORD __stdcall JSetWord( HANDLE hContact, const char* valueName, int parValue );
+char* __stdcall JTranslate( const char* str );
+
+//---- jabber_thread.cpp -------------------------------------------
+
+void __cdecl JabberServerThread( struct ThreadData *info );
+
+//---- jabber_util.c ----------------------------------------------
+
+void __stdcall JabberSerialInit( void );
+void __stdcall JabberSerialUninit( void );
+unsigned int __stdcall JabberSerialNext( void );
+int __stdcall JabberSend( JABBER_SOCKET s, const char* fmt, ... );
+int __stdcall JabberSend( JABBER_SOCKET s, XmlNode& node );
+HANDLE __stdcall JabberHContactFromJID( const TCHAR* jid );
+void __stdcall JabberLog( const char* fmt, ... );
+TCHAR* __stdcall JabberNickFromJID( const TCHAR* jid );
+char* __stdcall JabberUrlDecode( char* str );
+void __stdcall JabberUrlDecodeW( WCHAR* str );
+char* __stdcall JabberUrlEncode( const char* str );
+char* __stdcall JabberUtf8Decode( char*,WCHAR** );
+char* __stdcall JabberUtf8Encode( const char* str );
+char* __stdcall JabberSha1( char* str );
+char* __stdcall JabberUnixToDos( const char* str );
+WCHAR* __stdcall JabberUnixToDosW( const WCHAR* str );
+void __stdcall JabberHttpUrlDecode( char* str );
+char* __stdcall JabberHttpUrlEncode( const char* str );
+int __stdcall JabberCombineStatus( int status1, int status2 );
+TCHAR* __stdcall JabberErrorStr( int errorCode );
+TCHAR* __stdcall JabberErrorMsg( XmlNode *errorNode );
+void __stdcall JabberSendVisibleInvisiblePresence( BOOL invisible );
+char* __stdcall JabberTextEncode( const char* str );
+char* __stdcall JabberTextEncodeW( const wchar_t *str );
+char* __stdcall JabberTextDecode( const char* str );
+void __stdcall JabberUtfToTchar( const char* str, size_t cbLen, LPTSTR& dest );
+char* __stdcall JabberBase64Encode( const char* buffer, int bufferLen );
+char* __stdcall JabberBase64Decode( const TCHAR* buffer, int *resultLen );
+char* __stdcall JabberGetVersionText();
+time_t __stdcall JabberIsoToUnixTime( TCHAR* stamp );
+int __stdcall JabberCountryNameToId( TCHAR* ctry );
+void __stdcall JabberSendPresenceTo( int status, TCHAR* to, XmlNode* extra );
+void __stdcall JabberSendPresence( int );
+void __stdcall JabberStringAppend( char* *str, int *sizeAlloced, const char* fmt, ... );
+TCHAR* __stdcall JabberGetClientJID( const TCHAR* jid, TCHAR*, size_t );
+TCHAR* __stdcall JabberStripJid( const TCHAR* jid, TCHAR* dest, size_t destLen );
+int __stdcall JabberGetPictureType( const char* buf );
+
+#if defined( _UNICODE )
+ #define JabberUnixToDosT JabberUnixToDosW
+#else
+ #define JabberUnixToDosT JabberUnixToDos
+#endif
+
+//---- jabber_vcard.c -----------------------------------------------
+
+int JabberSendGetVcard( const TCHAR* jid );
+
+//---- jabber_ws.c -------------------------------------------------
+
+BOOL JabberWsInit( void );
+void JabberWsUninit( void );
+JABBER_SOCKET JabberWsConnect( char* host, WORD port );
+int JabberWsSend( JABBER_SOCKET s, char* data, int datalen );
+int JabberWsRecv( JABBER_SOCKET s, char* data, long datalen );
+
+///////////////////////////////////////////////////////////////////////////////
+// memory interface
+
+extern MM_INTERFACE memoryManagerInterface;
+#define mir_alloc(n) memoryManagerInterface.mmi_malloc(n)
+#define mir_free(ptr) memoryManagerInterface.mmi_free(ptr)
+#define mir_realloc(ptr,size) memoryManagerInterface.mmi_realloc(ptr,size)
+
+__forceinline char * mir_strdup(const char *src)
+{
+ return (src == NULL) ? NULL : strcpy(( char* )mir_alloc( strlen(src)+1 ), src );
+}
+
+__forceinline WCHAR* mir_wstrdup(const WCHAR *src)
+{
+ return (src == NULL) ? NULL : wcscpy(( WCHAR* )mir_alloc(( wcslen(src)+1 )*sizeof( WCHAR )), src );
+}
+
+#if defined( _UNICODE )
+ #define mir_tstrdup mir_wstrdup
+#else
+ #define mir_tstrdup mir_strdup
+#endif
+
+extern LIST_INTERFACE li;
+
+///////////////////////////////////////////////////////////////////////////////
+// TXT encode helper
+
+class TextEncoder {
+ char* m_body;
+
+public:
+ __forceinline TextEncoder( const char* pSrc ) :
+ m_body( JabberTextEncode( pSrc ))
+ {}
+
+ __forceinline ~TextEncoder()
+ { mir_free( m_body );
+ }
+
+ __forceinline const char* str() const { return m_body; }
+};
+
+#define TXT(A) TextEncoder(A).str()
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF encode helper
+
+class Utf8Encoder {
+ char* m_body;
+
+public:
+ __forceinline Utf8Encoder( const char* pSrc ) :
+ m_body( JabberUtf8Encode( pSrc ))
+ {}
+
+ __forceinline ~Utf8Encoder()
+ { mir_free( m_body );
+ }
+
+ __forceinline const char* str() const { return m_body; }
+};
+
+#define UTF8(A) Utf8Encoder(A).str()
+
+char* t2a( const TCHAR* src );
+char* u2a( const wchar_t* src );
+wchar_t* a2u( const char* src );
+
+#endif
diff --git a/miranda-wine/protocols/JabberG/jabber.rc b/miranda-wine/protocols/JabberG/jabber.rc
new file mode 100644
index 0000000..cad3677
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber.rc
@@ -0,0 +1,839 @@
+// Microsoft Visual C++ 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
+
+#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
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_OPT_JABBERMAIN DIALOGEX 0, 0, 312, 247
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_OPTIONSTAB,"SysTabControl32",WS_TABSTOP,1,1,310,245,
+ WS_EX_ACCEPTFILES
+END
+
+IDD_OPT_JABBER DIALOGEX 0, 0, 304, 227
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Jabber",IDC_SIMPLE,8,4,290,99
+ LTEXT "Username:",IDC_STATIC,19,21,45,8
+ EDITTEXT IDC_EDIT_USERNAME,70,19,86,12,ES_AUTOHSCROLL
+ LTEXT "Password:",IDC_STATIC,19,35,45,8
+ EDITTEXT IDC_EDIT_PASSWORD,70,33,86,12,ES_PASSWORD |
+ ES_AUTOHSCROLL
+ LTEXT "Resource:",IDC_RESOURCE_T,19,49,45,8
+ EDITTEXT IDC_EDIT_RESOURCE,70,47,86,12,ES_AUTOHSCROLL
+ LTEXT "Priority:",IDC_PRIORITY_LABEL,165,49,31,8
+ EDITTEXT IDC_PRIORITY,199,47,42,12,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "Spin1",IDC_PRIORITY_SPIN,"msctls_updown32",
+ UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY |
+ UDS_NOTHOUSANDS,231,47,11,12
+ CONTROL "Save password",IDC_SAVEPASSWORD,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,70,61,172,10
+ LTEXT "Login server:",IDC_STATIC,19,75,45,8
+ EDITTEXT IDC_EDIT_LOGIN_SERVER,70,73,86,12,ES_AUTOHSCROLL
+ LTEXT "Port:",IDC_STATIC,19,89,45,8
+ EDITTEXT IDC_PORT,70,87,26,12,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "Use SSL",IDC_USE_SSL,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,104,88,82,10
+ CONTROL "Use TLS",IDC_USE_TLS,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,193,88,97,10
+ PUSHBUTTON "Register new user",IDC_BUTTON_REGISTER,165,19,78,13
+ CONTROL "List of public servers",IDC_LINK_PUBLIC_SERVER,
+ "Hyperlink",WS_TABSTOP,165,74,79,11
+ GROUPBOX "Expert",IDC_STATIC,8,108,290,112
+ CONTROL "Manually specify connection host",IDC_MANUAL,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,19,121,223,10
+ LTEXT "Host:",IDC_STATIC,31,134,26,8
+ EDITTEXT IDC_HOST,62,132,90,12,ES_AUTOHSCROLL | WS_DISABLED
+ LTEXT "Port:",IDC_STATIC,161,134,21,8
+ EDITTEXT IDC_HOSTPORT,186,132,31,12,ES_AUTOHSCROLL | ES_NUMBER |
+ WS_DISABLED
+ CONTROL "Keep connection alive",IDC_KEEPALIVE,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,19,146,221,10
+ CONTROL "Automatically delete contacts not in my roster",
+ IDC_ROSTER_SYNC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,19,
+ 158,221,10
+ LTEXT "User directory:",IDC_JUD_LABEL,19,175,68,8
+ EDITTEXT IDC_JUD,92,172,103,12,ES_AUTOHSCROLL
+ LTEXT "Messaging language:",IDC_MSGLANG_LABEL,19,189,70,8
+ COMBOBOX IDC_MSGLANG,92,187,103,69,CBS_DROPDOWNLIST | CBS_SORT |
+ WS_VSCROLL | WS_TABSTOP
+END
+
+IDD_OPT_JABBER2 DIALOGEX 0, 0, 304, 199
+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,8,4,290,69
+ CONTROL "Allow file sending through direct peer-to-peer connection",
+ IDC_DIRECT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,18,
+ 202,10
+ CONTROL "Specify proxy server",IDC_PROXY_MANUAL,"Button",
+ BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,16,54,102,10
+ CONTROL "Allow file sending through bytestream proxy server",
+ IDC_PROXY,"Button",BS_AUTOCHECKBOX | WS_DISABLED |
+ WS_TABSTOP,16,42,202,10
+ EDITTEXT IDC_PROXY_ADDR,124,53,81,12,ES_AUTOHSCROLL | WS_DISABLED |
+ WS_GROUP
+ CONTROL "Specify external address",IDC_DIRECT_MANUAL,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,16,30,101,10
+ EDITTEXT IDC_DIRECT_ADDR,124,29,81,12,ES_AUTOHSCROLL
+ GROUPBOX "Miscellaneous",IDC_STATIC,8,75,290,116
+ CONTROL "Automatically add contact when accept authorization",
+ IDC_AUTO_ADD,"Button",BS_AUTOCHECKBOX | BS_TOP |
+ WS_TABSTOP,16,90,280,12
+ CONTROL "Automatically join conferences on login",IDC_AUTOJOIN,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,102,280,10
+ CONTROL "Autoaccept multiuser chat invitations",
+ IDC_AUTO_ACCEPT_MUC,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,16,114,280,10
+ CONTROL "Send messages slower, but with full acknowledgement",
+ IDC_MSG_ACK,"Button",BS_AUTOCHECKBOX | BS_TOP |
+ WS_TABSTOP,16,126,269,10
+ CONTROL "Disable main menu",IDC_DISABLE_MAINMENU,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,16,138,280,10
+ CONTROL "Show transport agents on contact list",
+ IDC_SHOW_TRANSPORT,"Button",BS_AUTOCHECKBOX | BS_TOP |
+ WS_TABSTOP,16,150,280,10
+ CONTROL "Enable avatars",IDC_ENABLE_AVATARS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,16,162,280,10
+ CONTROL "Disable SASL authentication (for old servers)",
+ IDC_DISABLE_SASL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 16,174,279,10
+END
+
+IDD_INFO_JABBER DIALOGEX 0, 0, 221, 132
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "JID:",IDC_STATIC,7,7,19,8
+ EDITTEXT IDC_INFO_JID,31,7,183,12,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ LTEXT "Resources:",IDC_STATIC,7,65,81,8
+ LISTBOX IDC_INFO_RESOURCE,7,75,69,50,LBS_SORT |
+ LBS_NOINTEGRALHEIGHT | WS_VSCROLL
+ LTEXT "Subscription type:",IDC_STATIC,7,20,60,8,NOT WS_GROUP
+ EDITTEXT IDC_SUBSCRIPTION,70,20,144,12,ES_READONLY | NOT
+ WS_BORDER
+ LTEXT "Software:",IDC_STATIC,81,74,35,8
+ LTEXT "Version:",IDC_STATIC,81,103,35,8
+ LTEXT "System:",IDC_STATIC,81,117,35,8
+ EDITTEXT IDC_SOFTWARE,121,74,93,26,ES_MULTILINE | ES_READONLY |
+ WS_DISABLED | NOT WS_BORDER
+ EDITTEXT IDC_VERSION,121,103,93,12,ES_AUTOHSCROLL | ES_READONLY |
+ WS_DISABLED | NOT WS_BORDER
+ EDITTEXT IDC_SYSTEM,121,117,93,13,ES_AUTOHSCROLL | ES_READONLY |
+ WS_DISABLED | NOT WS_BORDER
+END
+
+IDD_OPT_REGISTER DIALOGEX 0, 0, 165, 61
+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,18,7,139,19
+ CONTROL "Progress1",IDC_PROGRESS_REG,"msctls_progress32",NOT
+ WS_VISIBLE | WS_BORDER | WS_TABSTOP,18,27,130,7
+ PUSHBUTTON "OK",IDOK,29,40,50,14
+ DEFPUSHBUTTON "Cancel",IDCANCEL,85,40,50,14
+ DEFPUSHBUTTON "OK",IDOK2,55,40,50,14,NOT WS_VISIBLE
+ DEFPUSHBUTTON "Cancel",IDCANCEL2,55,40,50,14,NOT WS_VISIBLE
+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
+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
+ LTEXT "Instruction:",IDC_STATIC,7,7,243,8,NOT WS_GROUP
+ EDITTEXT IDC_INSTRUCTION,7,17,243,38,ES_MULTILINE | ES_READONLY |
+ WS_VSCROLL
+ LTEXT "",IDC_FRAME,7,60,243,138,NOT WS_GROUP,WS_EX_CLIENTEDGE
+ EDITTEXT IDC_FRAME_TEXT,18,101,220,33,ES_CENTER | ES_MULTILINE |
+ ES_READONLY | NOT WS_BORDER
+ SCROLLBAR IDC_VSCROLL,238,61,11,136,SBS_VERT | WS_DISABLED
+ DEFPUSHBUTTON "Submit",IDC_SUBMIT,146,203,50,14,WS_DISABLED
+ PUSHBUTTON "Cancel",IDCANCEL,200,203,50,14
+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
+ DEFPUSHBUTTON "OK",IDOK,23,42,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,77,42,50,14
+END
+
+IDD_VCARD DIALOGEX 0, 0, 238, 210
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK |
+ DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION |
+ WS_SYSMENU
+CAPTION "Personal vCard"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "Close",IDCLOSE,188,190,45,14
+ LTEXT "",IDC_WHITERECT,0,0,238,26
+ ICON IDI_WRITE,IDC_LOGO,7,4,20,20
+ LTEXT "",IDC_NAME,33,5,200,8,0,WS_EX_TRANSPARENT
+ CONTROL "Tab1",IDC_TABS,"SysTabControl32",TCS_HOTTRACK |
+ TCS_MULTILINE | WS_TABSTOP,5,29,228,158
+ LTEXT "View and update Jabber personal vCard",IDC_DESCRIPTION,
+ 44,13,189,8,0,WS_EX_TRANSPARENT
+ CTEXT "Updating",IDC_UPDATING,65,194,49,8,SS_NOPREFIX |
+ SS_CENTERIMAGE | NOT WS_VISIBLE
+ PUSHBUTTON "Update Now",IDC_UPDATE,5,190,55,14,WS_DISABLED
+ PUSHBUTTON "Save Changes",IDC_SAVE,124,190,61,14,WS_DISABLED
+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,50,8
+ LTEXT "City:",IDC_STATIC,5,34,50,8
+ LTEXT "State:",IDC_STATIC,5,48,50,8
+ LTEXT "Address2:",IDC_STATIC,5,20,50,8
+ EDITTEXT IDC_ADDRESS1,58,5,148,12,ES_AUTOHSCROLL
+ EDITTEXT IDC_ADDRESS2,58,19,148,12,ES_AUTOHSCROLL
+ EDITTEXT IDC_CITY,58,33,75,12,ES_AUTOHSCROLL
+ EDITTEXT IDC_STATE,58,47,75,12,ES_AUTOHSCROLL
+ LTEXT "ZIP:",IDC_STATIC,5,63,50,8
+ EDITTEXT IDC_ZIP,58,61,58,12,ES_AUTOHSCROLL
+ LTEXT "Country:",IDC_STATIC,5,76,50,8
+ EDITTEXT IDC_COUNTRY,58,75,75,12,ES_AUTOHSCROLL
+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
+ LTEXT "Middle:",IDC_STATIC,143,34,25,8
+ EDITTEXT IDC_MIDDLE,174,33,43,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,50,8
+ EDITTEXT IDC_COMPANY,58,5,148,12,ES_AUTOHSCROLL
+ LTEXT "Department:",IDC_STATIC,6,20,50,8
+ EDITTEXT IDC_DEPARTMENT,58,19,148,12,ES_AUTOHSCROLL
+ LTEXT "Title:",IDC_STATIC,6,33,50,8
+ EDITTEXT IDC_TITLE,58,32,75,12,ES_AUTOHSCROLL
+ LTEXT "Address1:",IDC_STATIC,5,47,50,8
+ EDITTEXT IDC_ADDRESS1,58,45,148,12,ES_AUTOHSCROLL
+ LTEXT "Address2:",IDC_STATIC,5,60,50,8
+ EDITTEXT IDC_ADDRESS2,58,59,148,12,ES_AUTOHSCROLL
+ LTEXT "City:",IDC_STATIC,5,74,50,8
+ EDITTEXT IDC_CITY,58,73,75,12,ES_AUTOHSCROLL
+ LTEXT "State:",IDC_STATIC,5,88,50,8
+ EDITTEXT IDC_STATE,58,87,75,12,ES_AUTOHSCROLL
+ LTEXT "ZIP:",IDC_STATIC,5,103,50,8
+ EDITTEXT IDC_ZIP,58,101,58,12,ES_AUTOHSCROLL
+ LTEXT "Country:",IDC_STATIC,5,116,50,8
+ EDITTEXT IDC_COUNTRY,58,115,75,12,ES_AUTOHSCROLL
+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
+ DEFPUSHBUTTON "OK",IDOK,40,88,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,96,88,50,14
+ 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 "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 "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
+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
+ PUSHBUTTON "",IDC_LOAD,200,5,17,14,BS_ICON
+ PUSHBUTTON "",IDC_SAVE,200,5,17,14,BS_ICON
+ CTEXT "",IDC_CANVAS,5,5,189,122,SS_CENTERIMAGE
+ PUSHBUTTON "",IDC_DELETE,200,23,17,14,BS_ICON | WS_DISABLED
+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
+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, 208, 96
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Join Jabber Multi-User Conference Room"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Conference server:",IDC_STATIC,7,8,64,8
+ EDITTEXT IDC_SERVER,74,7,127,12,ES_AUTOHSCROLL
+ LTEXT "Room:",IDC_STATIC,7,22,64,8
+ EDITTEXT IDC_ROOM,74,21,127,12,ES_AUTOHSCROLL
+ LTEXT "Nick name:",IDC_STATIC,7,36,64,8
+ EDITTEXT IDC_NICK,74,35,127,12,ES_AUTOHSCROLL
+ LTEXT "Password:",IDC_STATIC,7,50,64,8
+ EDITTEXT IDC_PASSWORD,74,49,127,12,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,51,75,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,106,75,50,14
+END
+
+IDD_GROUPCHAT_INPUT DIALOGEX 0, 0, 275, 46
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK |
+ DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ EDITTEXT IDC_TOPIC,7,7,261,12,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,165,25,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,218,25,50,14
+END
+
+IDD_JIDLIST DIALOGEX 0, 0, 207, 112
+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 "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,7,7,193,98
+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,7,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, 186, 73
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | WS_POPUP |
+ WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Jabber Groupchat Invite a User"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Room JID:",IDC_STATIC,7,6,46,8
+ EDITTEXT IDC_ROOM,57,4,122,12,ES_AUTOHSCROLL | ES_READONLY
+ LTEXT "User JID:",IDC_STATIC,7,21,46,8
+ COMBOBOX IDC_USER,57,19,122,64,CBS_DROPDOWN | CBS_AUTOHSCROLL |
+ CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Reason:",IDC_STATIC,7,37,46,8
+ EDITTEXT IDC_REASON,57,35,122,12,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "&Invite",IDC_INVITE,75,53,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,129,53,50,14
+END
+
+IDD_GROUPCHAT_INVITE_ACCEPT DIALOGEX 0, 0, 232, 112
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS |
+ DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Multi-User Conference Invitation"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "&Accept",IDC_ACCEPT,124,93,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,178,93,50,14
+ LTEXT "From:",IDC_STATIC,33,24,63,8
+ LTEXT "Room JID:",IDC_STATIC,33,38,63,8
+ LTEXT "Reason:",IDC_STATIC,33,52,63,8
+ LTEXT "Nick:",IDC_STATIC,33,76,62,8
+ LTEXT "The following invitation to join a multi-user conference is received.",
+ IDC_STATIC,3,4,225,8
+ EDITTEXT IDC_FROM,99,22,105,12,ES_AUTOHSCROLL | ES_READONLY
+ EDITTEXT IDC_ROOM,99,36,105,12,ES_AUTOHSCROLL | ES_READONLY
+ EDITTEXT IDC_REASON,99,50,105,12,ES_AUTOHSCROLL | ES_READONLY
+ GROUPBOX "",IDC_STATIC,12,13,211,57
+ EDITTEXT IDC_NICK,99,74,105,12,ES_AUTOHSCROLL
+END
+
+IDD_OPT_SETAVATAR DIALOGEX 0, 0, 222, 131
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "",IDC_AVATAR,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ SS_SUNKEN,9,11,96,96
+ LTEXT "Note: Only JPGs and GIFs\nImage size max 64x64\nFile size max 6kB",
+ IDC_STATIC,112,54,106,34
+ PUSHBUTTON "Set",IDC_SETAVATAR,9,112,45,13
+ PUSHBUTTON "Delete",IDC_DELETEAVATAR,61,112,41,13
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_OPT_JABBER, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 297
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 220
+ END
+
+ IDD_OPT_JABBER2, DIALOG
+ BEGIN
+ LEFTMARGIN, 1
+ RIGHTMARGIN, 296
+ VERTGUIDE, 9
+ TOPMARGIN, 3
+ BOTTOMMARGIN, 191
+ END
+
+ IDD_INFO_JABBER, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 214
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 125
+ END
+
+ IDD_OPT_REGISTER, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 158
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 54
+ END
+
+ IDD_AGENTS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 287
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 247
+ END
+
+ IDD_FORM, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 250
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 217
+ END
+
+ IDD_PASSWORD, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 279
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 56
+ END
+
+ IDD_VCARD, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 233
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 204
+ END
+
+ IDD_VCARD_HOME, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ END
+
+ IDD_VCARD_PERSONAL, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ END
+
+ IDD_VCARD_WORK, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ END
+
+ IDD_VCARD_CONTACT, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ END
+
+ IDD_VCARD_ADDEMAIL, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 82
+ END
+
+ IDD_VCARD_ADDPHONE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 102
+ END
+
+ IDD_VCARD_PHOTO, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ END
+
+ IDD_VCARD_NOTE, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ END
+
+ IDD_CHANGEPASSWORD, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 174
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 72
+ END
+
+ IDD_GROUPCHAT, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 299
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 203
+ END
+
+ IDD_GROUPCHAT_JOIN, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 201
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 89
+ END
+
+ IDD_GROUPCHAT_INPUT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 268
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 39
+ END
+
+ IDD_JIDLIST, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 200
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 105
+ END
+
+ IDD_AGENT_MANUAL_REGISTER, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 38
+ END
+
+ IDD_GROUPCHAT_INVITE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 67
+ END
+
+ IDD_GROUPCHAT_INVITE_ACCEPT, DIALOG
+ BEGIN
+ LEFTMARGIN, 3
+ RIGHTMARGIN, 228
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 107
+ END
+
+ IDD_OPT_SETAVATAR, DIALOG
+ BEGIN
+ LEFTMARGIN, 2
+ RIGHTMARGIN, 218
+ VERTGUIDE, 9
+ TOPMARGIN, 3
+ BOTTOMMARGIN, 126
+ 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_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\\block.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_WRITE ICON "icos\\write.ico"
+IDI_SAVE ICON "icos\\save.ico"
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/miranda-wine/protocols/JabberG/jabber_agent.cpp b/miranda-wine/protocols/JabberG/jabber_agent.cpp
new file mode 100644
index 0000000..061cfba
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_agent.cpp
@@ -0,0 +1,565 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_agent.cpp,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include <commctrl.h>
+#include "resource.h"
+#include "jabber_iq.h"
+
+static BOOL CALLBACK JabberAgentsDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam );
+BOOL CALLBACK JabberAgentRegInputDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam );
+static BOOL CALLBACK JabberAgentRegDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam );
+static BOOL CALLBACK JabberAgentManualRegDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam );
+
+int JabberMenuHandleAgents( WPARAM wParam, LPARAM lParam )
+{
+ if ( IsWindow( hwndJabberAgents ))
+ SetForegroundWindow( hwndJabberAgents );
+ else
+ CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_AGENTS ), NULL, JabberAgentsDlgProc, ( LPARAM )NULL );
+
+ return 0;
+}
+
+static void JabberRegisterAgent( HWND hwndDlg, TCHAR* jid )
+{
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_GETREGISTER, JabberIqResultGetRegister );
+ XmlNodeIq iq( "get", iqId, jid );
+ XmlNode* query = iq.addQuery( "jabber:iq:register" );
+ JabberSend( jabberThreadInfo->s, iq );
+ hwndAgentRegInput = CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_FORM ), hwndDlg, JabberAgentRegInputDlgProc, 0 );
+}
+
+static BOOL CALLBACK JabberAgentsDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ HWND lv;
+ LVCOLUMN lvCol;
+ LVITEM lvItem;
+ JABBER_LIST_ITEM *item;
+ int i;
+ TCHAR text[128];
+ TCHAR* p;
+ int iqId;
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ hwndJabberAgents = hwndDlg;
+ SendMessage( hwndDlg, WM_SETICON, ICON_BIG, ( LPARAM )LoadIcon( hInst, MAKEINTRESOURCE( IDI_AGENTS )) );
+ TranslateDialogDefault( hwndDlg );
+ // Add columns to the top list
+ lv = GetDlgItem( hwndDlg, IDC_AGENT_LIST );
+ lvCol.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
+ lvCol.pszText = TranslateT( "JID" );
+ lvCol.cx = 120;
+ lvCol.iSubItem = 0;
+ ListView_InsertColumn( lv, 0, &lvCol );
+ lvCol.pszText = TranslateT( "Description" );
+ lvCol.cx = 250;
+ lvCol.iSubItem = 1;
+ ListView_InsertColumn( lv, 1, &lvCol );
+ // Add columns to the bottom list
+ lv = GetDlgItem( hwndDlg, IDC_AGENT_TRANSPORT );
+ lvCol.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
+ lvCol.pszText = TranslateT( "JID" );
+ lvCol.cx = 120;
+ lvCol.iSubItem = 0;
+ ListView_InsertColumn( lv, 0, &lvCol );
+ lvCol.pszText = TranslateT( "Status" );
+ lvCol.cx = 80;
+ lvCol.iSubItem = 1;
+ ListView_InsertColumn( lv, 1, &lvCol );
+ if ( jabberOnline ) {
+ SetDlgItemTextA( hwndDlg, IDC_AGENT_SERVER, jabberThreadInfo->server );
+ JabberListRemoveList( LIST_AGENT );
+ iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_DISCOAGENTS, JabberIqResultDiscoAgentItems );
+
+ XmlNodeIq iq( "get", iqId, jabberThreadInfo->server );
+ XmlNode* query = iq.addQuery( "http://jabber.org/protocol/disco#items" );
+ JabberSend( jabberThreadInfo->s, iq );
+
+ SendMessage( hwndDlg, WM_JABBER_TRANSPORT_REFRESH, 0, 0 );
+ }
+ return TRUE;
+ case WM_NOTIFY:
+ switch (( ( LPNMHDR ) lParam )->code ) {
+ case LVN_ITEMCHANGED:
+ {
+ LPNMLISTVIEW lpnm;
+
+ lpnm = ( LPNMLISTVIEW ) lParam;
+ if ( lpnm->hdr.idFrom == IDC_AGENT_LIST ) {
+ lv = GetDlgItem( hwndDlg, IDC_AGENT_LIST );
+ if ( lpnm->uChanged & LVIF_STATE ) {
+ if ( lpnm->uNewState & LVIS_SELECTED ) {
+ lvItem.iItem = lpnm->iItem;
+ lvItem.iSubItem = 0;
+ lvItem.mask = LVIF_TEXT;
+ lvItem.pszText = text;
+ lvItem.cchTextMax = SIZEOF( text );
+ ListView_GetItem( lv, &lvItem );
+ if (( item=JabberListGetItemPtr( LIST_AGENT, lvItem.pszText )) != NULL ) {
+ if ( item->cap & AGENT_CAP_REGISTER )
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_REGISTER ), TRUE );
+ //if ( item->canSearch ) EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_SEARCH ), TRUE );
+ if ( item->cap & AGENT_CAP_GROUPCHAT )
+ EnableWindow( GetDlgItem( hwndDlg, IDC_JOIN ), TRUE );
+ }
+ }
+ else {
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_REGISTER ), FALSE );
+ //EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_SEARCH ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_JOIN ), FALSE );
+ }
+ return TRUE;
+ }
+ }
+ else if ( lpnm->hdr.idFrom == IDC_AGENT_TRANSPORT ) {
+ lv = GetDlgItem( hwndDlg, IDC_AGENT_TRANSPORT );
+ if ( lpnm->uChanged & LVIF_STATE ) {
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_LOGON ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_LOGOFF ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_UNREGISTER ), FALSE );
+ if ( lpnm->uNewState & LVIS_SELECTED ) {
+ lvItem.iItem = lpnm->iItem;
+ lvItem.iSubItem = 0;
+ lvItem.mask = LVIF_TEXT;
+ lvItem.pszText = text;
+ lvItem.cchTextMax = SIZEOF( text );
+ ListView_GetItem( lv, &lvItem );
+ if (( item=JabberListGetItemPtr( LIST_ROSTER, lvItem.pszText )) != NULL ) {
+ if ( item->status == ID_STATUS_OFFLINE )
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_LOGON ), TRUE );
+ else
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_LOGOFF ), TRUE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_UNREGISTER ), TRUE );
+ } }
+ return TRUE;
+ } } }
+ break;
+ }
+ break;
+ case WM_JABBER_AGENT_REFRESH:
+ // lParam = server from which agent information is obtained
+ if ( lParam )
+ SetDlgItemText( hwndDlg, IDC_AGENT_SERVER, ( TCHAR* )lParam );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_REGISTER ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_SEARCH ), FALSE );
+ i = 0;
+ lv = GetDlgItem( hwndDlg, IDC_AGENT_LIST );
+ ListView_DeleteAllItems( lv );
+ lvItem.iItem = 0;
+ while (( i=JabberListFindNext( LIST_AGENT, i )) >= 0 ) {
+ if (( item=JabberListGetItemPtrFromIndex( i )) != NULL ) {
+ lvItem.mask = LVIF_TEXT;
+ lvItem.iSubItem = 0;
+ lvItem.pszText = item->jid;
+ ListView_InsertItem( lv, &lvItem );
+ lvItem.iSubItem = 1;
+ lvItem.pszText = item->name;
+ ListView_SetItem( lv, &lvItem );
+ lvItem.iItem++;
+ }
+ i++;
+ }
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_SERVER ), TRUE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_BROWSE ), TRUE );
+ return TRUE;
+ case WM_JABBER_TRANSPORT_REFRESH:
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_LOGON ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_LOGOFF ), FALSE );
+ i = 0;
+ lv = GetDlgItem( hwndDlg, IDC_AGENT_TRANSPORT );
+ ListView_DeleteAllItems( lv );
+ lvItem.iItem = 0;
+ while (( i=JabberListFindNext( LIST_ROSTER, i )) >= 0 ) {
+ if (( item=JabberListGetItemPtrFromIndex( i )) != NULL ) {
+ if ( _tcschr( item->jid, '@' )==NULL && item->subscription!=SUB_NONE ) {
+ _tcscpy( text, item->jid );
+ if (( p=_tcschr( text, '/' )) != NULL )
+ *p = '\0';
+ lvItem.mask = LVIF_TEXT;
+ lvItem.iSubItem = 0;
+ lvItem.pszText = text;
+ ListView_InsertItem( lv, &lvItem );
+ lvItem.iSubItem = 1;
+ if ( item->status != ID_STATUS_OFFLINE )
+ lvItem.pszText = TranslateT( "Online" );
+ else
+ lvItem.pszText = TranslateT( "Offline" );
+ ListView_SetItem( lv, &lvItem );
+ lvItem.iItem++;
+ } }
+ i++;
+ }
+ return TRUE;
+ case WM_JABBER_CHECK_ONLINE:
+ if ( !jabberOnline ) {
+ if ( hwndAgentRegInput )
+ DestroyWindow( hwndAgentRegInput );
+ if ( hwndAgentManualReg )
+ DestroyWindow( hwndAgentManualReg );
+ }
+ break;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_MANUAL_REGISTER:
+ hwndAgentManualReg = CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_AGENT_MANUAL_REGISTER ), hwndDlg, JabberAgentManualRegDlgProc, 0 );
+ return TRUE;
+ case IDC_AGENT_REGISTER:
+ lv = GetDlgItem( hwndDlg, IDC_AGENT_LIST );
+ if (( lvItem.iItem=ListView_GetNextItem( lv, -1, LVNI_SELECTED )) >= 0 ) {
+ lvItem.iSubItem = 0;
+ lvItem.mask = LVIF_TEXT;
+ lvItem.pszText = text;
+ lvItem.cchTextMax = SIZEOF( text );
+ ListView_GetItem( lv, &lvItem );
+ ListView_SetItemState( lv, lvItem.iItem, 0, LVIS_SELECTED ); // Unselect the item
+ if (( item=JabberListGetItemPtr( LIST_AGENT, lvItem.pszText )) != NULL )
+ JabberRegisterAgent( hwndDlg, item->jid );
+ }
+ return TRUE;
+ case IDC_JOIN:
+ lv = GetDlgItem( hwndDlg, IDC_AGENT_LIST );
+ if (( lvItem.iItem=ListView_GetNextItem( lv, -1, LVNI_SELECTED )) >= 0 ) {
+ lvItem.iSubItem = 0;
+ lvItem.mask = LVIF_TEXT;
+ lvItem.pszText = text;
+ lvItem.cchTextMax = SIZEOF( text );
+ ListView_GetItem( lv, &lvItem );
+ ListView_SetItemState( lv, lvItem.iItem, 0, LVIS_SELECTED ); // Unselect the item
+ if (( item=JabberListGetItemPtr( LIST_AGENT, lvItem.pszText )) != NULL )
+ JabberMenuHandleGroupchat( 0, ( LPARAM )item->jid );
+ }
+ return TRUE;
+ case IDC_AGENT_SERVER:
+ GetDlgItemText( hwndDlg, IDC_AGENT_SERVER, text, SIZEOF( text ));
+ if ( jabberOnline && text[0] )
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_BROWSE ), TRUE );
+ else
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_BROWSE ), FALSE );
+ break;
+ case IDC_AGENT_BROWSE:
+ GetDlgItemText( hwndDlg, IDC_AGENT_SERVER, text, SIZEOF( text ));
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_BROWSE ), FALSE );
+ ListView_DeleteAllItems( GetDlgItem( hwndDlg, IDC_AGENT_LIST ));
+ JabberListRemoveList( LIST_AGENT );
+ iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_DISCOAGENTS, JabberIqResultDiscoAgentItems );
+ { XmlNodeIq iq( "get", iqId, text );
+ XmlNode* query = iq.addQuery( "http://jabber.org/protocol/disco#items" );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+ return TRUE;
+
+ case IDC_AGENT_LOGON:
+ case IDC_AGENT_LOGOFF:
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_UNREGISTER ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_LOGON ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_LOGOFF ), FALSE );
+ lv = GetDlgItem( hwndDlg, IDC_AGENT_TRANSPORT );
+ if (( lvItem.iItem=ListView_GetNextItem( lv, -1, LVNI_SELECTED )) >= 0 ) {
+ lvItem.iSubItem = 0;
+ lvItem.mask = LVIF_TEXT;
+ lvItem.pszText = text;
+ lvItem.cchTextMax = SIZEOF( text );
+ ListView_GetItem( lv, &lvItem );
+ if (( item=JabberListGetItemPtr( LIST_ROSTER, lvItem.pszText )) != NULL ) {
+ XmlNode p( "presence" ); p.addAttr( "to", item->jid );
+ if ( LOWORD( wParam ) != IDC_AGENT_LOGON )
+ p.addAttr( "type", "unavailable" );
+ JabberSend( jabberThreadInfo->s, p );
+ } }
+ return TRUE;
+ case IDC_AGENT_UNREGISTER:
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_UNREGISTER ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_LOGON ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_LOGOFF ), FALSE );
+ lv = GetDlgItem( hwndDlg, IDC_AGENT_TRANSPORT );
+ if (( lvItem.iItem=ListView_GetNextItem( lv, -1, LVNI_SELECTED )) >= 0 ) {
+ lvItem.iSubItem = 0;
+ lvItem.mask = LVIF_TEXT;
+ lvItem.pszText = text;
+ lvItem.cchTextMax = SIZEOF( text );
+ ListView_GetItem( lv, &lvItem );
+ if (( item=JabberListGetItemPtr( LIST_ROSTER, lvItem.pszText )) != NULL ) {
+ { XmlNodeIq iq( "set", NOID, item->jid );
+ XmlNode* query = iq.addQuery( "jabber:iq:register" );
+ query->addChild( "remove" );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+ {
+ XmlNodeIq iq( "set" );
+ XmlNode* query = iq.addQuery( "jabber:iq:roster" );
+ XmlNode* itm = query->addChild( "item" ); itm->addAttr( "jid", item->jid ); itm->addAttr( "subscription", "remove" );
+ JabberSend( jabberThreadInfo->s, iq );
+ } } }
+ return TRUE;
+
+ case IDCLOSE:
+ DestroyWindow( hwndDlg );
+ return TRUE;
+ }
+ break;
+ case WM_CLOSE:
+ DestroyWindow( hwndDlg );
+ break;
+ case WM_DESTROY:
+ hwndJabberAgents = NULL;
+ break;
+ }
+ return FALSE;
+}
+
+BOOL CALLBACK JabberAgentRegInputDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ static XmlNode *agentRegIqNode;
+
+ int id, ypos, i;
+ TCHAR *from, *str, *str2;
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ {
+ EnableWindow( GetParent( hwndDlg ), FALSE );
+ TranslateDialogDefault( hwndDlg );
+ agentRegIqNode = NULL;
+ SetWindowText( hwndDlg, TranslateT( "Jabber Agent Registration" ));
+ SetDlgItemText( hwndDlg, IDC_SUBMIT, TranslateT( "Register" ));
+ SetDlgItemText( hwndDlg, IDC_FRAME_TEXT, TranslateT( "Please wait..." ));
+
+ // Enable WS_EX_CONTROLPARENT on IDC_FRAME ( so tab stop goes through all its children )
+ LONG frameExStyle = GetWindowLong( GetDlgItem( hwndDlg, IDC_FRAME ), GWL_EXSTYLE );
+ frameExStyle |= WS_EX_CONTROLPARENT;
+ SetWindowLong( GetDlgItem( hwndDlg, IDC_FRAME ), GWL_EXSTYLE, frameExStyle );
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_SUBMIT:
+ {
+ XmlNode *queryNode, *xNode, *n;
+
+ if ( agentRegIqNode == NULL ) return TRUE;
+ if (( from=JabberXmlGetAttrValue( agentRegIqNode, "from" )) == NULL ) return TRUE;
+ if (( queryNode=JabberXmlGetChild( agentRegIqNode, "query" )) == NULL ) return TRUE;
+ HWND hFrame = GetDlgItem( hwndDlg, IDC_FRAME );
+
+ str = ( TCHAR* )alloca( sizeof(TCHAR) * 128 );
+ str2 = ( TCHAR* )alloca( sizeof(TCHAR) * 128 );
+ id = 0;
+
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_SETREGISTER, JabberIqResultSetRegister );
+
+ XmlNodeIq iq( "set", iqId, from );
+ XmlNode* query = iq.addQuery( "jabber:iq:register" );
+
+ if (( xNode=JabberXmlGetChild( queryNode, "x" )) != NULL ) {
+ // use new jabber:x:data form
+ query->addChild( JabberFormGetData( hFrame, xNode ));
+ }
+ else {
+ // use old registration information form
+ for ( i=0; i<queryNode->numChild; i++ ) {
+ n = queryNode->child[i];
+ if ( n->name ) {
+ if ( !strcmp( n->name, "key" )) {
+ // field that must be passed along with the registration
+ if ( n->text )
+ query->addChild( n->name, n->text );
+ else
+ query->addChild( n->name );
+ }
+ else if ( !strcmp( n->name, "registered" ) || !strcmp( n->name, "instructions" )) {
+ // do nothing, we will skip these
+ }
+ else {
+ GetDlgItemText( hFrame, id, str2, 128 );
+ query->addChild( n->name, str2 );
+ id++;
+ } } } }
+
+ JabberSend( jabberThreadInfo->s, iq );
+ DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_OPT_REGISTER ), hwndDlg, JabberAgentRegDlgProc, 0 );
+ // Fall through to IDCANCEL
+ }
+ case IDCANCEL:
+ if ( agentRegIqNode )
+ delete agentRegIqNode;
+ DestroyWindow( hwndDlg );
+ return TRUE;
+ }
+ break;
+ 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( hwndDlg, IDC_FRAME );
+ HFONT hFont = ( HFONT ) SendMessage( hFrame, WM_GETFONT, 0, 0 );
+ ShowWindow( GetDlgItem( hwndDlg, IDC_FRAME_TEXT ), SW_HIDE );
+
+ XmlNode *queryNode, *xNode, *n;
+ if (( agentRegIqNode=( XmlNode * ) lParam ) == NULL ) return TRUE;
+ if (( queryNode=JabberXmlGetChild( agentRegIqNode, "query" )) == NULL ) return TRUE;
+ id = 0;
+ ypos = 14;
+ if (( xNode=JabberXmlGetChild( queryNode, "x" )) != NULL ) {
+ // use new jabber:x:data form
+ if (( n=JabberXmlGetChild( xNode, "instructions" ))!=NULL && n->text!=NULL )
+ SetDlgItemText( hwndDlg, IDC_INSTRUCTION, n->text );
+
+ JabberFormCreateUI( hFrame, xNode, &i /*dummy*/ );
+ }
+ else {
+ // use old registration information form
+ for ( i=0; i<queryNode->numChild; i++ ) {
+ n = queryNode->child[i];
+ if ( n->name ) {
+ if ( !strcmp( n->name, "instructions" )) {
+ SetDlgItemText( hwndDlg, IDC_INSTRUCTION, n->text );
+ }
+ else if ( !strcmp( n->name, "key" ) || !strcmp( n->name, "registered" )) {
+ // do nothing
+ }
+ else if ( !strcmp( n->name, "password" )) {
+ HWND hCtrl = CreateWindowA( "static", n->name, WS_CHILD|WS_VISIBLE|SS_RIGHT, 10, ypos+4, 100, 18, hFrame, ( HMENU ) IDC_STATIC, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ hCtrl = CreateWindowEx( WS_EX_CLIENTEDGE, _T("edit"), n->text, WS_CHILD|WS_VISIBLE|WS_BORDER|WS_TABSTOP|ES_LEFT|ES_AUTOHSCROLL|ES_PASSWORD, 120, ypos, 128, 24, hFrame, ( HMENU ) id, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ id++;
+ ypos += 24;
+ }
+ else { // everything else is a normal text field
+ HWND hCtrl = CreateWindowA( "static", n->name, WS_CHILD|WS_VISIBLE|SS_RIGHT, 10, ypos+4, 100, 18, hFrame, ( HMENU ) IDC_STATIC, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ hCtrl = CreateWindowEx( WS_EX_CLIENTEDGE, _T("edit"), n->text, WS_CHILD|WS_VISIBLE|WS_BORDER|WS_TABSTOP|ES_LEFT|ES_AUTOHSCROLL, 120, ypos, 128, 24, hFrame, ( HMENU ) id, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ id++;
+ ypos += 24;
+ } } } }
+
+ EnableWindow( GetDlgItem( hwndDlg, IDC_SUBMIT ), TRUE );
+ }
+ else if ( wParam == 0 ) {
+ // lParam = error message
+ SetDlgItemTextA( hwndDlg, IDC_FRAME_TEXT, ( LPCSTR ) lParam );
+ }
+ return TRUE;
+ case WM_DESTROY:
+ hwndAgentRegInput = NULL;
+ EnableWindow( GetParent( hwndDlg ), TRUE );
+ SetActiveWindow( GetParent( hwndDlg ));
+ break;
+ }
+
+ return FALSE;
+}
+
+static BOOL CALLBACK JabberAgentManualRegDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ static BOOL dontEnableParent; // Very ugly hack
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ EnableWindow( GetParent( hwndDlg ), FALSE );
+ dontEnableParent = FALSE;
+ SendMessage( hwndDlg, WM_SETICON, ICON_BIG, ( LPARAM )LoadIcon( hInst, MAKEINTRESOURCE( IDI_AGENTS )) );
+ TranslateDialogDefault( hwndDlg );
+ return TRUE;
+ case WM_COMMAND:
+ {
+ TCHAR jid[256];
+
+ switch ( LOWORD( wParam )) {
+ case IDC_JID:
+ GetDlgItemText( hwndDlg, IDC_JID, jid, SIZEOF( jid ));
+ EnableWindow( GetDlgItem( hwndDlg, IDOK ), ( jid[0]=='\0' )?FALSE:TRUE );
+ break;
+ case IDOK:
+ GetDlgItemText( hwndDlg, IDC_JID, jid, SIZEOF( jid ));
+ JabberRegisterAgent( GetParent( hwndDlg ), jid );
+ dontEnableParent = TRUE;
+ // Fall through
+ case IDCANCEL:
+ case IDCLOSE:
+ DestroyWindow( hwndDlg );
+ return TRUE;
+ } }
+ break;
+ case WM_DESTROY:
+ hwndAgentManualReg = NULL;
+ if ( dontEnableParent == FALSE ) {
+ EnableWindow( GetParent( hwndDlg ), TRUE );
+ SetActiveWindow( GetParent( hwndDlg ));
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+static BOOL CALLBACK JabberAgentRegDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ hwndRegProgress = hwndDlg;
+ SetWindowTextA( hwndDlg, "Jabber Agent Registration" );
+ TranslateDialogDefault( hwndDlg );
+ ShowWindow( GetDlgItem( hwndDlg, IDOK ), SW_HIDE );
+ ShowWindow( GetDlgItem( hwndDlg, IDCANCEL ), SW_HIDE );
+ ShowWindow( GetDlgItem( hwndDlg, IDC_PROGRESS_REG ), SW_SHOW );
+ ShowWindow( GetDlgItem( hwndDlg, IDCANCEL2 ), SW_SHOW );
+ return TRUE;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDCANCEL2:
+ case IDOK2:
+ hwndRegProgress = NULL;
+ EndDialog( hwndDlg, 0 );
+ return TRUE;
+ }
+ break;
+ case WM_JABBER_REGDLG_UPDATE: // wParam=progress ( 0-100 ), lparam=status string
+ if (( TCHAR* )lParam == NULL )
+ SetDlgItemText( hwndDlg, IDC_REG_STATUS, TranslateT( "No message" ));
+ else
+ SetDlgItemText( hwndDlg, IDC_REG_STATUS, ( TCHAR* )lParam );
+ if ( wParam >= 0 )
+ SendMessage( GetDlgItem( hwndDlg, IDC_PROGRESS_REG ), PBM_SETPOS, wParam, 0 );
+ if ( wParam >= 100 ) {
+ ShowWindow( GetDlgItem( hwndDlg, IDCANCEL2 ), SW_HIDE );
+ ShowWindow( GetDlgItem( hwndDlg, IDOK2 ), SW_SHOW );
+ SetFocus( GetDlgItem( hwndDlg, IDOK2 ));
+ }
+ else
+ SetFocus( GetDlgItem( hwndDlg, IDCANCEL2 ));
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_bitmap.cpp b/miranda-wine/protocols/JabberG/jabber_bitmap.cpp
new file mode 100644
index 0000000..68a6fd1
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_bitmap.cpp
@@ -0,0 +1,53 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_bitmap.cpp,v $
+Revision : $Revision: 3016 $
+Last change on : $Date: 2006-06-04 23:07:43 +0400 (Ð’Ñк, 04 Июн 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberEnterBitmapName - enters the picture filename
+
+int __stdcall JabberEnterBitmapName( char* szDest )
+{
+ *szDest = 0;
+
+ char szFilter[ 512 ];
+ JCallService( MS_UTILS_GETBITMAPFILTERSTRINGS, sizeof szFilter, ( LPARAM )szFilter );
+
+ char str[ MAX_PATH ]; str[0] = 0;
+ OPENFILENAMEA ofn = {0};
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.lpstrFilter = szFilter;
+ ofn.lpstrFile = szDest;
+ ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
+ ofn.nMaxFile = MAX_PATH;
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.lpstrDefExt = "bmp";
+ if ( !GetOpenFileNameA( &ofn ))
+ return 1;
+
+ return ERROR_SUCCESS;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_byte.cpp b/miranda-wine/protocols/JabberG/jabber_byte.cpp
new file mode 100644
index 0000000..049d3fb
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_byte.cpp
@@ -0,0 +1,459 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_byte.cpp,v $
+Revision : $Revision: 3398 $
+Last change on : $Date: 2006-07-31 15:37:09 +0400 (Пнд, 31 Июл 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include "jabber_iq.h"
+#include "jabber_byte.h"
+
+#define JABBER_NETWORK_BUFFER_SIZE 4096
+
+///////////////// Bytestream sending /////////////////////////
+
+static void JabberByteInitiateResult( XmlNode *iqNode, void *userdata );
+static void JabberByteSendConnection( HANDLE hNewConnection, DWORD dwRemoteIP );
+static int JabberByteSendParse( HANDLE hConn, JABBER_BYTE_TRANSFER *jbt, char* buffer, int datalen );
+
+void JabberByteFreeJbt( JABBER_BYTE_TRANSFER *jbt )
+{
+ if ( !jbt ) return;
+ if ( jbt->srcJID ) mir_free( jbt->srcJID );
+ if ( jbt->dstJID ) mir_free( jbt->dstJID );
+ if ( jbt->streamhostJID ) mir_free( jbt->streamhostJID );
+ if ( jbt->iqId ) mir_free( jbt->iqId );
+ if ( jbt->sid ) mir_free( jbt->sid );
+ if ( jbt->iqNode ) delete jbt->iqNode;
+ mir_free( jbt );
+}
+
+void __cdecl JabberByteSendThread( JABBER_BYTE_TRANSFER *jbt )
+{
+ BOOL bDirect, bProxy;
+ char* localAddr;
+ struct in_addr in;
+ DBVARIANT dbv;
+ NETLIBBIND nlb = {0};
+ TCHAR szPort[8];
+ int iqId;
+ JABBER_LIST_ITEM *item;
+ HANDLE hEvent;
+
+ JabberLog( "Thread started: type=bytestream_send" );
+
+ bDirect = JGetByte( "BsDirect", TRUE );
+ bProxy = JGetByte( "BsProxy", FALSE );
+
+ iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_NONE, JabberByteInitiateResult );
+ XmlNodeIq iq( "set", iqId, jbt->dstJID );
+ XmlNode* query = iq.addQuery( "http://jabber.org/protocol/bytestreams" );
+ query->addAttr( "sid", jbt->sid );
+
+ if ( bDirect ) {
+ localAddr = NULL;
+ if ( JGetByte( "BsDirectManual", FALSE ) == TRUE ) {
+ if ( !DBGetContactSetting( NULL, jabberProtoName, "BsDirectAddr", &dbv )) {
+ localAddr = mir_strdup( dbv.pszVal );
+ JFreeVariant( &dbv );
+ }
+ }
+ if ( localAddr == NULL ) {
+ in.S_un.S_addr = jabberLocalIP;
+ localAddr = mir_strdup( inet_ntoa( in ));
+ }
+ nlb.cbSize = sizeof( NETLIBBIND );
+ nlb.pfnNewConnection = JabberByteSendConnection;
+ nlb.wPort = 0; // Use user-specified incoming port ranges, if available
+ jbt->hConn = ( HANDLE ) JCallService( MS_NETLIB_BINDPORT, ( WPARAM ) hNetlibUser, ( LPARAM )&nlb );
+ if ( jbt->hConn == NULL ) {
+ JabberLog( "Cannot allocate port for bytestream_send thread, thread ended." );
+ JabberByteFreeJbt( jbt );
+ return;
+ }
+ mir_sntprintf( szPort, SIZEOF( szPort ), _T("%d"), nlb.wPort );
+ item = JabberListAdd( LIST_BYTE, szPort );
+ item->jbt = jbt;
+ hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ jbt->hEvent = hEvent;
+ XmlNode* h = query->addChild( "streamhost" );
+ h->addAttr( "jid", jabberThreadInfo->fullJID ); h->addAttr( "host", localAddr ); h->addAttr( "port", nlb.wPort );
+ mir_free( localAddr );
+ }
+ JabberSend( jabberThreadInfo->s, iq );
+
+ if ( bDirect ) {
+ WaitForSingleObject( hEvent, INFINITE );
+ CloseHandle( hEvent );
+ jbt->hEvent = NULL;
+ jbt->pfnFinal(( jbt->state==JBT_DONE )?TRUE:FALSE, jbt->userdata );
+ if ( jbt->hConn != NULL )
+ Netlib_CloseHandle( jbt->hConn );
+ JabberByteFreeJbt( jbt );
+ JabberListRemove( LIST_BYTE, szPort );
+ }
+
+ JabberLog( "Thread ended: type=bytestream_send" );
+}
+
+static void JabberByteInitiateResult( XmlNode *iqNode, void *userdata )
+{
+ TCHAR* type;
+
+ if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+ if ( !lstrcmp( type, _T("result"))) {
+ }
+ else if ( !lstrcmp( type, _T("error"))) {
+ }
+}
+
+static void JabberByteSendConnection( HANDLE hConn, DWORD dwRemoteIP )
+{
+ SOCKET s;
+ SOCKADDR_IN saddr;
+ int len;
+ WORD localPort;
+ TCHAR szPort[8];
+ JABBER_BYTE_TRANSFER *jbt;
+ int recvResult, bytesParsed;
+ HANDLE hListen;
+ JABBER_LIST_ITEM *item;
+ char* buffer;
+ int datalen;
+
+ localPort = 0;
+ if (( s=JCallService( MS_NETLIB_GETSOCKET, ( WPARAM ) hConn, 0 )) != INVALID_SOCKET ) {
+ len = sizeof( saddr );
+ if ( getsockname( s, ( SOCKADDR * ) &saddr, &len ) != SOCKET_ERROR )
+ localPort = ntohs( saddr.sin_port );
+ }
+ if ( localPort == 0 ) {
+ JabberLog( "bytestream_send_connection unable to determine the local port, connection closed." );
+ Netlib_CloseHandle( hConn );
+ return;
+ }
+
+ mir_sntprintf( szPort, SIZEOF( szPort ), _T("%d"), localPort );
+ JabberLog( "bytestream_send_connection incoming connection accepted: local_port=" TCHAR_STR_PARAM, szPort );
+
+ if (( item=JabberListGetItemPtr( LIST_BYTE, szPort )) == NULL ) {
+ JabberLog( "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 ) {
+ JabberLog( "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 = JabberByteSendParse( hConn, jbt, buffer, datalen );
+ if ( bytesParsed < datalen )
+ memmove( buffer, buffer+bytesParsed, datalen-bytesParsed );
+ datalen -= bytesParsed;
+ }
+ if ( jbt->hConn ) Netlib_CloseHandle( jbt->hConn );
+ JabberLog( "bytestream_send_connection closing connection" );
+ jbt->hConn = hListen;
+ mir_free( buffer );
+
+ if ( jbt->hEvent != NULL ) SetEvent( jbt->hEvent );
+}
+
+static int JabberByteSendParse( 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];
+ mir_sntprintf( text, SIZEOF( text ), _T("%s%s%s"), jbt->sid, jbt->srcJID, jbt->dstJID );
+ char* szAuthString = t2a( text );
+ JabberLog( "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 );
+ if ( i>=20 && jbt->pfnSend( hConn, jbt->userdata )==TRUE )
+ jbt->state = JBT_DONE;
+ else
+ jbt->state = JBT_ERROR;
+ }
+ mir_free( szAuthString );
+ }
+ else
+ jbt->state = JBT_ERROR;
+ break;
+ }
+
+ return datalen;
+}
+
+///////////////// Bytestream receiving /////////////////////////
+
+static int JabberByteReceiveParse( HANDLE hConn, JABBER_BYTE_TRANSFER *jbt, char* buffer, int datalen );
+
+void __cdecl JabberByteReceiveThread( JABBER_BYTE_TRANSFER *jbt )
+{
+ XmlNode *iqNode, *queryNode, *n;
+ TCHAR *from, *to, *sid, *szId, *szHost, *szPort, *str;
+ int i;
+ WORD port;
+ HANDLE hConn;
+ char data[3];
+ char* buffer;
+ int datalen, bytesParsed, recvResult;
+ BOOL validStreamhost;
+
+ if ( jbt == NULL ) return;
+ if (( iqNode=jbt->iqNode )!=NULL &&
+ ( from=JabberXmlGetAttrValue( iqNode, "from" ))!=NULL &&
+ ( to=JabberXmlGetAttrValue( iqNode, "to" ))!=NULL &&
+ ( queryNode=JabberXmlGetChild( iqNode, "query" ))!=NULL &&
+ ( sid=JabberXmlGetAttrValue( queryNode, "sid" ))!=NULL &&
+ ( n=JabberXmlGetChild( queryNode, "streamhost" ))!=NULL ) {
+
+ szId = JabberXmlGetAttrValue( iqNode, "id" );
+ jbt->iqId = ( szId ) ? mir_tstrdup( szId ):NULL;
+ jbt->srcJID = mir_tstrdup( from );
+ jbt->dstJID = mir_tstrdup( to );
+ jbt->sid = mir_tstrdup( sid );
+
+ if (( buffer=( char* )mir_alloc( JABBER_NETWORK_BUFFER_SIZE )) == NULL ) {
+ JabberLog( "bytestream_send cannot allocate network buffer, connection closed." );
+
+ XmlNodeIq iq( "error", jbt->iqId, jbt->srcJID );
+ XmlNode* e = iq.addChild( "error" ); e->addAttr( "code", 406 ); e->addAttr( "type", "auth" );
+ XmlNode* na = e->addChild( "not-acceptable" ); na->addAttr( "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas" );
+ JabberSend( jabberThreadInfo->s, iq );
+
+ JabberByteFreeJbt( jbt );
+ return;
+ }
+
+ jbt->state = JBT_INIT;
+ validStreamhost = FALSE;
+ for ( i=1; ( n=JabberXmlGetNthChild( queryNode, "streamhost", i ))!=NULL; i++ ) {
+ if (( szHost=JabberXmlGetAttrValue( n, "host" ))!=NULL &&
+ ( szPort=JabberXmlGetAttrValue( n, "port" ))!=NULL &&
+ ( str=JabberXmlGetAttrValue( n, "jid" ))!=NULL ) {
+
+ port = ( WORD )_ttoi( szPort );
+ if ( jbt->streamhostJID ) mir_free( jbt->streamhostJID );
+ jbt->streamhostJID = mir_tstrdup( str );
+
+ JabberLog( "bytestream_recv connecting to " TCHAR_STR_PARAM ":%d", szHost, port );
+ NETLIBOPENCONNECTION nloc = { 0 };
+ nloc.cbSize = sizeof( nloc );
+ #if defined( _UNICODE )
+ nloc.szHost = u2a(szHost);
+ #else
+ nloc.szHost = szHost;
+ #endif
+ nloc.wPort = port;
+ hConn = ( HANDLE ) JCallService( MS_NETLIB_OPENCONNECTION, ( WPARAM ) hNetlibUser, ( LPARAM )&nloc );
+ #if defined( _UNICODE )
+ mir_free((void*)nloc.szHost);
+ #endif
+ if ( hConn == NULL ) {
+ JabberLog( "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 = JabberByteReceiveParse( 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 );
+ JabberLog( "bytestream_recv_connection closing connection" );
+ }
+ if ( jbt->state==JBT_ERROR || validStreamhost==TRUE )
+ break;
+ JabberLog( "bytestream_recv_connection stream cannot be established, try next streamhost" );
+ }
+ mir_free( buffer );
+ jbt->pfnFinal(( jbt->state==JBT_DONE )?TRUE:FALSE, jbt->userdata );
+ if ( !validStreamhost ) {
+ JabberLog( "bytestream_recv_connection session not completed" );
+
+ XmlNodeIq iq( "error", jbt->iqId, jbt->srcJID );
+ XmlNode* e = iq.addChild( "error" ); e->addAttr( "code", 404 ); e->addAttr( "type", _T("cancel"));
+ XmlNode* na = e->addChild( "item-not-found" ); na->addAttr( "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas" );
+ JabberSend( jabberThreadInfo->s, iq );
+ } }
+
+ JabberByteFreeJbt( jbt );
+ JabberLog( "Thread ended: type=bytestream_recv" );
+}
+
+static int JabberByteReceiveParse( 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[256];
+ mir_sntprintf( text, SIZEOF( text ), _T("%s%s%s"), jbt->sid, jbt->srcJID, jbt->dstJID );
+ char* szAuthString = t2a( text );
+ JabberLog( "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 )) {
+ if ( buffer[3]==1 && datalen>=10 )
+ num = 10;
+ else if ( buffer[3]==3 && datalen>=buffer[4]+7 )
+ num = buffer[4] + 7;
+ else {
+ jbt->state = JBT_SOCKSERR;
+ break;
+ }
+ jbt->state = JBT_RECVING;
+
+ XmlNodeIq iq( "result", jbt->iqId, jbt->srcJID );
+ XmlNode* query = iq.addQuery( "http://jabber.org/protocol/bytestreams" );
+ XmlNode* stream = query->addChild( "streamhost-used" ); stream->addAttr( "jid", jbt->streamhostJID );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+ else jbt->state = JBT_SOCKSERR;
+ break;
+
+ case JBT_RECVING:
+ bytesReceived = jbt->pfnRecv( hConn, jbt->userdata, buffer, datalen );
+ if ( bytesReceived < 0 )
+ jbt->state = JBT_ERROR;
+ else if ( bytesReceived == 0 )
+ jbt->state = JBT_DONE;
+ break;
+ }
+
+ return num;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_byte.h b/miranda-wine/protocols/JabberG/jabber_byte.h
new file mode 100644
index 0000000..cd16478
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_byte.h
@@ -0,0 +1,52 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_byte.h,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#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;
+
+typedef struct {
+ TCHAR* sid;
+ TCHAR* srcJID;
+ TCHAR* dstJID;
+ TCHAR* streamhostJID;
+ TCHAR* iqId;
+ JABBER_BYTE_STATE state;
+ HANDLE hConn;
+ HANDLE hEvent;
+ XmlNode *iqNode;
+ BOOL ( *pfnSend )( HANDLE hConn, void *userdata );
+ int ( *pfnRecv )( HANDLE hConn, void *userdata, char* buffer, int datalen );
+ void ( *pfnFinal )( BOOL success, void *userdata );
+ void *userdata;
+} JABBER_BYTE_TRANSFER;
+
+void __cdecl JabberByteSendThread( JABBER_BYTE_TRANSFER *jbt );
+void __cdecl JabberByteReceiveThread( JABBER_BYTE_TRANSFER *jbt );
+
+#endif
diff --git a/miranda-wine/protocols/JabberG/jabber_chat.cpp b/miranda-wine/protocols/JabberG/jabber_chat.cpp
new file mode 100644
index 0000000..946e38b
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_chat.cpp
@@ -0,0 +1,796 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_chat.cpp,v $
+Revision : $Revision: 3666 $
+Last change on : $Date: 2006-08-31 16:51:33 +0400 (Чтв, 31 Ðвг 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include "jabber_iq.h"
+#include "resource.h"
+
+extern HANDLE hInitChat;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// One string entry dialog
+
+struct JabberEnterStringParams
+{ TCHAR* result;
+ size_t resultLen;
+};
+
+BOOL CALLBACK JabberEnterStringDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault( hwndDlg );
+ JabberEnterStringParams* params = ( JabberEnterStringParams* )lParam;
+ SetWindowLong( hwndDlg, GWL_USERDATA, ( LONG )params );
+ SetWindowText( hwndDlg, params->result );
+ return TRUE;
+ }
+
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDOK:
+ { JabberEnterStringParams* params = ( JabberEnterStringParams* )GetWindowLong( hwndDlg, GWL_USERDATA );
+ GetDlgItemText( hwndDlg, IDC_TOPIC, params->result, params->resultLen );
+ params->result[ params->resultLen-1 ] = 0;
+ EndDialog( hwndDlg, 1 );
+ break;
+ }
+ case IDCANCEL:
+ EndDialog( hwndDlg, 0 );
+ break;
+ } }
+
+ return FALSE;
+}
+
+BOOL JabberEnterString( TCHAR* result, size_t resultLen )
+{
+ JabberEnterStringParams params = { result, resultLen };
+ return DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_GROUPCHAT_INPUT ), NULL, JabberEnterStringDlgProc, LPARAM( &params ));
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberGcInit - initializes the new chat
+
+static char* sttRoles[] = { "Other", "Visitors", "Participants", "Moderators" };
+
+int JabberGcInit( WPARAM wParam, LPARAM lParam )
+{
+ JABBER_LIST_ITEM* item = ( JABBER_LIST_ITEM* )wParam;
+ GCSESSION gcw = {0};
+ GCEVENT gce = {0};
+
+ #if defined( _UNICODE )
+ TCHAR* wszNick = JabberNickFromJID( item->jid );
+ char* szNick = u2a( wszNick );
+ mir_free( wszNick );
+ char* jid = u2a( item->jid );
+ #else
+ char* szNick = JabberNickFromJID( item->jid );
+ char* jid = item->jid;
+ #endif
+ gcw.cbSize = sizeof(GCSESSION);
+ gcw.iType = GCW_CHATROOM;
+ gcw.pszModule = jabberProtoName;
+ gcw.pszName = szNick;
+ gcw.pszID = jid;
+ gcw.pszStatusbarText = NULL;
+ gcw.bDisableNickList = FALSE;
+ JCallService(MS_GC_NEWSESSION, NULL, (LPARAM)&gcw);
+
+ HANDLE hContact = JabberHContactFromJID( item->jid );
+ if ( hContact != NULL ) {
+ DBVARIANT dbv;
+ if ( !DBGetContactSetting( hContact, jabberProtoName, "MyNick", &dbv )) {
+ if ( !strcmp( dbv.pszVal, szNick ))
+ JDeleteSetting( hContact, "MyNick" );
+ else
+ JSetStringT( hContact, "MyNick", item->nick );
+ JFreeVariant( &dbv );
+ }
+ else JSetStringT( hContact, "MyNick", item->nick );
+ }
+ mir_free( szNick );
+
+ item->bChatActive = TRUE;
+
+ GCDEST gcd = { jabberProtoName, jid, GC_EVENT_ADDGROUP };
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ for ( int i=sizeof(sttRoles)/sizeof(char*)-1; i >= 0; i-- ) {
+ gce.pszStatus = Translate( sttRoles[i] );
+ JCallService(MS_GC_EVENT, NULL, ( LPARAM )&gce );
+ }
+
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ gcd.iType = GC_EVENT_CONTROL;
+ JCallService(MS_GC_EVENT, SESSION_INITDONE, (LPARAM)&gce);
+ JCallService(MS_GC_EVENT, SESSION_ONLINE, (LPARAM)&gce);
+ JCallService(MS_GC_EVENT, WINDOW_VISIBLE, (LPARAM)&gce);
+ #if defined( _UNICODE )
+ mir_free( jid );
+ #endif
+ return 0;
+}
+
+void JabberGcLogCreate( JABBER_LIST_ITEM* item )
+{
+ if ( item->bChatActive )
+ return;
+
+ NotifyEventHooks( hInitChat, (WPARAM)item, 0 );
+}
+
+void JabberGcLogUpdateMemberStatus( JABBER_LIST_ITEM* item, TCHAR* nick, int action, XmlNode* reason )
+{
+ int statusToSet = 0;
+ char* szReason = NULL;
+ if ( reason != NULL && reason->text != NULL ) {
+ #if defined( _UNICODE )
+ szReason = u2a( reason->text );
+ #else
+ szReason = reason->text;
+ #endif
+ }
+
+ TCHAR* myNick = (item->nick == NULL) ? NULL : mir_tstrdup( item->nick );
+ if ( myNick == NULL )
+ myNick = JabberNickFromJID( jabberJID );
+
+ #if defined( _UNICODE )
+ char* dispNick = u2a( nick );
+ char* szNick = u2a( myNick );
+ char* jid = u2a( item->jid );
+ #else
+ char* dispNick = nick;
+ char* szNick = myNick;
+ char* jid = item->jid;
+ #endif
+
+ GCDEST gcd = { jabberProtoName, jid, 0 };
+ GCEVENT gce = {0};
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pszNick = dispNick;
+ gce.pszUID = dispNick;
+ gce.pDest = &gcd;
+ gce.pszText = szReason;
+ if ( item->bChatActive == 2 ) {
+ gce.bAddToLog = TRUE;
+ gce.time = time(0);
+ }
+
+ switch( gcd.iType = action ) {
+ case GC_EVENT_PART: break;
+ case GC_EVENT_KICK: gce.pszStatus = Translate( "Moderator" ); break;
+ default:
+ for ( int i=0; i < item->resourceCount; i++ ) {
+ JABBER_RESOURCE_STATUS& JS = item->resource[i];
+ if ( !lstrcmp( nick, JS.resourceName )) {
+ if ( action != GC_EVENT_JOIN ) {
+ switch( action ) {
+ case 0:
+ gcd.iType = GC_EVENT_ADDSTATUS;
+ case GC_EVENT_REMOVESTATUS:
+ gce.bAddToLog = false;
+ }
+ gce.pszText = Translate( "Moderator" );
+ }
+ gce.pszStatus = JTranslate( sttRoles[ JS.role ] );
+ gce.bIsMe = ( lstrcmpA( szNick, dispNick ) == 0 );
+ statusToSet = JS.status;
+ break;
+ } } }
+
+ JCallService( MS_GC_EVENT, NULL, ( LPARAM )&gce );
+
+ if ( statusToSet != 0 ) {
+ gce.pszText = dispNick;
+ 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;
+ JCallService( MS_GC_EVENT, NULL, ( LPARAM )&gce );
+ }
+
+ mir_free( myNick );
+ #if defined( _UNICODE )
+ mir_free( dispNick );
+ mir_free( szReason );
+ mir_free( jid );
+ mir_free( szNick );
+ #endif
+}
+
+void JabberGcQuit( JABBER_LIST_ITEM* item, int code, XmlNode* reason )
+{
+ char* szReason = NULL;
+ if ( reason != NULL && reason->text != NULL ) {
+ #if defined( _UNICODE )
+ szReason = u2a( reason->text );
+ #else
+ szReason = reason->text;
+ #endif
+ }
+
+ #if defined( _UNICODE )
+ char* jid = u2a( item->jid );
+ #else
+ char* jid = item->jid;
+ #endif
+
+ GCDEST gcd = { jabberProtoName, jid, GC_EVENT_CONTROL };
+ GCEVENT gce = {0};
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pszUID = jid;
+ gce.pDest = &gcd;
+ gce.pszText = szReason;
+
+ if ( code != 307 ) {
+ JCallService( MS_GC_EVENT, SESSION_TERMINATE, ( LPARAM )&gce );
+ JCallService( MS_GC_EVENT, WINDOW_CLEARLOG, ( LPARAM )&gce );
+ }
+ else {
+ TCHAR* myNick = JabberNickFromJID( jabberJID );
+ JabberGcLogUpdateMemberStatus( item, myNick, GC_EVENT_KICK, reason );
+ mir_free( myNick );
+ JCallService( MS_GC_EVENT, SESSION_OFFLINE, ( LPARAM )&gce );
+ }
+
+ DBDeleteContactSetting( JabberHContactFromJID( item->jid ), "CList", "Hidden" );
+ item->bChatActive = FALSE;
+
+ if ( jabberOnline ) {
+ XmlNode p( "presence" ); p.addAttr( "to", item->jid ); p.addAttr( "type", "unavailable" );
+ JabberSend( jabberThreadInfo->s, p );
+ JabberListRemove( LIST_CHATROOM, item->jid );
+ }
+
+ #if defined( _UNICODE )
+ mir_free( szReason );
+ mir_free( jid );
+ #endif
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Context menu hooks
+
+#define IDM_LEAVE 10
+#define IDM_TOPIC 12
+
+int JabberGcMenuHook( WPARAM wParam, LPARAM lParam )
+{
+ GCMENUITEMS* gcmi= ( GCMENUITEMS* )lParam;
+ if ( gcmi == NULL )
+ return 0;
+
+ if ( lstrcmpiA( gcmi->pszModule, jabberProtoName ))
+ return 0;
+
+ #if defined( _UNICODE )
+ TCHAR* pszID = a2u( gcmi->pszID );
+ #else
+ char* pszID = gcmi->pszID;
+ #endif
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_CHATROOM, pszID );
+ #if defined( _UNICODE )
+ mir_free( pszID );
+ #endif
+ if ( item == NULL )
+ return 0;
+
+ #if defined( _UNICODE )
+ TCHAR* pszUID = a2u( gcmi->pszUID );
+ #else
+ char* pszUID = gcmi->pszUID;
+ #endif
+
+ 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, pszUID )) him = &p;
+ }
+
+ #if defined( _UNICODE )
+ mir_free( pszUID );
+ #endif
+
+ if ( gcmi->Type == MENU_ON_LOG ) {
+ static struct gc_item sttLogListItems[] = {
+ { JTranslate( "&Leave chat session" ), IDM_LEAVE, MENU_ITEM, FALSE },
+ { NULL, 0, MENU_SEPARATOR, FALSE },
+ { JTranslate( "&Voice List..." ), IDM_VOICE, MENU_ITEM, TRUE },
+ { JTranslate( "&Ban List..." ), IDM_BAN, MENU_ITEM, TRUE },
+ { NULL, 0, MENU_SEPARATOR, FALSE },
+ { JTranslate( "&Member List..." ), IDM_MEMBER, MENU_ITEM, TRUE },
+ { JTranslate( "Mo&derator List..." ), IDM_MODERATOR, MENU_ITEM, TRUE },
+ { JTranslate( "&Admin List..." ), IDM_ADMIN, MENU_ITEM, TRUE },
+ { JTranslate( "&Owner List..." ), IDM_OWNER, MENU_ITEM, TRUE },
+ { NULL, 0, MENU_SEPARATOR, FALSE },
+ { JTranslate( "Change &Nickname..." ), IDM_NICK, MENU_ITEM, FALSE },
+ { JTranslate( "Set &Topic..." ), IDM_TOPIC, MENU_ITEM, FALSE },
+ { JTranslate( "&Invite a User..." ), IDM_INVITE, MENU_ITEM, FALSE },
+ { JTranslate( "Room Con&figuration..." ), IDM_CONFIG, MENU_ITEM, TRUE },
+ { NULL, 0, MENU_SEPARATOR, FALSE },
+ { JTranslate( "Destroy Room..." ), IDM_DESTROY, MENU_ITEM, TRUE }};
+
+ gcmi->nItems = sizeof( sttLogListItems ) / sizeof( sttLogListItems[0] );
+ gcmi->Item = sttLogListItems;
+
+ if ( me != NULL ) {
+ if ( me->role == ROLE_MODERATOR )
+ sttLogListItems[2].bDisabled = FALSE;
+
+ if ( me->affiliation == AFFILIATION_ADMIN )
+ sttLogListItems[3].bDisabled = sttLogListItems[5].bDisabled = sttLogListItems[6].bDisabled = FALSE;
+ else if ( me->affiliation == AFFILIATION_OWNER )
+ sttLogListItems[3].bDisabled = sttLogListItems[5].bDisabled =
+ sttLogListItems[6].bDisabled = sttLogListItems[7].bDisabled =
+ sttLogListItems[8].bDisabled = sttLogListItems[13].bDisabled =
+ sttLogListItems[15].bDisabled = FALSE;
+ }
+ }
+ else if ( gcmi->Type == MENU_ON_NICKLIST ) {
+ static struct gc_item sttListItems[] = {
+ { JTranslate( "&Leave chat session" ), IDM_LEAVE, MENU_ITEM, FALSE },
+ { NULL, 0, MENU_SEPARATOR, FALSE },
+ { JTranslate( "Kick" ), IDM_KICK, MENU_ITEM, TRUE },
+ { JTranslate( "Ban" ), IDM_BAN, MENU_ITEM, TRUE },
+ { NULL, 0, MENU_SEPARATOR, FALSE },
+ { JTranslate( "Toggle &Voice" ), IDM_VOICE, MENU_ITEM, TRUE },
+ { JTranslate( "Toggle Moderator" ), IDM_MODERATOR, MENU_ITEM, TRUE },
+ { JTranslate( "Toggle Admin" ), IDM_ADMIN, MENU_ITEM, TRUE },
+ { JTranslate( "Toggle Owner" ), IDM_OWNER, MENU_ITEM, TRUE }};
+
+ gcmi->nItems = sizeof( sttListItems )/sizeof( sttListItems[0] );
+ gcmi->Item = sttListItems;
+
+ if ( me != NULL && him != NULL ) {
+ if ( me->role == ROLE_MODERATOR )
+ if ( him->affiliation != AFFILIATION_ADMIN && him->affiliation != AFFILIATION_OWNER )
+ sttListItems[2].bDisabled = sttListItems[3].bDisabled = FALSE;
+
+ if ( me->affiliation == AFFILIATION_ADMIN ) {
+ if ( him->affiliation != AFFILIATION_ADMIN && him->affiliation != AFFILIATION_OWNER )
+ sttListItems[5].bDisabled = sttListItems[6].bDisabled = FALSE;
+ }
+ else if ( me->affiliation == AFFILIATION_OWNER )
+ sttListItems[5].bDisabled = sttListItems[6].bDisabled =
+ sttListItems[7].bDisabled = sttListItems[8].bDisabled = FALSE;
+ } }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Conference invitation dialog
+
+static BOOL CALLBACK JabberGcLogInviteDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault( hwndDlg );
+ SendMessage( hwndDlg, WM_SETICON, ICON_BIG, ( LPARAM )LoadIcon( hInst, MAKEINTRESOURCE( IDI_GROUP )) );
+ SetDlgItemTextA( hwndDlg, IDC_ROOM, ( char* )lParam );
+ HWND hwndComboBox = GetDlgItem( hwndDlg, IDC_USER );
+ int index = 0;
+ while (( index=JabberListFindNext( LIST_ROSTER, index )) >= 0 ) {
+ JABBER_LIST_ITEM* item = JabberListGetItemPtrFromIndex( index );
+ if ( item->status != ID_STATUS_OFFLINE ) {
+ // Add every non-offline users to the combobox
+ int n = SendMessage( hwndComboBox, CB_ADDSTRING, 0, ( LPARAM )item->jid );
+ SendMessage( hwndComboBox, CB_SETITEMDATA, n, ( LPARAM )item->jid );
+ }
+ index++;
+ }
+ SetWindowLong( hwndDlg, GWL_USERDATA, ( LONG ) mir_strdup(( char* )lParam ));
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_INVITE:
+ {
+ char* room = ( char* )GetWindowLong( hwndDlg, GWL_USERDATA );
+ if ( room != NULL ) {
+ TCHAR text[256], user[256], *pUser;
+ HWND hwndComboBox = GetDlgItem( hwndDlg, IDC_USER );
+ int n = SendMessage( hwndComboBox, CB_GETCURSEL, 0, 0 );
+ if ( n < 0 ) {
+ GetWindowText( hwndComboBox, user, SIZEOF( user ));
+ pUser = user;
+ }
+ else pUser = ( TCHAR* )SendMessage( hwndComboBox, CB_GETITEMDATA, n, 0 );
+
+ if ( pUser != NULL ) {
+ GetDlgItemText( hwndDlg, IDC_REASON, text, SIZEOF( text ));
+ int iqId = JabberSerialNext();
+
+ XmlNode m( "message" ); m.addAttr( "from", jabberJID ); m.addAttr( "to", room ); m.addAttrID( iqId );
+ XmlNode* x = m.addChild( "x" ); x->addAttr( "xmlns", _T("http://jabber.org/protocol/muc#user"));
+ XmlNode* i = x->addChild( "invite" ); i->addAttr( "to", pUser );
+ if ( text[0] != 0 )
+ i->addChild( "reason", text );
+ JabberSend( jabberThreadInfo->s, m );
+ } } }
+ // Fall through
+ case IDCANCEL:
+ case IDCLOSE:
+ DestroyWindow( hwndDlg );
+ return TRUE;
+ }
+ break;
+ case WM_CLOSE:
+ DestroyWindow( hwndDlg );
+ break;
+ case WM_DESTROY:
+ {
+ char* str;
+
+ if (( str=( char* )GetWindowLong( hwndDlg, GWL_USERDATA )) != NULL )
+ mir_free( str );
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Context menu processing
+
+static void JabberAdminSet( const TCHAR* to, const char* ns, const char* szItem, const TCHAR* itemVal, const char* var, const TCHAR* varVal )
+{
+ XmlNodeIq iq( "set", NOID, to );
+ XmlNode* query = iq.addQuery( ns );
+ XmlNode* item = query->addChild( "item" ); item->addAttr( szItem, itemVal ); item->addAttr( var, varVal );
+ JabberSend( jabberThreadInfo->s, iq );
+}
+
+static void JabberAdminGet( const TCHAR* to, const char* ns, const char* var, const TCHAR* varVal, JABBER_IQ_PFUNC foo )
+{
+ int id = JabberSerialNext();
+ JabberIqAdd( id, IQ_PROC_NONE, foo );
+
+ XmlNodeIq iq( "get", id, to );
+ XmlNode* query = iq.addQuery( ns );
+ XmlNode* item = query->addChild( "item" ); item->addAttr( var, varVal );
+ JabberSend( jabberThreadInfo->s, iq );
+}
+
+static void sttNickListHook( JABBER_LIST_ITEM* item, GCHOOK* gch )
+{
+ #if defined( _UNICODE )
+ TCHAR* pszUID = a2u( gch->pszUID );
+ #else
+ char* pszUID = gch->pszUID;
+ #endif
+
+ 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, pszUID )) him = &p;
+ }
+ #if defined( _UNICODE )
+ mir_free( pszUID );
+ #endif
+
+ if ( him == NULL || me == NULL )
+ return;
+
+ TCHAR szBuffer[ 1024 ];
+
+ switch( gch->dwData ) {
+ case IDM_LEAVE:
+ JabberGcQuit( item, 0, 0 );
+ break;
+
+ case IDM_KICK:
+ {
+ mir_sntprintf( szBuffer, SIZEOF(szBuffer), _T("%s %s"), TranslateT( "Reason to kick" ), him->resourceName );
+ if ( JabberEnterString( szBuffer, SIZEOF(szBuffer))) {
+ XmlNodeIq iq( "set", NOID, item->jid );
+ XmlNode* query = iq.addQuery( xmlnsAdmin );
+ XmlNode* item = query->addChild( "item" ); item->addAttr( "nick", him->resourceName ); item->addAttr( "role", "none" );
+ item->addChild( "reason", szBuffer );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+ break;
+ }
+
+ case IDM_BAN:
+ mir_sntprintf( szBuffer, SIZEOF(szBuffer), _T("%s %s"), TranslateT( "Reason to ban" ), him->resourceName );
+ if ( JabberEnterString( szBuffer, SIZEOF(szBuffer))) {
+ XmlNodeIq iq( "set", NOID, item->jid );
+ XmlNode* query = iq.addQuery( xmlnsAdmin );
+ XmlNode* item = query->addChild( "item" ); item->addAttr( "nick", him->resourceName ); item->addAttr( "affiliation", "outcast" );
+ item->addChild( "reason", szBuffer );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+ break;
+
+ case IDM_VOICE:
+ JabberAdminSet( item->jid, xmlnsAdmin, "nick", him->resourceName,
+ "role", ( him->role == ROLE_PARTICIPANT ) ? _T("visitor") : _T("participant"));
+ break;
+
+ case IDM_MODERATOR:
+ JabberAdminSet( item->jid, xmlnsAdmin, "nick", him->resourceName,
+ "role", ( him->role == ROLE_MODERATOR ) ? _T("participant") : _T("moderator"));
+ break;
+
+ case IDM_ADMIN:
+ JabberAdminSet( item->jid, xmlnsAdmin, "nick", him->resourceName,
+ "affiliation", ( him->affiliation==AFFILIATION_ADMIN )? _T("member") : _T("admin"));
+ break;
+
+ case IDM_OWNER:
+ JabberAdminSet( item->jid, xmlnsAdmin, "nick", him->resourceName,
+ "affiliation", ( him->affiliation==AFFILIATION_OWNER ) ? _T("admin") : _T("owner"));
+ break;
+} }
+
+static void sttLogListHook( JABBER_LIST_ITEM* item, GCHOOK* gch )
+{
+ TCHAR szBuffer[ 1024 ];
+ #if defined( _UNICODE )
+ TCHAR* pszID = a2u(gch->pDest->pszID);
+ #else
+ TCHAR* pszID = gch->pDest->pszID;
+ #endif
+
+ switch( gch->dwData ) {
+ case IDM_VOICE:
+ JabberAdminGet( pszID, xmlnsAdmin, "role", _T("participant"), JabberIqResultMucGetVoiceList );
+ break;
+
+ case IDM_MEMBER:
+ JabberAdminGet( pszID, xmlnsAdmin, "affiliation", _T("member"), JabberIqResultMucGetMemberList );
+ break;
+
+ case IDM_MODERATOR:
+ JabberAdminGet( pszID, xmlnsAdmin, "role", _T("moderator"), JabberIqResultMucGetModeratorList );
+ break;
+
+ case IDM_BAN:
+ JabberAdminGet( pszID, xmlnsAdmin, "affiliation", _T("outcast"), JabberIqResultMucGetBanList );
+ break;
+
+ case IDM_ADMIN:
+ JabberAdminGet( pszID, xmlnsOwner, "affiliation", _T("admin"), JabberIqResultMucGetAdminList );
+ break;
+
+ case IDM_OWNER:
+ JabberAdminGet( pszID, xmlnsOwner, "affiliation", _T("owner"), JabberIqResultMucGetOwnerList );
+ break;
+
+ case IDM_TOPIC:
+ mir_sntprintf( szBuffer, SIZEOF(szBuffer), _T("%s %s"), TranslateT( "Set topic for" ), pszID );
+ if ( JabberEnterString( szBuffer, SIZEOF(szBuffer))) {
+ XmlNode msg( "message" ); msg.addAttr( "to", pszID ); msg.addAttr( "type", "groupchat" );
+ msg.addChild( "subject", szBuffer );
+ JabberSend( jabberThreadInfo->s, msg );
+ }
+ break;
+
+ case IDM_NICK:
+ mir_sntprintf( szBuffer, SIZEOF(szBuffer), _T("%s %s"), TranslateT( "Change nickname in" ), pszID );
+ if ( JabberEnterString( szBuffer, SIZEOF(szBuffer))) {
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_CHATROOM, pszID );
+ if ( item != NULL ) {
+ TCHAR text[ 1024 ];
+ mir_sntprintf( text, SIZEOF( text ), _T("%s/%s"), pszID, szBuffer );
+ JabberSendPresenceTo( jabberStatus, text, NULL );
+ } }
+ break;
+
+ case IDM_INVITE:
+ CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_GROUPCHAT_INVITE ), NULL, JabberGcLogInviteDlgProc, ( LPARAM )gch->pDest->pszID );
+ break;
+
+ case IDM_CONFIG:
+ {
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultGetMuc );
+
+ XmlNodeIq iq( "get", iqId, pszID );
+ XmlNode* query = iq.addQuery( xmlnsOwner );
+ JabberSend( jabberThreadInfo->s, iq );
+ break;
+ }
+ case IDM_DESTROY:
+ mir_sntprintf( szBuffer, SIZEOF(szBuffer), _T("%s %s"), TranslateT( "Reason to destroy" ), pszID );
+ if ( !JabberEnterString( szBuffer, SIZEOF(szBuffer)))
+ break;
+
+ { XmlNodeIq iq( "set", NOID, pszID );
+ XmlNode* query = iq.addQuery( xmlnsOwner );
+ query->addChild( "destroy" )->addChild( "reason", szBuffer );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+
+ case IDM_LEAVE:
+ JabberGcQuit( item, 0, 0 );
+ break;
+ }
+
+ #if defined( _UNICODE )
+ mir_free( pszID );
+ #endif
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Sends a private message to a chat user
+
+static void sttSendPrivateMessage( JABBER_LIST_ITEM* item, const TCHAR* nick )
+{
+ TCHAR szFullJid[ 256 ];
+ mir_sntprintf( szFullJid, SIZEOF(szFullJid), _T("%s/%s"), item->jid, nick );
+ HANDLE hContact = JabberDBCreateContact( szFullJid, NULL, TRUE, FALSE );
+ if ( hContact != NULL ) {
+ for ( int i=0; i < item->resourceCount; i++ ) {
+ if ( _tcsicmp( item->resource[i].resourceName, nick ) == 0 ) {
+ JSetWord( hContact, "Status", item->resource[i].status );
+ break;
+ } }
+
+ DBWriteContactSettingByte( hContact, "CList", "Hidden", 1 );
+ JSetStringT( hContact, "Nick", nick );
+ DBWriteContactSettingDword( hContact, "Ignore", "Mask1", 0 );
+ JCallService( MS_MSG_SENDMESSAGE, ( WPARAM )hContact, 0 );
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// General chat event processing hook
+
+int JabberGcEventHook(WPARAM wParam,LPARAM lParam)
+{
+ GCHOOK* gch = ( GCHOOK* )lParam;
+ if ( gch == NULL )
+ return 0;
+
+ if ( lstrcmpiA( gch->pDest->pszModule, jabberProtoName ))
+ return 0;
+
+ #if defined( _UNICODE )
+ TCHAR* pszID = a2u(gch->pDest->pszID);
+ #else
+ TCHAR* pszID = gch->pDest->pszID;
+ #endif
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_CHATROOM, pszID );
+ #if defined( _UNICODE )
+ mir_free( pszID );
+ #endif
+ if ( item == NULL )
+ return 0;
+
+ switch ( gch->pDest->iType ) {
+ case GC_USER_MESSAGE:
+ if ( gch->pszText && lstrlenA( gch->pszText) > 0 ) {
+ rtrim( gch->pszText );
+
+ if ( jabberOnline ) {
+ XmlNode m( "message" ); m.addAttr( "to", item->jid ); m.addAttr( "type", "groupchat" );
+ XmlNode* b = m.addChild( "body", gch->pszText );
+ if ( b->sendText != NULL )
+ UnEscapeChatTags( b->sendText );
+ JabberSend( jabberThreadInfo->s, m );
+ } }
+ break;
+
+ case GC_USER_PRIVMESS:
+ #if defined( _UNICODE )
+ { TCHAR* id = a2u( gch->pszUID );
+ sttSendPrivateMessage( item, id );
+ mir_free( id );
+ }
+ #else
+ sttSendPrivateMessage( item, gch->pszUID );
+ #endif
+ break;
+
+ case GC_USER_LOGMENU:
+ sttLogListHook( item, gch );
+ break;
+
+ case GC_USER_NICKLISTMENU:
+ sttNickListHook( item, gch );
+ break;
+
+ case GC_USER_CHANMGR:
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultGetMuc );
+
+ XmlNodeIq iq( "get", iqId, item->jid );
+ XmlNode* query = iq.addQuery( xmlnsOwner );
+ JabberSend( jabberThreadInfo->s, iq );
+ break;
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+void JabberAddMucListItem( JABBER_MUC_JIDLIST_INFO* jidListInfo, TCHAR* str )
+{
+ const char* field = _tcschr(str,'@') ? "jid" : "nick";
+ TCHAR* roomJid = jidListInfo->roomJid;
+
+ switch (jidListInfo->type) {
+ case MUC_VOICELIST:
+ JabberAdminSet( roomJid, xmlnsAdmin, field, str, "role", _T("participant"));
+ JabberAdminGet( roomJid, xmlnsAdmin, "role", _T("participant"), JabberIqResultMucGetVoiceList);
+ break;
+ case MUC_MEMBERLIST:
+ JabberAdminSet( roomJid, xmlnsAdmin, field, str, "affiliation", _T("member"));
+ JabberAdminGet( roomJid, xmlnsAdmin, "affiliation", _T("member"), JabberIqResultMucGetMemberList);
+ break;
+ case MUC_MODERATORLIST:
+ JabberAdminSet( roomJid, xmlnsAdmin, field, str, "role", _T("moderator"));
+ JabberAdminGet( roomJid, xmlnsAdmin, "role", _T("moderator"), JabberIqResultMucGetModeratorList);
+ break;
+ case MUC_BANLIST:
+ JabberAdminSet( roomJid, xmlnsAdmin, field, str, "affiliation", _T("outcast"));
+ JabberAdminGet( roomJid, xmlnsAdmin, "affiliation", _T("outcast"), JabberIqResultMucGetBanList);
+ break;
+ case MUC_ADMINLIST:
+ JabberAdminSet( roomJid, xmlnsOwner, field, str, "affiliation", _T("admin"));
+ JabberAdminGet( roomJid, xmlnsOwner, "affiliation", _T("admin"), JabberIqResultMucGetAdminList);
+ break;
+ case MUC_OWNERLIST:
+ JabberAdminSet( roomJid, xmlnsOwner, field, str, "affiliation", _T("owner"));
+ JabberAdminGet( roomJid, xmlnsOwner, "affiliation", _T("owner"), JabberIqResultMucGetOwnerList);
+ break;
+} }
+
+void JabberDeleteMucListItem( JABBER_MUC_JIDLIST_INFO* jidListInfo, TCHAR* jid )
+{
+ TCHAR* roomJid = jidListInfo->roomJid;
+
+ switch ( jidListInfo->type ) {
+ case MUC_VOICELIST: // change role to visitor ( from participant )
+ JabberAdminSet( roomJid, xmlnsAdmin, "jid", jid, "role", _T("visitor"));
+ break;
+ case MUC_BANLIST: // change affiliation to none ( from outcast )
+ case MUC_MEMBERLIST: // change affiliation to none ( from member )
+ JabberAdminSet( roomJid, xmlnsAdmin, "jid", jid, "affiliation", _T("none"));
+ break;
+ case MUC_MODERATORLIST: // change role to participant ( from moderator )
+ JabberAdminSet( roomJid, xmlnsAdmin, "jid", jid, "role", _T("participant"));
+ break;
+ case MUC_ADMINLIST: // change affiliation to member ( from admin )
+ JabberAdminSet( roomJid, xmlnsOwner, "jid", jid, "affiliation", _T("member"));
+ break;
+ case MUC_OWNERLIST: // change affiliation to admin ( from owner )
+ JabberAdminSet( roomJid, xmlnsOwner, "jid", jid, "affiliation", _T("admin"));
+ break;
+} }
diff --git a/miranda-wine/protocols/JabberG/jabber_file.cpp b/miranda-wine/protocols/JabberG/jabber_file.cpp
new file mode 100644
index 0000000..56eafd7
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_file.cpp
@@ -0,0 +1,611 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_file.cpp,v $
+Revision : $Revision: 2961 $
+Last change on : $Date: 2006-05-26 23:39:41 +0400 (Птн, 26 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include <io.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+static char* fileBaseName;
+static char* filePathName;
+
+static int JabberFileReceiveParse( filetransfer* ft, char* buffer, int datalen );
+static void JabberFileServerConnection( HANDLE hNewConnection, DWORD dwRemoteIP );
+static int JabberFileSendParse( JABBER_SOCKET s, filetransfer* ft, char* buffer, int datalen );
+
+#define JABBER_NETWORK_BUFFER_SIZE 2048
+
+void __cdecl JabberFileReceiveThread( filetransfer* ft )
+{
+ char* buffer;
+ int datalen;
+ JABBER_SOCKET s;
+
+ JabberLog( "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 ) {
+ JabberLog( "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;
+ s = ( HANDLE ) JCallService( MS_NETLIB_OPENCONNECTION, ( WPARAM ) hNetlibUser, ( LPARAM )&nloc );
+ if ( s == NULL ) {
+ JabberLog( "Connection failed ( %d ), thread ended", WSAGetLastError());
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 );
+ mir_free( buffer );
+ delete ft;
+ return;
+ }
+
+ ft->s = s;
+
+ JabberSend( s, "GET /%s HTTP/1.1\r\nHost: %s\r\n\r\n", ft->httpPath, ft->httpHostName );
+ ft->state = FT_CONNECTING;
+
+ JabberLog( "Entering file_receive recv loop" );
+ datalen = 0;
+
+ while ( ft->state != FT_DONE && ft->state != FT_ERROR ) {
+ int recvResult, bytesParsed;
+
+ JabberLog( "Waiting for data..." );
+ recvResult = Netlib_Recv( s, buffer+datalen, JABBER_NETWORK_BUFFER_SIZE-datalen, 0 );
+ if ( recvResult <= 0 )
+ break;
+ datalen += recvResult;
+
+ bytesParsed = JabberFileReceiveParse( ft, buffer, datalen );
+ if ( bytesParsed < datalen )
+ memmove( buffer, buffer+bytesParsed, datalen-bytesParsed );
+ datalen -= bytesParsed;
+ }
+
+ if ( ft->s )
+ Netlib_CloseHandle( s );
+ ft->s = NULL;
+
+ if ( ft->state==FT_RECEIVING || ft->state==FT_DONE )
+ _close( ft->fileId );
+
+ if ( ft->state==FT_DONE || ( ft->state==FT_RECEIVING && ft->std.currentFileSize < 0 ))
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0 );
+ else
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 );
+
+ JabberLog( "Thread ended: type=file_receive server='%s'", ft->httpHostName );
+
+ mir_free( buffer );
+ delete ft;
+}
+
+static int JabberFileReceiveParse( filetransfer* ft, char* buffer, int datalen )
+{
+ char* p, *q, *s, *eob;
+ char* str;
+ int num, code;
+
+ eob = buffer + datalen;
+ p = buffer;
+ num = 0;
+ for ( ;; ) {
+ 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';
+ JabberLog( "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;
+ JabberLog( "Change to FT_INITIALIZING" );
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, ft, 0 );
+ }
+ }
+ else { // FT_INITIALIZING
+ if ( str[0] == '\0' ) {
+ if (( s=strrchr( ft->httpPath, '/' )) != NULL )
+ s++;
+ else
+ s = ft->httpPath;
+ ft->std.currentFile = mir_strdup( s );
+ JabberHttpUrlDecode( ft->std.currentFile );
+ if ( ft->create() == -1 ) {
+ ft->state = FT_ERROR;
+ break;
+ }
+ ft->state = FT_RECEIVING;
+ ft->std.currentFileSize = 0;
+ JabberLog( "Change to FT_RECEIVING" );
+ }
+ else if (( s=strchr( str, ':' )) != NULL ) {
+ *s = '\0';
+ if ( !strcmp( str, "Content-Length" ))
+ ft->std.totalBytes = strtol( s+1, NULL, 10 );
+ } }
+
+ 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, remainingBytes, writeSize;
+
+ 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 ) {
+ JabberLog( "_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 __cdecl JabberFileServerThread( filetransfer* ft )
+{
+ NETLIBBIND nlb = {0};
+ JABBER_SOCKET s;
+ int i;
+ JABBER_LIST_ITEM *item;
+ struct in_addr in;
+ HANDLE hEvent;
+ TCHAR *p, *resource;
+ char *myAddr;
+ char *pFileName;
+ DBVARIANT dbv;
+ TCHAR szPort[20];
+ int id;
+
+ JabberLog( "Thread started: type=file_send" );
+
+ ft->type = FT_OOB;
+
+ nlb.cbSize = sizeof( NETLIBBIND );
+ nlb.pfnNewConnection = JabberFileServerConnection;
+ nlb.wPort = 0; // Use user-specified incoming port ranges, if available
+ s = ( HANDLE ) JCallService( MS_NETLIB_BINDPORT, ( WPARAM ) hNetlibUser, ( LPARAM )&nlb );
+ if ( s == NULL ) {
+ JabberLog( "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 = s;
+ JabberLog( "ft->s = %d", s );
+
+ hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ ft->hFileEvent = hEvent;
+
+ mir_sntprintf( szPort, SIZEOF( szPort ), _T("%d"), nlb.wPort );
+ item = JabberListAdd( LIST_FILE, szPort );
+ item->ft = ft;
+
+ if (( p=JabberListGetBestClientResourceNamePtr( ft->jid )) == NULL )
+ resource = NULL;
+ else
+ resource = mir_tstrdup( p );
+
+ if ( resource != NULL ) {
+ ft->state = FT_CONNECTING;
+ for ( 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;
+
+ char* p;
+ if (( p=strrchr( ft->std.files[i], '\\' )) != NULL )
+ p++;
+ else
+ p = ft->std.files[i];
+ in.S_un.S_addr = jabberLocalIP;
+ if (( pFileName=JabberHttpUrlEncode( p )) != NULL ) {
+ id = JabberSerialNext();
+ 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 );
+
+ if ( JGetByte( "BsDirect", TRUE ) && JGetByte( "BsDirectManual", FALSE )) {
+ if ( !DBGetContactSetting( NULL, jabberProtoName, "BsDirectAddr", &dbv )) {
+ myAddr = NEWSTR_ALLOCA( dbv.pszVal );
+ JFreeVariant( &dbv );
+ }
+ else myAddr = inet_ntoa( in );
+ }
+ else myAddr = inet_ntoa( in );
+
+ char szAddr[ 256 ];
+ mir_snprintf( szAddr, sizeof(szAddr), "http://%s:%d/%s", myAddr, nlb.wPort, pFileName );
+
+ XmlNodeIq iq( "set", id, ft->jid );
+ XmlNode* query = iq.addQuery( "jabber:iq:oob" );
+ query->addChild( "url", szAddr );
+ query->addChild( "desc", ft->szDescription );
+ JabberSend( jabberThreadInfo->s, iq );
+
+ JabberLog( "Waiting for the file to be sent..." );
+ WaitForSingleObject( hEvent, INFINITE );
+ mir_free( pFileName );
+ }
+ JabberLog( "File sent, advancing to the next file..." );
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0 );
+ }
+ CloseHandle( hEvent );
+ ft->hFileEvent = NULL;
+ JabberLog( "Finish all files" );
+
+ Netlib_CloseHandle( s );
+
+ mir_free( resource );
+ }
+
+ ft->s = NULL;
+ JabberLog( "ft->s is NULL" );
+
+ JabberListRemove( LIST_FILE, szPort );
+
+ switch ( ft->state ) {
+ case FT_DONE:
+ JabberLog( "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:
+ JabberLog( "Finish with errors" );
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 );
+ break;
+ }
+
+ JabberLog( "Thread ended: type=file_send" );
+
+ delete ft;
+}
+
+static void JabberFileServerConnection( JABBER_SOCKET hConnection, DWORD dwRemoteIP )
+{
+ SOCKET s;
+ JABBER_SOCKET slisten;
+ SOCKADDR_IN saddr;
+ int len;
+ WORD localPort;
+ JABBER_LIST_ITEM *item;
+ char* buffer;
+ int datalen;
+ filetransfer* ft;
+ TCHAR szPort[20];
+
+ localPort = 0;
+ if (( s=JCallService( MS_NETLIB_GETSOCKET, ( WPARAM ) hConnection, 0 )) != INVALID_SOCKET ) {
+ len = sizeof( saddr );
+ if ( getsockname( s, ( SOCKADDR * ) &saddr, &len ) != SOCKET_ERROR ) {
+ localPort = ntohs( saddr.sin_port );
+ }
+ }
+ if ( localPort == 0 ) {
+ JabberLog( "Unable to determine the local port, file server connection closed." );
+ Netlib_CloseHandle( hConnection );
+ return;
+ }
+
+ mir_sntprintf( szPort, sizeof( szPort ), _T("%d"), localPort );
+ JabberLog( "File server incoming connection accepted: local_port=" TCHAR_STR_PARAM, szPort );
+
+ if (( item=JabberListGetItemPtr( LIST_FILE, szPort )) == NULL ) {
+ JabberLog( "No file is currently served, file server connection closed." );
+ Netlib_CloseHandle( hConnection );
+ return;
+ }
+
+ ft = item->ft;
+ slisten = ft->s;
+ ft->s = hConnection;
+ JabberLog( "Set ft->s to %d ( saving %d )", hConnection, slisten );
+
+ if (( buffer=( char* )mir_alloc( JABBER_NETWORK_BUFFER_SIZE+1 )) == NULL ) {
+ JabberLog( "Cannot allocate network buffer, file server connection closed." );
+ Netlib_CloseHandle( hConnection );
+ ft->state = FT_ERROR;
+ if ( ft->hFileEvent != NULL )
+ SetEvent( ft->hFileEvent );
+ return;
+ }
+ JabberLog( "Entering recv loop for this file connection... ( ft->s is hConnection )" );
+ datalen = 0;
+ while ( ft->state!=FT_DONE && ft->state!=FT_ERROR ) {
+ int recvResult, bytesParsed;
+
+ //recvResult = JabberWsRecv( hConnection, buffer+datalen, JABBER_NETWORK_BUFFER_SIZE-datalen );
+ recvResult = Netlib_Recv( hConnection, buffer+datalen, JABBER_NETWORK_BUFFER_SIZE-datalen, 0 );
+ if ( recvResult <= 0 )
+ break;
+ datalen += recvResult;
+
+ buffer[datalen] = '\0';
+ JabberLog( "RECV:%s", buffer );
+
+ bytesParsed = JabberFileSendParse( hConnection, ft, buffer, datalen );
+ if ( bytesParsed < datalen )
+ memmove( buffer, buffer+bytesParsed, datalen-bytesParsed );
+ datalen -= bytesParsed;
+ }
+
+ JabberLog( "Closing connection for this file transfer... ( ft->s is now hBind )" );
+ Netlib_CloseHandle( hConnection );
+ ft->s = slisten;
+ JabberLog( "ft->s is restored to %d", ft->s );
+ if ( ft->hFileEvent != NULL )
+ SetEvent( ft->hFileEvent );
+ mir_free( buffer );
+}
+
+static int JabberFileSendParse( 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';
+ JabberLog( "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_strdup( t );
+ JabberHttpUrlDecode( ft->httpPath );
+ ft->state = FT_INITIALIZING;
+ JabberLog( "Change to FT_INITIALIZING" );
+ }
+ }
+ else { // FT_INITIALIZING
+ if ( str[0] == '\0' ) {
+ struct _stat statbuf;
+
+ mir_free( str );
+ num += 2;
+
+ currentFile = ft->std.currentFileNumber;
+ if (( t=strrchr( ft->std.files[ currentFile ], '\\' )) != NULL )
+ t++;
+ else
+ t = ft->std.files[currentFile];
+ if ( ft->httpPath==NULL || strcmp( ft->httpPath, t )) {
+ if ( ft->httpPath == NULL )
+ JabberLog( "Requested file name does not matched ( httpPath==NULL )" );
+ else
+ JabberLog( "Requested file name does not matched ( '%s' vs. '%s' )", ft->httpPath, t );
+ ft->state = FT_ERROR;
+ break;
+ }
+ JabberLog( "Sending [%s]", ft->std.files[ currentFile ] );
+ _stat( ft->std.files[ currentFile ], &statbuf ); // file size in statbuf.st_size
+ if (( fileId=_open( ft->std.files[currentFile], _O_BINARY|_O_RDONLY )) < 0 ) {
+ JabberLog( "File cannot be opened" );
+ ft->state = FT_ERROR;
+ mir_free( ft->httpPath );
+ ft->httpPath = NULL;
+ break;
+ }
+ JabberSend( s, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n", statbuf.st_size );
+
+ ft->std.sending = TRUE;
+ ft->std.currentFileProgress = 0;
+ JabberLog( "Sending file data..." );
+
+ char fileBuffer[ 2048 ];
+ 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;
+ JabberLog( "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()
+{
+ memset( this, 0, sizeof( filetransfer ));
+ fileId = -1;
+ std.cbSize = sizeof( std );
+}
+
+filetransfer::~filetransfer()
+{
+ JabberLog( "Destroying file transfer session %08p", this );
+
+ if ( !bCompleted )
+ 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.workingDir ) mir_free( std.workingDir );
+ if ( std.currentFile ) mir_free( std.currentFile );
+
+ if ( std.files ) {
+ for ( int i=0; i < std.totalFiles; i++ )
+ if ( std.files[i] ) mir_free( std.files[i] );
+
+ mir_free( std.files );
+} }
+
+void filetransfer::close()
+{
+ if ( fileId != -1 ) {
+ _close( fileId );
+ fileId = -1;
+} }
+
+void filetransfer::complete()
+{
+ close();
+
+ bCompleted = true;
+ JSendBroadcast( std.hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, this, 0);
+}
+
+int filetransfer::create()
+{
+ if ( fileId != -1 )
+ return fileId;
+
+ char filefull[ MAX_PATH ];
+ mir_snprintf( filefull, sizeof filefull, "%s\\%s", std.workingDir, std.currentFile );
+ replaceStr( std.currentFile, filefull );
+
+ if ( hWaitEvent != INVALID_HANDLE_VALUE )
+ CloseHandle( hWaitEvent );
+ hWaitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+
+ if ( JSendBroadcast( std.hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, this, ( LPARAM )&std ))
+ WaitForSingleObject( hWaitEvent, INFINITE );
+
+ if ( IsWinVerNT() && wszFileName != NULL ) {
+ WCHAR wszTemp[ MAX_PATH ];
+ _snwprintf( wszTemp, sizeof wszTemp, L"%S\\%s", std.workingDir, wszFileName );
+ wszTemp[ MAX_PATH-1 ] = 0;
+ fileId = _wopen( wszTemp, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE);
+ if ( fileId != -1 ) {
+ WIN32_FIND_DATAW data;
+ HANDLE hFind = FindFirstFileW( wszFileName, &data );
+ if ( hFind != INVALID_HANDLE_VALUE ) {
+ mir_free( std.currentFile );
+
+ char tShortName[ 20 ];
+ WideCharToMultiByte( CP_ACP, 0,
+ ( data.cAlternateFileName[0] != 0 ) ? data.cAlternateFileName : data.cFileName,
+ -1, tShortName, sizeof tShortName, 0, 0 );
+ mir_snprintf( filefull, sizeof( filefull ), "%s\\%s", std.workingDir, tShortName );
+ std.currentFile = mir_strdup( filefull );
+ JabberLog( "Saving to [%s]", std.currentFile );
+ FindClose( hFind );
+ } } }
+
+ if ( fileId == -1 ) {
+ JabberLog( "Saving to [%s]", std.currentFile );
+ fileId = _open( std.currentFile, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE );
+ }
+
+ if ( fileId == -1 )
+ JabberLog( "Cannot create file '%s' during a file transfer", filefull );
+ else if ( std.currentFileSize != 0 )
+ _chsize( fileId, std.currentFileSize );
+
+ return fileId;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_form.cpp b/miranda-wine/protocols/JabberG/jabber_form.cpp
new file mode 100644
index 0000000..a676e7c
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_form.cpp
@@ -0,0 +1,479 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_form.cpp,v $
+Revision : $Revision: 2961 $
+Last change on : $Date: 2006-05-26 23:39:41 +0400 (Птн, 26 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include "resource.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 ) GetWindowLong( hwnd, GWL_USERDATA ), hwnd, msg, wParam, lParam );
+}
+
+void JabberFormCreateUI( HWND hwndStatic, XmlNode *xNode, int *formHeight )
+{
+ HWND hFrame, hCtrl;
+ HFONT hFont;
+ XmlNode *n, *v, *o, *vs;
+ int id, i, j, k, ypos, index, size;
+ TCHAR* label, *type, *labelStr, *valueStr, *varStr, *str, *p, *valueText;
+ int labelOffset, labelWidth, labelHeight;
+ int ctrlOffset, ctrlWidth;
+ RECT frameRect, strRect;
+
+ if ( xNode==NULL || xNode->name==NULL || strcmp( xNode->name, "x" ) || hwndStatic==NULL ) return;
+ hFrame = hwndStatic;
+ hFont = ( HFONT ) SendMessage( hFrame, WM_GETFONT, 0, 0 );
+
+ GetClientRect( hwndStatic, &frameRect );
+ labelOffset = 10;
+ labelWidth = ( frameRect.right - frameRect.left )/2 - 20 - 20;
+ ctrlOffset = labelWidth + 20;
+ ctrlWidth = frameRect.right - frameRect.left - labelWidth - 20 - 20;
+
+ id = 0;
+ ypos = 14;
+ for ( i=0; i<xNode->numChild; i++ ) {
+ n = xNode->child[i];
+ if ( n->name ) {
+ if ( !strcmp( n->name, "field" )) {
+ if (( varStr=JabberXmlGetAttrValue( n, "var" )) != NULL &&
+ ( type=JabberXmlGetAttrValue( n, "type" )) != NULL ) {
+
+ if (( label=JabberXmlGetAttrValue( n, "label" )) != NULL )
+ labelStr = mir_tstrdup( label );
+ else
+ labelStr = mir_tstrdup( varStr );
+ strRect.top = strRect.left = 0; strRect.right = labelWidth; strRect.bottom = 1;
+ labelHeight = DrawText( GetDC( hFrame ), labelStr, -1, &strRect, DT_CALCRECT|DT_RIGHT|DT_WORDBREAK );
+ //labelHeight = labelHeight * 6 / 7;
+ if ( labelHeight < 18 ) labelHeight = 18;
+
+ if (( v=JabberXmlGetChild( n, "value" )) != NULL ) {
+ valueStr = mir_tstrdup( v->text );
+ valueText = v->text;
+ }
+ else valueStr = valueText = NULL;
+
+ if ( !_tcscmp( type, _T("text-private"))) {
+ if ( labelStr ) {
+ hCtrl = CreateWindow( _T("static"), labelStr, WS_CHILD|WS_VISIBLE|SS_RIGHT, labelOffset, ypos+4, labelWidth, labelHeight, hFrame, ( HMENU ) IDC_STATIC, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ }
+ hCtrl = CreateWindowEx( WS_EX_CLIENTEDGE, _T("edit"), valueStr, WS_CHILD|WS_VISIBLE|WS_BORDER|WS_TABSTOP|ES_LEFT|ES_AUTOHSCROLL|ES_PASSWORD, ctrlOffset, ypos, ctrlWidth, 24, hFrame, ( HMENU ) id, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ id++;
+ ypos += (( labelHeight>24 )?labelHeight:24 );
+ }
+ else if ( !_tcscmp( type, _T("text-multi")) || !_tcscmp( type, _T("jid-multi"))) {
+ WNDPROC oldWndProc;
+
+ if ( labelStr ) {
+ hCtrl = CreateWindow( _T("static"), labelStr, WS_CHILD|WS_VISIBLE|SS_RIGHT, labelOffset, ypos+4, labelWidth, labelHeight, hFrame, ( HMENU ) IDC_STATIC, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ }
+ size = 1;
+ for ( j=0; j<n->numChild; j++ ) {
+ v = n->child[j];
+ if ( v->name && !strcmp( v->name, "value" ) && v->text )
+ size += _tcslen( v->text ) + 2;
+ }
+ str = ( TCHAR* )mir_alloc( sizeof(TCHAR)*size );
+ str[0] = '\0';
+ for ( j=0; j<n->numChild; j++ ) {
+ v = n->child[j];
+ if ( v->name && !strcmp( v->name, "value" ) && v->text ) {
+ if ( str[0] ) _tcscat( str, _T("\r\n"));
+ _tcscat( str, v->text );
+ } }
+
+ hCtrl = CreateWindowEx( WS_EX_CLIENTEDGE, _T("edit"), str, WS_CHILD|WS_VISIBLE|WS_BORDER|WS_TABSTOP|WS_VSCROLL|ES_LEFT|ES_MULTILINE|ES_AUTOVSCROLL|ES_WANTRETURN, ctrlOffset, ypos, ctrlWidth, 24*3, hFrame, ( HMENU ) id, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ oldWndProc = ( WNDPROC ) SetWindowLong( hCtrl, GWL_WNDPROC, ( LPARAM )JabberFormMultiLineWndProc );
+ SetWindowLong( hCtrl, GWL_USERDATA, ( LONG ) oldWndProc );
+ id++;
+ ypos += (( labelHeight>24*3 )?labelHeight:24*3 );
+ mir_free( str );
+ }
+ else if ( !_tcscmp( type, _T("boolean"))) {
+ strRect.top = strRect.left = 0;
+ strRect.right = ctrlWidth-20; strRect.bottom = 1;
+ labelHeight = DrawText( GetDC( hFrame ), labelStr, -1, &strRect, DT_CALCRECT|DT_WORDBREAK );
+ if ( labelHeight < 24 ) labelHeight = 24;
+ hCtrl = CreateWindowEx( 0, _T("button"), labelStr, WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX|BS_MULTILINE, ctrlOffset, ypos, ctrlWidth, ( labelHeight>24 )?labelHeight:24, hFrame, ( HMENU ) id, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ if ( valueStr && !_tcscmp( valueStr, _T("1")))
+ SendMessage( hCtrl, BM_SETCHECK, 1, 0 );
+ id++;
+ ypos += (( labelHeight>24 )?labelHeight:24 );
+ }
+ else if ( !_tcscmp( type, _T("list-single"))) {
+ if ( labelStr ) {
+ hCtrl = CreateWindow( _T("static"), labelStr, WS_CHILD|WS_VISIBLE|SS_RIGHT, labelOffset, ypos+4, labelWidth, labelHeight, hFrame, ( HMENU ) IDC_STATIC, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ }
+ hCtrl = CreateWindowExA( WS_EX_CLIENTEDGE, "combobox", NULL, WS_CHILD|WS_VISIBLE|WS_BORDER|WS_TABSTOP|CBS_DROPDOWNLIST, ctrlOffset, ypos, ctrlWidth, 24*4, hFrame, ( HMENU ) id, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ for ( j=0; j<n->numChild; j++ ) {
+ o = n->child[j];
+ if ( o->name && !strcmp( o->name, "option" )) {
+ if (( v=JabberXmlGetChild( o, "value" ))!=NULL && v->text ) {
+ if (( str=JabberXmlGetAttrValue( o, "label" )) == NULL )
+ str = v->text;
+ if (( p = mir_tstrdup( str )) != NULL ) {
+ index = SendMessage( hCtrl, CB_ADDSTRING, 0, ( LPARAM )p );
+ mir_free( p );
+ if ( valueText!=NULL && !_tcscmp( valueText, v->text )) {
+ SendMessage( hCtrl, CB_SETCURSEL, index, 0 );
+ } } } } }
+ id++;
+ ypos += (( labelHeight>24 )?labelHeight:24 );
+ }
+ else if ( !_tcscmp( type, _T("list-multi"))) {
+ if ( labelStr ) {
+ hCtrl = CreateWindow( _T("static"), labelStr, WS_CHILD|WS_VISIBLE|SS_RIGHT, labelOffset, ypos+4, labelWidth, labelHeight, hFrame, ( HMENU ) IDC_STATIC, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ }
+ hCtrl = CreateWindowExA( WS_EX_CLIENTEDGE, "listbox", NULL, WS_CHILD|WS_VISIBLE|WS_BORDER|WS_TABSTOP|LBS_MULTIPLESEL, ctrlOffset, ypos, ctrlWidth, 24*3, hFrame, ( HMENU ) id, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ for ( j=0; j<n->numChild; j++ ) {
+ o = n->child[j];
+ if ( o->name && !strcmp( o->name, "option" )) {
+ if (( v = JabberXmlGetChild( o, "value" ))!=NULL && v->text ) {
+ if (( str=JabberXmlGetAttrValue( o, "label" )) == NULL )
+ str = v->text;
+ if (( p = mir_tstrdup( str )) != NULL ) {
+ index = SendMessage( hCtrl, LB_ADDSTRING, 0, ( LPARAM )p );
+ mir_free( p );
+ for ( k=0; k<n->numChild; k++ ) {
+ vs = n->child[k];
+ if ( vs->name && !strcmp( vs->name, "value" ) && vs->text && !_tcscmp( vs->text, v->text ))
+ SendMessage( hCtrl, LB_SETSEL, TRUE, index );
+ } } } } }
+ id++;
+ ypos += (( labelHeight>24*3 )?labelHeight:24*3 );
+ }
+ else if ( !_tcscmp( type, _T("fixed"))) {
+ if ( valueStr ) {
+ strRect.top = strRect.left = 0;
+ strRect.right = ctrlWidth; strRect.bottom = 1;
+ labelHeight = DrawText( GetDC( hFrame ), labelStr, -1, &strRect, DT_CALCRECT|DT_WORDBREAK );
+ labelHeight = labelHeight * 6 / 7;
+ if ( labelHeight < 24 ) labelHeight = 24;
+ hCtrl = CreateWindow( _T("static"), valueStr, WS_CHILD|WS_VISIBLE|SS_RIGHT, labelOffset, ypos+4, labelWidth+ctrlWidth, labelHeight, hFrame, ( HMENU ) IDC_STATIC, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ ypos += labelHeight;
+ }
+ }
+ else if ( !_tcscmp( type, _T("hidden"))) {
+ // skip
+ }
+ else { // everything else is considered "text-single"
+ if ( labelStr ) {
+ hCtrl = CreateWindow( _T("static"), labelStr, WS_CHILD|WS_VISIBLE|SS_RIGHT, labelOffset, ypos+4, labelWidth, labelHeight, hFrame, ( HMENU ) IDC_STATIC, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ }
+ hCtrl = CreateWindowEx( WS_EX_CLIENTEDGE, _T("edit"), valueStr, WS_CHILD|WS_VISIBLE|WS_BORDER|WS_TABSTOP|ES_LEFT|ES_AUTOHSCROLL, ctrlOffset, ypos, ctrlWidth, 24, hFrame, ( HMENU ) id, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ id++;
+ ypos += (( labelHeight>24 )?labelHeight:24 );
+ }
+ mir_free( labelStr );
+ if ( valueStr ) mir_free( valueStr );
+ } } } }
+
+ *formHeight = ypos;
+}
+
+XmlNode* JabberFormGetData( HWND hwndStatic, XmlNode* xNode )
+{
+ HWND hFrame, hCtrl;
+ XmlNode *n, *v, *o, *x;
+ int id, j, k, len;
+ TCHAR *varName, *type, *fieldStr, *str, *str2, *p, *q, *labelText;
+
+ if ( xNode==NULL || xNode->name==NULL || strcmp( xNode->name, "x" ) || hwndStatic==NULL )
+ return NULL;
+
+ hFrame = hwndStatic;
+ id = 0;
+ x = new XmlNode( "x" ); x->addAttr( "xmlns", "jabber:x:data" ); x->addAttr( "type", "submit" );
+ for ( int i=0; i<xNode->numChild; i++ ) {
+ n = xNode->child[i];
+ fieldStr = NULL;
+ if ( lstrcmpA( n->name, "field" ))
+ continue;
+
+ if (( varName=JabberXmlGetAttrValue( n, "var" )) == NULL || ( type=JabberXmlGetAttrValue( n, "type" )) == NULL )
+ continue;
+
+ hCtrl = GetDlgItem( hFrame, id );
+ XmlNode* field = x->addChild( "field" ); field->addAttr( "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->addChild( "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->addChild( "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 );
+ for ( j=0; j < n->numChild; j++ ) {
+ o = n->child[j];
+ if ( o && o->name && !strcmp( o->name, "option" )) {
+ if (( v=JabberXmlGetChild( o, "value" ))!=NULL && v->text ) {
+ if (( str2=JabberXmlGetAttrValue( o, "label" )) == NULL )
+ str2 = v->text;
+ if ( !lstrcmp( str2, str ))
+ break;
+ } } }
+
+ if ( j < n->numChild )
+ field->addChild( "value", v->text );
+
+ 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, 0, 0 );
+ if (( str = ( TCHAR* )mir_alloc(( len+1 )*sizeof( TCHAR ))) != NULL ) {
+ SendMessage( hCtrl, LB_GETTEXT, j, ( LPARAM )str );
+ for ( k=0; k < n->numChild; k++ ) {
+ o = n->child[k];
+ if ( o && o->name && !strcmp( o->name, "option" )) {
+ if (( v=JabberXmlGetChild( o, "value" ))!=NULL && v->text ) {
+ if (( labelText=JabberXmlGetAttrValue( o, "label" )) == NULL )
+ labelText = v->text;
+
+ if ( !lstrcmp( labelText, str ))
+ field->addChild( "value", v->text );
+ } } }
+ mir_free( str );
+ } } }
+ id++;
+ }
+ else if ( !_tcscmp( type, _T("fixed")) || !_tcscmp( type, _T("hidden"))) {
+ v = JabberXmlGetChild( n, "value" );
+ if ( v != NULL && v->text != NULL )
+ field->addChild( "value", v->text );
+ }
+ 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->addChild( "value", str );
+ mir_free( str );
+ id++;
+ } }
+
+ return x;
+}
+
+typedef struct {
+ XmlNode *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;
+} JABBER_FORM_INFO;
+
+static BOOL CALLBACK JabberFormDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ JABBER_FORM_INFO *jfi;
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ {
+ XmlNode *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=JabberXmlGetChild( jfi->xNode, "title" ))!=NULL && n->text!=NULL )
+ SetWindowText( hwndDlg, n->text );
+ else if ( jfi->defTitle != NULL )
+ SetWindowText( hwndDlg, TranslateTS( jfi->defTitle ));
+ // Set instruction field
+ if ( jfi->xNode!=NULL && ( n=JabberXmlGetChild( jfi->xNode, "instructions" ))!=NULL && n->text!=NULL )
+ SetDlgItemText( hwndDlg, IDC_INSTRUCTION, n->text );
+
+ // 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 = GetWindowLong( GetDlgItem( hwndDlg, IDC_FRAME ), GWL_EXSTYLE );
+ frameExStyle |= WS_EX_CONTROLPARENT;
+ SetWindowLong( GetDlgItem( hwndDlg, IDC_FRAME ), GWL_EXSTYLE, frameExStyle );
+
+ SetWindowLong( hwndDlg, GWL_USERDATA, ( LONG ) jfi );
+ if ( jfi->pfnSubmit != NULL )
+ EnableWindow( GetDlgItem( hwndDlg, IDC_SUBMIT ), TRUE );
+ }
+ return TRUE;
+ case WM_VSCROLL:
+ {
+ int pos;
+
+ jfi = ( JABBER_FORM_INFO * ) GetWindowLong( hwndDlg, GWL_USERDATA );
+ if ( jfi != NULL ) {
+ pos = jfi->curPos;
+ switch ( LOWORD( wParam )) {
+ case SB_LINEDOWN:
+ pos += 10;
+ break;
+ case SB_LINEUP:
+ pos -= 10;
+ 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 * ) GetWindowLong( hwndDlg, GWL_USERDATA );
+ if ( jfi != NULL ) {
+ XmlNode* n = JabberFormGetData( GetDlgItem( hwndDlg, IDC_FRAME ), jfi->xNode );
+ ( jfi->pfnSubmit )( n, jfi->userdata );
+ }
+ // fall through
+ case IDCANCEL:
+ DestroyWindow( hwndDlg );
+ return TRUE;
+ }
+ break;
+ case WM_CLOSE:
+ DestroyWindow( hwndDlg );
+ break;
+ case WM_DESTROY:
+ jfi = ( JABBER_FORM_INFO * ) GetWindowLong( hwndDlg, GWL_USERDATA );
+ if ( jfi != NULL ) {
+ if ( jfi->xNode != NULL )
+ delete jfi->xNode;
+ mir_free( jfi );
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+static VOID CALLBACK JabberFormCreateDialogApcProc( DWORD param )
+{
+ CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_FORM ), NULL, JabberFormDlgProc, ( LPARAM )param );
+}
+
+void JabberFormCreateDialog( XmlNode *xNode, TCHAR* defTitle, JABBER_FORM_SUBMIT_FUNC pfnSubmit, void *userdata )
+{
+ JABBER_FORM_INFO *jfi;
+
+ jfi = ( JABBER_FORM_INFO * ) mir_alloc( sizeof( JABBER_FORM_INFO ));
+ memset( jfi, 0, sizeof( JABBER_FORM_INFO ));
+ jfi->xNode = JabberXmlCopyNode( xNode );
+ if ( defTitle )
+ _tcsncpy( jfi->defTitle, defTitle, SIZEOF( jfi->defTitle ));
+ jfi->pfnSubmit = pfnSubmit;
+ jfi->userdata = userdata;
+
+ if ( GetCurrentThreadId() != jabberMainThreadId )
+ QueueUserAPC( JabberFormCreateDialogApcProc, hMainThread, ( DWORD )jfi );
+ else
+ JabberFormCreateDialogApcProc(( DWORD )jfi );
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_ft.cpp b/miranda-wine/protocols/JabberG/jabber_ft.cpp
new file mode 100644
index 0000000..1c1897f
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_ft.cpp
@@ -0,0 +1,419 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_ft.cpp,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#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"
+
+void JabberFtCancel( filetransfer* ft )
+{
+ JABBER_LIST_ITEM *item;
+ JABBER_BYTE_TRANSFER *jbt;
+ int i;
+
+ JabberLog( "Invoking JabberFtCancel()" );
+
+ // For file sending session that is still in si negotiation phase
+ for ( i=0; ( i=JabberListFindNext( LIST_FTSEND, i ))>=0; i++ ) {
+ item = JabberListGetItemPtrFromIndex( i );
+ if ( item->ft == ft ) {
+ JabberLog( "Canceling file sending session while in si negotiation" );
+ JabberListRemoveByIndex( i );
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 );
+ delete ft;
+ return;
+ }
+ }
+ // For file receiving session that is still in si negotiation phase
+ for ( i=0; ( i=JabberListFindNext( LIST_FTRECV, i ))>=0; i++ ) {
+ item = JabberListGetItemPtrFromIndex( i );
+ if ( item->ft == ft ) {
+ JabberLog( "Canceling file receiving session while in si negotiation" );
+ JabberListRemoveByIndex( i );
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 );
+ delete ft;
+ return;
+ }
+ }
+ // For file transfer through bytestream
+ if (( jbt=ft->jbt ) != NULL ) {
+ JabberLog( "Canceling bytestream session" );
+ jbt->state = JBT_ERROR;
+ if ( jbt->hConn ) {
+ JabberLog( "Force closing bytestream session" );
+ Netlib_CloseHandle( jbt->hConn );
+ jbt->hConn = NULL;
+ }
+ if ( jbt->hEvent ) SetEvent( jbt->hEvent );
+ }
+}
+
+///////////////// File sending using stream initiation /////////////////////////
+
+static void JabberFtSiResult( XmlNode *iqNode, void *userdata );
+static BOOL JabberFtSend( HANDLE hConn, void *userdata );
+static void JabberFtSendFinal( BOOL success, void *userdata );
+
+void JabberFtInitiate( TCHAR* jid, filetransfer* ft )
+{
+ int iqId;
+ TCHAR *rs;
+ char *filename, *p;
+ TCHAR idStr[32];
+ JABBER_LIST_ITEM *item;
+ int i;
+ TCHAR sid[9];
+
+ if ( jid==NULL || ft==NULL || !jabberOnline || ( rs=JabberListGetBestClientResourceNamePtr( jid ))==NULL ) {
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 );
+ delete ft;
+ return;
+ }
+ iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_NONE, JabberFtSiResult );
+ mir_sntprintf( idStr, SIZEOF( idStr ), _T(JABBER_IQID)_T("%d"), iqId );
+ if (( item=JabberListAdd( LIST_FTSEND, idStr )) == NULL ) {
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 );
+ delete ft;
+ return;
+ }
+ item->ft = ft;
+ 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.files[ ft->std.currentFileNumber ];
+ if (( p=strrchr( filename, '\\' )) != NULL )
+ filename = p+1;
+
+ TCHAR tszJid[200];
+ mir_sntprintf( tszJid, SIZEOF(tszJid), _T("%s/%s"), jid, rs );
+
+ XmlNodeIq iq( "set", iqId, tszJid );
+ XmlNode* si = iq.addChild( "si" ); si->addAttr( "xmlns", "http://jabber.org/protocol/si" );
+ si->addAttr( "id", sid ); si->addAttr( "mime-type", "binary/octet-stream" );
+ si->addAttr( "profile", "http://jabber.org/protocol/si/profile/file-transfer" );
+ XmlNode* file = si->addChild( "file" ); file->addAttr( "name", filename ); file->addAttr( "size", ft->fileSize[ ft->std.currentFileNumber ] );
+ file->addAttr( "xmlns", "http://jabber.org/protocol/si/profile/file-transfer" );
+ file->addChild( "desc", ft->szDescription );
+ XmlNode* feature = si->addChild( "feature" ); feature->addAttr( "xmlns", "http://jabber.org/protocol/feature-neg" );
+ XmlNode* x = feature->addChild( "x" ); x->addAttr( "xmlns", "jabber:x:data" ); x->addAttr( "type", "form" );
+ XmlNode* field = x->addChild( "field" ); field->addAttr( "var", "stream-method" ); field->addAttr( "type", "list-single" );
+ XmlNode* option = field->addChild( "option" ); option->addChild( "value", "http://jabber.org/protocol/bytestreams" );
+ JabberSend( jabberThreadInfo->s, iq );
+}
+
+static void JabberFtSiResult( XmlNode *iqNode, void *userdata )
+{
+ TCHAR* type, *from, *to, *idStr, *str;
+ XmlNode *siNode, *fileNode, *rangeNode, *featureNode, *xNode, *fieldNode, *valueNode;
+ JABBER_LIST_ITEM *item;
+ int offset, length;
+ JABBER_BYTE_TRANSFER *jbt;
+
+ if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+ if (( from=JabberXmlGetAttrValue( iqNode, "from" )) == NULL ) return;
+ if (( to=JabberXmlGetAttrValue( iqNode, "to" )) == NULL ) return;
+ idStr = JabberXmlGetAttrValue( iqNode, "id" );
+ if (( item=JabberListGetItemPtr( LIST_FTSEND, idStr )) == NULL ) return;
+
+ if ( !_tcscmp( type, _T("result"))) {
+ if (( siNode=JabberXmlGetChild( iqNode, "si" )) != NULL ) {
+ if (( fileNode=JabberXmlGetChild( siNode, "file" )) != NULL ) {
+ if (( rangeNode=JabberXmlGetChild( fileNode, "range" )) != NULL ) {
+// ************** Need to store offset/length in ft structure **********************
+// but at this tiem, we should not get <range/> tag since we don't sent <range/> on our request
+ if (( str=JabberXmlGetAttrValue( rangeNode, "offset" )) != NULL )
+ offset = _ttoi( str );
+ if (( str=JabberXmlGetAttrValue( rangeNode, "length" )) != NULL )
+ length = _ttoi( str );
+ }
+ }
+ if (( featureNode=JabberXmlGetChild( siNode, "feature" )) != NULL ) {
+ if (( xNode=JabberXmlGetChildWithGivenAttrValue( featureNode, "x", "xmlns", _T("jabber:x:data"))) != NULL ) {
+ if (( fieldNode=JabberXmlGetChildWithGivenAttrValue( xNode, "field", "var", _T("stream-method"))) != NULL ) {
+ if (( valueNode=JabberXmlGetChild( fieldNode, "value" ))!=NULL && valueNode->text!=NULL ) {
+ if ( !_tcscmp( valueNode->text, _T("http://jabber.org/protocol/bytestreams"))) {
+ // Start Bytestream session
+ jbt = ( JABBER_BYTE_TRANSFER * ) mir_alloc( sizeof( JABBER_BYTE_TRANSFER ));
+ ZeroMemory( jbt, sizeof( JABBER_BYTE_TRANSFER ));
+ jbt->srcJID = mir_tstrdup( to );
+ jbt->dstJID = mir_tstrdup( from );
+ jbt->sid = mir_tstrdup( item->ft->sid );
+ jbt->pfnSend = JabberFtSend;
+ jbt->pfnFinal = JabberFtSendFinal;
+ jbt->userdata = item->ft;
+ item->ft->type = FT_BYTESTREAM;
+ item->ft->jbt = jbt;
+ JabberForkThread(( JABBER_THREAD_FUNC )JabberByteSendThread, 0, jbt );
+ } } } } } }
+ }
+ else if ( !_tcscmp( type, _T("error"))) {
+ JabberLog( "File transfer stream initiation request denied" );
+ JSendBroadcast( item->ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DENIED, item->ft, 0 );
+ delete item->ft;
+ item->ft = NULL;
+ }
+
+ JabberListRemove( LIST_FTSEND, idStr );
+}
+
+static BOOL JabberFtSend( HANDLE hConn, void *userdata )
+{
+ filetransfer* ft = ( filetransfer* ) userdata;
+
+ struct _stat statbuf;
+ int fd;
+ char* buffer;
+ int numRead;
+
+ JabberLog( "Sending [%s]", ft->std.files[ ft->std.currentFileNumber ] );
+ _stat( ft->std.files[ ft->std.currentFileNumber ], &statbuf ); // file size in statbuf.st_size
+ if (( fd=_open( ft->std.files[ ft->std.currentFileNumber ], _O_BINARY|_O_RDONLY )) < 0 ) {
+ JabberLog( "File cannot be opened" );
+ return FALSE;
+ }
+
+ ft->std.sending = TRUE;
+ 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;
+}
+
+static void JabberFtSendFinal( BOOL success, void *userdata )
+{
+ filetransfer* ft = ( filetransfer* )userdata;
+
+ if ( !success ) {
+ JabberLog( "File transfer complete with error" );
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 );
+ }
+ else {
+ if ( ft->std.currentFileNumber < ft->std.totalFiles-1 ) {
+ ft->std.currentFileNumber++;
+ replaceStr( ft->std.currentFile, ft->std.files[ ft->std.currentFileNumber ] );
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0 );
+ JabberFtInitiate( ft->jid, ft );
+ return;
+ }
+
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0 );
+ }
+
+ delete ft;
+}
+
+///////////////// File receiving through stream initiation /////////////////////////
+
+static int JabberFtReceive( HANDLE hConn, void *userdata, char* buffer, int datalen );
+static void JabberFtReceiveFinal( BOOL success, void *userdata );
+
+void JabberFtHandleSiRequest( XmlNode *iqNode )
+{
+ TCHAR* from, *sid, *str, *szId, *filename;
+ XmlNode *siNode, *fileNode, *featureNode, *xNode, *fieldNode, *optionNode, *n;
+ int filesize, i;
+ JABBER_FT_TYPE ftType;
+
+ if ( iqNode==NULL ||
+ ( from=JabberXmlGetAttrValue( iqNode, "from" ))==NULL ||
+ ( str=JabberXmlGetAttrValue( iqNode, "type" ))==NULL || _tcscmp( str, _T("set")) ||
+ ( siNode=JabberXmlGetChildWithGivenAttrValue( iqNode, "si", "xmlns", _T("http://jabber.org/protocol/si"))) == NULL )
+ return;
+
+ szId = JabberXmlGetAttrValue( iqNode, "id" );
+ if (( sid=JabberXmlGetAttrValue( siNode, "id" ))!=NULL &&
+ ( fileNode=JabberXmlGetChildWithGivenAttrValue( siNode, "file", "xmlns", _T("http://jabber.org/protocol/si/profile/file-transfer")))!=NULL &&
+ ( filename=JabberXmlGetAttrValue( fileNode, "name" ))!=NULL &&
+ ( str=JabberXmlGetAttrValue( fileNode, "size" ))!=NULL ) {
+
+ filesize = _ttoi( str );
+ if (( featureNode=JabberXmlGetChildWithGivenAttrValue( siNode, "feature", "xmlns", _T("http://jabber.org/protocol/feature-neg"))) != NULL &&
+ ( xNode=JabberXmlGetChildWithGivenAttrValue( featureNode, "x", "xmlns", _T("jabber:x:data")))!=NULL &&
+ ( fieldNode=JabberXmlGetChildWithGivenAttrValue( xNode, "field", "var", _T("stream-method")))!=NULL ) {
+
+ for ( i=0; i<fieldNode->numChild; i++ ) {
+ optionNode = fieldNode->child[i];
+ if ( optionNode->name && !strcmp( optionNode->name, "option" )) {
+ if (( n=JabberXmlGetChild( optionNode, "value" ))!=NULL && n->text ) {
+ if ( !_tcscmp( n->text, _T("http://jabber.org/protocol/bytestreams"))) {
+ ftType = FT_BYTESTREAM;
+ break;
+ } } } }
+
+ if ( i < fieldNode->numChild ) {
+ // Found known stream mechanism
+ CCSDATA ccs;
+ PROTORECVEVENT pre;
+
+ char *localFilename = t2a( filename );
+ char *desc = (( n=JabberXmlGetChild( fileNode, "desc" ))!=NULL && n->text!=NULL ) ? t2a( n->text ) : mir_strdup( "" );
+
+ filetransfer* ft = new filetransfer;
+ ft->jid = mir_tstrdup( from );
+ ft->std.hContact = JabberHContactFromJID( from );
+ ft->sid = mir_tstrdup( sid );
+ ft->iqId = ( szId ) ? mir_tstrdup( szId ):NULL;
+ ft->type = ftType;
+ ft->std.totalFiles = 1;
+ ft->std.currentFile = localFilename;
+ ft->std.totalBytes = ft->std.currentFileSize = filesize;
+ char* szBlob = ( char* )alloca( sizeof( DWORD )+ strlen( localFilename ) + strlen( desc ) + 2 );
+ *(( PDWORD ) szBlob ) = ( DWORD )ft;
+ strcpy( szBlob + sizeof( DWORD ), localFilename );
+ strcpy( szBlob + sizeof( DWORD )+ strlen( localFilename ) + 1, desc );
+ pre.flags = 0;
+ pre.timestamp = time( NULL );
+ pre.szMessage = szBlob;
+ pre.lParam = 0;
+ ccs.szProtoService = PSR_FILE;
+ ccs.hContact = ft->std.hContact;
+ ccs.wParam = 0;
+ ccs.lParam = ( LPARAM )&pre;
+ JCallService( MS_PROTO_CHAINRECV, 0, ( LPARAM )&ccs );
+ mir_free( desc );
+ return;
+ }
+ else {
+ // Unknown stream mechanism
+ XmlNodeIq iq( "error", szId, from );
+ XmlNode* e = iq.addChild( "error" ); e->addAttr( "code", 400 ); e->addAttr( "type", "cancel" );
+ XmlNode* br = e->addChild( "bad-request" ); br->addAttr( "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas" );
+ XmlNode* nvs = e->addChild( "no-valid-streams" ); nvs->addAttr( "xmlns", "http://jabber.org/protocol/si" );
+ JabberSend( jabberThreadInfo->s, iq );
+ return;
+ } } }
+
+ // Bad stream initiation, reply with bad-profile
+ XmlNodeIq iq( "error", szId, from );
+ XmlNode* e = iq.addChild( "error" ); e->addAttr( "code", 400 ); e->addAttr( "type", "cancel" );
+ XmlNode* br = e->addChild( "bad-request" ); br->addAttr( "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas" );
+ XmlNode* nvs = e->addChild( "bad-profile" ); nvs->addAttr( "xmlns", "http://jabber.org/protocol/si" );
+ JabberSend( jabberThreadInfo->s, iq );
+}
+
+void JabberFtAcceptSiRequest( filetransfer* ft )
+{
+ if ( !jabberOnline || ft==NULL || ft->jid==NULL || ft->sid==NULL ) return;
+
+ JABBER_LIST_ITEM *item;
+ if (( item=JabberListAdd( LIST_FTRECV, ft->sid )) != NULL ) {
+ item->ft = ft;
+
+ XmlNodeIq iq( "result", ft->iqId, ft->jid );
+ XmlNode* si = iq.addChild( "si" ); si->addAttr( "xmlns", "http://jabber.org/protocol/si" );
+ XmlNode* f = si->addChild( "feature" ); f->addAttr( "xmlns", "http://jabber.org/protocol/feature-neg" );
+ XmlNode* x = f->addChild( "x" ); x->addAttr( "xmlns", "jabber:x:data" ); x->addAttr( "type", "submit" );
+ XmlNode* fl = x->addChild( "field" ); fl->addAttr( "var", "stream-method" );
+ fl->addChild( "value", "http://jabber.org/protocol/bytestreams" );
+ JabberSend( jabberThreadInfo->s, iq );
+} }
+
+BOOL JabberFtHandleBytestreamRequest( XmlNode *iqNode )
+{
+ XmlNode *queryNode;
+ TCHAR* sid;
+ JABBER_LIST_ITEM *item;
+ JABBER_BYTE_TRANSFER *jbt;
+
+ if ( iqNode == NULL ) return FALSE;
+ if (( queryNode=JabberXmlGetChildWithGivenAttrValue( iqNode, "query", "xmlns", _T("http://jabber.org/protocol/bytestreams")))!=NULL &&
+ ( sid=JabberXmlGetAttrValue( queryNode, "sid" ))!=NULL &&
+ ( item=JabberListGetItemPtr( LIST_FTRECV, sid ))!=NULL ) {
+ // Start Bytestream session
+ jbt = ( JABBER_BYTE_TRANSFER * ) mir_alloc( sizeof( JABBER_BYTE_TRANSFER ));
+ ZeroMemory( jbt, sizeof( JABBER_BYTE_TRANSFER ));
+ jbt->iqNode = JabberXmlCopyNode( iqNode );
+ jbt->pfnRecv = JabberFtReceive;
+ jbt->pfnFinal = JabberFtReceiveFinal;
+ jbt->userdata = item->ft;
+ item->ft->jbt = jbt;
+ JabberForkThread(( JABBER_THREAD_FUNC )JabberByteReceiveThread, 0, jbt );
+ JabberListRemove( LIST_FTRECV, sid );
+ return TRUE;
+ }
+
+ JabberLog( "File transfer invalid bytestream initiation request received" );
+ return FALSE;
+}
+
+static int JabberFtReceive( HANDLE hConn, void *userdata, char* buffer, int datalen )
+{
+ filetransfer* ft = ( filetransfer* )userdata;
+ if ( ft->create() == -1 )
+ return -1;
+
+ int remainingBytes = ft->std.currentFileSize - ft->std.currentFileProgress;
+ if ( remainingBytes > 0 ) {
+ int writeSize = ( remainingBytes<datalen ) ? remainingBytes : datalen;
+ if ( _write( ft->fileId, buffer, writeSize ) != writeSize ) {
+ JabberLog( "_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;
+}
+
+static void JabberFtReceiveFinal( BOOL success, void *userdata )
+{
+ filetransfer* ft = ( filetransfer* )userdata;
+
+ if ( success ) {
+ JabberLog( "File transfer complete successfully" );
+ ft->complete();
+ }
+ else JabberLog( "File transfer complete with error" );
+
+ delete ft;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_groupchat.cpp b/miranda-wine/protocols/JabberG/jabber_groupchat.cpp
new file mode 100644
index 0000000..f12e77a
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_groupchat.cpp
@@ -0,0 +1,886 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_groupchat.cpp,v $
+Revision : $Revision: 3670 $
+Last change on : $Date: 2006-08-31 19:47:56 +0400 (Чтв, 31 Ðвг 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include <commctrl.h>
+#include "resource.h"
+#include "jabber_iq.h"
+
+#define GC_SERVER_LIST_SIZE 5
+
+static BOOL CALLBACK JabberGroupchatDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam );
+static BOOL CALLBACK JabberGroupchatJoinDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam );
+
+int JabberMenuHandleGroupchat( WPARAM wParam, LPARAM lParam )
+{
+ int iqId;
+
+ // lParam is the initial conference server to browse ( if any )
+ if ( IsWindow( hwndJabberGroupchat )) {
+ SetForegroundWindow( hwndJabberGroupchat );
+ if ( lParam != 0 ) {
+ SendMessage( hwndJabberGroupchat, WM_JABBER_ACTIVATE, 0, lParam ); // Just to update the IDC_SERVER and clear the list
+ iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_DISCOROOMSERVER, JabberIqResultDiscoRoomItems );
+
+ XmlNodeIq iq( "get", iqId, ( TCHAR* )lParam );
+ XmlNode* query = iq.addQuery( "http://jabber.org/protocol/disco#items" );
+ JabberSend( jabberThreadInfo->s, iq );
+ // <iq/> result will send WM_JABBER_REFRESH to update the list with real data
+ }
+ }
+ else hwndJabberGroupchat = CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_GROUPCHAT ), NULL, JabberGroupchatDlgProc, lParam );
+
+ return 0;
+}
+
+static BOOL sortAscending;
+static int sortColumn;
+
+static int CALLBACK GroupchatCompare( LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort )
+{
+ JABBER_LIST_ITEM *item1, *item2;
+ int res = 0;
+ item1 = JabberListGetItemPtr( LIST_ROOM, ( TCHAR* )lParam1 );
+ item2 = JabberListGetItemPtr( LIST_ROOM, ( TCHAR* )lParam2 );
+ if ( item1!=NULL && item2!=NULL ) {
+ switch ( lParamSort ) {
+ case 0: // sort by JID column
+ res = lstrcmp( item1->jid, item2->jid );
+ break;
+ case 1: // sort by Name column
+ res = lstrcmp( item1->name, item2->name );
+ break;
+ } }
+
+ if ( !sortAscending )
+ res *= -1;
+
+ return res;
+}
+
+static BOOL CALLBACK JabberGroupchatDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ HWND lv;
+ LVCOLUMN lvCol;
+ LVITEM lvItem;
+ JABBER_LIST_ITEM *item;
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ // lParam is the initial conference server ( if any )
+ SendMessage( hwndDlg, WM_SETICON, ICON_BIG, ( LPARAM )LoadIcon( hInst, MAKEINTRESOURCE( IDI_GROUP )) );
+ TranslateDialogDefault( hwndDlg );
+ sortColumn = -1;
+ // Add columns
+ lv = GetDlgItem( hwndDlg, IDC_ROOM );
+ lvCol.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
+ lvCol.pszText = TranslateT( "JID" );
+ lvCol.cx = 210;
+ lvCol.iSubItem = 0;
+ ListView_InsertColumn( lv, 0, &lvCol );
+ lvCol.pszText = TranslateT( "Name" );
+ lvCol.cx = 150;
+ lvCol.iSubItem = 1;
+ ListView_InsertColumn( lv, 1, &lvCol );
+ lvCol.pszText = TranslateT( "Type" );
+ lvCol.cx = 60;
+ lvCol.iSubItem = 2;
+ ListView_InsertColumn( lv, 2, &lvCol );
+ if ( jabberOnline ) {
+ if (( TCHAR* )lParam != NULL ) {
+ SetDlgItemText( hwndDlg, IDC_SERVER, ( TCHAR* )lParam );
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_DISCOROOMSERVER, JabberIqResultDiscoRoomItems );
+
+ XmlNodeIq iq( "get", iqId, ( TCHAR* )lParam );
+ XmlNode* query = iq.addQuery( "http://jabber.org/protocol/disco#items" );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+ else {
+ for ( int i=0; i < GC_SERVER_LIST_SIZE; i++ ) {
+ char text[100];
+ mir_snprintf( text, sizeof( text ), "GcServerLast%d", i );
+ DBVARIANT dbv;
+ if ( !JGetStringT( NULL, text, &dbv )) {
+ SendDlgItemMessage( hwndDlg, IDC_SERVER, CB_ADDSTRING, 0, ( LPARAM )dbv.ptszVal );
+ JFreeVariant( &dbv );
+ } } }
+ }
+ else EnableWindow( GetDlgItem( hwndDlg, IDC_JOIN ), FALSE );
+ return TRUE;
+
+ case WM_JABBER_ACTIVATE:
+ // lParam = server from which agent information is obtained
+ if ( lParam )
+ SetDlgItemText( hwndDlg, IDC_SERVER, ( TCHAR* )lParam );
+ ListView_DeleteAllItems( GetDlgItem( hwndDlg, IDC_ROOM ));
+ EnableWindow( GetDlgItem( hwndDlg, IDC_BROWSE ), FALSE );
+ return TRUE;
+
+ case WM_JABBER_REFRESH:
+ // lParam = server from which agent information is obtained
+ {
+ int i;
+ TCHAR szBuffer[256];
+ char text[128];
+
+ if ( lParam ){
+ _tcsncpy( szBuffer, ( TCHAR* )lParam, SIZEOF( szBuffer ));
+ for ( i=0; i<GC_SERVER_LIST_SIZE; i++ ) {
+ mir_snprintf( text, SIZEOF( text ), "GcServerLast%d", i );
+ DBVARIANT dbv;
+ if ( !JGetStringT( NULL, text, &dbv )) {
+ JSetStringT( NULL, text, szBuffer );
+ if ( !_tcsicmp( dbv.ptszVal, ( TCHAR* )lParam )) {
+ JFreeVariant( &dbv );
+ break;
+ }
+ _tcsncpy( szBuffer, dbv.ptszVal, SIZEOF( szBuffer ));
+ JFreeVariant( &dbv );
+ }
+ else {
+ JSetStringT( NULL, text, szBuffer );
+ break;
+ } }
+
+ SendDlgItemMessage( hwndDlg, IDC_SERVER, CB_RESETCONTENT, 0, 0 );
+ for ( i=0; i<GC_SERVER_LIST_SIZE; i++ ) {
+ mir_snprintf( text, SIZEOF( text ), "GcServerLast%d", i );
+ DBVARIANT dbv;
+ if ( !JGetStringT( NULL, text, &dbv )) {
+ SendDlgItemMessage( hwndDlg, IDC_SERVER, CB_ADDSTRING, 0, ( LPARAM )dbv.ptszVal );
+ JFreeVariant( &dbv );
+ }
+ }
+ SetDlgItemText( hwndDlg, IDC_SERVER, ( TCHAR* )lParam );
+ }
+ i = 0;
+ lv = GetDlgItem( hwndDlg, IDC_ROOM );
+ ListView_DeleteAllItems( lv );
+ LVITEM lvItem;
+ lvItem.iItem = 0;
+ while (( i=JabberListFindNext( LIST_ROOM, i )) >= 0 ) {
+ if (( item=JabberListGetItemPtrFromIndex( i )) != NULL ) {
+ lvItem.mask = LVIF_PARAM | LVIF_TEXT;
+ lvItem.iSubItem = 0;
+ _tcsncpy( szBuffer, item->jid, SIZEOF(szBuffer));
+ szBuffer[ SIZEOF(szBuffer)-1 ] = 0;
+ lvItem.lParam = ( LPARAM )item->jid;
+ lvItem.pszText = szBuffer;
+ ListView_InsertItem( lv, &lvItem );
+
+ lvItem.mask = LVIF_TEXT;
+ lvItem.iSubItem = 1;
+ lvItem.pszText = item->name;
+ ListView_SetItem( lv, &lvItem );
+
+ lvItem.iSubItem = 2;
+ lvItem.pszText = item->type;
+ ListView_SetItem( lv, &lvItem );
+ lvItem.iItem++;
+ }
+ i++;
+ }
+ EnableWindow( GetDlgItem( hwndDlg, IDC_BROWSE ), TRUE );
+ }
+ return TRUE;
+ case WM_JABBER_CHECK_ONLINE:
+ {
+ TCHAR text[128];
+ if ( jabberOnline ) {
+ EnableWindow( GetDlgItem( hwndDlg, IDC_JOIN ), TRUE );
+ GetDlgItemText( hwndDlg, IDC_SERVER, text, SIZEOF( text ));
+ EnableWindow( GetDlgItem( hwndDlg, IDC_BROWSE ), ( text[0]!='\0' ));
+ }
+ else {
+ EnableWindow( GetDlgItem( hwndDlg, IDC_JOIN ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_BROWSE ), FALSE );
+ SetDlgItemTextA( hwndDlg, IDC_SERVER, "" );
+ lv = GetDlgItem( hwndDlg, IDC_ROOM );
+ ListView_DeleteAllItems( lv );
+ }
+ break;
+ }
+ case WM_NOTIFY:
+ switch ( wParam ) {
+ case IDC_ROOM:
+ switch (( ( LPNMHDR )lParam )->code ) {
+ case LVN_COLUMNCLICK:
+ {
+ LPNMLISTVIEW pnmlv = ( LPNMLISTVIEW ) lParam;
+
+ if ( pnmlv->iSubItem>=0 && pnmlv->iSubItem<=1 ) {
+ if ( pnmlv->iSubItem == sortColumn )
+ sortAscending = !sortAscending;
+ else {
+ sortAscending = TRUE;
+ sortColumn = pnmlv->iSubItem;
+ }
+ ListView_SortItems( GetDlgItem( hwndDlg, IDC_ROOM ), GroupchatCompare, sortColumn );
+ }
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case WM_JABBER_JOIN:
+ if ( jabberChatDllPresent ) {
+ lv = GetDlgItem( hwndDlg, IDC_ROOM );
+ if (( lvItem.iItem=ListView_GetNextItem( lv, -1, LVNI_SELECTED )) >= 0 ) {
+ lvItem.iSubItem = 0;
+ lvItem.mask = LVIF_PARAM;
+ ListView_GetItem( lv, &lvItem );
+ ListView_SetItemState( lv, lvItem.iItem, 0, LVIS_SELECTED ); // Unselect the item
+ DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_GROUPCHAT_JOIN ), hwndDlg, JabberGroupchatJoinDlgProc, ( LPARAM )lvItem.lParam );
+ }
+ else {
+ TCHAR text[128];
+ GetDlgItemText( hwndDlg, IDC_SERVER, text, SIZEOF( text ));
+ DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_GROUPCHAT_JOIN ), hwndDlg, JabberGroupchatJoinDlgProc, ( LPARAM )text );
+ } }
+ else JabberChatDllError();
+ return TRUE;
+
+ case WM_JABBER_ADD_TO_ROSTER:
+ lv = GetDlgItem( hwndDlg, IDC_ROOM );
+ if (( lvItem.iItem=ListView_GetNextItem( lv, -1, LVNI_SELECTED )) >= 0 ) {
+ lvItem.iSubItem = 0;
+ lvItem.mask = LVIF_PARAM;
+ ListView_GetItem( lv, &lvItem );
+ TCHAR* jid = ( TCHAR* )lvItem.lParam;
+ { GCSESSION gcw = {0};
+ gcw.cbSize = sizeof(GCSESSION);
+ gcw.iType = GCW_CHATROOM;
+ gcw.pszID = t2a(jid);
+ gcw.pszModule = jabberProtoName;
+ gcw.pszName = NEWSTR_ALLOCA(gcw.pszID);
+ char* p = ( char* )strchr( gcw.pszName, '@' );
+ if ( p != NULL )
+ *p = 0;
+ CallService( MS_GC_NEWSESSION, 0, ( LPARAM )&gcw );
+ mir_free((void*)gcw.pszID);
+ }
+ { XmlNodeIq iq( "set" );
+ XmlNode* query = iq.addQuery( "jabber:iq:roster" );
+ XmlNode* item = query->addChild( "item" ); item->addAttr( "jid", jid );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+ { XmlNode p( "presence" ); p.addAttr( "to", jid ); p.addAttr( "type", "subscribe" );
+ JabberSend( jabberThreadInfo->s, p );
+ } }
+ break;
+
+ case IDC_SERVER:
+ { TCHAR text[ 128 ];
+ GetDlgItemText( hwndDlg, IDC_SERVER, text, SIZEOF( text ));
+ if ( jabberOnline && ( text[0] || HIWORD( wParam )==CBN_SELCHANGE ))
+ EnableWindow( GetDlgItem( hwndDlg, IDC_BROWSE ), TRUE );
+ break;
+ }
+ case IDC_BROWSE:
+ { TCHAR text[ 128 ];
+ GetDlgItemText( hwndDlg, IDC_SERVER, text, SIZEOF( text ));
+ if ( jabberOnline && text[0] ) {
+ EnableWindow( GetDlgItem( hwndDlg, IDC_BROWSE ), FALSE );
+ ListView_DeleteAllItems( GetDlgItem( hwndDlg, IDC_ROOM ));
+ GetDlgItemText( hwndDlg, IDC_SERVER, text, SIZEOF( text ));
+
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_DISCOROOMSERVER, JabberIqResultDiscoRoomItems );
+
+ XmlNodeIq iq( "get", iqId, text );
+ XmlNode* query = iq.addQuery( "http://jabber.org/protocol/disco#items" );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+ return TRUE;
+ }
+ case IDCLOSE:
+ DestroyWindow( hwndDlg );
+ return TRUE;
+ }
+ break;
+ case WM_CONTEXTMENU:
+ if (( HWND )wParam == GetDlgItem( hwndDlg, IDC_ROOM )) {
+ HMENU hMenu = CreatePopupMenu();
+ AppendMenu( hMenu, MF_STRING, WM_JABBER_JOIN, TranslateT( "Join" ));
+ AppendMenu( hMenu, MF_STRING, WM_JABBER_ADD_TO_ROSTER, TranslateT( "Add to roster" ));
+ TrackPopupMenu( hMenu, TPM_LEFTALIGN | TPM_NONOTIFY, LOWORD(lParam), HIWORD(lParam), 0, hwndDlg, 0 );
+ ::DestroyMenu( hMenu );
+ return TRUE;
+ }
+ break;
+ case WM_CLOSE:
+ DestroyWindow( hwndDlg );
+ break;
+ case WM_DESTROY:
+ hwndJabberGroupchat = NULL;
+ break;
+ }
+ return FALSE;
+}
+
+void JabberGroupchatJoinRoom( const TCHAR* server, const TCHAR* room, const TCHAR* nick, const TCHAR* password )
+{
+ TCHAR text[128];
+ mir_sntprintf( text, SIZEOF(text), _T("%s@%s/%s"), room, server, nick );
+
+ JABBER_LIST_ITEM* item = JabberListAdd( LIST_CHATROOM, text );
+ replaceStr( item->nick, nick );
+
+ int status = ( jabberStatus == ID_STATUS_INVISIBLE ) ? ID_STATUS_ONLINE : jabberStatus;
+ XmlNode* x = new XmlNode( "x" ); x->addAttr( "xmlns", "http://jabber.org/protocol/muc" );
+ if ( password && password[0]!='\0' )
+ x->addChild( "password", password );
+ JabberSendPresenceTo( status, text, x );
+}
+
+static BOOL CALLBACK JabberGroupchatJoinDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ TCHAR text[128];
+ TCHAR* p;
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ {
+ // lParam is the room JID ( room@server ) in UTF-8
+ hwndJabberJoinGroupchat = hwndDlg;
+ TranslateDialogDefault( hwndDlg );
+ if ( lParam ){
+ _tcsncpy( text, ( TCHAR* )lParam, SIZEOF( text ));
+ if (( p = _tcschr( text, '@' )) != NULL ) {
+ *p = '\0';
+ // Need to save room name in UTF-8 in case the room codepage is different
+ // from the local code page
+ TCHAR* room = mir_tstrdup( text );
+ SetWindowLong( hwndDlg, GWL_USERDATA, ( LONG ) room );
+ SetDlgItemText( hwndDlg, IDC_ROOM, room );
+ SetDlgItemText( hwndDlg, IDC_SERVER, p+1 );
+ }
+ else SetDlgItemText( hwndDlg, IDC_SERVER, text );
+ }
+
+ DBVARIANT dbv;
+ if ( !JGetStringT( NULL, "Nick", &dbv )) {
+ SetDlgItemText( hwndDlg, IDC_NICK, dbv.ptszVal );
+ JFreeVariant( &dbv );
+ }
+ else {
+ TCHAR* nick = JabberNickFromJID( jabberJID );
+ SetDlgItemText( hwndDlg, IDC_NICK, nick );
+ mir_free( nick );
+ } }
+ return TRUE;
+
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_ROOM:
+ if (( HWND )lParam==GetFocus() && HIWORD( wParam )==EN_CHANGE ) {
+ // Change in IDC_ROOM field is detected,
+ // invalidate the saved UTF-8 room name if any
+ char* str = ( char* )GetWindowLong( hwndDlg, GWL_USERDATA );
+ if ( str != NULL ) {
+ mir_free( str );
+ SetWindowLong( hwndDlg, GWL_USERDATA, ( LONG ) NULL );
+ } }
+ break;
+ case IDOK:
+ {
+ GetDlgItemText( hwndDlg, IDC_SERVER, text, SIZEOF( text ));
+ TCHAR* server = NEWTSTR_ALLOCA( text ), *room;
+
+ if (( room=( TCHAR* )GetWindowLong( hwndDlg, GWL_USERDATA )) != NULL )
+ room = NEWTSTR_ALLOCA( room );
+ else {
+ GetDlgItemText( hwndDlg, IDC_ROOM, text, SIZEOF( text ));
+ room = NEWTSTR_ALLOCA( text );
+ }
+
+ GetDlgItemText( hwndDlg, IDC_NICK, text, SIZEOF( text ));
+ TCHAR* nick = NEWTSTR_ALLOCA( text );
+
+ GetDlgItemText( hwndDlg, IDC_PASSWORD, text, SIZEOF( text ));
+ TCHAR* password = NEWTSTR_ALLOCA( text );
+ JabberGroupchatJoinRoom( server, room, nick, password );
+ }
+ // fall through
+ case IDCANCEL:
+ EndDialog( hwndDlg, 0 );
+ break;
+ }
+ break;
+ case WM_JABBER_CHECK_ONLINE:
+ if ( !jabberOnline ) EndDialog( hwndDlg, 0 );
+ break;
+ case WM_DESTROY:
+ {
+ char* str = ( char* )GetWindowLong( hwndDlg, GWL_USERDATA );
+ if ( str != NULL )
+ mir_free( str );
+
+ hwndJabberJoinGroupchat = NULL;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberGroupchatProcessPresence - handles the group chat presence packet
+
+static int sttGetStatusCode( XmlNode* node )
+{
+ XmlNode* statusNode = JabberXmlGetChild( node, "status" );
+ if ( statusNode == NULL )
+ return -1;
+
+ TCHAR* statusCode = JabberXmlGetAttrValue( statusNode, "code" );
+ if ( statusCode == NULL )
+ return -1;
+
+ return _ttol( statusCode );
+}
+
+void sttRenameParticipantNick( JABBER_LIST_ITEM* item, TCHAR* oldNick, XmlNode *itemNode )
+{
+ TCHAR* newNick = JabberXmlGetAttrValue( itemNode, "nick" );
+ if ( newNick == NULL )
+ return;
+
+ for ( int i=0; i < item->resourceCount; i++ ) {
+ JABBER_RESOURCE_STATUS& RS = item->resource[i];
+ if ( !lstrcmp( RS.resourceName, oldNick )) {
+ replaceStr( RS.resourceName, newNick );
+
+ if ( !lstrcmp( item->nick, oldNick )) {
+ replaceStr( item->nick, newNick );
+
+ HANDLE hContact = JabberHContactFromJID( item->jid );
+ if ( hContact != NULL )
+ JSetStringT( hContact, "MyNick", newNick );
+ }
+
+ #if defined( _UNICODE )
+ char* jid = u2a( item->jid );
+ char* dispNick = u2a( newNick );
+ char* dispOldNick = u2a( oldNick );
+ #else
+ char* jid = item->jid;
+ char* dispNick = NEWSTR_ALLOCA( newNick );
+ char* dispOldNick = NEWSTR_ALLOCA( oldNick );
+ #endif
+
+ GCDEST gcd = { jabberProtoName, jid, GC_EVENT_CHUID };
+ GCEVENT gce = {0};
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ gce.pszNick = dispOldNick;
+ gce.pszText = dispNick;
+ gce.time = time(0);
+ JCallService( MS_GC_EVENT, NULL, ( LPARAM )&gce );
+
+ gcd.iType = GC_EVENT_NICK;
+ gce.pszNick = dispOldNick;
+ gce.pszUID = dispNick;
+ gce.pszText = dispNick;
+ JCallService( MS_GC_EVENT, NULL, ( LPARAM )&gce );
+
+ #if defined( _UNICODE )
+ mir_free( jid );
+ mir_free( dispNick );
+ mir_free( dispOldNick );
+ #endif
+ break;
+} } }
+
+void JabberGroupchatProcessPresence( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info;
+ XmlNode *showNode, *statusNode, *errorNode, *itemNode, *n;
+ TCHAR* from;
+ int status, newRes;
+ int i;
+ BOOL roomCreated;
+
+ if ( !node || !node->name || strcmp( node->name, "presence" )) return;
+ if (( info=( struct ThreadData * ) userdata ) == NULL ) return;
+ if (( from=JabberXmlGetAttrValue( node, "from" )) == NULL ) return;
+
+ TCHAR* nick = _tcschr( from, '/' );
+ if ( nick == NULL || nick[1] == '\0' )
+ return;
+ nick++;
+
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_CHATROOM, from );
+ if ( item == NULL )
+ return;
+
+ XmlNode* xNode = JabberXmlGetChildWithGivenAttrValue( node, "x", "xmlns", _T("http://jabber.org/protocol/muc#user"));
+
+ TCHAR* type = JabberXmlGetAttrValue( node, "type" );
+ if ( type == NULL || !_tcscmp( type, _T("available"))) {
+ TCHAR* room = JabberNickFromJID( from );
+ if ( room == NULL )
+ return;
+
+ JabberGcLogCreate( item );
+
+ // Update status of room participant
+ status = ID_STATUS_ONLINE;
+ if (( showNode=JabberXmlGetChild( node, "show" )) != NULL ) {
+ if ( showNode->text != NULL ) {
+ if ( !_tcscmp( showNode->text , _T("away"))) status = ID_STATUS_AWAY;
+ else if ( !_tcscmp( showNode->text , _T("xa"))) status = ID_STATUS_NA;
+ else if ( !_tcscmp( showNode->text , _T("dnd"))) status = ID_STATUS_DND;
+ else if ( !_tcscmp( showNode->text , _T("chat"))) status = ID_STATUS_FREECHAT;
+ } }
+
+ TCHAR* str;
+ if (( statusNode=JabberXmlGetChild( node, "status" ))!=NULL && statusNode->text!=NULL )
+ str = statusNode->text;
+ else
+ str = NULL;
+ newRes = ( JabberListAddResource( LIST_CHATROOM, from, status, str ) == 0 ) ? 0 : GC_EVENT_JOIN;
+
+ roomCreated = FALSE;
+
+ // Check additional MUC info for this user
+ if ( xNode != NULL ) {
+ if (( itemNode=JabberXmlGetChild( xNode, "item" )) != NULL ) {
+ JABBER_RESOURCE_STATUS* r = item->resource;
+ for ( i=0; i<item->resourceCount && _tcscmp( r->resourceName, nick ); i++, r++ );
+ if ( i < item->resourceCount ) {
+ if (( str=JabberXmlGetAttrValue( itemNode, "affiliation" )) != NULL ) {
+ if ( !_tcscmp( str, _T("owner"))) r->affiliation = AFFILIATION_OWNER;
+ else if ( !_tcscmp( str, _T("admin"))) r->affiliation = AFFILIATION_ADMIN;
+ else if ( !_tcscmp( str, _T("member"))) r->affiliation = AFFILIATION_MEMBER;
+ else if ( !_tcscmp( str, _T("outcast"))) r->affiliation = AFFILIATION_OUTCAST;
+ }
+ if (( str=JabberXmlGetAttrValue( itemNode, "role" )) != NULL ) {
+ JABBER_GC_ROLE newRole = r->role;
+
+ if ( !_tcscmp( str, _T("moderator"))) newRole = ROLE_MODERATOR;
+ else if ( !_tcscmp( str, _T("participant"))) newRole = ROLE_PARTICIPANT;
+ else if ( !_tcscmp( str, _T("visitor"))) newRole = ROLE_VISITOR;
+ else newRole = ROLE_NONE;
+
+ if ( newRole != r->role && r->role != ROLE_NONE ) {
+ JabberGcLogUpdateMemberStatus( item, nick, GC_EVENT_REMOVESTATUS, NULL );
+ newRes = GC_EVENT_ADDSTATUS;
+ }
+ r->role = newRole;
+ } } }
+
+ if ( sttGetStatusCode( xNode ) == 201 )
+ roomCreated = TRUE;
+ }
+
+ // Update groupchat log window
+ JabberGcLogUpdateMemberStatus( item, nick, newRes, NULL );
+
+ HANDLE hContact = JabberHContactFromJID( 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=JabberXmlGetChild( node, "created" ))!=NULL &&
+ ( str=JabberXmlGetAttrValue( n, "xmlns" ))!=NULL &&
+ !_tcscmp( str, _T("http://jabber.org/protocol/muc#owner"))) ) {
+ // A new room just created by me
+ // Request room config
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultGetMuc );
+
+ XmlNodeIq iq( "get", iqId, item->jid );
+ XmlNode* query = iq.addQuery( xmlnsOwner );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+
+ mir_free( room );
+ }
+ else if ( !lstrcmp( type, _T("unavailable"))) {
+ if ( xNode != NULL && item->nick != NULL ) {
+ itemNode = JabberXmlGetChild( xNode, "item" );
+ XmlNode* reasonNode = JabberXmlGetChild( itemNode, "reason" );
+
+ if ( !lstrcmp( nick, item->nick )) {
+ int iStatus = sttGetStatusCode( xNode );
+ switch( iStatus ) {
+ case 301: case 307:
+ JabberGcQuit( item, iStatus, reasonNode );
+ break;
+
+ case 303:
+ sttRenameParticipantNick( item, nick, itemNode );
+ return;
+ } }
+ else {
+ switch( sttGetStatusCode( xNode )) {
+ case 303:
+ sttRenameParticipantNick( item, nick, itemNode );
+ return;
+
+ case 307:
+ JabberListRemoveResource( LIST_CHATROOM, from );
+ JabberGcLogUpdateMemberStatus( item, nick, GC_EVENT_KICK, reasonNode );
+ return;
+ } } }
+
+ JabberListRemoveResource( LIST_CHATROOM, from );
+ JabberGcLogUpdateMemberStatus( item, nick, GC_EVENT_PART, NULL );
+ }
+ else if ( !lstrcmp( type, _T("error"))) {
+ errorNode = JabberXmlGetChild( node, "error" );
+ TCHAR* str = JabberErrorMsg( errorNode );
+ MessageBox( NULL, str, TranslateT( "Jabber Error Message" ), MB_OK|MB_SETFOREGROUND );
+ //JabberListRemoveResource( LIST_CHATROOM, from );
+ JabberListRemove( LIST_CHATROOM, from );
+ mir_free( str );
+} }
+
+void strdel( char* parBuffer, int len )
+{
+ char* p;
+ for ( p = parBuffer+len; *p != 0; p++ )
+ p[ -len ] = *p;
+
+ p[ -len ] = '\0';
+}
+
+void JabberGroupchatProcessMessage( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info;
+ XmlNode *n, *xNode;
+ TCHAR* from, *type, *p, *nick, *msgText;
+ JABBER_LIST_ITEM *item;
+
+ if ( !node->name || strcmp( node->name, "message" )) return;
+ if (( info=( struct ThreadData * ) userdata ) == NULL ) return;
+ if (( from = JabberXmlGetAttrValue( node, "from" )) == NULL ) return;
+ if (( item = JabberListGetItemPtr( LIST_CHATROOM, from )) == NULL ) return;
+
+ if (( type = JabberXmlGetAttrValue( node, "type" )) == NULL ) return;
+ if ( !lstrcmp( type, _T("error")))
+ return;
+
+ #if defined( _UNICODE )
+ char* jid = u2a( item->jid );
+ #else
+ char* jid = item->jid;
+ #endif
+ GCDEST gcd = { jabberProtoName, jid, 0 };
+
+ if (( n = JabberXmlGetChild( node, "subject" )) != NULL ) {
+ if ( n->text == NULL || n->text[0] == '\0' )
+ return;
+
+ msgText = n->text;
+
+ gcd.iType = GC_EVENT_TOPIC;
+
+ if ( from != NULL ) {
+ nick = _tcschr( from, '/' );
+ if ( nick == NULL || nick[1] == '\0' )
+ nick = NULL;
+ else
+ nick++;
+ }
+ else nick = NULL;
+ }
+ else {
+ if (( n = JabberXmlGetChild( node, "body" )) == NULL ) return;
+ if ( n->text == NULL )
+ return;
+
+ nick = _tcschr( from, '/' );
+ if ( nick == NULL || nick[1] == '\0' )
+ return;
+ nick++;
+
+ msgText = n->text;
+
+ if ( _tcsncmp( msgText, _T("/me "), 4 ) == 0 && _tcslen( msgText ) > 4 ) {
+ msgText += 4;
+ gcd.iType = GC_EVENT_ACTION;
+ }
+ else gcd.iType = GC_EVENT_MESSAGE;
+ }
+
+ JabberGcLogCreate( item );
+
+ time_t msgTime = 0;
+ BOOL delivered = FALSE;
+ for ( int i = 1; ( xNode=JabberXmlGetNthChild( node, "x", i )) != NULL; i++ )
+ if (( p=JabberXmlGetAttrValue( xNode, "xmlns" )) != NULL )
+ if ( !_tcscmp( p, _T("jabber:x:delay")) && msgTime==0 )
+ if (( p=JabberXmlGetAttrValue( xNode, "stamp" )) != NULL )
+ msgTime = JabberIsoToUnixTime( p );
+
+ time_t now = time( NULL );
+ if ( msgTime == 0 || msgTime > now )
+ msgTime = now;
+
+ #if defined( _UNICODE )
+ char* dispNick = u2a( nick );
+ char* dispMsg = u2a( msgText );
+ #else
+ char* dispNick = nick;
+ char* dispMsg = msgText;
+ #endif
+
+ GCEVENT gce = {0};
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ gce.pszUID = dispNick;
+ gce.pszNick = dispNick;
+ gce.bAddToLog = TRUE;
+ gce.time = msgTime;
+ gce.pszText = EscapeChatTags( dispMsg );
+ gce.bIsMe = lstrcmp( nick, item->nick ) == 0;
+ JCallService(MS_GC_EVENT, NULL, (LPARAM)&gce);
+
+ item->bChatActive = 2;
+
+ if ( gcd.iType == GC_EVENT_TOPIC ) {
+ gce.bAddToLog = FALSE;
+ gcd.iType = GC_EVENT_SETSBTEXT;
+ JCallService(MS_GC_EVENT, NULL, (LPARAM)&gce);
+ }
+
+ #if defined( _UNICODE )
+ mir_free( dispNick );
+ mir_free( dispMsg );
+ mir_free( jid );
+ #endif
+ mir_free( (void*)gce.pszText ); // Since we processed msgText and created a new string
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Accepting groupchat invitations
+
+typedef struct {
+ TCHAR* roomJid;
+ TCHAR* from;
+ TCHAR* reason;
+ TCHAR* password;
+}
+ JABBER_GROUPCHAT_INVITE_INFO;
+
+static void JabberAcceptGroupchatInvite( TCHAR* roomJid, TCHAR* reason, TCHAR* password )
+{
+ TCHAR room[256], *server, *p;
+ _tcsncpy( room, roomJid, SIZEOF( room ));
+ p = _tcstok( room, _T( "@" ));
+ server = _tcstok( NULL, _T( "@" ));
+ JabberGroupchatJoinRoom( server, p, reason, password );
+}
+
+static BOOL CALLBACK JabberGroupchatInviteAcceptDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ {
+ JABBER_GROUPCHAT_INVITE_INFO *inviteInfo = ( JABBER_GROUPCHAT_INVITE_INFO * ) lParam;
+
+ TranslateDialogDefault( hwndDlg );
+ SetWindowLong( hwndDlg, GWL_USERDATA, ( LONG ) inviteInfo );
+ SetDlgItemText( hwndDlg, IDC_FROM, inviteInfo->from );
+ SetDlgItemText( hwndDlg, IDC_ROOM, inviteInfo->roomJid );
+
+ if ( inviteInfo->reason != NULL )
+ SetDlgItemText( hwndDlg, IDC_REASON, inviteInfo->reason );
+
+ TCHAR* myNick = JabberNickFromJID( jabberJID );
+ SetDlgItemText( hwndDlg, IDC_NICK, myNick );
+ mir_free( myNick );
+
+ SendMessage( hwndDlg, WM_SETICON, ICON_BIG, ( LPARAM )LoadIcon( hInst, MAKEINTRESOURCE( IDI_GROUP )) );
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_ACCEPT:
+ {
+ JABBER_GROUPCHAT_INVITE_INFO *inviteInfo = ( JABBER_GROUPCHAT_INVITE_INFO * ) GetWindowLong( hwndDlg, GWL_USERDATA );
+ TCHAR text[128];
+ GetDlgItemText( hwndDlg, IDC_NICK, text, SIZEOF( text ));
+ JabberAcceptGroupchatInvite( inviteInfo->roomJid, text, inviteInfo->password );
+ }
+ // Fall through
+ case IDCANCEL:
+ case IDCLOSE:
+ EndDialog( hwndDlg, 0 );
+ return TRUE;
+ }
+ break;
+ case WM_CLOSE:
+ EndDialog( hwndDlg, 0 );
+ break;
+ }
+
+ return FALSE;
+}
+
+static void __cdecl JabberGroupchatInviteAcceptThread( JABBER_GROUPCHAT_INVITE_INFO *inviteInfo )
+{
+ DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_GROUPCHAT_INVITE_ACCEPT ), NULL, JabberGroupchatInviteAcceptDlgProc, ( LPARAM )inviteInfo );
+ mir_free( inviteInfo->roomJid );
+ mir_free( inviteInfo->from );
+ mir_free( inviteInfo->reason );
+ mir_free( inviteInfo->password );
+ mir_free( inviteInfo );
+}
+
+void JabberGroupchatProcessInvite( TCHAR* roomJid, TCHAR* from, TCHAR* reason, TCHAR* password )
+{
+ if ( roomJid == NULL )
+ return;
+
+ if ( JGetByte( "AutoAcceptMUC", FALSE ) == 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 );
+ JabberForkThread(( JABBER_THREAD_FUNC )JabberGroupchatInviteAcceptThread, 0, ( void* )inviteInfo );
+ }
+ else {
+ TCHAR* myNick = JabberNickFromJID( jabberJID );
+ JabberAcceptGroupchatInvite( roomJid, myNick, password );
+ mir_free( myNick );
+} }
diff --git a/miranda-wine/protocols/JabberG/jabber_iq.cpp b/miranda-wine/protocols/JabberG/jabber_iq.cpp
new file mode 100644
index 0000000..4b0d90d
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_iq.cpp
@@ -0,0 +1,173 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_iq.cpp,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include "jabber_iq.h"
+#include "jabber_xmlns.h"
+
+static JABBER_IQ_XMLNS_FUNC jabberXmlns[] = {
+ { _T("http://jabber.org/protocol/disco"), JabberXmlnsDisco, TRUE },
+ { _T("jabber:iq:browse"), JabberXmlnsBrowse, FALSE }
+};
+
+typedef struct {
+ 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
+} JABBER_IQ_FUNC;
+
+static CRITICAL_SECTION csIqList;
+static JABBER_IQ_FUNC *iqList;
+static int iqCount;
+static int iqAlloced;
+
+void JabberIqInit()
+{
+ InitializeCriticalSection( &csIqList );
+ iqList = NULL;
+ iqCount = 0;
+ iqAlloced = 0;
+}
+
+void JabberIqUninit()
+{
+ if ( iqList ) mir_free( iqList );
+ iqList = NULL;
+ iqCount = 0;
+ iqAlloced = 0;
+ DeleteCriticalSection( &csIqList );
+}
+
+static void JabberIqRemove( int index )
+{
+ EnterCriticalSection( &csIqList );
+ if ( index>=0 && index<iqCount ) {
+ memmove( iqList+index, iqList+index+1, sizeof( JABBER_IQ_FUNC )*( iqCount-index-1 ));
+ iqCount--;
+ }
+ LeaveCriticalSection( &csIqList );
+}
+
+static void JabberIqExpire()
+{
+ int i;
+ time_t expire;
+
+ EnterCriticalSection( &csIqList );
+ expire = time( NULL ) - 120; // 2 minute
+ i = 0;
+ while ( i < iqCount ) {
+ if ( iqList[i].requestTime < expire )
+ JabberIqRemove( i );
+ else
+ i++;
+ }
+ LeaveCriticalSection( &csIqList );
+}
+
+JABBER_IQ_PFUNC JabberIqFetchFunc( int iqId )
+{
+ int i;
+ JABBER_IQ_PFUNC res;
+
+ EnterCriticalSection( &csIqList );
+ JabberIqExpire();
+#ifdef _DEBUG
+ for ( i=0; i<iqCount; i++ )
+ JabberLog( " %04d : %02d : 0x%x", iqList[i].iqId, iqList[i].procId, iqList[i].func );
+#endif
+ for ( i=0; i<iqCount && iqList[i].iqId!=iqId; i++ );
+ if ( i < iqCount ) {
+ res = iqList[i].func;
+ JabberIqRemove( i );
+ }
+ else {
+ res = ( JABBER_IQ_PFUNC ) NULL;
+ }
+ LeaveCriticalSection( &csIqList );
+ return res;
+}
+
+void JabberIqAdd( unsigned int iqId, JABBER_IQ_PROCID procId, JABBER_IQ_PFUNC func )
+{
+ int i;
+
+ EnterCriticalSection( &csIqList );
+ JabberLog( "IqAdd id=%d, proc=%d, func=0x%x", iqId, procId, func );
+ if ( procId == IQ_PROC_NONE )
+ i = iqCount;
+ else
+ for ( i=0; i<iqCount && iqList[i].procId!=procId; i++ );
+
+ if ( i>=iqCount && iqCount>=iqAlloced ) {
+ iqAlloced = iqCount + 8;
+ iqList = ( JABBER_IQ_FUNC * )mir_realloc( iqList, sizeof( JABBER_IQ_FUNC )*iqAlloced );
+ }
+
+ if ( iqList != NULL ) {
+ iqList[i].iqId = iqId;
+ iqList[i].procId = procId;
+ iqList[i].func = func;
+ iqList[i].requestTime = time( NULL );
+ if ( i == iqCount ) iqCount++;
+ }
+ LeaveCriticalSection( &csIqList );
+}
+
+JABBER_IQ_PFUNC JabberIqFetchXmlnsFunc( TCHAR* xmlns )
+{
+ unsigned int len, count, i;
+ TCHAR* p, *q;
+
+ if ( xmlns == NULL )
+ return NULL;
+
+ p = _tcsrchr( xmlns, '/' );
+ q = _tcsrchr( xmlns, '#' );
+ if ( p!=NULL && q!=NULL && q>p )
+ len = q - xmlns;
+ else
+ len = _tcslen( xmlns );
+
+ count = sizeof( jabberXmlns ) / sizeof( jabberXmlns[0] );
+ for ( i=0; i<count; i++ ) {
+ if ( jabberXmlns[i].allowSubNs ) {
+ if ( _tcslen( jabberXmlns[i].xmlns ) == len && !_tcsncmp( jabberXmlns[i].xmlns, xmlns, len ))
+ break;
+ }
+ else {
+ if ( !_tcscmp( jabberXmlns[i].xmlns, xmlns ))
+ break;
+ }
+ }
+
+ if ( i < count )
+ return jabberXmlns[i].func;
+
+ return NULL;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_iq.h b/miranda-wine/protocols/JabberG/jabber_iq.h
new file mode 100644
index 0000000..35a95e5
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_iq.h
@@ -0,0 +1,87 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_iq.h,v $
+Revision : $Revision: 3703 $
+Last change on : $Date: 2006-09-05 17:54:42 +0400 (Втр, 05 Сен 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#ifndef _JABBER_IQ_H_
+#define _JABBER_IQ_H_
+
+#include "jabber_xml.h"
+
+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_BROWSEROOMS,
+ IQ_PROC_DISCOROOMSERVER,
+ IQ_PROC_DISCOAGENTS
+} JABBER_IQ_PROCID;
+
+typedef void ( *JABBER_IQ_PFUNC )( XmlNode *iqNode, void *usedata );
+
+typedef struct {
+ TCHAR* xmlns;
+ JABBER_IQ_PFUNC func;
+ BOOL allowSubNs; // e.g. #info in disco#info
+} JABBER_IQ_XMLNS_FUNC;
+
+void JabberIqInit();
+void JabberIqUninit();
+JABBER_IQ_PFUNC JabberIqFetchFunc( int iqId );
+void JabberIqAdd( unsigned int iqId, JABBER_IQ_PROCID procId, JABBER_IQ_PFUNC func );
+JABBER_IQ_PFUNC JabberIqFetchXmlnsFunc( TCHAR* xmlns );
+
+void JabberIqResultBind( XmlNode *iqNode, void *userdata );
+void JabberIqResultBrowseRooms( XmlNode *iqNode, void *userdata );
+void JabberIqResultDiscoAgentInfo( XmlNode *iqNode, void *userdata );
+void JabberIqResultDiscoAgentItems( XmlNode *iqNode, void *userdata );
+void JabberIqResultDiscoClientInfo( XmlNode *iqNode, void *userdata );
+void JabberIqResultDiscoRoomItems( XmlNode *iqNode, void *userdata );
+void JabberIqResultExtSearch( XmlNode *iqNode, void *userdata );
+void JabberIqResultGetAgents( XmlNode *iqNode, void *userdata );
+void JabberIqResultGetAuth( XmlNode *iqNode, void *userdata );
+void JabberIqResultGetAvatar( XmlNode *iqNode, void *userdata );
+void JabberIqResultGetMuc( XmlNode *iqNode, void *userdata );
+void JabberIqResultGetRegister( XmlNode *iqNode, void *userdata );
+void JabberIqResultGetRoster( XmlNode *iqNode, void *userdata );
+void JabberIqResultGetVcard( XmlNode *iqNode, void *userdata );
+void JabberIqResultMucGetAdminList( XmlNode *iqNode, void *userdata );
+void JabberIqResultMucGetBanList( XmlNode *iqNode, void *userdata );
+void JabberIqResultMucGetMemberList( XmlNode *iqNode, void *userdata );
+void JabberIqResultMucGetModeratorList( XmlNode *iqNode, void *userdata );
+void JabberIqResultMucGetOwnerList( XmlNode *iqNode, void *userdata );
+void JabberIqResultMucGetVoiceList( XmlNode *iqNode, void *userdata );
+void JabberIqResultSession( XmlNode *iqNode, void *userdata );
+void JabberIqResultSetAuth( XmlNode *iqNode, void *userdata );
+void JabberIqResultSetPassword( XmlNode *iqNode, void *userdata );
+void JabberIqResultSetRegister( XmlNode *iqNode, void *userdata );
+void JabberIqResultSetSearch( XmlNode *iqNode, void *userdata );
+void JabberIqResultSetVcard( XmlNode *iqNode, void *userdata );
+
+#endif
diff --git a/miranda-wine/protocols/JabberG/jabber_iqid.cpp b/miranda-wine/protocols/JabberG/jabber_iqid.cpp
new file mode 100644
index 0000000..67b4808
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_iqid.cpp
@@ -0,0 +1,1429 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_iqid.cpp,v $
+Revision : $Revision: 3703 $
+Last change on : $Date: 2006-09-05 17:54:42 +0400 (Втр, 05 Сен 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include "resource.h"
+#include "jabber_list.h"
+#include "jabber_iq.h"
+#include "sha1.h"
+
+extern char* jabberVcardPhotoFileName;
+extern char* jabberVcardPhotoType;
+
+static void JabberOnLoggedIn( ThreadData* info )
+{
+ jabberOnline = TRUE;
+ jabberLoggedInTime = time(0);
+
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultGetRoster );
+
+ XmlNode iq( "iq" ); iq.addAttr( "type", "get" ); iq.addAttrID( iqId );
+ XmlNode* query = iq.addChild( "query" ); query->addAttr( "xmlns", "jabber:iq:roster" );
+ JabberSend( info->s, iq );
+}
+
+void JabberIqResultGetAuth( XmlNode *iqNode, void *userdata )
+{
+ // RECVED: result of the request for authentication method
+ // ACTION: send account authentication information to log in
+ JabberLog( "<iq/> iqIdGetAuth" );
+
+ ThreadData* info = ( ThreadData* ) userdata;
+ XmlNode *queryNode;
+ TCHAR* type;
+ if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+ if (( queryNode=JabberXmlGetChild( iqNode, "query" )) == NULL ) return;
+
+ if ( !lstrcmp( type, _T("result"))) {
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultSetAuth );
+
+ XmlNodeIq iq( "set", iqId );
+ XmlNode* query = iq.addQuery( "jabber:iq:auth" );
+ query->addChild( "username", info->username );
+ if ( JabberXmlGetChild( queryNode, "digest" )!=NULL && streamId ) {
+ char* str = JabberUtf8Encode( info->password );
+ char text[200];
+ mir_snprintf( text, SIZEOF(text), "%s%s", streamId, str );
+ mir_free( str );
+ if (( str=JabberSha1( text )) != NULL ) {
+ query->addChild( "digest", str );
+ mir_free( str );
+ }
+ }
+ else if ( JabberXmlGetChild( queryNode, "password" ) != NULL )
+ query->addChild( "password", info->password );
+ else {
+ JabberLog( "No known authentication mechanism accepted by the server." );
+
+ JabberSend( info->s, "</stream:stream>" );
+ return;
+ }
+
+ if ( JabberXmlGetChild( queryNode, "resource" ) != NULL )
+ query->addChild( "resource", info->resource );
+
+ JabberSend( info->s, iq );
+ }
+ else if ( !lstrcmp( type, _T("error"))) {
+ JabberSend( info->s, "</stream:stream>" );
+
+ TCHAR text[128];
+ mir_sntprintf( text, SIZEOF( text ), _T("%s %s."), TranslateT( "Authentication failed for" ), info->username );
+ MessageBox( NULL, text, TranslateT( "Jabber Authentication" ), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND );
+ JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD );
+ jabberThreadInfo = NULL; // To disallow auto reconnect
+} }
+
+void JabberIqResultSetAuth( XmlNode *iqNode, void *userdata )
+{
+ ThreadData* info = ( ThreadData* ) userdata;
+ TCHAR* type;
+ int iqId;
+
+ // RECVED: authentication result
+ // ACTION: if successfully logged in, continue by requesting roster list and set my initial status
+ JabberLog( "<iq/> iqIdSetAuth" );
+ if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+
+ if ( !lstrcmp( type, _T("result"))) {
+ DBVARIANT dbv;
+ if ( JGetStringT( NULL, "Nick", &dbv ))
+ JSetStringT( NULL, "Nick", info->username );
+ else
+ JFreeVariant( &dbv );
+
+ jabberOnline = TRUE;
+ jabberLoggedInTime = time(0);
+
+ iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultGetRoster );
+ { XmlNodeIq iq( "get", iqId );
+ XmlNode* query = iq.addQuery( "jabber:iq:roster" );
+ JabberSend( info->s, iq );
+ }
+
+ if ( hwndJabberAgents ) {
+ // Retrieve agent information
+ iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_GETAGENTS, JabberIqResultGetAgents );
+
+ XmlNodeIq iq( "get", iqId );
+ XmlNode* query = iq.addQuery( "jabber:iq:agents" );
+ JabberSend( info->s, iq );
+ }
+ }
+ // What to do if password error? etc...
+ else if ( !lstrcmp( type, _T("error"))) {
+ TCHAR text[128];
+
+ JabberSend( info->s, "</stream:stream>" );
+ mir_sntprintf( text, SIZEOF( text ), _T("%s %s."), TranslateT( "Authentication failed for" ), info->username );
+ MessageBox( NULL, text, TranslateT( "Jabber Authentication" ), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND );
+ JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD );
+ jabberThreadInfo = NULL; // To disallow auto reconnect
+} }
+
+void JabberIqResultBind( XmlNode *iqNode, void *userdata )
+{
+ ThreadData* info = ( ThreadData* ) userdata;
+ XmlNode* n = JabberXmlGetChild( iqNode, "bind" );
+ if ( n != NULL ) {
+ if ( n = JabberXmlGetChild( n, "jid" )) {
+ if ( n->text ) {
+ if ( !_tcsncmp( info->fullJID, n->text, SIZEOF( info->fullJID )))
+ JabberLog( "Result Bind: "TCHAR_STR_PARAM" %s "TCHAR_STR_PARAM, info->fullJID, "confirmed.", NULL );
+ else {
+ JabberLog( "Result Bind: "TCHAR_STR_PARAM" %s "TCHAR_STR_PARAM, info->fullJID, "changed to", n->text);
+ _tcsncpy( info->fullJID, n->text, SIZEOF( info->fullJID ));
+ } } }
+
+ if ( info->bIsSessionAvailable ) {
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultSession );
+
+ XmlNodeIq iq( "set" ); iq.addAttrID( iqId );
+ iq.addChild( "session" )->addAttr( "xmlns", "urn:ietf:params:xml:ns:xmpp-session" );
+ JabberSend( info->s, iq );
+ }
+ else JabberOnLoggedIn( info );
+ }
+ else if ( n = JabberXmlGetChild( n, "error" )) {
+ //rfc3920 page 39
+ TCHAR errorMessage [256];
+ int pos=0;
+ pos = mir_sntprintf( errorMessage, SIZEOF(errorMessage), TranslateT("Resource "));
+ XmlNode *tempNode;
+ if (tempNode = JabberXmlGetChild( n, "resource" ))
+ pos += mir_sntprintf(errorMessage,256-pos,_T("\"%s\" "),tempNode->text);
+ pos += mir_sntprintf( errorMessage+pos,256-pos,TranslateT("refused by server\n%s: %s"),TranslateT("Type"),Translate(JabberXmlGetAttrValue( n, "type" )));
+ if ( n->numChild )
+ pos += mir_sntprintf( errorMessage+pos,256-pos,_T("\n%s: ")_T(TCHAR_STR_PARAM)_T("\n"),TranslateT("Reason"),JTranslate( n->child[0]->name));
+ mir_sntprintf( errorMessage,256-pos, _T("%s @")_T(TCHAR_STR_PARAM)_T("."), TranslateT( "Authentication failed for" ), info->username, info->server );
+ MessageBox( NULL, errorMessage, TranslateT( "Jabber Protocol" ), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND );
+ JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPROTOCOL );
+ JabberSend( info->s, "</stream:stream>" );
+ jabberThreadInfo = NULL; // To disallow auto reconnect
+} }
+
+void JabberIqResultSession( XmlNode *iqNode, void *userdata )
+{
+ ThreadData* info = ( ThreadData* )userdata;
+
+ TCHAR* type;
+ if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+
+ if ( !lstrcmp( type, _T("result")))
+ JabberOnLoggedIn( info );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberIqResultGetRoster - populates LIST_ROSTER and creates contact for any new rosters
+
+void sttGroupchatJoinByHContact( HANDLE hContact )
+{
+ DBVARIANT dbv;
+ if( JGetStringT( hContact, "ChatRoomID", &dbv ))
+ return;
+ if( dbv.type != DBVT_ASCIIZ && dbv.type != DBVT_WCHAR )
+ return;
+
+ TCHAR* roomjid = mir_tstrdup( dbv.ptszVal );
+ JFreeVariant( &dbv );
+ if( !roomjid ) return;
+
+ TCHAR* room = roomjid;
+ TCHAR* server = _tcschr( roomjid, '@' );
+ if( !server )
+ return;
+ server[0] = '\0'; server++;
+
+ TCHAR nick[ 256 ];
+ if ( JGetStringT( hContact, "MyNick", &dbv )) {
+ TCHAR* jidnick = JabberNickFromJID( jabberJID );
+ if( !jidnick ) {
+ mir_free( jidnick );
+ mir_free( roomjid );
+ return;
+ }
+ _tcsncpy( nick, jidnick, SIZEOF( nick ));
+ mir_free( jidnick );
+ }
+ else {
+ _tcsncpy( nick, dbv.ptszVal, SIZEOF( nick ));
+ JFreeVariant( &dbv );
+ }
+
+ JabberGroupchatJoinRoom( server, room, nick, _T(""));
+ mir_free( roomjid );
+}
+
+void CALLBACK sttCreateRoom( ULONG dwParam )
+{
+ char* jid = t2a(( TCHAR* )dwParam), *p;
+
+ GCSESSION gcw = {0};
+ gcw.cbSize = sizeof(GCSESSION);
+ gcw.iType = GCW_CHATROOM;
+ gcw.pszID = jid;
+ gcw.pszModule = jabberProtoName;
+ gcw.pszName = strcpy(( char* )alloca( strlen(jid)+1 ), jid );
+ if (( p = (char*)strchr( gcw.pszName, '@' )) != NULL )
+ *p = 0;
+ CallService( MS_GC_NEWSESSION, 0, ( LPARAM )&gcw );
+ mir_free(jid);
+}
+
+void JabberIqResultGetRoster( XmlNode* iqNode, void* )
+{
+ JabberLog( "<iq/> iqIdGetRoster" );
+ TCHAR* type = JabberXmlGetAttrValue( iqNode, "type" );
+ if ( lstrcmp( type, _T("result")))
+ return;
+
+ XmlNode* queryNode = JabberXmlGetChild( iqNode, "query" );
+ if ( queryNode == NULL )
+ return;
+
+ if ( lstrcmp( JabberXmlGetAttrValue( queryNode, "xmlns" ), _T("jabber:iq:roster")))
+ return;
+
+ TCHAR* name, *nick;
+ int i;
+ SortedList chatRooms = {0};
+ chatRooms.increment = 10;
+
+ for ( i=0; i < queryNode->numChild; i++ ) {
+ XmlNode* itemNode = queryNode->child[i];
+ if ( strcmp( itemNode->name, "item" ))
+ continue;
+
+ TCHAR* str = JabberXmlGetAttrValue( itemNode, "subscription" );
+
+ 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;
+
+ TCHAR* jid = JabberXmlGetAttrValue( itemNode, "jid" );
+ if ( jid == NULL )
+ continue;
+
+ if (( name = JabberXmlGetAttrValue( itemNode, "name" )) != NULL )
+ nick = mir_tstrdup( name );
+ else
+ nick = JabberNickFromJID( jid );
+
+ if ( nick == NULL )
+ continue;
+
+ JABBER_LIST_ITEM* item = JabberListAdd( LIST_ROSTER, jid );
+ item->subscription = sub;
+
+ if ( item->nick ) mir_free( item->nick );
+ item->nick = nick;
+
+ if ( item->group ) mir_free( item->group );
+ XmlNode* groupNode = JabberXmlGetChild( itemNode, "group" );
+ if ( groupNode != NULL && groupNode->text != NULL )
+ item->group = mir_tstrdup( groupNode->text );
+ else
+ item->group = NULL;
+
+ HANDLE hContact = JabberHContactFromJID( jid );
+ if ( hContact == NULL ) {
+ // Received roster has a new JID.
+ // Add the jid ( with empty resource ) to Miranda contact list.
+ hContact = JabberDBCreateContact( jid, nick, FALSE, TRUE );
+ }
+
+ 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 );
+
+ if ( JGetByte( hContact, "ChatRoom", 0 )) {
+ //DBDeleteContactSetting( hContact, "CList", "Hidden" );
+ QueueUserAPC( sttCreateRoom, hMainThread, ( unsigned long )jid );
+ DBDeleteContactSetting( hContact, "CList", "Hidden" );
+ li.List_Insert( &chatRooms, hContact, chatRooms.realCount );
+ }
+
+ 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" );
+ }
+
+ // Delete orphaned contacts ( if roster sync is enabled )
+ if ( JGetByte( "RosterSync", FALSE ) == TRUE ) {
+ int listSize = 0, listAllocSize = 0;
+ HANDLE* list = NULL;
+ HANDLE hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL ) {
+ char* str = ( char* )JCallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 );
+ if ( str != NULL && !strcmp( str, jabberProtoName )) {
+ DBVARIANT dbv;
+ if ( !JGetStringT( hContact, "jid", &dbv )) {
+ if ( !JabberListExist( LIST_ROSTER, dbv.ptszVal )) {
+ JabberLog( "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 = ( HANDLE ) JCallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM ) hContact, 0 );
+ }
+
+ for ( i=0; i < listSize; i++ ) {
+ JabberLog( "Syncing roster: deleting 0x%x", list[i] );
+ JCallService( MS_DB_CONTACT_DELETE, ( WPARAM ) list[i], 0 );
+ }
+ if ( list != NULL )
+ mir_free( list );
+ }
+
+ JabberEnableMenuItems( TRUE );
+
+ if ( hwndJabberGroupchat )
+ SendMessage( hwndJabberGroupchat, WM_JABBER_CHECK_ONLINE, 0, 0 );
+ if ( hwndJabberJoinGroupchat )
+ SendMessage( hwndJabberJoinGroupchat, WM_JABBER_CHECK_ONLINE, 0, 0 );
+
+ JabberLog( "Status changed via THREADSTART" );
+ modeMsgStatusChangePending = FALSE;
+ JabberSetServerStatus( jabberDesiredStatus );
+
+ if ( JGetByte( "AutoJoinConferences", 0 )) {
+ for ( int i=0; i < chatRooms.realCount; i++ )
+ sttGroupchatJoinByHContact(( HANDLE )chatRooms.items[i] );
+ }
+ li.List_Destroy( &chatRooms );
+
+ if ( hwndJabberAgents )
+ SendMessage( hwndJabberAgents, WM_JABBER_TRANSPORT_REFRESH, 0, 0 );
+ if ( hwndJabberVcard )
+ SendMessage( hwndJabberVcard, WM_JABBER_CHECK_ONLINE, 0, 0 );
+}
+
+void JabberIqResultGetAgents( XmlNode *iqNode, void *userdata )
+{
+ ThreadData* info = ( ThreadData* ) userdata;
+ XmlNode *queryNode;
+ TCHAR* type, *jid, *str;
+
+ // RECVED: agent list
+ // ACTION: refresh agent list dialog
+ JabberLog( "<iq/> iqIdGetAgents" );
+ if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+ if (( queryNode=JabberXmlGetChild( iqNode, "query" )) == NULL ) return;
+
+ if ( !lstrcmp( type, _T("result"))) {
+ str = JabberXmlGetAttrValue( queryNode, "xmlns" );
+ if ( str!=NULL && !lstrcmp( str, _T("jabber:iq:agents"))) {
+ XmlNode *agentNode, *n;
+ JABBER_LIST_ITEM *item;
+ int i;
+
+ JabberListRemoveList( LIST_AGENT );
+ for ( i=0; i<queryNode->numChild; i++ ) {
+ agentNode = queryNode->child[i];
+ if ( !lstrcmpA( agentNode->name, "agent" )) {
+ if (( jid=JabberXmlGetAttrValue( agentNode, "jid" )) != NULL ) {
+ item = JabberListAdd( LIST_AGENT, jid );
+ if ( JabberXmlGetChild( agentNode, "register" ) != NULL )
+ item->cap |= AGENT_CAP_REGISTER;
+ if ( JabberXmlGetChild( agentNode, "search" ) != NULL )
+ item->cap |= AGENT_CAP_SEARCH;
+ if ( JabberXmlGetChild( agentNode, "groupchat" ) != NULL )
+ item->cap |= AGENT_CAP_GROUPCHAT;
+ // set service also???
+ // most chatroom servers don't announce <grouchat/> so we will
+ // also treat <service>public</service> as groupchat services
+ if (( n=JabberXmlGetChild( agentNode, "service" ))!=NULL && n->text!=NULL && !_tcscmp( n->text, _T("public")))
+ item->cap |= AGENT_CAP_GROUPCHAT;
+ if (( n=JabberXmlGetChild( agentNode, "name" ))!=NULL && n->text!=NULL )
+ item->name = mir_tstrdup( n->text );
+ } } } }
+
+ if ( hwndJabberAgents != NULL ) {
+ if (( jid = JabberXmlGetAttrValue( iqNode, "from" )) != NULL )
+ SendMessage( hwndJabberAgents, WM_JABBER_AGENT_REFRESH, 0, ( LPARAM )jid );
+ else
+ SendMessage( hwndJabberAgents, WM_JABBER_AGENT_REFRESH, 0, ( LPARAM )info->server );
+} } }
+
+void JabberIqResultGetRegister( XmlNode *iqNode, void *userdata )
+{
+ // RECVED: result of the request for ( agent ) registration mechanism
+ // ACTION: activate ( agent ) registration input dialog
+ JabberLog( "<iq/> iqIdGetRegister" );
+
+ ThreadData* info = ( ThreadData* ) userdata;
+ XmlNode *queryNode, *n;
+ TCHAR *type;
+ if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+ if (( queryNode=JabberXmlGetChild( iqNode, "query" )) == NULL ) return;
+
+ if ( !lstrcmp( type, _T("result"))) {
+ if ( hwndAgentRegInput )
+ if (( n = JabberXmlCopyNode( iqNode )) != NULL )
+ SendMessage( hwndAgentRegInput, WM_JABBER_REGINPUT_ACTIVATE, 1 /*success*/, ( LPARAM )n );
+ }
+ else if ( !lstrcmp( type, _T("error"))) {
+ if ( hwndAgentRegInput ) {
+ XmlNode *errorNode = JabberXmlGetChild( iqNode, "error" );
+ TCHAR* str = JabberErrorMsg( errorNode );
+ SendMessage( hwndAgentRegInput, WM_JABBER_REGINPUT_ACTIVATE, 0 /*error*/, ( LPARAM )str );
+ mir_free( str );
+} } }
+
+void JabberIqResultSetRegister( XmlNode *iqNode, void *userdata )
+{
+ // RECVED: result of registration process
+ // ACTION: notify of successful agent registration
+ JabberLog( "<iq/> iqIdSetRegister" );
+
+ TCHAR *type;
+ if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+
+ if ( !lstrcmp( type, _T("result"))) {
+ if ( hwndRegProgress )
+ SendMessage( hwndRegProgress, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )TranslateT( "Registration successful" ));
+ }
+ else if ( !lstrcmp( type, _T("error"))) {
+ if ( hwndRegProgress ) {
+ XmlNode *errorNode = JabberXmlGetChild( iqNode, "error" );
+ TCHAR* str = JabberErrorMsg( errorNode );
+ SendMessage( hwndRegProgress, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )str );
+ mir_free( str );
+} } }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberIqResultGetVcard - processes the server-side v-card
+
+static void JabberIqResultGetVcardPhoto( const TCHAR* jid, XmlNode* n, HANDLE hContact, BOOL& hasPhoto )
+{
+ if ( hasPhoto ) return;
+
+ XmlNode* o = JabberXmlGetChild( n, "BINVAL" );
+ if ( o == NULL || o->text == NULL ) return;
+
+ int bufferLen;
+ char* buffer = JabberBase64Decode( o->text, &bufferLen );
+ if ( buffer == NULL ) return;
+
+ XmlNode* m = JabberXmlGetChild( n, "TYPE" );
+ if ( m == NULL || m->text == NULL ) {
+LBL_NoTypeSpecified:
+ char* szPicType;
+
+ switch( JabberGetPictureType( buffer )) {
+ case PA_FORMAT_GIF: szPicType = "image/gif"; break;
+ case PA_FORMAT_BMP: szPicType = "image/bmp"; break;
+ case PA_FORMAT_PNG: szPicType = "image/png"; break;
+ case PA_FORMAT_JPEG: szPicType = "image/jpeg"; break;
+ default:
+ goto LBL_Ret;
+ }
+
+ replaceStr( jabberVcardPhotoType, szPicType );
+ }
+ else {
+ if ( _tcscmp( m->text, _T("image/jpeg")) && _tcscmp( m->text, _T("image/png")) && _tcscmp( m->text, _T("image/gif")) && _tcscmp( m->text, _T("image/bmp")))
+ goto LBL_NoTypeSpecified;
+
+ if ( jabberVcardPhotoType ) mir_free(jabberVcardPhotoType);
+ jabberVcardPhotoType = t2a( m->text );
+ }
+
+ DWORD nWritten;
+ char szTempPath[MAX_PATH], szTempFileName[MAX_PATH];
+ JABBER_LIST_ITEM *item;
+ DBVARIANT dbv;
+
+ if ( GetTempPathA( sizeof( szTempPath ), szTempPath ) <= 0 )
+ lstrcpyA( szTempPath, ".\\" );
+ if ( !GetTempFileNameA( szTempPath, jabberProtoName, GetTickCount(), szTempFileName )) {
+LBL_Ret:
+ mir_free( buffer );
+ return;
+ }
+
+ { char* p = strrchr( szTempFileName, '.' );
+ if ( p != NULL )
+ lstrcpyA( p+1, jabberVcardPhotoType + 6 );
+ }
+
+ JabberLog( "Picture file name set to %s", szTempFileName );
+ HANDLE hFile = CreateFileA( szTempFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
+ if ( hFile == INVALID_HANDLE_VALUE )
+ goto LBL_Ret;
+
+ JabberLog( "Writing %d bytes", bufferLen );
+ if ( !WriteFile( hFile, buffer, bufferLen, &nWritten, NULL ))
+ goto LBL_Ret;
+
+ JabberLog( "%d bytes written", nWritten );
+ if ( hContact == NULL ) {
+ hasPhoto = TRUE;
+ if ( jabberVcardPhotoFileName ) {
+ DeleteFileA( jabberVcardPhotoFileName );
+ mir_free( jabberVcardPhotoFileName );
+ jabberVcardPhotoFileName = NULL;
+ }
+ replaceStr( jabberVcardPhotoFileName, szTempFileName );
+ JabberLog( "My picture saved to %s", szTempFileName );
+ }
+ else if ( !JGetStringT( hContact, "jid", &dbv )) {
+ if (( item = JabberListGetItemPtr( LIST_ROSTER, jid )) != NULL ) {
+ hasPhoto = TRUE;
+ if ( item->photoFileName )
+ DeleteFileA( item->photoFileName );
+ replaceStr( item->photoFileName, szTempFileName );
+ JabberLog( "Contact's picture saved to %s", szTempFileName );
+ }
+ JFreeVariant( &dbv );
+ }
+
+ CloseHandle( hFile );
+
+ if ( !hasPhoto )
+ DeleteFileA( szTempFileName );
+
+ goto LBL_Ret;
+}
+
+void JabberIqResultGetVcard( XmlNode *iqNode, void *userdata )
+{
+ XmlNode *vCardNode, *m, *n, *o;
+ TCHAR* type, *jid;
+ HANDLE hContact;
+ TCHAR text[128];
+ int len;
+ DBVARIANT dbv;
+
+ JabberLog( "<iq/> iqIdGetVcard" );
+ if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+ if (( jid=JabberXmlGetAttrValue( iqNode, "from" )) == NULL ) return;
+
+ len = _tcslen( jabberJID );
+ if ( !_tcsnicmp( jid, jabberJID, len ) && ( jid[len]=='/' || jid[len]=='\0' )) {
+ hContact = NULL;
+ JabberLog( "Vcard for myself" );
+ }
+ else {
+ if (( hContact = JabberHContactFromJID( jid )) == NULL )
+ return;
+ JabberLog( "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=JabberXmlGetChild( iqNode, "vCard" )) != NULL ) {
+ for ( int i=0; i<vCardNode->numChild; i++ ) {
+ n = vCardNode->child[i];
+ if ( n==NULL || n->name==NULL ) continue;
+ if ( !strcmp( n->name, "FN" )) {
+ if ( n->text != NULL ) {
+ hasFn = TRUE;
+ JSetStringT( hContact, "FullName", n->text );
+ }
+ }
+ else if ( !strcmp( n->name, "NICKNAME" )) {
+ if ( n->text != NULL ) {
+ hasNick = TRUE;
+ JSetStringT( hContact, "Nick", n->text );
+ }
+ }
+ else if ( !strcmp( n->name, "N" )) {
+ // First/Last name
+ if ( !hasGiven && !hasFamily && !hasMiddle ) {
+ if (( m=JabberXmlGetChild( n, "GIVEN" )) != NULL && m->text!=NULL ) {
+ hasGiven = TRUE;
+ JSetStringT( hContact, "FirstName", m->text );
+ }
+ if (( m=JabberXmlGetChild( n, "FAMILY" )) != NULL && m->text!=NULL ) {
+ hasFamily = TRUE;
+ JSetStringT( hContact, "LastName", m->text );
+ }
+ if (( m=JabberXmlGetChild( n, "MIDDLE" )) != NULL && m->text != NULL ) {
+ hasMiddle = TRUE;
+ JSetStringT( hContact, "MiddleName", m->text );
+ } }
+ }
+ else if ( !strcmp( n->name, "EMAIL" )) {
+ // E-mail address( es )
+ if (( m=JabberXmlGetChild( n, "USERID" )) == NULL ) // Some bad client put e-mail directly in <EMAIL/> instead of <USERID/>
+ m = n;
+ if ( m->text != 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, m->text );
+
+ if ( hContact == NULL ) {
+ sprintf( text, "e-mailFlag%d", nEmail );
+ int nFlag = 0;
+ if ( JabberXmlGetChild( n, "HOME" ) != NULL ) nFlag |= JABBER_VCEMAIL_HOME;
+ if ( JabberXmlGetChild( n, "WORK" ) != NULL ) nFlag |= JABBER_VCEMAIL_WORK;
+ if ( JabberXmlGetChild( n, "INTERNET" ) != NULL ) nFlag |= JABBER_VCEMAIL_INTERNET;
+ if ( JabberXmlGetChild( n, "X400" ) != NULL ) nFlag |= JABBER_VCEMAIL_X400;
+ JSetWord( NULL, text, nFlag );
+ }
+ nEmail++;
+ }
+ }
+ else if ( !strcmp( n->name, "BDAY" )) {
+ // Birthday
+ if ( !hasBday && n->text!=NULL ) {
+ if ( hContact != NULL ) {
+ if ( _stscanf( n->text, _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 );
+ }
+ }
+ else {
+ hasBday = TRUE;
+ JSetStringT( NULL, "BirthDate", n->text );
+ } }
+ }
+ else if ( !lstrcmpA( n->name, "GENDER" )) {
+ // Gender
+ if ( !hasGender && n->text!=NULL ) {
+ if ( hContact != NULL ) {
+ if ( n->text[0] && strchr( "mMfF", n->text[0] )!=NULL ) {
+ hasGender = TRUE;
+ JSetByte( hContact, "Gender", ( BYTE ) toupper( n->text[0] ));
+ }
+ }
+ else {
+ hasGender = TRUE;
+ JSetStringT( NULL, "GenderString", n->text );
+ } }
+ }
+ else if ( !strcmp( n->name, "ADR" )) {
+ if ( !hasHome && JabberXmlGetChild( n, "HOME" )!=NULL ) {
+ // Home address
+ hasHome = TRUE;
+ if (( m=JabberXmlGetChild( n, "STREET" )) != NULL && m->text != NULL ) {
+ hasHomeStreet = TRUE;
+ if ( hContact != NULL ) {
+ if (( o=JabberXmlGetChild( n, "EXTADR" )) != NULL && o->text != NULL )
+ mir_sntprintf( text, SIZEOF( text ), _T("%s\r\n%s"), m->text, o->text );
+ else if (( o=JabberXmlGetChild( n, "EXTADD" ))!=NULL && o->text!=NULL )
+ mir_sntprintf( text, SIZEOF( text ), _T("%s\r\n%s"), m->text, o->text );
+ else
+ _tcsncpy( text, m->text, SIZEOF( text ));
+ text[sizeof( text )-1] = '\0';
+ JSetStringT( hContact, "Street", text );
+ }
+ else {
+ JSetStringT( hContact, "Street", m->text );
+ if (( m=JabberXmlGetChild( n, "EXTADR" )) == NULL )
+ m = JabberXmlGetChild( n, "EXTADD" );
+ if ( m!=NULL && m->text!=NULL ) {
+ hasHomeStreet2 = TRUE;
+ JSetStringT( hContact, "Street2", m->text );
+ } } }
+
+ if (( m=JabberXmlGetChild( n, "LOCALITY" ))!=NULL && m->text!=NULL ) {
+ hasHomeLocality = TRUE;
+ JSetStringT( hContact, "City", m->text );
+ }
+ if (( m=JabberXmlGetChild( n, "REGION" ))!=NULL && m->text!=NULL ) {
+ hasHomeRegion = TRUE;
+ JSetStringT( hContact, "State", m->text );
+ }
+ if (( m=JabberXmlGetChild( n, "PCODE" ))!=NULL && m->text!=NULL ) {
+ hasHomePcode = TRUE;
+ JSetStringT( hContact, "ZIP", m->text );
+ }
+ if (( m=JabberXmlGetChild( n, "CTRY" ))==NULL || m->text==NULL ) // Some bad client use <COUNTRY/> instead of <CTRY/>
+ m = JabberXmlGetChild( n, "COUNTRY" );
+ if ( m!=NULL && m->text!=NULL ) {
+ hasHomeCtry = TRUE;
+ if ( hContact != NULL )
+ JSetWord( hContact, "Country", ( WORD )JabberCountryNameToId( m->text ));
+ else
+ JSetStringT( hContact, "CountryName", m->text );
+ } }
+
+ if ( !hasWork && JabberXmlGetChild( n, "WORK" )!=NULL ) {
+ // Work address
+ hasWork = TRUE;
+ if (( m=JabberXmlGetChild( n, "STREET" ))!=NULL && m->text!=NULL ) {
+ hasWorkStreet = TRUE;
+ if ( hContact != NULL ) {
+ if (( o=JabberXmlGetChild( n, "EXTADR" ))!=NULL && o->text!=NULL )
+ mir_sntprintf( text, SIZEOF( text ), _T("%s\r\n%s"), m->text, o->text );
+ else if (( o=JabberXmlGetChild( n, "EXTADD" ))!=NULL && o->text!=NULL )
+ mir_sntprintf( text, SIZEOF( text ), _T("%s\r\n%s"), m->text, o->text );
+ else
+ _tcsncpy( text, m->text, SIZEOF( text ));
+ text[sizeof( text )-1] = '\0';
+ JSetStringT( hContact, "CompanyStreet", text );
+ }
+ else {
+ JSetStringT( hContact, "CompanyStreet", m->text );
+ if (( m=JabberXmlGetChild( n, "EXTADR" )) == NULL )
+ m = JabberXmlGetChild( n, "EXTADD" );
+ if ( m!=NULL && m->text!=NULL ) {
+ hasWorkStreet2 = TRUE;
+ JSetStringT( hContact, "CompanyStreet2", m->text );
+ } } }
+
+ if (( m=JabberXmlGetChild( n, "LOCALITY" ))!=NULL && m->text!=NULL ) {
+ hasWorkLocality = TRUE;
+ JSetStringT( hContact, "CompanyCity", m->text );
+ }
+ if (( m=JabberXmlGetChild( n, "REGION" ))!=NULL && m->text!=NULL ) {
+ hasWorkRegion = TRUE;
+ JSetStringT( hContact, "CompanyState", m->text );
+ }
+ if (( m=JabberXmlGetChild( n, "PCODE" ))!=NULL && m->text!=NULL ) {
+ hasWorkPcode = TRUE;
+ JSetStringT( hContact, "CompanyZIP", m->text );
+ }
+ if (( m=JabberXmlGetChild( n, "CTRY" ))==NULL || m->text==NULL ) // Some bad client use <COUNTRY/> instead of <CTRY/>
+ m = JabberXmlGetChild( n, "COUNTRY" );
+ if ( m!=NULL && m->text!=NULL ) {
+ hasWorkCtry = TRUE;
+ if ( hContact != NULL )
+ JSetWord( hContact, "CompanyCountry", ( WORD )JabberCountryNameToId( m->text ));
+ else
+ JSetStringT( hContact, "CompanyCountryName", m->text );
+ } }
+ }
+ else if ( !strcmp( n->name, "TEL" )) {
+ // Telephone/Fax/Cellular
+ if (( m=JabberXmlGetChild( n, "NUMBER" ))!=NULL && m->text!=NULL ) {
+ if ( hContact != NULL ) {
+ if ( !hasFax && JabberXmlGetChild( n, "FAX" )!=NULL ) {
+ hasFax = TRUE;
+ JSetStringT( hContact, "Fax", m->text );
+ }
+ if ( !hasCell && JabberXmlGetChild( n, "CELL" )!=NULL ) {
+ hasCell = TRUE;
+ JSetStringT( hContact, "Cellular", m->text );
+ }
+ if ( !hasPhone &&
+ ( JabberXmlGetChild( n, "HOME" )!=NULL ||
+ JabberXmlGetChild( n, "WORK" )!=NULL ||
+ JabberXmlGetChild( n, "VOICE" )!=NULL ||
+ ( JabberXmlGetChild( n, "FAX" )==NULL &&
+ JabberXmlGetChild( n, "PAGER" )==NULL &&
+ JabberXmlGetChild( n, "MSG" )==NULL &&
+ JabberXmlGetChild( n, "CELL" )==NULL &&
+ JabberXmlGetChild( n, "VIDEO" )==NULL &&
+ JabberXmlGetChild( n, "BBS" )==NULL &&
+ JabberXmlGetChild( n, "MODEM" )==NULL &&
+ JabberXmlGetChild( n, "ISDN" )==NULL &&
+ JabberXmlGetChild( n, "PCS" )==NULL )) ) {
+ hasPhone = TRUE;
+ JSetStringT( hContact, "Phone", m->text );
+ }
+ }
+ else {
+ char text[ 100 ];
+ sprintf( text, "Phone%d", nPhone );
+ JSetStringT( NULL, text, m->text );
+
+ sprintf( text, "PhoneFlag%d", nPhone );
+ int nFlag = 0;
+ if ( JabberXmlGetChild( n, "HOME" ) != NULL ) nFlag |= JABBER_VCTEL_HOME;
+ if ( JabberXmlGetChild( n, "WORK" ) != NULL ) nFlag |= JABBER_VCTEL_WORK;
+ if ( JabberXmlGetChild( n, "VOICE" ) != NULL ) nFlag |= JABBER_VCTEL_VOICE;
+ if ( JabberXmlGetChild( n, "FAX" ) != NULL ) nFlag |= JABBER_VCTEL_FAX;
+ if ( JabberXmlGetChild( n, "PAGER" ) != NULL ) nFlag |= JABBER_VCTEL_PAGER;
+ if ( JabberXmlGetChild( n, "MSG" ) != NULL ) nFlag |= JABBER_VCTEL_MSG;
+ if ( JabberXmlGetChild( n, "CELL" ) != NULL ) nFlag |= JABBER_VCTEL_CELL;
+ if ( JabberXmlGetChild( n, "VIDEO" ) != NULL ) nFlag |= JABBER_VCTEL_VIDEO;
+ if ( JabberXmlGetChild( n, "BBS" ) != NULL ) nFlag |= JABBER_VCTEL_BBS;
+ if ( JabberXmlGetChild( n, "MODEM" ) != NULL ) nFlag |= JABBER_VCTEL_MODEM;
+ if ( JabberXmlGetChild( n, "ISDN" ) != NULL ) nFlag |= JABBER_VCTEL_ISDN;
+ if ( JabberXmlGetChild( n, "PCS" ) != NULL ) nFlag |= JABBER_VCTEL_PCS;
+ JSetWord( NULL, text, nFlag );
+ nPhone++;
+ } }
+ }
+ else if ( !strcmp( n->name, "URL" )) {
+ // Homepage
+ if ( !hasUrl && n->text!=NULL ) {
+ hasUrl = TRUE;
+ JSetStringT( hContact, "Homepage", n->text );
+ }
+ }
+ else if ( !strcmp( n->name, "ORG" )) {
+ if ( !hasOrgname && !hasOrgunit ) {
+ if (( m=JabberXmlGetChild( n, "ORGNAME" ))!=NULL && m->text!=NULL ) {
+ hasOrgname = TRUE;
+ JSetStringT( hContact, "Company", m->text );
+ }
+ if (( m=JabberXmlGetChild( n, "ORGUNIT" ))!=NULL && m->text!=NULL ) { // The real vCard can have multiple <ORGUNIT/> but we will only display the first one
+ hasOrgunit = TRUE;
+ JSetStringT( hContact, "CompanyDepartment", m->text );
+ } }
+ }
+ else if ( !strcmp( n->name, "ROLE" )) {
+ if ( !hasRole && n->text!=NULL ) {
+ hasRole = TRUE;
+ JSetStringT( hContact, "Role", n->text );
+ }
+ }
+ else if ( !strcmp( n->name, "TITLE" )) {
+ if ( !hasTitle && n->text!=NULL ) {
+ hasTitle = TRUE;
+ JSetStringT( hContact, "CompanyPosition", n->text );
+ }
+ }
+ else if ( !strcmp( n->name, "DESC" )) {
+ if ( !hasDesc && n->text!=NULL ) {
+ hasDesc = TRUE;
+ TCHAR* szMemo = JabberUnixToDosT( n->text );
+ JSetStringT( hContact, "About", szMemo );
+ mir_free( szMemo );
+ }
+ }
+ else if ( !strcmp( n->name, "PHOTO" ))
+ JabberIqResultGetVcardPhoto( jid, n, hContact, hasPhoto );
+ } }
+
+ 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 ( DBGetContactSetting( hContact, jabberProtoName, text, &dbv )) break;
+ JFreeVariant( &dbv );
+ JDeleteSetting( hContact, text );
+ }
+ nEmail++;
+ }
+ }
+ else {
+ while ( true ) {
+ char text[ 100 ];
+ sprintf( text, "e-mail%d", nEmail );
+ if ( DBGetContactSetting( NULL, jabberProtoName, 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" );
+ }
+ 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 ( DBGetContactSetting( NULL, jabberProtoName, 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 ) {
+ if ( hContact != NULL )
+ JDeleteSetting( hContact, "Country" );
+ else
+ JDeleteSetting( hContact, "CountryName" );
+ }
+ 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 ) {
+ if ( hContact != NULL )
+ JDeleteSetting( hContact, "CompanyCountry" );
+ else
+ JDeleteSetting( hContact, "CompanyCountryName" );
+ }
+ 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 ( !hasPhoto && jabberVcardPhotoFileName!=NULL ) {
+ DeleteFileA( jabberVcardPhotoFileName );
+ jabberVcardPhotoFileName = NULL;
+ }
+
+ if ( hContact != NULL )
+ JSendBroadcast( hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, ( HANDLE ) 1, 0 );
+ else if ( hwndJabberVcard )
+ SendMessage( hwndJabberVcard, WM_JABBER_REFRESH, 0, 0 );
+ }
+ else if ( !lstrcmp( type, _T("error"))) {
+ if ( hContact != NULL )
+ JSendBroadcast( hContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, ( HANDLE ) 1, 0 );
+} }
+
+void JabberIqResultSetVcard( XmlNode *iqNode, void *userdata )
+{
+ JabberLog( "<iq/> iqIdSetVcard" );
+ TCHAR* type = JabberXmlGetAttrValue( iqNode, "type" );
+ if ( type == NULL )
+ return;
+
+ if ( hwndJabberVcard )
+ SendMessage( hwndJabberVcard, WM_JABBER_REFRESH, 0, 0 );
+}
+
+void JabberIqResultSetSearch( XmlNode *iqNode, void *userdata )
+{
+ XmlNode *queryNode, *itemNode, *n;
+ TCHAR* type, *jid, *str;
+ int id, i;
+ JABBER_SEARCH_RESULT jsr;
+
+ JabberLog( "<iq/> iqIdGetSearch" );
+ if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+ if (( str=JabberXmlGetAttrValue( iqNode, "id" )) == NULL ) return;
+ id = _ttoi( str+strlen( JABBER_IQID ));
+
+ if ( !lstrcmp( type, _T("result"))) {
+ if (( queryNode=JabberXmlGetChild( iqNode, "query" )) == NULL ) return;
+ jsr.hdr.cbSize = sizeof( JABBER_SEARCH_RESULT );
+ for ( i=0; i<queryNode->numChild; i++ ) {
+ itemNode = queryNode->child[i];
+ if ( !lstrcmpA( itemNode->name, "item" )) {
+ if (( jid=JabberXmlGetAttrValue( itemNode, "jid" )) != NULL ) {
+ _tcsncpy( jsr.jid, jid, SIZEOF( jsr.jid ));
+ jsr.jid[ SIZEOF( jsr.jid )-1] = '\0';
+ JabberLog( "Result jid = " TCHAR_STR_PARAM, jid );
+ if (( n=JabberXmlGetChild( itemNode, "nick" ))!=NULL && n->text!=NULL )
+ jsr.hdr.nick = t2a( n->text );
+ else
+ jsr.hdr.nick = mir_strdup( "" );
+ if (( n=JabberXmlGetChild( itemNode, "first" ))!=NULL && n->text!=NULL )
+ jsr.hdr.firstName = t2a( n->text );
+ else
+ jsr.hdr.firstName = mir_strdup( "" );
+ if (( n=JabberXmlGetChild( itemNode, "last" ))!=NULL && n->text!=NULL )
+ jsr.hdr.lastName = t2a( n->text );
+ else
+ jsr.hdr.lastName = mir_strdup( "" );
+ if (( n=JabberXmlGetChild( itemNode, "email" ))!=NULL && n->text!=NULL )
+ jsr.hdr.email = t2a( n->text );
+ else
+ jsr.hdr.email = mir_strdup( "" );
+ JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, ( HANDLE ) id, ( LPARAM )&jsr );
+ mir_free( jsr.hdr.nick );
+ mir_free( jsr.hdr.firstName );
+ mir_free( jsr.hdr.lastName );
+ mir_free( jsr.hdr.email );
+ } } }
+
+ 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 JabberIqResultExtSearch( XmlNode *iqNode, void *userdata )
+{
+ XmlNode *queryNode;
+ TCHAR* type, *str;
+
+ JabberLog( "<iq/> iqIdGetExtSearch" );
+ if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+ if (( str=JabberXmlGetAttrValue( iqNode, "id" )) == NULL ) return;
+ int id = _ttoi( str+strlen( JABBER_IQID ));
+
+ if ( !lstrcmp( type, _T("result"))) {
+ if (( queryNode=JabberXmlGetChild( iqNode, "query" )) == NULL ) return;
+ if (( queryNode=JabberXmlGetChild( queryNode, "x" )) == NULL ) return;
+ for ( int i=0; i<queryNode->numChild; i++ ) {
+ XmlNode* itemNode = queryNode->child[i];
+ if ( strcmp( itemNode->name, "item" ))
+ continue;
+
+ JABBER_SEARCH_RESULT jsr = { 0 };
+ jsr.hdr.cbSize = sizeof( JABBER_SEARCH_RESULT );
+// jsr.hdr.firstName = "";
+
+ for ( int j=0; j < itemNode->numChild; j++ ) {
+ XmlNode* fieldNode = itemNode->child[j];
+ if ( strcmp( fieldNode->name, "field" ))
+ continue;
+
+ TCHAR* fieldName = JabberXmlGetAttrValue( fieldNode, "var" );
+ if ( fieldName == NULL )
+ continue;
+
+ XmlNode* n = JabberXmlGetChild( fieldNode, "value" );
+ if ( n == NULL )
+ continue;
+
+ if ( !lstrcmp( fieldName, _T("jid"))) {
+ _tcsncpy( jsr.jid, n->text, SIZEOF( jsr.jid ));
+ jsr.jid[sizeof( jsr.jid )-1] = '\0';
+ JabberLog( "Result jid = " TCHAR_STR_PARAM, jsr.jid );
+ }
+ else if ( !lstrcmp( fieldName, _T("nickname")))
+ jsr.hdr.nick = ( n->text != NULL ) ? t2a( n->text ) : mir_strdup( "" );
+ else if ( !lstrcmp( fieldName, _T("fn"))) {
+ mir_free( jsr.hdr.firstName );
+ jsr.hdr.firstName = ( n->text != NULL ) ? t2a(n->text) : mir_strdup( "" );
+ }
+ else if ( !lstrcmp( fieldName, _T("given"))) {
+ mir_free( jsr.hdr.firstName );
+ jsr.hdr.firstName = ( n->text != NULL ) ? t2a(n->text) : mir_strdup( "" );
+ }
+ else if ( !lstrcmp( fieldName, _T("family")))
+ jsr.hdr.lastName = ( n->text != NULL ) ? t2a(n->text) : mir_strdup( "" );
+ else if ( !lstrcmp( fieldName, _T("email")))
+ jsr.hdr.email = ( n->text != NULL ) ? t2a(n->text) : mir_strdup( "" );
+ }
+
+ JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, ( HANDLE ) id, ( LPARAM )&jsr );
+ mir_free( jsr.hdr.nick );
+ mir_free( jsr.hdr.firstName );
+ mir_free( jsr.hdr.lastName );
+ mir_free( jsr.hdr.email );
+ }
+
+ 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 JabberIqResultSetPassword( XmlNode *iqNode, void *userdata )
+{
+ JabberLog( "<iq/> iqIdSetPassword" );
+
+ TCHAR* type = JabberXmlGetAttrValue( iqNode, "type" );
+ if ( type == NULL )
+ return;
+
+ if ( !lstrcmp( type, _T("result"))) {
+ strncpy( jabberThreadInfo->password, jabberThreadInfo->newPassword, SIZEOF( jabberThreadInfo->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 JabberIqResultDiscoAgentItems( XmlNode *iqNode, void *userdata )
+{
+ ThreadData* info = ( ThreadData* ) userdata;
+ XmlNode *queryNode, *itemNode;
+ TCHAR* type, *jid, *from;
+
+ // RECVED: agent list
+ // ACTION: refresh agent list dialog
+ JabberLog( "<iq/> iqIdDiscoAgentItems" );
+ if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+ if (( from=JabberXmlGetAttrValue( iqNode, "from" )) == NULL ) return;
+
+ if ( !lstrcmp( type, _T("result"))) {
+ if (( queryNode=JabberXmlGetChild( iqNode, "query" )) != NULL ) {
+ TCHAR* str = JabberXmlGetAttrValue( queryNode, "xmlns" );
+ if ( !lstrcmp( str, _T("http://jabber.org/protocol/disco#items"))) {
+ JabberListRemoveList( LIST_AGENT );
+ for ( int i=0; i<queryNode->numChild; i++ ) {
+ if (( itemNode=queryNode->child[i] )!=NULL && itemNode->name!=NULL && !lstrcmpA( itemNode->name, "item" )) {
+ if (( jid=JabberXmlGetAttrValue( itemNode, "jid" )) != NULL ) {
+ JABBER_LIST_ITEM* item = JabberListAdd( LIST_AGENT, jid );
+ replaceStr( item->name, JabberXmlGetAttrValue( itemNode, "name" ));
+ item->cap = AGENT_CAP_REGISTER | AGENT_CAP_GROUPCHAT; // default to all cap until specific info is later received
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultDiscoAgentInfo );
+
+ XmlNodeIq iq( "get", iqId, jid );
+ XmlNode* query = iq.addQuery( "http://jabber.org/protocol/disco#info" );
+ JabberSend( jabberThreadInfo->s, iq );
+ } } } } }
+
+ if ( hwndJabberAgents != NULL ) {
+ if (( jid=JabberXmlGetAttrValue( iqNode, "from" )) != NULL )
+ SendMessage( hwndJabberAgents, WM_JABBER_AGENT_REFRESH, 0, ( LPARAM )jid );
+ else
+ SendMessage( hwndJabberAgents, WM_JABBER_AGENT_REFRESH, 0, ( LPARAM )info->server );
+ }
+ }
+ else if ( !lstrcmp( type, _T("error"))) {
+ // disco is not supported, try jabber:iq:agents
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_GETAGENTS, JabberIqResultGetAgents );
+
+ XmlNodeIq iq( "get", iqId, from );
+ XmlNode* query = iq.addQuery( "jabber:iq:agents" );
+ JabberSend( jabberThreadInfo->s, iq );
+} }
+
+void JabberIqResultDiscoAgentInfo( XmlNode *iqNode, void *userdata )
+{
+ ThreadData* info = ( ThreadData* ) userdata;
+ XmlNode *queryNode, *itemNode, *identityNode;
+ TCHAR* type, *from, *var;
+ JABBER_LIST_ITEM *item;
+
+ // RECVED: info for a specific agent
+ // ACTION: refresh agent list dialog
+ JabberLog( "<iq/> iqIdDiscoAgentInfo" );
+ if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+ if (( from = JabberXmlGetAttrValue( iqNode, "from" )) == NULL ) return;
+
+ if ( !lstrcmp( type, _T("result"))) {
+ if (( queryNode=JabberXmlGetChild( iqNode, "query" )) != NULL ) {
+ TCHAR* str = JabberXmlGetAttrValue( queryNode, "xmlns" );
+ if ( !lstrcmp( str, _T("http://jabber.org/protocol/disco#info"))) {
+ if (( item=JabberListGetItemPtr( LIST_AGENT, from )) != NULL ) {
+ // Use the first <identity/> to set name
+ if (( identityNode=JabberXmlGetChild( queryNode, "identity" )) != NULL ) {
+ if (( str=JabberXmlGetAttrValue( identityNode, "name" )) != NULL )
+ replaceStr( item->name, str );
+ }
+
+ item->cap = 0;
+ for ( int i=0; i<queryNode->numChild; i++ ) {
+ if (( itemNode=queryNode->child[i] )!=NULL && itemNode->name!=NULL ) {
+ if ( !strcmp( itemNode->name, "feature" )) {
+ if (( var=JabberXmlGetAttrValue( itemNode, "var" )) != NULL ) {
+ if ( !lstrcmp( var, _T("jabber:iq:register")))
+ item->cap |= AGENT_CAP_REGISTER;
+ else if ( !lstrcmp( var, _T("http://jabber.org/protocol/muc")))
+ item->cap |= AGENT_CAP_GROUPCHAT;
+ } } } } } } }
+
+ if ( hwndJabberAgents != NULL )
+ SendMessage( hwndJabberAgents, WM_JABBER_AGENT_REFRESH, 0, ( LPARAM )NULL );
+} }
+
+void JabberIqResultDiscoClientInfo( XmlNode *iqNode, void *userdata )
+{
+ ThreadData* info = ( ThreadData* ) userdata;
+ XmlNode *queryNode, *itemNode;
+ TCHAR* type, *from, *var;
+ JABBER_LIST_ITEM *item;
+
+ // RECVED: info for a specific client
+ // ACTION: update client cap
+ // ACTION: if item->ft is pending, initiate file transfer
+ JabberLog( "<iq/> iqIdDiscoClientInfo" );
+ if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+ if (( from=JabberXmlGetAttrValue( iqNode, "from" )) == NULL ) return;
+
+ if ( lstrcmp( type, _T("result")) != 0 )
+ return;
+ if (( item=JabberListGetItemPtr( LIST_ROSTER, from )) == NULL )
+ return;
+
+ if (( queryNode=JabberXmlGetChild( iqNode, "query" )) != NULL ) {
+ TCHAR* str = JabberXmlGetAttrValue( queryNode, "xmlns" );
+ if ( !lstrcmp( str, _T("http://jabber.org/protocol/disco#info"))) {
+ item->cap = CLIENT_CAP_READY;
+ for ( int i=0; i<queryNode->numChild; i++ ) {
+ if (( itemNode=queryNode->child[i] )!=NULL && itemNode->name!=NULL ) {
+ if ( !strcmp( itemNode->name, "feature" )) {
+ if (( var=JabberXmlGetAttrValue( itemNode, "var" )) != NULL ) {
+ if ( !lstrcmp( var, _T("http://jabber.org/protocol/si")))
+ item->cap |= CLIENT_CAP_SI;
+ else if ( !lstrcmp( var, _T("http://jabber.org/protocol/si/profile/file-transfer")))
+ item->cap |= CLIENT_CAP_SIFILE;
+ else if ( !lstrcmp( var, _T("http://jabber.org/protocol/bytestreams")))
+ item->cap |= CLIENT_CAP_BYTESTREAM;
+ } } } } } }
+
+ // Check for pending file transfer session request
+ if ( item->ft != NULL ) {
+ filetransfer* ft = item->ft;
+ item->ft = NULL;
+ if (( item->cap & CLIENT_CAP_FILE ) && ( item->cap & CLIENT_CAP_BYTESTREAM ))
+ JabberFtInitiate( item->jid, ft );
+ else
+ JabberForkThread(( JABBER_THREAD_FUNC )JabberFileServerThread, 0, ft );
+} }
+
+void JabberIqResultGetAvatar( XmlNode *iqNode, void *userdata )
+{
+ if ( !JGetByte( "EnableAvatars", TRUE ))
+ return;
+
+ ThreadData* info = ( ThreadData* ) userdata;
+ TCHAR* type;
+
+ // RECVED: agent list
+ // ACTION: refresh agent list dialog
+ JabberLog( "<iq/> iqIdResultGetAvatar" );
+ if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+ if ( _tcscmp( type, _T("result"))) return;
+
+ TCHAR* from = JabberXmlGetAttrValue( iqNode, "from" );
+ if ( from == NULL )
+ return;
+ HANDLE hContact = JabberHContactFromJID( from );
+ if ( hContact == NULL )
+ return;
+ XmlNode* n = NULL;
+ TCHAR* mimeType = NULL;
+ if (JGetByte(hContact,"AvatarXVcard",0)){
+ XmlNode *vCard = JabberXmlGetChild( iqNode, "vCard" );
+ if (vCard == NULL) return;
+ vCard = JabberXmlGetChild( vCard, "PHOTO" );
+ if (vCard == NULL) return;
+ XmlNode *typeNode = JabberXmlGetChild( vCard, "TYPE" );
+ if (typeNode != NULL) mimeType = typeNode->text;
+ n = JabberXmlGetChild( vCard, "BINVAL" );
+ }else {
+ XmlNode *queryNode = JabberXmlGetChild( iqNode, "query" );
+ if ( queryNode == NULL )
+ return;
+
+ TCHAR* xmlns = JabberXmlGetAttrValue( queryNode, "xmlns" );
+ if ( lstrcmp( xmlns, _T("jabber:iq:avatar")))
+ return;
+
+ mimeType = JabberXmlGetAttrValue( n, "mimetype" );
+
+ n = JabberXmlGetChild( queryNode, "data" );
+ }
+ if ( n == NULL )
+ return;
+
+ int resultLen = 0;
+ char* body = JabberBase64Decode( n->text, &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:
+ JabberLog( "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;
+
+ PROTO_AVATAR_INFORMATION AI;
+ AI.cbSize = sizeof AI;
+ AI.format = pictureType;
+ AI.hContact = hContact;
+
+ if ( JGetByte( hContact, "AvatarType", PA_FORMAT_UNKNOWN ) != (unsigned char)pictureType ) {
+ JabberGetAvatarFileName( hContact, AI.filename, sizeof AI.filename );
+ DeleteFileA( AI.filename );
+ }
+
+ JSetByte( hContact, "AvatarType", pictureType );
+
+ char buffer[ 41 ];
+ uint8_t digest[20];
+ SHA1Context sha;
+ SHA1Reset( &sha );
+ SHA1Input( &sha, ( const unsigned __int8* )body, resultLen );
+ SHA1Result( &sha, digest );
+ for ( int i=0; i<20; i++ )
+ sprintf( buffer+( i<<1 ), "%02x", digest[i] );
+ JSetString( hContact, "AvatarSaved", buffer );
+
+ JabberGetAvatarFileName( hContact, AI.filename, sizeof AI.filename );
+
+ DBWriteContactSettingString( hContact, "ContactPhoto", "File", AI.filename );
+
+ FILE* out = fopen( AI.filename, "wb" );
+ if ( out != NULL ) {
+ fwrite( body, resultLen, 1, out );
+ fclose( out );
+ JSendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, HANDLE( &AI ), NULL );
+ JabberLog("Broadcast new avatar: %s",AI.filename);
+ }
+ else JSendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, HANDLE( &AI ), NULL );
+
+ mir_free( body );
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_iqid_muc.cpp b/miranda-wine/protocols/JabberG/jabber_iqid_muc.cpp
new file mode 100644
index 0000000..114931d
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_iqid_muc.cpp
@@ -0,0 +1,531 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_iqid_muc.cpp,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include "resource.h"
+#include "jabber_list.h"
+#include "jabber_iq.h"
+#include <commctrl.h>
+
+void JabberAddMucListItem( JABBER_MUC_JIDLIST_INFO* jidListInfo, TCHAR* str );
+void JabberDeleteMucListItem( JABBER_MUC_JIDLIST_INFO* jidListInfo, TCHAR* str );
+BOOL JabberEnterString( TCHAR* result, size_t resultLen );
+
+void JabberIqResultBrowseRooms( XmlNode *iqNode, void *userdata )
+{
+ struct ThreadData *info = ( struct ThreadData * ) userdata;
+ XmlNode *confNode, *roomNode;
+ TCHAR* type, *category, *jid, *str;
+ JABBER_LIST_ITEM *item;
+ int i, j;
+
+ // RECVED: room list
+ // ACTION: refresh groupchat room list dialog
+ JabberLog( "<iq/> iqIdBrowseRooms" );
+ if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+
+ if ( !lstrcmp( type, _T("result"))) {
+ JabberListRemoveList( LIST_ROOM );
+ for ( i=0; i<iqNode->numChild; i++ ) {
+ if (( confNode=iqNode->child[i] )!=NULL && confNode->name!=NULL ) {
+ if ( !strcmp( confNode->name, "item" )) {
+ if (( category=JabberXmlGetAttrValue( confNode, "category" ))!=NULL && !lstrcmp( category, _T("conference"))) {
+ for ( j=0; j<confNode->numChild; j++ ) {
+ if (( roomNode=confNode->child[j] )!=NULL && !strcmp( roomNode->name, "item" )) {
+ if (( category=JabberXmlGetAttrValue( roomNode, "category" ))!=NULL && !lstrcmp( category, _T("conference"))) {
+ if (( jid=JabberXmlGetAttrValue( roomNode, "jid" )) != NULL ) {
+ item = JabberListAdd( LIST_ROOM, jid );
+ if (( str=JabberXmlGetAttrValue( roomNode, "name" )) != NULL )
+ item->name = mir_tstrdup( str );
+ if (( str=JabberXmlGetAttrValue( roomNode, "type" )) != NULL )
+ item->type = mir_tstrdup( str );
+ } } } } }
+ }
+ else if ( !strcmp( confNode->name, "conference" )) {
+ for ( j=0; j<confNode->numChild; j++ ) {
+ if (( roomNode=confNode->child[j] )!=NULL && !strcmp( roomNode->name, "conference" )) {
+ if (( jid=JabberXmlGetAttrValue( roomNode, "jid" )) != NULL ) {
+ item = JabberListAdd( LIST_ROOM, jid );
+ if (( str=JabberXmlGetAttrValue( roomNode, "name" )) != NULL )
+ item->name = mir_tstrdup( str );
+ if (( str=JabberXmlGetAttrValue( roomNode, "type" )) != NULL )
+ item->type = mir_tstrdup( str );
+ } } } } } }
+
+ if ( hwndJabberGroupchat != NULL ) {
+ if (( jid=JabberXmlGetAttrValue( iqNode, "from" )) != NULL )
+ SendMessage( hwndJabberGroupchat, WM_JABBER_REFRESH, 0, ( LPARAM )jid );
+ else
+ SendMessage( hwndJabberGroupchat, WM_JABBER_REFRESH, 0, ( LPARAM )info->server );
+ }
+ }
+}
+
+void JabberSetMucConfig( XmlNode* node, void *from )
+{
+ if ( jabberThreadInfo && from ) {
+ XmlNodeIq iq( "set", NOID, ( TCHAR* )from );
+ XmlNode* query = iq.addQuery( xmlnsOwner );
+ query->addChild( node );
+ JabberSend( jabberThreadInfo->s, iq );
+} }
+
+void JabberIqResultGetMuc( XmlNode *iqNode, void *userdata )
+{
+ XmlNode *queryNode, *xNode;
+ TCHAR *type, *from, *str;
+
+ // RECVED: room config form
+ // ACTION: show the form
+ JabberLog( "<iq/> iqIdGetMuc" );
+ if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+ if (( from=JabberXmlGetAttrValue( iqNode, "from" )) == NULL ) return;
+
+ if ( !_tcscmp( type, _T("result"))) {
+ if (( queryNode=JabberXmlGetChild( iqNode, "query" )) != NULL ) {
+ str = JabberXmlGetAttrValue( queryNode, "xmlns" );
+ if ( !lstrcmp( str, _T("http://jabber.org/protocol/muc#owner" ))) {
+ if (( xNode=JabberXmlGetChild( queryNode, "x" )) != NULL ) {
+ str = JabberXmlGetAttrValue( xNode, "xmlns" );
+ if ( !lstrcmp( str, _T("jabber:x:data" )))
+ JabberFormCreateDialog( xNode, _T("Jabber Conference Room Configuration"), JabberSetMucConfig, mir_tstrdup( from ));
+} } } } }
+
+void JabberIqResultDiscoRoomItems( XmlNode *iqNode, void *userdata )
+{
+ struct ThreadData *info = ( struct ThreadData * ) userdata;
+ XmlNode *queryNode, *itemNode;
+ TCHAR* type, *jid, *from;
+ JABBER_LIST_ITEM *item;
+ int i;
+ int iqId;
+
+ // RECVED: room list
+ // ACTION: refresh groupchat room list dialog
+ JabberLog( "<iq/> iqIdDiscoRoomItems" );
+ if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+ if (( from=JabberXmlGetAttrValue( iqNode, "from" )) == NULL ) return;
+
+ if ( !lstrcmp( type, _T("result"))) {
+ if (( queryNode=JabberXmlGetChild( iqNode, "query" )) != NULL ) {
+ JabberListRemoveList( LIST_ROOM );
+ for ( i=0; i<queryNode->numChild; i++ ) {
+ if (( itemNode=queryNode->child[i] )!=NULL && itemNode->name!=NULL && !strcmp( itemNode->name, "item" )) {
+ if (( jid=JabberXmlGetAttrValue( itemNode, "jid" )) != NULL ) {
+ item = JabberListAdd( LIST_ROOM, jid );
+ item->name = mir_tstrdup( JabberXmlGetAttrValue( itemNode, "name" ));
+ } } } }
+
+ if ( hwndJabberGroupchat != NULL ) {
+ if (( jid=JabberXmlGetAttrValue( iqNode, "from" )) != NULL )
+ SendMessage( hwndJabberGroupchat, WM_JABBER_REFRESH, 0, ( LPARAM )jid );
+ else
+ SendMessage( hwndJabberGroupchat, WM_JABBER_REFRESH, 0, ( LPARAM )info->server );
+ }
+ }
+ else if ( !_tcscmp( type, _T("error"))) {
+ // disco is not supported, try browse
+ iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_BROWSEROOMS, JabberIqResultBrowseRooms );
+
+ XmlNodeIq iq( "get", iqId, from );
+ XmlNode* query = iq.addQuery( "jabber:iq:browse" );
+ JabberSend( jabberThreadInfo->s, iq );
+} }
+
+static BOOL CALLBACK JabberMucJidListDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch( msg ) {
+ case WM_INITDIALOG:
+ {
+ // lParam is ( JABBER_MUC_JIDLIST_INFO * )
+ LVCOLUMN lvc;
+ RECT rc;
+ HWND hwndList;
+
+ TranslateDialogDefault( hwndDlg );
+ hwndList = GetDlgItem( hwndDlg, IDC_LIST );
+ 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 );
+ }
+ return TRUE;
+ case WM_JABBER_REFRESH:
+ {
+ // lParam is ( JABBER_MUC_JIDLIST_INFO * )
+ JABBER_MUC_JIDLIST_INFO *jidListInfo;
+ XmlNode *iqNode, *queryNode, *itemNode;
+ TCHAR* from, *jid, *localFrom;
+ LVITEM lvi;
+ HWND hwndList;
+ int count, i;
+ TCHAR title[256];
+
+ // Clear current GWL_USERDATA, if any
+ jidListInfo = ( JABBER_MUC_JIDLIST_INFO * ) GetWindowLong( hwndDlg, GWL_USERDATA );
+ if ( jidListInfo != NULL ) {
+ if ( jidListInfo->roomJid != NULL )
+ mir_free( jidListInfo->roomJid );
+ if ( jidListInfo->iqNode != NULL )
+ delete jidListInfo->iqNode;
+ mir_free( jidListInfo );
+ }
+
+ // Clear current displayed list
+ 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 );
+
+ // Set new GWL_USERDATA
+ jidListInfo = ( JABBER_MUC_JIDLIST_INFO * ) lParam;
+ SetWindowLong( hwndDlg, GWL_USERDATA, ( LONG ) jidListInfo );
+
+ // Populate displayed list from iqNode
+ lstrcpyn( title, TranslateT( "JID List" ), SIZEOF( title ));
+ if (( jidListInfo=( JABBER_MUC_JIDLIST_INFO * ) lParam ) != NULL ) {
+ if (( iqNode = jidListInfo->iqNode ) != NULL ) {
+ if (( from = JabberXmlGetAttrValue( iqNode, "from" )) != NULL ) {
+ jidListInfo->roomJid = mir_tstrdup( from );
+ localFrom = mir_tstrdup( from );
+ mir_sntprintf( title, SIZEOF( title ), _T("%s ( %s )"),
+ ( jidListInfo->type==MUC_VOICELIST ) ? TranslateT( "Voice List" ) :
+ ( jidListInfo->type==MUC_MEMBERLIST ) ? TranslateT( "Member List" ) :
+ ( jidListInfo->type==MUC_MODERATORLIST ) ? TranslateT( "Moderator List" ) :
+ ( jidListInfo->type==MUC_BANLIST ) ? TranslateT( "Ban List" ) :
+ ( jidListInfo->type==MUC_ADMINLIST ) ? TranslateT( "Admin List" ) :
+ ( jidListInfo->type==MUC_OWNERLIST ) ? TranslateT( "Owner List" ) :
+ TranslateT( "JID List" ),
+ localFrom );
+ mir_free( localFrom );
+ if (( queryNode=JabberXmlGetChild( iqNode, "query" )) != NULL ) {
+ lvi.mask = LVIF_TEXT | LVIF_PARAM;
+ lvi.iSubItem = 0;
+ lvi.iItem = 0;
+ for ( i=0; i<queryNode->numChild; i++ ) {
+ if (( itemNode=queryNode->child[i] ) != NULL ) {
+ if (( jid=JabberXmlGetAttrValue( itemNode, "jid" )) != NULL ) {
+ lvi.pszText = jid;
+ lvi.lParam = ( LPARAM )mir_tstrdup( jid );
+ ListView_InsertItem( hwndList, &lvi );
+ lvi.iItem++;
+ } } } } } }
+
+ lvi.mask = LVIF_PARAM;
+ lvi.lParam = ( LPARAM )( -1 );
+ ListView_InsertItem( hwndList, &lvi );
+ }
+ SetWindowText( hwndDlg, title );
+ }
+ 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:
+ SetWindowLong( hwndDlg, DWL_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, NULL, DI_NORMAL );
+ DestroyIcon( hIcon );
+ SetWindowLong( hwndDlg, DWL_MSGRESULT, CDRF_SKIPDEFAULT );
+ return TRUE;
+ } } } }
+ break;
+ case NM_CLICK:
+ {
+ JABBER_MUC_JIDLIST_INFO *jidListInfo;
+ NMLISTVIEW *nm = ( NMLISTVIEW * ) lParam;
+ LVITEM lvi;
+ LVHITTESTINFO hti;
+ TCHAR text[128];
+
+ if ( nm->iSubItem < 1 ) break;
+ jidListInfo = ( JABBER_MUC_JIDLIST_INFO * ) GetWindowLong( hwndDlg, GWL_USERDATA );
+ 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, jidListInfo->type2str());
+ if ( !JabberEnterString( szBuffer, SIZEOF(szBuffer)))
+ 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;
+
+ JabberAddMucListItem( jidListInfo, p );
+ }
+ else {
+ //delete
+ TCHAR msgText[128];
+
+ mir_sntprintf( msgText, sizeof( msgText ), _T("%s %s?"), TranslateT( "Removing" ), text );
+ if ( MessageBox( hwndDlg, msgText, jidListInfo->type2str(), MB_YESNO|MB_SETFOREGROUND ) == IDYES ) {
+ JabberDeleteMucListItem( jidListInfo, ( TCHAR* )lvi.lParam );
+ ListView_DeleteItem( nm->hdr.hwndFrom, hti.iItem );
+ } } }
+ 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_CLOSE:
+ {
+ JABBER_MUC_JIDLIST_INFO *jidListInfo;
+ 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 );
+
+ jidListInfo = ( JABBER_MUC_JIDLIST_INFO * ) GetWindowLong( hwndDlg, GWL_USERDATA );
+ switch ( jidListInfo->type ) {
+ case MUC_VOICELIST:
+ hwndMucVoiceList = NULL;
+ break;
+ case MUC_MEMBERLIST:
+ hwndMucMemberList = NULL;
+ break;
+ case MUC_MODERATORLIST:
+ hwndMucModeratorList = NULL;
+ break;
+ case MUC_BANLIST:
+ hwndMucBanList = NULL;
+ break;
+ case MUC_ADMINLIST:
+ hwndMucAdminList = NULL;
+ break;
+ case MUC_OWNERLIST:
+ hwndMucOwnerList = NULL;
+ break;
+ }
+
+ DestroyWindow( hwndDlg );
+ }
+ break;
+ case WM_DESTROY:
+ {
+ JABBER_MUC_JIDLIST_INFO *jidListInfo;
+
+ // Clear GWL_USERDATA
+ jidListInfo = ( JABBER_MUC_JIDLIST_INFO * ) GetWindowLong( hwndDlg, GWL_USERDATA );
+ if ( jidListInfo != NULL ) {
+ if ( jidListInfo->iqNode != NULL )
+ delete jidListInfo->iqNode;
+ if ( jidListInfo->roomJid != NULL )
+ mir_free( jidListInfo->roomJid );
+ mir_free( jidListInfo );
+ }
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static VOID CALLBACK JabberMucJidListCreateDialogApcProc( DWORD param )
+{
+ XmlNode *iqNode, *queryNode;
+ TCHAR* from;
+ JABBER_MUC_JIDLIST_INFO *jidListInfo;
+ HWND *pHwndJidList;
+
+ if (( jidListInfo=( JABBER_MUC_JIDLIST_INFO * ) param ) == NULL ) return;
+ if (( iqNode=jidListInfo->iqNode ) == NULL ) return;
+ if (( from=JabberXmlGetAttrValue( iqNode, "from" )) == NULL ) return;
+ if (( queryNode=JabberXmlGetChild( iqNode, "query" )) == NULL ) return;
+
+ switch ( jidListInfo->type ) {
+ case MUC_VOICELIST:
+ pHwndJidList = &hwndMucVoiceList;
+ break;
+ case MUC_MEMBERLIST:
+ pHwndJidList = &hwndMucMemberList;
+ break;
+ case MUC_MODERATORLIST:
+ pHwndJidList = &hwndMucModeratorList;
+ break;
+ case MUC_BANLIST:
+ pHwndJidList = &hwndMucBanList;
+ break;
+ case MUC_ADMINLIST:
+ pHwndJidList = &hwndMucAdminList;
+ break;
+ case MUC_OWNERLIST:
+ pHwndJidList = &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 ), NULL, JabberMucJidListDlgProc, ( LPARAM )jidListInfo );
+}
+
+static void JabberIqResultMucGetJidList( XmlNode *iqNode, JABBER_MUC_JIDLIST_TYPE listType )
+{
+ TCHAR* type;
+ JABBER_MUC_JIDLIST_INFO *jidListInfo;
+
+ if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+
+ if ( !lstrcmp( type, _T("result" ))) {
+ if (( jidListInfo=( JABBER_MUC_JIDLIST_INFO * ) mir_alloc( sizeof( JABBER_MUC_JIDLIST_INFO )) ) != NULL ) {
+ jidListInfo->type = listType;
+ jidListInfo->roomJid = NULL; // Set in the dialog procedure
+ if (( ( jidListInfo->iqNode )=JabberXmlCopyNode( iqNode )) != NULL ) {
+ if ( GetCurrentThreadId() != jabberMainThreadId )
+ QueueUserAPC( JabberMucJidListCreateDialogApcProc, hMainThread, ( DWORD )jidListInfo );
+ else
+ JabberMucJidListCreateDialogApcProc(( DWORD )jidListInfo );
+ }
+ else mir_free( jidListInfo );
+} } }
+
+void JabberIqResultMucGetVoiceList( XmlNode *iqNode, void *userdata )
+{
+ JabberLog( "<iq/> iqResultMucGetVoiceList" );
+ JabberIqResultMucGetJidList( iqNode, MUC_VOICELIST );
+}
+
+void JabberIqResultMucGetMemberList( XmlNode *iqNode, void *userdata )
+{
+ JabberLog( "<iq/> iqResultMucGetMemberList" );
+ JabberIqResultMucGetJidList( iqNode, MUC_MEMBERLIST );
+}
+
+void JabberIqResultMucGetModeratorList( XmlNode *iqNode, void *userdata )
+{
+ JabberLog( "<iq/> iqResultMucGetModeratorList" );
+ JabberIqResultMucGetJidList( iqNode, MUC_MODERATORLIST );
+}
+
+void JabberIqResultMucGetBanList( XmlNode *iqNode, void *userdata )
+{
+ JabberLog( "<iq/> iqResultMucGetBanList" );
+ JabberIqResultMucGetJidList( iqNode, MUC_BANLIST );
+}
+
+void JabberIqResultMucGetAdminList( XmlNode *iqNode, void *userdata )
+{
+ JabberLog( "<iq/> iqResultMucGetAdminList" );
+ JabberIqResultMucGetJidList( iqNode, MUC_ADMINLIST );
+}
+
+void JabberIqResultMucGetOwnerList( XmlNode *iqNode, void *userdata )
+{
+ JabberLog( "<iq/> iqResultMucGetOwnerList" );
+ JabberIqResultMucGetJidList( iqNode, MUC_OWNERLIST );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+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/miranda-wine/protocols/JabberG/jabber_libstr.cpp b/miranda-wine/protocols/JabberG/jabber_libstr.cpp
new file mode 100644
index 0000000..b5fd916
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_libstr.cpp
@@ -0,0 +1,76 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_libstr.cpp,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+
+void __stdcall replaceStr( char*& dest, const char* src )
+{
+ if ( src != NULL ) {
+ if ( dest != NULL )
+ mir_free( dest );
+ dest = mir_strdup( src );
+ }
+ else dest = NULL;
+}
+
+void __stdcall replaceStr( WCHAR*& dest, const WCHAR* src )
+{
+ if ( src != NULL ) {
+ if ( dest != NULL )
+ mir_free( dest );
+ dest = mir_wstrdup( src );
+ }
+ else dest = NULL;
+}
+
+char* __stdcall rtrim( char *string )
+{
+ char* p = string + strlen( string ) - 1;
+
+ while ( p >= string ) {
+ if ( *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r' )
+ break;
+
+ *p-- = 0;
+ }
+ return string;
+}
+
+#if defined( _UNICODE )
+TCHAR* __stdcall rtrim( TCHAR *string )
+{
+ TCHAR* p = string + _tcslen( string ) - 1;
+
+ while ( p >= string ) {
+ if ( *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r' )
+ break;
+
+ *p-- = 0;
+ }
+ return string;
+}
+#endif
diff --git a/miranda-wine/protocols/JabberG/jabber_list.cpp b/miranda-wine/protocols/JabberG/jabber_list.cpp
new file mode 100644
index 0000000..e1dcfe9
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_list.cpp
@@ -0,0 +1,388 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_list.cpp,v $
+Revision : $Revision: 3651 $
+Last change on : $Date: 2006-08-30 16:54:52 +0400 (Срд, 30 Ðвг 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include "jabber_list.h"
+
+static int count;
+static JABBER_LIST_ITEM *lists;
+static CRITICAL_SECTION csLists;
+
+static void JabberListFreeItemInternal( JABBER_LIST_ITEM *item );
+
+void JabberListInit( void )
+{
+ lists = NULL;
+ count = 0;
+ InitializeCriticalSection( &csLists );
+}
+
+void JabberListUninit( void )
+{
+ JabberListWipe();
+ DeleteCriticalSection( &csLists );
+}
+
+void JabberListWipe( void )
+{
+ int i;
+
+ EnterCriticalSection( &csLists );
+ for( i=0; i<count; i++ )
+ JabberListFreeItemInternal( &( lists[i] ));
+ if ( lists != NULL ) {
+ mir_free( lists );
+ lists = NULL;
+ }
+ count=0;
+ LeaveCriticalSection( &csLists );
+}
+
+static void JabberListFreeItemInternal( JABBER_LIST_ITEM *item )
+{
+ int i;
+
+ 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 ( i=0; i<item->resourceCount; i++, r++ ) {
+ if ( r->resourceName ) mir_free( r->resourceName );
+ 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 ( item->resource ) mir_free( item->resource );
+ if ( item->statusMessage ) mir_free( item->statusMessage );
+ if ( item->group ) mir_free( item->group );
+ if ( item->photoFileName ) {
+ DeleteFileA( 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->list==LIST_ROSTER && item->ft ) delete item->ft;
+}
+
+int JabberListExist( JABBER_LIST list, const TCHAR* jid )
+{
+ TCHAR szSrc[ JABBER_MAX_JID_LEN ];
+ JabberStripJid( jid, szSrc, sizeof( szSrc ));
+
+ EnterCriticalSection( &csLists );
+ for ( int i=0; i<count; i++ ) {
+ if ( lists[i].list == list ) {
+ TCHAR szTempJid[ JABBER_MAX_JID_LEN ];
+ if ( !_tcsicmp( szSrc, JabberStripJid( lists[i].jid, szTempJid, sizeof( szTempJid )))) {
+ LeaveCriticalSection( &csLists );
+ return i+1;
+ } } }
+
+ LeaveCriticalSection( &csLists );
+ return 0;
+}
+
+JABBER_LIST_ITEM *JabberListAdd( JABBER_LIST list, const TCHAR* jid )
+{
+ TCHAR* s, *p, *q;
+ JABBER_LIST_ITEM *item;
+
+ EnterCriticalSection( &csLists );
+ if (( item=JabberListGetItemPtr( list, jid )) != NULL ) {
+ LeaveCriticalSection( &csLists );
+ return item;
+ }
+
+ s = mir_tstrdup( jid );
+ // strip resource name if any
+ if (( p = _tcschr( s, '@' )) != NULL )
+ if (( q = _tcschr( p, '/' )) != NULL )
+ *q = '\0';
+
+ lists = ( JABBER_LIST_ITEM * ) mir_realloc( lists, sizeof( JABBER_LIST_ITEM )*( count+1 ));
+ item = &( lists[count] );
+ ZeroMemory( item, sizeof( JABBER_LIST_ITEM ));
+ item->list = list;
+ item->jid = s;
+ item->status = ID_STATUS_OFFLINE;
+ item->resource = NULL;
+ item->resourceMode = RSMODE_LASTSEEN;
+ item->defaultResource = -1;
+ if ( list == LIST_ROSTER )
+ item->cap = CLIENT_CAP_CHATSTAT;
+ count++;
+ LeaveCriticalSection( &csLists );
+
+ return item;
+}
+
+void JabberListRemove( JABBER_LIST list, const TCHAR* jid )
+{
+ EnterCriticalSection( &csLists );
+ int i = JabberListExist( list, jid );
+ if ( !i ) {
+ LeaveCriticalSection( &csLists );
+ return;
+ }
+ i--;
+ JabberListFreeItemInternal( &( lists[i] ));
+ count--;
+ memmove( lists+i, lists+i+1, sizeof( JABBER_LIST_ITEM )*( count-i ));
+ lists = ( JABBER_LIST_ITEM * ) mir_realloc( lists, sizeof( JABBER_LIST_ITEM )*count );
+ LeaveCriticalSection( &csLists );
+}
+
+void JabberListRemoveList( JABBER_LIST list )
+{
+ int i = 0;
+ while (( i=JabberListFindNext( list, i )) >= 0 )
+ JabberListRemoveByIndex( i );
+}
+
+void JabberListRemoveByIndex( int index )
+{
+ EnterCriticalSection( &csLists );
+ if ( index>=0 && index<count ) {
+ JabberListFreeItemInternal( &( lists[index] ));
+ count--;
+ memmove( lists+index, lists+index+1, sizeof( JABBER_LIST_ITEM )*( count-index ));
+ lists = ( JABBER_LIST_ITEM * ) mir_realloc( lists, sizeof( JABBER_LIST_ITEM )*count );
+ }
+ LeaveCriticalSection( &csLists );
+}
+
+int JabberListAddResource( JABBER_LIST list, const TCHAR* jid, int status, const TCHAR* statusMessage )
+{
+ int j;
+ const TCHAR* p, *q;
+
+ EnterCriticalSection( &csLists );
+ int i = JabberListExist( list, jid );
+ if ( !i ) {
+ LeaveCriticalSection( &csLists );
+ return 0;
+ }
+ JABBER_LIST_ITEM* LI = &lists[i-1];
+
+ int bIsNewResource = false;
+
+ if (( p = _tcschr( jid, '@' )) != NULL ) {
+ if (( q = _tcschr( p, '/' )) != NULL ) {
+ 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;
+ replaceStr( r->statusMessage, statusMessage );
+ 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 );
+ if ( statusMessage )
+ r->statusMessage = mir_tstrdup( statusMessage );
+ } }
+ }
+ // No resource, update the main statusMessage
+ else replaceStr( LI->statusMessage, statusMessage );
+ }
+
+ LeaveCriticalSection( &csLists );
+ return bIsNewResource;
+}
+
+void JabberListRemoveResource( JABBER_LIST list, const TCHAR* jid )
+{
+ int j;
+ const TCHAR* p, *q;
+
+ EnterCriticalSection( &csLists );
+ int i = JabberListExist( list, jid );
+ JABBER_LIST_ITEM* LI = &lists[i-1];
+ if ( !i || LI == NULL ) {
+ LeaveCriticalSection( &csLists );
+ return;
+ }
+
+ if (( p = _tcschr( jid, '@' )) != NULL ) {
+ if (( q = _tcschr( p, '/' )) != NULL ) {
+ const TCHAR* resource = q+1;
+ if ( resource[0] ) {
+ JABBER_RESOURCE_STATUS* r = LI->resource;
+ for ( j=0; j < LI->resourceCount; j++, r++ ) {
+ if ( !_tcsicmp( r->resourceName, resource ))
+ break;
+ }
+ if ( j < LI->resourceCount ) {
+ // Found resource to be removed
+ if ( LI->defaultResource == j )
+ LI->defaultResource = -1;
+ else if ( LI->defaultResource > j )
+ LI->defaultResource--;
+ if ( r->resourceName ) mir_free( r->resourceName );
+ 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 ( 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( &csLists );
+}
+
+TCHAR* JabberListGetBestResourceNamePtr( const TCHAR* jid )
+{
+ TCHAR* res;
+
+ EnterCriticalSection( &csLists );
+ int i = JabberListExist( LIST_ROSTER, jid );
+ JABBER_LIST_ITEM* LI = &lists[i-1];
+ if ( !i || LI == NULL ) {
+ LeaveCriticalSection( &csLists );
+ return NULL;
+ }
+
+ if ( LI->resourceCount == 1 )
+ res = LI->resource[0].resourceName;
+ else {
+ res = NULL;
+ if ( LI->resourceMode == RSMODE_MANUAL || LI->resourceMode == RSMODE_LASTSEEN ) {
+ if ( LI->defaultResource>=0 && LI->defaultResource < LI->resourceCount )
+ res = LI->resource[ LI->defaultResource ].resourceName;
+ } }
+
+ LeaveCriticalSection( &csLists );
+ return res;
+}
+
+TCHAR* JabberListGetBestClientResourceNamePtr( const TCHAR* jid )
+{
+ EnterCriticalSection( &csLists );
+ int i = JabberListExist( LIST_ROSTER, jid );
+ JABBER_LIST_ITEM* LI = &lists[i-1];
+
+ if ( !i || LI == NULL ) {
+ LeaveCriticalSection( &csLists );
+ return NULL;
+ }
+
+ TCHAR* res = JabberListGetBestResourceNamePtr( 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( &csLists );
+ return res;
+}
+
+int JabberListFindNext( JABBER_LIST list, int fromOffset )
+{
+ EnterCriticalSection( &csLists );
+ int i = ( fromOffset>=0 ) ? fromOffset : 0;
+ for( ; i<count; i++ )
+ if ( lists[i].list == list ) {
+ LeaveCriticalSection( &csLists );
+ return i;
+ }
+ LeaveCriticalSection( &csLists );
+ return -1;
+}
+
+JABBER_LIST_ITEM *JabberListGetItemPtr( JABBER_LIST list, const TCHAR* jid )
+{
+ EnterCriticalSection( &csLists );
+ int i = JabberListExist( list, jid );
+ if ( !i ) {
+ LeaveCriticalSection( &csLists );
+ return NULL;
+ }
+ i--;
+ LeaveCriticalSection( &csLists );
+ return &( lists[i] );
+}
+
+JABBER_LIST_ITEM *JabberListGetItemPtrFromIndex( int index )
+{
+ EnterCriticalSection( &csLists );
+ if ( index>=0 && index<count ) {
+ LeaveCriticalSection( &csLists );
+ return &( lists[index] );
+ }
+ LeaveCriticalSection( &csLists );
+ return NULL;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_list.h b/miranda-wine/protocols/JabberG/jabber_list.h
new file mode 100644
index 0000000..dabd81f
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_list.h
@@ -0,0 +1,174 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_list.h,v $
+Revision : $Revision: 3651 $
+Last change on : $Date: 2006-08-30 16:54:52 +0400 (Срд, 30 Ðвг 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#ifndef _JABBER_LIST_H_
+#define _JABBER_LIST_H_
+
+typedef enum {
+ LIST_ROSTER, // Roster list
+ LIST_AGENT, // Agent list to show on the Jabber Agents dialog
+ 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_FTSEND,
+ LIST_FTRECV
+} 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;
+
+#define CLIENT_CAP_READY ( 1<<0 ) // have already done disco#info query
+#define CLIENT_CAP_SI ( 1<<1 ) // stream initiation ( si ) profile
+#define CLIENT_CAP_SIFILE ( 1<<2 ) // file transfer si profile
+#define CLIENT_CAP_BYTESTREAM ( 1<<3 ) // socks5 bytestream
+#define CLIENT_CAP_CHATSTAT ( 1<<4 ) // http://jabber.org/protocol/chatstates support (JEP-0085)
+
+#define AGENT_CAP_REGISTER ( 1<<13 )
+#define AGENT_CAP_SEARCH ( 1<<14 )
+#define AGENT_CAP_GROUPCHAT ( 1<<15 )
+
+#define CLIENT_CAP_FILE ( CLIENT_CAP_SI | CLIENT_CAP_SIFILE )
+
+struct JABBER_RESOURCE_STATUS
+{
+ int status;
+ TCHAR* resourceName;
+ TCHAR* statusMessage;
+ TCHAR* software;
+ TCHAR* version;
+ TCHAR* system;
+ unsigned int cap; // 0 = haven't done disco#info yet, see CLIENT_CAP_*
+ JABBER_GC_AFFILIATION affiliation;
+ JABBER_GC_ROLE role;
+};
+
+struct JABBER_LIST_ITEM
+{
+ JABBER_LIST list;
+ TCHAR* jid;
+
+ // LIST_ROSTER
+ // jid = jid of the contact
+ TCHAR* nick;
+ int resourceCount;
+ int status; // Main status, currently useful for transport where no resource information is kept.
+ // On normal contact, this is the same status as shown on contact list.
+ JABBER_RESOURCE_STATUS *resource;
+ 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* statusMessage; // Status message when the update is to JID with no resource specified ( e.g. transport user )
+ TCHAR* group;
+ char* photoFileName;
+ int idMsgAckPending;
+ TCHAR* messageEventIdStr;
+ BOOL wantComposingEvent;
+ WORD cap; // See CLIENT_CAP_* above
+
+ // LIST_AGENT
+ // jid = jid of the agent
+ // WORD cap; // See AGENT_CAP_* above
+ 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;
+
+ // LIST_FILE
+ // jid = string representation of port number
+ filetransfer* ft;
+ WORD port;
+
+ // LIST_BYTE
+ // jid = string representation of port number
+ JABBER_BYTE_TRANSFER *jbt;
+
+ // LIST_FTSEND
+ // jid = string representation of iq id
+ // ft = file transfer data
+ // jbt
+
+ // LIST_FTRECV
+ // jid = string representation of stream id ( sid )
+ // ft = file transfer data
+};
+
+void JabberListInit( void );
+void JabberListUninit( void );
+void JabberListWipe( void );
+int JabberListExist( JABBER_LIST list, const TCHAR* jid );
+JABBER_LIST_ITEM *JabberListAdd( JABBER_LIST list, const TCHAR* jid );
+void JabberListRemove( JABBER_LIST list, const TCHAR* jid );
+void JabberListRemoveList( JABBER_LIST list );
+void JabberListRemoveByIndex( int index );
+int JabberListFindNext( JABBER_LIST list, int fromOffset );
+JABBER_LIST_ITEM *JabberListGetItemPtr( JABBER_LIST list, const TCHAR* jid );
+JABBER_LIST_ITEM *JabberListGetItemPtrFromIndex( int index );
+
+int JabberListAddResource( JABBER_LIST list, const TCHAR* jid, int status, const TCHAR* statusMessage );
+void JabberListRemoveResource( JABBER_LIST list, const TCHAR* jid );
+TCHAR* JabberListGetBestResourceNamePtr( const TCHAR* jid );
+TCHAR* JabberListGetBestClientResourceNamePtr( const TCHAR* jid );
+
+#endif
diff --git a/miranda-wine/protocols/JabberG/jabber_menu.cpp b/miranda-wine/protocols/JabberG/jabber_menu.cpp
new file mode 100644
index 0000000..a25fe61
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_menu.cpp
@@ -0,0 +1,281 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_menu.cpp,v $
+Revision : $Revision: 2948 $
+Last change on : $Date: 2006-05-24 23:59:47 +0400 (Срд, 24 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include "jabber_list.h"
+#include "resource.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// module data
+
+static HANDLE hMenuRequestAuth = NULL;
+static HANDLE hMenuGrantAuth = NULL;
+static HANDLE hMenuJoinLeave = NULL;
+static HANDLE hMenuConvert = NULL;
+static HANDLE hMenuRosterAdd = NULL;
+
+static void sttEnableMenuItem( HANDLE hMenuItem, BOOL bEnable )
+{
+ CLISTMENUITEM clmi = {0};
+ clmi.cbSize = sizeof( CLISTMENUITEM );
+ clmi.flags = CMIM_FLAGS;
+ if ( !bEnable )
+ clmi.flags |= CMIF_HIDDEN;
+
+ JCallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuItem, ( LPARAM )&clmi );
+}
+
+int JabberMenuPrebuildContactMenu( WPARAM wParam, LPARAM lParam )
+{
+ sttEnableMenuItem( hMenuRequestAuth, FALSE );
+ sttEnableMenuItem( hMenuGrantAuth, FALSE );
+ sttEnableMenuItem( hMenuJoinLeave, FALSE );
+ sttEnableMenuItem( hMenuConvert, FALSE );
+ sttEnableMenuItem( hMenuRosterAdd, FALSE );
+
+ HANDLE hContact;
+ if (( hContact=( HANDLE )wParam ) == NULL )
+ return 0;
+
+ BYTE chatRoomType = (BYTE)JGetByte( hContact, "ChatRoom", 0 );
+
+ if ((chatRoomType == GCW_CHATROOM) || chatRoomType == 0 ) {
+ DBVARIANT dbv;
+ if ( !JGetStringT( hContact, chatRoomType?"ChatRoomID":"jid", &dbv )) {
+ JFreeVariant( &dbv );
+ CLISTMENUITEM clmi = { 0 };
+ sttEnableMenuItem( hMenuConvert, TRUE );
+ clmi.cbSize = sizeof( clmi );
+ clmi.pszName = JTranslate( chatRoomType ? "&Convert to Contact" : "&Convert to Chat Room" );
+ clmi.flags = CMIM_NAME | CMIM_FLAGS;
+ JCallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuConvert, ( LPARAM )&clmi );
+ } }
+
+ if (!jabberOnline)
+ return 0;
+
+ if ( chatRoomType ) {
+ DBVARIANT dbv;
+ if ( !JGetStringT( hContact, "ChatRoomID", &dbv )) {
+ if ( JabberListGetItemPtr( LIST_ROSTER, dbv.ptszVal ) == NULL ) {
+ sttEnableMenuItem( hMenuRosterAdd, TRUE );
+ }
+ JFreeVariant( &dbv );
+ } }
+
+ if ( chatRoomType == GCW_CHATROOM ) {
+ CLISTMENUITEM clmi = { 0 };
+ clmi.cbSize = sizeof( clmi );
+ clmi.pszName = JTranslate(( JGetWord( hContact, "Status", 0 ) == ID_STATUS_ONLINE ) ? "&Leave" : "&Join" );
+ clmi.flags = CMIM_NAME | CMIM_FLAGS;
+ JCallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuJoinLeave, ( LPARAM )&clmi );
+ return 0;
+ }
+
+ DBVARIANT dbv;
+ if ( !JGetStringT( hContact, "jid", &dbv )) {
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_ROSTER, dbv.ptszVal );
+ JFreeVariant( &dbv );
+ if ( item != NULL ) {
+ sttEnableMenuItem( hMenuRequestAuth, item->subscription == SUB_FROM || item->subscription == SUB_NONE );
+ sttEnableMenuItem( hMenuGrantAuth, item->subscription == SUB_TO || item->subscription == SUB_NONE );
+ return 0;
+ } }
+
+ return 0;
+}
+
+int JabberMenuConvertChatContact( WPARAM wParam, LPARAM lParam )
+{
+ BYTE chatRoomType = (BYTE)JGetByte( (HANDLE ) wParam, "ChatRoom", 0 );
+ if ((chatRoomType == GCW_CHATROOM) || chatRoomType == 0 ) {
+ DBVARIANT dbv;
+ if ( !JGetStringT( (HANDLE ) wParam, (chatRoomType == GCW_CHATROOM)?"ChatRoomID":"jid", &dbv )) {
+ JDeleteSetting( (HANDLE ) wParam, (chatRoomType == GCW_CHATROOM)?"ChatRoomID":"jid");
+ JSetStringT( (HANDLE ) wParam, (chatRoomType != GCW_CHATROOM)?"ChatRoomID":"jid", dbv.ptszVal);
+ JFreeVariant( &dbv );
+ JSetByte((HANDLE ) wParam, "ChatRoom", (chatRoomType == GCW_CHATROOM)?0:GCW_CHATROOM);
+ } }
+ return 0;
+}
+
+int JabberMenuRosterAdd( WPARAM wParam, LPARAM 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 ( JabberListGetItemPtr( 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 );
+ }
+ JabberAddContactToRoster(roomID, nick, group, SUB_NONE);
+ if (nick) mir_free(nick);
+ if (nick) mir_free(group);
+ }
+ mir_free(roomID);
+ }
+ return 0;
+}
+
+int JabberMenuHandleRequestAuth( WPARAM wParam, LPARAM lParam )
+{
+ HANDLE hContact;
+ DBVARIANT dbv;
+
+ if (( hContact=( HANDLE ) wParam )!=NULL && jabberOnline ) {
+ if ( !JGetStringT( hContact, "jid", &dbv )) {
+ XmlNode presence( "presence" ); presence.addAttr( "to", dbv.ptszVal ); presence.addAttr( "type", "subscribe" );
+ JabberSend( jabberThreadInfo->s, presence );
+ JFreeVariant( &dbv );
+ } }
+
+ return 0;
+}
+
+int JabberMenuHandleGrantAuth( WPARAM wParam, LPARAM lParam )
+{
+ HANDLE hContact;
+ DBVARIANT dbv;
+
+ if (( hContact=( HANDLE ) wParam )!=NULL && jabberOnline ) {
+ if ( !JGetStringT( hContact, "jid", &dbv )) {
+ XmlNode presence( "presence" ); presence.addAttr( "to", dbv.ptszVal ); presence.addAttr( "type", "subscribed" );
+ JabberSend( jabberThreadInfo->s, presence );
+ JFreeVariant( &dbv );
+ } }
+
+ return 0;
+}
+
+int JabberMenuJoinLeave( WPARAM wParam, LPARAM lParam )
+{
+ DBVARIANT dbv, jid;
+ if ( JGetStringT(( HANDLE )wParam, "ChatRoomID", &jid ))
+ return 0;
+
+ if ( JGetStringT(( HANDLE )wParam, "MyNick", &dbv ))
+ if ( JGetStringT( NULL, "Nick", &dbv )) {
+ JFreeVariant( &jid );
+ return 0;
+ }
+
+ if ( JGetWord(( HANDLE )wParam, "Status", 0 ) != ID_STATUS_ONLINE ) {
+ if ( !jabberChatDllPresent ) {
+ JabberChatDllError();
+ goto LBL_Return;
+ }
+
+ TCHAR* p = _tcschr( jid.ptszVal, '@' );
+ if ( p == NULL )
+ goto LBL_Return;
+
+ *p++ = 0;
+ JabberGroupchatJoinRoom( p, jid.ptszVal, dbv.ptszVal, _T(""));
+ }
+ else {
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_CHATROOM, jid.ptszVal );
+ if ( item != NULL )
+ JabberGcQuit( item, 0, NULL );
+ }
+
+LBL_Return:
+ JFreeVariant( &dbv );
+ JFreeVariant( &jid );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// contact menu initialization code
+
+void JabberMenuInit()
+{
+ CLISTMENUITEM mi = { 0 };
+ mi.cbSize = sizeof( CLISTMENUITEM );
+
+ char text[ 200 ];
+ strcpy( text, jabberProtoName );
+ char* tDest = text + strlen( text );
+
+ // "Request authorization"
+ strcpy( tDest, "/RequestAuth" );
+ CreateServiceFunction( text, JabberMenuHandleRequestAuth );
+ mi.pszName = JTranslate( "Request authorization" );
+ mi.position = -2000001001;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_REQUEST ));
+ mi.pszService = text;
+ mi.pszContactOwner = jabberProtoName;
+ hMenuRequestAuth = ( HANDLE ) JCallService( MS_CLIST_ADDCONTACTMENUITEM, 0, ( LPARAM )&mi );
+
+ // "Grant authorization"
+ strcpy( tDest, "/GrantAuth" );
+ CreateServiceFunction( text, JabberMenuHandleGrantAuth );
+ mi.pszName = JTranslate( "Grant authorization" );
+ mi.position = -2000001000;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_GRANT ));
+ mi.pszService = text;
+ mi.pszContactOwner = jabberProtoName;
+ hMenuGrantAuth = ( HANDLE ) JCallService( MS_CLIST_ADDCONTACTMENUITEM, 0, ( LPARAM )&mi );
+
+ // "Grant authorization"
+ strcpy( tDest, "/JoinChat" );
+ CreateServiceFunction( text, JabberMenuJoinLeave );
+ mi.pszName = JTranslate( "Join chat" );
+ mi.position = -2000001002;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_GROUP ));
+ mi.pszService = text;
+ mi.pszContactOwner = jabberProtoName;
+ hMenuJoinLeave = ( HANDLE ) JCallService( MS_CLIST_ADDCONTACTMENUITEM, 0, ( LPARAM )&mi );
+
+ // "Convert Chat/Contact"
+ strcpy( tDest, "/ConvertChatContact" );
+ CreateServiceFunction( text, JabberMenuConvertChatContact );
+ mi.pszName = JTranslate( "Convert" );
+ mi.position = -1999901003;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_USER2ROOM ));
+ mi.pszService = text;
+ mi.pszContactOwner = jabberProtoName;
+ hMenuConvert = ( HANDLE ) JCallService( MS_CLIST_ADDCONTACTMENUITEM, 0, ( LPARAM )&mi );
+
+ // "Add to roster"
+ strcpy( tDest, "/AddToRoster" );
+ CreateServiceFunction( text, JabberMenuRosterAdd );
+ mi.pszName = JTranslate( "Add to roster" );
+ mi.position = -1999901004;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_ADDROSTER ));
+ mi.pszService = text;
+ mi.pszContactOwner = jabberProtoName;
+ hMenuRosterAdd = ( HANDLE ) JCallService( MS_CLIST_ADDCONTACTMENUITEM, 0, ( LPARAM )&mi );
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_misc.cpp b/miranda-wine/protocols/JabberG/jabber_misc.cpp
new file mode 100644
index 0000000..35e356e
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_misc.cpp
@@ -0,0 +1,382 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_misc.cpp,v $
+Revision : $Revision: 3322 $
+Last change on : $Date: 2006-07-13 16:11:29 +0400 (Чтв, 13 Июл 2006) $
+Last change by : $Author: rainwater $
+
+*/
+
+#include "jabber.h"
+#include "jabber_list.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// JabberAddContactToRoster() - adds a contact to the roster
+
+void JabberAddContactToRoster( const TCHAR* jid, const TCHAR* nick, const TCHAR* grpName, JABBER_SUBSCRIPTION subscription )
+{
+ XmlNodeIq iq( "set" );
+ XmlNode* query = iq.addQuery( "jabber:iq:roster" );
+ XmlNode* item = query->addChild( "item" ); item->addAttr( "name", nick ); item->addAttr( "jid", jid );
+ switch( subscription ) {
+ case SUB_BOTH: item->addAttr( "subscription", "both" ); break;
+ case SUB_TO: item->addAttr( "subscription", "to" ); break;
+ case SUB_FROM: item->addAttr( "subscription", "from" ); break;
+ default: item->addAttr( "subscription", "none" ); break;
+ }
+
+ if ( grpName != NULL )
+ item->addChild( "group", grpName );
+ JabberSend( jabberThreadInfo->s, iq );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// JabberChatDllError() - missing CHAT.DLL
+
+void JabberChatDllError()
+{
+ MessageBox( NULL,
+ TranslateT( "CHAT plugin is required for conferences. Install it before chatting" ),
+ TranslateT( "Jabber Error Message" ), 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 );
+ JCallService( 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 JabberDBAddAuthRequest( TCHAR* jid, TCHAR* nick )
+{
+ HANDLE hContact = JabberDBCreateContact( jid, NULL, FALSE, TRUE );
+ JDeleteSetting( hContact, "Hidden" );
+ JSetStringT( hContact, "Nick", nick );
+
+ #if defined( _UNICODE )
+ char* szJid = u2a( jid );
+ char* szNick = u2a( nick );
+ #else
+ char* szJid = jid;
+ char* szNick = nick;
+ #endif
+
+ //blob is: uin( DWORD ), hContact( HANDLE ), nick( ASCIIZ ), first( ASCIIZ ), last( ASCIIZ ), email( ASCIIZ ), reason( ASCIIZ )
+ //blob is: 0( DWORD ), hContact( HANDLE ), nick( ASCIIZ ), ""( ASCIIZ ), ""( ASCIIZ ), email( ASCIIZ ), ""( ASCIIZ )
+ DBEVENTINFO dbei = {0};
+ dbei.cbSize = sizeof( DBEVENTINFO );
+ dbei.szModule = jabberProtoName;
+ dbei.timestamp = ( DWORD )time( NULL );
+ dbei.flags = 0;
+ dbei.eventType = EVENTTYPE_AUTHREQUEST;
+ dbei.cbBlob = sizeof( DWORD )+ sizeof( HANDLE ) + strlen( szNick ) + strlen( szJid ) + 5;
+ PBYTE pCurBlob = dbei.pBlob = ( PBYTE ) mir_alloc( dbei.cbBlob );
+ *(( PDWORD ) pCurBlob ) = 0; pCurBlob += sizeof( DWORD );
+ *(( PHANDLE ) pCurBlob ) = hContact; pCurBlob += sizeof( HANDLE );
+ 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
+
+ JCallService( MS_DB_EVENT_ADD, ( WPARAM ) ( HANDLE ) NULL, ( LPARAM )&dbei );
+ JabberLog( "Setup DBAUTHREQUEST with nick='" TCHAR_STR_PARAM "' jid='" TCHAR_STR_PARAM "'", szNick, szJid );
+
+ #if defined( _UNICODE )
+ mir_free( szJid );
+ mir_free( szNick );
+ #endif
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// JabberDBCreateContact()
+// jid & nick are passed in TXT
+
+HANDLE JabberDBCreateContact( TCHAR* jid, TCHAR* nick, BOOL temporary, BOOL stripResource )
+{
+ TCHAR* s, *p, *q;
+ int 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 ) JCallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL ) {
+ szProto = ( char* )JCallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 );
+ if ( szProto!=NULL && !strcmp( jabberProtoName, szProto )) {
+ DBVARIANT dbv;
+ if ( !JGetStringT( hContact, "jid", &dbv )) {
+ p = dbv.ptszVal;
+ if ( p && ( int )_tcslen( p )>=len && ( p[len]=='\0'||p[len]=='/' ) && !_tcsnicmp( p, s, len )) {
+ JFreeVariant( &dbv );
+ break;
+ }
+ JFreeVariant( &dbv );
+ } }
+ hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM ) hContact, 0 );
+ }
+
+ if ( hContact == NULL ) {
+ hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_ADD, 0, 0 );
+ JCallService( MS_PROTO_ADDTOCONTACT, ( WPARAM ) hContact, ( LPARAM )jabberProtoName );
+ JSetStringT( hContact, "jid", s );
+ if ( nick != NULL && *nick != '\0' )
+ JSetStringT( hContact, "Nick", nick );
+ if ( temporary )
+ DBWriteContactSettingByte( hContact, "CList", "NotOnList", 1 );
+ JabberLog( "Create Jabber contact jid=" TCHAR_STR_PARAM ", nick=" TCHAR_STR_PARAM, s, nick );
+ }
+
+ mir_free( s );
+ return hContact;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// JabberGetAvatarFileName() - gets a file name for the avatar image
+
+void JabberGetAvatarFileName( HANDLE hContact, char* pszDest, int cbLen )
+{
+ JCallService( MS_DB_GETPROFILEPATH, cbLen, LPARAM( pszDest ));
+
+ int tPathLen = strlen( pszDest );
+ tPathLen += mir_snprintf( pszDest + tPathLen, MAX_PATH - tPathLen, "\\Jabber\\" );
+ CreateDirectoryA( pszDest, NULL );
+
+ char* szFileType;
+ 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 ltoa(( long )hContact, str, 10 );
+
+ char* hash = JabberSha1( str );
+ mir_snprintf( pszDest + tPathLen, MAX_PATH - tPathLen, "%s.%s", hash, szFileType );
+ mir_free( hash );
+ }
+ else if ( jabberThreadInfo != NULL ) {
+ mir_snprintf( pszDest + tPathLen, MAX_PATH - tPathLen, TCHAR_STR_PARAM"@%s avatar.%s", jabberThreadInfo->username, jabberThreadInfo->server, szFileType );
+ }
+ else {
+ DBVARIANT dbv1, dbv2;
+ BOOL res1 = DBGetContactSetting( NULL, jabberProtoName, "LoginName", &dbv1 );
+ BOOL res2 = DBGetContactSetting( NULL, jabberProtoName, "LoginServer", &dbv2 );
+ mir_snprintf( pszDest + tPathLen, MAX_PATH - tPathLen, "%s@%s avatar.%s",
+ res1 ? "noname" : dbv1.pszVal,
+ res2 ? jabberProtoName : dbv2.pszVal,
+ szFileType );
+ if (!res1) JFreeVariant( &dbv1 );
+ if (!res2) JFreeVariant( &dbv2 );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// JabberForkThread()
+
+struct FORK_ARG {
+ HANDLE hEvent;
+ void ( __cdecl *threadcode )( void* );
+ void *arg;
+};
+
+static void __cdecl forkthread_r( struct FORK_ARG *fa )
+{
+ void ( *callercode )( void* ) = fa->threadcode;
+ void *arg = fa->arg;
+ JabberLog( "Thread started: %08X %d", callercode, GetCurrentThreadId());
+ JCallService( MS_SYSTEM_THREAD_PUSH, 0, 0 );
+ SetEvent( fa->hEvent );
+ __try {
+ callercode( arg );
+ } __finally {
+ JCallService( MS_SYSTEM_THREAD_POP, 0, 0 );
+ }
+ return;
+}
+
+ULONG JabberForkThread( void ( __cdecl *threadcode )( void* ), unsigned long stacksize, void *arg )
+{
+ struct FORK_ARG fa;
+ fa.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ fa.threadcode = threadcode;
+ fa.arg = arg;
+
+ ULONG rc = _beginthread(( JABBER_THREAD_FUNC )forkthread_r, stacksize, &fa );
+ if (( unsigned long ) -1L != rc )
+ WaitForSingleObject( fa.hEvent, INFINITE );
+
+ CloseHandle( fa.hEvent );
+ return rc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// JabberSetServerStatus()
+
+void JabberSetServerStatus( int iNewStatus )
+{
+ if ( !jabberConnected )
+ return;
+
+ // change status
+ int oldStatus = jabberStatus;
+ switch ( iNewStatus ) {
+ case ID_STATUS_ONLINE:
+ case ID_STATUS_NA:
+ case ID_STATUS_FREECHAT:
+ case ID_STATUS_INVISIBLE:
+ jabberStatus = iNewStatus;
+ break;
+ case ID_STATUS_AWAY:
+ case ID_STATUS_ONTHEPHONE:
+ case ID_STATUS_OUTTOLUNCH:
+ jabberStatus = ID_STATUS_AWAY;
+ break;
+ case ID_STATUS_DND:
+ case ID_STATUS_OCCUPIED:
+ jabberStatus = ID_STATUS_DND;
+ break;
+ default:
+ return;
+ }
+
+ // send presence update
+ JabberSendPresence( jabberStatus );
+ JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, jabberStatus );
+}
+
+// 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)
+char* EscapeChatTags(char* pszText)
+{
+ int nChars = 0;
+ for ( char* p = pszText; ( p = strchr( p, '%' )) != NULL; p++ )
+ nChars++;
+
+ if ( nChars == 0 )
+ return mir_strdup( pszText );
+
+ char* pszNewText = (char*)mir_alloc( strlen( pszText ) + 1 + nChars ), *s, *d;
+ if ( pszNewText == NULL )
+ return mir_strdup( pszText );
+
+ for ( s = pszText, d = pszNewText; *s; s++ ) {
+ if ( *s == '%' )
+ *d++ = '%';
+ *d++ = *s;
+ }
+ *d = 0;
+ return pszNewText;
+}
+
+char* UnEscapeChatTags(char* str_in)
+{
+ char* s = str_in, *d = str_in;
+ while ( *s ) {
+ if (( *s == '%' && s[1] == '%' ) || ( *s == '\n' && s[1] == '\n' ))
+ s++;
+ *d++ = *s++;
+ }
+ *d = 0;
+ return str_in;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_opt.cpp b/miranda-wine/protocols/JabberG/jabber_opt.cpp
new file mode 100644
index 0000000..4454671
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_opt.cpp
@@ -0,0 +1,724 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_opt.cpp,v $
+Revision : $Revision: 3703 $
+Last change on : $Date: 2006-09-05 17:54:42 +0400 (Втр, 05 Сен 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include "jabber_list.h"
+#include <commctrl.h>
+#include "resource.h"
+#include <uxtheme.h>
+
+extern BOOL jabberSendKeepAlive;
+extern UINT jabberCodePage;
+
+static BOOL (WINAPI *pfnEnableThemeDialogTexture)(HANDLE, DWORD) = 0;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberRegisterDlgProc - the dialog proc for registering new account
+
+#if defined( _UNICODE )
+ #define STR_FORMAT _T("%s %s@%S:%d?")
+#else
+ #define STR_FORMAT _T("%s %s@%s:%d?")
+#endif
+
+static BOOL CALLBACK JabberRegisterDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ struct ThreadData *thread, *regInfo;
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault( hwndDlg );
+ regInfo = ( struct ThreadData * ) lParam;
+ TCHAR text[256];
+ mir_sntprintf( text, SIZEOF(text), STR_FORMAT, TranslateT( "Register" ), regInfo->username, regInfo->server, regInfo->port );
+ SetDlgItemText( hwndDlg, IDC_REG_STATUS, text );
+ SetWindowLong( hwndDlg, GWL_USERDATA, ( LONG )regInfo );
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDOK:
+ ShowWindow( GetDlgItem( hwndDlg, IDOK ), SW_HIDE );
+ ShowWindow( GetDlgItem( hwndDlg, IDCANCEL ), SW_HIDE );
+ ShowWindow( GetDlgItem( hwndDlg, IDC_PROGRESS_REG ), SW_SHOW );
+ ShowWindow( GetDlgItem( hwndDlg, IDCANCEL2 ), SW_SHOW );
+ regInfo = ( struct ThreadData * ) GetWindowLong( hwndDlg, GWL_USERDATA );
+ thread = ( struct ThreadData * ) mir_alloc( sizeof( struct ThreadData ));
+ memset( thread, 0, sizeof( struct ThreadData ));
+ thread->type = JABBER_SESSION_REGISTER;
+ _tcsncpy( thread->username, regInfo->username, SIZEOF( thread->username ));
+ strncpy( thread->password, regInfo->password, SIZEOF( thread->password ));
+ strncpy( thread->server, regInfo->server, SIZEOF( thread->server ));
+ strncpy( thread->manualHost, regInfo->manualHost, SIZEOF( thread->manualHost ));
+ thread->port = regInfo->port;
+ thread->useSSL = regInfo->useSSL;
+ thread->reg_hwndDlg = hwndDlg;
+ JabberForkThread(( JABBER_THREAD_FUNC )JabberServerThread, 0, thread );
+ return TRUE;
+ case IDCANCEL:
+ case IDOK2:
+ EndDialog( hwndDlg, 0 );
+ return TRUE;
+ }
+ break;
+ case WM_JABBER_REGDLG_UPDATE: // wParam=progress ( 0-100 ), lparam=status string
+ if (( TCHAR* )lParam == NULL )
+ SetDlgItemText( hwndDlg, IDC_REG_STATUS, TranslateT( "No message" ));
+ else
+ SetDlgItemText( hwndDlg, IDC_REG_STATUS, ( TCHAR* )lParam );
+ if ( wParam >= 0 )
+ SendMessage( GetDlgItem( hwndDlg, IDC_PROGRESS_REG ), PBM_SETPOS, wParam, 0 );
+ if ( wParam >= 100 ) {
+ ShowWindow( GetDlgItem( hwndDlg, IDCANCEL2 ), SW_HIDE );
+ ShowWindow( GetDlgItem( hwndDlg, IDOK2 ), SW_SHOW );
+ }
+ else SetFocus( GetDlgItem( hwndDlg, IDC_PROGRESS_REG ));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberOptDlgProc - main options dialog procedure
+
+static HWND msgLangListBox;
+static BOOL CALLBACK JabberMsgLangAdd( LPSTR str )
+{
+ int i, count, index;
+ UINT cp;
+ static struct { UINT cpId; TCHAR* cpName; } cpTable[] = {
+ { 874, _T("Thai") },
+ { 932, _T("Japanese") },
+ { 936, _T("Simplified Chinese") },
+ { 949, _T("Korean") },
+ { 950, _T("Traditional Chinese") },
+ { 1250, _T("Central European") },
+ { 1251, _T("Cyrillic") },
+ { 1252, _T("Latin I") },
+ { 1253, _T("Greek") },
+ { 1254, _T("Turkish") },
+ { 1255, _T("Hebrew") },
+ { 1256, _T("Arabic") },
+ { 1257, _T("Baltic") },
+ { 1258, _T("Vietnamese") },
+ { 1361, _T("Korean ( Johab )") }
+ };
+
+ cp = atoi( str );
+ count = sizeof( cpTable )/sizeof( cpTable[0] );
+ for ( i=0; i<count && cpTable[i].cpId!=cp; i++ );
+ if ( i < count ) {
+ if (( index=SendMessage( msgLangListBox, CB_ADDSTRING, 0, ( LPARAM )TranslateTS( cpTable[i].cpName )) ) >= 0 ) {
+ SendMessage( msgLangListBox, CB_SETITEMDATA, ( WPARAM ) index, ( LPARAM )cp );
+ if ( jabberCodePage == cp )
+ SendMessage( msgLangListBox, CB_SETCURSEL, ( WPARAM ) index, 0 );
+ } }
+
+ return TRUE;
+}
+
+static LRESULT CALLBACK JabberValidateUsernameWndProc( HWND hwndEdit, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ WNDPROC oldProc = ( WNDPROC ) GetWindowLong( hwndEdit, GWL_USERDATA );
+
+ switch ( msg ) {
+ case WM_CHAR:
+ if ( strchr( "\"&'/:<>@", wParam&0xff ) != NULL )
+ return 0;
+ break;
+ }
+ return CallWindowProc( oldProc, hwndEdit, msg, wParam, lParam );
+}
+
+static BOOL CALLBACK JabberOptDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ {
+ DBVARIANT dbv;
+ BOOL enableRegister = TRUE;
+
+ TranslateDialogDefault( hwndDlg );
+ SetDlgItemTextA( hwndDlg, IDC_SIMPLE, jabberModuleName );
+ if ( !DBGetContactSetting( NULL, jabberProtoName, "LoginName", &dbv )) {
+ SetDlgItemTextA( hwndDlg, IDC_EDIT_USERNAME, dbv.pszVal );
+ if ( !dbv.pszVal[0] ) enableRegister = FALSE;
+ JFreeVariant( &dbv );
+ }
+ if ( !DBGetContactSetting( NULL, jabberProtoName, "Password", &dbv )) {
+ JCallService( MS_DB_CRYPT_DECODESTRING, strlen( dbv.pszVal )+1, ( LPARAM )dbv.pszVal );
+ SetDlgItemTextA( hwndDlg, IDC_EDIT_PASSWORD, dbv.pszVal );
+ if ( !dbv.pszVal[0] ) enableRegister = FALSE;
+ JFreeVariant( &dbv );
+ }
+ if ( !DBGetContactSettingTString( NULL, jabberProtoName, "Resource", &dbv )) {
+ SetDlgItemText( hwndDlg, IDC_EDIT_RESOURCE, dbv.ptszVal );
+ JFreeVariant( &dbv );
+ }
+ else SetDlgItemTextA( hwndDlg, IDC_EDIT_RESOURCE, "Miranda" );
+
+ SendMessage( GetDlgItem( hwndDlg, IDC_PRIORITY_SPIN ), UDM_SETRANGE, 0, ( LPARAM )MAKELONG( 100, 0 ));
+
+ char text[256];
+ sprintf( text, "%d", JGetWord( NULL, "Priority", 0 ));
+ SetDlgItemTextA( hwndDlg, IDC_PRIORITY, text );
+ CheckDlgButton( hwndDlg, IDC_SAVEPASSWORD, JGetByte( "SavePassword", TRUE ));
+ if ( !DBGetContactSetting( NULL, jabberProtoName, "LoginServer", &dbv )) {
+ SetDlgItemTextA( hwndDlg, IDC_EDIT_LOGIN_SERVER, dbv.pszVal );
+ if ( !dbv.pszVal[0] ) enableRegister = FALSE;
+ JFreeVariant( &dbv );
+ }
+ else SetDlgItemTextA( hwndDlg, IDC_EDIT_LOGIN_SERVER, "jabber.org" );
+
+ WORD port = ( WORD )JGetWord( NULL, "Port", JABBER_DEFAULT_PORT );
+ SetDlgItemInt( hwndDlg, IDC_PORT, port, FALSE );
+ if ( port <= 0 ) enableRegister = FALSE;
+
+ CheckDlgButton( hwndDlg, IDC_USE_SSL, JGetByte( "UseSSL", FALSE ));
+ CheckDlgButton( hwndDlg, IDC_USE_TLS, JGetByte( "UseTLS", FALSE ));
+ EnableWindow(GetDlgItem( hwndDlg, IDC_USE_TLS ), !JGetByte( "UseSSL", FALSE ));
+
+ EnableWindow( GetDlgItem( hwndDlg, IDC_BUTTON_REGISTER ), enableRegister );
+
+ if ( JGetByte( "ManualConnect", FALSE ) == TRUE ) {
+ CheckDlgButton( hwndDlg, IDC_MANUAL, TRUE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_HOST ), TRUE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_HOSTPORT ), TRUE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_PORT ), FALSE );
+ }
+ if ( !DBGetContactSetting( NULL, jabberProtoName, "ManualHost", &dbv )) {
+ SetDlgItemTextA( hwndDlg, IDC_HOST, dbv.pszVal );
+ JFreeVariant( &dbv );
+ }
+ SetDlgItemInt( hwndDlg, IDC_HOSTPORT, JGetWord( NULL, "ManualPort", JABBER_DEFAULT_PORT ), FALSE );
+
+ CheckDlgButton( hwndDlg, IDC_KEEPALIVE, JGetByte( "KeepAlive", TRUE ));
+ CheckDlgButton( hwndDlg, IDC_ROSTER_SYNC, JGetByte( "RosterSync", FALSE ));
+
+ if ( !DBGetContactSetting( NULL, jabberProtoName, "Jud", &dbv )) {
+ SetDlgItemTextA( hwndDlg, IDC_JUD, dbv.pszVal );
+ JFreeVariant( &dbv );
+ }
+ else SetDlgItemTextA( hwndDlg, IDC_JUD, "users.jabber.org" );
+
+ msgLangListBox = GetDlgItem( hwndDlg, IDC_MSGLANG );
+ TCHAR str[ 256 ];
+ mir_sntprintf( str, SIZEOF(str), _T("== %s =="), TranslateT( "System default" ));
+ SendMessage( msgLangListBox, CB_ADDSTRING, 0, ( LPARAM )str );
+ SendMessage( msgLangListBox, CB_SETITEMDATA, 0, CP_ACP );
+ SendMessage( msgLangListBox, CB_SETCURSEL, 0, 0 );
+ EnumSystemCodePagesA( JabberMsgLangAdd, CP_INSTALLED );
+
+ WNDPROC oldProc = ( WNDPROC ) GetWindowLong( GetDlgItem( hwndDlg, IDC_EDIT_USERNAME ), GWL_WNDPROC );
+ SetWindowLong( GetDlgItem( hwndDlg, IDC_EDIT_USERNAME ), GWL_USERDATA, ( LONG ) oldProc );
+ SetWindowLong( GetDlgItem( hwndDlg, IDC_EDIT_USERNAME ), GWL_WNDPROC, ( LONG ) JabberValidateUsernameWndProc );
+
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_EDIT_USERNAME:
+ case IDC_EDIT_PASSWORD:
+ case IDC_EDIT_RESOURCE:
+ case IDC_EDIT_LOGIN_SERVER:
+ case IDC_PORT:
+ case IDC_MANUAL:
+ case IDC_HOST:
+ case IDC_HOSTPORT:
+ case IDC_JUD:
+ case IDC_PRIORITY:
+ {
+ if ( LOWORD( wParam ) == IDC_MANUAL ) {
+ if ( IsDlgButtonChecked( hwndDlg, IDC_MANUAL )) {
+ EnableWindow( GetDlgItem( hwndDlg, IDC_HOST ), TRUE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_HOSTPORT ), TRUE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_PORT ), FALSE );
+ }
+ else {
+ EnableWindow( GetDlgItem( hwndDlg, IDC_HOST ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_HOSTPORT ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_PORT ), TRUE );
+ }
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ }
+ else {
+ if (( HWND )lParam==GetFocus() && HIWORD( wParam )==EN_CHANGE )
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ }
+
+ ThreadData regInfo;
+ GetDlgItemText( hwndDlg, IDC_EDIT_USERNAME, regInfo.username, SIZEOF( regInfo.username ));
+ GetDlgItemTextA( hwndDlg, IDC_EDIT_PASSWORD, regInfo.password, SIZEOF( regInfo.password ));
+ GetDlgItemTextA( hwndDlg, IDC_EDIT_LOGIN_SERVER, regInfo.server, SIZEOF( regInfo.server ));
+ if ( IsDlgButtonChecked( hwndDlg, IDC_MANUAL )) {
+ regInfo.port = ( WORD )GetDlgItemInt( hwndDlg, IDC_HOSTPORT, NULL, FALSE );
+ GetDlgItemTextA( hwndDlg, IDC_HOST, regInfo.manualHost, SIZEOF( regInfo.manualHost ));
+ }
+ else {
+ regInfo.port = ( WORD )GetDlgItemInt( hwndDlg, IDC_PORT, NULL, FALSE );
+ regInfo.manualHost[0] = '\0';
+ }
+ if ( regInfo.username[0] && regInfo.password[0] && regInfo.server[0] && regInfo.port>0 && ( !IsDlgButtonChecked( hwndDlg, IDC_MANUAL ) || regInfo.manualHost[0] ))
+ EnableWindow( GetDlgItem( hwndDlg, IDC_BUTTON_REGISTER ), TRUE );
+ else
+ EnableWindow( GetDlgItem( hwndDlg, IDC_BUTTON_REGISTER ), FALSE );
+ break;
+ }
+ case IDC_LINK_PUBLIC_SERVER:
+ ShellExecuteA( hwndDlg, "open", "http://www.jabber.org/network", "", "", SW_SHOW );
+ return TRUE;
+ case IDC_BUTTON_REGISTER:
+ {
+ ThreadData regInfo;
+ GetDlgItemText( hwndDlg, IDC_EDIT_USERNAME, regInfo.username, SIZEOF( regInfo.username ));
+ GetDlgItemTextA( hwndDlg, IDC_EDIT_PASSWORD, regInfo.password, SIZEOF( regInfo.password ));
+ GetDlgItemTextA( hwndDlg, IDC_EDIT_LOGIN_SERVER, regInfo.server, SIZEOF( regInfo.server ));
+ if ( IsDlgButtonChecked( hwndDlg, IDC_MANUAL )) {
+ GetDlgItemTextA( hwndDlg, IDC_HOST, regInfo.manualHost, SIZEOF( regInfo.manualHost ));
+ regInfo.port = ( WORD )GetDlgItemInt( hwndDlg, IDC_HOSTPORT, NULL, FALSE );
+ }
+ else {
+ regInfo.manualHost[0] = '\0';
+ regInfo.port = ( WORD )GetDlgItemInt( hwndDlg, IDC_PORT, NULL, FALSE );
+ }
+ regInfo.useSSL = IsDlgButtonChecked( hwndDlg, IDC_USE_SSL );
+
+ if ( regInfo.username[0] && regInfo.password[0] && regInfo.server[0] && regInfo.port>0 && ( !IsDlgButtonChecked( hwndDlg, IDC_MANUAL ) || regInfo.manualHost[0] ))
+ DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_OPT_REGISTER ), hwndDlg, JabberRegisterDlgProc, ( LPARAM )&regInfo );
+
+ return TRUE;
+ }
+ case IDC_MSGLANG:
+ if ( HIWORD( wParam ) == CBN_SELCHANGE )
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ break;
+ case IDC_USE_SSL:
+ if ( !IsDlgButtonChecked( hwndDlg, IDC_MANUAL )) {
+ if ( IsDlgButtonChecked( hwndDlg, IDC_USE_SSL )) {
+ EnableWindow(GetDlgItem( hwndDlg, IDC_USE_TLS ), FALSE );
+ SetDlgItemInt( hwndDlg, IDC_PORT, 5223, FALSE );
+ }
+ else {
+ EnableWindow(GetDlgItem( hwndDlg, IDC_USE_TLS ), TRUE );
+ SetDlgItemInt( hwndDlg, IDC_PORT, 5222, FALSE );
+ } }
+ // Fall through
+ case IDC_USE_TLS:
+ case IDC_SAVEPASSWORD:
+ case IDC_KEEPALIVE:
+ case IDC_ROSTER_SYNC:
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ break;
+ default:
+ return 0;
+ }
+ break;
+ case WM_NOTIFY:
+ if (( ( LPNMHDR ) lParam )->code == PSN_APPLY ) {
+ BOOL reconnectRequired = FALSE;
+ DBVARIANT dbv;
+
+ char userName[256], text[256];
+ TCHAR textT [256];
+ GetDlgItemTextA( hwndDlg, IDC_EDIT_USERNAME, userName, sizeof( userName ));
+ if ( DBGetContactSetting( NULL, jabberProtoName, "LoginName", &dbv ) || strcmp( userName, dbv.pszVal ))
+ reconnectRequired = TRUE;
+ if ( dbv.pszVal != NULL ) JFreeVariant( &dbv );
+ JSetString( NULL, "LoginName", userName );
+
+ if ( IsDlgButtonChecked( hwndDlg, IDC_SAVEPASSWORD )) {
+ GetDlgItemTextA( hwndDlg, IDC_EDIT_PASSWORD, text, sizeof( text ));
+ JCallService( MS_DB_CRYPT_ENCODESTRING, sizeof( text ), ( LPARAM )text );
+ if ( DBGetContactSetting( NULL, jabberProtoName, "Password", &dbv ) || strcmp( text, dbv.pszVal ))
+ reconnectRequired = TRUE;
+ if ( dbv.pszVal != NULL ) JFreeVariant( &dbv );
+ JSetString( NULL, "Password", text );
+ }
+ else JDeleteSetting( NULL, "Password" );
+
+ GetDlgItemText( hwndDlg, IDC_EDIT_RESOURCE, textT, SIZEOF( textT ));
+ if ( !JGetStringT( NULL, "Resource", &dbv )) {
+ if ( _tcscmp( textT, dbv.ptszVal ))
+ reconnectRequired = TRUE;
+ JFreeVariant( &dbv );
+ }
+ else reconnectRequired = TRUE;
+ JSetStringT( NULL, "Resource", textT );
+
+ GetDlgItemTextA( hwndDlg, IDC_PRIORITY, text, sizeof( text ));
+ WORD port = ( WORD )atoi( text );
+ if ( port > 100 ) port = 100;
+ if ( port < 0 ) port = 0;
+ if ( JGetWord( NULL, "Priority", 0 ) != port )
+ reconnectRequired = TRUE;
+ JSetWord( NULL, "Priority", ( WORD )port );
+
+ JSetByte( "SavePassword", ( BYTE ) IsDlgButtonChecked( hwndDlg, IDC_SAVEPASSWORD ));
+
+ GetDlgItemTextA( hwndDlg, IDC_EDIT_LOGIN_SERVER, text, sizeof( text ));
+ if ( DBGetContactSetting( NULL, jabberProtoName, "LoginServer", &dbv ) || strcmp( text, dbv.pszVal ))
+ reconnectRequired = TRUE;
+ if ( dbv.pszVal != NULL ) JFreeVariant( &dbv );
+ JSetString( NULL, "LoginServer", text );
+
+ strcat( userName, "@" );
+ strncat( userName, text, sizeof( userName ));
+ userName[ sizeof(userName)-1 ] = 0;
+ JSetString( NULL, "jid", userName );
+
+ port = ( WORD )GetDlgItemInt( hwndDlg, IDC_PORT, NULL, FALSE );
+ if ( JGetWord( NULL, "Port", JABBER_DEFAULT_PORT ) != port )
+ reconnectRequired = TRUE;
+ JSetWord( NULL, "Port", port );
+
+ JSetByte( "UseSSL", ( BYTE ) IsDlgButtonChecked( hwndDlg, IDC_USE_SSL ));
+ JSetByte( "UseTLS", ( BYTE ) IsDlgButtonChecked( hwndDlg, IDC_USE_TLS ));
+
+ JSetByte( "ManualConnect", ( BYTE ) IsDlgButtonChecked( hwndDlg, IDC_MANUAL ));
+
+ GetDlgItemTextA( hwndDlg, IDC_HOST, text, sizeof( text ));
+ if ( DBGetContactSetting( NULL, jabberProtoName, "ManualHost", &dbv ) || strcmp( text, dbv.pszVal ))
+ reconnectRequired = TRUE;
+ if ( dbv.pszVal != NULL ) JFreeVariant( &dbv );
+ JSetString( NULL, "ManualHost", text );
+
+ port = ( WORD )GetDlgItemInt( hwndDlg, IDC_HOSTPORT, NULL, FALSE );
+ if ( JGetWord( NULL, "ManualPort", JABBER_DEFAULT_PORT ) != port )
+ reconnectRequired = TRUE;
+ JSetWord( NULL, "ManualPort", port );
+
+ JSetByte( "KeepAlive", ( BYTE ) IsDlgButtonChecked( hwndDlg, IDC_KEEPALIVE ));
+ jabberSendKeepAlive = IsDlgButtonChecked( hwndDlg, IDC_KEEPALIVE );
+
+ JSetByte( "RosterSync", ( BYTE ) IsDlgButtonChecked( hwndDlg, IDC_ROSTER_SYNC ));
+
+ GetDlgItemTextA( hwndDlg, IDC_JUD, text, sizeof( text ));
+ JSetString( NULL, "Jud", text );
+
+ int index = SendMessage( GetDlgItem( hwndDlg, IDC_MSGLANG ), CB_GETCURSEL, 0, 0 );
+ if ( index >= 0 ) {
+ jabberCodePage = SendMessage( GetDlgItem( hwndDlg, IDC_MSGLANG ), CB_GETITEMDATA, ( WPARAM ) index, 0 );
+ JSetWord( NULL, "CodePage", ( WORD )jabberCodePage );
+ }
+
+ if ( reconnectRequired && jabberConnected )
+ MessageBox( hwndDlg, TranslateT( "These changes will take effect the next time you connect to the Jabber network." ), TranslateT( "Jabber Protocol Option" ), MB_OK|MB_SETFOREGROUND );
+
+ return TRUE;
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberAdvOptDlgProc - advanced options dialog procedure
+
+static BOOL CALLBACK JabberAdvOptDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ char text[256];
+ BOOL bChecked;
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault( hwndDlg );
+
+ // File transfer options
+ BOOL bDirect = JGetByte( "BsDirect", TRUE );
+ BOOL bManualDirect = JGetByte( "BsDirectManual", FALSE );
+ CheckDlgButton( hwndDlg, IDC_DIRECT, bDirect );
+ CheckDlgButton( hwndDlg, IDC_DIRECT_MANUAL, bManualDirect );
+
+ DBVARIANT dbv;
+ if ( !DBGetContactSetting( NULL, jabberProtoName, "BsDirectAddr", &dbv )) {
+ SetDlgItemTextA( hwndDlg, IDC_DIRECT_ADDR, dbv.pszVal );
+ JFreeVariant( &dbv );
+ }
+ if ( !bDirect )
+ EnableWindow( GetDlgItem( hwndDlg, IDC_DIRECT_MANUAL ), FALSE );
+ if ( !bDirect || !bManualDirect )
+ EnableWindow( GetDlgItem( hwndDlg, IDC_DIRECT_ADDR ), FALSE );
+
+ BOOL bProxy = JGetByte( "BsProxy", FALSE );
+ BOOL bManualProxy = JGetByte( "BsProxyManual", FALSE );
+ CheckDlgButton( hwndDlg, IDC_PROXY, bProxy );
+ CheckDlgButton( hwndDlg, IDC_PROXY_MANUAL, bManualProxy );
+ if ( !DBGetContactSetting( NULL, jabberProtoName, "BsProxyServer", &dbv )) {
+ SetDlgItemTextA( hwndDlg, IDC_PROXY_ADDR, dbv.pszVal );
+ JFreeVariant( &dbv );
+ }
+ if ( !bProxy )
+ EnableWindow( GetDlgItem( hwndDlg, IDC_PROXY_MANUAL ), FALSE );
+ if ( !bProxy || !bManualProxy )
+ EnableWindow( GetDlgItem( hwndDlg, IDC_PROXY_ADDR ), FALSE );
+
+ // Miscellaneous options
+ CheckDlgButton( hwndDlg, IDC_SHOW_TRANSPORT, JGetByte( "ShowTransport", TRUE ));
+ CheckDlgButton( hwndDlg, IDC_AUTO_ADD, JGetByte( "AutoAdd", TRUE ));
+ CheckDlgButton( hwndDlg, IDC_MSG_ACK, JGetByte( "MsgAck", FALSE ));
+ CheckDlgButton( hwndDlg, IDC_DISABLE_MAINMENU, JGetByte( "DisableMainMenu", FALSE ));
+ CheckDlgButton( hwndDlg, IDC_ENABLE_AVATARS, JGetByte( "EnableAvatars", TRUE ));
+ CheckDlgButton( hwndDlg, IDC_AUTO_ACCEPT_MUC, JGetByte( "AutoAcceptMUC", FALSE ));
+ CheckDlgButton( hwndDlg, IDC_AUTOJOIN, JGetByte( "AutoJoinConferences", FALSE ));
+ CheckDlgButton( hwndDlg, IDC_DISABLE_SASL, JGetByte( "Disable3920auth", FALSE ));
+ return TRUE;
+ }
+ case WM_COMMAND:
+ {
+ switch ( LOWORD( wParam )) {
+ case IDC_DIRECT_ADDR:
+ case IDC_PROXY_ADDR:
+ if (( HWND )lParam==GetFocus() && HIWORD( wParam )==EN_CHANGE )
+ goto LBL_Apply;
+ break;
+ case IDC_DIRECT:
+ bChecked = IsDlgButtonChecked( hwndDlg, IDC_DIRECT );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_DIRECT_MANUAL ), bChecked );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_DIRECT_ADDR ), ( bChecked && IsDlgButtonChecked( hwndDlg, IDC_DIRECT_MANUAL )) );
+ goto LBL_Apply;
+ case IDC_DIRECT_MANUAL:
+ bChecked = IsDlgButtonChecked( hwndDlg, IDC_DIRECT_MANUAL );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_DIRECT_ADDR ), bChecked );
+ goto LBL_Apply;
+ case IDC_PROXY:
+ bChecked = IsDlgButtonChecked( hwndDlg, IDC_PROXY );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_PROXY_MANUAL ), bChecked );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_PROXY_ADDR ), ( bChecked && IsDlgButtonChecked( hwndDlg, IDC_PROXY_MANUAL )) );
+ goto LBL_Apply;
+ case IDC_PROXY_MANUAL:
+ bChecked = IsDlgButtonChecked( hwndDlg, IDC_PROXY_MANUAL );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_PROXY_ADDR ), bChecked );
+ default:
+ LBL_Apply:
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ break;
+ }
+ break;
+ }
+ case WM_NOTIFY:
+ if (( ( LPNMHDR ) lParam )->code == PSN_APPLY ) {
+ // File transfer options
+ JSetByte( "BsDirect", ( BYTE ) IsDlgButtonChecked( hwndDlg, IDC_DIRECT ));
+ JSetByte( "BsDirectManual", ( BYTE ) IsDlgButtonChecked( hwndDlg, IDC_DIRECT_MANUAL ));
+ GetDlgItemTextA( hwndDlg, IDC_DIRECT_ADDR, text, sizeof( text ));
+ JSetString( NULL, "BsDirectAddr", text );
+ JSetByte( "BsProxy", ( BYTE ) IsDlgButtonChecked( hwndDlg, IDC_PROXY ));
+ JSetByte( "BsProxyManual", ( BYTE ) IsDlgButtonChecked( hwndDlg, IDC_PROXY_MANUAL ));
+ GetDlgItemTextA( hwndDlg, IDC_PROXY_ADDR, text, sizeof( text ));
+ JSetString( NULL, "BsProxyAddr", text );
+
+ // Miscellaneous options
+ bChecked = IsDlgButtonChecked( hwndDlg, IDC_SHOW_TRANSPORT );
+ JSetByte( "ShowTransport", ( BYTE ) bChecked );
+ int index = 0;
+ while (( index=JabberListFindNext( LIST_ROSTER, index )) >= 0 ) {
+ JABBER_LIST_ITEM* item = JabberListGetItemPtrFromIndex( index );
+ if ( item != NULL ) {
+ if ( _tcschr( item->jid, '@' ) == NULL ) {
+ HANDLE hContact = JabberHContactFromJID( item->jid );
+ if ( hContact != NULL ) {
+ if ( bChecked ) {
+ if ( item->status != JGetWord( hContact, "Status", ID_STATUS_OFFLINE )) {
+ JSetWord( hContact, "Status", ( WORD )item->status );
+ } }
+ else if ( JGetWord( hContact, "Status", ID_STATUS_OFFLINE ) != ID_STATUS_OFFLINE )
+ JSetWord( hContact, "Status", ID_STATUS_OFFLINE );
+ } } }
+ index++;
+ }
+
+ JSetByte( "AutoAdd", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_AUTO_ADD ));
+ JSetByte( "MsgAck", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_MSG_ACK ));
+ JSetByte( "DisableMainMenu", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_DISABLE_MAINMENU ));
+ JSetByte( "Disable3920auth", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_DISABLE_SASL ));
+ JSetByte( "EnableAvatars", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_ENABLE_AVATARS ));
+ JSetByte( "AutoAcceptMUC", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_AUTO_ACCEPT_MUC ));
+ JSetByte( "AutoJoinConferences", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_AUTOJOIN ));
+ return TRUE;
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberOptInit - initializes all options dialogs
+
+static HWND hwndAcc = 0, hwndAdv = 0;
+
+static void SetOptionsDlgToType(HWND hwnd, int iExpert)
+{
+ TCITEM tci;
+ RECT rcClient;
+ HWND hwndTab = GetDlgItem(hwnd, IDC_OPTIONSTAB), hwndEnum;
+ int iPages = 0;
+
+ if(!hwndAcc)
+ hwndAcc = CreateDialog(hInst,MAKEINTRESOURCE(IDD_OPT_JABBER), hwnd, JabberOptDlgProc);
+
+ hwndEnum = GetWindow(hwndAcc, GW_CHILD);
+
+ while(hwndEnum) {
+ ShowWindow(hwndEnum, iExpert ? SW_SHOW : SW_HIDE);
+ hwndEnum = GetWindow(hwndEnum, GW_HWNDNEXT);
+ }
+ if(!iExpert) {
+ hwndEnum = GetDlgItem(hwndAcc, IDC_SIMPLE);
+ ShowWindow(hwndEnum, SW_SHOW);
+ hwndEnum = GetWindow(hwndEnum, GW_HWNDNEXT);
+ do {
+ ShowWindow(hwndEnum, SW_SHOW);
+ hwndEnum = GetWindow(hwndEnum, GW_HWNDNEXT);
+ } while(hwndEnum && hwndEnum != GetDlgItem(hwndAcc, IDC_LINK_PUBLIC_SERVER));
+ }
+ ShowWindow(hwndEnum, SW_SHOW);
+ GetClientRect(hwnd, &rcClient);
+ TabCtrl_DeleteAllItems(hwndTab);
+
+ tci.mask = TCIF_PARAM|TCIF_TEXT;
+ tci.lParam = (LPARAM)hwndAcc;
+ tci.pszText = TranslateT("Account");
+ TabCtrl_InsertItem(hwndTab, 0, &tci);
+ MoveWindow((HWND)tci.lParam,5,26,rcClient.right-8,rcClient.bottom-29,1);
+ iPages++;
+
+ if(!hwndAdv)
+ hwndAdv = CreateDialog(hInst,MAKEINTRESOURCE(IDD_OPT_JABBER2),hwnd,JabberAdvOptDlgProc);
+
+ if(pfnEnableThemeDialogTexture) {
+ if(hwndAcc)
+ pfnEnableThemeDialogTexture(hwndAcc, ETDT_ENABLETAB);
+ if(hwndAdv)
+ pfnEnableThemeDialogTexture(hwndAdv, ETDT_ENABLETAB);
+ }
+
+ ShowWindow(hwndAdv, SW_HIDE);
+ ShowWindow(hwndAcc, SW_SHOW);
+
+ if(iExpert) {
+ tci.lParam = (LPARAM)hwndAdv;
+ tci.pszText = TranslateT("Advanced");
+ TabCtrl_InsertItem(hwndTab, iPages++, &tci);
+ MoveWindow((HWND)tci.lParam,5,26,rcClient.right-8,rcClient.bottom-29,1);
+ }
+ TabCtrl_SetCurSel(hwndTab, 0);
+}
+
+static BOOL CALLBACK OptionsDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static int iInit = TRUE;
+
+ switch(msg) {
+ case WM_INITDIALOG:
+ {
+ iInit = TRUE;
+ int iExpert = SendMessage(GetParent(hwnd), PSM_ISEXPERT, 0, 0);
+ SetOptionsDlgToType(hwnd, iExpert);
+ iInit = FALSE;
+ return FALSE;
+ }
+ case WM_DESTROY:
+ hwndAcc = hwndAdv = 0;
+ break;
+ case PSM_CHANGED: // used so tabs dont have to call SendMessage(GetParent(GetParent(hwnd)), PSM_CHANGED, 0, 0);
+ if(!iInit)
+ SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_APPLY:
+ {
+ TCITEM tci;
+ int i,count = TabCtrl_GetItemCount(GetDlgItem(hwnd,IDC_OPTIONSTAB));
+ tci.mask = TCIF_PARAM;
+ for (i=0;i<count;i++) {
+ TabCtrl_GetItem(GetDlgItem(hwnd,IDC_OPTIONSTAB),i,&tci);
+ SendMessage((HWND)tci.lParam,WM_NOTIFY,0,lParam);
+ }
+ break;
+ }
+ case PSN_EXPERTCHANGED:
+ {
+ int iExpert = SendMessage(GetParent(hwnd), PSM_ISEXPERT, 0, 0);
+ SetOptionsDlgToType(hwnd, iExpert);
+ break;
+ } }
+ break;
+ case IDC_OPTIONSTAB:
+ switch (((LPNMHDR)lParam)->code) {
+ case TCN_SELCHANGING:
+ {
+ TCITEM tci;
+ tci.mask = TCIF_PARAM;
+ TabCtrl_GetItem(GetDlgItem(hwnd,IDC_OPTIONSTAB),TabCtrl_GetCurSel(GetDlgItem(hwnd,IDC_OPTIONSTAB)),&tci);
+ ShowWindow((HWND)tci.lParam,SW_HIDE);
+ }
+ break;
+ case TCN_SELCHANGE:
+ {
+ TCITEM tci;
+ tci.mask = TCIF_PARAM;
+ TabCtrl_GetItem(GetDlgItem(hwnd,IDC_OPTIONSTAB),TabCtrl_GetCurSel(GetDlgItem(hwnd,IDC_OPTIONSTAB)),&tci);
+ ShowWindow((HWND)tci.lParam,SW_SHOW);
+ break;
+ } }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+int JabberOptInit( WPARAM wParam, LPARAM lParam )
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ HMODULE hUxTheme = 0;
+
+ if(IsWinVerXPPlus()) {
+ hUxTheme = GetModuleHandle(_T("uxtheme.dll"));
+
+ if(hUxTheme)
+ pfnEnableThemeDialogTexture = (BOOL (WINAPI *)(HANDLE, DWORD))GetProcAddress(hUxTheme, "EnableThemeDialogTexture");
+ }
+
+ odp.cbSize = sizeof( odp );
+ odp.hInstance = hInst;
+ odp.pszGroup = "Network";
+ odp.pszTemplate = MAKEINTRESOURCEA( IDD_OPT_JABBERMAIN );
+ odp.pszTitle = jabberModuleName;
+ odp.pfnDlgProc = OptionsDlgProc;
+ odp.flags = ODPF_BOLDGROUPS;
+ JCallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_password.cpp b/miranda-wine/protocols/JabberG/jabber_password.cpp
new file mode 100644
index 0000000..da4c4c2
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_password.cpp
@@ -0,0 +1,100 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_password.cpp,v $
+Revision : $Revision: 3351 $
+Last change on : $Date: 2006-07-21 00:31:42 +0400 (Птн, 21 Июл 2006) $
+Last change by : $Author: rainwater $
+
+*/
+
+#include "jabber.h"
+#include "jabber_iq.h"
+#include "resource.h"
+
+static BOOL CALLBACK JabberChangePasswordDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam );
+
+int JabberMenuHandleChangePassword( WPARAM wParam, LPARAM lParam )
+{
+ if ( IsWindow( hwndJabberChangePassword ))
+ SetForegroundWindow( hwndJabberChangePassword );
+ else {
+ hwndJabberChangePassword = CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_CHANGEPASSWORD ), NULL, JabberChangePasswordDlgProc, 0 );
+ }
+
+ return 0;
+}
+
+static BOOL CALLBACK JabberChangePasswordDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ SendMessage( hwndDlg, WM_SETICON, ICON_BIG, ( LPARAM )LoadIcon( hInst, MAKEINTRESOURCE( IDI_KEYS )) );
+ TranslateDialogDefault( hwndDlg );
+ if ( jabberOnline && jabberThreadInfo!=NULL ) {
+ TCHAR text[128];
+ mir_sntprintf( text, SIZEOF( text ), _T("%s %s@") _T(TCHAR_STR_PARAM), TranslateT( "Set New Password for" ), jabberThreadInfo->username, jabberThreadInfo->server );
+ SetWindowText( hwndDlg, text );
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDOK:
+ if ( jabberOnline && jabberThreadInfo!=NULL ) {
+ char newPasswd[128], text[128];
+ GetDlgItemTextA( hwndDlg, IDC_NEWPASSWD, newPasswd, SIZEOF( newPasswd ));
+ GetDlgItemTextA( hwndDlg, IDC_NEWPASSWD2, text, SIZEOF( text ));
+ if ( strcmp( newPasswd, text )) {
+ MessageBox( hwndDlg, TranslateT( "New password does not match." ), TranslateT( "Change Password" ), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND );
+ break;
+ }
+ GetDlgItemTextA( hwndDlg, IDC_OLDPASSWD, text, SIZEOF( text ));
+ if ( strcmp( text, jabberThreadInfo->password )) {
+ MessageBox( hwndDlg, TranslateT( "Current password is incorrect." ), TranslateT( "Change Password" ), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND );
+ break;
+ }
+ strncpy( jabberThreadInfo->newPassword, newPasswd, SIZEOF( jabberThreadInfo->newPassword ));
+
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultSetPassword );
+
+ XmlNodeIq iq( "set", iqId, jabberThreadInfo->server );
+ XmlNode* q = iq.addQuery( "jabber:iq:register" );
+ q->addChild( "username", jabberThreadInfo->username );
+ q->addChild( "password", newPasswd );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+ DestroyWindow( hwndDlg );
+ break;
+ case IDCANCEL:
+ DestroyWindow( hwndDlg );
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ DestroyWindow( hwndDlg );
+ break;
+ case WM_DESTROY:
+ hwndJabberChangePassword = NULL;
+ break;
+ }
+
+ return FALSE;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_proxy.cpp b/miranda-wine/protocols/JabberG/jabber_proxy.cpp
new file mode 100644
index 0000000..51fae58
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_proxy.cpp
@@ -0,0 +1,154 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_proxy.cpp,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#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 JCallService( 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;
+}
+
+#if 0
+int icq_httpGatewayWrapSend( HANDLE hConn, PBYTE buf, int len, int flags, MIRANDASERVICE pfnNetlibSend )
+{
+ icq_packet packet;
+ int sendResult;
+
+ packet.wLen = len;
+ write_httphdr( &packet, HTTP_PACKETTYPE_FLAP );
+ packString( &packet, buf, ( WORD )len );
+ sendResult = Netlib_Send( hConn, packet.pData, packet.wLen, flags );
+ mir_free( packet.pData );
+ if( sendResult <= 0 )
+ return sendResult;
+ if( sendResult < 14 )
+ return 0;
+ return sendResult - 14;
+}
+
+PBYTE icq_httpGatewayUnwrapRecv( 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/miranda-wine/protocols/JabberG/jabber_proxy.h b/miranda-wine/protocols/JabberG/jabber_proxy.h
new file mode 100644
index 0000000..02a5d9f
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_proxy.h
@@ -0,0 +1,34 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_proxy.h,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#ifndef _JABBER_PROXY_H_
+#define _JABBER_PROXY_H_
+
+int JabberHttpGatewayInit( HANDLE hConn, NETLIBOPENCONNECTION *nloc, NETLIBHTTPREQUEST *nlhr );
+int JabberHttpGatewayBegin( HANDLE hConn, NETLIBOPENCONNECTION *nloc );
+
+#endif \ No newline at end of file
diff --git a/miranda-wine/protocols/JabberG/jabber_ssl.cpp b/miranda-wine/protocols/JabberG/jabber_ssl.cpp
new file mode 100644
index 0000000..5c7f23b
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_ssl.cpp
@@ -0,0 +1,181 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_ssl.cpp,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#define _JABBER_SSL_C_
+
+#include "jabber.h"
+#include "jabber_ssl.h"
+
+PFN_SSL_int_void pfn_SSL_library_init; // int SSL_library_init()
+PFN_SSL_pvoid_void pfn_SSLv23_client_method; // SSL_METHOD *SSLv23_client_method()
+PFN_SSL_pvoid_pvoid pfn_SSL_CTX_new; // SSL_CTX *SSL_CTX_new( SSL_METHOD *method )
+PFN_SSL_void_pvoid pfn_SSL_CTX_free; // void SSL_CTX_free( SSL_CTX *ctx );
+PFN_SSL_pvoid_pvoid pfn_SSL_new; // SSL *SSL_new( SSL_CTX *ctx )
+PFN_SSL_void_pvoid pfn_SSL_free; // void SSL_free( SSL *ssl );
+PFN_SSL_int_pvoid_int pfn_SSL_set_fd; // int SSL_set_fd( SSL *ssl, int fd );
+PFN_SSL_int_pvoid pfn_SSL_connect; // int SSL_connect( SSL *ssl );
+PFN_SSL_int_pvoid_pvoid_int pfn_SSL_read; // int SSL_read( SSL *ssl, void *buffer, int bufsize )
+PFN_SSL_int_pvoid_pvoid_int pfn_SSL_write; // int SSL_write( SSL *ssl, void *buffer, int bufsize )
+
+static CRITICAL_SECTION sslHandleMutex;
+static JABBER_SSL_MAPPING *sslHandleList = NULL;
+static int sslHandleCount = 0;
+
+BOOL JabberSslInit()
+{
+ BOOL error = FALSE;
+
+ sslHandleList = NULL;
+ sslHandleCount = 0;
+ InitializeCriticalSection( &sslHandleMutex );
+
+ hLibSSL = LoadLibraryA( "SSLEAY32.DLL" );
+
+ if ( !hLibSSL )
+ hLibSSL = LoadLibraryA( "LIBSSL32.DLL" );
+
+ if ( hLibSSL ) {
+ if (( pfn_SSL_library_init=( PFN_SSL_int_void )GetProcAddress( hLibSSL, "SSL_library_init" )) == NULL )
+ error = TRUE;
+ if (( pfn_SSLv23_client_method=( PFN_SSL_pvoid_void )GetProcAddress( hLibSSL, "SSLv23_client_method" )) == NULL )
+ error = TRUE;
+ if (( pfn_SSL_CTX_new=( PFN_SSL_pvoid_pvoid )GetProcAddress( hLibSSL, "SSL_CTX_new" )) == NULL )
+ error = TRUE;
+ if (( pfn_SSL_CTX_free=( PFN_SSL_void_pvoid )GetProcAddress( hLibSSL, "SSL_CTX_free" )) == NULL )
+ error = TRUE;
+ if (( pfn_SSL_new=( PFN_SSL_pvoid_pvoid )GetProcAddress( hLibSSL, "SSL_new" )) == NULL )
+ error = TRUE;
+ if (( pfn_SSL_free=( PFN_SSL_void_pvoid )GetProcAddress( hLibSSL, "SSL_free" )) == NULL )
+ error = TRUE;
+ if (( pfn_SSL_set_fd=( PFN_SSL_int_pvoid_int )GetProcAddress( hLibSSL, "SSL_set_fd" )) == NULL )
+ error = TRUE;
+ if (( pfn_SSL_connect=( PFN_SSL_int_pvoid )GetProcAddress( hLibSSL, "SSL_connect" )) == NULL )
+ error = TRUE;
+ if (( pfn_SSL_read=( PFN_SSL_int_pvoid_pvoid_int )GetProcAddress( hLibSSL, "SSL_read" )) == NULL )
+ error = TRUE;
+ if (( pfn_SSL_write=( PFN_SSL_int_pvoid_pvoid_int )GetProcAddress( hLibSSL, "SSL_write" )) == NULL )
+ error = TRUE;
+
+ if ( error == TRUE ) {
+ FreeLibrary( hLibSSL );
+ hLibSSL = NULL;
+ }
+ }
+
+
+#ifdef _DEBUG
+ if ( hLibSSL )
+ JabberLog( "SSL library load successful" );
+ else
+ JabberLog( "SSL library cannot load" );
+#endif
+
+ if ( hLibSSL ) {
+ pfn_SSL_library_init();
+ jabberSslCtx = pfn_SSL_CTX_new( pfn_SSLv23_client_method());
+
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+void JabberSslUninit()
+{
+ if ( hLibSSL ) {
+ pfn_SSL_CTX_free( jabberSslCtx );
+
+ JabberLog( "Free SSL library" );
+ FreeLibrary( hLibSSL );
+ hLibSSL = NULL;
+ }
+
+ if ( sslHandleList ) mir_free( sslHandleList );
+ sslHandleCount = 0;
+ DeleteCriticalSection( &sslHandleMutex );
+}
+
+int JabberSslFindHandle( HANDLE hConn )
+{
+ int i;
+
+ EnterCriticalSection( &sslHandleMutex );
+ for ( i=0; i<sslHandleCount; i++ ) {
+ if ( sslHandleList[i].h == hConn ) {
+ LeaveCriticalSection( &sslHandleMutex );
+ return i;
+ }
+ }
+ LeaveCriticalSection( &sslHandleMutex );
+ return -1;
+}
+
+PVOID JabberSslHandleToSsl( HANDLE hConn )
+{
+ int i;
+
+ EnterCriticalSection( &sslHandleMutex );
+ for ( i=0; i<sslHandleCount; i++ ) {
+ if ( sslHandleList[i].h == hConn ) {
+ LeaveCriticalSection( &sslHandleMutex );
+ return sslHandleList[i].ssl;
+ }
+ }
+ LeaveCriticalSection( &sslHandleMutex );
+ return NULL;
+}
+
+void JabberSslAddHandle( HANDLE hConn, PVOID ssl )
+{
+ EnterCriticalSection( &sslHandleMutex );
+ if ( JabberSslFindHandle( hConn ) >= 0 ) {
+ LeaveCriticalSection( &sslHandleMutex );
+ return;
+ }
+
+ sslHandleList = ( JABBER_SSL_MAPPING * ) mir_realloc( sslHandleList, ( sslHandleCount+1 )*sizeof( JABBER_SSL_MAPPING ));
+ sslHandleList[sslHandleCount].h = hConn;
+ sslHandleList[sslHandleCount].ssl = ssl;
+ sslHandleCount++;
+ LeaveCriticalSection( &sslHandleMutex );
+}
+
+void JabberSslRemoveHandle( HANDLE hConn )
+{
+ int i;
+
+ EnterCriticalSection( &sslHandleMutex );
+ if (( i=JabberSslFindHandle( hConn )) < 0 ) {
+ LeaveCriticalSection( &sslHandleMutex );
+ return;
+ }
+
+ sslHandleCount--;
+ memmove( sslHandleList+i, sslHandleList+i+1, ( sslHandleCount-i )*sizeof( JABBER_SSL_MAPPING ));
+ sslHandleList = ( JABBER_SSL_MAPPING * ) mir_realloc( sslHandleList, sslHandleCount*sizeof( JABBER_SSL_MAPPING ));
+ LeaveCriticalSection( &sslHandleMutex );
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_ssl.h b/miranda-wine/protocols/JabberG/jabber_ssl.h
new file mode 100644
index 0000000..5832b40
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_ssl.h
@@ -0,0 +1,64 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_ssl.h,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#ifndef _JABBER_SSL_H_
+#define _JABBER_SSL_H_
+
+typedef int ( *PFN_SSL_int_void ) ( void );
+typedef PVOID ( *PFN_SSL_pvoid_void ) ( void );
+typedef PVOID ( *PFN_SSL_pvoid_pvoid ) ( PVOID );
+typedef void ( *PFN_SSL_void_pvoid ) ( PVOID );
+typedef int ( *PFN_SSL_int_pvoid_int ) ( PVOID, int );
+typedef int ( *PFN_SSL_int_pvoid ) ( PVOID );
+typedef int ( *PFN_SSL_int_pvoid_pvoid_int ) ( PVOID, PVOID, int );
+
+#ifndef _JABBER_SSL_C_
+extern PFN_SSL_int_void pfn_SSL_library_init; // int SSL_library_init()
+extern PFN_SSL_pvoid_void pfn_SSLv23_client_method; // SSL_METHOD *SSLv23_client_method()
+extern PFN_SSL_pvoid_pvoid pfn_SSL_CTX_new; // SSL_CTX *SSL_CTX_new( SSL_METHOD *method )
+extern PFN_SSL_void_pvoid pfn_SSL_CTX_free; // void SSL_CTX_free( SSL_CTX *ctx );
+extern PFN_SSL_pvoid_pvoid pfn_SSL_new; // SSL *SSL_new( SSL_CTX *ctx )
+extern PFN_SSL_void_pvoid pfn_SSL_free; // void SSL_free( SSL *ssl );
+extern PFN_SSL_int_pvoid_int pfn_SSL_set_fd; // int SSL_set_fd( SSL *ssl, int fd );
+extern PFN_SSL_int_pvoid pfn_SSL_connect; // int SSL_connect( SSL *ssl );
+extern PFN_SSL_int_pvoid_pvoid_int pfn_SSL_read; // int SSL_read( SSL *ssl, void *buffer, int bufsize )
+extern PFN_SSL_int_pvoid_pvoid_int pfn_SSL_write; // int SSL_write( SSL *ssl, void *buffer, int bufsize )
+#endif
+
+typedef struct {
+ HANDLE h;
+ PVOID ssl;
+} JABBER_SSL_MAPPING;
+
+BOOL JabberSslInit();
+void JabberSslUninit();
+int JabberSslFindHandle( HANDLE hConn );
+PVOID JabberSslHandleToSsl( HANDLE hConn );
+void JabberSslAddHandle( HANDLE hConn, PVOID ssl );
+void JabberSslRemoveHandle( HANDLE hConn );
+
+#endif
diff --git a/miranda-wine/protocols/JabberG/jabber_std.cpp b/miranda-wine/protocols/JabberG/jabber_std.cpp
new file mode 100644
index 0000000..562beda
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_std.cpp
@@ -0,0 +1,171 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright ( c ) 2003-5 George Hazan.
+Copyright ( c ) 2002-3 Richard Hughes ( original version ).
+
+Miranda IM: the mir_free icq client for MS Windows
+Copyright ( C ) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or ( at your option ) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_std.cpp,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+
+HANDLE __stdcall JCreateServiceFunction(
+ const char* szService,
+ MIRANDASERVICE serviceProc )
+{
+ char str[ MAXMODULELABELLENGTH ];
+ strcpy( str, jabberProtoName );
+ strcat( str, szService );
+ return CreateServiceFunction( str, serviceProc );
+}
+
+HANDLE __stdcall JCreateHookableEvent(
+ const char* szService )
+{
+ char str[ MAXMODULELABELLENGTH ];
+ strcpy( str, jabberProtoName );
+ strcat( str, szService );
+ return CreateHookableEvent( str );
+}
+
+#if !defined( _DEBUG )
+int __stdcall JCallService( const char* szSvcName, WPARAM wParam, LPARAM lParam )
+{
+ return CallService( szSvcName, wParam, lParam );
+}
+#endif
+
+void __stdcall JDeleteSetting( HANDLE hContact, const char* valueName )
+{
+ DBDeleteContactSetting( hContact, jabberProtoName, valueName );
+}
+
+DWORD __stdcall JGetByte( const char* valueName, int parDefltValue )
+{
+ return DBGetContactSettingByte( NULL, jabberProtoName, valueName, parDefltValue );
+}
+
+DWORD __stdcall JGetByte( HANDLE hContact, const char* valueName, int parDefltValue )
+{
+ return DBGetContactSettingByte( hContact, jabberProtoName, valueName, parDefltValue );
+}
+
+char* __stdcall JGetContactName( HANDLE hContact )
+{
+ return ( char* )JCallService( MS_CLIST_GETCONTACTDISPLAYNAME, WPARAM( hContact ), 0 );
+}
+
+DWORD __stdcall JGetDword( HANDLE hContact, const char* valueName, DWORD parDefltValue )
+{
+ return DBGetContactSettingDword( hContact, jabberProtoName, valueName, parDefltValue );
+}
+
+int __stdcall 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 = jabberProtoName;
+ sVal.szSetting = valueName;
+ if ( JCallService( MS_DB_CONTACT_GETSETTINGSTATIC, ( WPARAM )hContact, ( LPARAM )&sVal ) != 0 )
+ return 1;
+
+ return ( dbv.type != DBVT_ASCIIZ );
+}
+
+int __stdcall JGetStringUtf( HANDLE hContact, char* valueName, DBVARIANT* dbv )
+{
+ return DBGetContactSettingStringUtf( hContact, jabberProtoName, valueName, dbv );
+}
+
+int __stdcall JGetStringT( HANDLE hContact, char* valueName, DBVARIANT* dbv )
+{
+ return DBGetContactSettingTString( hContact, jabberProtoName, valueName, dbv );
+}
+
+WORD __stdcall JGetWord( HANDLE hContact, const char* valueName, int parDefltValue )
+{
+ return DBGetContactSettingWord( hContact, jabberProtoName, valueName, parDefltValue );
+}
+
+void __fastcall JFreeVariant( DBVARIANT* dbv )
+{
+ DBFreeVariant( dbv );
+}
+
+int __stdcall JSendBroadcast( HANDLE hContact, int type, int result, HANDLE hProcess, LPARAM lParam )
+{
+ ACKDATA ack = {0};
+ ack.cbSize = sizeof( ACKDATA );
+ ack.szModule = jabberProtoName;
+ ack.hContact = hContact;
+ ack.type = type;
+ ack.result = result;
+ ack.hProcess = hProcess;
+ ack.lParam = lParam;
+ return JCallService( MS_PROTO_BROADCASTACK, 0, ( LPARAM )&ack );
+}
+
+DWORD __stdcall JSetByte( const char* valueName, int parValue )
+{
+ return DBWriteContactSettingByte( NULL, jabberProtoName, valueName, parValue );
+}
+
+DWORD __stdcall JSetByte( HANDLE hContact, const char* valueName, int parValue )
+{
+ return DBWriteContactSettingByte( hContact, jabberProtoName, valueName, parValue );
+}
+
+DWORD __stdcall JSetDword( HANDLE hContact, const char* valueName, DWORD parValue )
+{
+ return DBWriteContactSettingDword( hContact, jabberProtoName, valueName, parValue );
+}
+
+DWORD __stdcall JSetString( HANDLE hContact, const char* valueName, const char* parValue )
+{
+ return DBWriteContactSettingString( hContact, jabberProtoName, valueName, parValue );
+}
+
+DWORD __stdcall JSetStringT( HANDLE hContact, const char* valueName, const TCHAR* parValue )
+{
+ return DBWriteContactSettingTString( hContact, jabberProtoName, valueName, parValue );
+}
+
+DWORD __stdcall JSetStringUtf( HANDLE hContact, const char* valueName, const char* parValue )
+{
+ return DBWriteContactSettingStringUtf( hContact, jabberProtoName, valueName, parValue );
+}
+
+DWORD __stdcall JSetWord( HANDLE hContact, const char* valueName, int parValue )
+{
+ return DBWriteContactSettingWord( hContact, jabberProtoName, valueName, parValue );
+}
+
+char* __stdcall JTranslate( const char* str )
+{
+ return Translate( str );
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_svc.cpp b/miranda-wine/protocols/JabberG/jabber_svc.cpp
new file mode 100644
index 0000000..16d25a2
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_svc.cpp
@@ -0,0 +1,1431 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_svc.cpp,v $
+Revision : $Revision: 3711 $
+Last change on : $Date: 2006-09-06 12:33:14 +0400 (Срд, 06 Сен 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include <io.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "resource.h"
+#include "jabber_list.h"
+#include "jabber_iq.h"
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberAddToList - adds a contact to the contact list
+
+static HANDLE AddToListByJID( const TCHAR* newJid, DWORD flags )
+{
+ HANDLE hContact;
+ TCHAR* jid, *nick;
+
+ JabberLog( "AddToListByJID jid = " TCHAR_STR_PARAM, newJid );
+
+ if (( hContact=JabberHContactFromJID( newJid )) == NULL ) {
+ // not already there: add
+ jid = mir_tstrdup( newJid );
+ JabberLog( "Add new jid to contact jid = " TCHAR_STR_PARAM, jid );
+ hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_ADD, 0, 0 );
+ JCallService( MS_PROTO_ADDTOCONTACT, ( WPARAM ) hContact, ( LPARAM )jabberProtoName );
+ 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 );
+ }
+
+ return hContact;
+}
+
+int JabberAddToList( WPARAM wParam, LPARAM lParam )
+{
+ JABBER_SEARCH_RESULT* jsr = ( JABBER_SEARCH_RESULT * ) lParam;
+ if ( jsr->hdr.cbSize != sizeof( JABBER_SEARCH_RESULT ))
+ return ( int )NULL;
+
+ return ( int )AddToListByJID( jsr->jid, wParam ); // wParam is flag e.g. PALF_TEMPORARY
+}
+
+int JabberAddToListByEvent( WPARAM wParam, LPARAM lParam )
+{
+ DBEVENTINFO dbei;
+ HANDLE hContact;
+ char* nick, *firstName, *lastName, *jid;
+
+ JabberLog( "AddToListByEvent" );
+ ZeroMemory( &dbei, sizeof( dbei ));
+ dbei.cbSize = sizeof( dbei );
+ if (( dbei.cbBlob=JCallService( MS_DB_EVENT_GETBLOBSIZE, lParam, 0 )) == ( DWORD )( -1 ))
+ return ( int )( HANDLE ) NULL;
+ if (( dbei.pBlob=( PBYTE ) alloca( dbei.cbBlob )) == NULL )
+ return ( int )( HANDLE ) NULL;
+ if ( JCallService( MS_DB_EVENT_GET, lParam, ( LPARAM )&dbei ))
+ return ( int )( HANDLE ) NULL;
+ if ( strcmp( dbei.szModule, jabberProtoName ))
+ return ( int )( HANDLE ) 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 ( int )( HANDLE ) NULL;
+
+ nick = ( char* )( dbei.pBlob + sizeof( DWORD )+ sizeof( HANDLE ));
+ firstName = nick + strlen( nick ) + 1;
+ lastName = firstName + strlen( firstName ) + 1;
+ jid = lastName + strlen( lastName ) + 1;
+
+ #if defined( _UNICODE )
+ TCHAR* newJid = a2u( jid );
+ #else
+ TCHAR* newJid = mir_strdup( jid );
+ #endif
+ hContact = ( HANDLE ) AddToListByJID( newJid, wParam );
+ mir_free( newJid );
+ return ( int ) hContact;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberAuthAllow - processes the successful authorization
+
+int JabberAuthAllow( WPARAM wParam, LPARAM lParam )
+{
+ DBEVENTINFO dbei;
+ char* nick, *firstName, *lastName, *jid;
+
+ if ( !jabberOnline )
+ return 1;
+
+ memset( &dbei, sizeof( dbei ), 0 );
+ dbei.cbSize = sizeof( dbei );
+ if (( dbei.cbBlob=JCallService( MS_DB_EVENT_GETBLOBSIZE, wParam, 0 )) == ( DWORD )( -1 ))
+ return 1;
+ if (( dbei.pBlob=( PBYTE )alloca( dbei.cbBlob )) == NULL )
+ return 1;
+ if ( JCallService( MS_DB_EVENT_GET, wParam, ( LPARAM )&dbei ))
+ return 1;
+ if ( dbei.eventType != EVENTTYPE_AUTHREQUEST )
+ return 1;
+ if ( strcmp( dbei.szModule, jabberProtoName ))
+ return 1;
+
+ nick = ( char* )( dbei.pBlob + sizeof( DWORD )+ sizeof( HANDLE ));
+ firstName = nick + strlen( nick ) + 1;
+ lastName = firstName + strlen( firstName ) + 1;
+ jid = lastName + strlen( lastName ) + 1;
+
+ JabberLog( "Send 'authorization allowed' to " TCHAR_STR_PARAM, jid );
+
+ XmlNode presence( "presence" ); presence.addAttr( "to", jid ); presence.addAttr( "type", "subscribed" );
+ JabberSend( jabberThreadInfo->s, presence );
+
+ #if defined( _UNICODE )
+ TCHAR* newJid = a2u( jid );
+ #else
+ TCHAR* newJid = mir_strdup( jid );
+ #endif
+
+ // Automatically add this user to my roster if option is enabled
+ if ( JGetByte( "AutoAdd", TRUE ) == TRUE ) {
+ HANDLE hContact;
+ JABBER_LIST_ITEM *item;
+
+ if (( item = JabberListGetItemPtr( LIST_ROSTER, newJid )) == NULL || ( item->subscription != SUB_BOTH && item->subscription != SUB_TO )) {
+ JabberLog( "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 JabberAuthDeny( WPARAM wParam, LPARAM lParam )
+{
+ DBEVENTINFO dbei;
+ char* nick, *firstName, *lastName, *jid;
+
+ if ( !jabberOnline )
+ return 1;
+
+ JabberLog( "Entering AuthDeny" );
+ memset( &dbei, sizeof( dbei ), 0 );
+ dbei.cbSize = sizeof( dbei );
+ if (( dbei.cbBlob=JCallService( MS_DB_EVENT_GETBLOBSIZE, wParam, 0 )) == ( DWORD )( -1 ))
+ return 1;
+ if (( dbei.pBlob=( PBYTE ) mir_alloc( dbei.cbBlob )) == NULL )
+ return 1;
+ if ( JCallService( MS_DB_EVENT_GET, wParam, ( LPARAM )&dbei )) {
+ mir_free( dbei.pBlob );
+ return 1;
+ }
+ if ( dbei.eventType != EVENTTYPE_AUTHREQUEST ) {
+ mir_free( dbei.pBlob );
+ return 1;
+ }
+ if ( strcmp( dbei.szModule, jabberProtoName )) {
+ mir_free( dbei.pBlob );
+ return 1;
+ }
+
+ nick = ( char* )( dbei.pBlob + sizeof( DWORD )+ sizeof( HANDLE ));
+ firstName = nick + strlen( nick ) + 1;
+ lastName = firstName + strlen( firstName ) + 1;
+ jid = lastName + strlen( lastName ) + 1;
+
+ JabberLog( "Send 'authorization denied' to " TCHAR_STR_PARAM, jid );
+
+ XmlNode presence( "presence" ); presence.addAttr( "to", jid ); presence.addAttr( "type", "unsubscribed" );
+ JabberSend( jabberThreadInfo->s, presence );
+
+ mir_free( dbei.pBlob );
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberBasicSearch - searches the contact by JID
+
+struct JABBER_SEARCH_BASIC
+{ int hSearch;
+ char jid[128];
+};
+
+static void __cdecl JabberBasicSearchThread( JABBER_SEARCH_BASIC *jsb )
+{
+ SleepEx( 100, TRUE );
+
+ JABBER_SEARCH_RESULT jsr = { 0 };
+ jsr.hdr.cbSize = sizeof( JABBER_SEARCH_RESULT );
+ jsr.hdr.nick = "";
+ jsr.hdr.firstName = "";
+ jsr.hdr.lastName = "";
+ jsr.hdr.email = jsb->jid;
+ #if defined( _UNICODE )
+ TCHAR* jid = a2u(jsb->jid);
+ _tcsncpy( jsr.jid, jid, SIZEOF( jsr.jid ));
+ mir_free( jid );
+ #else
+ strncpy( jsr.jid, jsb->jid, SIZEOF( jsr.jid ));
+ #endif
+ 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 );
+}
+
+int JabberBasicSearch( WPARAM wParam, LPARAM lParam )
+{
+ char* szJid = ( char* )lParam;
+ JabberLog( "JabberBasicSearch called with lParam = " TCHAR_STR_PARAM, szJid );
+
+ JABBER_SEARCH_BASIC *jsb;
+ if ( !jabberOnline || ( jsb=( JABBER_SEARCH_BASIC * ) mir_alloc( sizeof( JABBER_SEARCH_BASIC )) )==NULL )
+ return 0;
+
+ jsb->hSearch = JabberSerialNext();
+ if ( strchr( szJid, '@' ) == NULL ) {
+ char szServer[ 100 ];
+ if ( JGetStaticString( "LoginServer", NULL, szServer, sizeof szServer ))
+ strcpy( szServer, "jabber.org" );
+
+ mir_snprintf( jsb->jid, SIZEOF(jsb->jid), "%s@%s", szJid, szServer );
+ }
+ else strncpy( jsb->jid, szJid, SIZEOF(jsb->jid));
+
+ JabberForkThread(( JABBER_THREAD_FUNC )JabberBasicSearchThread, 0, jsb );
+ return jsb->hSearch;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberContactDeleted - processes a contact deletion
+
+int JabberContactDeleted( WPARAM wParam, LPARAM lParam )
+{
+ if( !jabberOnline ) // should never happen
+ return 0;
+
+ char* szProto = ( char* )JCallService( MS_PROTO_GETCONTACTBASEPROTO, wParam, 0 );
+ if ( szProto==NULL || strcmp( szProto, jabberProtoName ))
+ return 0;
+
+ DBVARIANT dbv;
+ if ( !JGetStringT(( HANDLE ) wParam, JGetByte( (HANDLE ) wParam, "ChatRoom", 0 )?"ChatRoomID":"jid", &dbv )) {
+ TCHAR* jid, *p, *q = NULL;
+
+ jid = dbv.ptszVal;
+ if (( p = _tcschr( jid, '@' )) != NULL )
+ if (( q = _tcschr( p, '/' )) != NULL )
+ *q = '\0';
+
+ if ( !JabberListExist( LIST_CHATROOM, jid ) || q == NULL )
+ if ( JabberListExist( LIST_ROSTER, jid )) {
+ // Remove from roster, server also handles the presence unsubscription process.
+ XmlNodeIq iq( "set" );
+ XmlNode* query = iq.addQuery( "jabber:iq:roster" );
+ XmlNode* item = query->addChild( "item" ); item->addAttr( "jid", jid ); item->addAttr( "subscription", "remove" );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+
+ JFreeVariant( &dbv );
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberDbSettingChanged - process database changes
+
+static TCHAR* sttSettingToTchar( DBCONTACTWRITESETTING* cws )
+{
+ switch( cws->value.type ) {
+ case DBVT_ASCIIZ:
+ #if defined( _UNICODE )
+ return a2u( cws->value.pszVal );
+ #else
+ return mir_strdup( cws->value.pszVal );
+ #endif
+
+ case DBVT_UTF8:
+ #if defined( _UNICODE )
+ { TCHAR* result;
+ JabberUtf8Decode( NEWSTR_ALLOCA(cws->value.pszVal), &result );
+ return result;
+ }
+ #else
+ return mir_strdup( JabberUtf8Decode( NEWSTR_ALLOCA(cws->value.pszVal), NULL ));
+ #endif
+ }
+ return NULL;
+}
+
+static void sttRenameGroup( DBCONTACTWRITESETTING* cws, HANDLE hContact )
+{
+ DBVARIANT jid, dbv;
+ if ( JGetStringT( hContact, "jid", &jid ))
+ return;
+
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( 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 ) {
+ JabberLog( "Group set to nothing" );
+ JabberAddContactToRoster( item->jid, nick, NULL, item->subscription );
+ }
+ }
+ else {
+ TCHAR* p = sttSettingToTchar( cws );
+ if ( cws->value.pszVal != NULL && lstrcmp( p, item->group )) {
+ JabberLog( "Group set to " TCHAR_STR_PARAM, p );
+ if ( p )
+ JabberAddContactToRoster( item->jid, nick, p, item->subscription );
+ }
+ mir_free( p );
+ }
+ mir_free( nick );
+}
+
+static void sttRenameContact( DBCONTACTWRITESETTING* cws, HANDLE hContact )
+{
+ DBVARIANT jid;
+ if ( JGetStringT( hContact, "jid", &jid ))
+ return;
+
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_ROSTER, jid.ptszVal );
+ JFreeVariant( &jid );
+ if ( item == NULL )
+ return;
+
+ if ( cws->value.type == DBVT_DELETED ) {
+ TCHAR* nick = ( TCHAR* )JCallService( MS_CLIST_GETCONTACTDISPLAYNAME, ( WPARAM )hContact, GCDNF_NOMYHANDLE | GCDNF_TCHAR );
+ JabberAddContactToRoster( item->jid, nick, item->group, item->subscription );
+ mir_free(nick);
+ return;
+ }
+
+ TCHAR* newNick = sttSettingToTchar( cws );
+ if ( newNick ) {
+ if ( lstrcmp( item->nick, newNick )) {
+ JabberLog( "Renaming contact " TCHAR_STR_PARAM ": " TCHAR_STR_PARAM " -> " TCHAR_STR_PARAM, item->jid, item->nick, newNick );
+ JabberAddContactToRoster( item->jid, newNick, item->group, item->subscription );
+ }
+ mir_free( newNick );
+} }
+
+void sttAddContactForever( 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;
+ JabberLog( "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;
+ }
+
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_ROSTER, jid.ptszVal );
+ JABBER_SUBSCRIPTION subscription = ( item == NULL ) ? SUB_NONE : item->subscription;
+
+ if ( !DBGetContactSettingTString( hContact, "CList", "Group", &dbv )) {
+ JabberAddContactToRoster( jid.ptszVal, nick, dbv.ptszVal, subscription );
+ JFreeVariant( &dbv );
+ }
+ else JabberAddContactToRoster( jid.ptszVal, nick, NULL, subscription );
+
+ XmlNode presence( "presence" ); presence.addAttr( "to", jid.ptszVal ); presence.addAttr( "type", "subscribe" );
+ JabberSend( jabberThreadInfo->s, presence );
+
+ mir_free( nick );
+ DBDeleteContactSetting( hContact, "CList", "Hidden" );
+ JFreeVariant( &jid );
+}
+
+int JabberDbSettingChanged( WPARAM wParam, LPARAM lParam )
+{
+ HANDLE hContact = ( HANDLE ) wParam;
+ if ( hContact == NULL || !jabberConnected )
+ return 0;
+
+ DBCONTACTWRITESETTING* cws = ( DBCONTACTWRITESETTING* )lParam;
+ if ( strcmp( cws->szModule, "CList" ))
+ return 0;
+
+ char* szProto = ( char* )JCallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 );
+ if ( szProto == NULL || strcmp( szProto, jabberProtoName ))
+ return 0;
+
+ if ( !strcmp( cws->szSetting, "Group" ))
+ sttRenameGroup( cws, hContact );
+ else if ( !strcmp( cws->szSetting, "MyHandle" ))
+ sttRenameContact( cws, hContact );
+ else if ( !strcmp( cws->szSetting, "NotOnList" ))
+ sttAddContactForever( cws, hContact );
+
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberFileAllow - starts a file transfer
+
+int JabberFileAllow( WPARAM wParam, LPARAM lParam )
+{
+ if ( !jabberOnline ) return 0;
+
+ CCSDATA *ccs = ( CCSDATA * ) lParam;
+ filetransfer* ft = ( filetransfer* ) ccs->wParam;
+ ft->std.workingDir = mir_strdup(( char* )ccs->lParam );
+ int len = strlen( ft->std.workingDir )-1;
+ if ( ft->std.workingDir[len] == '//' || ft->std.workingDir[len] == '\\' )
+ ft->std.workingDir[len] = 0;
+
+ switch ( ft->type ) {
+ case FT_OOB:
+ JabberForkThread(( JABBER_THREAD_FUNC )JabberFileReceiveThread, 0, ft );
+ break;
+ case FT_BYTESTREAM:
+ JabberFtAcceptSiRequest( ft );
+ break;
+ }
+ return ccs->wParam;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberFileCancel - cancels a file transfer
+
+int JabberFileCancel( WPARAM wParam, LPARAM lParam )
+{
+ CCSDATA *ccs = ( CCSDATA * ) lParam;
+ filetransfer* ft = ( filetransfer* ) ccs->wParam;
+ HANDLE hEvent;
+
+ JabberLog( "Invoking FileCancel()" );
+ if ( ft->type == FT_OOB ) {
+ if ( ft->s ) {
+ JabberLog( "FT canceled" );
+ JabberLog( "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 );
+ }
+ JabberLog( "ft->s is now NULL, ft->state is now FT_ERROR" );
+ }
+ }
+ else JabberFtCancel( ft );
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberFileDeny - denies a file transfer
+
+int JabberFileDeny( WPARAM wParam, LPARAM lParam )
+{
+ if ( !jabberOnline ) return 1;
+
+ CCSDATA *ccs = ( CCSDATA * ) lParam;
+ filetransfer* ft = ( filetransfer* )ccs->wParam;
+
+ XmlNodeIq iq( "error", ft->iqId, ft->jid );
+
+ switch ( ft->type ) {
+ case FT_OOB:
+ { XmlNode* e = iq.addChild( "error", _T("File transfer refused"));
+ e->addAttr( "code", 406 );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+ break;
+ case FT_BYTESTREAM:
+ { XmlNode* e = iq.addChild( "error", _T("File transfer refused"));
+ e->addAttr( "code", 403 ); e->addAttr( "type", "cancel" );
+ XmlNode* f = e->addChild( "forbidden" ); f->addAttr( "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas" );
+ XmlNode* t = f->addChild( "text", "File transfer refused" ); t->addAttr( "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas" );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+ break;
+ }
+ delete ft;
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberFileResume - processes file renaming etc
+
+int JabberFileResume( WPARAM wParam, LPARAM lParam )
+{
+ filetransfer* ft = ( filetransfer* )wParam;
+ if ( !jabberConnected || ft == NULL )
+ return 1;
+
+ PROTOFILERESUME *pfr = (PROTOFILERESUME*)lParam;
+ if ( pfr->action == FILERESUME_RENAME ) {
+ if ( ft->wszFileName != NULL ) {
+ mir_free( ft->wszFileName );
+ ft->wszFileName = NULL;
+ }
+
+ replaceStr( ft->std.currentFile, pfr->szFilename );
+ }
+
+ SetEvent( ft->hWaitEvent );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberGetAvatarInfo - retrieves the avatar info
+
+static int JabberGetAvatarInfo(WPARAM wParam,LPARAM lParam)
+{
+ if ( !JGetByte( "EnableAvatars", TRUE ))
+ return GAIR_NOAVATAR;
+
+ PROTO_AVATAR_INFORMATION* AI = ( PROTO_AVATAR_INFORMATION* )lParam;
+
+ char szHashValue[ MAX_PATH ];
+ if ( JGetStaticString( "AvatarHash", AI->hContact, szHashValue, sizeof szHashValue )) {
+ JabberLog( "No avatar" );
+ return GAIR_NOAVATAR;
+ }
+
+ JabberGetAvatarFileName( AI->hContact, AI->filename, sizeof AI->filename );
+ AI->format = ( AI->hContact == NULL ) ? PA_FORMAT_PNG : JGetByte( AI->hContact, "AvatarType", 0 );
+
+ if ( ::access( AI->filename, 0 ) == 0 ) {
+ char szSavedHash[ 256 ];
+ if ( !JGetStaticString( "AvatarSaved", AI->hContact, szSavedHash, sizeof szSavedHash )) {
+ if ( !strcmp( szSavedHash, szHashValue )) {
+ JabberLog( "Avatar is Ok: %s == %s", szSavedHash, szHashValue );
+ return GAIR_SUCCESS;
+ } } }
+
+ if (( wParam & GAIF_FORCE ) != 0 && AI->hContact != NULL && jabberOnline ) {
+ DBVARIANT dbv;
+ if ( !JGetStringT( AI->hContact, "jid", &dbv )) {
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_ROSTER, dbv.ptszVal );
+ if ( item != NULL ) {
+ TCHAR szJid[ 512 ];
+ BOOL isXVcard = JGetByte(AI->hContact,"AvatarXVcard",0);
+ if ( (item->resourceCount != NULL) & (!isXVcard)){
+ TCHAR *bestResName = JabberListGetBestClientResourceNamePtr(dbv.ptszVal);
+ mir_sntprintf( szJid, SIZEOF( szJid ), bestResName?_T("%s/%s"):_T("%s"), dbv.ptszVal, bestResName );
+ }else
+ lstrcpyn( szJid, dbv.ptszVal, SIZEOF( szJid ));
+
+ JabberLog( "Rereading %s for " TCHAR_STR_PARAM, isXVcard?"vcard-temp":"jabber:iq:avatar", szJid );
+
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultGetAvatar );
+
+ XmlNodeIq iq( "get", iqId, szJid );
+ if (isXVcard) {
+ XmlNode* vs = iq.addChild( "vCard" ); vs->addAttr( "xmlns", "vcard-temp" );
+ } else XmlNode* query = iq.addQuery( isXVcard?"":"jabber:iq:avatar" );
+ JabberSend( jabberThreadInfo->s, iq );
+
+ JFreeVariant( &dbv );
+ return GAIR_WAITFOR;
+ } } }
+
+ JabberLog( "No avatar" );
+ return GAIR_NOAVATAR;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberGetAwayMsg - returns a contact's away message
+
+static void __cdecl JabberGetAwayMsgThread( HANDLE hContact )
+{
+ DBVARIANT dbv;
+ JABBER_LIST_ITEM *item;
+ JABBER_RESOURCE_STATUS *r;
+ int i, len, msgCount;
+
+ if ( !JGetStringT( hContact, "jid", &dbv )) {
+ if (( item=JabberListGetItemPtr( LIST_ROSTER, dbv.ptszVal )) != NULL ) {
+ JFreeVariant( &dbv );
+ if ( item->resourceCount > 0 ) {
+ JabberLog( "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 );
+ } }
+
+ #if defined( _UNICODE )
+ char* msg = u2a(str);
+ #else
+ char* msg = str;
+ #endif
+ JSendBroadcast( hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, ( HANDLE ) 1, ( LPARAM )msg );
+ #if defined( _UNICODE )
+ mir_free(msg);
+ #endif
+ return;
+ }
+
+ if ( item->statusMessage != NULL ) {
+ #if defined( _UNICODE )
+ char* msg = u2a(item->statusMessage);
+ #else
+ char* msg = item->statusMessage;
+ #endif
+ JSendBroadcast( hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, ( HANDLE ) 1, ( LPARAM )msg );
+ #if defined( _UNICODE )
+ mir_free(msg);
+ #endif
+ return;
+ }
+ }
+ else JFreeVariant( &dbv );
+ }
+
+ JSendBroadcast( hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, ( HANDLE ) 1, ( LPARAM )"" );
+}
+
+int JabberGetAwayMsg( WPARAM wParam, LPARAM lParam )
+{
+ CCSDATA *ccs = ( CCSDATA * ) lParam;
+
+ JabberLog( "GetAwayMsg called, wParam=%d lParam=%d", wParam, lParam );
+ JabberForkThread( JabberGetAwayMsgThread, 0, ( void * ) ccs->hContact );
+ return 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberGetCaps - return protocol capabilities bits
+
+int JabberGetCaps( WPARAM wParam, LPARAM lParam )
+{
+ switch( wParam ) {
+ case PFLAGNUM_1:
+ return PF1_IM|PF1_AUTHREQ|PF1_SERVERCLIST|PF1_MODEMSG|PF1_BASICSEARCH|PF1_SEARCHBYEMAIL|PF1_SEARCHBYNAME|PF1_FILE|PF1_VISLIST|PF1_INVISLIST;
+ 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_SUPPORTTYPING | PF4_AVATARS;
+ case PFLAG_UNIQUEIDTEXT:
+ return ( int ) JTranslate( "JID" );
+ case PFLAG_UNIQUEIDSETTING:
+ return ( int ) "jid";
+ }
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberGetInfo - retrieves a contact info
+
+int JabberGetInfo( WPARAM wParam, LPARAM lParam )
+{
+ if ( !jabberOnline )
+ return 1;
+
+ CCSDATA *ccs = ( CCSDATA * ) lParam;
+ int result = 1;
+ DBVARIANT dbv;
+ if ( !JGetStringT( ccs->hContact, "jid", &dbv )) {
+ result = JabberSendGetVcard( dbv.ptszVal );
+ JFreeVariant( &dbv );
+ }
+
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberGetName - returns the protocol name
+
+int JabberGetName( WPARAM wParam, LPARAM lParam )
+{
+ lstrcpynA(( char* )lParam, jabberModuleName, wParam );
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberGetStatus - returns the protocol status
+
+int JabberGetStatus( WPARAM wParam, LPARAM lParam )
+{
+ return jabberStatus;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberLoadIcon - loads an icon for the contact list
+
+int JabberLoadIcon( WPARAM wParam, LPARAM lParam )
+{
+ if (( wParam&0xffff ) == PLI_PROTOCOL )
+ return ( int ) LoadImage( hInst, MAKEINTRESOURCE( IDI_JABBER ), IMAGE_ICON, GetSystemMetrics( wParam&PLIF_SMALL?SM_CXSMICON:SM_CXICON ), GetSystemMetrics( wParam&PLIF_SMALL?SM_CYSMICON:SM_CYICON ), 0 );
+ else
+ return ( int ) ( HICON ) NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberRecvFile - receives a file
+
+int JabberRecvFile( WPARAM wParam, LPARAM lParam )
+{
+ CCSDATA *ccs = ( CCSDATA * ) lParam;
+ PROTORECVEVENT *pre = ( PROTORECVEVENT * ) ccs->lParam;
+ char* szFile = pre->szMessage + sizeof( DWORD );
+ char* szDesc = szFile + strlen( szFile ) + 1;
+ JabberLog( "Description = %s", szDesc );
+
+ DBDeleteContactSetting( ccs->hContact, "CList", "Hidden" );
+
+ DBEVENTINFO dbei = { 0 };
+ dbei.cbSize = sizeof( dbei );
+ dbei.szModule = jabberProtoName;
+ dbei.timestamp = pre->timestamp;
+ dbei.flags = pre->flags & ( PREF_CREATEREAD ? DBEF_READ : 0 );
+ dbei.eventType = EVENTTYPE_FILE;
+ dbei.cbBlob = sizeof( DWORD )+ strlen( szFile ) + strlen( szDesc ) + 2;
+ dbei.pBlob = ( PBYTE ) pre->szMessage;
+ JCallService( MS_DB_EVENT_ADD, ( WPARAM ) ccs->hContact, ( LPARAM )&dbei );
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberRecvMessage - receives a message
+
+int JabberRecvMessage( WPARAM wParam, LPARAM lParam )
+{
+ CCSDATA *ccs = ( CCSDATA* )lParam;
+ PROTORECVEVENT *pre = ( PROTORECVEVENT* )ccs->lParam;
+
+ DBEVENTINFO dbei = { 0 };
+ dbei.cbSize = sizeof( dbei );
+ dbei.szModule = jabberProtoName;
+ dbei.timestamp = pre->timestamp;
+ dbei.flags = pre->flags&PREF_CREATEREAD?DBEF_READ:0;
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ dbei.cbBlob = strlen( pre->szMessage ) + 1;
+ if ( pre->flags & PREF_UNICODE )
+ dbei.cbBlob *= ( sizeof( wchar_t )+1 );
+
+ dbei.pBlob = ( PBYTE ) pre->szMessage;
+ JCallService( MS_DB_EVENT_ADD, ( WPARAM ) ccs->hContact, ( LPARAM )&dbei );
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberSearchByEmail - searches the contact by its e-mail
+
+int JabberSearchByEmail( WPARAM wParam, LPARAM lParam )
+{
+ if ( !jabberOnline ) return 0;
+ if (( char* )lParam == NULL ) return 0;
+
+ char szServerName[100];
+ if ( JGetStaticString( "Jud", NULL, szServerName, sizeof szServerName ))
+ strcpy( szServerName, "users.jabber.org" );
+
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_GETSEARCH, JabberIqResultSetSearch );
+
+ XmlNodeIq iq( "set", iqId, szServerName );
+ XmlNode* query = iq.addQuery( "jabber:iq:search" );
+ query->addChild( "email", ( char* )lParam );
+ JabberSend( jabberThreadInfo->s, iq );
+ return iqId;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberSearchByName - searches the contact by its first or last name, or by a nickname
+
+int JabberSearchByName( WPARAM wParam, LPARAM lParam )
+{
+ if ( !jabberOnline ) return 0;
+
+ PROTOSEARCHBYNAME *psbn = ( PROTOSEARCHBYNAME * ) lParam;
+ BOOL bIsExtFormat = JGetByte( "ExtendedSearch", TRUE );
+
+ char szServerName[100];
+ if ( JGetStaticString( "Jud", NULL, szServerName, sizeof szServerName ))
+ strcpy( szServerName, "users.jabber.org" );
+
+ int iqId = JabberSerialNext();
+ XmlNodeIq iq( "set", iqId, szServerName );
+ XmlNode* query = iq.addChild( "query" ), *field, *x;
+ query->addAttr( "xmlns", "jabber:iq:search" );
+
+ if ( bIsExtFormat ) {
+ JabberIqAdd( iqId, IQ_PROC_GETSEARCH, JabberIqResultExtSearch );
+
+ iq.addAttr( "xml:lang", "en" );
+ x = query->addChild( "x" ); x->addAttr( "xmlns", "jabber:x:data" ); x->addAttr( "type", "submit" );
+ }
+ else JabberIqAdd( iqId, IQ_PROC_GETSEARCH, JabberIqResultSetSearch );
+
+ if ( psbn->pszNick[0] != '\0' ) {
+ if ( bIsExtFormat ) {
+ field = x->addChild( "field" ); field->addAttr( "var", "user" );
+ field->addChild( "value", psbn->pszNick );
+ }
+ else query->addChild( "nick", psbn->pszNick );
+ }
+
+ if ( psbn->pszFirstName[0] != '\0' ) {
+ if ( bIsExtFormat ) {
+ field = x->addChild( "field" ); field->addAttr( "var", "fn" );
+ field->addChild( "value", psbn->pszFirstName );
+ }
+ else query->addChild( "first", psbn->pszFirstName );
+ }
+
+ if ( psbn->pszLastName[0] != '\0' ) {
+ if ( bIsExtFormat ) {
+ field = x->addChild( "field" ); field->addAttr( "var", "given" );
+ field->addChild( "value", psbn->pszLastName );
+ }
+ else query->addChild( "last", psbn->pszLastName );
+ }
+
+ JabberSend( jabberThreadInfo->s, iq );
+ return iqId;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberSendFile - sends a file
+
+int JabberSendFile( WPARAM wParam, LPARAM lParam )
+{
+ if ( !jabberOnline ) return 0;
+
+ CCSDATA *ccs = ( CCSDATA * ) lParam;
+ if ( JGetWord( ccs->hContact, "Status", ID_STATUS_OFFLINE ) == ID_STATUS_OFFLINE )
+ return 0;
+
+ DBVARIANT dbv;
+ if ( JGetStringT( ccs->hContact, "jid", &dbv ))
+ return 0;
+
+ char* *files = ( char* * ) ccs->lParam;
+ int i, j;
+ struct _stat statbuf;
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_ROSTER, dbv.ptszVal );
+ if ( item == NULL )
+ return 0;
+
+ // Check if another file transfer session request is pending ( waiting for disco result )
+ if ( item->ft != NULL ) return 0;
+
+ filetransfer* ft = new filetransfer;
+ ft->std.hContact = ccs->hContact;
+ while( files[ ft->std.totalFiles ] != NULL )
+ ft->std.totalFiles++;
+
+ ft->std.files = ( char** ) mir_alloc( sizeof( char* )* ft->std.totalFiles );
+ ft->fileSize = ( long* ) mir_alloc( sizeof( long ) * ft->std.totalFiles );
+ for( i=j=0; i < ft->std.totalFiles; i++ ) {
+ if ( _stat( files[i], &statbuf ))
+ JabberLog( "'%s' is an invalid filename", files[i] );
+ else {
+ ft->std.files[j] = mir_strdup( files[i] );
+ ft->fileSize[j] = statbuf.st_size;
+ j++;
+ ft->std.totalBytes += statbuf.st_size;
+ } }
+
+ ft->std.currentFile = mir_strdup( files[0] );
+ ft->szDescription = mir_strdup(( char* )ccs->wParam );
+ ft->jid = mir_tstrdup( dbv.ptszVal );
+ JFreeVariant( &dbv );
+
+ if (( item->cap & CLIENT_CAP_READY ) == 0 ) {
+ int iqId;
+ TCHAR* rs;
+
+ // Probe client capability
+ if (( rs=JabberListGetBestClientResourceNamePtr( item->jid )) != NULL ) {
+ item->ft = ft;
+ iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultDiscoClientInfo );
+
+ TCHAR jid[ 200 ];
+ mir_sntprintf( jid, SIZEOF(jid), _T("%s/%s"), item->jid, rs );
+ XmlNodeIq iq( "get", iqId, jid );
+ XmlNode* query = iq.addQuery( "http://jabber.org/protocol/disco#info" );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+ }
+ else if (( item->cap & CLIENT_CAP_FILE ) && ( item->cap & CLIENT_CAP_BYTESTREAM ))
+ // Use the new standard file transfer
+ JabberFtInitiate( item->jid, ft );
+ else // Use the jabber:iq:oob file transfer
+ JabberForkThread(( JABBER_THREAD_FUNC )JabberFileServerThread, 0, ft );
+
+ return ( int )( HANDLE ) ft;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberSendMessage - sends a message
+
+static void __cdecl JabberSendMessageAckThread( HANDLE hContact )
+{
+ SleepEx( 10, TRUE );
+ JabberLog( "Broadcast ACK" );
+ JSendBroadcast( hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, ( HANDLE ) 1, 0 );
+ JabberLog( "Returning from thread" );
+}
+
+static char PGP_PROLOG[] = "-----BEGIN PGP MESSAGE-----\r\n\r\n";
+static char PGP_EPILOG[] = "\r\n-----END PGP MESSAGE-----\r\n";
+
+int JabberSendMessage( WPARAM wParam, LPARAM lParam )
+{
+ CCSDATA *ccs = ( CCSDATA * ) lParam;
+ JABBER_LIST_ITEM *item;
+ int id;
+
+ DBVARIANT dbv;
+ if ( !jabberOnline || JGetStringT( ccs->hContact, "jid", &dbv )) {
+ JSendBroadcast( ccs->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, ( HANDLE ) 1, 0 );
+ return 0;
+ }
+
+ char* pszSrc = ( char* )ccs->lParam, *msg;
+ int isEncrypted;
+
+ char* pdest = strstr( pszSrc, PGP_PROLOG );//pdest-string+1 is index of first occurence
+ if ( pdest != NULL ) {
+ pdest = strstr( pszSrc, PGP_EPILOG );
+ int result = ( pdest ) ? strlen( PGP_PROLOG ) : 0;
+
+ char* tempstring = ( char* )alloca( strlen( pszSrc ));
+ strncpy( tempstring, pszSrc+strlen(PGP_PROLOG), strlen(pszSrc)-strlen(PGP_EPILOG)-result );
+ pszSrc = tempstring;
+ isEncrypted = 1;
+ }
+ else isEncrypted = 0;
+
+ if ( ccs->wParam & PREF_UNICODE )
+ msg = JabberTextEncodeW(( wchar_t* )&pszSrc[ strlen( pszSrc )+1 ] );
+ else
+ msg = JabberTextEncode( pszSrc );
+
+ if ( msg != NULL ) {
+ char msgType[ 16 ];
+ if ( JabberListExist( LIST_CHATROOM, dbv.ptszVal ) && _tcschr( dbv.ptszVal, '/' )==NULL )
+ strcpy( msgType, "groupchat" );
+ else
+ strcpy( msgType, "chat" );
+
+ XmlNode m( "message" ); m.addAttr( "type", msgType );
+ if ( !isEncrypted ) {
+ XmlNode* body = m.addChild( "body" );
+ body->sendText = msg;
+ }
+ else {
+ m.addChild( "body", "[This message is encrypted.]" );
+ XmlNode* x = m.addChild( "x" ); x->addAttr( "xmlns", "jabber:x:encrypted" );
+ x->sendText = msg;
+ }
+
+ XmlNode* active = m.addChild( "active" ); active->addAttr( "xmlns", _T("http://jabber.org/protocol/chatstates"));
+
+ if ( !strcmp( msgType, "groupchat" ) || JGetByte( "MsgAck", FALSE ) == FALSE ) {
+ if ( !strcmp( msgType, "groupchat" ))
+ m.addAttr( "to", dbv.ptszVal );
+ else {
+ id = JabberSerialNext();
+ TCHAR szClientJid[ 256 ];
+ JabberGetClientJID( dbv.ptszVal, szClientJid, SIZEOF( szClientJid ));
+
+ m.addAttr( "to", szClientJid ); m.addAttrID( id );
+ XmlNode* x = m.addChild( "x" ); x->addAttr( "xmlns", "jabber:x:event" ); x->addChild( "composing" );
+ }
+
+ JabberSend( jabberThreadInfo->s, m );
+ JabberForkThread( JabberSendMessageAckThread, 0, ( void* )ccs->hContact );
+ }
+ else {
+ id = JabberSerialNext();
+ if (( item=JabberListGetItemPtr( LIST_ROSTER, dbv.ptszVal )) != NULL )
+ item->idMsgAckPending = id;
+
+ TCHAR szClientJid[ 256 ];
+ JabberGetClientJID( dbv.ptszVal, szClientJid, SIZEOF( szClientJid ));
+ m.addAttr( "to", szClientJid ); m.addAttrID( id );
+
+ XmlNode* x = m.addChild( "x" ); x->addAttr( "xmlns", "jabber:x:event" );
+ x->addChild( "composing" ); x->addChild( "delivered" ); x->addChild( "offline" );
+ JabberSend( jabberThreadInfo->s, m );
+ } }
+
+ JFreeVariant( &dbv );
+ return 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberSetApparentMode - sets the visibility status
+
+int JabberSetApparentMode( WPARAM wParam, LPARAM lParam )
+{
+ CCSDATA *ccs = ( CCSDATA * ) lParam;
+
+ if ( ccs->wParam!=0 && ccs->wParam!=ID_STATUS_ONLINE && ccs->wParam!=ID_STATUS_OFFLINE ) return 1;
+ int oldMode = JGetWord( ccs->hContact, "ApparentMode", 0 );
+ if (( int ) ccs->wParam == oldMode ) return 1;
+ JSetWord( ccs->hContact, "ApparentMode", ( WORD )ccs->wParam );
+
+ if ( !jabberOnline ) return 0;
+
+ DBVARIANT dbv;
+ if ( !JGetStringT( ccs->hContact, "jid", &dbv )) {
+ TCHAR* jid = dbv.ptszVal;
+ switch ( ccs->wParam ) {
+ case ID_STATUS_ONLINE:
+ if ( jabberStatus == ID_STATUS_INVISIBLE || oldMode == ID_STATUS_OFFLINE ) {
+ XmlNode p( "presence" ); p.addAttr( "to", jid );
+ JabberSend( jabberThreadInfo->s, p );
+ }
+ break;
+ case ID_STATUS_OFFLINE:
+ if ( jabberStatus != ID_STATUS_INVISIBLE || oldMode == ID_STATUS_ONLINE )
+ JabberSendPresenceTo( ID_STATUS_INVISIBLE, jid, NULL );
+ break;
+ case 0:
+ if ( oldMode == ID_STATUS_ONLINE && jabberStatus == ID_STATUS_INVISIBLE )
+ JabberSendPresenceTo( ID_STATUS_INVISIBLE, jid, NULL );
+ else if ( oldMode == ID_STATUS_OFFLINE && jabberStatus != ID_STATUS_INVISIBLE )
+ JabberSendPresenceTo( jabberStatus, jid, NULL );
+ break;
+ }
+ JFreeVariant( &dbv );
+ }
+
+ // TODO: update the zebra list ( jabber:iq:privacy )
+
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberSetAwayMsg - sets the away status message
+
+int JabberSetAwayMsg( WPARAM wParam, LPARAM lParam )
+{
+ JabberLog( "SetAwayMsg called, wParam=%d lParam=%s", wParam, ( char* )lParam );
+
+ EnterCriticalSection( &modeMsgMutex );
+
+ char **szMsg;
+ int desiredStatus = wParam;
+
+ switch ( desiredStatus ) {
+ case ID_STATUS_ONLINE:
+ szMsg = &modeMsgs.szOnline;
+ break;
+ case ID_STATUS_AWAY:
+ case ID_STATUS_ONTHEPHONE:
+ case ID_STATUS_OUTTOLUNCH:
+ szMsg = &modeMsgs.szAway;
+ break;
+ case ID_STATUS_NA:
+ szMsg = &modeMsgs.szNa;
+ break;
+ case ID_STATUS_DND:
+ case ID_STATUS_OCCUPIED:
+ szMsg = &modeMsgs.szDnd;
+ break;
+ case ID_STATUS_FREECHAT:
+ szMsg = &modeMsgs.szFreechat;
+ break;
+ default:
+ LeaveCriticalSection( &modeMsgMutex );
+ return 1;
+ }
+
+ char* newModeMsg = mir_strdup(( char* )lParam );
+
+ if (( *szMsg==NULL && newModeMsg==NULL ) ||
+ ( *szMsg!=NULL && newModeMsg!=NULL && !strcmp( *szMsg, newModeMsg )) ) {
+ // Message is the same, no update needed
+ if ( newModeMsg != NULL ) mir_free( newModeMsg );
+ }
+ else {
+ // Update with the new mode message
+ if ( *szMsg != NULL ) mir_free( *szMsg );
+ *szMsg = newModeMsg;
+ // Send a presence update if needed
+ if ( desiredStatus == jabberStatus ) {
+ JabberSendPresence( jabberStatus );
+ } }
+
+ LeaveCriticalSection( &modeMsgMutex );
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberSetStatus - sets the protocol status
+
+int JabberSetStatus( WPARAM wParam, LPARAM lParam )
+{
+ JabberLog( "PS_SETSTATUS( %d )", wParam );
+ int desiredStatus = wParam;
+ jabberDesiredStatus = desiredStatus;
+
+ if ( desiredStatus == ID_STATUS_OFFLINE ) {
+ if ( jabberThreadInfo ) {
+ HANDLE s = jabberThreadInfo->s;
+ jabberThreadInfo = NULL;
+ if ( jabberConnected ) {
+ JabberSend( s, "</stream:stream>" );
+ jabberConnected = jabberOnline = FALSE;
+ }
+ Netlib_CloseHandle(s); // New Line
+ }
+
+ int oldStatus = jabberStatus;
+ jabberStatus = jabberDesiredStatus = ID_STATUS_OFFLINE;
+ JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, jabberStatus );
+ }
+ else if ( !jabberConnected && !( jabberStatus >= ID_STATUS_CONNECTING && jabberStatus < ID_STATUS_CONNECTING + MAX_CONNECT_RETRIES )) {
+ if ( jabberConnected )
+ return 0;
+
+ ThreadData* thread = ( ThreadData* ) mir_alloc( sizeof( struct ThreadData ));
+
+ ZeroMemory( thread, sizeof( struct ThreadData ));
+ thread->type = JABBER_SESSION_NORMAL;
+ jabberDesiredStatus = desiredStatus;
+
+ int oldStatus = jabberStatus;
+ jabberStatus = ID_STATUS_CONNECTING;
+ JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, jabberStatus );
+ thread->hThread = ( HANDLE ) JabberForkThread(( JABBER_THREAD_FUNC )JabberServerThread, 0, thread );
+ }
+ else JabberSetServerStatus( desiredStatus );
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberUserIsTyping - sends a UTN notification
+
+int JabberUserIsTyping( WPARAM wParam, LPARAM lParam )
+{
+ if ( !jabberOnline ) return 0;
+
+ HANDLE hContact = ( HANDLE ) wParam;
+ DBVARIANT dbv;
+ if ( JGetStringT( hContact, "jid", &dbv )) return 0;
+
+ JABBER_LIST_ITEM *item;
+ if (( item = JabberListGetItemPtr( LIST_ROSTER, dbv.ptszVal )) != NULL ) {
+ TCHAR szClientJid[ 256 ];
+ JabberGetClientJID( dbv.ptszVal, szClientJid, SIZEOF( szClientJid ));
+ XmlNode m( "message" ); m.addAttr( "to", szClientJid );
+
+ if ( item->cap & CLIENT_CAP_CHATSTAT ) {
+ m.addAttr( "type", "chat" );
+ m.addAttrID( JabberSerialNext());
+ switch ( lParam ){
+ case PROTOTYPE_SELFTYPING_OFF:
+ m.addChild( "paused" )->addAttr( "xmlns", _T("http://jabber.org/protocol/chatstates"));
+ JabberSend( jabberThreadInfo->s, m );
+ break;
+ case PROTOTYPE_SELFTYPING_ON:
+ m.addChild( "composing" )->addAttr( "xmlns", _T("http://jabber.org/protocol/chatstates"));
+ JabberSend( jabberThreadInfo->s, m );
+ break;
+ }
+ }
+ else if ( item->wantComposingEvent == TRUE ) {
+ XmlNode* x = m.addChild( "x" ); x->addAttr( "xmlns", "jabber:x:event" );
+ if ( item->messageEventIdStr != NULL )
+ x->addChild( "id", item->messageEventIdStr );
+
+ switch ( lParam ){
+ case PROTOTYPE_SELFTYPING_OFF:
+ JabberSend( jabberThreadInfo->s, m );
+ break;
+ case PROTOTYPE_SELFTYPING_ON:
+ x->addChild( "composing" );
+ JabberSend( jabberThreadInfo->s, m );
+ break;
+ } } }
+
+ JFreeVariant( &dbv );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// "/SendXML" - Allows external plugins to send XML to the server
+
+int ServiceSendXML(WPARAM wParam, LPARAM lParam)
+{
+ return JabberSend( jabberThreadInfo->s, (char*)lParam);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Service initialization code
+
+static HANDLE hEventSettingChanged = NULL;
+static HANDLE hEventContactDeleted = NULL;
+static HANDLE hEventRebuildCMenu = NULL;
+
+static HANDLE hMenuAgent = NULL;
+static HANDLE hMenuChangePassword = NULL;
+static HANDLE hMenuGroupchat = NULL;
+
+int JabberMenuHandleAgents( WPARAM wParam, LPARAM lParam );
+int JabberMenuHandleChangePassword( WPARAM wParam, LPARAM lParam );
+int JabberMenuHandleVcard( WPARAM wParam, LPARAM lParam );
+int JabberMenuHandleRequestAuth( WPARAM wParam, LPARAM lParam );
+int JabberMenuHandleGrantAuth( WPARAM wParam, LPARAM lParam );
+int JabberMenuPrebuildContactMenu( WPARAM wParam, LPARAM lParam );
+
+void JabberEnableMenuItems( BOOL bEnable )
+{
+ CLISTMENUITEM clmi = { 0 };
+ clmi.cbSize = sizeof( CLISTMENUITEM );
+ clmi.flags = CMIM_FLAGS;
+ if ( !bEnable )
+ clmi.flags += CMIF_GRAYED;
+
+ JCallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuAgent, ( LPARAM )&clmi );
+ JCallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuChangePassword, ( LPARAM )&clmi );
+ JCallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuGroupchat, ( LPARAM )&clmi );
+}
+
+int JabberSvcInit( void )
+{
+ hEventSettingChanged = HookEvent( ME_DB_CONTACT_SETTINGCHANGED, JabberDbSettingChanged );
+ hEventContactDeleted = HookEvent( ME_DB_CONTACT_DELETED, JabberContactDeleted );
+ hEventRebuildCMenu = HookEvent( ME_CLIST_PREBUILDCONTACTMENU, JabberMenuPrebuildContactMenu );
+
+ JCreateServiceFunction( PS_GETCAPS, JabberGetCaps );
+ JCreateServiceFunction( PS_GETNAME, JabberGetName );
+ JCreateServiceFunction( PS_LOADICON, JabberLoadIcon );
+ JCreateServiceFunction( PS_BASICSEARCH, JabberBasicSearch );
+ JCreateServiceFunction( PS_SEARCHBYEMAIL, JabberSearchByEmail );
+ JCreateServiceFunction( PS_SEARCHBYNAME, JabberSearchByName );
+ JCreateServiceFunction( PS_ADDTOLIST, JabberAddToList );
+ JCreateServiceFunction( PS_ADDTOLISTBYEVENT, JabberAddToListByEvent );
+ JCreateServiceFunction( PS_AUTHALLOW, JabberAuthAllow );
+ JCreateServiceFunction( PS_AUTHDENY, JabberAuthDeny );
+ JCreateServiceFunction( PS_SETSTATUS, JabberSetStatus );
+ JCreateServiceFunction( PS_GETAVATARINFO, JabberGetAvatarInfo );
+ JCreateServiceFunction( PS_GETSTATUS, JabberGetStatus );
+ JCreateServiceFunction( PS_SETAWAYMSG, JabberSetAwayMsg );
+ JCreateServiceFunction( PS_FILERESUME, JabberFileResume );
+
+ JCreateServiceFunction( PSS_GETINFO, JabberGetInfo );
+ JCreateServiceFunction( PSS_SETAPPARENTMODE, JabberSetApparentMode );
+ JCreateServiceFunction( PSS_MESSAGE, JabberSendMessage );
+ JCreateServiceFunction( PSS_GETAWAYMSG, JabberGetAwayMsg );
+ JCreateServiceFunction( PSS_FILEALLOW, JabberFileAllow );
+ JCreateServiceFunction( PSS_FILECANCEL, JabberFileCancel );
+ JCreateServiceFunction( PSS_FILEDENY, JabberFileDeny );
+ JCreateServiceFunction( PSS_FILE, JabberSendFile );
+ JCreateServiceFunction( PSR_MESSAGE, JabberRecvMessage );
+ JCreateServiceFunction( PSR_FILE, JabberRecvFile );
+ JCreateServiceFunction( PSS_USERISTYPING, JabberUserIsTyping );
+
+ // Protocol services and events...
+ heventRawXMLIn = JCreateHookableEvent( JE_RAWXMLIN );
+ heventRawXMLOut = JCreateHookableEvent( JE_RAWXMLOUT );
+ JCreateServiceFunction( JS_SENDXML, ServiceSendXML );
+
+ // Menu items
+ CLISTMENUITEM mi, clmi;
+ memset( &mi, 0, sizeof( CLISTMENUITEM ));
+ mi.cbSize = sizeof( CLISTMENUITEM );
+ memset( &clmi, 0, sizeof( CLISTMENUITEM ));
+ clmi.cbSize = sizeof( CLISTMENUITEM );
+ clmi.flags = CMIM_FLAGS | CMIF_GRAYED;
+
+ // Add Jabber menu to the main menu
+ char text[_MAX_PATH];
+ strcpy( text, jabberProtoName );
+ char* tDest = text + strlen( text );
+
+ if ( !JGetByte( "DisableMainMenu", FALSE )) {
+ // "Agents..."
+ strcpy( tDest, "/Agents" );
+ CreateServiceFunction( text, JabberMenuHandleAgents );
+
+ mi.pszPopupName = jabberModuleName;
+ mi.popupPosition = 500090000;
+ mi.pszName = JTranslate( "Agents..." );
+ mi.position = 2000050000;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_AGENTS ));
+ mi.pszService = text;
+ hMenuAgent = ( HANDLE ) JCallService( MS_CLIST_ADDMAINMENUITEM, 0, ( LPARAM )&mi );
+ JCallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM ) hMenuAgent, ( LPARAM )&clmi );
+
+ // "Change Password..."
+ strcpy( tDest, "/ChangePassword" );
+ CreateServiceFunction( text, JabberMenuHandleChangePassword );
+ mi.pszName = JTranslate( "Change Password..." );
+ mi.position = 2000050001;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_KEYS ));
+ mi.pszService = text;
+ hMenuChangePassword = ( HANDLE ) JCallService( MS_CLIST_ADDMAINMENUITEM, 0, ( LPARAM )&mi );
+ JCallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM ) hMenuChangePassword, ( LPARAM )&clmi );
+
+ // "Multi-User Conference..."
+ strcpy( tDest, "/Groupchat" );
+ CreateServiceFunction( text, JabberMenuHandleGroupchat );
+ mi.pszName = JTranslate( "Multi-User Conference..." );
+ mi.position = 2000050002;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_GROUP ));
+ mi.pszService = text;
+ hMenuGroupchat = ( HANDLE ) JCallService( MS_CLIST_ADDMAINMENUITEM, 0, ( LPARAM )&mi );
+ JCallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM ) hMenuGroupchat, ( LPARAM )&clmi );
+
+ // "Personal vCard..."
+ strcpy( tDest, "/Vcard" );
+ CreateServiceFunction( text, JabberMenuHandleVcard );
+ mi.pszName = JTranslate( "Personal vCard..." );
+ mi.position = 2000050003;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_VCARD ));
+ mi.pszService = text;
+ JCallService( MS_CLIST_ADDMAINMENUITEM, 0, ( LPARAM )&mi );
+ }
+ return 0;
+}
+
+int JabberSvcUninit()
+{
+ if ( hEventSettingChanged ) UnhookEvent( hEventSettingChanged );
+ if ( hEventContactDeleted ) UnhookEvent( hEventContactDeleted );
+ if ( hEventRebuildCMenu ) UnhookEvent( hEventRebuildCMenu );
+ return 0;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_thread.cpp b/miranda-wine/protocols/JabberG/jabber_thread.cpp
new file mode 100644
index 0000000..84eabb7
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_thread.cpp
@@ -0,0 +1,1793 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_thread.cpp,v $
+Revision : $Revision: 3703 $
+Last change on : $Date: 2006-09-05 17:54:42 +0400 (Втр, 05 Сен 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+
+#include <io.h>
+#include <WinDNS.h> // requires Windows Platform SDK
+
+#include "jabber_ssl.h"
+#include "jabber_list.h"
+#include "jabber_iq.h"
+#include "resource.h"
+
+// <iq/> identification number for various actions
+// for JABBER_REGISTER thread
+unsigned int iqIdRegGetReg;
+unsigned int iqIdRegSetReg;
+
+static void __cdecl JabberKeepAliveThread( JABBER_SOCKET s );
+static void JabberProcessStreamOpening( XmlNode *node, void *userdata );
+static void JabberProcessStreamClosing( XmlNode *node, void *userdata );
+static void JabberProcessProtocol( XmlNode *node, void *userdata );
+static void JabberProcessMessage( XmlNode *node, void *userdata );
+static void JabberProcessPresence( XmlNode *node, void *userdata );
+static void JabberProcessIq( XmlNode *node, void *userdata );
+static void JabberProcessProceed( XmlNode *node, void *userdata );
+static void JabberProcessRegIq( XmlNode *node, void *userdata );
+
+static VOID CALLBACK JabberDummyApcFunc( DWORD param )
+{
+ return;
+}
+
+static char onlinePassword[128];
+static HANDLE hEventPasswdDlg;
+
+static BOOL CALLBACK JabberPasswordDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ { TCHAR text[128];
+ mir_sntprintf( text, SIZEOF(text), _T("%s %s"), TranslateT( "Enter password for" ), ( TCHAR* )lParam );
+ SetDlgItemText( hwndDlg, IDC_JID, text );
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDOK:
+ GetDlgItemTextA( hwndDlg, IDC_PASSWORD, onlinePassword, SIZEOF( onlinePassword ));
+ //EndDialog( hwndDlg, ( int ) onlinePassword );
+ //return TRUE;
+ // Fall through
+ case IDCANCEL:
+ //EndDialog( hwndDlg, 0 );
+ SetEvent( hEventPasswdDlg );
+ DestroyWindow( hwndDlg );
+ return TRUE;
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+static VOID CALLBACK JabberPasswordCreateDialogApcProc( DWORD param )
+{
+ CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_PASSWORD ), NULL, JabberPasswordDlgProc, ( LPARAM )param );
+}
+
+static VOID CALLBACK JabberOfflineChatWindows( DWORD )
+{
+ GCDEST gcd = { jabberProtoName, NULL, GC_EVENT_CONTROL };
+ GCEVENT gce = { 0 };
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ CallService( MS_GC_EVENT, SESSION_TERMINATE, (LPARAM)&gce );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+typedef DNS_STATUS (WINAPI *DNSQUERYA)(IN PCSTR pszName, IN WORD wType, IN DWORD Options, IN PIP4_ARRAY aipServers OPTIONAL, IN OUT PDNS_RECORD *ppQueryResults OPTIONAL, IN OUT PVOID *pReserved OPTIONAL);
+typedef void (WINAPI *DNSFREELIST)(IN OUT PDNS_RECORD pRecordList, IN DNS_FREE_TYPE FreeType);
+
+static int xmpp_client_query( char* domain )
+{
+ HINSTANCE hDnsapi = LoadLibraryA( "dnsapi.dll" );
+ if ( hDnsapi == NULL )
+ return 0;
+
+ 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 0;
+ }
+
+ char temp[256];
+ mir_snprintf( temp, SIZEOF(temp), "_xmpp-client._tcp.%s", domain );
+
+ DNS_RECORD *results = NULL;
+ DNS_STATUS status = pDnsQuery(temp, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &results, NULL);
+ if (FAILED(status)||!results || results[0].Data.Srv.pNameTarget == 0||results[0].wType != DNS_TYPE_SRV) {
+ FreeLibrary(hDnsapi);
+ return NULL;
+ }
+
+ strncpy(domain, (char*)results[0].Data.Srv.pNameTarget, 127);
+ int port = results[0].Data.Srv.wPort;
+ pDnsRecordListFree(results, DnsFreeRecordList);
+ FreeLibrary(hDnsapi);
+ return port;
+}
+
+static XmlState xmlState;
+static char *xmlStreamToBeInitialized = 0;
+static void xmlStreamInitialize(char *which){
+ JabberLog("Stream will be initialized %s",which);
+ xmlStreamToBeInitialized = strdup(which);
+}
+static void xmlStreamInitializeNow(struct ThreadData *info){
+ JabberLog("Stream is initializing %s",xmlStreamToBeInitialized?xmlStreamToBeInitialized:"after connect");
+ if (xmlStreamToBeInitialized){
+ free(xmlStreamToBeInitialized);
+ xmlStreamToBeInitialized = NULL;
+ JabberXmlDestroyState(&xmlState);
+ }
+ JabberXmlInitState( &xmlState );
+ JabberXmlSetCallback( &xmlState, 1, ELEM_OPEN, JabberProcessStreamOpening, info );
+ JabberXmlSetCallback( &xmlState, 1, ELEM_CLOSE, JabberProcessStreamClosing, info );
+ JabberXmlSetCallback( &xmlState, 2, ELEM_CLOSE, JabberProcessProtocol, info );
+ //JabberSend( info->s, "<?xml version=\"1.0\" encoding=\"UTF-8\"?><stream:stream to=\"%s\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\">", TXT(info->server) );
+ { XmlNode stream( "stream:stream" );
+ stream.props = "<?xml version='1.0' encoding='UTF-8'?>";
+ stream.addAttr( "to", info->server );
+ stream.addAttr( "xmlns", "jabber:client" );
+ stream.addAttr( "xmlns:stream", "http://etherx.jabber.org/streams" );
+ if ( !JGetByte( "Disable3920auth", 0 ))
+ stream.addAttr( "version", "1.0" );
+ stream.dirtyHack = true; // this is to keep the node open - do not send </stream:stream>
+ JabberSend( info->s, stream );
+} }
+
+static bool wasSaslPerformed = 0;
+
+void __cdecl JabberServerThread( struct ThreadData *info )
+{
+ DBVARIANT dbv;
+ char* buffer;
+ int datalen;
+ int oldStatus;
+ PVOID ssl;
+
+ JabberLog( "Thread started: type=%d", info->type );
+
+ wasSaslPerformed = false;
+ if ( info->type == JABBER_SESSION_NORMAL ) {
+
+ // Normal server connection, we will fetch all connection parameters
+ // e.g. username, password, etc. from the database.
+
+ if ( jabberThreadInfo != 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, jabberThreadInfo->hThread, 0 );
+ JabberLog( "Thread ended, another normal thread is running" );
+ mir_free( info );
+ return;
+ }
+
+ jabberThreadInfo = info;
+ if ( streamId ) mir_free( streamId );
+ streamId = NULL;
+
+ if ( !JGetStringT( NULL, "LoginName", &dbv )) {
+ _tcsncpy( info->username, dbv.ptszVal, SIZEOF( info->username )-1 );
+ JFreeVariant( &dbv );
+ }
+ else {
+ JabberLog( "Thread ended, login name is not configured" );
+ JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_BADUSERID );
+LBL_FatalError:
+ jabberThreadInfo = NULL;
+ oldStatus = jabberStatus;
+ jabberStatus = ID_STATUS_OFFLINE;
+ JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, jabberStatus );
+LBL_Exit:
+ mir_free( info );
+ return;
+ }
+
+ if ( *rtrim(info->username) == '\0' ) {
+ JabberLog( "Thread ended, login name is not configured" );
+ JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_BADUSERID );
+ goto LBL_FatalError;
+ }
+
+ if ( !DBGetContactSetting( NULL, jabberProtoName, "LoginServer", &dbv )) {
+ strncpy( info->server, dbv.pszVal, SIZEOF( info->server )-1 );
+ JFreeVariant( &dbv );
+ }
+ else {
+ JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK );
+ JabberLog( "Thread ended, login server is not configured" );
+ goto LBL_FatalError;
+ }
+
+ if ( !JGetStringT( NULL, "Resource", &dbv )) {
+ _tcsncpy( info->resource, dbv.ptszVal, SIZEOF( info->resource )-1 );
+ JFreeVariant( &dbv );
+ }
+ else _tcscpy( info->resource, _T("Miranda"));
+
+ TCHAR jidStr[128];
+ 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 ( JGetByte( "SavePassword", TRUE ) == FALSE ) {
+ mir_sntprintf( jidStr, SIZEOF( jidStr ), _T("%s@") _T(TCHAR_STR_PARAM), info->username, info->server );
+
+ // Ugly hack: continue logging on only the return value is &( onlinePassword[0] )
+ // because if WM_QUIT while dialog box is still visible, p is returned with some
+ // exit code which may not be NULL.
+ // Should be better with modeless.
+ onlinePassword[0] = ( char )-1;
+ hEventPasswdDlg = CreateEvent( NULL, FALSE, FALSE, NULL );
+ QueueUserAPC( JabberPasswordCreateDialogApcProc, hMainThread, ( DWORD )jidStr );
+ WaitForSingleObject( hEventPasswdDlg, INFINITE );
+ CloseHandle( hEventPasswdDlg );
+
+ if ( onlinePassword[0] == ( TCHAR ) -1 ) {
+ JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_BADUSERID );
+ JabberLog( "Thread ended, password request dialog was canceled" );
+ goto LBL_FatalError;
+ }
+ strncpy( info->password, onlinePassword, SIZEOF( info->password ));
+ info->password[ SIZEOF( info->password )-1] = '\0';
+ }
+ else {
+ if ( DBGetContactSetting( NULL, jabberProtoName, "Password", &dbv )) {
+ JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_BADUSERID );
+ JabberLog( "Thread ended, password is not configured" );
+ goto LBL_FatalError;
+ }
+ JCallService( MS_DB_CRYPT_DECODESTRING, strlen( dbv.pszVal )+1, ( LPARAM )dbv.pszVal );
+ strncpy( info->password, dbv.pszVal, SIZEOF( info->password ));
+ info->password[SIZEOF( info->password )-1] = '\0';
+ JFreeVariant( &dbv );
+ }
+
+ if ( JGetByte( "ManualConnect", FALSE ) == TRUE ) {
+ if ( !DBGetContactSetting( NULL, jabberProtoName, "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 = JGetByte( "UseSSL", FALSE );
+ }
+
+ 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 {
+ JabberLog( "Thread ended, invalid session type" );
+ goto LBL_Exit;
+ }
+
+ char connectHost[128];
+ if ( info->manualHost[0] == 0 ) {
+ int port_temp;
+ strncpy( connectHost, info->server, SIZEOF(info->server));
+ if ( port_temp = xmpp_client_query( connectHost )) { // port_temp will be > 0 if resolution is successful
+ JabberLog("%s%s resolved to %s:%d","_xmpp-client._tcp.",info->server,connectHost,port_temp);
+ if (info->port==0 || info->port==5222)
+ info->port = port_temp;
+ }
+ else JabberLog("%s%s not resolved", "_xmpp-client._tcp.", connectHost);
+ }
+ else strncpy( connectHost, info->manualHost, SIZEOF(connectHost)); // do not resolve if manual host is selected
+
+ JabberLog( "Thread type=%d server='%s' port='%d'", info->type, connectHost, info->port );
+
+ int jabberNetworkBufferSize = 2048;
+ if (( buffer=( char* )mir_alloc( jabberNetworkBufferSize+1 )) == NULL ) { // +1 is for '\0' when debug logging this buffer
+ JabberLog( "Cannot allocate network buffer, thread ended" );
+ if ( info->type == JABBER_SESSION_NORMAL ) {
+ oldStatus = jabberStatus;
+ jabberStatus = ID_STATUS_OFFLINE;
+ JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK );
+ JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, jabberStatus );
+ jabberThreadInfo = NULL;
+ }
+ else if ( info->type == JABBER_SESSION_REGISTER ) {
+ SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )TranslateT( "Error: Not enough memory" ));
+ }
+ JabberLog( "Thread ended, network buffer cannot be allocated" );
+ goto LBL_Exit;
+ }
+
+ info->s = JabberWsConnect( connectHost, info->port );
+ if ( info->s == NULL ) {
+ JabberLog( "Connection failed ( %d )", WSAGetLastError());
+ if ( info->type == JABBER_SESSION_NORMAL ) {
+ if ( jabberThreadInfo == info ) {
+ oldStatus = jabberStatus;
+ jabberStatus = ID_STATUS_OFFLINE;
+ JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK );
+ JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, jabberStatus );
+ jabberThreadInfo = NULL;
+ } }
+ else if ( info->type == JABBER_SESSION_REGISTER )
+ SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )TranslateT( "Error: Cannot connect to the server" ));
+
+ JabberLog( "Thread ended, connection failed" );
+ mir_free( buffer );
+ goto LBL_Exit;
+ }
+
+ // Determine local IP
+ int socket = JCallService( MS_NETLIB_GETSOCKET, ( WPARAM ) info->s, 0 );
+ if ( info->type==JABBER_SESSION_NORMAL && socket!=INVALID_SOCKET ) {
+ struct sockaddr_in saddr;
+ int len;
+
+ len = sizeof( saddr );
+ getsockname( socket, ( struct sockaddr * ) &saddr, &len );
+ jabberLocalIP = saddr.sin_addr.S_un.S_addr;
+ JabberLog( "Local IP = %s", inet_ntoa( saddr.sin_addr ));
+ }
+
+ BOOL sslMode = FALSE;
+ if ( info->useSSL ) {
+ JabberLog( "Intializing SSL connection" );
+ if ( hLibSSL!=NULL && socket!=INVALID_SOCKET ) {
+ JabberLog( "SSL using socket = %d", socket );
+ if (( ssl=pfn_SSL_new( jabberSslCtx )) != NULL ) {
+ JabberLog( "SSL create context ok" );
+ if ( pfn_SSL_set_fd( ssl, socket ) > 0 ) {
+ JabberLog( "SSL set fd ok" );
+ if ( pfn_SSL_connect( ssl ) > 0 ) {
+ JabberLog( "SSL negotiation ok" );
+ JabberSslAddHandle( info->s, ssl ); // This make all communication on this handle use SSL
+ sslMode = TRUE; // Used in the receive loop below
+ JabberLog( "SSL enabled for handle = %d", info->s );
+ }
+ else {
+ JabberLog( "SSL negotiation failed" );
+ pfn_SSL_free( ssl );
+ } }
+ else {
+ JabberLog( "SSL set fd failed" );
+ pfn_SSL_free( ssl );
+ } } }
+
+ if ( !sslMode ) {
+ if ( info->type == JABBER_SESSION_NORMAL ) {
+ oldStatus = jabberStatus;
+ jabberStatus = ID_STATUS_OFFLINE;
+ JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, jabberStatus );
+ JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK );
+ if ( jabberThreadInfo == info )
+ jabberThreadInfo = NULL;
+ }
+ 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 );
+ if ( !hLibSSL )
+ MessageBox( NULL, TranslateT( "The connection requires an OpenSSL library, which is not installed." ), TranslateT( "Jabber Connection Error" ), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND );
+ JabberLog( "Thread ended, SSL connection failed" );
+ goto LBL_Exit;
+ } }
+
+ // User may change status to OFFLINE while we are connecting above
+ if ( jabberDesiredStatus!=ID_STATUS_OFFLINE || info->type==JABBER_SESSION_REGISTER ) {
+
+ if ( info->type == JABBER_SESSION_NORMAL ) {
+ jabberConnected = TRUE;
+ int len = _tcslen( info->username ) + strlen( info->server )+1;
+ jabberJID = ( TCHAR* )mir_alloc( sizeof( TCHAR)*( len+1 ));
+ mir_sntprintf( jabberJID, len+1, _T("%s@") _T(TCHAR_STR_PARAM), info->username, info->server );
+ if ( JGetByte( "KeepAlive", 1 ))
+ jabberSendKeepAlive = TRUE;
+ else
+ jabberSendKeepAlive = FALSE;
+ JabberForkThread( JabberKeepAliveThread, 0, info->s );
+ }
+
+ xmlStreamInitializeNow( info );
+
+ JabberLog( "Entering main recv loop" );
+ datalen = 0;
+
+ for ( ;; ) {
+ int recvResult, bytesParsed;
+
+ if ( !sslMode ) if (info->useSSL) {
+ ssl = JabberSslHandleToSsl( info->s );
+ sslMode = TRUE;
+ }
+
+ if ( sslMode )
+ recvResult = pfn_SSL_read( ssl, buffer+datalen, jabberNetworkBufferSize-datalen );
+ else
+ recvResult = JabberWsRecv( info->s, buffer+datalen, jabberNetworkBufferSize-datalen );
+
+ JabberLog( "recvResult = %d", recvResult );
+ if ( recvResult <= 0 )
+ break;
+ datalen += recvResult;
+
+ buffer[datalen] = '\0';
+ if ( sslMode && DBGetContactSettingByte( NULL, "Netlib", "DumpRecv", TRUE ) == TRUE ) {
+ // Emulate netlib log feature for SSL connection
+ char* szLogBuffer = ( char* )mir_alloc( recvResult+128 );
+ if ( szLogBuffer != NULL ) {
+ strcpy( szLogBuffer, "( SSL ) Data received\n" );
+ memcpy( szLogBuffer+strlen( szLogBuffer ), buffer+datalen-recvResult, recvResult+1 /* also copy \0 */ );
+ Netlib_Logf( hNetlibUser, "%s", szLogBuffer ); // %s to protect against when fmt tokens are in szLogBuffer causing crash
+ mir_free( szLogBuffer );
+ } }
+
+ bytesParsed = JabberXmlParse( &xmlState, buffer );
+ JabberLog( "bytesParsed = %d", bytesParsed );
+ if ( bytesParsed > 0 ) {
+ if ( bytesParsed < datalen )
+ memmove( buffer, buffer+bytesParsed, datalen-bytesParsed );
+ datalen -= bytesParsed;
+ }
+ else if ( datalen == jabberNetworkBufferSize ) {
+ jabberNetworkBufferSize += 65536;
+ JabberLog( "Increasing network buffer size to %d", jabberNetworkBufferSize );
+ if (( buffer=( char* )mir_realloc( buffer, jabberNetworkBufferSize+1 )) == NULL ) {
+ JabberLog( "Cannot reallocate more network buffer, go offline now" );
+ break;
+ } }
+ else JabberLog( "Unknown state: bytesParsed=%d, datalen=%d, jabberNetworkBufferSize=%d", bytesParsed, datalen, jabberNetworkBufferSize );
+
+ if (xmlStreamToBeInitialized) xmlStreamInitializeNow(info);
+ }
+
+ JabberXmlDestroyState(&xmlState);
+
+ if ( info->type == JABBER_SESSION_NORMAL ) {
+ jabberOnline = FALSE;
+ jabberConnected = FALSE;
+ JabberEnableMenuItems( FALSE );
+ if ( hwndJabberChangePassword ) {
+ //DestroyWindow( hwndJabberChangePassword );
+ // Since this is a different thread, simulate the click on the cancel button instead
+ SendMessage( hwndJabberChangePassword, WM_COMMAND, MAKEWORD( IDCANCEL, 0 ), 0 );
+ }
+
+ if ( jabberChatDllPresent )
+ QueueUserAPC( JabberOfflineChatWindows, hMainThread, 0 );
+
+ JabberListRemoveList( LIST_CHATROOM );
+ if ( hwndJabberAgents )
+ SendMessage( hwndJabberAgents, WM_JABBER_CHECK_ONLINE, 0, 0 );
+ if ( hwndJabberGroupchat )
+ SendMessage( hwndJabberGroupchat, WM_JABBER_CHECK_ONLINE, 0, 0 );
+ if ( hwndJabberJoinGroupchat )
+ SendMessage( hwndJabberJoinGroupchat, WM_JABBER_CHECK_ONLINE, 0, 0 );
+
+ // Set status to offline
+ oldStatus = jabberStatus;
+ jabberStatus = ID_STATUS_OFFLINE;
+ JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, jabberStatus );
+
+ // Set all contacts to offline
+ HANDLE hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL ) {
+ if ( !lstrcmpA(( char* )JCallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ), jabberProtoName ))
+ if ( JGetWord( hContact, "Status", ID_STATUS_OFFLINE ) != ID_STATUS_OFFLINE )
+ JSetWord( hContact, "Status", ID_STATUS_OFFLINE );
+
+ hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM ) hContact, 0 );
+ }
+
+ mir_free( jabberJID );
+ jabberJID = NULL;
+ jabberLoggedInTime = 0;
+ JabberListWipe();
+ if ( hwndJabberAgents ) {
+ SendMessage( hwndJabberAgents, WM_JABBER_AGENT_REFRESH, 0, ( LPARAM )"" );
+ SendMessage( hwndJabberAgents, WM_JABBER_TRANSPORT_REFRESH, 0, 0 );
+ }
+ if ( hwndJabberVcard )
+ SendMessage( hwndJabberVcard, WM_JABBER_CHECK_ONLINE, 0, 0 );
+ }
+ 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 = jabberStatus;
+ jabberStatus = ID_STATUS_OFFLINE;
+ JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, jabberStatus );
+ } }
+
+ Netlib_CloseHandle( info->s );
+
+ if ( sslMode ) {
+ pfn_SSL_free( ssl );
+ JabberSslRemoveHandle( info->s );
+ }
+
+ JabberLog( "Thread ended: type=%d server='%s'", info->type, info->server );
+
+ if ( info->type==JABBER_SESSION_NORMAL && jabberThreadInfo==info ) {
+ if ( streamId ) mir_free( streamId );
+ streamId = NULL;
+ jabberThreadInfo = NULL;
+ }
+
+ mir_free( buffer );
+ JabberLog( "Exiting ServerThread" );
+ goto LBL_Exit;
+}
+
+static void JabberIqProcessSearch( XmlNode *node, void *userdata )
+{
+}
+
+static void JabberPerformRegistration( ThreadData* info )
+{
+ iqIdRegGetReg = JabberSerialNext();
+ XmlNodeIq iq("get",iqIdRegGetReg,(char*)NULL);
+ XmlNode* query = iq.addQuery("jabber:iq:register");
+ JabberSend(info->s,iq);
+ SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 50, ( LPARAM )TranslateT( "Requesting registration instruction..." ));
+}
+
+static void JabberPerformIqAuth( ThreadData* info )
+{
+ if ( info->type == JABBER_SESSION_NORMAL ) {
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultGetAuth );
+ XmlNodeIq iq( "get", iqId );
+ XmlNode* query = iq.addQuery( "jabber:iq:auth" );
+ query->addChild( "username", info->username );
+ JabberSend( info->s, iq );
+ }
+ else if ( info->type == JABBER_SESSION_REGISTER )
+ JabberPerformRegistration( info );
+}
+
+static void JabberProcessStreamOpening( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info = ( struct ThreadData * ) userdata;
+ TCHAR* sid;
+
+ if ( node->name==NULL || strcmp( node->name, "stream:stream" ))
+ return;
+
+ if ( info->type == JABBER_SESSION_NORMAL ) {
+ if (( sid=JabberXmlGetAttrValue( node, "id" )) != NULL ) {
+ if ( streamId ) mir_free( streamId );
+ streamId = t2a( sid );
+ } }
+
+ if ( JGetByte( "Disable3920auth", 0 ))
+ JabberPerformIqAuth( info );
+}
+
+static void JabberProcessStreamClosing( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info = ( struct ThreadData * ) userdata;
+
+ Netlib_CloseHandle( info->s );
+ if ( node->name && !strcmp( node->name, "stream:error" ) && node->text )
+ MessageBox( NULL, TranslateTS( node->text ), TranslateT( "Jabber Connection Error" ), MB_OK|MB_ICONERROR|MB_SETFOREGROUND );
+}
+
+static void JabberProcessFeatures( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info = ( struct ThreadData * ) userdata;
+ bool isPlainAvailable = false;
+ bool isMd5available = false;
+ bool isAuthAvailable = false;
+ bool isXGoogleTokenAvailable = false;
+ bool isRegisterAvailable = false;
+ bool areMechanismsDefined = false;
+ bool isSessionAvailable = false;
+
+ for ( int i=0; i < node->numChild; i++ ) {
+ XmlNode* n = node->child[i];
+ if ( !strcmp( n->name, "starttls" )) {
+ if ( !info->useSSL && JGetByte( "UseTLS", FALSE )) {
+ JabberLog( "Requesting TLS" );
+ XmlNode stls( n->name ); stls.addAttr( "xmlns", "urn:ietf:params:xml:ns:xmpp-tls" );
+ JabberSend( info->s, stls );
+ return;
+ } }
+ else if ( !strcmp( n->name, "mechanisms" )) {
+ areMechanismsDefined = true;
+ //JabberLog("%d mechanisms\n",n->numChild);
+ for ( int k=0; k < n->numChild; k++ ) {
+ XmlNode* c = n->child[k];
+ if ( !strcmp( c->name, "mechanism" ))
+ //JabberLog("Mechanism: %s",c->text);
+ if ( !_tcscmp( c->text, _T("PLAIN"))) isPlainAvailable = true;
+ else if ( !_tcscmp( c->text, _T("DIGEST-MD5"))) isMd5available = true;
+ else if ( !_tcscmp( c->text, _T("X-GOOGLE-TOKEN"))) isXGoogleTokenAvailable = true;
+ } }
+ else if ( !strcmp( n->name, "register" )) isRegisterAvailable = true;
+ else if ( !strcmp( n->name, "auth" )) isAuthAvailable = true;
+ else if ( !strcmp( n->name, "session" )) isSessionAvailable = true;
+ }
+
+ if ( areMechanismsDefined ) {
+ char *PLAIN = NULL, *mechanism = NULL;
+ /*if ( isMd5available ) {
+ mechanism = NEWSTR_ALLOCA( "DIGEST-MD5" );
+ }
+ else */if ( isPlainAvailable ) {
+ char *temp = t2a(info->username);
+ int size = strlen(temp)*2+strlen(info->server)+strlen(info->password)+3;
+ char *toEncode = ( char* )alloca( size+1 );
+ mir_snprintf( toEncode, size+1, "%s@%s%c%s%c%s", temp, info->server, 0, temp, 0, info->password );
+ PLAIN = JabberBase64Encode( toEncode, size );
+ mir_free(temp);
+ JabberLog( "Never publish the hash below" );
+ mechanism = NEWSTR_ALLOCA( "PLAIN" );
+ }
+ else {
+ if ( isAuthAvailable ) { // no known mechanisms but iq_auth is available
+ JabberPerformIqAuth( info );
+ return;
+ }
+
+ MessageBox( NULL, TranslateT("No known auth methods available. Giving up."), TranslateT( "Jabber Authentication" ), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND );
+ JabberSend( info->s, "</stream:stream>" );
+ JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD );
+ return;
+ }
+
+ if ( info->type == JABBER_SESSION_NORMAL ) {
+ XmlNode auth( "auth", PLAIN );
+ auth.addAttr( "xmlns", "urn:ietf:params:xml:ns:xmpp-sasl" );
+ auth.addAttr( "mechanism", mechanism );
+ JabberSend(info->s,auth);
+ wasSaslPerformed = true; //sasl was requested, but we dont know the result
+ }
+ else if ( info->type == JABBER_SESSION_REGISTER )
+ JabberPerformRegistration( info );
+ else
+ JabberSend( info->s, "</stream:stream>" );
+ if (PLAIN) mir_free(PLAIN);
+ return;
+ }
+
+ // mechanisms are not defined.
+ if ( wasSaslPerformed ) { //We are already logged-in
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultBind );
+ XmlNodeIq iq("set",iqId);
+ XmlNode* bind = iq.addChild( "bind" ); bind->addAttr( "xmlns", "urn:ietf:params:xml:ns:xmpp-bind" );
+ bind->addChild( "resource", info->resource );
+ JabberSend( info->s, iq );
+
+ if ( isSessionAvailable )
+ info->bIsSessionAvailable = TRUE;
+
+ return;
+ }
+
+ //mechanisms not available and we are not logged in
+ if ( isAuthAvailable )
+ JabberPerformIqAuth( info );
+}
+
+static void __cdecl JabberWaitAndReconnectThread( int unused )
+{
+ JabberLog("Reconnecting after with new X-GOOGLE-TOKEN");
+ Sleep(1000);
+ ThreadData* thread = ( ThreadData* ) mir_alloc( sizeof( struct ThreadData ));
+ ZeroMemory( thread, sizeof( struct ThreadData ));
+ thread->type = JABBER_SESSION_NORMAL;
+ thread->hThread = ( HANDLE ) JabberForkThread(( JABBER_THREAD_FUNC )JabberServerThread, 0, thread );
+}
+
+
+static void JabberProcessFailure( XmlNode *node, void *userdata ){
+// JabberXmlDumpNode( node );
+ struct ThreadData *info = ( struct ThreadData * ) userdata;
+ TCHAR* type;
+//failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"
+ if (( type=JabberXmlGetAttrValue( node, "xmlns" )) == NULL ) return;
+ if ( !_tcscmp( type, _T("urn:ietf:params:xml:ns:xmpp-sasl") )){
+ JabberSend( info->s, "</stream:stream>" );
+
+ TCHAR text[128];
+ mir_sntprintf( text, sizeof( text ), _T("%s %s@")_T(TCHAR_STR_PARAM)_T("."), TranslateT( "Authentication failed for" ), info->username, info->server );
+ MessageBox( NULL, text, TranslateT( "Jabber Authentication" ), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND );
+ JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD );
+ jabberThreadInfo = NULL; // To disallow auto reconnect
+} }
+
+static void JabberProcessError( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info = ( struct ThreadData * ) userdata;
+ TCHAR *buff;
+ int i;
+ int pos;
+//failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"
+ if ( !node->numChild ) return;
+ buff = (TCHAR *)mir_alloc(1024*SIZEOF(buff));
+ pos=0;
+ for (i=0;i<node->numChild;i++){
+ pos += mir_sntprintf(buff+pos,1024-pos,
+ _T(TCHAR_STR_PARAM)_T(": %s\n"),
+ node->child[i]->name,node->child[i]->text);
+ if (!strcmp(node->child[i]->name,"conflict")) JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_OTHERLOCATION);
+ }
+ MessageBox( NULL, buff, TranslateT( "Jabber Error" ), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND );
+ mir_free(buff);
+ JabberSend( info->s, "</stream:stream>" );
+}
+
+static void JabberProcessSuccess( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info = ( struct ThreadData * ) userdata;
+ TCHAR* type;
+// int iqId;
+ // RECVED: <success ...
+ // ACTION: if successfully logged in, continue by requesting roster list and set my initial status
+ if (( type=JabberXmlGetAttrValue( node, "xmlns" )) == NULL ) return;
+
+ if ( !_tcscmp( type, _T("urn:ietf:params:xml:ns:xmpp-sasl") )){
+ DBVARIANT dbv;
+
+ JabberLog( "Succcess: Logged-in." );
+ if ( DBGetContactSetting( NULL, jabberProtoName, "Nick", &dbv ))
+ JSetStringT( NULL, "Nick", info->username );
+ else
+ JFreeVariant( &dbv );
+ xmlStreamInitialize( "after successful sasl" );
+ }
+ else {
+ JabberLog( "Succcess: unknown action "TCHAR_STR_PARAM".",type);
+} }
+
+
+static void JabberProcessProtocol( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info;
+
+ info = ( struct ThreadData * ) userdata;
+ if ( !strcmp( node->name, "proceed" )){
+ JabberProcessProceed( node, userdata );
+ return;
+ }
+ else if ( !strcmp( node->name, "stream:features" )){
+ JabberProcessFeatures( node, userdata );
+ }
+ else if ( !strcmp( node->name, "success")){
+ JabberProcessSuccess( node, userdata );
+ }
+ else if ( !strcmp( node->name, "failure")){
+ JabberProcessFailure( node, userdata );
+ }
+ else if ( !strcmp( node->name, "stream:error")){
+ JabberProcessError( node, userdata );
+ }
+ else if ( info->type == JABBER_SESSION_NORMAL ) {
+ if ( !strcmp( node->name, "message" ))
+ JabberProcessMessage( node, userdata );
+ else if ( !strcmp( node->name, "presence" ))
+ JabberProcessPresence( node, userdata );
+ else if ( !strcmp( node->name, "iq" ))
+ JabberProcessIq( node, userdata );
+ else
+ JabberLog( "Invalid top-level tag ( only <message/> <presence/> and <iq/> allowed )" );
+ }
+ else if ( info->type == JABBER_SESSION_REGISTER ) {
+ if ( !strcmp( node->name, "iq" ))
+ JabberProcessRegIq( node, userdata );
+ else
+ JabberLog( "Invalid top-level tag ( only <iq/> allowed )" );
+} }
+
+static void JabberProcessProceed( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info;
+ TCHAR* type;
+ node = node;
+ if (( info=( struct ThreadData * ) userdata ) == NULL ) return;
+ if (( type = JabberXmlGetAttrValue( node, "xmlns" )) != NULL && !lstrcmp( type, _T("error")))
+ return;
+
+ if ( !lstrcmp( type, _T("urn:ietf:params:xml:ns:xmpp-tls" ))){
+ JabberLog("Starting TLS...");
+ int socket = JCallService( MS_NETLIB_GETSOCKET, ( WPARAM ) info->s, 0 );
+ PVOID ssl;
+ if (( ssl=pfn_SSL_new( jabberSslCtx )) != NULL ) {
+ JabberLog( "SSL create context ok" );
+ if ( pfn_SSL_set_fd( ssl, socket ) > 0 ) {
+ JabberLog( "SSL set fd ok" );
+ if ( pfn_SSL_connect( ssl ) > 0 ) {
+ JabberLog( "SSL negotiation ok" );
+ JabberSslAddHandle( info->s, ssl ); // This make all communication on this handle use SSL
+ info->useSSL = true;
+ JabberLog( "SSL enabled for handle = %d", info->s );
+ xmlStreamInitialize( "after successful StartTLS" );
+ }
+ else {
+ JabberLog( "SSL negotiation failed" );
+ pfn_SSL_free( ssl );
+ } }
+ else {
+ JabberLog( "SSL set fd failed" );
+ pfn_SSL_free( ssl );
+} } } }
+
+static void JabberProcessMessage( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info;
+ XmlNode *subjectNode, *xNode, *inviteNode, *idNode, *n;
+ TCHAR* from, *type, *nick, *p, *idStr, *fromResource;
+ int id;
+ HANDLE hContact;
+
+ if ( !node->name || strcmp( node->name, "message" )) return;
+ if (( info=( struct ThreadData * ) userdata ) == NULL ) return;
+
+ type = JabberXmlGetAttrValue( node, "type" );
+ if (( from = JabberXmlGetAttrValue( node, "from" )) == NULL )
+ return;
+
+ XmlNode* errorNode = JabberXmlGetChild( node, "error" );
+ if ( errorNode != NULL || !lstrcmp( type, _T("error"))) {
+ //we check if is message delivery failure
+ if (( idStr = JabberXmlGetAttrValue( node, "id" )) != NULL ) {
+ if ( !_tcsncmp( idStr, _T(JABBER_IQID), strlen( JABBER_IQID )) ){
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_ROSTER, from );
+ if ( item != NULL ){
+ id = _ttoi(( idStr )+strlen( JABBER_IQID ));
+ if ( id == item->idMsgAckPending ){ // yes, it is
+ char *errText = t2a(JabberErrorMsg(errorNode));
+ JSendBroadcast( JabberHContactFromJID( from ), ACKTYPE_MESSAGE, ACKRESULT_FAILED, ( HANDLE ) 1, (LPARAM)errText );
+ mir_free(errText);
+ } } } }
+ return;
+ }
+
+ JABBER_LIST_ITEM* chatItem = JabberListGetItemPtr( LIST_CHATROOM, from );
+ BOOL isChatRoomJid = ( chatItem != NULL );
+ if ( isChatRoomJid && !lstrcmp( type, _T("groupchat"))) {
+ JabberGroupchatProcessMessage( node, userdata );
+ return;
+ }
+ BOOL isRss = !lstrcmp( type, _T("headline"));
+
+ // If message is from a stranger ( not in roster ), item is NULL
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_ROSTER, from );
+
+ TCHAR* szMessage = NULL;
+ XmlNode* bodyNode = JabberXmlGetChild( node, "body" );
+ if ( bodyNode != NULL ) {
+ if (( subjectNode=JabberXmlGetChild( node, "subject" ))!=NULL && subjectNode->text!=NULL && subjectNode->text[0]!='\0' && !isRss ) {
+ p = ( TCHAR* )alloca( sizeof( TCHAR )*( _tcslen( subjectNode->text ) + _tcslen( bodyNode->text ) + 12 ));
+ wsprintf( p, _T("Subject: %s\r\n%s"), subjectNode->text, bodyNode->text );
+ szMessage = p;
+ }
+ else szMessage = bodyNode->text;
+
+ if (( szMessage = JabberUnixToDosT( szMessage )) == NULL )
+ szMessage = mir_tstrdup( _T(""));
+ }
+
+ time_t msgTime = 0;
+ BOOL isChatRoomInvitation = FALSE;
+ TCHAR* inviteRoomJid = NULL;
+ TCHAR* inviteFromJid = NULL;
+ TCHAR* inviteReason = NULL;
+ TCHAR* invitePassword = NULL;
+ BOOL delivered = FALSE, composing = FALSE;
+
+ n = JabberXmlGetChild( node, "active" );
+ if ( item != NULL && bodyNode != NULL ) {
+ if ( n != NULL && !lstrcmp( JabberXmlGetAttrValue( n, "xmlns" ), _T("http://jabber.org/protocol/chatstates")))
+ item->cap |= CLIENT_CAP_CHATSTAT;
+ else
+ item->cap &= ~CLIENT_CAP_CHATSTAT;
+ }
+
+ n = JabberXmlGetChild( node, "composing" );
+ if ( n != NULL && !lstrcmp( JabberXmlGetAttrValue( n, "xmlns" ), _T("http://jabber.org/protocol/chatstates")))
+ if (( hContact = JabberHContactFromJID( from )) != NULL )
+ JCallService( MS_PROTO_CONTACTISTYPING, ( WPARAM ) hContact, 60 );
+
+ n = JabberXmlGetChild( node, "paused" );
+ if ( n != NULL && !lstrcmp( JabberXmlGetAttrValue( n, "xmlns" ), _T("http://jabber.org/protocol/chatstates")))
+ if (( hContact = JabberHContactFromJID( from )) != NULL )
+ JCallService( MS_PROTO_CONTACTISTYPING, ( WPARAM ) hContact, PROTOTYPE_CONTACTTYPING_OFF );
+
+ for ( int i = 1; ( xNode = JabberXmlGetNthChild( node, "x", i )) != NULL; i++ ) {
+ if (( p=JabberXmlGetAttrValue( xNode, "xmlns" )) != NULL ) {
+ if ( !_tcscmp( p, _T("jabber:x:encrypted" ))) {
+ if ( xNode->text == 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( xNode->text ) + _tcslen( epilog )));
+ _tcsncpy( tempstring, prolog, _tcslen( prolog )+1 );
+ _tcsncpy(tempstring + _tcslen( prolog ), xNode->text, _tcslen( xNode->text )+1);
+ _tcsncpy(tempstring + _tcslen( prolog )+_tcslen(xNode->text ), epilog, _tcslen( epilog )+1);
+ szMessage = tempstring;
+ }
+ else if ( !_tcscmp( p, _T("jabber:x:delay")) && msgTime == 0 ) {
+ if (( p=JabberXmlGetAttrValue( xNode, "stamp" )) != NULL )
+ msgTime = JabberIsoToUnixTime( p );
+ }
+ else if ( !_tcscmp( p, _T("jabber:x:event"))) {
+ if ( bodyNode == NULL ) {
+ idNode = JabberXmlGetChild( xNode, "id" );
+ if ( JabberXmlGetChild( xNode, "delivered" )!=NULL || JabberXmlGetChild( xNode, "offline" )!=NULL ) {
+ id = -1;
+ if ( idNode!=NULL && idNode->text!=NULL )
+ if ( !_tcsncmp( idNode->text, _T(JABBER_IQID), strlen( JABBER_IQID )) )
+ id = _ttoi(( idNode->text )+strlen( JABBER_IQID ));
+
+ if ( item != NULL )
+ if ( id == item->idMsgAckPending )
+ JSendBroadcast( JabberHContactFromJID( from ), ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, ( HANDLE ) 1, 0 );
+ }
+
+ if ( JabberXmlGetChild( xNode, "composing" ) != NULL )
+ if (( hContact = JabberHContactFromJID( from )) != NULL )
+ JCallService( MS_PROTO_CONTACTISTYPING, ( WPARAM ) hContact, 60 );
+
+ if ( xNode->numChild==0 || ( xNode->numChild==1 && idNode != NULL ))
+ // Maybe a cancel to the previous composing
+ if (( hContact = JabberHContactFromJID( from )) != NULL )
+ JCallService( MS_PROTO_CONTACTISTYPING, ( WPARAM ) hContact, PROTOTYPE_CONTACTTYPING_OFF );
+ }
+ else {
+ // Check whether any event is requested
+ if ( !delivered && ( n=JabberXmlGetChild( xNode, "delivered" )) != NULL ) {
+ delivered = TRUE;
+ idStr = JabberXmlGetAttrValue( node, "id" );
+
+ XmlNode m( "message" ); m.addAttr( "to", from );
+ XmlNode* x = m.addChild( "x" ); x->addAttr( "xmlns", "jabber:x:event" ); x->addChild( "delivered" );
+ x->addChild( "id", ( idStr != NULL ) ? idStr : NULL );
+ JabberSend( info->s, m );
+ }
+ if ( item!=NULL && JabberXmlGetChild( xNode, "composing" ) != NULL ) {
+ composing = TRUE;
+ if ( item->messageEventIdStr )
+ mir_free( item->messageEventIdStr );
+ idStr = JabberXmlGetAttrValue( node, "id" );
+ item->messageEventIdStr = ( idStr==NULL )?NULL:mir_tstrdup( idStr );
+ } }
+ }
+ else if ( !_tcscmp( p, _T("jabber:x:oob")) && isRss) {
+ XmlNode* rssUrlNode;
+ if ( (rssUrlNode = JabberXmlGetNthChild( xNode, "url", 1 )) != NULL) {
+ p = ( TCHAR* )alloca( sizeof(TCHAR)*( _tcslen( subjectNode->text ) + _tcslen( bodyNode->text ) + _tcslen( rssUrlNode->text ) + 14 ));
+ wsprintf( p, _T("Subject: %s\r\n%s\r\n%s"), subjectNode->text, rssUrlNode->text, bodyNode->text );
+ szMessage = p;
+ }
+ }
+ else if ( !_tcscmp( p, _T("http://jabber.org/protocol/muc#user"))) {
+ if (( inviteNode=JabberXmlGetChild( xNode, "invite" )) != NULL ) {
+ inviteFromJid = JabberXmlGetAttrValue( inviteNode, "from" );
+ if (( n=JabberXmlGetChild( inviteNode, "reason" )) != NULL )
+ inviteReason = n->text;
+ }
+
+ if (( n=JabberXmlGetChild( xNode, "password" )) != NULL )
+ invitePassword = n->text;
+ }
+ else if ( !_tcscmp( p, _T("jabber:x:conference"))) {
+ inviteRoomJid = JabberXmlGetAttrValue( xNode, "jid" );
+ if ( inviteReason == NULL )
+ inviteReason = xNode->text;
+ isChatRoomInvitation = TRUE;
+ } } }
+
+ if ( isChatRoomInvitation ) {
+ if ( inviteRoomJid != NULL )
+ JabberGroupchatProcessInvite( inviteRoomJid, inviteFromJid, inviteReason, invitePassword );
+ return;
+ }
+
+ if ( bodyNode != NULL ) {
+ if ( bodyNode->text == NULL )
+ return;
+
+ WCHAR* wszMessage;
+ char* szAnsiMsg;
+ int cbAnsiLen, cbWideLen;
+
+ #if defined( _UNICODE )
+ wszMessage = szMessage; cbWideLen = wcslen( szMessage );
+ cbAnsiLen = WideCharToMultiByte( CP_ACP, 0, wszMessage, cbWideLen, NULL, 0, NULL, NULL );
+ szAnsiMsg = ( char* )alloca( cbAnsiLen+1 );
+ WideCharToMultiByte( CP_ACP, 0, wszMessage, cbWideLen, szAnsiMsg, cbAnsiLen, NULL, NULL );
+ szAnsiMsg[ cbAnsiLen ] = 0;
+ #else
+ szAnsiMsg = szMessage; cbAnsiLen = strlen( szMessage );
+ cbWideLen = MultiByteToWideChar( CP_ACP, 0, szAnsiMsg, cbAnsiLen, NULL, 0 );
+ wszMessage = ( WCHAR* )alloca( sizeof(WCHAR)*( cbWideLen+1 ));
+ MultiByteToWideChar( CP_ACP, 0, szAnsiMsg, cbAnsiLen, wszMessage, cbWideLen );
+ wszMessage[ cbWideLen ] = 0;
+ #endif
+
+ char* buf = ( char* )alloca( cbAnsiLen+1 + (cbWideLen+1)*sizeof( WCHAR ));
+ memcpy( buf, szAnsiMsg, cbAnsiLen+1 );
+ memcpy( buf + cbAnsiLen + 1, wszMessage, (cbWideLen+1)*sizeof( WCHAR ));
+
+ HANDLE hContact = JabberHContactFromJID( from );
+
+ if ( item != NULL ) {
+ item->wantComposingEvent = composing;
+ if ( hContact != NULL )
+ JCallService( MS_PROTO_CONTACTISTYPING, ( WPARAM ) hContact, PROTOTYPE_CONTACTTYPING_OFF );
+
+ 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 )) {
+ item->defaultResource = i;
+ break;
+ } } } } }
+
+ if ( hContact == NULL ) {
+ // Create a temporary contact
+ if ( isChatRoomJid ) {
+ if (( p = _tcschr( from, '/' ))!=NULL && p[1]!='\0' )
+ p++;
+ else
+ p = from;
+ hContact = JabberDBCreateContact( from, 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 {
+ nick = JabberNickFromJID( from );
+ hContact = JabberDBCreateContact( from, nick, TRUE, TRUE );
+ mir_free( nick );
+ } }
+
+ time_t now = time( NULL );
+ if ( msgTime == 0 || now - jabberLoggedInTime > 60 )
+ msgTime = now;
+
+ PROTORECVEVENT recv;
+ recv.flags = PREF_UNICODE;
+ recv.timestamp = ( DWORD )msgTime;
+ recv.szMessage = buf;
+ recv.lParam = 0;
+
+ CCSDATA ccs;
+ ccs.hContact = hContact;
+ ccs.wParam = 0;
+ ccs.szProtoService = PSR_MESSAGE;
+ ccs.lParam = ( LPARAM )&recv;
+ JCallService( MS_PROTO_CHAINRECV, 0, ( LPARAM )&ccs );
+
+ mir_free( szMessage );
+} }
+
+static void JabberProcessPresence( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info;
+ HANDLE hContact;
+ XmlNode *showNode, *statusNode;
+ JABBER_LIST_ITEM *item;
+ TCHAR* from, *nick, *show;
+ int i;
+ TCHAR* p;
+
+ if ( !node || !node->name || strcmp( node->name, "presence" )) return;
+ if (( info=( struct ThreadData * ) userdata ) == NULL ) return;
+ if (( from = JabberXmlGetAttrValue( node, "from" )) == NULL ) return;
+
+ if ( JabberListExist( LIST_CHATROOM, from )) {
+ JabberGroupchatProcessPresence( node, userdata );
+ return;
+ }
+
+ TCHAR* type = JabberXmlGetAttrValue( node, "type" );
+ if ( type == NULL || !_tcscmp( type, _T("available"))) {
+ if (( nick=JabberNickFromJID( from )) == NULL )
+ return;
+ if (( hContact = JabberHContactFromJID( from )) == NULL )
+ hContact = JabberDBCreateContact( from, nick, FALSE, TRUE );
+ if ( !JabberListExist( LIST_ROSTER, from )) {
+ JabberLog("Receive presence online from "TCHAR_STR_PARAM" ( who is not in my roster )", from );
+ JabberListAdd( LIST_ROSTER, from );
+ }
+ int status = ID_STATUS_ONLINE;
+ if (( showNode = JabberXmlGetChild( node, "show" )) != NULL ) {
+ if (( show = showNode->text ) != 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;
+ } }
+
+ // Send version query if this is the new resource
+ if (( p = _tcschr( from, '@' )) != NULL ) {
+ if (( p = _tcschr( p, '/' ))!=NULL && p[1]!='\0' ) {
+ p++;
+ if (( item = JabberListGetItemPtr( LIST_ROSTER, from )) != NULL ) {
+ JABBER_RESOURCE_STATUS *r = item->resource;
+ for ( i=0; i < item->resourceCount && lstrcmp( r->resourceName, p ); i++, r++ );
+ if ( i >= item->resourceCount || ( r->version == NULL && r->system == NULL && r->software == NULL )) {
+ XmlNodeIq iq( "get", NOID, from );
+ XmlNode* query = iq.addQuery( "jabber:iq:version" );
+ JabberSend( info->s, iq );
+ } } } }
+
+ if (( statusNode = JabberXmlGetChild( node, "status" )) != NULL && statusNode->text != NULL )
+ p = mir_tstrdup( statusNode->text );
+ else
+ p = NULL;
+ JabberListAddResource( LIST_ROSTER, from, status, p );
+ if ( p ) {
+ DBWriteContactSettingTString( hContact, "CList", "StatusMsg", p );
+ mir_free( p );
+ }
+ else DBDeleteContactSetting( hContact, "CList", "StatusMsg" );
+
+ // Determine status to show for the contact
+ if (( item=JabberListGetItemPtr( LIST_ROSTER, from )) != NULL ) {
+ for ( i=0; i < item->resourceCount; i++ )
+ status = JabberCombineStatus( status, item->resource[i].status );
+ item->status = status;
+ }
+
+ if ( _tcschr( from, '@' )!=NULL || JGetByte( "ShowTransport", TRUE )==TRUE )
+ if ( JGetWord( hContact, "Status", ID_STATUS_OFFLINE ) != status )
+ JSetWord( hContact, "Status", ( WORD )status );
+
+ if ( _tcschr( from, '@' )==NULL && hwndJabberAgents )
+ SendMessage( hwndJabberAgents, WM_JABBER_TRANSPORT_REFRESH, 0, 0 );
+ JabberLog( TCHAR_STR_PARAM " ( " TCHAR_STR_PARAM " ) online, set contact status to %s", nick, from, JCallService(MS_CLIST_GETSTATUSMODEDESCRIPTION,(WPARAM)status,0 ));
+ mir_free( nick );
+
+ XmlNode* xNode;
+ BOOL hasXAvatar = false;
+ if (JGetByte( "EnableAvatars", TRUE )){
+ JabberLog( "Avatar enabled" );
+ for ( int i = 1; ( xNode=JabberXmlGetNthChild( node, "x", i )) != NULL; i++ ) {
+ if ( !lstrcmp( JabberXmlGetAttrValue( xNode, "xmlns" ), _T("jabber:x:avatar"))) {
+ if (( xNode = JabberXmlGetChild( xNode, "hash" )) != NULL && xNode->text != NULL ) {
+ JDeleteSetting(hContact,"AvatarXVcard");
+ JabberLog( "AvatarXVcard deleted" );
+ JSetStringT( hContact, "AvatarHash", xNode->text );
+ hasXAvatar = true;
+ DBVARIANT dbv = {0};
+ int result = JGetStringT( hContact, "AvatarSaved", &dbv );
+ if ( !result || lstrcmp( dbv.ptszVal, xNode->text )) {
+ JabberLog( "Avatar was changed" );
+ JSendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, NULL );
+ } else JabberLog( "Not broadcasting avatar changed" );
+ if ( !result ) JFreeVariant( &dbv );
+ } } }
+ if (!hasXAvatar){ //no jabber:x:avatar. try vcard-temp:x:update
+ JabberLog( "Not hasXAvatar" );
+ for ( int i = 1; ( xNode=JabberXmlGetNthChild( node, "x", i )) != NULL; i++ ) {
+ if ( !lstrcmp( JabberXmlGetAttrValue( xNode, "xmlns" ), _T("vcard-temp:x:update"))) {
+ if (( xNode = JabberXmlGetChild( xNode, "photo" )) != NULL && xNode->text != NULL ) {
+ JSetByte(hContact,"AvatarXVcard",1);
+ JabberLog( "AvatarXVcard set" );
+ JSetStringT( hContact, "AvatarHash", xNode->text );
+ DBVARIANT dbv = {0};
+ int result = JGetStringT( hContact, "AvatarSaved", &dbv );
+ if ( !result || lstrcmp( dbv.ptszVal, xNode->text )) {
+ JabberLog( "Avatar was changed. Using vcard-temp:x:update" );
+ JSendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, NULL );
+ } JabberLog( "Not broadcasting avatar changed" );
+ if ( !result ) JFreeVariant( &dbv );
+ } } } } }
+ return;
+ }
+
+ if ( !_tcscmp( type, _T("unavailable"))) {
+ if ( !JabberListExist( LIST_ROSTER, from )) {
+ JabberLog( "Receive presence offline from " TCHAR_STR_PARAM " ( who is not in my roster )", from );
+ JabberListAdd( LIST_ROSTER, from );
+ }
+ else JabberListRemoveResource( LIST_ROSTER, from );
+
+ int status = ID_STATUS_OFFLINE;
+ if (( statusNode = JabberXmlGetChild( node, "status" )) != NULL ) {
+ if ( JGetByte( "OfflineAsInvisible", FALSE ) == TRUE )
+ status = ID_STATUS_INVISIBLE;
+
+ if (( hContact = JabberHContactFromJID( from )) != NULL) {
+ if ( statusNode->text )
+ DBWriteContactSettingTString(hContact, "CList", "StatusMsg", statusNode->text );
+ else
+ DBDeleteContactSetting(hContact, "CList", "StatusMsg");
+ } }
+
+ if (( item=JabberListGetItemPtr( LIST_ROSTER, from )) != NULL ) {
+ // Determine status to show for the contact based on the remaining resources
+ status = ID_STATUS_OFFLINE;
+ for ( i=0; i < item->resourceCount; i++ )
+ status = JabberCombineStatus( status, item->resource[i].status );
+ item->status = status;
+ }
+ if (( hContact=JabberHContactFromJID( from )) != NULL ) {
+ if ( _tcschr( from, '@' )!=NULL || JGetByte( "ShowTransport", TRUE )==TRUE )
+ if ( JGetWord( hContact, "Status", ID_STATUS_OFFLINE ) != status )
+ JSetWord( hContact, "Status", ( WORD )status );
+
+ JabberLog( TCHAR_STR_PARAM " offline, set contact status to %d", from, status );
+ }
+ if ( _tcschr( from, '@' )==NULL && hwndJabberAgents )
+ SendMessage( hwndJabberAgents, WM_JABBER_TRANSPORT_REFRESH, 0, 0 );
+ return;
+ }
+
+ if ( !_tcscmp( type, _T("subscribe"))) {
+ if ( _tcschr( from, '@' ) == NULL ) {
+ // automatically send authorization allowed to agent/transport
+ XmlNode p( "presence" ); p.addAttr( "to", from ); p.addAttr( "type", "subscribed" );
+ JabberSend( info->s, p );
+ }
+ else if (( nick=JabberNickFromJID( from )) != NULL ) {
+ JabberLog( TCHAR_STR_PARAM " ( " TCHAR_STR_PARAM " ) requests authorization", nick, from );
+ JabberDBAddAuthRequest( from, nick );
+ mir_free( nick );
+ }
+ return;
+ }
+
+ if ( !_tcscmp( type, _T("subscribed"))) {
+ if (( item=JabberListGetItemPtr( LIST_ROSTER, from )) != NULL ) {
+ if ( item->subscription == SUB_FROM ) item->subscription = SUB_BOTH;
+ else if ( item->subscription == SUB_NONE ) {
+ item->subscription = SUB_TO;
+ if ( hwndJabberAgents && _tcschr( from, '@' )==NULL )
+ SendMessage( hwndJabberAgents, WM_JABBER_TRANSPORT_REFRESH, 0, 0 );
+} } } }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Handles various <iq... requests
+
+static void JabberProcessIqVersion( TCHAR* idStr, XmlNode* node )
+{
+ TCHAR* from;
+ if (( from=JabberXmlGetAttrValue( node, "from" )) == NULL )
+ return;
+
+ char* version = JabberGetVersionText();
+ TCHAR* os = NULL;
+
+ OSVERSIONINFO osvi = { 0 };
+ osvi.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
+ if ( GetVersionEx( &osvi )) {
+ switch ( osvi.dwPlatformId ) {
+ case VER_PLATFORM_WIN32_NT:
+ if ( osvi.dwMajorVersion == 5 ) {
+ if ( osvi.dwMinorVersion == 2 ) os = TranslateT( "Windows Server 2003" );
+ else if ( osvi.dwMinorVersion == 1 ) os = TranslateT( "Windows XP" );
+ else if ( osvi.dwMinorVersion == 0 ) os = TranslateT( "Windows 2000" );
+ }
+ else if ( osvi.dwMajorVersion <= 4 ) {
+ os = TranslateT( "Windows NT" );
+ }
+ break;
+ case VER_PLATFORM_WIN32_WINDOWS:
+ if ( osvi.dwMajorVersion == 4 ) {
+ if ( osvi.dwMinorVersion == 0 ) os = TranslateT( "Windows 95" );
+ if ( osvi.dwMinorVersion == 10 ) os = TranslateT( "Windows 98" );
+ if ( osvi.dwMinorVersion == 90 ) os = TranslateT( "Windows ME" );
+ }
+ break;
+ } }
+
+ if ( os == NULL ) os = TranslateT( "Windows" );
+
+ char mversion[100];
+ strcpy( mversion, "Miranda IM " );
+ JCallService( MS_SYSTEM_GETVERSIONTEXT, sizeof( mversion )-12, ( LPARAM )&mversion[11] );
+
+ XmlNodeIq iq( "result", idStr, from );
+ XmlNode* query = iq.addQuery( "jabber:iq:version" );
+ query->addChild( "name", mversion ); query->addChild( "version", version ); query->addChild( "os", os );
+ JabberSend( jabberThreadInfo->s, iq );
+
+ if ( version ) mir_free( version );
+}
+
+static void JabberProcessIqTime( TCHAR* idStr, XmlNode* node ) //added by Rion (jep-0090)
+{
+ TCHAR* from;
+ struct tm *gmt;
+ time_t ltime;
+ char stime[20],*dtime;
+ if (( from=JabberXmlGetAttrValue( node, "from" )) == NULL )
+ return;
+
+ _tzset();
+ time( &ltime );
+ gmt = gmtime( &ltime );
+ sprintf (stime,"%.4i%.2i%.2iT%.2i:%.2i:%.2i",gmt->tm_year+1900,gmt->tm_mon,gmt->tm_mday,gmt->tm_hour,gmt->tm_min,gmt->tm_sec);
+ dtime = ctime(&ltime);
+ dtime[24]=0;
+
+ XmlNodeIq iq( "result", idStr, from );
+ XmlNode* query = iq.addQuery( "jabber:iq:time" );
+ query->addChild( "utc", stime ); query->addChild( "tz", _tzname[1] ); query->addChild( "display", dtime );
+ JabberSend( jabberThreadInfo->s, iq );
+}
+
+static void JabberProcessIqAvatar( TCHAR* idStr, XmlNode* node )
+{
+ if ( !JGetByte( "EnableAvatars", TRUE ))
+ return;
+
+ TCHAR* from;
+ if (( from = JabberXmlGetAttrValue( node, "from" )) == NULL )
+ return;
+
+ int pictureType = JGetByte( "AvatarType", PA_FORMAT_UNKNOWN );
+ if ( pictureType == PA_FORMAT_UNKNOWN )
+ return;
+
+ char* szMimeType;
+ switch( pictureType ) {
+ case PA_FORMAT_JPEG: szMimeType = "image/jpeg"; break;
+ case PA_FORMAT_GIF: szMimeType = "image/gif"; break;
+ case PA_FORMAT_PNG: szMimeType = "image/png"; break;
+ case PA_FORMAT_BMP: szMimeType = "image/bmp"; break;
+ default: return;
+ }
+
+ char szFileName[ MAX_PATH ];
+ JabberGetAvatarFileName( NULL, szFileName, MAX_PATH );
+
+ FILE* in = fopen( szFileName, "rb" );
+ if ( in == NULL )
+ return;
+
+ long bytes = filelength( fileno( in ));
+ char* buffer = ( char* )mir_alloc( bytes*4/3 + bytes + 1000 );
+ if ( buffer == NULL ) {
+ fclose( in );
+ return;
+ }
+
+ fread( buffer, bytes, 1, in );
+ fclose( in );
+
+ char* str = JabberBase64Encode( buffer, bytes );
+ XmlNodeIq iq( "result", idStr, from );
+ XmlNode* query = iq.addQuery( "jabber:iq:avatar" );
+ XmlNode* data = query->addChild( "data", str ); data->addAttr( "mimetype", szMimeType );
+ JabberSend( jabberThreadInfo->s, iq );
+ mir_free( str );
+ mir_free( buffer );
+}
+
+static void JabberProcessIqResultVersion( TCHAR* type, XmlNode* node, XmlNode* queryNode )
+{
+ TCHAR* from = JabberXmlGetAttrValue( node, "from" );
+ if ( from == NULL ) return;
+
+ JABBER_LIST_ITEM *item = JabberListGetItemPtr( LIST_ROSTER, from );
+ if ( item == NULL ) return;
+
+ JABBER_RESOURCE_STATUS *r = item->resource;
+ if ( r == NULL ) return;
+
+ TCHAR* p = _tcschr( from, '/' );
+ if ( p == NULL ) return;
+ if ( *++p == '\0' ) return;
+
+ int i;
+ for ( i=0; i<item->resourceCount && _tcscmp( r->resourceName, p ); i++, r++ );
+ if ( i >= item->resourceCount )
+ return;
+
+ HANDLE hContact = JabberHContactFromJID( from );
+ if ( hContact == NULL )
+ return;
+
+ if ( !lstrcmp( type, _T("error"))) {
+ if ( r->resourceName != NULL )
+ JSetStringT( hContact, "MirVer", r->resourceName );
+ return;
+ }
+
+ XmlNode* n;
+ if ( r->software ) mir_free( r->software );
+ if (( n=JabberXmlGetChild( queryNode, "name" ))!=NULL && n->text ) {
+ if (( hContact=JabberHContactFromJID( item->jid )) != NULL ) {
+ if (( p = _tcsstr( n->text, _T("Miranda IM"))) != NULL )
+ JSetStringT( hContact, "MirVer", p );
+ else
+ JSetStringT( hContact, "MirVer", n->text );
+ }
+ r->software = mir_tstrdup( n->text );
+ }
+ else r->software = NULL;
+ if ( r->version ) mir_free( r->version );
+ if (( n=JabberXmlGetChild( queryNode, "version" ))!=NULL && n->text )
+ r->version = mir_tstrdup( n->text );
+ else
+ r->version = NULL;
+ if ( r->system ) mir_free( r->system );
+ if (( n=JabberXmlGetChild( queryNode, "os" ))!=NULL && n->text )
+ r->system = mir_tstrdup( n->text );
+ else
+ r->system = NULL;
+}
+
+static void JabberProcessIq( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info;
+ HANDLE hContact;
+ XmlNode *queryNode, *siNode, *n;
+ TCHAR* from, *type, *jid, *nick;
+ TCHAR* xmlns, *profile;
+ TCHAR* idStr, *str, *p, *q;
+ TCHAR text[256];
+ int id;
+ int i;
+ JABBER_IQ_PFUNC pfunc;
+
+ if ( !node->name || strcmp( node->name, "iq" )) return;
+ if (( info=( struct ThreadData * ) userdata ) == NULL ) return;
+ if (( type=JabberXmlGetAttrValue( node, "type" )) == NULL ) return;
+
+ id = -1;
+ if (( idStr=JabberXmlGetAttrValue( node, "id" )) != NULL )
+ if ( !_tcsncmp( idStr, _T(JABBER_IQID), strlen( JABBER_IQID )) )
+ id = _ttoi( idStr+strlen( JABBER_IQID ));
+
+ queryNode = JabberXmlGetChild( node, "query" );
+ xmlns = JabberXmlGetAttrValue( queryNode, "xmlns" );
+
+ /////////////////////////////////////////////////////////////////////////
+ // MATCH BY ID
+ /////////////////////////////////////////////////////////////////////////
+
+ if (( pfunc=JabberIqFetchFunc( id )) != NULL ) {
+ JabberLog( "Handling iq request for id=%d", id );
+ pfunc( node, userdata );
+ }
+
+ /////////////////////////////////////////////////////////////////////////
+ // MORE GENERAL ROUTINES, WHEN ID DOES NOT MATCH
+ /////////////////////////////////////////////////////////////////////////
+
+ else if (( pfunc=JabberIqFetchXmlnsFunc( xmlns )) != NULL ) {
+ JabberLog( "Handling iq request for xmlns = " TCHAR_STR_PARAM, xmlns );
+ pfunc( node, userdata );
+ }
+
+ // RECVED: <iq type='set'><query ...
+ else if ( !_tcscmp( type, _T("set")) && queryNode!=NULL && xmlns != NULL ) {
+
+ // RECVED: roster push
+ // ACTION: similar to iqIdGetRoster above
+ if ( !_tcscmp( xmlns, _T("jabber:iq:roster"))) {
+ XmlNode *itemNode, *groupNode;
+ JABBER_LIST_ITEM *item;
+ TCHAR* name;
+
+ JabberLog( "<iq/> Got roster push, query has %d children", queryNode->numChild );
+ for ( i=0; i<queryNode->numChild; i++ ) {
+ itemNode = queryNode->child[i];
+ if ( strcmp( itemNode->name, "item" ) != 0 )
+ continue;
+ if (( jid = JabberXmlGetAttrValue( itemNode, "jid" )) == NULL )
+ continue;
+ if (( str = JabberXmlGetAttrValue( itemNode, "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=JabberXmlGetAttrValue( itemNode, "name" )) != NULL )
+ nick = mir_tstrdup( name );
+ else
+ nick = JabberNickFromJID( jid );
+
+ if ( nick != NULL ) {
+ if (( item=JabberListAdd( LIST_ROSTER, jid )) != NULL ) {
+ if ( item->nick ) mir_free( item->nick );
+ item->nick = nick;
+
+ if ( item->group ) mir_free( item->group );
+ if (( groupNode=JabberXmlGetChild( itemNode, "group" ))!=NULL && groupNode->text!=NULL )
+ item->group = mir_tstrdup( groupNode->text );
+ else
+ item->group = NULL;
+
+ if (( hContact=JabberHContactFromJID( jid )) == NULL ) {
+ // Received roster has a new JID.
+ // Add the jid ( with empty resource ) to Miranda contact list.
+ hContact = JabberDBCreateContact( jid, nick, FALSE, TRUE );
+ }
+ else JSetStringT( hContact, "jid", jid );
+
+ 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 );
+
+ if ( item->group != NULL ) {
+ JabberContactListCreateGroup( item->group );
+ DBWriteContactSettingTString( hContact, "CList", "Group", item->group );
+ }
+ else DBDeleteContactSetting( hContact, "CList", "Group" );
+ }
+ else mir_free( nick );
+ } }
+
+ if (( item=JabberListGetItemPtr( 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;
+ JabberLog( "Roster push for jid=" TCHAR_STR_PARAM ", set subscription to %s", 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=JabberHContactFromJID( jid )) != NULL ) {
+ if ( JGetWord( hContact, "Status", ID_STATUS_OFFLINE ) != ID_STATUS_OFFLINE )
+ JSetWord( hContact, "Status", ID_STATUS_OFFLINE );
+ JabberListRemove( LIST_ROSTER, jid );
+ } }
+ else if ( JGetByte( hContact, "ChatRoom", 0 ))
+ DBDeleteContactSetting( hContact, "CList", "Hidden" );
+ } }
+
+ if ( hwndJabberAgents )
+ SendMessage( hwndJabberAgents, WM_JABBER_TRANSPORT_REFRESH, 0, 0 );
+ }
+
+ // RECVED: file transfer request
+ // ACTION: notify Miranda throuch CHAINRECV
+ else if ( !_tcscmp( xmlns, _T("jabber:iq:oob"))) {
+ if (( jid=JabberXmlGetAttrValue( node, "from" ))!=NULL && ( n=JabberXmlGetChild( queryNode, "url" ))!=NULL && n->text!=NULL ) {
+ str = n->text; // URL of the file to get
+ filetransfer* ft = new filetransfer;
+ ft->std.totalFiles = 1;
+ ft->jid = mir_tstrdup( jid );
+ ft->std.hContact = JabberHContactFromJID( jid );
+ 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 = t2a( text );
+ ft->httpPath = t2a( ++q );
+ } } }
+
+ if (( str=JabberXmlGetAttrValue( node, "id" )) != NULL )
+ ft->iqId = mir_tstrdup( str );
+
+ if ( ft->httpHostName && ft->httpPath ) {
+ CCSDATA ccs;
+ PROTORECVEVENT pre;
+ char* szBlob, *desc;
+
+ JabberLog( "Host=%s Port=%d Path=%s", ft->httpHostName, ft->httpPort, ft->httpPath );
+ if (( n=JabberXmlGetChild( queryNode, "desc" ))!=NULL && n->text!=NULL )
+ desc = t2a( n->text );
+ else
+ desc = mir_strdup( "" );
+
+ if ( desc != NULL ) {
+ char* str;
+ JabberLog( "description = %s", desc );
+ if (( str = strrchr( ft->httpPath, '/' )) != NULL )
+ str++;
+ else
+ str = ft->httpPath;
+ str = mir_strdup( str );
+ JabberHttpUrlDecode( str );
+ szBlob = ( char* )mir_alloc( sizeof( DWORD )+ strlen( str ) + strlen( desc ) + 2 );
+ *(( PDWORD ) szBlob ) = ( DWORD )ft;
+ strcpy( szBlob + sizeof( DWORD ), str );
+ strcpy( szBlob + sizeof( DWORD )+ strlen( str ) + 1, desc );
+ pre.flags = 0;
+ pre.timestamp = time( NULL );
+ pre.szMessage = szBlob;
+ pre.lParam = 0;
+ ccs.szProtoService = PSR_FILE;
+ ccs.hContact = ft->std.hContact;
+ ccs.wParam = 0;
+ ccs.lParam = ( LPARAM )&pre;
+ JCallService( MS_PROTO_CHAINRECV, 0, ( LPARAM )&ccs );
+ mir_free( szBlob );
+ mir_free( str );
+ mir_free( desc );
+ }
+ }
+ else {
+ // reject
+ XmlNodeIq iq( "error", idStr, ft->jid );
+ XmlNode* e = iq.addChild( "error", "File transfer refused" ); e->addAttr( "code", 406 );
+ JabberSend( jabberThreadInfo->s, iq );
+ delete ft;
+ } } }
+
+ // RECVED: bytestream initiation request
+ // ACTION: check for any stream negotiation that is pending ( now only file transfer is handled )
+ else if ( !_tcscmp( xmlns, _T("http://jabber.org/protocol/bytestreams")))
+ JabberFtHandleBytestreamRequest( node );
+ }
+ // RECVED: <iq type='get'><query ...
+ else if ( !_tcscmp( type, _T("get")) && queryNode!=NULL && xmlns != NULL ) {
+
+ // RECVED: software version query
+ // ACTION: return my software version
+ if ( !_tcscmp( xmlns, _T("jabber:iq:version")))
+ JabberProcessIqVersion( idStr, node );
+ else if ( !_tcscmp( xmlns, _T("jabber:iq:avatar")))
+ JabberProcessIqAvatar( idStr, node );
+ else if ( !_tcscmp( xmlns, _T("jabber:iq:time")))
+ JabberProcessIqTime( idStr, node );
+ }
+ // RECVED: <iq type='result'><query ...
+ else if ( !_tcscmp( type, _T("result")) && queryNode != NULL && xmlns != NULL ) {
+
+ // RECVED: software version result
+ // ACTION: update version information for the specified jid/resource
+ if ( !_tcscmp( xmlns, _T("jabber:iq:version")))
+ JabberProcessIqResultVersion( type, node, queryNode );
+ }
+ // RECVED: <iq type='set'><si xmlns='http://jabber.org/protocol/si' ...
+ else if ( !_tcscmp( type, _T("set")) && ( siNode=JabberXmlGetChildWithGivenAttrValue( node, "si", "xmlns", _T("http://jabber.org/protocol/si")))!=NULL && ( profile=JabberXmlGetAttrValue( siNode, "profile" ))!=NULL ) {
+
+ // RECVED: file transfer request
+ // ACTION: notify Miranda throuch CHAINRECV
+ if ( !_tcscmp( profile, _T("http://jabber.org/protocol/si/profile/file-transfer" ))) {
+ JabberFtHandleSiRequest( node );
+ }
+ // RECVED: unknown profile
+ // ACTION: reply with bad-profile
+ else {
+ if (( from=JabberXmlGetAttrValue( node, "from" )) != NULL ) {
+ idStr = JabberXmlGetAttrValue( node, "id" );
+
+ XmlNodeIq iq( "error", idStr, from );
+ XmlNode* error = iq.addChild( "error" ); error->addAttr( "code", "400" ); error->addAttr( "type", "cancel" );
+ XmlNode* brq = error->addChild( "bad-request" ); brq->addAttr( "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas" );
+ XmlNode* bp = error->addChild( "bad-profile" ); brq->addAttr( "xmlns", "http://jabber.org/protocol/si" );
+ JabberSend( jabberThreadInfo->s, iq );
+ } }
+ }
+ // RECVED: <iq type='error'> ...
+ else if ( !_tcscmp( type, _T("error"))) {
+ if ( !lstrcmp( xmlns, _T("jabber:iq:version"))) {
+ JabberProcessIqResultVersion( type, node, queryNode );
+ return;
+ }
+ JabberLog( "XXX on entry" );
+ // Check for file transfer deny by comparing idStr with ft->iqId
+ i = 0;
+ while (( i=JabberListFindNext( LIST_FILE, i )) >= 0 ) {
+ JABBER_LIST_ITEM *item = JabberListGetItemPtrFromIndex( i );
+ if ( item->ft != NULL && item->ft->state == FT_CONNECTING && !_tcscmp( idStr, item->ft->iqId )) {
+ JabberLog( "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
+ }
+ i++;
+} } }
+
+static void JabberProcessRegIq( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info;
+ XmlNode *errorNode;
+ TCHAR *type, *str;
+
+ if ( !node->name || strcmp( node->name, "iq" )) return;
+ if (( info=( struct ThreadData * ) userdata ) == NULL ) return;
+ if (( type=JabberXmlGetAttrValue( node, "type" )) == NULL ) return;
+
+ unsigned int id = -1;
+ if (( str=JabberXmlGetAttrValue( node, "id" )) != NULL )
+ if ( !_tcsncmp( str, _T(JABBER_IQID), strlen( JABBER_IQID )) )
+ id = _ttoi( str + strlen( JABBER_IQID ));
+
+ if ( !_tcscmp( type, _T("result"))) {
+
+ // RECVED: result of the request for registration mechanism
+ // ACTION: send account registration information
+ if ( id == iqIdRegGetReg ) {
+ iqIdRegSetReg = JabberSerialNext();
+
+ XmlNodeIq iq( "set", iqIdRegSetReg );
+ XmlNode* query = iq.addQuery( "jabber:iq:register" );
+ query->addChild( "password", info->password );
+ query->addChild( "username", info->username );
+ JabberSend( info->s, 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 ) {
+ JabberSend( info->s, "</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 = JabberXmlGetChild( node, "error" );
+ str = JabberErrorMsg( errorNode );
+ SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )str );
+ mir_free( str );
+ info->reg_done = TRUE;
+ JabberSend( info->s, "</stream:stream>" );
+} }
+
+static void __cdecl JabberKeepAliveThread( JABBER_SOCKET s )
+{
+ NETLIBSELECT nls = {0};
+
+ nls.cbSize = sizeof( NETLIBSELECT );
+ nls.dwTimeout = 60000; // 60000 millisecond ( 1 minute )
+ nls.hExceptConns[0] = s;
+ for ( ;; ) {
+ if ( JCallService( MS_NETLIB_SELECT, 0, ( LPARAM )&nls ) != 0 )
+ break;
+ if ( jabberSendKeepAlive )
+ JabberSend( s, " \t " );
+ }
+ JabberLog( "Exiting KeepAliveThread" );
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_userinfo.cpp b/miranda-wine/protocols/JabberG/jabber_userinfo.cpp
new file mode 100644
index 0000000..f792448
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_userinfo.cpp
@@ -0,0 +1,525 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_userinfo.cpp,v $
+Revision : $Revision: 3016 $
+Last change on : $Date: 2006-06-04 23:07:43 +0400 (Ð’Ñк, 04 Июн 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+
+#include <commctrl.h>
+#include "jabber_list.h"
+#include "resource.h"
+#include "sha1.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberUserInfoDlgProc - main user info dialog
+
+static BOOL CALLBACK JabberUserInfoDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ // lParam is hContact
+ TranslateDialogDefault( hwndDlg );
+ SetWindowLong( hwndDlg, GWL_USERDATA, ( LONG )( HANDLE ) lParam );
+ SendMessage( hwndDlg, WM_JABBER_REFRESH, 0, 0 );
+ return TRUE;
+ case WM_JABBER_REFRESH:
+ {
+ DBVARIANT dbv;
+ JABBER_LIST_ITEM *item;
+ JABBER_RESOURCE_STATUS *r;
+
+ HWND hwndList = GetDlgItem( hwndDlg, IDC_INFO_RESOURCE );
+ SendMessage( hwndList, LB_RESETCONTENT, 0, 0 );
+ SetDlgItemTextA( hwndDlg, IDC_INFO_JID, "" );
+ SetDlgItemTextA( hwndDlg, IDC_SUBSCRIPTION, "" );
+ SetDlgItemText( hwndDlg, IDC_SOFTWARE, TranslateT( "<click resource to view>" ));
+ SetDlgItemText( hwndDlg, IDC_VERSION, TranslateT( "<click resource to view>" ));
+ SetDlgItemText( hwndDlg, IDC_SYSTEM, TranslateT( "<click resource to view>" ));
+ EnableWindow( GetDlgItem( hwndDlg, IDC_SOFTWARE ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_VERSION ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_SYSTEM ), FALSE );
+
+ HANDLE hContact = ( HANDLE ) GetWindowLong( hwndDlg, GWL_USERDATA );
+ if ( !JGetStringT( hContact, "jid", &dbv )) {
+ SetDlgItemText( hwndDlg, IDC_INFO_JID, dbv.ptszVal );
+
+ if ( jabberOnline ) {
+ if (( item=JabberListGetItemPtr( LIST_ROSTER, dbv.ptszVal )) != NULL ) {
+ if (( r=item->resource ) != NULL ) {
+ int count = item->resourceCount;
+ for ( int i=0; i<count; i++ ) {
+ int index = SendMessage( hwndList, LB_ADDSTRING, 0, ( LPARAM )r[i].resourceName );
+ SendMessage( hwndList, LB_SETITEMDATA, index, ( LPARAM )r[i].resourceName );
+ } }
+
+ switch ( item->subscription ) {
+ case SUB_BOTH:
+ SetDlgItemText( hwndDlg, IDC_SUBSCRIPTION, TranslateT( "both" ));
+ break;
+ case SUB_TO:
+ SetDlgItemText( hwndDlg, IDC_SUBSCRIPTION, TranslateT( "to" ));
+ break;
+ case SUB_FROM:
+ SetDlgItemText( hwndDlg, IDC_SUBSCRIPTION, TranslateT( "from" ));
+ break;
+ default:
+ SetDlgItemText( hwndDlg, IDC_SUBSCRIPTION, TranslateT( "none" ));
+ break;
+ } }
+ else SetDlgItemText( hwndDlg, IDC_SUBSCRIPTION, TranslateT( "none ( not on roster )" ));
+ }
+ else EnableWindow( hwndList, FALSE );
+ JFreeVariant( &dbv );
+ } }
+ break;
+ case WM_NOTIFY:
+ switch (( ( LPNMHDR )lParam )->idFrom ) {
+ case 0:
+ switch (( ( LPNMHDR )lParam )->code ) {
+ case PSN_INFOCHANGED:
+ {
+ HANDLE hContact = ( HANDLE ) (( LPPSHNOTIFY ) lParam )->lParam;
+ SendMessage( hwndDlg, WM_JABBER_REFRESH, 0, ( LPARAM )hContact );
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_INFO_RESOURCE:
+ switch ( HIWORD( wParam )) {
+ case LBN_SELCHANGE:
+ {
+ HWND hwndList = GetDlgItem( hwndDlg, IDC_INFO_RESOURCE );
+ HANDLE hContact = ( HANDLE ) GetWindowLong( hwndDlg, GWL_USERDATA );
+
+ DBVARIANT dbv;
+ if ( !JGetStringT( hContact, "jid", &dbv )) {
+ TCHAR* jid = dbv.ptszVal;
+ int nItem = SendMessage( hwndList, LB_GETCURSEL, 0, 0 );
+ TCHAR* szResource = ( TCHAR* )SendMessage( hwndList, LB_GETITEMDATA, ( WPARAM ) nItem, 0 );
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_ROSTER, jid );
+ JABBER_RESOURCE_STATUS *r;
+
+ if ( szResource != ( TCHAR* )LB_ERR && item != NULL && ( r=item->resource ) != NULL ) {
+ int i;
+ for ( i=0; i < item->resourceCount && _tcscmp( r[i].resourceName, szResource ); i++ );
+ if ( i < item->resourceCount ) {
+ if ( r[i].software != NULL ) {
+ SetDlgItemText( hwndDlg, IDC_SOFTWARE, r[i].software );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_SOFTWARE ), TRUE );
+ }
+ else {
+ SetDlgItemText( hwndDlg, IDC_SOFTWARE, TranslateT( "<not specified>" ));
+ EnableWindow( GetDlgItem( hwndDlg, IDC_SOFTWARE ), FALSE );
+ }
+ if ( r[i].version != NULL ) {
+ SetDlgItemText( hwndDlg, IDC_VERSION, r[i].version );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_VERSION ), TRUE );
+ }
+ else {
+ SetDlgItemText( hwndDlg, IDC_VERSION, TranslateT( "<not specified>" ));
+ EnableWindow( GetDlgItem( hwndDlg, IDC_VERSION ), FALSE );
+ }
+ if ( r[i].system != NULL ) {
+ SetDlgItemText( hwndDlg, IDC_SYSTEM, r[i].system );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_SYSTEM ), TRUE );
+ }
+ else {
+ SetDlgItemText( hwndDlg, IDC_SYSTEM, TranslateT( "<not specified>" ));
+ EnableWindow( GetDlgItem( hwndDlg, IDC_SYSTEM ), FALSE );
+ } } }
+ JFreeVariant( &dbv );
+ } } }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberUserPhotoDlgProc - Jabber photo dialog
+
+typedef struct {
+ HANDLE hContact;
+ HBITMAP hBitmap;
+} USER_PHOTO_INFO;
+
+static BOOL CALLBACK JabberUserPhotoDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ USER_PHOTO_INFO *photoInfo;
+
+ photoInfo = ( USER_PHOTO_INFO * ) GetWindowLong( hwndDlg, GWL_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->hBitmap = NULL;
+ SetWindowLong( hwndDlg, GWL_USERDATA, ( LONG ) photoInfo );
+ SendMessage( GetDlgItem( hwndDlg, IDC_SAVE ), BM_SETIMAGE, IMAGE_ICON, ( LPARAM )LoadImage( hInst, MAKEINTRESOURCE( IDI_SAVE ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 ));
+ ShowWindow( GetDlgItem( hwndDlg, IDC_LOAD ), SW_HIDE );
+ ShowWindow( GetDlgItem( hwndDlg, IDC_DELETE ), SW_HIDE );
+ SendMessage( hwndDlg, WM_JABBER_REFRESH, 0, 0 );
+ return TRUE;
+ case WM_NOTIFY:
+ switch (( ( LPNMHDR )lParam )->idFrom ) {
+ case 0:
+ switch (( ( LPNMHDR )lParam )->code ) {
+ case PSN_INFOCHANGED:
+ SendMessage( hwndDlg, WM_JABBER_REFRESH, 0, 0 );
+ 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 ( !JGetStringT( photoInfo->hContact, "jid", &dbv )) {
+ TCHAR* jid = dbv.ptszVal;
+ if (( item=JabberListGetItemPtr( LIST_ROSTER, jid )) != NULL ) {
+ if ( item->photoFileName ) {
+ JabberLog( "Showing picture from %s", item->photoFileName );
+ photoInfo->hBitmap = ( HBITMAP ) JCallService( MS_UTILS_LOADBITMAP, 0, ( LPARAM )item->photoFileName );
+ 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;
+ OPENFILENAMEA ofn;
+ static char szFilter[512];
+ unsigned char buffer[3];
+ char szFileName[_MAX_PATH];
+ DWORD n;
+
+ if ( JGetStringT( photoInfo->hContact, "jid", &dbv ))
+ break;
+
+ TCHAR* jid = dbv.ptszVal;
+ if (( item=JabberListGetItemPtr( LIST_ROSTER, jid )) != NULL ) {
+ if (( hFile=CreateFileA( 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_snprintf( szFilter, sizeof( szFilter ), "BMP %s ( *.bmp )", JTranslate( "format" ));
+ n = strlen( szFilter );
+ strncpy( szFilter+n+1, "*.BMP", sizeof( szFilter )-n-2 );
+ }
+ else if ( !strncmp(( char* )buffer, "GIF", 3 )) {
+ mir_snprintf( szFilter, sizeof( szFilter ), "GIF %s ( *.gif )", JTranslate( "format" ));
+ n = strlen( szFilter );
+ strncpy( szFilter+n+1, "*.GIF", sizeof( szFilter )-n-2 );
+ }
+ else if ( buffer[0]==0xff && buffer[1]==0xd8 && buffer[2]==0xff ) {
+ mir_snprintf( szFilter, sizeof( szFilter ), "JPEG %s ( *.jpg;*.jpeg )", JTranslate( "format" ));
+ n = strlen( szFilter );
+ strncpy( szFilter+n+1, "*.JPG;*.JPEG", sizeof( szFilter )-n-2 );
+ }
+ else {
+ mir_snprintf( szFilter, sizeof( szFilter ), "%s ( *.* )", JTranslate( "Unknown format" ));
+ n = strlen( szFilter );
+ strncpy( szFilter+n+1, "*.*", sizeof( szFilter )-n-2 );
+ }
+ szFilter[sizeof( szFilter )-1] = '\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 ( GetSaveFileNameA( &ofn )) {
+ JabberLog( "File selected is %s", szFileName );
+ CopyFileA( item->photoFileName, szFileName, FALSE );
+ }
+ }
+ CloseHandle( hFile );
+ }
+ }
+ JFreeVariant( &dbv );
+
+ }
+ break;
+ }
+ break;
+ case WM_PAINT:
+ if ( !jabberOnline )
+ 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;
+ BitBlt( hdcCanvas, pt.x, pt.y, ptSize.x, ptSize.y, hdcMem, ptOrg.x, ptOrg.y, SRCCOPY );
+ }
+ 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;
+ }
+ 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:
+ if ( photoInfo->hBitmap ) {
+ JabberLog( "Delete bitmap" );
+ DeleteObject( photoInfo->hBitmap );
+ }
+ if ( photoInfo ) mir_free( photoInfo );
+ break;
+ }
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberSetAvatarDlgProc - avatar options dialog procedure
+
+static HBITMAP hAvatar;
+static char szFileName[ MAX_PATH ];
+
+static void sttSaveAvatar()
+{
+ char tFileName[ MAX_PATH ];
+ JabberGetAvatarFileName( NULL, tFileName, sizeof tFileName );
+
+ if ( CopyFileA( szFileName, tFileName, FALSE ) == FALSE ) {
+ JabberLog( "Copy failed with error %d", GetLastError() );
+ return;
+ }
+
+ SHA1Context ctx;
+ uint8_t digest[20];
+ SHA1Reset( &ctx );
+
+ FILE* in = fopen( tFileName, "rb" );
+ if ( in == NULL )
+ return;
+
+ char buf[ 512 ];
+ bool bIsFirst = true;
+ int pictureType;
+ while( !feof( in )) {
+ int bytes = fread( buf, 1, sizeof buf, in );
+ if ( bIsFirst ) {
+ pictureType = JabberGetPictureType( buf );
+ bIsFirst = false;
+ }
+ SHA1Input( &ctx, ( const unsigned __int8* )buf, bytes );
+ }
+ fclose( in );
+
+ if ( pictureType == PA_FORMAT_UNKNOWN )
+ return;
+
+ SHA1Result( &ctx, digest );
+ for ( int i=0; i<20; i++ )
+ sprintf( buf+( i<<1 ), "%02x", digest[i] );
+ JSetString( NULL, "AvatarHash", buf );
+ JSetByte( "AvatarType", pictureType );
+
+ JabberGetAvatarFileName( NULL, szFileName, MAX_PATH );
+ if ( strcmp( szFileName, tFileName ))
+ MoveFileA( tFileName, szFileName );
+}
+
+static BOOL CALLBACK JabberSetAvatarDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ {
+ hAvatar = NULL;
+ szFileName[0] = 0;
+
+ BOOL tValue = JGetByte( "EnableAvatars", 1 );
+ CheckDlgButton( hwndDlg, IDC_ENABLE_AVATARS, tValue );
+ if ( tValue ) {
+ char szAvatar[ MAX_PATH ];
+ JabberGetAvatarFileName( NULL, szAvatar, sizeof szAvatar );
+ hAvatar = (HBITMAP)CallService(MS_UTILS_LOADBITMAP, 0, (WPARAM)szAvatar );
+ if ( hAvatar )
+ SendDlgItemMessage(hwndDlg, IDC_AVATAR, STM_SETIMAGE, IMAGE_BITMAP, (WPARAM)hAvatar );
+ } }
+
+ return TRUE;
+
+ case WM_COMMAND:
+ if ( HIWORD( wParam ) == BN_CLICKED )
+ switch( LOWORD( wParam )) {
+ case IDC_SETAVATAR:
+ if ( JabberEnterBitmapName( szFileName ) == ERROR_SUCCESS ) {
+ HBITMAP hBitmap = (HBITMAP)CallService(MS_UTILS_LOADBITMAP, 0, (WPARAM)szFileName );
+ if ( hBitmap != NULL ) {
+ hAvatar = hBitmap;
+ hBitmap = ( HBITMAP )SendDlgItemMessage(hwndDlg, IDC_AVATAR, STM_SETIMAGE, IMAGE_BITMAP, (WPARAM)hBitmap );
+ if ( hBitmap )
+ DeleteObject( hBitmap );
+
+ sttSaveAvatar();
+ if ( jabberConnected )
+ JabberSendPresence( jabberDesiredStatus );
+ RedrawWindow(GetDlgItem(hwndDlg, IDC_AVATAR), NULL, NULL, RDW_INVALIDATE);
+ } }
+ break;
+
+ case IDC_DELETEAVATAR:
+ char tFileName[ MAX_PATH ];
+ JabberGetAvatarFileName( NULL, tFileName, sizeof tFileName );
+ DeleteFileA( tFileName );
+ JDeleteSetting( NULL, "AvatarHash" );
+ JDeleteSetting( NULL, "AvatarType" );
+
+ DeleteObject( hAvatar ); hAvatar = NULL;
+ HBITMAP hBitmap = (HBITMAP)SendDlgItemMessage(hwndDlg, IDC_AVATAR, STM_SETIMAGE, IMAGE_BITMAP, (WPARAM)NULL );
+ if ( hBitmap )
+ DeleteObject( hBitmap );
+
+ if ( jabberConnected )
+ JabberSendPresence( jabberDesiredStatus );
+ break;
+ }
+ break;
+
+ case WM_DESTROY:
+ if ( hAvatar )
+ DeleteObject( hAvatar );
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberUserInfoInit - initializes user info option dialogs
+
+int JabberUserInfoInit( WPARAM wParam, LPARAM lParam )
+{
+ if ( !JCallService( MS_PROTO_ISPROTOCOLLOADED, 0, ( LPARAM )jabberProtoName ))
+ return 0;
+
+ OPTIONSDIALOGPAGE odp = {0};
+ odp.cbSize = sizeof( odp );
+ odp.hInstance = hInst;
+
+ HANDLE hContact = ( HANDLE )lParam;
+ if ( hContact == NULL ) {
+ if ( JGetByte( "EnableAvatars", TRUE )) {
+ char szTitle[256];
+ mir_snprintf( szTitle, sizeof( szTitle ), "%s %s", jabberProtoName, JTranslate( "Avatar" ));
+
+ odp.pfnDlgProc = JabberSetAvatarDlgProc;
+ odp.position = 2000000001;
+ odp.pszTemplate = MAKEINTRESOURCEA( IDD_OPT_SETAVATAR );
+ odp.pszTitle = szTitle;
+ JCallService( MS_USERINFO_ADDPAGE, wParam, ( LPARAM )&odp );
+ }
+ return 0;
+ }
+
+ char* szProto = ( char* )JCallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 );
+ if ( szProto != NULL && !strcmp( szProto, jabberProtoName )) {
+ odp.pfnDlgProc = JabberUserInfoDlgProc;
+ odp.position = -2000000000;
+ odp.pszTemplate = MAKEINTRESOURCEA( IDD_INFO_JABBER );
+ odp.pszTitle = jabberModuleName;
+ JCallService( MS_USERINFO_ADDPAGE, wParam, ( LPARAM )&odp );
+
+ odp.pfnDlgProc = JabberUserPhotoDlgProc;
+ odp.position = 2000000000;
+ odp.pszTemplate = MAKEINTRESOURCEA( IDD_VCARD_PHOTO );
+ odp.pszTitle = JTranslate( "Photo" );
+ JCallService( MS_USERINFO_ADDPAGE, wParam, ( LPARAM )&odp );
+ }
+ return 0;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_util.cpp b/miranda-wine/protocols/JabberG/jabber_util.cpp
new file mode 100644
index 0000000..d725f98
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_util.cpp
@@ -0,0 +1,1133 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_util.cpp,v $
+Revision : $Revision: 3667 $
+Last change on : $Date: 2006-08-31 18:10:18 +0400 (Чтв, 31 Ðвг 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include "jabber_ssl.h"
+#include "jabber_list.h"
+#include "sha1.h"
+
+extern CRITICAL_SECTION mutex;
+extern UINT jabberCodePage;
+
+static CRITICAL_SECTION serialMutex;
+static unsigned int serial;
+
+void __stdcall JabberSerialInit( void )
+{
+ InitializeCriticalSection( &serialMutex );
+ serial = 0;
+}
+
+void __stdcall JabberSerialUninit( void )
+{
+ DeleteCriticalSection( &serialMutex );
+}
+
+unsigned int __stdcall JabberSerialNext( void )
+{
+ unsigned int ret;
+
+ EnterCriticalSection( &serialMutex );
+ ret = serial;
+ serial++;
+ LeaveCriticalSection( &serialMutex );
+ return ret;
+}
+
+void __stdcall JabberLog( const char* fmt, ... )
+{
+ va_list vararg;
+ va_start( vararg, fmt );
+ char* str = ( char* )alloca( 32000 );
+ mir_vsnprintf( str, 32000, fmt, vararg );
+ va_end( vararg );
+
+ JCallService( MS_NETLIB_LOG, ( WPARAM )hNetlibUser, ( LPARAM )str );
+}
+
+// Caution: DO NOT use JabberSend() to send binary ( non-string ) data
+int __stdcall JabberSend( HANDLE hConn, XmlNode& node )
+{
+ char* str = node.getText();
+ int size = strlen( str ), result;
+
+ EnterCriticalSection( &mutex );
+
+ PVOID ssl;
+ if (( ssl=JabberSslHandleToSsl( hConn )) != NULL ) {
+ if ( DBGetContactSettingByte( NULL, "Netlib", "DumpSent", TRUE ) == TRUE ) {
+ char* szLogBuffer = ( char* )alloca( size+32 );
+ strcpy( szLogBuffer, "( SSL ) Data sent\n" );
+ memcpy( szLogBuffer+strlen( szLogBuffer ), str, size+1 ); // also copy \0
+ Netlib_Logf( hNetlibUser, "%s", szLogBuffer ); // %s to protect against when fmt tokens are in szLogBuffer causing crash
+ }
+
+ result = pfn_SSL_write( ssl, str, size );
+ }
+ else result = JabberWsSend( hConn, str, size );
+ LeaveCriticalSection( &mutex );
+
+ mir_free( str );
+ return result;
+}
+
+int __stdcall JabberSend( HANDLE hConn, const char* fmt, ... )
+{
+ int result;
+
+ EnterCriticalSection( &mutex );
+
+ 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 );
+
+ size = strlen( str );
+ PVOID ssl;
+ if (( ssl=JabberSslHandleToSsl( hConn )) != NULL ) {
+ if ( DBGetContactSettingByte( NULL, "Netlib", "DumpSent", TRUE ) == TRUE ) {
+ char* szLogBuffer = ( char* )alloca( size+32 );
+ strcpy( szLogBuffer, "( SSL ) Data sent\n" );
+ memcpy( szLogBuffer+strlen( szLogBuffer ), str, size+1 ); // also copy \0
+ Netlib_Logf( hNetlibUser, "%s", szLogBuffer ); // %s to protect against when fmt tokens are in szLogBuffer causing crash
+ }
+
+ result = pfn_SSL_write( ssl, str, size );
+ }
+ else result = JabberWsSend( hConn, str, size );
+ LeaveCriticalSection( &mutex );
+
+ mir_free( str );
+ return result;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// JabberHContactFromJID - looks for the HCONTACT with required JID
+
+HANDLE __stdcall JabberHContactFromJID( const TCHAR* jid )
+{
+ if ( jid == NULL )
+ return ( HANDLE )NULL;
+
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_CHATROOM, jid );
+
+ HANDLE hContactMatched = NULL;
+ HANDLE hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL ) {
+ char* szProto = ( char* )JCallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 );
+ if ( szProto != NULL && !strcmp( jabberProtoName, szProto )) {
+ DBVARIANT dbv;
+ int result = JGetStringT( hContact, "jid", &dbv );
+ if ( result )
+ result = JGetStringT( hContact, "ChatRoomID", &dbv );
+
+ if ( !result ) {
+ int result;
+ if ( item != NULL )
+ result = lstrcmpi( jid, dbv.ptszVal );
+ else
+ result = JabberCompareJids( jid, dbv.ptszVal );
+ JFreeVariant( &dbv );
+ if ( !result ) {
+ hContactMatched = hContact;
+ break;
+ } } }
+
+ hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM ) hContact, 0 );
+ }
+
+ return hContactMatched;
+}
+
+TCHAR* __stdcall JabberNickFromJID( const TCHAR* jid )
+{
+ 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;
+}
+
+char* __stdcall JabberUrlDecode( char* str )
+{
+ char* p, *q;
+
+ if ( str == NULL )
+ return NULL;
+
+ for ( p=q=str; *p!='\0'; p++,q++ ) {
+ if ( *p == '&' ) {
+ if ( !strncmp( p, "&amp;", 5 )) { *q = '&'; p += 4; }
+ else if ( !strncmp( p, "&apos;", 6 )) { *q = '\''; p += 5; }
+ else if ( !strncmp( p, "&gt;", 4 )) { *q = '>'; p += 3; }
+ else if ( !strncmp( p, "&lt;", 4 )) { *q = '<'; p += 3; }
+ else if ( !strncmp( p, "&quot;", 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"&amp;", 5 )) { *q = '&'; p += 4; }
+ else if ( !wcsncmp( p, L"&apos;", 6 )) { *q = '\''; p += 5; }
+ else if ( !wcsncmp( p, L"&gt;", 4 )) { *q = '>'; p += 3; }
+ else if ( !wcsncmp( p, L"&lt;", 4 )) { *q = '<'; p += 3; }
+ else if ( !wcsncmp( p, L"&quot;", 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, "&amp;" ); q += 5; break;
+ case '\'': strcpy( q, "&apos;" ); q += 6; break;
+ case '>': strcpy( q, "&gt;" ); q += 4; break;
+ case '<': strcpy( q, "&lt;" ); q += 4; break;
+ case '"': strcpy( q, "&quot;" ); q += 6; break;
+ default: *q = *p; q++; break;
+ }
+ }
+ *q = '\0';
+ }
+
+ return s;
+}
+
+static void __stdcall sttUtf8Decode( const BYTE* str, wchar_t* tempBuf )
+{
+ wchar_t* d = tempBuf;
+ BYTE* s = ( BYTE* )str;
+
+ while( *s )
+ {
+ if (( *s & 0x80 ) == 0 ) {
+ *d++ = *s++;
+ continue;
+ }
+
+ if (( s[0] & 0xE0 ) == 0xE0 && ( s[1] & 0xC0 ) == 0x80 && ( s[2] & 0xC0 ) == 0x80 ) {
+ *d++ = (( WORD )( s[0] & 0x0F ) << 12 ) + ( WORD )(( s[1] & 0x3F ) << 6 ) + ( WORD )( s[2] & 0x3F );
+ s += 3;
+ continue;
+ }
+
+ if (( s[0] & 0xE0 ) == 0xC0 && ( s[1] & 0xC0 ) == 0x80 ) {
+ *d++ = ( WORD )(( s[0] & 0x1F ) << 6 ) + ( WORD )( s[1] & 0x3F );
+ s += 2;
+ continue;
+ }
+
+ *d++ = *s++;
+ }
+
+ *d = 0;
+}
+
+
+char* __stdcall JabberUtf8Decode( char* str, WCHAR** ucs2 )
+{
+ if ( str == NULL )
+ return NULL;
+
+ int len = strlen( str );
+ if ( len < 2 ) {
+ if ( ucs2 != NULL ) {
+ *ucs2 = ( wchar_t* )mir_alloc(( len+1 )*sizeof( wchar_t ));
+ MultiByteToWideChar( CP_ACP, 0, str, len, *ucs2, len );
+ ( *ucs2 )[ len ] = 0;
+ }
+ return str;
+ }
+
+ wchar_t* tempBuf = ( wchar_t* )alloca(( len+1 )*sizeof( wchar_t ));
+ sttUtf8Decode(( BYTE* )str, tempBuf );
+
+ if ( ucs2 != NULL ) {
+ int fullLen = ( len+1 )*sizeof( wchar_t );
+ *ucs2 = ( wchar_t* )mir_alloc( fullLen );
+ memcpy( *ucs2, tempBuf, fullLen );
+ }
+
+ WideCharToMultiByte( CP_ACP, 0, tempBuf, -1, str, len, NULL, NULL );
+ return str;
+}
+
+char* __stdcall JabberUtf8EncodeW( const WCHAR* wstr )
+{
+ const WCHAR* w;
+
+ // Convert unicode to utf8
+ int len = 0;
+ for ( w = wstr; *w; w++ ) {
+ if ( *w < 0x0080 ) len++;
+ else if ( *w < 0x0800 ) len += 2;
+ else len += 3;
+ }
+
+ unsigned char* szOut = ( unsigned char* )mir_alloc( len+1 );
+ if ( szOut == NULL )
+ return NULL;
+
+ int i = 0;
+ for ( w = wstr; *w; w++ ) {
+ if ( *w < 0x0080 )
+ szOut[i++] = ( unsigned char ) *w;
+ else if ( *w < 0x0800 ) {
+ szOut[i++] = 0xc0 | (( *w ) >> 6 );
+ szOut[i++] = 0x80 | (( *w ) & 0x3f );
+ }
+ else {
+ szOut[i++] = 0xe0 | (( *w ) >> 12 );
+ szOut[i++] = 0x80 | (( ( *w ) >> 6 ) & 0x3f );
+ szOut[i++] = 0x80 | (( *w ) & 0x3f );
+ } }
+
+ szOut[ i ] = '\0';
+ return ( char* )szOut;
+}
+
+void __stdcall JabberUtfToTchar( const char* pszValue, size_t cbLen, LPTSTR& dest )
+{
+ char* pszCopy = ( char* )alloca( cbLen+1 );
+ memcpy( pszCopy, pszValue, cbLen );
+ pszCopy[ cbLen ] = 0;
+
+ JabberUrlDecode( pszCopy );
+
+ #if defined( _UNICODE )
+ JabberUtf8Decode( pszCopy, &dest );
+ #else
+ JabberUtf8Decode( pszCopy, NULL );
+ dest = mir_strdup( pszCopy );
+ #endif
+}
+
+char* __stdcall JabberUtf8Encode( const char* str )
+{
+ if ( str == NULL )
+ return NULL;
+
+ // Convert local codepage to unicode
+ int len = strlen( str );
+ WCHAR* wszTemp = ( WCHAR* )alloca( sizeof( WCHAR )*( len+1 ));
+ MultiByteToWideChar( jabberCodePage, 0, str, -1, wszTemp, len+1 );
+
+ return JabberUtf8EncodeW( wszTemp );
+}
+
+char* __stdcall JabberSha1( char* str )
+{
+ SHA1Context sha;
+ uint8_t digest[20];
+ char* result;
+ int i;
+
+ if ( str == NULL )
+ return NULL;
+
+ SHA1Reset( &sha );
+ SHA1Input( &sha, ( const unsigned __int8* )str, strlen( str ));
+ SHA1Result( &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;
+}
+
+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;
+}
+
+char* __stdcall JabberHttpUrlEncode( const char* str )
+{
+ unsigned char* p, *q, *res;
+
+ if ( str == NULL ) return NULL;
+ res = ( BYTE* ) mir_alloc( 3*strlen( str ) + 1 );
+ for ( p=( BYTE* )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 {
+ sprintf(( char* )q, "%%%02X", *p );
+ q += 2;
+ }
+ }
+ *q = '\0';
+ return ( char* )res;
+}
+
+void __stdcall JabberHttpUrlDecode( char* str )
+{
+ unsigned char* p, *q;
+ unsigned int code;
+
+ if ( str == NULL ) return;
+ for ( p=q=( BYTE* )str; *p!='\0'; p++,q++ ) {
+ if ( *p=='%' && *( p+1 )!='\0' && isxdigit( *( p+1 )) && *( p+2 )!='\0' && isxdigit( *( p+2 )) ) {
+ sscanf(( char* )p+1, "%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( XmlNode *errorNode )
+{
+ TCHAR* errorStr, *str;
+ int errorCode;
+
+ errorStr = ( TCHAR* )mir_alloc( 256 * sizeof( TCHAR ));
+ if ( errorNode == NULL ) {
+ mir_sntprintf( errorStr, 256, _T("%s -1: %s"), TranslateT( "Error" ), TranslateT( "Unknown error message" ));
+ return errorStr;
+ }
+
+ errorCode = -1;
+ if (( str=JabberXmlGetAttrValue( errorNode, "code" )) != NULL )
+ errorCode = _ttoi( str );
+ if (( str=errorNode->text ) != 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 )) );
+ return errorStr;
+}
+
+void __stdcall JabberSendVisibleInvisiblePresence( BOOL invisible )
+{
+ if ( !jabberOnline ) return;
+
+ for ( int i = 0; ( i=JabberListFindNext( LIST_ROSTER, i )) >= 0; i++ ) {
+ JABBER_LIST_ITEM *item = JabberListGetItemPtrFromIndex( i );
+ if ( item == NULL )
+ continue;
+
+ HANDLE hContact = JabberHContactFromJID( item->jid );
+ if ( hContact == NULL )
+ continue;
+
+ WORD apparentMode = JGetWord( hContact, "ApparentMode", 0 );
+ if ( invisible==TRUE && apparentMode==ID_STATUS_OFFLINE ) {
+ XmlNode p( "presence" ); p.addAttr( "to", item->jid ); p.addAttr( "type", "invisible" );
+ JabberSend( jabberThreadInfo->s, p );
+ }
+ else if ( invisible==FALSE && apparentMode==ID_STATUS_ONLINE )
+ JabberSendPresenceTo( jabberStatus, item->jid, NULL );
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberTextEncodeW - prepare a string for transmission
+
+char* __stdcall JabberTextEncode( const char* str )
+{
+ if ( str == NULL )
+ return NULL;
+
+ char* s1 = JabberUrlEncode( str );
+ if ( s1 == NULL )
+ return NULL;
+
+ // Convert invalid control characters to space
+ if ( *s1 ) {
+ char* p, *q;
+
+ for ( p = s1; *p != '\0'; p++ )
+ if ( *p > 0 && *p < 0x20 && *p != 0x09 && *p != 0x0a && *p != 0x0d )
+ *p = ( char )0x20;
+
+ for ( p = q = s1; *p!='\0'; p++ ) {
+ if ( *p != '\r' ) {
+ *q = *p;
+ q++;
+ } }
+
+ *q = '\0';
+ }
+
+ char* s2 = JabberUtf8Encode( s1 );
+ mir_free( s1 );
+ return s2;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberTextEncodeW - prepare a string for transmission
+
+char* __stdcall JabberTextEncodeW( const wchar_t* str )
+{
+ if ( str == NULL )
+ return NULL;
+
+ const wchar_t *s;
+ int resLen = 1;
+
+ for ( s = str; *s; s++ ) {
+ switch( *s ) {
+ case '\r': continue;
+ case '&': resLen += 5; break;
+ case '\'': resLen += 6; break;
+ case '>':
+ case '<': resLen += 6; break;
+ case '\"': resLen += 6; break;
+ default: resLen++; break;
+ } }
+
+ wchar_t* tmp = ( wchar_t* )alloca( resLen * sizeof( wchar_t )), *d;
+
+ for ( s = str, d = tmp; *s; s++ ) {
+ switch( *s ) {
+ case '\r': continue;
+ case '&': wcscpy( d, L"&amp;" ); d += 5; break;
+ case '\'': wcscpy( d, L"&apos;" ); d += 6; break;
+ case '>': wcscpy( d, L"&gt;" ); d += 4; break;
+ case '<': wcscpy( d, L"&lt;" ); d += 4; break;
+ case '\"': wcscpy( d, L"&quot;" ); d += 6; break;
+ default:
+ if ( *s > 0 && *s < 0x20 && *s != 0x09 && *s != 0x0a && *s != 0x0d )
+ *d++ = ' ';
+ else
+ *d++ = *s;
+ } }
+
+ *d = 0;
+
+ return JabberUtf8EncodeW( tmp );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberTextDecode - retrieve a text from the encoded string
+
+char* __stdcall JabberTextDecode( const char* str )
+{
+ if ( str == NULL )
+ return NULL;
+
+ char* s1 = ( char* )alloca( strlen( str )+1 ), *s2;
+ strcpy( s1, str );
+
+ JabberUtf8Decode( s1, NULL );
+ JabberUrlDecode( s1 );
+ if (( s2 = JabberUnixToDos( s1 )) == NULL )
+ return NULL;
+
+ return s2;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// 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];
+ int nGroups = 0;
+ 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 JabberBase64Decode( const TCHAR* 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(( ( _tcslen( 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;
+}
+
+char* __stdcall JabberGetVersionText()
+{
+ char filename[MAX_PATH], *fileVersion, *res;
+ DWORD unused;
+ DWORD verInfoSize;
+ UINT blockSize;
+ PVOID pVerInfo;
+
+ GetModuleFileNameA( hInst, filename, sizeof( filename ));
+ verInfoSize = GetFileVersionInfoSizeA( filename, &unused );
+ if (( pVerInfo=mir_alloc( verInfoSize )) != NULL ) {
+ GetFileVersionInfoA( filename, 0, verInfoSize, pVerInfo );
+ VerQueryValueA( pVerInfo, "\\StringFileInfo\\040904b0\\FileVersion", ( LPVOID* )&fileVersion, &blockSize );
+ if ( strstr( fileVersion, "cvs" )) {
+ res = ( char* )mir_alloc( strlen( fileVersion ) + strlen( __DATE__ ) + 2 );
+ sprintf( res, "%s %s", fileVersion, __DATE__ );
+ }
+ else {
+ res = mir_strdup( fileVersion );
+ }
+ mir_free( pVerInfo );
+ return res;
+ }
+ return NULL;
+}
+
+time_t __stdcall JabberIsoToUnixTime( TCHAR* stamp )
+{
+ struct tm timestamp;
+ TCHAR date[9];
+ TCHAR* p;
+ int i, y;
+ time_t t;
+
+ if ( stamp == NULL ) return ( time_t ) 0;
+
+ 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"), &timestamp.tm_hour, &timestamp.tm_min, &timestamp.tm_sec ) != 3 )
+ return ( time_t ) 0;
+
+ timestamp.tm_isdst = 0; // DST is already present in _timezone below
+ t = mktime( &timestamp );
+
+ _tzset();
+ t -= _timezone;
+
+ if ( t >= 0 )
+ return t;
+ else
+ return ( time_t ) 0;
+}
+
+struct MyCountryListEntry
+{
+ int id;
+ TCHAR* szName;
+}
+static extraCtry[] =
+{
+ { 1, _T("United States") },
+ { 1, _T("United States of America") },
+ { 1, _T("US") },
+ { 44, _T("England") }
+};
+
+int __stdcall JabberCountryNameToId( TCHAR* ctry )
+{
+ int ctryCount, i;
+ MyCountryListEntry *ctryList;
+
+ // Check for some common strings not present in the country list
+ ctryCount = sizeof( extraCtry )/sizeof( extraCtry[0] );
+ for ( i=0; i<ctryCount && _tcsicmp( extraCtry[i].szName, ctry ); i++ );
+ if ( i < ctryCount )
+ return extraCtry[i].id;
+
+ // Check Miranda country list
+ JCallService( MS_UTILS_GETCOUNTRYLIST, ( WPARAM ) &ctryCount, ( LPARAM )&ctryList );
+ for ( i=0; i<ctryCount && _tcsicmp( ctryList[i].szName, ctry ); i++ );
+ if ( i < ctryCount )
+ return ctryList[i].id;
+ else
+ return 0xffff; // Unknown
+}
+
+void __stdcall JabberSendPresenceTo( int status, TCHAR* to, XmlNode* extra )
+{
+ if ( !jabberOnline ) return;
+
+ // Send <presence/> update for status ( we won't handle ID_STATUS_OFFLINE here )
+ // Note: jabberModeMsg is already encoded using JabberTextEncode()
+ EnterCriticalSection( &modeMsgMutex );
+
+ char szPriority[40];
+ itoa( JGetWord( NULL, "Priority", 0 ), szPriority, 10 );
+
+ XmlNode p( "presence" ); p.addChild( "priority", szPriority );
+ if ( to != NULL )
+ p.addAttr( "to", to );
+
+ if ( extra )
+ p.addChild( extra );
+
+ if ( JGetByte( "EnableAvatars", TRUE )) {
+ char hashValue[ 50 ];
+ if ( !JGetStaticString( "AvatarHash", NULL, hashValue, sizeof hashValue )) {
+ XmlNode* x = p.addChild( "x" ); x->addAttr( "xmlns", "jabber:x:avatar" );
+ x->addChild( "hash", hashValue );
+
+ x = p.addChild( "x" ); x->addAttr( "xmlns", "vcard-temp:x:update" );
+ x->addChild( "photo", hashValue );
+ } }
+
+ switch ( status ) {
+ case ID_STATUS_ONLINE:
+ if ( modeMsgs.szOnline )
+ p.addChild( "status", modeMsgs.szOnline );
+ break;
+ case ID_STATUS_INVISIBLE:
+ p.addAttr( "type", "invisible" );
+ break;
+ case ID_STATUS_AWAY:
+ case ID_STATUS_ONTHEPHONE:
+ case ID_STATUS_OUTTOLUNCH:
+ p.addChild( "show", "away" );
+ if ( modeMsgs.szAway )
+ p.addChild( "status", modeMsgs.szAway );
+ break;
+ case ID_STATUS_NA:
+ p.addChild( "show", "xa" );
+ if ( modeMsgs.szNa )
+ p.addChild( "status", modeMsgs.szNa );
+ break;
+ case ID_STATUS_DND:
+ case ID_STATUS_OCCUPIED:
+ p.addChild( "show", "dnd" );
+ if ( modeMsgs.szDnd )
+ p.addChild( "status", modeMsgs.szDnd );
+ break;
+ case ID_STATUS_FREECHAT:
+ p.addChild( "show", "chat" );
+ if ( modeMsgs.szFreechat )
+ p.addChild( "status", modeMsgs.szFreechat );
+ break;
+ default:
+ // Should not reach here
+ break;
+ }
+ JabberSend( jabberThreadInfo->s, p );
+ LeaveCriticalSection( &modeMsgMutex );
+}
+
+void __stdcall JabberSendPresence( int status )
+{
+ JabberSendPresenceTo( status, NULL, NULL );
+ JabberSendVisibleInvisiblePresence( status == ID_STATUS_INVISIBLE );
+
+ // Also update status in all chatrooms
+ for ( int i = 0; ( i=JabberListFindNext( LIST_CHATROOM, i )) >= 0; i++ ) {
+ JABBER_LIST_ITEM *item = JabberListGetItemPtrFromIndex( i );
+ if ( item != NULL )
+ JabberSendPresenceTo( status, item->jid, NULL );
+} }
+
+void __stdcall JabberStringAppend( char* *str, int *sizeAlloced, const char* fmt, ... )
+{
+ va_list vararg;
+ char* p;
+ int size, len;
+
+ if ( str == NULL ) return;
+
+ if ( *str==NULL || *sizeAlloced<=0 ) {
+ *sizeAlloced = 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 );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// JabberGetClientJID - adds a resource postfix to a JID
+
+TCHAR* __stdcall JabberGetClientJID( 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, '/' );
+ if ( p == NULL ) {
+ TCHAR* resource = JabberListGetBestResourceNamePtr( 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, "GIF89", 5 ) == 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+6, "JFIF", 4 ) == 0 ) return PA_FORMAT_JPEG;
+ }
+
+ return PA_FORMAT_UNKNOWN;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Unicode functions
+
+char* t2a( const TCHAR* src )
+{
+ #if defined( _UNICODE )
+ return u2a( src );
+ #else
+ return mir_strdup( src );
+ #endif
+}
+
+char* u2a( const wchar_t* src )
+{
+ int codepage = CallService( MS_LANGPACK_GETCODEPAGE, 0, 0 );
+
+ int cbLen = WideCharToMultiByte( codepage, 0, src, -1, NULL, 0, NULL, NULL );
+ char* result = ( char* )mir_alloc( cbLen+1 );
+ if ( result == NULL )
+ return NULL;
+
+ WideCharToMultiByte( codepage, 0, src, -1, result, cbLen, NULL, NULL );
+ result[ cbLen ] = 0;
+ return result;
+}
+
+wchar_t* a2u( const char* src )
+{
+ int codepage = CallService( MS_LANGPACK_GETCODEPAGE, 0, 0 );
+
+ int cbLen = MultiByteToWideChar( codepage, 0, src, -1, NULL, 0 );
+ wchar_t* result = ( wchar_t* )mir_alloc( sizeof( wchar_t )*(cbLen+1));
+ if ( result == NULL )
+ return NULL;
+
+ MultiByteToWideChar( codepage, 0, src, -1, result, cbLen );
+ result[ cbLen ] = 0;
+ return result;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_vcard.cpp b/miranda-wine/protocols/JabberG/jabber_vcard.cpp
new file mode 100644
index 0000000..0f551eb
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_vcard.cpp
@@ -0,0 +1,1179 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_vcard.cpp,v $
+Revision : $Revision: 3016 $
+Last change on : $Date: 2006-06-04 23:07:43 +0400 (Ð’Ñк, 04 Июн 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <io.h>
+#include <commctrl.h>
+#include "jabber_iq.h"
+#include "resource.h"
+
+extern char* jabberVcardPhotoFileName;
+extern char* jabberVcardPhotoType;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static BOOL CALLBACK JabberVcardDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam );
+
+int JabberMenuHandleVcard( WPARAM wParam, LPARAM lParam )
+{
+ if ( IsWindow( hwndJabberVcard ))
+ SetForegroundWindow( hwndJabberVcard );
+ else {
+ hwndJabberVcard = CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_VCARD ), NULL, JabberVcardDlgProc, ( LPARAM )NULL );
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int JabberSendGetVcard( const TCHAR* jid )
+{
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, ( jid == jabberJID ) ? IQ_PROC_GETVCARD : IQ_PROC_NONE, JabberIqResultGetVcard );
+
+ XmlNodeIq iq( "get", iqId, jid );
+ XmlNode* vs = iq.addChild( "vCard" ); vs->addAttr( "xmlns", "vcard-temp" );
+ vs->addAttr( "prodid", "-//HandGen//NONSGML vGen v1.0//EN" ); vs->addAttr( "version", "2.0" );
+ JabberSend( jabberThreadInfo->s, iq );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+typedef struct {
+ HWND hwnd;
+ int dlgId;
+ DLGPROC dlgProc;
+} VcardPage;
+
+typedef struct {
+ int pageCount;
+ int currentPage;
+ RECT rectTab;
+ VcardPage *page;
+ BOOL changed;
+ int updateAnimFrame;
+ TCHAR* szUpdating;
+ BOOL animating;
+} VcardTab;
+
+static void SetDialogField( HWND hwndDlg, int nDlgItem, char* key )
+{
+ DBVARIANT dbv;
+
+ if ( !DBGetContactSettingTString( NULL, jabberProtoName, key, &dbv )) {
+ SetDlgItemText( hwndDlg, nDlgItem, dbv.ptszVal );
+ JFreeVariant( &dbv );
+ }
+ else SetDlgItemTextA( hwndDlg, nDlgItem, "" );
+}
+
+static BOOL CALLBACK PersonalDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ SendMessage( GetDlgItem( hwndDlg, IDC_GENDER ), CB_ADDSTRING, 0, ( LPARAM )TranslateT( "Male" ));
+ SendMessage( GetDlgItem( hwndDlg, IDC_GENDER ), CB_ADDSTRING, 0, ( LPARAM )TranslateT( "Female" ));
+ SendMessage( hwndDlg, WM_JABBER_REFRESH, 0, 0 );
+ return TRUE;
+ case WM_JABBER_REFRESH:
+ SetDialogField( hwndDlg, IDC_FULLNAME, "FullName" );
+ SetDialogField( hwndDlg, IDC_NICKNAME, "Nick" );
+ SetDialogField( hwndDlg, IDC_FIRSTNAME, "FirstName" );
+ SetDialogField( hwndDlg, IDC_MIDDLE, "MiddleName" );
+ SetDialogField( hwndDlg, IDC_LASTNAME, "LastName" );
+ SetDialogField( hwndDlg, IDC_BIRTH, "BirthDate" );
+ SetDialogField( hwndDlg, IDC_GENDER, "GenderString" );
+ SetDialogField( hwndDlg, IDC_OCCUPATION, "Role" );
+ SetDialogField( 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 )) )
+ SendMessage( GetParent( hwndDlg ), WM_JABBER_CHANGED, 0, 0 );
+ break;
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK HomeDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ SendMessage( hwndDlg, WM_JABBER_REFRESH, 0, 0 );
+ return TRUE;
+ case WM_JABBER_REFRESH:
+ SetDialogField( hwndDlg, IDC_ADDRESS1, "Street" );
+ SetDialogField( hwndDlg, IDC_ADDRESS2, "Street2" );
+ SetDialogField( hwndDlg, IDC_CITY, "City" );
+ SetDialogField( hwndDlg, IDC_STATE, "State" );
+ SetDialogField( hwndDlg, IDC_ZIP, "ZIP" );
+ SetDialogField( hwndDlg, IDC_COUNTRY, "CountryName" );
+ break;
+ case WM_COMMAND:
+ if (( HWND )lParam==GetFocus() && HIWORD( wParam )==EN_CHANGE )
+ SendMessage( GetParent( hwndDlg ), WM_JABBER_CHANGED, 0, 0 );
+ break;
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK WorkDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ SendMessage( hwndDlg, WM_JABBER_REFRESH, 0, 0 );
+ return TRUE;
+ case WM_JABBER_REFRESH:
+ SetDialogField( hwndDlg, IDC_COMPANY, "Company" );
+ SetDialogField( hwndDlg, IDC_DEPARTMENT, "CompanyDepartment" );
+ SetDialogField( hwndDlg, IDC_TITLE, "CompanyPosition" );
+ SetDialogField( hwndDlg, IDC_ADDRESS1, "CompanyStreet" );
+ SetDialogField( hwndDlg, IDC_ADDRESS2, "CompanyStreet2" );
+ SetDialogField( hwndDlg, IDC_CITY, "CompanyCity" );
+ SetDialogField( hwndDlg, IDC_STATE, "CompanyState" );
+ SetDialogField( hwndDlg, IDC_ZIP, "CompanyZIP" );
+ SetDialogField( hwndDlg, IDC_COUNTRY, "CompanyCountryName" );
+ break;
+ case WM_COMMAND:
+ if (( HWND )lParam==GetFocus() && HIWORD( wParam )==EN_CHANGE )
+ SendMessage( GetParent( hwndDlg ), WM_JABBER_CHANGED, 0, 0 );
+ break;
+ }
+ return FALSE;
+}
+
+static char szPhotoFileName[MAX_PATH];
+static char szPhotoType[33];
+static BOOL bPhotoChanged;
+
+static BOOL CALLBACK PhotoDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ static HBITMAP hBitmap;
+ char szTempPath[MAX_PATH], szTempFileName[MAX_PATH];
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ hBitmap = NULL;
+ SendMessage( GetDlgItem( hwndDlg, IDC_LOAD ), BM_SETIMAGE, IMAGE_ICON, ( LPARAM )LoadImage( hInst, MAKEINTRESOURCE( IDI_OPEN ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 ));
+ SendMessage( GetDlgItem( hwndDlg, IDC_DELETE ), BM_SETIMAGE, IMAGE_ICON, ( LPARAM )LoadImage( hInst, MAKEINTRESOURCE( IDI_DELETE ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 ));
+ ShowWindow( GetDlgItem( hwndDlg, IDC_SAVE ), SW_HIDE );
+ SendMessage( hwndDlg, WM_JABBER_REFRESH, 0, 0 );
+ return TRUE;
+ case WM_JABBER_REFRESH:
+ if ( hBitmap ) {
+ DeleteObject( hBitmap );
+ hBitmap = NULL;
+ DeleteFileA( szPhotoFileName );
+ szPhotoFileName[0] = '\0';
+ }
+ EnableWindow( GetDlgItem( hwndDlg, IDC_DELETE ), FALSE );
+ if ( jabberVcardPhotoFileName ) {
+ if ( GetTempPathA( sizeof( szTempPath ), szTempPath ) <= 0 )
+ strcpy( szTempPath, ".\\" );
+ if ( GetTempFileNameA( szTempPath, "jab", 0, szTempFileName ) > 0 ) {
+ JabberLog( "Temp file = %s", szTempFileName );
+ if ( CopyFileA( jabberVcardPhotoFileName, szTempFileName, FALSE ) == TRUE ) {
+ if (( hBitmap=( HBITMAP ) JCallService( MS_UTILS_LOADBITMAP, 0, ( LPARAM )szTempFileName )) != NULL ) {
+ strcpy( szPhotoFileName, szTempFileName );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_DELETE ), TRUE );
+ }
+ else DeleteFileA( szTempFileName );
+ }
+ else DeleteFileA( szTempFileName );
+ }
+ }
+ bPhotoChanged = FALSE;
+ InvalidateRect( hwndDlg, NULL, TRUE );
+ UpdateWindow( hwndDlg );
+ break;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_LOAD:
+ {
+ OPENFILENAMEA ofn = {0};
+ static char szFilter[512];
+ char szFileName[_MAX_PATH];
+ char* p;
+ int n;
+
+// JCallService( MS_UTILS_GETBITMAPFILTERSTRINGS, ( WPARAM ) sizeof( szFilter ), ( LPARAM )szFilter );
+ p = szFilter;
+ n = sizeof( szFilter );
+ strncpy( p, JTranslate( "All Bitmaps" ), n ); n = sizeof( szFilter )-strlen( szFilter );
+ strncat( p, " ( *.bmp;*.jpg;*.jpeg;*.gif )", n ); n = sizeof( szFilter )-strlen( szFilter );
+ p += strlen( p )+1; n = sizeof( szFilter )-( p-szFilter );
+ strncpy( p, "*.BMP;*.JPG;*.JPEG;*.GIF", n );
+ szFilter[512-1] = '\0';
+
+
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner = hwndDlg;
+ ofn.lpstrFilter = szFilter;
+ ofn.lpstrCustomFilter = NULL;
+ ofn.lpstrFile = szFileName;
+ ofn.nMaxFile = _MAX_PATH;
+ ofn.Flags = OFN_FILEMUSTEXIST;
+ szFileName[0] = '\0';
+ if ( GetOpenFileNameA( &ofn )) {
+ struct _stat st;
+ HBITMAP hNewBitmap;
+
+ JabberLog( "File selected is %s", szFileName );
+ if ( _stat( 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 ( GetTempPathA( sizeof( szTempPath ), szTempPath ) <= 0 )
+ strcpy( szTempPath, ".\\" );
+ if ( GetTempFileNameA( szTempPath, "jab", 0, szTempFileName ) > 0 ) {
+ JabberLog( "Temp file = %s", szTempFileName );
+ if ( CopyFileA( szFileName, szTempFileName, FALSE ) == TRUE ) {
+ if (( hNewBitmap=( HBITMAP ) JCallService( MS_UTILS_LOADBITMAP, 0, ( LPARAM )szTempFileName )) != NULL ) {
+ if ( hBitmap ) {
+ DeleteObject( hBitmap );
+ DeleteFileA( szPhotoFileName );
+ }
+ if (( p=strrchr( szFileName, '.' )) != NULL ) {
+ if ( !stricmp( p, ".bmp" ))
+ strcpy( szPhotoType, "image/bmp" );
+ else if ( !stricmp( p, ".gif" ))
+ strcpy( szPhotoType, "image/gif" );
+ else
+ strcpy( szPhotoType, "image/jpeg" );
+ }
+ else
+ strcpy( szPhotoType, "image/jpeg" );
+ hBitmap = hNewBitmap;
+ strcpy( szPhotoFileName, szTempFileName );
+ bPhotoChanged = TRUE;
+ EnableWindow( GetDlgItem( hwndDlg, IDC_DELETE ), TRUE );
+ InvalidateRect( hwndDlg, NULL, TRUE );
+ UpdateWindow( hwndDlg );
+ SendMessage( GetParent( hwndDlg ), WM_JABBER_CHANGED, 0, 0 );
+ }
+ else {
+ DeleteFileA( szTempFileName );
+ }
+ }
+ else
+ DeleteFileA( szTempFileName );
+ }
+ }
+ }
+ break;
+ case IDC_DELETE:
+ if ( hBitmap ) {
+ DeleteObject( hBitmap );
+ hBitmap = NULL;
+ DeleteFileA( szPhotoFileName );
+ szPhotoFileName[0] = '\0';
+ bPhotoChanged = TRUE;
+ EnableWindow( GetDlgItem( hwndDlg, IDC_DELETE ), FALSE );
+ InvalidateRect( hwndDlg, NULL, TRUE );
+ UpdateWindow( hwndDlg );
+ SendMessage( GetParent( hwndDlg ), WM_JABBER_CHANGED, 0, 0 );
+ }
+ break;
+ }
+ break;
+ case WM_PAINT:
+ if ( 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, 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;
+ BitBlt( hdcCanvas, pt.x, pt.y, ptSize.x, ptSize.y, hdcMem, ptOrg.x, ptOrg.y, SRCCOPY );
+ }
+ 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;
+ }
+ 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:
+ if ( hBitmap ) {
+ JabberLog( "Delete bitmap" );
+ DeleteObject( hBitmap );
+ DeleteFileA( szPhotoFileName );
+ szPhotoFileName[0] = '\0';
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK NoteDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ SendMessage( hwndDlg, WM_JABBER_REFRESH, 0, 0 );
+ return TRUE;
+ case WM_JABBER_REFRESH:
+ SetDialogField( hwndDlg, IDC_DESC, "About" );
+ break;
+ case WM_COMMAND:
+ if (( HWND )lParam==GetFocus() && HIWORD( wParam )==EN_CHANGE )
+ SendMessage( GetParent( hwndDlg ), WM_JABBER_CHANGED, 0, 0 );
+ break;
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK EditEmailDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ SetWindowLong( hwndDlg, GWL_USERDATA, lParam );
+ if ( lParam >= 0 ) {
+ DBVARIANT dbv;
+ char idstr[33];
+ WORD nFlag;
+
+ SetWindowText( hwndDlg, TranslateT( "Jabber vCard: Edit Email Address" ));
+ wsprintfA( idstr, "e-mail%d", lParam );
+ if ( !DBGetContactSetting( NULL, jabberProtoName, idstr, &dbv )) {
+ SetDlgItemTextA( hwndDlg, IDC_EMAIL, dbv.pszVal );
+ JFreeVariant( &dbv );
+ wsprintfA( idstr, "e-mailFlag%d", lParam );
+ nFlag = DBGetContactSettingWord( NULL, jabberProtoName, 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 );
+ }
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDOK:
+ {
+ TCHAR text[128];
+ char idstr[33];
+ int id = ( int ) GetWindowLong( hwndDlg, GWL_USERDATA );
+ DBVARIANT dbv;
+ WORD nFlag;
+
+ if ( id < 0 ) {
+ for ( id=0;;id++ ) {
+ mir_snprintf( idstr, SIZEOF(idstr), "e-mail%d", id );
+ if ( DBGetContactSetting( NULL, jabberProtoName, idstr, &dbv )) break;
+ JFreeVariant( &dbv );
+ } }
+ GetDlgItemText( hwndDlg, IDC_EMAIL, text, SIZEOF( text ));
+ mir_snprintf( idstr, SIZEOF(idstr), "e-mail%d", id );
+ 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", id );
+ JSetWord( NULL, idstr, nFlag );
+ }
+ // fall through
+ case IDCANCEL:
+ EndDialog( hwndDlg, wParam );
+ break;
+ }
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK EditPhoneDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ SetWindowLong( hwndDlg, GWL_USERDATA, lParam );
+ if ( lParam >= 0 ) {
+ DBVARIANT dbv;
+ char idstr[33];
+ WORD nFlag;
+
+ SetWindowText( hwndDlg, TranslateT( "Jabber vCard: Edit Phone Number" ));
+ wsprintfA( idstr, "Phone%d", lParam );
+ if ( !DBGetContactSetting( NULL, jabberProtoName, idstr, &dbv )) {
+ SetDlgItemTextA( hwndDlg, IDC_PHONE, dbv.pszVal );
+ JFreeVariant( &dbv );
+ wsprintfA( idstr, "PhoneFlag%d", lParam );
+ nFlag = 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 );
+ }
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDOK:
+ {
+ char text[128];
+ char idstr[33];
+ int id = ( int ) GetWindowLong( hwndDlg, GWL_USERDATA );
+ DBVARIANT dbv;
+ WORD nFlag;
+
+ if ( id < 0 ) {
+ for ( id=0;;id++ ) {
+ wsprintfA( idstr, "Phone%d", id );
+ if ( DBGetContactSetting( NULL, jabberProtoName, idstr, &dbv )) break;
+ JFreeVariant( &dbv );
+ }
+ }
+ GetDlgItemTextA( hwndDlg, IDC_PHONE, text, SIZEOF( text ));
+ wsprintfA( idstr, "Phone%d", id );
+ 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", id );
+ JSetWord( NULL, idstr, nFlag );
+ }
+ // fall through
+ case IDCANCEL:
+ EndDialog( hwndDlg, wParam );
+ break;
+ }
+ }
+ return FALSE;
+}
+
+#define M_REMAKELISTS ( WM_USER+1 )
+static BOOL CALLBACK ContactDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch( msg ) {
+ case WM_INITDIALOG:
+ {
+ LVCOLUMN lvc;
+ RECT rc;
+
+ 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 );
+ }
+ return TRUE;
+ 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, jabberProtoName, 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, jabberProtoName, 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 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:
+ SetWindowLong( hwndDlg, DWL_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 );
+ SetWindowLong( hwndDlg, DWL_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
+ if ( DialogBoxParam( hInst, MAKEINTRESOURCE( nm->hdr.idFrom==IDC_PHONES?IDD_VCARD_ADDPHONE:IDD_VCARD_ADDEMAIL ), hwndDlg, nm->hdr.idFrom==IDC_PHONES?EditPhoneDlgProc:EditEmailDlgProc, ( LPARAM )( -1 )) != IDOK )
+ break;
+ SendMessage( hwndDlg, M_REMAKELISTS, 0, 0 );
+ SendMessage( GetParent( hwndDlg ), WM_JABBER_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 ( DBGetContactSetting( NULL, jabberProtoName, idstr, &dbv )) break;
+ wsprintfA( idstr,szIdTemplate,i );
+ JSetString( NULL, idstr, dbv.pszVal );
+ wsprintfA( idstr, szFlagTemplate, i+1 );
+ JFreeVariant( &dbv );
+ nFlag = JGetWord( NULL, idstr, 0 );
+ wsprintfA( idstr, szFlagTemplate, i );
+ JSetWord( NULL, idstr, nFlag );
+ }
+ wsprintfA( idstr, szIdTemplate, i );
+ JDeleteSetting( NULL, idstr );
+ wsprintfA( idstr, szFlagTemplate, i );
+ JDeleteSetting( NULL, idstr );
+ SendMessage( hwndDlg, M_REMAKELISTS, 0, 0 );
+ SendMessage( GetParent( hwndDlg ), WM_JABBER_CHANGED, 0, 0 );
+ }
+ else if ( hti.iSubItem == 2 ) {
+ //edit
+ if ( DialogBoxParam( hInst, MAKEINTRESOURCE( nm->hdr.idFrom==IDC_PHONES?IDD_VCARD_ADDPHONE:IDD_VCARD_ADDEMAIL ), hwndDlg, nm->hdr.idFrom==IDC_PHONES?EditPhoneDlgProc:EditEmailDlgProc, lvi.lParam ) != IDOK )
+ break;
+ SendMessage( hwndDlg,M_REMAKELISTS,0,0 );
+ SendMessage( GetParent( hwndDlg ), WM_JABBER_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;
+ }
+ return FALSE;
+}
+
+static void SaveVcardToDB( VcardTab *dat )
+{
+ HWND hwndPage;
+ TCHAR text[2048];
+
+ if ( dat==NULL || dat->page==NULL ) return;
+
+ // Page 0: Personal
+ if (( hwndPage=dat->page[0].hwnd ) != NULL ) {
+ 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 );
+ GetDlgItemText( hwndPage, IDC_GENDER, text, SIZEOF( text ));
+ JSetStringT( NULL, "GenderString", text );
+ GetDlgItemText( hwndPage, IDC_OCCUPATION, text, SIZEOF( text ));
+ JSetStringT( NULL, "Role", text );
+ GetDlgItemText( hwndPage, IDC_HOMEPAGE, text, SIZEOF( text ));
+ JSetStringT( NULL, "Homepage", text );
+ }
+ // Page 1: Contacts
+ // no need to save, always in sync with the DB
+ // Page 2: Home
+ if (( hwndPage=dat->page[2].hwnd ) != NULL ) {
+ 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 );
+ GetDlgItemText( hwndPage, IDC_COUNTRY, text, SIZEOF( text ));
+ JSetStringT( NULL, "CountryName", text );
+ }
+ // Page 3: Work
+ if (( hwndPage=dat->page[3].hwnd ) != NULL ) {
+ 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 );
+ GetDlgItemText( hwndPage, IDC_COUNTRY, text, SIZEOF( text ));
+ JSetStringT( NULL, "CompanyCountryName", text );
+ }
+ // Page 4: Photo
+ // not saved in the database
+ // Page 5: Note
+ if (( hwndPage=dat->page[5].hwnd ) != NULL ) {
+ GetDlgItemText( hwndPage, IDC_DESC, text, SIZEOF( text ));
+ JSetStringT( NULL, "About", text );
+ }
+}
+
+static void AppendVcardFromDB( XmlNode* n, char* tag, char* key )
+{
+ if ( n == NULL || tag == NULL || key == NULL )
+ return;
+
+ DBVARIANT dbv;
+ if ( DBGetContactSettingTString( NULL, jabberProtoName, key, &dbv ))
+ n->addChild( tag );
+ else {
+ n->addChild( tag, dbv.ptszVal );
+ JFreeVariant( &dbv );
+} }
+
+static void SetServerVcard()
+{
+ DBVARIANT dbv;
+ int iqId;
+ char *szFileName, *szFileType;
+ int i;
+ char idstr[33];
+ WORD nFlag;
+
+ iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_SETVCARD, JabberIqResultSetVcard );
+
+ XmlNodeIq iq( "set", iqId );
+ XmlNode* v = iq.addChild( "vCard" ); v->addAttr( "xmlns", "vcard-temp" );
+
+ AppendVcardFromDB( v, "FN", "FullName" );
+
+ XmlNode* n = v->addChild( "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, jabberProtoName, idstr, &dbv ))
+ break;
+
+ XmlNode* e = v->addChild( "EMAIL", dbv.ptszVal );
+ JFreeVariant( &dbv );
+ AppendVcardFromDB( e, "USERID", idstr );
+
+ wsprintfA( idstr, "e-mailFlag%d", i );
+ nFlag = DBGetContactSettingWord( NULL, jabberProtoName, idstr, 0 );
+ if ( nFlag & JABBER_VCEMAIL_HOME ) e->addChild( "HOME" );
+ if ( nFlag & JABBER_VCEMAIL_WORK ) e->addChild( "WORK" );
+ if ( nFlag & JABBER_VCEMAIL_INTERNET ) e->addChild( "INTERNET" );
+ if ( nFlag & JABBER_VCEMAIL_X400 ) e->addChild( "X400" );
+ }
+
+ n = v->addChild( "ADR" );
+ n->addChild( "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", "CountryName" );
+ AppendVcardFromDB( n, "COUNTRY", "CountryName" ); // for compatibility with client using old vcard format
+
+ n = v->addChild( "ADR" );
+ n->addChild( "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", "CompanyCountryName" );
+ AppendVcardFromDB( n, "COUNTRY", "CompanyCountryName" ); // for compatibility with client using old vcard format
+
+ n = v->addChild( "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, jabberProtoName, idstr, &dbv )) break;
+ JFreeVariant( &dbv );
+
+ n = v->addChild( "TEL" );
+ AppendVcardFromDB( n, "NUMBER", idstr );
+
+ wsprintfA( idstr, "PhoneFlag%d", i );
+ nFlag = JGetWord( NULL, idstr, 0 );
+ if ( nFlag & JABBER_VCTEL_HOME ) n->addChild( "HOME" );
+ if ( nFlag & JABBER_VCTEL_WORK ) n->addChild( "WORK" );
+ if ( nFlag & JABBER_VCTEL_VOICE ) n->addChild( "VOICE" );
+ if ( nFlag & JABBER_VCTEL_FAX ) n->addChild( "FAX" );
+ if ( nFlag & JABBER_VCTEL_PAGER ) n->addChild( "PAGER" );
+ if ( nFlag & JABBER_VCTEL_MSG ) n->addChild( "MSG" );
+ if ( nFlag & JABBER_VCTEL_CELL ) n->addChild( "CELL" );
+ if ( nFlag & JABBER_VCTEL_VIDEO ) n->addChild( "VIDEO" );
+ if ( nFlag & JABBER_VCTEL_BBS ) n->addChild( "BBS" );
+ if ( nFlag & JABBER_VCTEL_MODEM ) n->addChild( "MODEM" );
+ if ( nFlag & JABBER_VCTEL_ISDN ) n->addChild( "ISDN" );
+ if ( nFlag & JABBER_VCTEL_PCS ) n->addChild( "PCS" );
+ }
+
+ if ( bPhotoChanged ) {
+ if ( szPhotoFileName[0] ) {
+ szFileName = szPhotoFileName;
+ szFileType = szPhotoType;
+ }
+ else szFileName = NULL;
+ }
+ else {
+ szFileName = jabberVcardPhotoFileName;
+ szFileType = jabberVcardPhotoType;
+ }
+
+ // Set photo element, also update the global jabberVcardPhotoFileName to reflect the update
+ JabberLog( "Before update, jabberVcardPhotoFileName = %s", jabberVcardPhotoFileName );
+ if ( szFileName == NULL ) {
+ v->addChild( "PHOTO" );
+ if ( jabberVcardPhotoFileName ) {
+ DeleteFileA( jabberVcardPhotoFileName );
+ mir_free( jabberVcardPhotoFileName );
+ jabberVcardPhotoFileName = NULL;
+ } }
+ else {
+ char szTempPath[MAX_PATH], szTempFileName[MAX_PATH];
+ HANDLE hFile;
+ struct _stat st;
+ char* buffer, *str;
+ DWORD nRead;
+
+ JabberLog( "Saving picture from %s", szFileName );
+ if ( _stat( szFileName, &st ) >= 0 ) {
+ // Note the FILE_SHARE_READ attribute so that the CopyFile can succeed
+ if (( hFile=CreateFileA( 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->addChild( "PHOTO" );
+ if ( szFileType ) {
+ n->addChild( "TYPE", szFileType );
+ JabberLog( "File type sent is %s", szFileType );
+ }
+ else {
+ n->addChild( "TYPE", "image/jpeg" );
+ JabberLog( "File type sent is default to image/jpge" );
+ }
+
+ n->addChild( "BINVAL", str );
+ mir_free( str );
+
+ if ( szFileName != jabberVcardPhotoFileName ) {
+ if ( jabberVcardPhotoFileName ) {
+ DeleteFileA( jabberVcardPhotoFileName );
+ mir_free( jabberVcardPhotoFileName );
+ jabberVcardPhotoFileName = NULL;
+ if ( jabberVcardPhotoType ) {
+ mir_free( jabberVcardPhotoType );
+ jabberVcardPhotoType = NULL;
+ } }
+
+ if ( GetTempPathA( sizeof( szTempPath ), szTempPath ) <= 0 )
+ strcpy( szTempPath, ".\\" );
+ if ( GetTempFileNameA( szTempPath, "jab", 0, szTempFileName ) > 0 ) {
+ JabberLog( "New global file is %s", szTempFileName );
+ if ( CopyFileA( szFileName, szTempFileName, FALSE ) == TRUE ) {
+ jabberVcardPhotoFileName = mir_strdup( szTempFileName );
+ if ( jabberVcardPhotoType ) mir_free( jabberVcardPhotoType );
+ if ( szFileType )
+ jabberVcardPhotoType = mir_strdup( szFileType );
+ else
+ jabberVcardPhotoType = NULL;
+ }
+ else DeleteFileA( szTempFileName );
+ } } } }
+ mir_free( buffer );
+ }
+ CloseHandle( hFile );
+ } } }
+
+ JabberSend( jabberThreadInfo->s, iq );
+}
+
+static void ThemeDialogBackground( HWND hwnd ) {
+ if ( IsWinVerXPPlus()) {
+ static HMODULE hThemeAPI = NULL;
+ if ( !hThemeAPI ) hThemeAPI = GetModuleHandleA( "uxtheme" );
+ if ( hThemeAPI ) {
+ HRESULT ( STDAPICALLTYPE *MyEnableThemeDialogTexture )( HWND,DWORD ) = ( HRESULT ( STDAPICALLTYPE* )( HWND,DWORD ))GetProcAddress( hThemeAPI,"EnableThemeDialogTexture" );
+ if ( MyEnableThemeDialogTexture )
+ MyEnableThemeDialogTexture( hwnd,0x00000002|0x00000004 ); //0x00000002|0x00000004=ETDT_ENABLETAB
+} } }
+
+static BOOL CALLBACK JabberVcardDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ VcardTab* dat = ( VcardTab* ) GetWindowLong( hwndDlg, GWL_USERDATA );
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ {
+ SendMessage( hwndDlg, WM_SETICON, ICON_BIG, ( LPARAM )LoadIcon( hInst, MAKEINTRESOURCE( IDI_VCARD )) );
+ TranslateDialogDefault( hwndDlg );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_UPDATE ), jabberOnline );
+
+ dat = ( VcardTab * ) mir_alloc( sizeof( VcardTab ));
+ memset( dat, 0, sizeof( VcardTab ));
+ dat->pageCount = 6;
+ dat->currentPage = 0;
+ dat->changed = FALSE;
+ dat->updateAnimFrame = 0;
+ dat->animating = FALSE;
+ dat->page = ( VcardPage * ) mir_alloc( dat->pageCount * sizeof( VcardPage ));
+ memset( dat->page, 0, dat->pageCount * sizeof( VcardPage ));
+
+ HWND hwndTabs = GetDlgItem( hwndDlg, IDC_TABS );
+
+ TCITEM tci = { 0 };
+ tci.mask = TCIF_TEXT;
+ // Page 0: Personal
+ dat->page[0].dlgId = IDD_VCARD_PERSONAL;
+ dat->page[0].dlgProc = PersonalDlgProc;
+ tci.pszText = TranslateT( "Personal" );
+ TabCtrl_InsertItem( hwndTabs, 0, &tci );
+ // Page 1: Contacts
+ dat->page[1].dlgId = IDD_VCARD_CONTACT;
+ dat->page[1].dlgProc = ContactDlgProc;
+ tci.pszText = TranslateT( "Contacts" );
+ TabCtrl_InsertItem( hwndTabs, 1, &tci );
+ // Page 2: Home
+ dat->page[2].dlgId = IDD_VCARD_HOME;
+ dat->page[2].dlgProc = HomeDlgProc;
+ tci.pszText = TranslateT( "Home" );
+ TabCtrl_InsertItem( hwndTabs, 2, &tci );
+ // Page 3: Work
+ dat->page[3].dlgId = IDD_VCARD_WORK;
+ dat->page[3].dlgProc = WorkDlgProc;
+ tci.pszText = TranslateT( "Work" );
+ TabCtrl_InsertItem( hwndTabs, 3, &tci );
+ // Page 4: Photo
+ dat->page[4].dlgId = IDD_VCARD_PHOTO;
+ dat->page[4].dlgProc = PhotoDlgProc;
+ tci.pszText = TranslateT( "Photo" );
+ TabCtrl_InsertItem( hwndTabs, 4, &tci );
+ // Page 5: Note
+ dat->page[5].dlgId = IDD_VCARD_NOTE;
+ dat->page[5].dlgProc = NoteDlgProc;
+ tci.pszText = TranslateT( "Note" );
+ TabCtrl_InsertItem( hwndTabs, 5, &tci );
+
+ GetWindowRect( hwndTabs, &( dat->rectTab ));
+ TabCtrl_AdjustRect( hwndTabs, FALSE, &( dat->rectTab ));
+ { POINT pt = {0,0};
+ ClientToScreen( hwndDlg, &pt );
+ OffsetRect( &( dat->rectTab ), -pt.x, -pt.y );
+ }
+
+ TabCtrl_SetCurSel( hwndTabs, dat->currentPage );
+ dat->page[dat->currentPage].hwnd = CreateDialogParam( hInst, MAKEINTRESOURCE( dat->page[dat->currentPage].dlgId ), hwndDlg, dat->page[dat->currentPage].dlgProc, 0 );
+ ThemeDialogBackground( dat->page[dat->currentPage].hwnd );
+ SetWindowPos( dat->page[dat->currentPage].hwnd, HWND_TOP, dat->rectTab.left, dat->rectTab.top, 0, 0, SWP_NOSIZE );
+ ShowWindow( dat->page[dat->currentPage].hwnd, SW_SHOW );
+
+ SetWindowLong( hwndDlg, GWL_USERDATA, ( LONG ) dat );
+
+ bPhotoChanged = FALSE;
+ szPhotoFileName[0] = '\0';
+
+ if ( jabberOnline ) SendMessage( hwndDlg, WM_COMMAND, IDC_UPDATE, 0 );
+ return TRUE;
+ }
+ case WM_CTLCOLORSTATIC:
+ switch (GetDlgCtrlID((HWND)lParam)) {
+ case IDC_WHITERECT:
+ case IDC_LOGO:
+ case IDC_NAME:
+ case IDC_DESCRIPTION:
+ SetBkColor(( HDC ) wParam, RGB( 255, 255, 255 ));
+ return ( BOOL ) GetStockObject( WHITE_BRUSH );
+
+ case IDC_UPDATING:
+ SetBkColor(( HDC )wParam, GetSysColor( COLOR_3DFACE ));
+ return ( BOOL ) GetSysColorBrush( COLOR_3DFACE );
+ }
+ break;
+
+ case WM_NOTIFY:
+ switch ( wParam ) {
+ case IDC_TABS:
+ switch (( ( LPNMHDR ) lParam )->code ) {
+ case TCN_SELCHANGE:
+ if ( dat->currentPage>=0 && dat->page[dat->currentPage].hwnd!=NULL )
+ ShowWindow( dat->page[dat->currentPage].hwnd, SW_HIDE );
+ dat->currentPage = TabCtrl_GetCurSel( GetDlgItem( hwndDlg, IDC_TABS ));
+ if ( dat->currentPage >= 0 ) {
+ if ( dat->page[dat->currentPage].hwnd == NULL ) {
+ dat->page[dat->currentPage].hwnd = CreateDialogParam( hInst, MAKEINTRESOURCE( dat->page[dat->currentPage].dlgId ), hwndDlg, dat->page[dat->currentPage].dlgProc, 0 );
+ ThemeDialogBackground( dat->page[dat->currentPage].hwnd );
+ SetWindowPos( dat->page[dat->currentPage].hwnd, HWND_TOP, dat->rectTab.left, dat->rectTab.top, 0, 0, SWP_NOSIZE );
+ }
+ ShowWindow( dat->page[dat->currentPage].hwnd, SW_SHOW );
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ case WM_JABBER_CHANGED:
+ dat->changed = TRUE;
+ EnableWindow( GetDlgItem( hwndDlg, IDC_SAVE ), jabberOnline );
+ break;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_UPDATE:
+ EnableWindow( GetDlgItem( hwndDlg,IDC_UPDATE ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg,IDC_SAVE ), FALSE );
+ dat->szUpdating = TranslateT( "Updating" );
+ SetDlgItemText( hwndDlg, IDC_UPDATING, dat->szUpdating );
+ ShowWindow( GetDlgItem( hwndDlg, IDC_UPDATING ), SW_SHOW );
+ JabberSendGetVcard( jabberJID );
+ dat->animating = TRUE;
+ SetTimer( hwndDlg, 1, 200, NULL );
+ break;
+ case IDC_SAVE:
+ EnableWindow( GetDlgItem( hwndDlg,IDC_UPDATE ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg,IDC_SAVE ), FALSE );
+ dat->szUpdating = TranslateT( "Saving" );
+ SetDlgItemText( hwndDlg, IDC_UPDATING, dat->szUpdating );
+ ShowWindow( GetDlgItem( hwndDlg, IDC_UPDATING ), SW_SHOW );
+ dat->animating = TRUE;
+ SetTimer( hwndDlg, 1, 200, NULL );
+ SaveVcardToDB( dat );
+ SetServerVcard();
+ break;
+ case IDCLOSE:
+ DestroyWindow( hwndDlg );
+ break;
+ }
+ break;
+ case WM_TIMER:
+ { TCHAR str[128];
+ mir_sntprintf( str, SIZEOF(str), _T("%.*s%s%.*s"), dat->updateAnimFrame%5, _T("...."), dat->szUpdating, dat->updateAnimFrame%5, _T("...."));
+ SetDlgItemText( hwndDlg, IDC_UPDATING, str );
+ if (( ++dat->updateAnimFrame ) >= 5 ) dat->updateAnimFrame = 0;
+ }
+ break;
+ case WM_JABBER_CHECK_ONLINE:
+ EnableWindow( GetDlgItem( hwndDlg, IDC_UPDATE ), jabberOnline );
+ if ( dat->changed )
+ EnableWindow( GetDlgItem( hwndDlg, IDC_SAVE ), jabberOnline );
+ break;
+ case WM_JABBER_REFRESH:
+ if ( dat->animating ) {
+ KillTimer( hwndDlg, 1 );
+ dat->animating = FALSE;
+ ShowWindow( GetDlgItem( hwndDlg, IDC_UPDATING ), FALSE );
+ }
+ { for ( int i=0; i<dat->pageCount; i++ )
+ if ( dat->page[i].hwnd != NULL )
+ SendMessage( dat->page[i].hwnd, WM_JABBER_REFRESH, 0, 0 );
+ }
+ dat->changed = FALSE;
+ EnableWindow( GetDlgItem( hwndDlg, IDC_UPDATE ), TRUE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_SAVE ), FALSE );
+ break;
+ case WM_CLOSE:
+ DestroyWindow( hwndDlg );
+ break;
+ case WM_DESTROY:
+ hwndJabberVcard = NULL;
+ for ( int i=0; i<dat->pageCount; i++ )
+ if ( dat->page[i].hwnd != NULL )
+ DestroyWindow( dat->page[i].hwnd );
+
+ if ( dat->page ) mir_free( dat->page );
+ if ( dat ) mir_free( dat );
+ break;
+ }
+ return FALSE;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_ws.cpp b/miranda-wine/protocols/JabberG/jabber_ws.cpp
new file mode 100644
index 0000000..a2bd1d1
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_ws.cpp
@@ -0,0 +1,92 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_ws.cpp,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+
+BOOL JabberWsInit( void )
+{
+ NETLIBUSER nlu = {0};
+ char name[128];
+
+ sprintf( name, "%s %s", jabberModuleName, JTranslate( "connection" ));
+
+ nlu.cbSize = sizeof( nlu );
+ nlu.flags = NUF_OUTGOING | NUF_INCOMING | NUF_HTTPCONNS; // | NUF_HTTPGATEWAY;
+ nlu.szDescriptiveName = name;
+ nlu.szSettingsModule = jabberProtoName;
+ //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;
+ hNetlibUser = ( HANDLE ) JCallService( MS_NETLIB_REGISTERUSER, 0, ( LPARAM )&nlu );
+
+ return ( hNetlibUser!=NULL )?TRUE:FALSE;
+}
+
+void JabberWsUninit( void )
+{
+ Netlib_CloseHandle( hNetlibUser );
+ hNetlibUser = NULL;
+}
+
+JABBER_SOCKET JabberWsConnect( char* host, WORD port )
+{
+ NETLIBOPENCONNECTION nloc = { 0 };
+ nloc.cbSize = sizeof( nloc );
+ nloc.szHost = host;
+ nloc.wPort = port;
+ return ( HANDLE )JCallService( MS_NETLIB_OPENCONNECTION, ( WPARAM ) hNetlibUser, ( LPARAM )&nloc );
+}
+
+int JabberWsSend( JABBER_SOCKET hConn, char* data, int datalen )
+{
+ int len;
+
+ if (( len=Netlib_Send( hConn, data, datalen, MSG_DUMPASTEXT ))==SOCKET_ERROR || len!=datalen ) {
+ JabberLog( "Netlib_Send() failed, error=%d", WSAGetLastError());
+ return FALSE;
+ }
+ return TRUE;
+}
+
+int JabberWsRecv( JABBER_SOCKET hConn, char* data, long datalen )
+{
+ int ret;
+
+ ret = Netlib_Recv( hConn, data, datalen, MSG_DUMPASTEXT );
+ if( ret == SOCKET_ERROR ) {
+ JabberLog( "Netlib_Recv() failed, error=%d", WSAGetLastError());
+ return 0;
+ }
+ if( ret == 0 ) {
+ JabberLog( "Connection closed gracefully" );
+ return 0;
+ }
+ return ret;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_xml.cpp b/miranda-wine/protocols/JabberG/jabber_xml.cpp
new file mode 100644
index 0000000..d3bd155
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_xml.cpp
@@ -0,0 +1,786 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_xml.cpp,v $
+Revision : $Revision: 3703 $
+Last change on : $Date: 2006-09-05 17:54:42 +0400 (Втр, 05 Сен 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+
+static BOOL JabberXmlProcessElem( XmlState *xmlState, XmlElemType elemType, char* elemText, char* elemAttr );
+static void JabberXmlRemoveChild( XmlNode *node, XmlNode *child );
+
+void JabberXmlInitState( XmlState *xmlState )
+{
+ if ( xmlState == NULL ) return;
+ xmlState->root.name = NULL;
+ xmlState->root.depth = 0;
+ xmlState->root.numAttr = 0;
+ xmlState->root.maxNumAttr = 0;
+ xmlState->root.attr = NULL;
+ xmlState->root.numChild = 0;
+ xmlState->root.maxNumChild = 0;
+ xmlState->root.child = NULL;
+ xmlState->root.text = NULL;
+ xmlState->root.state = NODE_OPEN;
+ xmlState->callback1_open = NULL;
+ xmlState->callback1_close = NULL;
+ xmlState->callback2_open = NULL;
+ xmlState->callback2_close = NULL;
+ xmlState->userdata1_open = NULL;
+ xmlState->userdata1_close = NULL;
+ xmlState->userdata2_open = NULL;
+ xmlState->userdata2_close = NULL;
+}
+
+void JabberXmlDestroyState( XmlState *xmlState )
+{
+ int i;
+ XmlNode *node;
+
+ if ( xmlState == NULL ) return;
+ // Note: cannot use JabberXmlFreeNode() to mir_free xmlState->root
+ // because it will do mir_free( xmlState->root ) which is not freeable.
+ node = &( xmlState->root );
+
+ // Free all children first
+ for ( i=0; i<node->numChild; i++ )
+ delete node->child[i];
+ if ( node->child ) mir_free( node->child );
+
+ // Free all attributes
+ for ( i=0; i<node->numAttr; i++ )
+ delete node->attr[i];
+ if ( node->attr ) mir_free( node->attr );
+
+ // Free string field
+ if ( node->text ) mir_free( node->text );
+ if ( node->name ) mir_free( node->name );
+
+ memset( xmlState, 0, sizeof( XmlState ));
+}
+
+BOOL JabberXmlSetCallback( XmlState *xmlState, int depth, XmlElemType type, JABBER_XML_CALLBACK callback, void *userdata )
+{
+ if ( depth==1 && type==ELEM_OPEN ) {
+ xmlState->callback1_open = callback;
+ xmlState->userdata1_open = userdata;
+ }
+ else if ( depth==1 && type==ELEM_CLOSE ) {
+ xmlState->callback1_close = callback;
+ xmlState->userdata1_close = userdata;
+ }
+ else if ( depth==2 && type==ELEM_OPEN ) {
+ xmlState->callback2_open = callback;
+ xmlState->userdata2_open = userdata;
+ }
+ else if ( depth==2 && type==ELEM_CLOSE ) {
+ xmlState->callback2_close = callback;
+ xmlState->userdata2_close = userdata;
+ }
+ else
+ return FALSE;
+
+ return TRUE;
+}
+
+#define TAG_MAX_LEN 50
+#define ATTR_MAX_LEN 1024
+
+static char* skipSpaces( char* p, int* num = NULL )
+{
+ int i;
+
+ for ( i=0; *p != 0 && isspace( BYTE( *p )); i++ )
+ p++;
+
+ if ( num != NULL )
+ num += i;
+ return p;
+}
+
+static char* findClose( char* p )
+{
+ while ( *p != 0 ) {
+ switch( *p ) {
+ case '>': return p;
+
+ case '\'':
+ case '\"':
+ p = strchr( p+1, *p );
+ if ( p == NULL )
+ return NULL;
+ }
+
+ p++;
+ }
+
+ return NULL;
+}
+
+int JabberXmlParse( XmlState *xmlState, char* buffer )
+{
+ char* r;
+ int num = 0;
+ char tag[TAG_MAX_LEN];
+ char attr[ATTR_MAX_LEN];
+ XmlElemType elemType;
+
+ char* p = skipSpaces( buffer, &num );
+
+ while ( *p != 0 ) {
+ // found starting bracket
+ if ( *p == '<' ) {
+ if ( memcmp( p, "<!--", 4 ) == 0 ) {
+ char* q = strstr( p+4, "-->" );
+ if ( q == NULL )
+ break;
+
+ p = q+3;
+ continue;
+ }
+
+ char* q = findClose( p+1 );
+ if ( q == NULL )
+ break;
+
+ // found closing bracket
+ for ( r=p+1; *r!='>' && *r!=' ' && *r!='\t'; r++ );
+ if ( r-( p+1 ) > TAG_MAX_LEN ) {
+ JabberLog( "TAG_MAX_LEN too small, ignore current tag" );
+ }
+ else {
+ if ( *( p+1 ) == '/' ) { // closing tag
+ strncpy( tag, p+2, r-( p+2 ));
+ tag[r-( p+2 )] = '\0';
+ elemType = ELEM_CLOSE;
+ }
+ else {
+ if ( *( r-1 ) == '/' ) { // single open/close tag
+ strncpy( tag, p+1, r-( p+1 )-1 );
+ tag[r-( p+1 )-1] = '\0';
+ elemType = ELEM_OPENCLOSE;
+ }
+ else {
+ strncpy( tag, p+1, r-( p+1 ));
+ tag[r-( p+1 )] = '\0';
+ elemType = ELEM_OPEN;
+ }
+ }
+ for ( ;r<q && ( *r==' ' || *r=='\t' ); r++ );
+ if ( q-r > ATTR_MAX_LEN ) {
+ JabberLog( "ATTR_MAX_LEN too small, ignore current tag" );
+ }
+ else {
+ strncpy( attr, r, q-r );
+ if (( q-r )>0 && attr[q-r-1]=='/' ) {
+ attr[q-r-1] = '\0';
+ elemType = ELEM_OPENCLOSE;
+ }
+ else
+ attr[q-r] = '\0';
+ JabberXmlProcessElem( xmlState, elemType, tag, attr );
+ }
+ }
+ num += ( q-p+1 );
+ p = q + 1;
+ if ( elemType==ELEM_CLOSE || elemType==ELEM_OPENCLOSE )
+ p = skipSpaces( p, &num ); // Skip whitespaces after end tags
+ }
+ else { // found inner text
+ char* q = strchr( p+1, '<' );
+ if ( q == NULL )
+ break;
+
+ // found starting bracket of the next element
+ char* str = ( char* )mir_alloc( q-p+1 );
+ strncpy( str, p, q-p );
+ str[q-p] = '\0';
+ JabberXmlProcessElem( xmlState, ELEM_TEXT, str, NULL );
+ mir_free( str );
+ num += ( q-p );
+ p = q;
+ } }
+
+ return num;
+}
+
+static void JabberXmlParseAttr( XmlNode *node, char* text )
+{
+ char* kstart, *vstart;
+ int klen, vlen;
+ char* p;
+ XmlAttr *a;
+
+ if ( node==NULL || text==NULL || strlen( text )<=0 )
+ return;
+
+ for ( p=text;; ) {
+
+ // Skip leading whitespaces
+ p = skipSpaces( p );
+ if ( *p == '\0' )
+ break;
+
+ // Fetch key
+ kstart = p;
+ for ( ;*p!='\0' && *p!='=' && *p!=' ' && *p!='\t'; p++ );
+ klen = p-kstart;
+
+ if ( node->numAttr >= node->maxNumAttr ) {
+ node->maxNumAttr = node->numAttr + 20;
+ node->attr = ( XmlAttr ** ) mir_realloc( node->attr, node->maxNumAttr*sizeof( XmlAttr * ));
+ }
+ a = node->attr[node->numAttr] = new XmlAttr();
+ node->numAttr++;
+
+ // Skip possible whitespaces between key and '='
+ p = skipSpaces( p );
+
+ if ( *p == '\0' ) {
+ a->name = ( char* )mir_alloc( klen+1 );
+ strncpy( a->name, kstart, klen );
+ a->name[klen] = '\0';
+ a->value = mir_tstrdup( _T(""));
+ break;
+ }
+
+ if ( *p != '=' ) {
+ a->name = ( char* )mir_alloc( klen+1 );
+ strncpy( a->name, kstart, klen );
+ a->name[klen] = '\0';
+ a->value = mir_tstrdup( _T(""));
+ continue;
+ }
+
+ // Found '='
+ p++;
+
+ // Skip possible whitespaces between '=' and value
+ p = skipSpaces( p );
+
+ if ( *p == '\0' ) {
+ a->name = ( char* )mir_alloc( klen+1 );
+ strncpy( a->name, kstart, klen );
+ a->name[klen] = '\0';
+ a->value = mir_tstrdup( _T(""));
+ break;
+ }
+
+ // Fetch value
+ if ( *p=='\'' || *p=='"' ) {
+ p++;
+ vstart = p;
+ for ( ;*p!='\0' && *p!=*( vstart-1 ); p++ );
+ vlen = p-vstart;
+ if ( *p != '\0' ) p++;
+ }
+ else {
+ vstart = p;
+ for ( ;*p!='\0' && *p!=' ' && *p!='\t'; p++ );
+ vlen = p-vstart;
+ }
+
+ a->name = ( char* )mir_alloc( klen+1 );
+ strncpy( a->name, kstart, klen );
+ a->name[klen] = '\0';
+
+ JabberUtfToTchar( vstart, vlen, a->value );
+ }
+}
+
+static BOOL JabberXmlProcessElem( XmlState *xmlState, XmlElemType elemType, char* elemText, char* elemAttr )
+{
+ XmlNode *node, *parentNode, *n;
+ BOOL activateCallback = FALSE;
+ char* text, *attr;
+
+ if ( elemText == NULL ) return FALSE;
+
+ if ( elemType==ELEM_OPEN && !strcmp( elemText, "?xml" )) {
+ JabberLog( "XML: skip <?xml> tag" );
+ return TRUE;
+ }
+
+ // Find active node
+ node = &( xmlState->root );
+ parentNode = NULL;
+ while ( node->numChild>0 && node->child[node->numChild-1]->state==NODE_OPEN ) {
+ parentNode = node;
+ node = node->child[node->numChild-1];
+ }
+
+ if ( node->state != NODE_OPEN ) return FALSE;
+
+ text = NEWSTR_ALLOCA( elemText );
+
+ if ( elemAttr )
+ attr = NEWSTR_ALLOCA( elemAttr );
+ else
+ attr = NULL;
+
+ switch ( elemType ) {
+ case ELEM_OPEN:
+ if ( node->numChild >= node->maxNumChild ) {
+ node->maxNumChild = node->numChild + 20;
+ node->child = ( XmlNode ** ) mir_realloc( node->child, node->maxNumChild*sizeof( XmlNode * ));
+ }
+ n = node->child[node->numChild] = new XmlNode(text);
+ node->numChild++;
+ n->depth = node->depth + 1;
+ n->state = NODE_OPEN;
+ n->numChild = n->maxNumChild = 0;
+ n->child = NULL;
+ n->numAttr = n->maxNumAttr = 0;
+ n->attr = NULL;
+ JabberXmlParseAttr( n, attr );
+ n->text = NULL;
+ if ( n->depth==1 && xmlState->callback1_open!=NULL )
+ ( *( xmlState->callback1_open ))( n, xmlState->userdata1_open );
+ if ( n->depth==2 && xmlState->callback2_open!=NULL )
+ ( *xmlState->callback2_open )( n, xmlState->userdata2_open );
+ break;
+ case ELEM_OPENCLOSE:
+ if ( node->numChild >= node->maxNumChild ) {
+ node->maxNumChild = node->numChild + 20;
+ node->child = ( XmlNode ** ) mir_realloc( node->child, node->maxNumChild*sizeof( XmlNode * ));
+ }
+ n = node->child[node->numChild] = new XmlNode( text );
+ node->numChild++;
+ n->depth = node->depth + 1;
+ n->state = NODE_CLOSE;
+ n->numChild = n->maxNumAttr = 0;
+ n->child = NULL;
+ n->numAttr = n->maxNumAttr = 0;
+ n->attr = NULL;
+ JabberXmlParseAttr( n, attr );
+ n->text = NULL;
+ if ( n->depth==1 && xmlState->callback1_close!=NULL ) {
+ ( *( xmlState->callback1_close ))( n, xmlState->userdata1_close );
+ JabberXmlRemoveChild( node, n );
+ }
+ if ( n->depth==2 && xmlState->callback2_close!=NULL ) {
+ ( *xmlState->callback2_close )( n, xmlState->userdata2_close );
+ JabberXmlRemoveChild( node, n );
+ }
+ break;
+ case ELEM_CLOSE:
+ if ( node->name!=NULL && !strcmp( node->name, text )) {
+ node->state = NODE_CLOSE;
+ if ( node->depth==1 && xmlState->callback1_close!=NULL ) {
+ ( *( xmlState->callback1_close ))( node, xmlState->userdata1_close );
+ JabberXmlRemoveChild( parentNode, node );
+ }
+ else if ( node->depth==2 && xmlState->callback2_close!=NULL ) {
+ ( *xmlState->callback2_close )( node, xmlState->userdata2_close );
+ JabberXmlRemoveChild( parentNode, node );
+ } }
+ else {
+ JabberLog( "XML: Closing </%s> without opening tag", text );
+ return FALSE;
+ }
+ break;
+ case ELEM_TEXT:
+ JabberUtfToTchar( text, strlen( text ), node->text );
+ break;
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+TCHAR* JabberXmlGetAttrValue( XmlNode *node, char* key )
+{
+ if ( node==NULL || node->numAttr<=0 || key==NULL || strlen( key )<=0 )
+ return NULL;
+
+ for ( int i=0; i<node->numAttr; i++ )
+ if ( !lstrcmpA( key, node->attr[i]->name ))
+ return node->attr[i]->value;
+
+ return NULL;
+}
+
+XmlNode *JabberXmlGetChild( XmlNode *node, char* tag )
+{
+ return JabberXmlGetNthChild( node, tag, 1 );
+}
+
+XmlNode *JabberXmlGetNthChild( XmlNode *node, char* tag, int nth )
+{
+ int i, num;
+
+ if ( node==NULL || node->numChild<=0 || tag==NULL || strlen( tag )<=0 || nth<1 )
+ return NULL;
+ num = 1;
+ for ( i=0; i<node->numChild; i++ ) {
+ if ( node->child[i]->name && !strcmp( tag, node->child[i]->name )) {
+ if ( num == nth ) {
+ return node->child[i];
+ }
+ num++;
+ }
+ }
+ return NULL;
+}
+
+XmlNode *JabberXmlGetChildWithGivenAttrValue( XmlNode *node, char* tag, char* attrKey, TCHAR* attrValue )
+{
+ if ( node==NULL || node->numChild<=0 || tag==NULL || strlen( tag )<=0 || attrKey==NULL || strlen( attrKey )<=0 || attrValue==NULL || lstrlen( attrValue )<=0 )
+ return NULL;
+
+ TCHAR* str;
+ for ( int i=0; i<node->numChild; i++ )
+ if ( node->child[i]->name && !strcmp( tag, node->child[i]->name ))
+ if (( str=JabberXmlGetAttrValue( node->child[i], attrKey )) != NULL )
+ if ( !lstrcmp( str, attrValue ))
+ return node->child[i];
+
+ return NULL;
+}
+
+static void JabberXmlRemoveChild( XmlNode *node, XmlNode *child )
+{
+ int i;
+
+ if ( node==NULL || child==NULL || node->numChild<=0 ) return;
+ for ( i=0; i<node->numChild; i++ ) {
+ if ( node->child[i] == child )
+ break;
+ }
+ if ( i < node->numChild ) {
+ for ( ++i; i<node->numChild; i++ )
+ node->child[i-1] = node->child[i];
+ node->numChild--;
+ delete child;
+ }
+}
+
+XmlNode *JabberXmlCopyNode( XmlNode *node )
+{
+ if ( node == NULL )
+ return NULL;
+
+ XmlNode *n = new XmlNode( node->name );
+ // Copy attributes
+ if ( node->numAttr > 0 ) {
+ n->attr = ( XmlAttr ** ) mir_alloc( node->numAttr*sizeof( XmlAttr * ));
+ for ( int i=0; i < node->numAttr; i++ ) {
+ n->attr[i] = new XmlAttr;
+ if ( node->attr[i]->name )
+ n->attr[i]->name = mir_strdup( node->attr[i]->name );
+ if ( node->attr[i]->value )
+ n->attr[i]->value = mir_tstrdup( node->attr[i]->value );
+ }
+ }
+ else
+ n->attr = NULL;
+ // Recursively copy children
+ if ( node->numChild > 0 ) {
+ n->child = ( XmlNode ** ) mir_alloc( node->numChild*sizeof( XmlNode * ));
+ for ( int i=0; i<node->numChild; i++ )
+ n->child[i] = JabberXmlCopyNode( node->child[i] );
+ }
+ else
+ n->child = NULL;
+ // Copy other fields
+ n->numAttr = node->numAttr;
+ n->maxNumAttr = node->numAttr;
+ n->numChild = node->numChild;
+ n->maxNumChild = node->numChild;
+ n->depth = node->depth;
+ n->state = node->state;
+ n->text = ( node->text )?mir_tstrdup( node->text ):NULL;
+ return n;
+}
+
+XmlNode *JabberXmlAddChild( XmlNode *n, char* name )
+{
+ if ( n==NULL || name==NULL )
+ return NULL;
+
+ XmlNode* result = new XmlNode( name );
+ if ( result == NULL )
+ return NULL;
+
+ return n->addChild( result );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// XmlNodeIq class members
+
+XmlNodeIq::XmlNodeIq( const char* type, int id, const TCHAR* to ) :
+ XmlNode( "iq" )
+{
+ if ( type != NULL ) addAttr( "type", type );
+ if ( to != NULL ) addAttr( "to", to );
+ if ( id != NOID ) addAttrID( id );
+}
+
+XmlNodeIq::XmlNodeIq( const char* type, const TCHAR* idStr, const TCHAR* to ) :
+ XmlNode( "iq" )
+{
+ if ( type != NULL ) addAttr( "type", type );
+ if ( to != NULL ) addAttr( "to", to );
+ if ( idStr != NULL ) addAttr( "id", idStr );
+}
+
+#if defined( _UNICODE )
+XmlNodeIq::XmlNodeIq( const char* type, int id, const char* to ) :
+ XmlNode( "iq" )
+{
+ if ( type != NULL ) addAttr( "type", type );
+ if ( to != NULL ) addAttr( "to", to );
+ if ( id != NOID ) addAttrID( id );
+}
+#endif
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// XmlNode class members
+
+XmlNode::XmlNode( const char* pszName )
+{
+ memset( this, 0, sizeof( XmlNode ));
+ name = mir_strdup( pszName );
+}
+
+XmlNode::XmlNode( const char* pszName, const TCHAR* ptszText )
+{
+ memset( this, 0, sizeof( XmlNode ));
+ name = mir_strdup( pszName );
+ #if defined( _UNICODE )
+ sendText = JabberTextEncodeW( ptszText );
+ #else
+ sendText = JabberTextEncode( ptszText );
+ #endif
+}
+
+#if defined( _UNICODE )
+XmlNode::XmlNode( const char* pszName, const char* ptszText )
+{
+ memset( this, 0, sizeof( XmlNode ));
+ name = mir_strdup( pszName );
+ sendText = JabberTextEncode( ptszText );
+}
+#endif
+
+XmlNode::~XmlNode()
+{
+ if ( this == NULL ) return;
+
+ // Free all children first
+ int i;
+ for ( i=0; i < numChild; i++ )
+ delete child[i];
+ if ( child ) mir_free( child );
+
+ // Free all attributes
+ for ( i=0; i < numAttr; i++ )
+ delete attr[i];
+ if ( attr ) mir_free( attr );
+
+ // Free string field
+ if ( text ) mir_free( text );
+ if ( name ) mir_free( name );
+}
+
+XmlAttr* XmlNode::addAttr( XmlAttr* a )
+{
+ if ( this == NULL || a == NULL )
+ return NULL;
+
+ int i = numAttr++;
+ attr = ( XmlAttr ** ) mir_realloc( attr, sizeof( XmlAttr * ) * numAttr );
+ attr[i] = a;
+ return a;
+}
+
+XmlAttr* XmlNode::addAttr( const char* pszName, const TCHAR* ptszValue )
+{
+ return addAttr( new XmlAttr( pszName, ptszValue ));
+}
+
+#if defined( _UNICODE )
+XmlAttr* XmlNode::addAttr( const char* pszName, const char* pszValue )
+{
+ return addAttr( new XmlAttr( pszName, pszValue ));
+}
+#endif
+
+XmlAttr* XmlNode::addAttr( const char* pszName, int value )
+{
+ if ( this == NULL )
+ return NULL;
+
+ TCHAR buf[ 40 ];
+ _itot( value, buf, 10 );
+ return addAttr( new XmlAttr( pszName, buf ));
+}
+
+XmlAttr* XmlNode::addAttrID( int id )
+{
+ if ( this == NULL )
+ return NULL;
+
+ TCHAR text[ 100 ];
+ mir_sntprintf( text, SIZEOF(text), _T("mir_%d"), id );
+ return addAttr( new XmlAttr( "id", text ));
+}
+
+XmlNode* XmlNode::addChild( XmlNode* pNode )
+{
+ if ( this == NULL || pNode == NULL )
+ return NULL;
+
+ int i = numChild++;
+ child = ( XmlNode ** ) mir_realloc( child, sizeof( XmlNode * ) * numChild );
+ child[i] = pNode;
+ pNode->depth = depth+1;
+ return pNode;
+}
+
+XmlNode* XmlNode::addChild( const char* pszName )
+{
+ return addChild( new XmlNode( pszName ));
+}
+
+XmlNode* XmlNode::addChild( const char* pszName, const TCHAR* ptszValue )
+{
+ return addChild( new XmlNode( pszName, ptszValue ));
+}
+
+#if defined( _UNICODE )
+XmlNode* XmlNode::addChild( const char* pszName, const char* pszValue )
+{
+ return addChild( new XmlNode( pszName, pszValue ));
+}
+#endif
+
+XmlNode* XmlNode::addQuery( const char* szNameSpace )
+{
+ XmlNode* n = addChild( "query" );
+ if ( n )
+ n->addAttr( "xmlns", szNameSpace );
+ return n;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// text extraction routines
+
+static char* sttCopyNode( const XmlNode* n, char* dest )
+{
+ if ( n->props ) {
+ lstrcpyA( dest, n->props ); dest += lstrlenA( n->props );
+ }
+
+ *dest++ = '<';
+ lstrcpyA( dest, n->name ); dest += lstrlenA( n->name );
+
+ for ( int i=0; i < n->numAttr; i++ ) {
+ *dest++ = ' ';
+ lstrcpyA( dest, n->attr[i]->name ); dest += lstrlenA( n->attr[i]->name );
+ *dest++ = '=';
+ *dest++ = '\'';
+ lstrcpyA( dest, n->attr[i]->sendValue ); dest += lstrlenA( n->attr[i]->sendValue );
+ *dest++ = '\'';
+ }
+
+ if ( n->numChild != 0 || n->sendText != NULL )
+ *dest++ = '>';
+
+ if ( n->sendText != NULL ) {
+ lstrcpyA( dest, n->sendText ); dest += lstrlenA( n->sendText );
+ }
+
+ if ( n->numChild != 0 )
+ for ( int i=0; i < n->numChild; i++ )
+ dest = sttCopyNode( n->child[i], dest );
+
+ if ( n->numChild != 0 || n->sendText != NULL ) {
+ *dest++ = '<';
+ *dest++ = '/';
+ lstrcpyA( dest, n->name ); dest += lstrlenA( n->name );
+ }
+ else if ( !n->dirtyHack ) *dest++ = '/';
+
+ *dest++ = '>';
+ *dest = 0;
+ return dest;
+}
+
+char* XmlNode::getText() const
+{
+ int cbLen = getTextLen();
+ char* result = ( char* )mir_alloc( cbLen+1 );
+ if ( result == NULL )
+ return NULL;
+
+ sttCopyNode( this, result );
+ return result;
+}
+
+int XmlNode::getTextLen() const
+{
+ int result = 10 + lstrlenA( props ) + lstrlenA( name )*2 + lstrlenA( sendText );
+
+ for ( int i=0; i < numAttr; i++ )
+ result += lstrlenA( attr[i]->name ) + lstrlenA( attr[i]->sendValue ) + 4;
+
+ for ( int j=0; j < numChild; j++ )
+ result += child[j]->getTextLen();
+
+ return result;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// XmlAttr class members
+
+XmlAttr::XmlAttr() :
+ name( NULL ), value( NULL )
+{
+}
+
+XmlAttr::XmlAttr( const char* pszName, const TCHAR* ptszValue )
+{
+ name = mir_strdup( pszName );
+ #if defined( _UNICODE )
+ sendValue = JabberTextEncodeW( ptszValue );
+ #else
+ sendValue = JabberTextEncode( ptszValue );
+ #endif
+}
+
+#if defined( _UNICODE )
+XmlAttr::XmlAttr( const char* pszName, const char* ptszValue )
+{
+ name = mir_strdup( pszName );
+ sendValue = JabberTextEncode( ptszValue );
+}
+#endif
+
+XmlAttr::~XmlAttr()
+{
+ if ( name != NULL ) mir_free( name );
+ if ( value != NULL ) mir_free( value );
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_xml.h b/miranda-wine/protocols/JabberG/jabber_xml.h
new file mode 100644
index 0000000..50e3268
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_xml.h
@@ -0,0 +1,152 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_xml.h,v $
+Revision : $Revision: 3691 $
+Last change on : $Date: 2006-09-04 10:04:06 +0400 (Пнд, 04 Сен 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#ifndef _JABBER_XML_H_
+#define _JABBER_XML_H_
+
+#define NOID (-1)
+
+typedef enum { ELEM_OPEN, ELEM_CLOSE, ELEM_OPENCLOSE, ELEM_TEXT } XmlElemType;
+typedef enum { NODE_OPEN, NODE_CLOSE } XmlNodeType;
+
+struct XmlAttr
+{
+ XmlAttr();
+ XmlAttr( const char* pszName, const TCHAR* ptszValue );
+ #if defined( _UNICODE )
+ XmlAttr( const char* pszName, const char* ptszValue );
+ #endif
+ ~XmlAttr();
+
+ char* name;
+ union {
+ TCHAR* value;
+ char* sendValue;
+ };
+};
+
+struct XmlNode
+{
+ XmlNode( const char* name );
+ XmlNode( const char* pszName, const TCHAR* ptszText );
+ #if defined( _UNICODE )
+ XmlNode( const char* pszName, const char* ptszText );
+ #endif
+ ~XmlNode();
+
+ XmlAttr* addAttr( XmlAttr* );
+ XmlAttr* addAttr( const char* pszName, const TCHAR* ptszValue );
+ #if defined( _UNICODE )
+ XmlAttr* addAttr( const char* pszName, const char* pszValue );
+ #endif
+ XmlAttr* addAttr( const char* pszName, int value );
+ XmlAttr* addAttrID( int id );
+
+ XmlNode* addChild( XmlNode* );
+ XmlNode* addChild( const char* pszName );
+ XmlNode* addChild( const char* pszName, const TCHAR* ptszValue );
+ #if defined( _UNICODE )
+ XmlNode* addChild( const char* pszName, const char* pszValue );
+ #endif
+
+ XmlNode* addQuery( const char* szNameSpace );
+
+ int getTextLen() const;
+ char* getText() const;
+
+ int depth; // depth of the current node ( 1=root )
+ char* name; // tag name of the current node
+ union {
+ TCHAR* text;
+ char* sendText;
+ };
+ int numAttr; // number of attributes
+ int maxNumAttr; // internal use ( num of slots currently allocated to attr )
+ XmlAttr **attr; // attribute list
+ int numChild; // number of direct child nodes
+ int maxNumChild; // internal use ( num of slots currently allocated to child )
+ XmlNode **child; // child node list
+ XmlNodeType state; // internal use by parser
+ char* props;
+ boolean dirtyHack; // to allow generator to issue the unclosed tag
+};
+
+struct XmlNodeIq : public XmlNode
+{
+ XmlNodeIq( const char* type, int id = NOID, const TCHAR* to = NULL );
+ XmlNodeIq( const char* type, const TCHAR* idStr, const TCHAR* to );
+ #if defined( _UNICODE )
+ XmlNodeIq( const char* type, int id, const char* to );
+ #endif
+};
+
+typedef void ( *JABBER_XML_CALLBACK )( XmlNode*, void* );
+
+struct XmlState
+{
+ XmlState() : root(NULL) {}
+
+ XmlNode root; // root is the document ( depth = 0 );
+ // callback for depth=n element on opening/closing
+ JABBER_XML_CALLBACK callback1_open;
+ JABBER_XML_CALLBACK callback1_close;
+ JABBER_XML_CALLBACK callback2_open;
+ JABBER_XML_CALLBACK callback2_close;
+ void *userdata1_open;
+ void *userdata1_close;
+ void *userdata2_open;
+ void *userdata2_close;
+};
+
+void JabberXmlInitState( XmlState *xmlState );
+void JabberXmlDestroyState( XmlState *xmlState );
+BOOL JabberXmlSetCallback( XmlState *xmlState, int depth, XmlElemType type, void ( *callback )(), void *userdata );
+int JabberXmlParse( XmlState *xmlState, char* buffer );
+TCHAR* JabberXmlGetAttrValue( XmlNode *node, char* key );
+XmlNode *JabberXmlGetChild( XmlNode *node, char* tag );
+XmlNode *JabberXmlGetNthChild( XmlNode *node, char* tag, int nth );
+XmlNode *JabberXmlGetChildWithGivenAttrValue( XmlNode *node, char* tag, char* attrKey, TCHAR* attrValue );
+void JabberXmlDumpAll( XmlState *xmlState );
+void JabberXmlDumpNode( XmlNode *node );
+XmlNode *JabberXmlCopyNode( XmlNode *node );
+BOOL JabberXmlSetCallback( XmlState *xmlState, int depth, XmlElemType type, JABBER_XML_CALLBACK callback, void *userdata );
+
+XmlNode *JabberXmlCreateNode( char* name );
+void JabberXmlAddAttr( XmlNode *n, char* name, char* value );
+XmlNode *JabberXmlAddChild( XmlNode *n, char* name );
+
+inline XmlNode& operator+( XmlNode& n1, XmlNode& n2 )
+{ n1.addChild( &n2 );
+ return n1;
+}
+
+inline XmlNode& operator+( XmlNode& n, XmlAttr& a )
+{ n.addAttr( &a );
+ return n;
+}
+
+#endif
diff --git a/miranda-wine/protocols/JabberG/jabber_xmlns.cpp b/miranda-wine/protocols/JabberG/jabber_xmlns.cpp
new file mode 100644
index 0000000..2ddcd25
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_xmlns.cpp
@@ -0,0 +1,107 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_xmlns.cpp,v $
+Revision : $Revision: 3651 $
+Last change on : $Date: 2006-08-30 16:54:52 +0400 (Срд, 30 Ðвг 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberXmlnsBrowse
+
+void JabberXmlnsBrowse( XmlNode *iqNode, void *userdata )
+{
+ XmlNode *queryNode;
+ TCHAR *xmlns, *iqFrom, *iqType;
+
+ if ( iqNode == NULL ) return;
+ if (( iqFrom=JabberXmlGetAttrValue( iqNode, "from" )) == NULL ) return;
+ if (( iqType=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+ if (( queryNode=JabberXmlGetChild( iqNode, "query" )) == NULL ) return;
+ if (( xmlns=JabberXmlGetAttrValue( queryNode, "xmlns" )) == NULL ) return;
+
+ if ( !_tcscmp( iqType, _T("get"))) {
+ XmlNodeIq iq( "result", JabberXmlGetAttrValue( iqNode, "id" ), iqFrom );
+ XmlNode* user = iq.addChild( "user" ); user->addAttr( "jid", jabberJID ); user->addAttr( "type", "client" ); user->addAttr( "xmlns", xmlns );
+ user->addChild( "ns", "http://jabber.org/protocol/disco#info" );
+ user->addChild( "ns", "http://jabber.org/protocol/muc" );
+ user->addChild( "ns", "jabber:iq:agents" );
+ user->addChild( "ns", "jabber:iq:browse" );
+ user->addChild( "ns", "jabber:iq:oob" );
+ user->addChild( "ns", "jabber:iq:version" );
+ user->addChild( "ns", "jabber:x:data" );
+ user->addChild( "ns", "jabber:x:event" );
+ user->addChild( "ns", "vcard-temp" );
+ JabberSend( jabberThreadInfo->s, iq );
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberXmlnsDisco
+
+static void sttAddFeature( XmlNode* n, char* text )
+{
+ XmlNode* f = n->addChild( "feature" ); f->addAttr( "var", text );
+}
+
+void JabberXmlnsDisco( XmlNode *iqNode, void *userdata )
+{
+ XmlNode *queryNode;
+ TCHAR *xmlns, *p, *discoType;
+ TCHAR *iqFrom, *iqType;
+
+ if ( iqNode == NULL ) return;
+ if (( iqFrom = JabberXmlGetAttrValue( iqNode, "from" )) == NULL ) return;
+ if (( iqType = JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+ if (( queryNode = JabberXmlGetChild( iqNode, "query" )) == NULL ) return;
+ if (( xmlns = JabberXmlGetAttrValue( queryNode, "xmlns" )) == NULL ) return;
+
+ p = _tcsrchr( xmlns, '/' );
+ discoType = _tcsrchr( xmlns, '#' );
+
+ if ( p==NULL || discoType==NULL || discoType < p )
+ return;
+
+ if ( !_tcscmp( iqType, _T("get"))) {
+ XmlNodeIq iq( "result", JabberXmlGetAttrValue( iqNode, "id" ), iqFrom );
+
+ if ( !_tcscmp( discoType, _T("#info"))) {
+ XmlNode* query = iq.addChild( "query" ); query->addAttr( "xmlns", xmlns );
+ XmlNode* ident = query->addChild( "identity" ); ident->addAttr( "category", "user" );
+ ident->addAttr( "type", "client" ); ident->addAttr( "name", "Miranda" );
+ sttAddFeature( query, "http://jabber.org/protocol/disco#info" );
+ sttAddFeature( query, "http://jabber.org/protocol/muc" );
+ sttAddFeature( query, "http://jabber.org/protocol/si" );
+ sttAddFeature( query, "http://jabber.org/protocol/si/profile/file-transfer" );
+ sttAddFeature( query, "http://jabber.org/protocol/bytestreams" );
+ sttAddFeature( query, "http://jabber.org/protocol/chatstates" );
+ sttAddFeature( query, "jabber:iq:agents" );
+ sttAddFeature( query, "jabber:iq:browse" );
+ sttAddFeature( query, "jabber:iq:oob" );
+ sttAddFeature( query, "jabber:iq:version" );
+ sttAddFeature( query, "jabber:x:data" );
+ sttAddFeature( query, "jabber:x:event" );
+ sttAddFeature( query, "vcard-temp" );
+ }
+ JabberSend( jabberThreadInfo->s, iq );
+} }
diff --git a/miranda-wine/protocols/JabberG/jabber_xmlns.h b/miranda-wine/protocols/JabberG/jabber_xmlns.h
new file mode 100644
index 0000000..e0bfd49
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/jabber_xmlns.h
@@ -0,0 +1,34 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_xmlns.h,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#ifndef _JABBER_XMLNS_H_
+#define _JABBER_XMLNS_H_
+
+void JabberXmlnsBrowse( XmlNode *iqNode, void *userdata );
+void JabberXmlnsDisco( XmlNode *iqNode, void *userdata );
+
+#endif
diff --git a/miranda-wine/protocols/JabberG/msvc6.rc b/miranda-wine/protocols/JabberG/msvc6.rc
new file mode 100644
index 0000000..da0ebe9
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/msvc6.rc
@@ -0,0 +1,2 @@
+#include "jabber.rc"
+#include "version.rc"
diff --git a/miranda-wine/protocols/JabberG/resource.h b/miranda-wine/protocols/JabberG/resource.h
new file mode 100644
index 0000000..42469ef
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/resource.h
@@ -0,0 +1,232 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by jabber.rc
+//
+#define IDCANCEL2 3
+#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 IDD_PASSWORD 111
+#define IDI_TLEN 121
+#define IDI_ADDCONTACT 122
+#define IDI_DELETE 123
+#define IDI_EDIT 124
+#define IDD_VCARD 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_OPT_JABBERMAIN 139
+#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_WRITE 162
+#define IDI_SAVE 166
+#define IDD_GROUPCHAT_INPUT 167
+#define IDD_ADVSEARCH_TLEN 169
+#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 IDD_OPT_SETAVATAR 185
+#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_EDIT_RESOURCE 1005
+#define IDC_INFO_JID 1007
+#define IDC_INFO_RESOURCE 1008
+#define IDC_LINK_PUBLIC_SERVER 1009
+#define IDC_NAME 1009
+#define IDC_PROGRESS_REG 1011
+#define IDOK2 1012
+#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_LOGO 1024
+#define IDC_AGENT_BROWSE 1029
+#define IDC_INSTRUCTION 1030
+#define IDC_DESCRIPTION 1031
+#define IDC_FRAME 1037
+#define IDC_FRAME_TEXT 1038
+#define IDC_SUBSCRIPTION 1039
+#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_AVATAR 1068
+#define IDC_ENABLE_AVATARS 1069
+#define IDC_SETAVATAR 1070
+#define IDC_DELETEAVATAR 1071
+#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_OPTIONSTAB 1095
+#define IDC_GENDER 1096
+#define IDC_JUD 1097
+#define IDC_JUD_LABEL 1098
+#define IDC_MSGLANG_LABEL 1099
+#define IDC_SOFTWARE 1101
+#define IDC_VERSION 1102
+#define IDC_SYSTEM 1103
+#define IDC_PRIORITY_SPIN 1104
+#define IDC_PRIORITY 1105
+#define IDC_PRIORITY_LABEL 1106
+#define IDC_NEWPASSWD 1107
+#define IDC_PASS_SERVER 1112
+#define IDC_PROXY_ADDR 1112
+#define IDC_PASS_PORT 1113
+#define IDC_EXT_ADDRESS 1114
+#define IDC_DIRECT_ADDR 1114
+#define IDC_SHOW_TRANSPORT 1115
+#define IDC_AUTO_ADD 1116
+#define IDC_PASS_SERVER_LABEL 1117
+#define IDC_EXT_ADDRESS_LABEL 1118
+#define IDC_PASS_PORT_LABEL 1119
+#define IDC_USE_PASS 1120
+#define IDC_PROXY 1120
+#define IDC_USE_EXT_ADDRESS 1121
+#define IDC_DIRECT_MANUAL 1121
+#define IDC_REG_STATUS 1122
+#define IDC_MSG_ACK 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_HSPLIT 1134
+#define IDC_LOG 1136
+#define IDC_VSPLIT 1137
+#define IDC_SET 1140
+#define IDC_TABS 1141
+#define IDC_TOPIC 1141
+#define IDC_FONT 1143
+#define IDC_ENTER 1144
+#define IDC_CTRLENTER 1145
+#define IDC_FONTSHOW 1146
+#define IDC_FLASH 1148
+#define IDC_AGEFROM 1152
+#define IDC_AGETO 1153
+#define IDC_LOOKFOR 1154
+#define IDC_SCHOOL 1155
+#define IDC_TIME 1156
+#define IDC_DATE 1157
+#define IDC_MANUAL_REGISTER 1167
+#define IDC_REASON 1171
+#define IDC_USER 1172
+#define IDC_INVITE 1173
+#define IDC_ACCEPT 1174
+#define IDC_FROM 1175
+#define IDC_AUTOJOIN 1176
+#define IDC_DISABLE_MAINMENU 1178
+#define IDC_USE_TLS 1179
+#define IDC_AUTO_ACCEPT_MUC 1180
+#define IDC_DISABLE_SASL 1182
+#define IDC_WHITERECT 1221
+#define IDC_UPDATING 1231
+#define IDC_EMAILS 1306
+#define IDC_PHONES 1308
+#define IDC_UPDATE 1313
+#define IDC_STATUS 1414
+#define IDC_PLAN 1415
+#define IDC_PERSONALGROUP 1434
+#define IDC_EXTRAGROUP 1436
+#define IDM_MESSAGE 10002
+#define IDM_CLEAR 10003
+#define IDM_VOICE 10005
+#define IDM_BAN 10006
+#define IDM_ADMIN 10007
+#define IDM_OWNER 10008
+#define IDM_CONFIG 10009
+#define IDM_KICK 10011
+#define IDM_NICK 10012
+#define IDM_MODERATOR 10013
+#define IDM_DESTROY 10014
+#define IDM_MEMBER 10015
+#define IDM_INVITE 10016
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 185
+#define _APS_NEXT_COMMAND_VALUE 40017
+#define _APS_NEXT_CONTROL_VALUE 1183
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/miranda-wine/protocols/JabberG/sdk/m_smileyadd.h b/miranda-wine/protocols/JabberG/sdk/m_smileyadd.h
new file mode 100644
index 0000000..83b2dbb
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/sdk/m_smileyadd.h
@@ -0,0 +1,78 @@
+/*
+Miranda SmileyAdd Plugin
+Plugin support header file
+Copyright ( C ) 2003 Rein-Peter de Boer ( peacow )
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or ( at your option ) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+
+//replace smiley tags in a rich edit control...
+//wParam = ( WPARAM ) 0; not used
+//lParam = ( LPARAM )( SMADD_RICHEDIT* ) &smre; //pointer to SmAddRicheditStructure
+//return: TRUE if replacement succeeded, FALSE if not ( disable by user? ).
+typedef struct
+{
+ int cbSize; //size of the structure
+ HWND hwndRichEditControl; //handle to the rich edit control
+ CHARRANGE* rangeToReplace; //same meaning as for normal Richedit use ( NULL = replaceall )
+ char* Protocolname; //protocol to use... if you have defined a protocol, u can
+ //use your own protocol name. Smiley add wil automatically
+ //select the smileypack that is defined for your protocol.
+ //Or, use "Standard" for standard smiley set. Or "ICQ", "MSN"
+ //if you prefer those icons.
+ //If not found or NULL: "Standard" will be used
+ } SMADD_RICHEDIT;
+
+//new version from smileyadd 1.2
+typedef struct
+{
+ int cbSize; //size of the structure
+ HWND hwndRichEditControl; //handle to the rich edit control
+ CHARRANGE* rangeToReplace; //same meaning as for normal Richedit use ( NULL = replaceall )
+ char* Protocolname; //protocol to use... if you have defined a protocol, u can
+ //use your own protocol name. Smiley add wil automatically
+ //select the smileypack that is defined for your protocol.
+ //Or, use "Standard" for standard smiley set. Or "ICQ", "MSN"
+ //if you prefer those icons.
+ //If not found or NULL: "Standard" will be used
+ BOOL useSounds; //NOT IMPLEMENTED YET, set to FALSE
+ BOOL disableRedraw; //If true then you have to restore scrollbars, selection
+ //etc and redraw yourself
+ //everything will be screwed up and not restored.
+
+} SMADD_RICHEDIT2;
+
+#define MS_SMILEYADD_REPLACESMILEYS "SmileyAdd/ReplaceSmileys"
+
+
+
+
+//replace smiley tags in a rich edit control...
+//wParam = ( WPARAM ) 0; not used
+//lParam = ( LPARAM )( SMADD_GETICON* ) &smgi; //pointer to SmAddRicheditStructure
+//return: TRUE if found, FALSE if not
+//NOTE: the
+typedef struct
+{
+ int cbSize; //same as in SMADD_RICHEDIT
+ char* Protocolname; // " "
+ char* SmileySequence; //character string containing the smiley
+ HICON SmileyIcon; //RETURN VALUE: this is filled with the icon handle...
+ //do not destroy!
+ int Smileylength; //length of the smiley that is found.
+} SMADD_GETICON;
+#define MS_SMILEYADD_GETSMILEYICON "SmileyAdd/GetSmileyIcon"
+
diff --git a/miranda-wine/protocols/JabberG/sha1.cpp b/miranda-wine/protocols/JabberG/sha1.cpp
new file mode 100644
index 0000000..107c4cd
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/sha1.cpp
@@ -0,0 +1,446 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/sha1.cpp,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+/*
+
+ Copyright ( C ) The Internet Society ( 2001 ). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+*/
+
+/*
+ * sha1.c
+ *
+ * Description:
+ * This file implements the Secure Hashing Algorithm 1 as
+ * defined in FIPS PUB 180-1 published April 17, 1995.
+ *
+ * The SHA-1, produces a 160-bit message digest for a given
+ * data stream. It should take about 2**n steps to find a
+ * message with the same digest as a given message and
+ * 2**( n/2 ) to find any two messages with the same digest,
+ * when n is the digest size in bits. Therefore, this
+ * algorithm can serve as a means of providing a
+ * "fingerprint" for a message.
+ *
+ * Portability Issues:
+ * SHA-1 is defined in terms of 32-bit "words". This code
+ * uses <stdint.h> ( included via "sha1.h" to define 32 and 8
+ * bit unsigned integer types. If your C compiler does not
+ * support 32 bit unsigned integers, this code is not
+ * appropriate.
+ *
+ * Caveats:
+ * SHA-1 is designed to work with messages less than 2^64 bits
+ * long. Although SHA-1 allows a message digest to be generated
+ * for messages of any number of bits less than 2^64, this
+ * implementation only works with messages with a length that is
+ * a multiple of the size of an 8-bit character.
+ *
+ */
+
+#include "sha1.h"
+
+/*
+ * Define the SHA1 circular left shift macro
+ */
+#define SHA1CircularShift( bits,word ) \
+ (( ( word ) << ( bits )) | (( word ) >> ( 32-( bits )) ))
+
+/* Local Function Prototyptes */
+void SHA1PadMessage( SHA1Context * );
+void SHA1ProcessMessageBlock( SHA1Context * );
+
+/*
+ * SHA1Reset
+ *
+ * Description:
+ * This function will initialize the SHA1Context in preparation
+ * for computing a new SHA1 message digest.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to reset.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA1Reset( SHA1Context *context )
+{
+ if ( !context )
+ {
+ return shaNull;
+ }
+
+ context->Length_Low = 0;
+ context->Length_High = 0;
+ context->Message_Block_Index = 0;
+
+ context->Intermediate_Hash[0] = 0x67452301;
+ context->Intermediate_Hash[1] = 0xEFCDAB89;
+ context->Intermediate_Hash[2] = 0x98BADCFE;
+ context->Intermediate_Hash[3] = 0x10325476;
+ context->Intermediate_Hash[4] = 0xC3D2E1F0;
+
+ context->Computed = 0;
+ context->Corrupted = 0;
+
+ return shaSuccess;
+}
+
+/*
+ * SHA1Result
+ *
+ * Description:
+ * This function will return the 160-bit message digest into the
+ * Message_Digest array provided by the caller.
+ * NOTE: The first octet of hash is stored in the 0th element,
+ * the last octet of hash in the 19th element.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to use to calculate the SHA-1 hash.
+ * Message_Digest: [out]
+ * Where the digest is returned.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA1Result( SHA1Context *context,
+ uint8_t Message_Digest[SHA1HashSize] )
+{
+ int i;
+
+ if ( !context || !Message_Digest )
+ {
+ return shaNull;
+ }
+
+ if ( context->Corrupted )
+ {
+ return context->Corrupted;
+ }
+
+ if ( !context->Computed )
+ {
+ SHA1PadMessage( context );
+ for( i=0; i<64; ++i )
+ {
+ /* message may be sensitive, clear it out */
+ context->Message_Block[i] = 0;
+ }
+ context->Length_Low = 0; /* and clear length */
+ context->Length_High = 0;
+ context->Computed = 1;
+
+ }
+
+ for( i = 0; i < SHA1HashSize; ++i )
+ {
+ Message_Digest[i] = ( uint8_t ) ( context->Intermediate_Hash[i>>2]
+ >> 8 * ( 3 - ( i & 0x03 )) );
+ }
+
+ return shaSuccess;
+}
+
+/*
+ * SHA1Input
+ *
+ * Description:
+ * This function accepts an array of octets as the next portion
+ * of the message.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The SHA context to update
+ * message_array: [in]
+ * An array of characters representing the next portion of
+ * the message.
+ * length: [in]
+ * The length of the message in message_array
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA1Input( SHA1Context *context,
+ const uint8_t *message_array,
+ unsigned length )
+{
+ if ( !length )
+ {
+ return shaSuccess;
+ }
+
+ if ( !context || !message_array )
+ {
+ return shaNull;
+ }
+
+ if ( context->Computed )
+ {
+ context->Corrupted = shaStateError;
+
+ return shaStateError;
+ }
+
+ if ( context->Corrupted )
+ {
+ return context->Corrupted;
+ }
+ while( length-- && !context->Corrupted )
+ {
+ context->Message_Block[context->Message_Block_Index++] =
+ ( *message_array & 0xFF );
+
+ context->Length_Low += 8;
+ if ( context->Length_Low == 0 )
+ {
+ context->Length_High++;
+ if ( context->Length_High == 0 )
+ {
+ /* Message is too long */
+ context->Corrupted = 1;
+ }
+ }
+
+ if ( context->Message_Block_Index == 64 )
+ {
+ SHA1ProcessMessageBlock( context );
+ }
+
+ message_array++;
+ }
+
+ return shaSuccess;
+}
+
+/*
+ * SHA1ProcessMessageBlock
+ *
+ * Description:
+ * This function will process the next 512 bits of the message
+ * stored in the Message_Block array.
+ *
+ * Parameters:
+ * None.
+ *
+ * Returns:
+ * Nothing.
+ *
+ * Comments:
+
+ * Many of the variable names in this code, especially the
+ * single character names, were used because those were the
+ * names used in the publication.
+ *
+ *
+ */
+void SHA1ProcessMessageBlock( SHA1Context *context )
+{
+ const uint32_t K[] = { /* Constants defined in SHA-1 */
+ 0x5A827999,
+ 0x6ED9EBA1,
+ 0x8F1BBCDC,
+ 0xCA62C1D6
+ };
+ int t; /* Loop counter */
+ uint32_t temp; /* Temporary word value */
+ uint32_t W[80]; /* Word sequence */
+ uint32_t A, B, C, D, E; /* Word buffers */
+
+ /*
+ * Initialize the first 16 words in the array W
+ */
+ for( t = 0; t < 16; t++ )
+ {
+ W[t] = context->Message_Block[t * 4] << 24;
+ W[t] |= context->Message_Block[t * 4 + 1] << 16;
+ W[t] |= context->Message_Block[t * 4 + 2] << 8;
+ W[t] |= context->Message_Block[t * 4 + 3];
+ }
+
+ for( t = 16; t < 80; t++ )
+ {
+ W[t] = SHA1CircularShift( 1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16] );
+ }
+
+ A = context->Intermediate_Hash[0];
+ B = context->Intermediate_Hash[1];
+ C = context->Intermediate_Hash[2];
+ D = context->Intermediate_Hash[3];
+ E = context->Intermediate_Hash[4];
+
+ for( t = 0; t < 20; t++ )
+ {
+ temp = SHA1CircularShift( 5,A ) +
+ (( B & C ) | (( ~B ) & D )) + E + W[t] + K[0];
+ E = D;
+ D = C;
+ C = SHA1CircularShift( 30,B );
+
+ B = A;
+ A = temp;
+ }
+
+ for( t = 20; t < 40; t++ )
+ {
+ temp = SHA1CircularShift( 5,A ) + ( B ^ C ^ D ) + E + W[t] + K[1];
+ E = D;
+ D = C;
+ C = SHA1CircularShift( 30,B );
+ B = A;
+ A = temp;
+ }
+
+ for( t = 40; t < 60; t++ )
+ {
+ temp = SHA1CircularShift( 5,A ) +
+ (( B & C ) | ( B & D ) | ( C & D )) + E + W[t] + K[2];
+ E = D;
+ D = C;
+ C = SHA1CircularShift( 30,B );
+ B = A;
+ A = temp;
+ }
+
+ for( t = 60; t < 80; t++ )
+ {
+ temp = SHA1CircularShift( 5,A ) + ( B ^ C ^ D ) + E + W[t] + K[3];
+ E = D;
+ D = C;
+ C = SHA1CircularShift( 30,B );
+ B = A;
+ A = temp;
+ }
+
+ context->Intermediate_Hash[0] += A;
+ context->Intermediate_Hash[1] += B;
+ context->Intermediate_Hash[2] += C;
+ context->Intermediate_Hash[3] += D;
+ context->Intermediate_Hash[4] += E;
+
+ context->Message_Block_Index = 0;
+}
+
+/*
+ * SHA1PadMessage
+ *
+
+ * Description:
+ * According to the standard, the message must be padded to an even
+ * 512 bits. The first padding bit must be a '1'. The last 64
+ * bits represent the length of the original message. All bits in
+ * between should be 0. This function will pad the message
+ * according to those rules by filling the Message_Block array
+ * accordingly. It will also call the ProcessMessageBlock function
+ * provided appropriately. When it returns, it can be assumed that
+ * the message digest has been computed.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to pad
+ * ProcessMessageBlock: [in]
+ * The appropriate SHA*ProcessMessageBlock function
+ * Returns:
+ * Nothing.
+ *
+ */
+
+void SHA1PadMessage( SHA1Context *context )
+{
+ /*
+ * Check to see if the current message block is too small to hold
+ * the initial padding bits and length. If so, we will pad the
+ * block, process it, and then continue padding into a second
+ * block.
+ */
+ if ( context->Message_Block_Index > 55 )
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0x80;
+ while( context->Message_Block_Index < 64 )
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0;
+ }
+
+ SHA1ProcessMessageBlock( context );
+
+ while( context->Message_Block_Index < 56 )
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0;
+ }
+ }
+ else
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0x80;
+ while( context->Message_Block_Index < 56 )
+ {
+
+ context->Message_Block[context->Message_Block_Index++] = 0;
+ }
+ }
+
+ /*
+ * Store the message length as the last 8 octets
+ */
+ context->Message_Block[56] = ( uint8_t ) ( context->Length_High >> 24 );
+ context->Message_Block[57] = ( uint8_t ) ( context->Length_High >> 16 );
+ context->Message_Block[58] = ( uint8_t ) ( context->Length_High >> 8 );
+ context->Message_Block[59] = ( uint8_t ) ( context->Length_High );
+ context->Message_Block[60] = ( uint8_t ) ( context->Length_Low >> 24 );
+ context->Message_Block[61] = ( uint8_t ) ( context->Length_Low >> 16 );
+ context->Message_Block[62] = ( uint8_t ) ( context->Length_Low >> 8 );
+ context->Message_Block[63] = ( uint8_t ) ( context->Length_Low );
+
+ SHA1ProcessMessageBlock( context );
+}
diff --git a/miranda-wine/protocols/JabberG/sha1.h b/miranda-wine/protocols/JabberG/sha1.h
new file mode 100644
index 0000000..b7a96ae
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/sha1.h
@@ -0,0 +1,133 @@
+/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 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 : $Source: /cvsroot/miranda/miranda/protocols/JabberG/sha1.h,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+/*
+
+ Copyright ( C ) The Internet Society ( 2001 ). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+*/
+
+/*
+ * sha1.h
+ *
+ * Description:
+ * This is the header file for code which implements the Secure
+ * Hashing Algorithm 1 as defined in FIPS PUB 180-1 published
+ * April 17, 1995.
+ *
+ * Many of the variable names in this code, especially the
+ * single character names, were used because those were the names
+ * used in the publication.
+ *
+ * Please read the file sha1.c for more information.
+ *
+ */
+
+#ifndef _SHA1_H_
+#define _SHA1_H_
+
+//#include <stdint.h>
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int8 uint8_t;
+typedef __int32 int_least16_t;
+/*
+ * If you do not have the ISO standard stdint.h header file, then you
+ * must typdef the following:
+ * name meaning
+ * uint32_t unsigned 32 bit integer
+ * uint8_t unsigned 8 bit integer ( i.e., unsigned char )
+ * int_least16_t integer of >= 16 bits
+ *
+ */
+
+#ifndef _SHA_enum_
+#define _SHA_enum_
+enum
+{
+ shaSuccess = 0,
+ shaNull, /* Null pointer parameter */
+ shaInputTooLong, /* input data too long */
+ shaStateError /* called Input after Result */
+};
+#endif
+#define SHA1HashSize 20
+
+/*
+ * This structure will hold context information for the SHA-1
+ * hashing operation
+ */
+typedef struct SHA1Context
+{
+ uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */
+
+ uint32_t Length_Low; /* Message length in bits */
+ uint32_t Length_High; /* Message length in bits */
+
+ /* Index into message block array */
+ int_least16_t Message_Block_Index;
+ uint8_t Message_Block[64]; /* 512-bit message blocks */
+
+ int Computed; /* Is the digest computed? */
+ int Corrupted; /* Is the message digest corrupted? */
+} SHA1Context;
+
+/*
+ * Function Prototypes
+ */
+
+int SHA1Reset( SHA1Context * );
+int SHA1Input( SHA1Context *,
+ const uint8_t *,
+ unsigned int );
+int SHA1Result( SHA1Context *,
+ uint8_t Message_Digest[SHA1HashSize] );
+
+#endif
diff --git a/miranda-wine/protocols/JabberG/version.h b/miranda-wine/protocols/JabberG/version.h
new file mode 100644
index 0000000..def2e71
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/version.h
@@ -0,0 +1,3 @@
+#define __FILEVERSION_STRING 0,6,0,1
+#define __VERSION_STRING "0.6.0.1"
+#define __VERSION_DWORD 0x00060001
diff --git a/miranda-wine/protocols/JabberG/version.rc b/miranda-wine/protocols/JabberG/version.rc
new file mode 100644
index 0000000..6ca3961
--- /dev/null
+++ b/miranda-wine/protocols/JabberG/version.rc
@@ -0,0 +1,52 @@
+#include "version.h"
+#include "winres.h"
+
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page( 1252)
+#endif //_WIN32
+
+#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 IM\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 IM\0"
+ VALUE "ProductVersion", __VERSION_STRING
+ VALUE "SpecialBuild", "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // !_MAC
diff --git a/miranda-wine/protocols/MSN/Icos/avatar.ico b/miranda-wine/protocols/MSN/Icos/avatar.ico
new file mode 100644
index 0000000..ec321e6
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/avatar.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/Icos/inbox.ico b/miranda-wine/protocols/MSN/Icos/inbox.ico
new file mode 100644
index 0000000..55097a1
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/inbox.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/Icos/invite.ico b/miranda-wine/protocols/MSN/Icos/invite.ico
new file mode 100644
index 0000000..2efc4dc
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/invite.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/Icos/list_al.ico b/miranda-wine/protocols/MSN/Icos/list_al.ico
new file mode 100644
index 0000000..d71446d
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/list_al.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/Icos/list_bl.ico b/miranda-wine/protocols/MSN/Icos/list_bl.ico
new file mode 100644
index 0000000..c3fd47d
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/list_bl.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/Icos/list_fl.ico b/miranda-wine/protocols/MSN/Icos/list_fl.ico
new file mode 100644
index 0000000..d85c54b
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/list_fl.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/Icos/list_rl.ico b/miranda-wine/protocols/MSN/Icos/list_rl.ico
new file mode 100644
index 0000000..b921290
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/list_rl.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/Icos/msn.ico b/miranda-wine/protocols/MSN/Icos/msn.ico
new file mode 100644
index 0000000..966acba
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/msn.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/Icos/msnblock.ico b/miranda-wine/protocols/MSN/Icos/msnblock.ico
new file mode 100644
index 0000000..db4af0c
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/msnblock.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/Icos/netmeeting.ico b/miranda-wine/protocols/MSN/Icos/netmeeting.ico
new file mode 100644
index 0000000..169f799
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/netmeeting.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/Icos/nudge.ico b/miranda-wine/protocols/MSN/Icos/nudge.ico
new file mode 100644
index 0000000..73613d2
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/nudge.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/Icos/profile.ico b/miranda-wine/protocols/MSN/Icos/profile.ico
new file mode 100644
index 0000000..a2c16ae
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/profile.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/Icos/services.ico b/miranda-wine/protocols/MSN/Icos/services.ico
new file mode 100644
index 0000000..5b0db43
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/services.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/SDK/m_chat.h b/miranda-wine/protocols/MSN/SDK/m_chat.h
new file mode 100644
index 0000000..28f8e68
--- /dev/null
+++ b/miranda-wine/protocols/MSN/SDK/m_chat.h
@@ -0,0 +1,424 @@
+/*
+Chat module plugin for Miranda IM
+
+Copyright (C) 2003 Jörgen Persson
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+
+#if 0
+
+/*
+ This plugin provides event driven chat rooms for protocols that wish to use it.
+ It is built for IRC, which I also develop and is naturally biased towards IRC,
+ but it should work very well with other protocols too. I will try to explain as
+ careful as possible in this document how to use chat.dll
+
+ -- General guidelines --
+
+ There is one rule a protocol MUST follow to use this:
+
+ 1. Do not touch contacts that has a byte "ChatRoom" set to ANYTHING other than 0! (Could be 1, 2, 3, ...)
+ This is because chat.dll adds contacts to the clist using the protocol name
+ supplied by the protocol. But this will naturally not work well if the
+ protocol also tampers with the contacts. The value of the BYTE indicates which type of
+ window/contact it is (see the GCW_* flags below). There is two exceptions to this rule:
+
+ * You should continue to handle the right click menu items of these
+ contacts as usual, by hooking the menu prebuild hook etc. Chat.dll can not
+ handle this in an efficient manner!
+
+ * You should also handle when the user deletes the contact/room from the
+ contact list, as the protocol will then most likely have to send some message
+ to the server that the user has left the room.
+
+ 2. The chat.dll plugin keeps its own copies of strings passed.
+
+*/
+
+
+// Example of implementing point 1:
+
+// This is a code snippet that is common in protocols:
+
+
+
+ hContact = (HANDLE) MSN_CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact)
+ {
+ szProto = (char *) MSN_CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ if (szProto != NULL && !lstrcmpiA(szProto, PROTONAME))
+ {
+// ... do something with the hContact here;
+ }
+ hContact = (HANDLE) MSN_CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ }
+
+
+
+// You should do this instead:
+
+
+
+ hContact = (HANDLE) MSN_CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact)
+ {
+ szProto = (char *) MSN_CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ if (szProto != NULL && !lstrcmpiA(szProto, PROTONAME))
+ {
+ if(DBGetContactSettingByte(hContact, PROTONAME, "ChatRoom", 0) == 0)
+ {
+// ... do something with the hContact here;
+ }
+ }
+ hContact = (HANDLE) MSN_CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ }
+
+
+// There is not more to it than that. To recapitulate: do not touch contacts where the
+// BYTE "ChatRoom" is set to 1, apart from the two exceptions mentioned!
+
+// ... now onto how to use this thing!
+
+
+#endif
+
+
+
+//------------------------- SERVICES ------------------------
+/*
+ -- Register with the chat module --
+
+ The first thing that a protocol need to do is register with chat.dll. This is best done
+ after ALL modules has loaded naturally. The registration is needed to make sure that
+ the protocol obey rule 1 mentioned above, but equally important to set protocol specific
+ settings.
+
+ wParam= NULL
+ lParam= (LPARAM)(GCREGISTER *)gcr
+ returns 0 on success or nonzero on failure
+*/
+
+#define GC_BOLD 0x0001 //enable the 'bold' button
+#define GC_ITALICS 0x0002 //enable the 'italics' button
+#define GC_UNDERLINE 0x0004 //enable the 'underline' button
+#define GC_COLOR 0x0008 //enable the 'foreground color' button
+#define GC_BKGCOLOR 0x0010 //enable the 'background color' button
+#define GC_ACKMSG 0x0020 //the protocol must ack. messages sent
+#define GC_TYPNOTIF 0x0040 //enable typing notifications
+#define GC_CHANMGR 0x0080 //enable the 'channel settings' button
+
+typedef struct {
+ int cbSize; //Set to sizeof();
+ DWORD dwFlags; //Use GC_* flags above
+ const char *pszModule; //This MUST be the protocol name as registered with Miranda IM
+ const char *pszModuleDispName; //This is the protocol name as it will be displayed to the user
+ int iMaxText; //Max message length the protocol supports. Will limit the typing area
+ int nColors; //Number of colors in the colorchooser menu for the color buttons. Max = 100
+ COLORREF* pColors; //pointer to the first static COLORREF array. ie: COLORREF crCols[nColors]; pColors = &crCols[0];
+ } GCREGISTER;
+#define MS_GC_REGISTER "GChat/Register"
+
+
+
+/*
+ -- Tell the chat module to create a new window --
+
+ Create a new chat room and set various settings related to it. This is not
+ the same as actually joining the chat room. The chat room will not be visible
+ to the user until the 'set up' phase is completed. See the MS_GC_EVENT for that.
+
+ wParam=0
+ lParam=(LPARAM)(GCWINDOW*)gcw
+
+ returns 0 on success or nonzero on failure
+*/
+#define GCW_CHATROOM 1
+#define GCW_SERVER 2
+#define GCW_PRIVMESS 3
+
+typedef struct {
+ int cbSize; //Set to sizeof();
+ int iType; //Use one of the GCW_* flags above to set the general type of usage for the window
+ const char *pszModule; //The name of the protocol owning the window (the same as pszModule when you register)
+ const char *pszName; //The name of the chat room as it will be displayed to the user
+ const char *pszID; //The unique identifier for the chat room
+ const char *pszStatusbarText; //Optional text to set in the statusbar, or NULL.
+ BOOL bDisableNickList; //Disable the nicklist
+ DWORD dwItemData; //Set user defined data for this chat room. Retrieve it by using the service below
+ } GCWINDOW;
+#define MS_GC_NEWCHAT "GChat/NewChat"
+
+
+
+/*
+ -- Show an event --
+
+ Events is what drives chat.dll! After having created the chat room with
+ MS_GC_NEWCHAT it is time to make it work for real. Start off by telling chat.dll
+ what statuses a user can have by sending GC_EVENT_ADDGROUP as many times as needed.
+ Then send join events
+ (GC_EVENT_JOIN) to populate the user list. You will need to send one event
+ per user that should be added. When you are done with filling the user list
+ it is a good time to end the 'set up' phase and make the window visible by
+ calling a GC_EVENT_VISIBILITY event. A nice tip is to make sure the bAddToLog
+ member of GCEVENT is set to FALSE during the initial filling of the user list.
+
+ The GCDEST structure and its members are always used, but what members of
+ GCEVENT to use is determined by what event is sent to chat.dll. bAddToLog and
+ time is valid (at least where it makes sense). See the description of each event
+ for more information of what members that are valid.
+
+ It is possible to send formatted text (bold, italics, underlined, foreground color
+ and background color) by using the following keywords in pszText:
+ %cRRRGGGBBB - set the foreground color
+ %C - set foreground color to default
+ %fRRRGGGBBB - set the background color
+ %F - set the background color to default
+ %b - enable bold
+ %B - disable bold
+ %u - enable underlined
+ %U - disable underlined
+ %i - enable italics
+ %I - disable italics
+ %r - reset all to default
+ %% - escape the formatting. Translates to %
+
+ wParam=0
+ lParam=(LPARAM)(GCEVENT *) gce
+
+ returns 0 on success or nonzero on failure
+*/
+
+
+// GC_EVENT_JOIN <pszNick> has joined
+// A user is joining the channel, set bIsMe to indicate who is the user
+// pszNick - Display name
+// pszUID - Unique identifier
+// pszStatus - Which group (status) to add the user to
+// bIsMe - Is this the user? Used to indicate that the user has joined the channel
+#define GC_EVENT_JOIN 0x0001
+
+// GC_EVENT_PART <pszNick> has left[: pszText]
+// A user left the chat room
+// pszUID - Unique identifier
+// pszText - part message
+#define GC_EVENT_PART 0x0002
+
+// GC_EVENT_QUIT <pszNick> disconnected[: pszText]
+// A user disconnected, use pszID = NULL (of GCDEST) to broadcast to all windows.
+// pszUID - Unique identifier
+// pszText - part message
+#define GC_EVENT_QUIT 0x0004
+
+// GC_EVENT_KICK <pszStatus> kicked <pszNick>
+// A user is kicking another user from the room
+// pszUID - Unique identifier of the one being kicked
+// pszStatus - Name of user doing the kick
+#define GC_EVENT_KICK 0x0008
+
+// GC_EVENT_NICK <pszNick> is now known as <pszText>
+// A user changed his name
+// NOTE, see GC_EVENT_CHID also
+// pszUID - Unique identifier of the one changing name
+// pszText - New name of the user
+#define GC_EVENT_NICK 0x0010
+
+// GC_EVENT_NOTICE Notice from <pszNick>: <pszText>
+// An IRC type notice, will be sent to the active window
+// pszUID - Unique identifier
+// pszText - Notice text
+#define GC_EVENT_NOTICE 0x0020
+
+// GC_EVENT_MESSAGE
+// A regular chat room message
+// is outgoing or incoming
+// pszUID - Unique identifier
+// pszText - Message text, use the formatting variables above.
+// NOTE make sure % is translated to %% to avoid accidental formatting
+#define GC_EVENT_MESSAGE 0x0040
+
+// GC_EVENT_TOPIC Topic is <pszText>
+// pszUID - Unique identifier
+// pszText - Topic text
+#define GC_EVENT_TOPIC 0x0080
+
+// GC_EVENT_INFORMATION
+// Informational style text
+// pszText - Information text
+#define GC_EVENT_INFORMATION 0x0100
+
+// GC_EVENT_ACTION
+// An IRC Style action event. Same as GC_EVENT_MESSAGE otherwise
+#define GC_EVENT_ACTION 0x0200
+
+// GC_EVENT_ADDSTATUS <pszText> enables '<pszStatus>' for <pszNick>
+// pszUID - Unique identifier
+// pszText - The one enabling the status for another user
+// pszStatus - The status given
+#define GC_EVENT_ADDSTATUS 0x0400
+
+// GC_EVENT_REMOVESTATUS <pszText> disables '<pszStatus>' for <pszNick>
+// pszUID - Unique identifier
+// pszText - The one disabling the status for another user
+// pszStatus - The status taken
+#define GC_EVENT_REMOVESTATUS 0x0800
+
+// GC_EVENT_CHID - not shown in the log
+// Change the unique identifier of a contact
+// pszUID - Unique identifier
+// pszText - The new unique identifier
+#define GC_EVENT_CHID 0x1000
+
+// GC_EVENT_CHID - not shown in the log
+// Change the name of a window
+// pszText - The new name
+#define GC_EVENT_CHWINNAME 0x1001
+
+// GC_EVENT_ADDGROUP - not shown in the log
+// Add a new status group to the user list
+// pszStatus - The new group name
+#define GC_EVENT_ADDGROUP 0x1002
+
+// GC_EVENT_SETITEMDATA GC_EVENT_SETITEMDATA - not shown in the log
+// Get or set the user defined data of a window
+// dwItemData - The itemdata to set or get
+#define GC_EVENT_SETITEMDATA 0x1003
+#define GC_EVENT_GETITEMDATA 0x1004
+
+// GC_EVENT_CONTROL - not shown in the log
+// Call WINDOW_INITDONE after the initial setup is done.
+// Also use it to control aspects of a window if needed .
+// No members of GCEVENT used, send one of the below flags in wParam instead
+#define WINDOW_INITDONE 1 //send when the window is joined and all users have ben added to the nicklist
+#define WINDOW_VISIBLE 2 //make the room visible (most likely you will never use this)
+#define WINDOW_HIDDEN 3 //make the room hidden (most likely you will never use this)
+#define WINDOW_MAXIMIZE 4 //make the room maximized (most likely you will never use this)
+#define WINDOW_MINIMIZE 5 //make the room minimized (most likely you will never use this)
+#define WINDOW_CLEARLOG 6 //clear the log of the room
+#define WINDOW_TERMINATE 7 //send to remove a window from chat.dll,
+#define WINDOW_OFFLINE 8 //send when the user leave the room
+#define WINDOW_ONLINE 9 //send when the user join the room
+
+#define GC_EVENT_CONTROL 0x1005
+
+// GC_EVENT_SETSBTEXT - not shown in the log
+// Set the text of the statusbar
+// pszText - text
+#define GC_EVENT_SETSBTEXT 0x1006
+
+// GC_EVENT_ACK - not shown in the log
+// Used to ack a outgoing message, when GC_ACKMSG is set
+// dwItemData - The itemdata
+#define GC_EVENT_ACK 0x1007
+
+// GC_EVENT_SENDMESSAGE - not shown in the log
+// Send a message from the window as if the user had typed it.
+// Used by IRC to broadcast /AME and /AMSG messages
+// pszText - The text
+#define GC_EVENT_SENDMESSAGE 0x1008
+
+typedef struct {
+ char *pszModule; //Name of the protocol (same as you registered with)
+ char *pszID; //Unique identifier of the room corresponding to the event, or NULL to broadcast to all rooms.
+ int iType; //Use GC_EVENT_* as defined above. Only one event per service call.
+} GCDEST;
+
+typedef struct {
+ int cbSize; // Set to sizeof();
+ GCDEST* pDest; // pointer to a GCDEST structure
+ const char *pszText; // Text, usage depends on type of event (see above), max 2048 characters
+ const char *pszNick; // Nick, usage depends on type of event (see above)
+ const char *pszUID; // Unique identifier, usage depends on type of event (see above)
+ const char *pszStatus; // Status, usage depends on type of event (see above)
+ const char *pszUserInfo; // Additional user information that is displayed in the log only for join, part, quit and nick
+ BOOL bIsMe; // Is this event related to the user?
+ BOOL bAddToLog; // Should this event be added to the message log
+ DWORD dwItemData; // User specified data
+ time_t time; // Time of the event
+ } GCEVENT;
+#define MS_GC_EVENT "GChat/NewEvent"
+
+
+
+
+//------------------------- HOOKS ------------------------
+/*
+ -- user interaction --
+ Hook this to receive notifications about user commands. The below flags will tell what sort of
+ user interaction is taking place and is set in iType of the GCDEST pointer member. The other
+ members of GCDEST will tell what protocol and chat room name it is.
+
+ wParam=0
+ lParam=(LPARAM)(GCEVENT *)pgch
+
+ Returning nonzero from your hook will stop other hooks from being called.
+*/
+#define GC_USER_MESSAGE 1 // user typed a message, with \n delimiting lines, valid members: pszText
+#define GC_USER_CHANMGR 2 // user clicked the chat room settings button
+#define GC_USER_LOGMENU 3 // user has chosen a message log menu item, valid members: dwData
+#define GC_USER_NICKLISTMENU 4 // user has chosen a user list menu item, valid members: dwData
+#define GC_USER_TYPNOTIFY 5 // user is typing
+#define GC_USER_PRIVMESS 6 // user wants to talk privately to user, valid members: pszText, pszUID
+#define GC_USER_TERMINATE 7 // a chat window is about to be closed, useful for freeing the Item data which is passed in dwData, valid members: dwData
+#define ME_GC_EVENT "GChat/OutgoingEvent"
+
+typedef struct {
+ GCDEST* pDest; // Same meaning as for MS_GC_EVENT
+ char * pszText; // Text
+ char * pszUID; // Unique identifier
+ DWORD dwData; // user data
+ } GCHOOK;
+
+
+/*
+ -- Build the pop up menus --
+ The user is activating a right click menu and the protocol should tell what
+ Items should be added to the menu. You should have a static array of struct gc_item's.
+ When the hook is fired the protocol should set nItems to the number of gc_item's
+ it want to add and then set Item to point to that array.
+
+ wParam=0
+ lParam=(LPARAM)(GCMENUITEM *)gcmi
+
+ Returning nonzero from your hook will stop other hooks from being called.
+
+*/
+
+#define MENU_NEWPOPUP 1 // add submenu
+#define MENU_POPUPITEM 2 // add item to current submenu
+#define MENU_POPUPSEPARATOR 3 // add separator to current submenu
+#define MENU_SEPARATOR 4 // add separator to menu
+#define MENU_ITEM 5 // add item
+struct gc_item {
+ char * pszDesc; // Textual description of the menu item to add
+ DWORD dwID; // must not be 0, must be unique. Will be returned via the above hook when the user click the item
+ int uType; // What kind of item is it?
+ BOOL bDisabled; // should the item be disabled
+ };
+
+#define MENU_ON_LOG 1 // pop up menu on the log
+#define MENU_ON_NICKLIST 2 // pop up menu on the user list
+typedef struct {
+ char * pszModule; // Set by chat.dll to the protocol name, do not change.
+ char * pszID; // The unique identifier of the window
+ char * pszUID; // The unique identifier of the user, if clicked in the user list
+ int Type; // MENU_ON_LOG or MENU_ON_USERLIST, what menu type is it?
+ int nItems; // set to number of items
+ struct gc_item* Item; // pointer to the first in the array of gc_item's
+ } GCMENUITEMS;
+#define ME_GC_BUILDMENU "GChat/BuildMenu"
+
diff --git a/miranda-wine/protocols/MSN/mmdecsjis.cpp b/miranda-wine/protocols/MSN/mmdecsjis.cpp
new file mode 100644
index 0000000..507c3b6
--- /dev/null
+++ b/miranda-wine/protocols/MSN/mmdecsjis.cpp
@@ -0,0 +1,489 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 <stdio.h>
+#include <string.h>
+
+#include "msn_global.h"
+
+int maybekanji(int c1, int c2);
+int rjis(char *t, char *s);
+unsigned short Jis2Sjis( unsigned short jis );
+void JIS2SJIS( char* text );
+//void JIStoSJIS( unsigned char knj1, unsigned char knj2 );
+void JIStoSJIS( unsigned char *knj1, unsigned char *knj2 );
+void jiskarasjis(char *trg, char *str);
+
+/*
+ * MIME decoding routines
+ *
+ * Written by S. Ichikawa,
+ * partially inspired by encdec.c of <jh@efd.lth.se>.
+ */
+#define BUFLEN 1024
+#define ESC (0x1b)
+
+
+#define ASCII 0x00
+#define EUC 0x01
+#define SJIS 0x02
+#define JIS 0x04
+#define JAPANESE 0xff
+
+
+static char mm64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" ;
+static char mmquote[] = "0123456789ABCDEF";
+static int mmcont = 0;
+
+void mmdec_base64( char *t, char *s)
+{
+ int d, count, j, val;
+ char buf[BUFLEN], *bp, nw[4], *p;
+
+ for (bp = buf; *s; s += 4)
+ {
+ val = 0;
+ if (s[2] == '=') count = 1;
+ else if (s[3] == '=') count = 2;
+ else count = 3;
+
+ for (j = 0; j <= count; j++)
+ {
+ if (!(p = strchr(mm64, s[j])))
+ return;
+
+ d = p - mm64;
+ d <<= (3-j)*6;
+ val += d;
+ }
+
+ for (j = 2; j >= 0; j--)
+ {
+ nw[j] = val & 255;
+ val >>= 8;
+ }
+ if (count--) *bp++ = nw[0];
+ if (count--) *bp++ = nw[1];
+ if (count) *bp++ = nw[2];
+ }
+ *bp = '\0';
+ strcpy(t, buf);
+}
+
+void mmdec_quote( char *t, char *s )
+{
+ char buf[BUFLEN], cval, *bp, *p;
+
+ for ( bp = buf; *s; )
+ {
+ if (*s == '=')
+ {
+ cval = 0;
+ if (s[1] && (p = strchr(mmquote, s[1])))
+ cval += (p - mmquote);
+ else
+ { *bp++ = *s++;
+ continue;
+ }
+
+ if (s[2] && (p = strchr(mmquote, s[2])))
+ {
+ cval <<= 4;
+ cval += (p - mmquote);
+ *bp++ = cval;
+ s += 3;
+ }
+ else *bp++ = *s++;
+ }
+ else if (*s == '_')
+ {
+ *bp++ = 0x20;
+ s++;
+ }
+ else *bp++ = *s++;
+ }
+
+ *bp = '\0';
+ strcpy( t, buf );
+}
+
+void mmdecode( char *trg, char *str )
+{
+ char buf[BUFLEN], mmbuf[BUFLEN];
+ char *s, *t, *u;
+ int base64, quote;
+ int jis = 0;
+ char *c;
+
+ buf[0] = '\0';
+
+ for (s = str, u = buf; *s; )
+ {
+ // if (!strnicmp(s, "=?ISO-2022-JP?B?", 16) || !strnicmp(s, "=?iso-2022-jp?B?", 16)) {
+ // if (!strncasecmp(s, "=?ISO-2022-JP?B?", 16)) {
+ if ( strstr(s, "=?") && strstr(s, "?B?" ))
+ base64 = 1;
+ else
+ base64 = 0;
+
+ // if (!strncasecmp(s, "=?ISO-2022-JP?Q?", 16)) {
+ // if (!strnicmp(s, "=?ISO-2022-JP?Q?", 16) || !strnicmp(s, "=?iso-2022-jp?Q?", 16)){
+ if ( strstr( s, "=?" ) && strstr( s, "?Q?" ))
+ quote = 1;
+ else
+ quote = 0;
+
+ if ( strstr(s, "ISO-2022-JP") || strstr( s, "iso-2022-jp" ))
+ jis = 1;
+ else
+ jis = 0;
+
+ if ( base64 || quote )
+ {
+ if ( mmcont )
+ {
+ for ( t = s - 1; t >= str && (*t == ' ' || *t == '\t'); t--)
+ u--;
+ }
+ if(quote) c = strstr(s,"?Q?");
+ if(base64) c = strstr(s,"?B?");
+
+ for (s = c+3, t = mmbuf; *s; )
+ {
+ if (s[0] == '?' && s[1] == '=')
+ break;
+
+ *t++ = *s++;
+ }
+
+ if ( s[0] != '?' || s[1] != '=' )
+ goto end;
+
+ s += 2;
+ *t = '\0';
+
+ if (base64) mmdec_base64(mmbuf, mmbuf);
+ if (quote) mmdec_quote(mmbuf, mmbuf);
+ for ( t = mmbuf; *t; )
+ *u++ = *t++;
+
+ mmcont = 1;
+ /* if (*s == ' ' || *s == '\t') *u++ = *s; */
+ /* for ( ; *s == ' ' || *s == '\t'; s++) ; */
+ }
+ else
+ {
+ if (*s != ' ' && *s != '\t') mmcont = 0;
+ *u++ = *s++;
+ } }
+
+ *u = '\0';
+end:
+ if ( jis )
+ jiskarasjis( buf, buf ); // japanese jis code to shift-jis code
+ strcpy( trg, buf );
+}
+
+void jiskarasjis( char *trg, char *str )
+{
+ char buf[BUFLEN];
+
+ strcpy(buf,str);
+ rjis(buf, buf);
+
+ JIS2SJIS(buf);
+
+ strcpy(trg, buf);
+}
+
+/*
+ * Insert ESC where it seems lost.
+ * (The author of this function "rjis" is S. Ichikawa.)
+ */
+
+int rjis( char *t, char *s )
+{
+ char *p, buf[BUFLEN];
+ int kanji = 0;
+
+ if (strchr(s, ESC) || !strchr(s, '$'))
+ {
+ if (s != t) strcpy(t, s);
+ return 1;
+ }
+
+ for (p = buf; *s; )
+ {
+ if (!kanji && s[0] == '$' && (s[1] == '@' || s[1] == 'B'))
+ {
+ if (maybekanji((int)s[2], (int)s[3]))
+ {
+ kanji = 1;
+ *p++ = ESC;
+ *p++ = *s++;
+ *p++ = *s++;
+ *p++ = *s++;
+ *p++ = *s++;
+ continue;
+ }
+ *p++ = *s++;
+ continue;
+ }
+ if (kanji && s[0] == '(' && (s[1] == 'J' || s[1] == 'B'))
+ {
+ kanji = 0;
+ *p++ = ESC;
+ *p++ = *s++;
+ *p++ = *s++;
+ continue;
+ }
+ *p++ = *s++;
+ }
+ *p = *s; /* terminate string */
+
+ strcpy(t, buf);
+ return 0;
+}
+
+/*
+ * The following function "maybekanji" is derived from
+ * RJIS-1.0 by Mr. Hironobu Takahashi.
+ * Maybekanji() is included here under the courtesy of the author.
+ * The original comment of rjis.c is also included here.
+ */
+
+/*
+ * RJIS ( Recover JIS code from broken file )
+ * Copyright (C) 1992 1994
+ * Hironobu Takahashi (takahasi@tiny.or.jp)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either versions 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with SKK, see the file COPYING. If not, write to the Free
+ * Software Foundation Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+int maybekanji( int c1, int c2 )
+{
+ if ((c2 < 33) || (c2 > 126)) return 0;
+ if ((c1 < 33) || ((40 < c1) && (c1 < 48)) || (116 < c1)) return 0;
+ c2 -= 32;
+ switch(c1-32) {
+ case 2:
+ if ((14 < c2) && ( c2 < 26)) return 0;
+ if ((33 < c2) && ( c2 < 42)) return 0;
+ if ((48 < c2) && ( c2 < 60)) return 0;
+ if ((74 < c2) && ( c2 < 82)) return 0;
+ if ((89 < c2) && ( c2 < 94)) return 0;
+ break;
+ case 3:
+ if (c2 < 16) return 0;
+ if ((25 < c2) && ( c2 < 33)) return 0;
+ if ((58 < c2) && ( c2 < 65)) return 0;
+ if (90 < c2) return 0;
+ break;
+ case 4:
+ if (83 < c2) return 0;
+ break;
+ case 5:
+ if (86 < c2) return 0;
+ break;
+ case 6:
+ if ((24 < c2) && ( c2 < 33)) return 0;
+ if (56 < c2) return 0;
+ break;
+ case 7:
+ if ((33 < c2) && ( c2 < 49)) return 0;
+ if (81 < c2) return 0;
+ break;
+ case 8:
+ if (32 < c2) return 0;
+ break;
+ case 47:
+ if (51 < c2) return 0;
+ break;
+ case 84:
+ if (6 < c2) return 0;
+ break;
+ }
+ return 1;
+}
+
+unsigned int jis2sjis(unsigned int jis)
+{
+ unsigned int hib, lob;
+
+ hib = (jis >> 8) & 0xff;
+ lob = jis & 0xff;
+ lob += (hib & 1) ? 0x1f : 0x7d;
+ if (lob >= 0x7f) lob++;
+ hib = ((hib - 0x21) >> 1) + 0x81;
+ if (hib > 0x9f) hib += 0x40;
+
+ return (hib << 8) | lob;
+}
+
+static void rint2hexsz(char *str, int num, int *off)
+{
+ int k, n;
+
+ if ((k = num >> 4) != 0)
+ rint2hexsz(str, k, off);
+
+ n = num & 0xf;
+ *(str + *off) = n <= 9 ? n + '0' : n - 10 + 'A';
+ (*off)++;
+}
+
+void int2hexsz(char *str, int num)
+{
+ int i;
+
+ i = 0;
+ if (num < 0) {
+ num = -num;
+ *str = '-';
+ i++;
+ }
+ rint2hexsz(str, num, &i);
+ *(str + i) = '\0';
+}
+
+int hexsz2int(char *str)
+{
+ int val;
+ int sign;
+
+ while (*str == ' ' || *str == '\t') str++;
+ sign = 1;
+ if (*str == '+') str++;
+ else if (*str == '-') {
+ sign = -1;
+ str++;
+ }
+ val = 0;
+ while (*str >= '0' && *str <= '9' ||
+ *str >= 'A' && *str <= 'F' ||
+ *str >= 'a' && *str <= 'f') {
+ val <<= 4;
+ if (*str >= '0' && *str <= '9') val += *str - '0';
+ else if (*str >= 'A' && *str <= 'F') val += *str - 'A' + 10;
+ else val += *str - 'a' + 10;
+ str++;
+ }
+
+ return sign == 1 ? val : -val;
+}
+
+unsigned short Jis2Sjis( unsigned short jis )
+{
+ unsigned short ubyte, lbyte;
+
+ ubyte = jis >> 8;
+ lbyte = jis & 0x00ff;
+
+ lbyte += 0x1f;
+ if ( lbyte >= 0x7f ) lbyte++;
+ if ( lbyte <= 0x3f ) return 0;
+
+ if ( (ubyte & 0x0001) == 0 )
+ {
+ lbyte = jis & 0x00ff;
+ lbyte += 0x7e;
+ ubyte--;
+ if ( lbyte > 0xfd ) return 0;
+ }
+
+ ubyte -= 0x1f;
+ ubyte = ubyte >> 1;
+ ubyte += 0x80;
+ if ( ubyte >= 0xa0 ) ubyte += 0x40;
+
+ if ( ((ubyte >= 0x81) && (ubyte <= 0x9f)) || ((ubyte >= 0xe0) && (ubyte <= 0xef)) )
+ return (ubyte << 8) + lbyte;
+
+ return 0;
+}
+
+//---- JISʸ»ú¤òSJISʸ»ú¤ËÊÑ´¹¤¹¤ë´Ø¿ô
+//inline
+void JIStoSJIS(unsigned char *knj1, unsigned char *knj2 )
+{
+ if( *knj1 & 0x01 ){
+ *knj1 >>= 1;
+ if( *knj1 < 0x2F ) *knj1 += 0x71; else *knj1 -= 0x4F;
+ if( *knj2 > 0x5F ) *knj2 += 0x20; else *knj2 += 0x1F;
+ }else{
+ *knj1 >>= 1;
+ if( *knj1 < 0x2F ) *knj1 += 0x70; else *knj1 -= 0x50;
+ *knj2 += 0x7E;
+ }
+}
+
+
+
+void JIS2SJIS( char* text ) {
+ int mode = ASCII;
+
+ unsigned char *wr, *re;
+ for( wr=re=(unsigned char*)text; *re; re++ ){
+ if( (re[0]=='\x1b' && re[1]=='$' && re[2] == 'B' ) ||
+ (re[0]=='\x1b' && re[1]=='$' && re[2] == '@' ) ){
+ re+=2;
+ mode = JAPANESE;
+ continue;
+ }else if( (re[0]=='\x0f') ||
+ (re[0]=='\x1b' && re[1]=='(' && re[2] == 'B' ) ||
+ (re[0]=='\x1b' && re[1]=='(' && re[2] == 'J' ) ){
+ re+=2;
+ mode = ASCII;
+ continue;
+ }else if( (re[0]=='\x0e') ||
+ (re[0]=='\x1b' && re[1]=='(' && re[2] == 'I' ) ){
+ re+=2;
+ mode = ASCII; // hankaku IGNORE
+ continue;
+ }
+
+ if( mode == ASCII ){
+ *wr++ = *re;
+ continue;
+ }
+ *wr++ = *re;
+ if( !(*wr = *++re) ) break;
+// JIStoSJIS( *(wr-1), *wr );
+ JIStoSJIS( (wr-1), wr );
+ wr++;
+ }
+ *wr='\0';
+}
diff --git a/miranda-wine/protocols/MSN/msn.cpp b/miranda-wine/protocols/MSN/msn.cpp
new file mode 100644
index 0000000..1281add
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn.cpp
@@ -0,0 +1,407 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "msn_global.h"
+#include "version.h"
+
+#pragma comment( lib, "shlwapi.lib" )
+
+HINSTANCE hInst;
+PLUGINLINK *pluginLink;
+
+struct MM_INTERFACE memoryManagerInterface;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Initialization routines
+int MsnOnDetailsInit( WPARAM, LPARAM );
+
+int LoadMsnServices( void );
+void UnloadMsnServices( void );
+void MsgQueue_Init( void );
+void MsgQueue_Uninit( void );
+void Lists_Init( void );
+void Lists_Uninit( void );
+void P2pSessions_Uninit( void );
+void P2pSessions_Init( void );
+void Threads_Uninit( void );
+int MsnOptInit( WPARAM wParam, LPARAM lParam );
+void UninitSsl( void );
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Global variables
+
+int uniqueEventId = 0;
+int msnSearchID = -1;
+char* msnExternalIP = NULL;
+char* msnPreviousUUX = NULL;
+HANDLE msnMainThread;
+int msnOtherContactsBlocked = 0;
+HANDLE hHookOnUserInfoInit = NULL;
+HANDLE hGroupAddEvent = NULL;
+HANDLE hMSNNudge = NULL;
+bool msnHaveChatDll = false;
+
+MYOPTIONS MyOptions;
+
+MSN_StatusMessage msnModeMsgs[ MSN_NUM_MODES ] = {
+ { ID_STATUS_ONLINE, NULL },
+ { ID_STATUS_AWAY, NULL },
+ { ID_STATUS_NA, NULL },
+ { ID_STATUS_DND, NULL },
+ { ID_STATUS_OCCUPIED, NULL },
+ { ID_STATUS_ONTHEPHONE, NULL },
+ { ID_STATUS_OUTTOLUNCH, NULL } };
+
+char* msnProtocolName = NULL;
+char* msnProtChallenge = NULL;
+char* msnProductID = NULL;
+
+char* mailsoundname;
+char* ModuleName;
+
+PLUGININFO pluginInfo =
+{
+ sizeof(PLUGININFO),
+ #if defined( _UNICODE )
+ "MSN Protocol (Unicode)",
+ #else
+ "MSN Protocol",
+ #endif
+ __VERSION_DWORD,
+ "Adds support for communicating with users of the MSN Messenger network",
+ "George Hazan",
+ "george_hazan@hotmail.com",
+ "© 2001-5 Richard Hughes, George Hazan",
+ "http://miranda-im.org/download/details.php?action=viewfile&id=702",
+ 0, 0
+};
+
+bool volatile msnLoggedIn = false;
+ThreadData* volatile msnNsThread = NULL;
+
+int msnStatusMode,
+ msnDesiredStatus;
+HANDLE msnMenuItems[ MENU_ITEMS_COUNT ];
+HANDLE hNetlibUser = NULL;
+HANDLE hInitChat = NULL;
+HANDLE hEvInitChat = NULL;
+bool msnUseExtendedPopups;
+
+int MsnOnDetailsInit( WPARAM wParam, LPARAM lParam );
+
+int MSN_GCEventHook( WPARAM wParam, LPARAM lParam );
+int MSN_GCMenuHook( WPARAM wParam, LPARAM lParam );
+int MSN_ChatInit( WPARAM wParam, LPARAM lParam );
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Main DLL function
+
+extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
+{
+ hInst = hinstDLL;
+ return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// OnModulesLoaded - finalizes plugin's configuration on load
+
+int msn_httpGatewayInit(HANDLE hConn,NETLIBOPENCONNECTION *nloc,NETLIBHTTPREQUEST *nlhr);
+int msn_httpGatewayBegin(HANDLE hConn,NETLIBOPENCONNECTION *nloc);
+int msn_httpGatewayWrapSend(HANDLE hConn,PBYTE buf,int len,int flags,MIRANDASERVICE pfnNetlibSend);
+PBYTE msn_httpGatewayUnwrapRecv(NETLIBHTTPREQUEST *nlhr,PBYTE buf,int len,int *outBufLen,void *(*NetlibRealloc)(void*,size_t));
+
+static COLORREF crCols[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+
+static HANDLE hChatEvent = NULL, hChatMenu = NULL;
+
+static int OnModulesLoaded( WPARAM wParam, LPARAM lParam )
+{
+ if ( !ServiceExists( MS_DB_CONTACT_GETSETTING_STR )) {
+ MessageBox( NULL, TranslateT( "This plugin requires db3x plugin version 0.5.1.0 or later" ), _T("MSN"), MB_OK );
+ return 1;
+ }
+
+ char szBuffer[ MAX_PATH ];
+
+ if ( MSN_GetStaticString( "MsnPassportHost", NULL, szBuffer, sizeof szBuffer ))
+ MSN_SetString( NULL, "MsnPassportHost", "https://loginnet.passport.com/login2.srf" );
+
+ WORD wPort = MSN_GetWord( NULL, "YourPort", 0xFFFF );
+ if ( wPort != 0xFFFF ) {
+ MSN_SetByte( "NLSpecifyIncomingPorts", 1 );
+
+ ltoa( wPort, szBuffer, 10 );
+ MSN_SetString( NULL, "NLIncomingPorts", szBuffer );
+
+ DBDeleteContactSetting( NULL, msnProtocolName, "YourPort" );
+ }
+
+ mir_snprintf( szBuffer, sizeof szBuffer, "%s plugin connections", msnProtocolName );
+
+ NETLIBUSER nlu = {0};
+ nlu.cbSize = sizeof( nlu );
+ nlu.flags = NUF_INCOMING | NUF_OUTGOING | NUF_HTTPCONNS;
+ nlu.szSettingsModule = msnProtocolName;
+ nlu.szDescriptiveName = MSN_Translate( szBuffer );
+
+ if ( MyOptions.UseGateway ) {
+ nlu.flags |= NUF_HTTPGATEWAY;
+ nlu.szHttpGatewayUserAgent = MSN_USER_AGENT;
+ nlu.pfnHttpGatewayInit = msn_httpGatewayInit;
+ nlu.pfnHttpGatewayWrapSend = msn_httpGatewayWrapSend;
+ nlu.pfnHttpGatewayUnwrapRecv = msn_httpGatewayUnwrapRecv;
+ }
+
+ hNetlibUser = ( HANDLE )MSN_CallService( MS_NETLIB_REGISTERUSER, 0, ( LPARAM )&nlu );
+
+ if ( MSN_GetByte( "UseIeProxy", 0 )) {
+ NETLIBUSERSETTINGS nls = { 0 };
+ nls.cbSize = sizeof( nls );
+ MSN_CallService(MS_NETLIB_GETUSERSETTINGS,WPARAM(hNetlibUser),LPARAM(&nls));
+
+ HKEY hSettings;
+ if ( RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", &hSettings ))
+ return 0;
+
+ char tValue[ 256 ];
+ DWORD tType = REG_SZ, tValueLen = sizeof( tValue );
+ int tResult = RegQueryValueExA( hSettings, "ProxyServer", NULL, &tType, ( BYTE* )tValue, &tValueLen );
+ RegCloseKey( hSettings );
+
+ if ( !tResult )
+ {
+ char* tDelim = strstr( tValue, "http=" );
+ if ( tDelim != 0 ) {
+ strdel( tValue, int( tDelim - tValue )+5 );
+
+ tDelim = strchr( tValue, ';' );
+ if ( tDelim != NULL )
+ *tDelim = '\0';
+ }
+
+ tDelim = strchr( tValue, ':' );
+ if ( tDelim != NULL ) {
+ *tDelim = 0;
+ nls.wProxyPort = atol( tDelim+1 );
+ }
+
+ rtrim( tValue );
+ nls.szProxyServer = tValue;
+ MyOptions.UseProxy = nls.useProxy = tValue[0] != 0;
+ nls.proxyType = PROXYTYPE_HTTP;
+ nls.szIncomingPorts = NEWSTR_ALLOCA(nls.szIncomingPorts);
+ nls.szOutgoingPorts = NEWSTR_ALLOCA(nls.szOutgoingPorts);
+ nls.szProxyAuthPassword = NEWSTR_ALLOCA(nls.szProxyAuthPassword);
+ nls.szProxyAuthUser = NEWSTR_ALLOCA(nls.szProxyAuthUser);
+ MSN_CallService(MS_NETLIB_SETUSERSETTINGS,WPARAM(hNetlibUser),LPARAM(&nls));
+ } }
+
+ if ( ServiceExists( MS_GC_REGISTER )) {
+ msnHaveChatDll = true;
+
+ GCREGISTER gcr = {0};
+ gcr.cbSize = sizeof( GCREGISTER );
+ gcr.dwFlags = GC_TYPNOTIF|GC_CHANMGR;
+ gcr.iMaxText = 0;
+ gcr.nColors = 16;
+ gcr.pColors = &crCols[0];
+ gcr.pszModuleDispName = msnProtocolName;
+ gcr.pszModule = msnProtocolName;
+ MSN_CallService( MS_GC_REGISTER, NULL, ( LPARAM )&gcr );
+
+ hChatEvent = HookEvent( ME_GC_EVENT, MSN_GCEventHook );
+ hChatMenu = HookEvent( ME_GC_BUILDMENU, MSN_GCMenuHook );
+
+ char szEvent[ 200 ];
+ mir_snprintf( szEvent, sizeof szEvent, "%s\\ChatInit", msnProtocolName );
+ hInitChat = CreateHookableEvent( szEvent );
+ hEvInitChat = HookEvent( szEvent, MSN_ChatInit );
+ }
+
+ msnUseExtendedPopups = ServiceExists( MS_POPUP_ADDPOPUPEX ) != 0;
+ hHookOnUserInfoInit = HookEvent( ME_USERINFO_INITIALISE, MsnOnDetailsInit );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// OnPreShutdown - prepare a global Miranda shutdown
+
+extern HANDLE hKeepAliveThreadEvt;
+
+static int OnPreShutdown( WPARAM wParam, LPARAM lParam )
+{
+ if ( hKeepAliveThreadEvt != NULL )
+ SetEvent( hKeepAliveThreadEvt );
+
+ MSN_CloseThreads();
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Performs a primary set of actions upon plugin loading
+
+extern "C" int __declspec(dllexport) Load( PLUGINLINK* link )
+{
+ pluginLink = link;
+ DuplicateHandle( GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &msnMainThread, THREAD_SET_CONTEXT, FALSE, 0 );
+
+ // get the internal malloc/free()
+ memset(&memoryManagerInterface, 0, sizeof(memoryManagerInterface));
+ memoryManagerInterface.cbSize = sizeof(memoryManagerInterface);
+ CallService(MS_SYSTEM_GET_MMI, 0, (LPARAM) &memoryManagerInterface);
+
+ char path[MAX_PATH];
+ char* protocolname;
+ char* fend;
+
+ GetModuleFileNameA( hInst, path, sizeof( path ));
+
+ protocolname = strrchr(path,'\\');
+ protocolname++;
+ fend = strrchr(path,'.');
+ *fend = '\0';
+ CharUpperA( protocolname );
+ msnProtocolName = strdup( protocolname );
+
+ mir_snprintf( path, sizeof( path ), "%s:HotmailNotify", protocolname );
+ ModuleName = strdup( path );
+
+ mir_snprintf( path, sizeof( path ), "%s/Status", protocolname );
+ MSN_CallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )path );
+
+// Uninstalling purposes
+// if (ServiceExists("PluginSweeper/Add"))
+// MSN_CallService("PluginSweeper/Add",(WPARAM)MSN_Translate(ModuleName),(LPARAM)ModuleName);
+
+ HookEvent( ME_SYSTEM_MODULESLOADED, OnModulesLoaded );
+
+ srand(( unsigned int )time( NULL ));
+
+ LoadOptions();
+ HookEvent( ME_OPT_INITIALISE, MsnOptInit );
+ HookEvent( ME_SYSTEM_PRESHUTDOWN, OnPreShutdown );
+
+ char nudge[250];
+ sprintf(nudge,"%s/Nudge",protocolname);
+ hMSNNudge = CreateHookableEvent(nudge);
+
+ MSN_InitThreads();
+
+ PROTOCOLDESCRIPTOR pd;
+ memset( &pd, 0, sizeof( pd ));
+ pd.cbSize = sizeof( pd );
+ pd.szName = msnProtocolName;
+ pd.type = PROTOTYPE_PROTOCOL;
+ MSN_CallService( MS_PROTO_REGISTERMODULE, 0, ( LPARAM )&pd );
+
+ HANDLE hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL ) {
+ if ( !lstrcmpA( msnProtocolName, ( char* )MSN_CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact,0 )))
+ MSN_SetWord( hContact, "Status", ID_STATUS_OFFLINE );
+ hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDNEXT,( WPARAM )hContact, 0 );
+ }
+
+ char mailsoundtemp[ 64 ];
+ strcpy( mailsoundtemp, protocolname );
+ strcat( mailsoundtemp, ": " );
+ strcat( mailsoundtemp, MSN_Translate( "Hotmail" ));
+ mailsoundname = strdup( mailsoundtemp );
+ SkinAddNewSound( mailsoundtemp, mailsoundtemp, "hotmail.wav" );
+
+ msnStatusMode = msnDesiredStatus = ID_STATUS_OFFLINE;
+ msnLoggedIn = false;
+ LoadMsnServices();
+ Lists_Init();
+ MsgQueue_Init();
+ P2pSessions_Init();
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Unload a plugin
+
+extern char* rru;
+extern char* profileURL;
+
+extern "C" int __declspec( dllexport ) Unload( void )
+{
+ if ( msnLoggedIn )
+ msnNsThread->sendPacket( "OUT", NULL );
+
+ if ( hHookOnUserInfoInit )
+ UnhookEvent( hHookOnUserInfoInit );
+
+ if ( hChatEvent ) UnhookEvent( hChatEvent );
+ if ( hChatMenu ) UnhookEvent( hChatMenu );
+ if ( hEvInitChat ) UnhookEvent( hEvInitChat );
+
+ if ( hInitChat )
+ DestroyHookableEvent( hInitChat );
+
+ if ( hMSNNudge )
+ DestroyHookableEvent( hMSNNudge );
+
+ UninitSsl();
+ MSN_FreeGroups();
+ Threads_Uninit();
+ MsgQueue_Uninit();
+ Lists_Uninit();
+ P2pSessions_Uninit();
+ Netlib_CloseHandle( hNetlibUser );
+
+ UnloadMsnServices();
+
+ free( mailsoundname );
+ free( msnProtocolName );
+ free( ModuleName );
+
+ CloseHandle( msnMainThread );
+
+ for ( int i=0; i < MSN_NUM_MODES; i++ )
+ if ( msnModeMsgs[ i ].m_msg )
+ free( msnModeMsgs[ i ].m_msg );
+
+ if ( kv ) free( kv );
+ if ( sid ) free( sid );
+ if ( passport ) free( passport );
+ if ( MSPAuth ) free( MSPAuth );
+ if ( rru ) free( rru );
+ if ( profileURL ) free( profileURL );
+
+ if ( msnPreviousUUX ) free( msnPreviousUUX );
+ if ( msnExternalIP ) free( msnExternalIP );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MirandaPluginInfo - returns an information about a plugin
+
+extern "C" __declspec(dllexport) PLUGININFO* MirandaPluginInfo(DWORD mirandaVersion)
+{
+ if ( mirandaVersion < PLUGIN_MAKE_VERSION( 0, 6, 0, 0 )) {
+ MessageBox( NULL, _T("The MSN protocol plugin cannot be loaded. It requires Miranda IM 0.6.0 or later."), _T("MSN Protocol Plugin"), MB_OK|MB_ICONWARNING|MB_SETFOREGROUND|MB_TOPMOST );
+ return NULL;
+ }
+
+ return &pluginInfo;
+}
diff --git a/miranda-wine/protocols/MSN/msn.rc b/miranda-wine/protocols/MSN/msn.rc
new file mode 100644
index 0000000..06d391b
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn.rc
@@ -0,0 +1,348 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include <windows.h>
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Russian resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)
+#ifdef _WIN32
+LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
+#pragma code_page(1251)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_OPT_MSNMAIN DIALOGEX 0, 0, 312, 247
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_OPTIONSTAB,"SysTabControl32",WS_TABSTOP,1,1,310,245,WS_EX_ACCEPTFILES
+END
+
+IDD_SETAVATAR DIALOGEX 0, 0, 222, 131
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_AVATAR,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_SUNKEN,9,11,96,96
+ PUSHBUTTON "Set",IDC_SETAVATAR,9,112,45,13
+ PUSHBUTTON "Delete",IDC_DELETEAVATAR,61,112,41,13
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_SETAVATAR, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 107
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // Russian resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.K.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_OPT_MSN DIALOGEX 0, 0, 304, 207
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "MSN",IDC_STMSNGROUP,4,0,298,84,WS_GROUP
+ RTEXT "Full e-mail:",IDC_STATIC,16,20,52,8
+ EDITTEXT IDC_HANDLE,72,18,100,12,ES_AUTOHSCROLL
+ RTEXT "Password:",IDC_STATIC,16,36,52,8
+ EDITTEXT IDC_PASSWORD,72,34,100,12,ES_PASSWORD | ES_AUTOHSCROLL
+ RTEXT "Nickname:",IDC_STATIC,16,52,52,8
+ EDITTEXT IDC_HANDLE2,72,50,100,12,ES_AUTOHSCROLL
+ CONTROL "Create a new MSN messenger account using the MSN website",IDC_NEWMSNACCOUNTLINK,
+ "Hyperlink",WS_TABSTOP,21,68,208,8
+ GROUPBOX "Expert",IDC_STATIC,4,84,298,119,WS_GROUP
+ CONTROL "Disable main menu",IDC_DISABLE_MAIN_MENU,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,96,288,10
+ CONTROL "Send message font color/size info inside messages",IDC_SENDFONTINFO,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,107,288,10
+ CONTROL "Disable all contacts not included into my contact list",IDC_DISABLE_ANOTHER_CONTACTS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,118,288,10
+ CONTROL "Never update your nickname from server",IDC_USE_OWN_NICKNAME,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,129,288,10
+ CONTROL "Treat Away status as 'Be Right Back'",IDC_AWAY_AS_BRB,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,140,288,10
+ CONTROL "Manage server groups",IDC_MANAGEGROUPS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,151,288,10
+ CONTROL "Run the following application when new Hotmail is arrived",IDC_RUN_APP_ON_HOTMAIL,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,173,288,10
+ EDITTEXT IDC_MAILER_APP,23,184,161,12,ES_AUTOHSCROLL
+ PUSHBUTTON "...",IDC_ENTER_MAILER_APP,189,184,15,12
+ CONTROL "Enable avatars",IDC_ENABLE_AVATARS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,162,288,10
+END
+
+IDD_OPT_MSN_CONN DIALOGEX 0, 0, 304, 175
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Connection settings",IDC_STATIC,4,0,298,120
+ LTEXT "Login server:",IDC_STATIC,16,18,44,8
+ EDITTEXT IDC_LOGINSERVER,68,16,168,12,ES_AUTOHSCROLL
+ LTEXT "Port:",IDC_STATIC,16,32,48,8
+ EDITTEXT IDC_MSNPORT,68,30,44,12,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "Use HTTP gateway mode (incompatible with MSN Gateway plugin)",IDC_USEGATEWAY,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,46,264,8
+ CONTROL "Use IE proxy settings",IDC_USEIEPROXY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,58,264,8
+ CONTROL "Keep connection alive (send a ping packet every minute)",IDC_KEEPALIVE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,70,264,8
+ CONTROL "Notify me when a message delivery has failed",IDC_SLOWSEND,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,82,263,8
+ CONTROL "Use MSN Messenger 7 protocol",IDC_USEMSNP11,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,94,262,8
+ CONTROL "Use OpenSSL encryption (requires LIBSSL32.DLL)",IDC_USEOPENSSL,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,106,263,8
+ GROUPBOX "Incoming file transfers",IDC_STATIC,4,124,298,48
+ CONTROL "Automatically obtain host/port for incoming file transfers",IDC_AUTOGETHOST,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,136,264,10
+ LTEXT "Your host (or router):",IDC_STATIC,12,152,72,8
+ EDITTEXT IDC_YOURHOST,90,151,184,12,ES_AUTOHSCROLL
+ PUSHBUTTON "Reset",IDC_RESETSERVER,244,16,34,12
+END
+
+IDD_LISTSMGR DIALOGEX 0, 0, 304, 228
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Server List Manager",IDC_STATIC,4,0,298,224
+ CONTROL "",IDC_LIST,"CListControl",WS_TABSTOP | 0x190,9,12,287,180,WS_EX_CLIENTEDGE
+ ICON IDI_LIST_FL,IDC_ICON_FL,10,196,21,20,SS_REALSIZEIMAGE
+ LTEXT "Contact is included into your server list",IDC_STATIC,28,196,144,8
+ ICON IDI_LIST_AL,IDC_ICON_AL,187,196,21,20,SS_REALSIZEIMAGE
+ LTEXT "Somebody included you in his/her server list",IDC_STATIC,28,208,144,8
+ ICON IDI_LIST_BL,IDC_ICON_BL,187,208,21,20,SS_REALSIZEIMAGE
+ LTEXT "Allowed (active) contact",IDC_STATIC,204,196,82,8
+ ICON IDI_LIST_RL,IDC_ICON_RL,10,208,21,20,SS_REALSIZEIMAGE
+ LTEXT "Blocked contact",IDC_STATIC,204,208,82,8
+END
+
+IDD_HOTMAIL_OPT_POPUP DIALOGEX 0, 0, 238, 220
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Colours",IDC_STATIC,4,0,232,59
+ CONTROL "",IDC_BGCOLOUR,"ColourPicker",WS_TABSTOP,12,12,39,12
+ LTEXT "Background colour",IDC_STATIC,56,14,176,8,SS_CENTERIMAGE
+ CONTROL "",IDC_TEXTCOLOUR,"ColourPicker",WS_TABSTOP,12,28,39,12
+ LTEXT "Text colour",IDC_STATIC,56,30,176,8,SS_CENTERIMAGE
+ CONTROL "&Use Windows colours",IDC_USEWINCOLORS,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | BS_FLAT | WS_TABSTOP,12,44,220,8
+ GROUPBOX "Hotmail",IDC_STATIC,4,61,232,59
+ CONTROL "Disable receiving Hotmail notifications",IDC_DISABLEHOTMAIL,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,72,220,10
+ CONTROL "Ignore new messages in 'Junk Mail' folder only (at startup)",IDC_DISABLEHOTJUNK,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,84,202,10
+ LTEXT "Timeout (*)",IDC_STATIC,12,102,52,8
+ EDITTEXT IDC_POPUP_TIMEOUT,72,100,24,12,ES_AUTOHSCROLL | ES_NUMBER
+ LTEXT "sec.",IDC_STATIC,100,102,30,8
+ DEFPUSHBUTTON "Previe&w",IDC_PREVIEW,176,100,52,12
+ GROUPBOX "Other",IDC_STATIC,3,122,232,81
+ CONTROL "Display popups when user is typing",IDC_NOTIFY_USERTYPE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,135,216,10
+ CONTROL "Display errors using popups",IDC_ERRORS_USING_POPUPS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,147,216,10
+ CONTROL "Enable 'First message delivered' popup",IDC_NOTIFY_FIRSTMSG,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,159,216,10
+ LTEXT "Timeout (*)",IDC_STATIC,10,186,60,8
+ EDITTEXT IDC_POPUP_TIMEOUT2,70,183,24,12,ES_AUTOHSCROLL | ES_NUMBER
+ LTEXT "sec.",IDC_STATIC,98,186,30,8
+ DEFPUSHBUTTON "Previe&w",IDC_PREVIEW2,174,183,52,12
+ LTEXT "(*) Timeouts require Popup v. 1.0.1.9 or later",IDC_STATIC,4,207,232,8
+ CONTROL "Enable 'User left channel' popup",IDC_NOTIFY_ENDSESSION,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,172,218,8
+END
+
+IDD_SETNICKNAME DIALOGEX 0, 0, 187, 42
+STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Set Nickname"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ EDITTEXT IDC_NICKNAME,5,5,177,12,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,36,23,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,102,23,50,14
+END
+
+IDD_USEROPTS DIALOGEX 0, 0, 224, 132
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Avatar",IDC_STATIC,8,8,100,10
+ CONTROL "",IDC_MSN_PICT,"Static",SS_BITMAP,8,18,64,64
+ CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME | SS_SUNKEN,8,18,64,60
+ LTEXT "Running on a mobile device",IDC_STATIC,8,82,100,8
+ LTEXT "",IDC_MOBILE,108,82,10,8
+ LTEXT "Running on a MSN mobile device",IDC_STATIC,8,92,100,8
+ LTEXT "",IDC_MSN_MOBILE,108,92,10,8
+ LTEXT "Using MSN Webmessenger",IDC_STATIC,8,102,100,8
+ LTEXT "",IDC_WEBMESSENGER,108,102,10,8
+END
+
+IDD_GET_PNG2DIB DIALOGEX 0, 0, 276, 101
+STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "png2lib download"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "To enable the avatar support, you must obtain the valid copy of the png2dib.dll. Choose one of the following:",IDC_STATIC,8,8,256,16
+ LTEXT "[Install] - install a png2lib plugin using Miranda Installer",IDC_STATIC,16,32,248,8
+ LTEXT "[Download] - manually download a zipped DLL and then unzip it to the plugins folder",IDC_STATIC,16,44,248,16
+ LTEXT "[Cancel] - disable the avatar support",IDC_STATIC,16,64,248,8
+ PUSHBUTTON "Install",IDC_BTN_INSTALL,37,80,68,16
+ PUSHBUTTON "Download",IDC_BTN_DOWNLOAD,113,80,60,16
+ PUSHBUTTON "Cancel",IDC_BTN_CANCEL,181,80,56,16
+END
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_OPT_MSN, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 304
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 202
+ END
+
+ IDD_OPT_MSN_CONN, DIALOG
+ BEGIN
+ BOTTOMMARGIN, 163
+ END
+
+ IDD_HOTMAIL_OPT_POPUP, DIALOG
+ BEGIN
+ LEFTMARGIN, 3
+ RIGHTMARGIN, 236
+ END
+
+ IDD_SETNICKNAME, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 182
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 37
+ END
+
+ IDD_LISTSMGR, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 308
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 240
+ END
+
+ IDD_OPT_MSN_EXTRAS, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 303
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 202
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_MSN ICON "Icos\\msn.ico"
+IDI_LIST_FL ICON "Icos\\list_fl.ico"
+IDI_LIST_AL ICON "Icos\\list_al.ico"
+IDI_LIST_BL ICON "Icos\\list_bl.ico"
+IDI_LIST_RL ICON "Icos\\list_rl.ico"
+IDI_MSNBLOCK ICON "Icos\\msnblock.ico"
+IDI_INBOX ICON "Icos\\inbox.ico"
+IDI_INVITE ICON "Icos\\invite.ico"
+IDI_PROFILE ICON "Icos\\profile.ico"
+IDI_NETMEETING ICON "Icos\\netmeeting.ico"
+IDI_SERVICES ICON "Icos\\services.ico"
+IDI_AVATAR ICON "Icos\\avatar.ico"
+IDI_NUDGE ICON "Icos\\nudge.ico"
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include <windows.h>\r\n"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.K.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/miranda-wine/protocols/MSN/msn_bitmap.cpp b/miranda-wine/protocols/MSN/msn_bitmap.cpp
new file mode 100644
index 0000000..fccb6c6
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_bitmap.cpp
@@ -0,0 +1,213 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "msn_global.h"
+
+#include "sha1.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_BitmapToAvatarDibBits - rescales a bitmap to 96x96 pixels and creates a DIB from it
+
+HBITMAP __stdcall MSN_StretchBitmap( HBITMAP hBitmap )
+{
+ BITMAPINFO bmStretch = { 0 };
+ bmStretch.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmStretch.bmiHeader.biWidth = 96;
+ bmStretch.bmiHeader.biHeight = 96;
+ bmStretch.bmiHeader.biPlanes = 1;
+ bmStretch.bmiHeader.biBitCount = 32;
+
+ UINT* ptPixels;
+ HBITMAP hStretchedBitmap = CreateDIBSection( NULL, &bmStretch, DIB_RGB_COLORS, ( void** )&ptPixels, NULL, 0);
+ if ( hStretchedBitmap == NULL ) {
+ MSN_DebugLog( "Bitmap creation failed with error %d", GetLastError() );
+ return NULL;
+ }
+
+ BITMAP bmp;
+ HDC hDC = CreateCompatibleDC( NULL );
+ HBITMAP hOldBitmap1 = ( HBITMAP )SelectObject( hDC, hBitmap );
+ GetObject( hBitmap, sizeof( BITMAP ), &bmp );
+
+ HDC hBmpDC = CreateCompatibleDC( hDC );
+ HBITMAP hOldBitmap2 = ( HBITMAP )SelectObject( hBmpDC, hStretchedBitmap );
+ int side, dx, dy;
+
+ if ( bmp.bmWidth > bmp.bmHeight ) {
+ side = bmp.bmHeight;
+ dx = ( bmp.bmWidth - bmp.bmHeight )/2;
+ dy = 0;
+ }
+ else {
+ side = bmp.bmWidth;
+ dx = 0;
+ dy = ( bmp.bmHeight - bmp.bmWidth )/2;
+ }
+
+ SetStretchBltMode( hBmpDC, HALFTONE );
+ StretchBlt( hBmpDC, 0, 0, 96, 96, hDC, dx, dy, side, side, SRCCOPY );
+
+ SelectObject( hDC, hOldBitmap1 );
+ DeleteObject( hBitmap );
+ DeleteDC( hDC );
+
+ SelectObject( hBmpDC, hOldBitmap2 );
+ DeleteDC( hBmpDC );
+ return hStretchedBitmap;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_SaveBitmapAsAvatar - updates the avatar database settins and file from a bitmap
+
+int __stdcall MSN_SaveBitmapAsAvatar( HBITMAP hBitmap, const char* szFileName )
+{
+ if ( !MSN_LoadPngModule())
+ return 1;
+
+ HDC hdc = CreateCompatibleDC( NULL );
+ HBITMAP hOldBitmap = ( HBITMAP )SelectObject( hdc, hBitmap );
+
+ BITMAPINFO* bmi = ( BITMAPINFO* )alloca( sizeof( BITMAPINFO ) + sizeof( RGBQUAD )*256 );
+ memset( bmi, 0, sizeof( BITMAPINFO ));
+ bmi->bmiHeader.biSize = 0x28;
+ if ( GetDIBits( hdc, hBitmap, 0, 96, NULL, bmi, DIB_RGB_COLORS ) == 0 ) {
+ TWinErrorCode errCode;
+ MSN_ShowError( "Unable to get the bitmap: error %d (%s)", errCode.mErrorCode, errCode.getText() );
+ return 2;
+ }
+
+ BITMAPINFOHEADER* pDib;
+ BYTE* pDibBits;
+ pDib = ( BITMAPINFOHEADER* )GlobalAlloc( LPTR, sizeof( BITMAPINFO ) + sizeof( RGBQUAD )*256 + bmi->bmiHeader.biSizeImage );
+ if ( pDib == NULL )
+ return 3;
+
+ memcpy( pDib, bmi, sizeof( BITMAPINFO ) + sizeof( RGBQUAD )*256 );
+ pDibBits = (( BYTE* )pDib ) + sizeof( BITMAPINFO ) + sizeof( RGBQUAD )*256;
+
+ GetDIBits( hdc, hBitmap, 0, pDib->biHeight, pDibBits, ( BITMAPINFO* )pDib, DIB_RGB_COLORS );
+ SelectObject( hdc, hOldBitmap );
+ DeleteDC( hdc );
+
+ long dwPngSize = 0;
+ DIB2PNG convertor;
+ convertor.pbmi = ( BITMAPINFO* )pDib;
+ convertor.pDiData = pDibBits;
+ convertor.pResult = NULL;
+ convertor.pResultLen = &dwPngSize;
+ if ( !CallService( MS_DIB2PNG, 0, (LPARAM)&convertor )) {
+ GlobalFree( pDib );
+ return 2;
+ }
+
+ convertor.pResult = new BYTE[ dwPngSize ];
+ CallService( MS_DIB2PNG, 0, (LPARAM)&convertor );
+ GlobalFree( pDib );
+
+ SHA1Context sha1ctx;
+ BYTE sha1c[ SHA1HashSize ], sha1d[ SHA1HashSize ];
+ char szSha1c[ 40 ], szSha1d[ 40 ];
+ SHA1Reset( &sha1ctx );
+ SHA1Input( &sha1ctx, convertor.pResult, dwPngSize );
+ SHA1Result( &sha1ctx, sha1d );
+ { NETLIBBASE64 nlb = { szSha1d, sizeof szSha1d, ( PBYTE )sha1d, sizeof sha1d };
+ MSN_CallService( MS_NETLIB_BASE64ENCODE, 0, LPARAM( &nlb ));
+ }
+ char drive[_MAX_DRIVE];
+ char dir[_MAX_DIR];
+ char fname[_MAX_FNAME];
+ char ext[_MAX_EXT];
+ _splitpath(szFileName, drive, dir, fname, ext );
+ SHA1Reset( &sha1ctx );
+
+ char szEmail[ MSN_MAX_EMAIL_LEN ];
+ MSN_GetStaticString( "e-mail", NULL, szEmail, sizeof szEmail );
+ SHA1Input( &sha1ctx, ( PBYTE )"Creator", 7 );
+ SHA1Input( &sha1ctx, ( PBYTE )szEmail, strlen( szEmail ));
+
+ char szFileSize[ 20 ];
+ ltoa( dwPngSize, szFileSize, 10 );
+ SHA1Input( &sha1ctx, ( PBYTE )"Size", 4 );
+ SHA1Input( &sha1ctx, ( PBYTE )szFileSize, strlen( szFileSize ));
+
+ SHA1Input( &sha1ctx, ( PBYTE )"Type", 4 );
+ SHA1Input( &sha1ctx, ( PBYTE )"3", 1 );
+
+ SHA1Input( &sha1ctx, ( PBYTE )"Location", 8 );
+ SHA1Input( &sha1ctx, ( PBYTE )fname, sizeof(fname));
+
+ SHA1Input( &sha1ctx, ( PBYTE )"Friendly", 8 );
+ SHA1Input( &sha1ctx, ( PBYTE )"AAA=", 4 );
+
+ SHA1Input( &sha1ctx, ( PBYTE )"SHA1D", 5 );
+ SHA1Input( &sha1ctx, ( PBYTE )szSha1d, strlen( szSha1d ));
+ SHA1Result( &sha1ctx, sha1c );
+ { NETLIBBASE64 nlb = { szSha1c, sizeof szSha1c, ( PBYTE )sha1c, sizeof sha1c };
+ MSN_CallService( MS_NETLIB_BASE64ENCODE, 0, LPARAM( &nlb ));
+ }
+ {
+ char* szBuffer = ( char* )alloca( 1000 );
+ mir_snprintf( szBuffer, 1000,
+ "<msnobj Creator=\"%s\" Size=\"%ld\" Type=\"3\" Location=\"%s\" Friendly=\"AAA=\" SHA1D=\"%s\" SHA1C=\"%s\"/>",
+ szEmail, dwPngSize,fname, szSha1d, szSha1c );
+
+ char* szEncodedBuffer = ( char* )alloca( 1000 );
+ UrlEncode( szBuffer, szEncodedBuffer, 1000 );
+
+ MSN_SetString( NULL, "PictObject", szEncodedBuffer );
+ }
+ { char tFileName[ MAX_PATH ];
+ MSN_GetAvatarFileName( NULL, tFileName, sizeof tFileName );
+ FILE* out = fopen( tFileName, "wb" );
+ if ( out != NULL ) {
+ fwrite( convertor.pResult, dwPngSize, 1, out );
+ fclose( out );
+ } }
+ delete convertor.pResult;
+ return ERROR_SUCCESS;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_EnterBitmapFileName - enters a bitmap filename
+
+int __stdcall MSN_EnterBitmapFileName( char* szDest )
+{
+ *szDest = 0;
+
+ char szFilter[ 512 ];
+ MSN_CallService( MS_UTILS_GETBITMAPFILTERSTRINGS, sizeof szFilter, ( LPARAM )szFilter );
+
+ char str[ MAX_PATH ]; str[0] = 0;
+ OPENFILENAMEA ofn = {0};
+ ofn.lStructSize = sizeof( OPENFILENAME );
+ ofn.lpstrFilter = szFilter;
+ ofn.lpstrFile = szDest;
+ ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
+ ofn.nMaxFile = MAX_PATH;
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.lpstrDefExt = "bmp";
+ if ( !GetOpenFileNameA( &ofn ))
+ return 1;
+
+ return ERROR_SUCCESS;
+}
diff --git a/miranda-wine/protocols/MSN/msn_block.cpp b/miranda-wine/protocols/MSN/msn_block.cpp
new file mode 100644
index 0000000..12199f0
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_block.cpp
@@ -0,0 +1,33 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 <windows.h>
+#include <stdio.h>
+
+#include "msn_global.h"
+
+#pragma hdrstop
+
+#include "resource.h"
+
+extern HINSTANCE hInst;
diff --git a/miranda-wine/protocols/MSN/msn_chat.cpp b/miranda-wine/protocols/MSN/msn_chat.cpp
new file mode 100644
index 0000000..fae3574
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_chat.cpp
@@ -0,0 +1,335 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "msn_global.h"
+#include "../../include/m_history.h"
+
+static LONG sttChatID = 0;
+extern HANDLE hInitChat;
+
+int MSN_ChatInit( WPARAM wParam, LPARAM lParam )
+{
+ ThreadData *info = (ThreadData*)wParam;
+ GCWINDOW gcw = {0};
+ GCDEST gcd = {0};
+ GCEVENT gce = {0};
+
+ InterlockedIncrement( &sttChatID );
+ ltoa( sttChatID, info->mChatID, 10 );
+
+ info->mJoinedContacts = ( HANDLE* )realloc(info->mJoinedContacts, sizeof(HANDLE)*(++info->mJoinedCount));
+ info->mJoinedContacts[info->mJoinedCount - 1] = info->mJoinedContacts[0];
+ info->mJoinedContacts[0] = ( HANDLE )-sttChatID;
+
+ char szName[ 512 ];
+ char tEmail[ MSN_MAX_EMAIL_LEN ], tNick[ 1024 ];
+ mir_snprintf( szName, sizeof( szName ), "%s%s", Translate("MSN Chat #"), info->mChatID );
+
+ gcw.cbSize = sizeof(GCWINDOW);
+ gcw.iType = GCW_CHATROOM;
+ gcw.pszModule = msnProtocolName;
+ gcw.pszName = szName;
+ gcw.pszID = info->mChatID;
+ gcw.pszStatusbarText = NULL;
+ gcw.bDisableNickList = FALSE;
+ MSN_CallService(MS_GC_NEWCHAT, NULL, (LPARAM)&gcw);
+
+ gce.cbSize = sizeof(GCEVENT);
+ gcd.pszModule = msnProtocolName;
+ gcd.pszID = info->mChatID;
+ gcd.iType = GC_EVENT_ADDGROUP;
+ gce.pDest = &gcd;
+ gce.pszStatus = Translate("Me");
+ MSN_CallService(MS_GC_EVENT, NULL, (LPARAM)&gce);
+
+ gcd.iType = GC_EVENT_JOIN;
+ gce.pszStatus, Translate("Me");
+ MSN_GetStaticString( "Nick", NULL, tNick, sizeof tNick );
+ gce.pszNick = tNick;
+ MSN_GetStaticString( "e-mail", NULL, tEmail, sizeof tEmail );
+ gce.pszUID = tEmail;
+ gce.time = 0;
+ gce.bIsMe = TRUE;
+ gce.bAddToLog = FALSE;
+ MSN_CallService(MS_GC_EVENT, NULL, (LPARAM)&gce);
+
+ gcd.iType = GC_EVENT_ADDGROUP;
+ gce.pDest = &gcd;
+ gce.pszStatus = Translate("Others");
+ MSN_CallService(MS_GC_EVENT, NULL, (LPARAM)&gce);
+
+ gce.cbSize = sizeof(GCEVENT);
+ gcd.iType = GC_EVENT_CONTROL;
+ gce.pDest = &gcd;
+ MSN_CallService(MS_GC_EVENT, WINDOW_INITDONE, (LPARAM)&gce);
+ MSN_CallService(MS_GC_EVENT, WINDOW_ONLINE, (LPARAM)&gce);
+ MSN_CallService(MS_GC_EVENT, WINDOW_VISIBLE, (LPARAM)&gce);
+ return 0;
+}
+
+void MSN_ChatStart(ThreadData* info) {
+ if ( info->mChatID[0] == 0 ) {
+ NotifyEventHooks( hInitChat, (WPARAM)info, 0 );
+
+ // add all participants onto the list
+ GCDEST gcd = {0};
+ gcd.pszModule = msnProtocolName;
+ gcd.pszID = info->mChatID;
+ gcd.iType = GC_EVENT_JOIN;
+
+ GCEVENT gce = {0};
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ gce.pszStatus = Translate("Others");
+ gce.time = time(NULL);
+ gce.bIsMe = FALSE;
+ gce.bAddToLog = TRUE;
+
+ for ( int j=0; j < info->mJoinedCount; j++ ) {
+ if (( long )info->mJoinedContacts[j] > 0 ) {
+ gce.pszNick = MSN_GetContactName( info->mJoinedContacts[j] );
+
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( !MSN_GetStaticString( "e-mail", info->mJoinedContacts[j], tEmail, sizeof tEmail )) {
+ gce.pszUID = tEmail;
+ MSN_CallService( MS_GC_EVENT, NULL, ( LPARAM )&gce );
+ } } } }
+}
+
+void KillChatSession(char* id, GCHOOK* gch) {
+ GCDEST gcd = {0};
+ GCEVENT gce = {0};
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ gcd.pszModule = gch->pDest->pszModule;
+ gcd.pszID = gch->pDest->pszID;
+ gcd.iType = GC_EVENT_CONTROL;
+ MSN_CallService(MS_GC_EVENT, WINDOW_OFFLINE, (LPARAM)&gce);
+ MSN_CallService(MS_GC_EVENT, WINDOW_TERMINATE, (LPARAM)&gce);
+}
+
+void InviteUser(ThreadData* info) {
+ HMENU tMenu = ::CreatePopupMenu();
+ HANDLE hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+
+ // add the heading
+ ::AppendMenu(tMenu, MF_STRING|MF_GRAYED|MF_DISABLED, (UINT_PTR)0, TranslateT("&Invite user..."));
+ ::AppendMenu(tMenu, MF_SEPARATOR, (UINT_PTR)1, NULL);
+
+ // generate a list of contact
+ while ( hContact != NULL ) {
+ if ( !lstrcmpA( msnProtocolName, ( char* )MSN_CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact,0 ))) {
+ if (DBGetContactSettingByte(hContact, msnProtocolName, "ChatRoom", 0) == 0) {
+ if (MSN_GetWord(hContact, "Status", ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE) {
+ BOOL alreadyInSession = FALSE;
+ for ( int j=0; j < info->mJoinedCount; j++ ) {
+ if (info->mJoinedContacts[j] == hContact) {
+ alreadyInSession = TRUE;
+ break;
+ }
+ }
+ if (!alreadyInSession)
+ ::AppendMenu(tMenu, MF_STRING, (UINT_PTR)hContact, MSN_GetContactNameT(hContact));
+ }
+ } }
+ hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDNEXT,( WPARAM )hContact, 0 );
+ }
+
+ HWND tWindow = CreateWindow(_T("EDIT"),_T(""),0,1,1,1,1,NULL,NULL,hInst,NULL);
+
+ POINT pt;
+ ::GetCursorPos ( &pt );
+ HANDLE hInvitedUser = (HANDLE)::TrackPopupMenu( tMenu, TPM_NONOTIFY | TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD, pt.x, pt.y, 0, tWindow, NULL );
+ ::DestroyMenu( tMenu );
+ ::DestroyWindow( tWindow );
+
+ if ( !hInvitedUser )
+ return;
+
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( !MSN_GetStaticString( "e-mail", ( HANDLE )hInvitedUser, tEmail, sizeof( tEmail ))) {
+ info->sendPacket( "CAL", tEmail );
+ MSN_ChatStart(info);
+} }
+
+int MSN_GCEventHook(WPARAM wParam,LPARAM lParam) {
+ GCHOOK *gch = (GCHOOK*) lParam;
+ char S[512] = "";
+
+ if(gch) {
+ if (!lstrcmpiA(gch->pDest->pszModule, msnProtocolName)) {
+ char *p = new char[lstrlenA(gch->pDest->pszID)+1];
+ lstrcpyA(p, gch->pDest->pszID);
+ switch (gch->pDest->iType) {
+ case GC_USER_TERMINATE: {
+ int chatID = atoi( p );
+ ThreadData* thread = MSN_GetThreadByContact((HANDLE)-chatID);
+ if ( thread != NULL ) {
+ // open up srmm dialog when quit while 1 person left
+ if ( thread->mJoinedCount == 1 ) {
+ // switch back to normal session
+ thread->mJoinedContacts[0] = thread->mJoinedContacts[1];
+ thread->mJoinedContacts = ( HANDLE* )realloc( thread->mJoinedContacts, sizeof( HANDLE ) );
+ MSN_CallService(MS_MSG_SENDMESSAGE, (WPARAM)thread->mJoinedContacts[0], 0);
+ thread->mChatID[0] = 0;
+ }
+ else thread->sendPacket( "OUT", NULL );
+ }
+ break;
+ }
+ case GC_USER_MESSAGE:
+ if ( gch && gch->pszText && lstrlenA( gch->pszText ) > 0 ) {
+ rtrim( gch->pszText ); // remove the ending linebreak
+
+ { char* pszMsg = UnEscapeChatTags( NEWSTR_ALLOCA( gch->pszText ));
+
+ CCSDATA ccs = {0};
+ ccs.hContact = (HANDLE)-atoi(p);
+ ccs.wParam = 0;
+ ccs.lParam = (LPARAM)pszMsg;
+ CallProtoService(msnProtocolName, PSS_MESSAGE, (WPARAM)0, (LPARAM)&ccs);
+ }
+
+ GCDEST gcd = {0};
+ GCEVENT gce = {0};
+
+ gcd.pszModule = msnProtocolName;
+ gcd.pszID = p;
+ gcd.iType = GC_EVENT_MESSAGE;
+
+ char tEmail[ MSN_MAX_EMAIL_LEN ], tNick[ 1024 ];
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ MSN_GetStaticString( "Nick", NULL, tNick, sizeof tNick );
+ gce.pszNick = tNick;
+ MSN_GetStaticString( "e-mail", NULL, tEmail, sizeof tEmail );
+ gce.pszUID = tEmail;
+ gce.time = time(NULL);
+ gce.pszText = gch->pszText;
+ gce.bAddToLog = TRUE;
+ gce.bIsMe = TRUE;
+ MSN_CallService(MS_GC_EVENT, NULL, (LPARAM)&gce);
+ }
+ break;
+ case GC_USER_CHANMGR: {
+ int chatID = atoi(p);
+ ThreadData* thread = MSN_GetThreadByContact((HANDLE)-chatID);
+ if ( thread != NULL ) {
+ InviteUser(thread);
+ }
+ break;
+ }
+ case GC_USER_PRIVMESS: {
+ HANDLE hContact = MSN_HContactFromEmail((char*)gch->pszUID, NULL, 0, 0);
+ MSN_CallService(MS_MSG_SENDMESSAGE, (WPARAM)hContact, 0);
+ break;
+ }
+ case GC_USER_LOGMENU:
+ switch(gch->dwData) {
+ case 10: {
+ int chatID = atoi(p);
+ ThreadData* thread = MSN_GetThreadByContact((HANDLE)-chatID);
+ if ( thread != NULL ) {
+ InviteUser(thread);
+ }
+ break;
+ }
+ case 20:
+ KillChatSession(p, gch);
+ break;
+ }
+ break;
+ case GC_USER_NICKLISTMENU: {
+ HANDLE hContact = MSN_HContactFromEmail((char*)gch->pszUID, NULL, 0, 0);
+
+ switch(gch->dwData) {
+ case 10:
+ MSN_CallService(MS_USERINFO_SHOWDIALOG, (WPARAM)hContact, 0);
+ break;
+ case 20:
+ MSN_CallService(MS_HISTORY_SHOWCONTACTHISTORY, (WPARAM)hContact, 0);
+ break;
+ case 110:
+ KillChatSession(p, gch);
+ break;
+ }
+ break;
+ }
+/* haven't implemented in chat.dll
+ case GC_USER_TYPNOTIFY: {
+ int chatID = atoi(p);
+ ThreadData* thread = MSN_GetThreadByContact((HANDLE)-chatID);
+ for ( int j=0; j < thread->mJoinedCount; j++ ) {
+ if (( long )thread->mJoinedContacts[j] > 0 )
+ CallService(MS_PROTO_SELFISTYPING, (WPARAM) thread->mJoinedContacts[j], (LPARAM) PROTOTYPE_SELFTYPING_ON);
+ }
+ break;
+ }
+*/
+ default:
+ break;
+ }
+ delete[]p;
+ }
+
+ }
+ return 0;
+}
+
+int MSN_GCMenuHook(WPARAM wParam,LPARAM lParam) {
+ GCMENUITEMS *gcmi= (GCMENUITEMS*) lParam;
+
+ if ( gcmi ) {
+ if (!lstrcmpiA(gcmi->pszModule, msnProtocolName)) {
+ if(gcmi->Type == MENU_ON_LOG) {
+ static struct gc_item Item[] = {
+ {Translate("&Invite user..."), 10, MENU_ITEM, FALSE},
+ {Translate("&Leave chat session"), 20, MENU_ITEM, FALSE}
+ };
+ gcmi->nItems = sizeof(Item)/sizeof(Item[0]);
+ gcmi->Item = &Item[0];
+ }
+ if(gcmi->Type == MENU_ON_NICKLIST) {
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ MSN_GetStaticString( "e-mail", NULL, tEmail, sizeof tEmail );
+ if (!lstrcmpA(tEmail, (char *)gcmi->pszUID)) {
+ static struct gc_item Item[] = {
+ {Translate("User &details"), 10, MENU_ITEM, FALSE},
+ {Translate("User &history"), 20, MENU_ITEM, FALSE},
+ {Translate(""), 100, MENU_SEPARATOR, FALSE},
+ {Translate("&Leave chat session"), 110, MENU_ITEM, FALSE}
+ };
+ gcmi->nItems = sizeof(Item)/sizeof(Item[0]);
+ gcmi->Item = &Item[0];
+ }
+ else {
+ static struct gc_item Item[] = {
+ {Translate("User &details"), 10, MENU_ITEM, FALSE},
+ {Translate("User &history"), 20, MENU_ITEM, FALSE}
+ };
+ gcmi->nItems = sizeof(Item)/sizeof(Item[0]);
+ gcmi->Item = &Item[0];
+ } } } }
+
+ return 0;
+}
diff --git a/miranda-wine/protocols/MSN/msn_commands.cpp b/miranda-wine/protocols/MSN/msn_commands.cpp
new file mode 100644
index 0000000..4e84931
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_commands.cpp
@@ -0,0 +1,1841 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "msn_global.h"
+
+#include <io.h>
+#include <direct.h>
+#include <process.h>
+#include <time.h>
+
+#include "resource.h"
+
+#include "msn_md5.h"
+
+void __cdecl MSNNudgeThread( ThreadData* info );
+void __cdecl MSNServerThread( ThreadData* info );
+void __cdecl MSNSendfileThread( ThreadData* info );
+
+int MSN_GetPassportAuth( char* authChallengeInfo, char*& parResult );
+
+void mmdecode(char *trg, char *str);
+
+void MSN_ChatStart(ThreadData* info);
+
+ int tridUrlInbox = -1, tridUrlEdit = -1;
+
+char* sid = NULL;
+char* kv = NULL;
+char* MSPAuth = NULL;
+char* passport = NULL;
+char* profileURL = NULL;
+char* rru = NULL;
+extern HANDLE hMSNNudge;
+
+extern int msnPingTimeout, msnPingTimeoutCurrent;
+
+unsigned long sl;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_ReceiveMessage - receives message or a file from the server
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static int sttDivideWords( char* parBuffer, int parMinItems, char** parDest )
+{
+ int i;
+ for ( i=0; i < parMinItems; i++ ) {
+ parDest[ i ] = parBuffer;
+
+ int tWordLen = strcspn( parBuffer, " \t" );
+ if ( tWordLen == 0 )
+ return i;
+
+ parBuffer += tWordLen;
+ if ( *parBuffer != '\0' ) {
+ int tSpaceLen = strspn( parBuffer, " \t" );
+ memset( parBuffer, 0, tSpaceLen );
+ parBuffer += tSpaceLen;
+ } }
+
+ return i;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_GetMyHostAsString - retrieves a host address as a string
+
+int __stdcall MSN_GetMyHostAsString( char* parBuf, int parBufSize )
+{
+ IN_ADDR in;
+ hostent* myhost;
+
+ if ( msnExternalIP != NULL )
+ strncpy( parBuf, msnExternalIP, parBufSize );
+ else
+ gethostname( parBuf, parBufSize );
+
+ if ( MSN_GetByte( "AutoGetHost", 1 ))
+ MSN_SetString( NULL, "YourHost", parBuf );
+ else
+ MSN_GetStaticString( "YourHost", NULL, parBuf, parBufSize );
+
+ long ipaddrlong = inet_addr( parBuf );
+ if ( ipaddrlong != INADDR_NONE )
+ in.S_un.S_addr = ipaddrlong;
+ else
+ { myhost = gethostbyname( parBuf );
+ if ( myhost == NULL ) {
+ { TWinErrorCode tError;
+ MSN_ShowError( "Unknown or invalid host name was specified (%s). Error %d: %s.",
+ parBuf, tError.mErrorCode, tError.getText());
+ }
+
+ return 1;
+ }
+ memcpy( &in, myhost->h_addr, 4 );
+ }
+
+ strncpy( parBuf, inet_ntoa( in ), parBufSize );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Starts a file sending thread
+
+void MSN_ConnectionProc( HANDLE hNewConnection, DWORD dwRemoteIP, void* )
+{
+ MSN_DebugLog( "File transfer connection accepted" );
+
+ WORD localPort = 0;
+ SOCKET s = MSN_CallService( MS_NETLIB_GETSOCKET, ( WPARAM )hNewConnection, 0 );
+ if ( s != INVALID_SOCKET) {
+ SOCKADDR_IN saddr;
+ int len = sizeof( saddr );
+ if ( getsockname( s, ( SOCKADDR* )&saddr, &len ) != SOCKET_ERROR )
+ localPort = ntohs( saddr.sin_port );
+ }
+
+ if ( localPort != 0 ) {
+ ThreadData* T = MSN_GetThreadByPort( localPort );
+ if ( T != NULL ) {
+ T->s = hNewConnection;
+ if ( T->mMsnFtp != NULL ) {
+ T->mMsnFtp->mIncomingPort = 0;
+ SetEvent( T->mMsnFtp->hWaitEvent );
+ }
+ else {
+ T->mP2pSession->mIncomingPort = 0;
+ SetEvent( T->mP2pSession->hWaitEvent );
+ }
+ return;
+ }
+ MSN_DebugLog( "There's no registered file transfers for incoming port #%d, connection closed", localPort );
+ }
+ else MSN_DebugLog( "Unable to determine the local port, file server connection closed." );
+
+ Netlib_CloseHandle( hNewConnection );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Processes e-mail notification
+
+static void sttNotificationMessage( const char* msgBody, bool isInitial )
+{
+ char tBuffer[512];
+ char tBuffer2[512];
+ bool tIsPopup = ServiceExists( MS_POPUP_ADDPOPUP ) != 0;
+ int UnreadMessages = 0, UnreadJunkEmails = 0;
+
+ MimeHeaders tFileInfo;
+ tFileInfo.readFromBuffer( msgBody );
+
+ const char* From = tFileInfo[ "From" ];
+ const char* Subject = tFileInfo[ "Subject" ];
+ const char* Fromaddr = tFileInfo[ "From-Addr" ];
+ {
+ const char* p;
+ if (( p = tFileInfo[ "Inbox-Unread" ] ) != NULL )
+ UnreadMessages = atoi( p );
+ if (( p = tFileInfo[ "Folders-Unread" ] ) != NULL )
+ UnreadJunkEmails = atoi( p );
+ }
+
+ if ( From != NULL && Subject != NULL && Fromaddr != NULL ) {
+ const char* SrcFolder = tFileInfo[ "Src-Folder" ];
+ const char* DestFolder = tFileInfo[ "Dest-Folder" ];
+ if ( DestFolder != NULL && SrcFolder == NULL ) {
+ UnreadMessages = strcmp( DestFolder, "ACTIVE" ) == 0;
+ UnreadJunkEmails = strcmp( DestFolder, "HM_BuLkMail_" ) == 0;
+ }
+
+ // nothing to do, a fake notification
+ if ( UnreadMessages == 0 && UnreadJunkEmails == 0 )
+ return;
+
+ char mimeFrom[ 1024 ], mimeSubject[ 1024 ];
+ mmdecode( mimeFrom, ( char* )From );
+ mmdecode( mimeSubject, ( char* )Subject );
+
+ if ( !strcmpi( From, Fromaddr )) {
+ if ( tIsPopup ) {
+ mir_snprintf( tBuffer, sizeof( tBuffer ), MSN_Translate( "Hotmail from %s" ), mimeFrom );
+ mir_snprintf( tBuffer2, sizeof( tBuffer2 ), MSN_Translate( "Subject: %s" ), mimeSubject );
+ }
+ else mir_snprintf( tBuffer, sizeof( tBuffer ), MSN_Translate("A new mail has come from %s (title: %s)."), mimeFrom, mimeSubject );
+ }
+ else {
+ if ( tIsPopup ) {
+ mir_snprintf( tBuffer, sizeof( tBuffer ), MSN_Translate("Hotmail from %s (%s)"),mimeFrom, Fromaddr );
+ mir_snprintf( tBuffer2, sizeof( tBuffer2 ), MSN_Translate("Subject: %s"), mimeSubject );
+ }
+ else mir_snprintf( tBuffer, sizeof( tBuffer ), MSN_Translate("A new mail has come from %s (%s) (title: %s)."),mimeFrom, Fromaddr, mimeSubject );
+ } }
+ else {
+ const char* MailData = tFileInfo[ "Mail-Data" ];
+ if ( MailData != NULL ) {
+ const char* p = strstr( MailData, "<IU>" );
+ if ( p != NULL )
+ UnreadMessages = atoi( p+4 );
+ if (( p = strstr( MailData, "<OU>" )) != NULL )
+ UnreadJunkEmails = atoi( p+4 );
+ }
+
+ // nothing to do, a fake notification
+ if ( UnreadMessages == 0 && UnreadJunkEmails == 0 )
+ return;
+
+ char* dest;
+ if ( tIsPopup ) {
+ mir_snprintf( tBuffer, sizeof( tBuffer ), MSN_Translate( "Hotmail" ));
+ dest = tBuffer2;
+ }
+ else dest = tBuffer;
+ mir_snprintf( dest, sizeof( tBuffer ), MSN_Translate( "Unread mail is available: %d messages (%d junk e-mails)." ),
+ UnreadMessages, UnreadJunkEmails );
+ }
+
+ // Disable to notify receiving hotmail
+ if ( !MSN_GetByte( "DisableHotmail", 1 )) {
+ if ( UnreadMessages != 0 || !MSN_GetByte( "DisableHotmailJunk", 0 )) {
+ SkinPlaySound( mailsoundname );
+ if ( tIsPopup )
+ MSN_ShowPopup( tBuffer, tBuffer2, MSN_ALLOW_ENTER + MSN_ALLOW_MSGBOX + MSN_HOTMAIL_POPUP );
+ else
+ MessageBoxA( NULL, tBuffer, "MSN Protocol", MB_OK | MB_ICONINFORMATION );
+ } }
+
+ if ( !MSN_GetByte( "RunMailerOnHotmail", 0 ))
+ return;
+
+ if ( !MSN_GetStaticString( "MailerPath", NULL, tBuffer, sizeof( tBuffer ))) {
+ if ( tBuffer[0] ) {
+ char* tParams = "";
+ char* p = tBuffer;
+
+ if ( *p == '\"' ) {
+ char* tEndPtr = strchr( p+1, '\"' );
+ if ( tEndPtr != NULL ) {
+ *tEndPtr = 0;
+ strdel( p, 1 );
+ tParams = tEndPtr+1;
+ goto LBL_Run;
+ } }
+
+ p = strchr( p+1, ' ' );
+ if ( p != NULL ) {
+ *p = 0;
+ tParams = p+1;
+ }
+LBL_Run:
+ while ( *tParams == ' ' )
+ tParams++;
+
+ MSN_DebugLog( "Running mailer \"%s\" with params \"%s\"", tBuffer, tParams );
+ ShellExecuteA( NULL, "open", tBuffer, tParams, NULL, TRUE );
+} } }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Processes various invitations
+
+static void sttInviteMessage( ThreadData* info, const char* msgBody, char* email, char* nick )
+{
+ MimeHeaders tFileInfo;
+ tFileInfo.readFromBuffer( msgBody );
+
+ const char* Appname = tFileInfo[ "Application-Name" ];
+ const char* AppGUID = tFileInfo[ "Application-GUID" ];
+ const char* Invcommand = tFileInfo[ "Invitation-Command" ];
+ const char* Invcookie = tFileInfo[ "Invitation-Cookie" ];
+ const char* Appfile = tFileInfo[ "Application-File" ];
+ const char* Appfilesize = tFileInfo[ "Application-FileSize" ];
+ const char* IPAddress = tFileInfo[ "IP-Address" ];
+ const char* Port = tFileInfo[ "Port" ];
+ const char* AuthCookie = tFileInfo[ "AuthCookie" ];
+ const char* SessionID = tFileInfo[ "Session-ID" ];
+ const char* SessionProtocol = tFileInfo[ "Session-Protocol" ];
+
+ if ( AppGUID != NULL ) {
+ if ( !strcmp( AppGUID, "{02D3C01F-BF30-4825-A83A-DE7AF41648AA}" )) {
+ MSN_ShowPopup( MSN_GetContactName( info->mJoinedContacts[0] ),
+ MSN_Translate( "Contact tried to open an audio conference (currently not supported)" ), MSN_ALLOW_MSGBOX );
+ return;
+ } }
+
+ if ( Invcommand && ( strcmp( Invcommand, "CANCEL" ) == 0 )) {
+ delete info->mMsnFtp;
+ info->mMsnFtp = NULL;
+ }
+
+ if ( Appname != NULL && Appfile != NULL && Appfilesize != NULL ) { // receive first
+ filetransfer* ft = info->mMsnFtp = new filetransfer();
+
+ ft->mThreadId = info->mUniqueID;
+ ft->std.hContact = MSN_HContactFromEmail( email, nick, 1, 1 );
+ replaceStr( ft->std.currentFile, Appfile );
+ Utf8Decode( ft->std.currentFile, &ft->wszFileName );
+ ft->fileId = -1;
+ ft->std.currentFileSize = atol( Appfilesize );
+ ft->std.totalBytes = atol( Appfilesize );
+ ft->std.totalFiles = 1;
+ ft->szInvcookie = strdup( Invcookie );
+
+ int tFileNameLen = strlen( ft->std.currentFile );
+ char tComment[ 40 ];
+ int tCommentLen = mir_snprintf( tComment, sizeof( tComment ), "%lu bytes", ft->std.currentFileSize );
+ char* szBlob = ( char* )malloc( sizeof( DWORD ) + tFileNameLen + tCommentLen + 2 );
+ *( PDWORD )szBlob = ( DWORD )ft;
+ strcpy( szBlob + sizeof( DWORD ), ft->std.currentFile );
+ strcpy( szBlob + sizeof( DWORD ) + tFileNameLen + 1, tComment );
+
+ PROTORECVEVENT pre;
+ pre.flags = 0;
+ pre.timestamp = ( DWORD )time( NULL );
+ pre.szMessage = ( char* )szBlob;
+ pre.lParam = ( LPARAM )( char* )Invcookie;
+
+ CCSDATA ccs;
+ ccs.hContact = MSN_HContactFromEmail( email, nick, 1, 1 );
+ ccs.szProtoService = PSR_FILE;
+ ccs.wParam = 0;
+ ccs.lParam = ( LPARAM )&pre;
+ MSN_CallService( MS_PROTO_CHAINRECV, 0, ( LPARAM )&ccs );
+ return;
+ }
+
+ if ( IPAddress != NULL && Port != NULL && AuthCookie != NULL ) { // receive Second
+ ThreadData* newThread = new ThreadData;
+ strcpy( newThread->mServer, IPAddress );
+ strcat( newThread->mServer, ":" );
+ strcat( newThread->mServer, Port );
+ newThread->mType = SERVER_FILETRANS;
+
+ if ( info->mMsnFtp == NULL )
+ {
+ ThreadData* otherThread = MSN_GetOtherContactThread( info );
+ if ( otherThread )
+ {
+ info->mMsnFtp = otherThread->mMsnFtp;
+ otherThread->mMsnFtp = NULL;
+ }
+ }
+
+ newThread->mMsnFtp = info->mMsnFtp; info->mMsnFtp = NULL;
+ strcpy( newThread->mCookie, AuthCookie );
+
+ MSN_DebugLog( "Connecting to '%s'...", newThread->mServer );
+ newThread->startThread(( pThreadFunc )MSNServerThread );
+ return;
+ }
+
+ if ( Invcommand != NULL && Invcookie != NULL && Port == NULL && AuthCookie == NULL && SessionID == NULL ) { // send 1
+ ft_startFileSend( info, Invcommand, Invcookie );
+ return;
+ }
+
+ if ( Appname == NULL && SessionID != NULL && SessionProtocol != NULL ) { // netmeeting send 1
+ if ( !strcmpi( Invcommand,"ACCEPT" )) {
+ char ipaddr[256];
+ MSN_GetMyHostAsString( ipaddr, sizeof( ipaddr ));
+
+ ShellExecuteA(NULL, "open", "conf.exe", NULL, NULL, SW_SHOW);
+ Sleep(3000);
+
+ char command[ 1024 ];
+ int nBytes = mir_snprintf( command, sizeof( command ),
+ "MIME-Version: 1.0\r\n"
+ "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
+ "Invitation-Command: ACCEPT\r\n"
+ "Invitation-Cookie: %s\r\n"
+ "Session-ID: {1A879604-D1B8-11D7-9066-0003FF431510}\r\n"
+ "Launch-Application: TRUE\r\n"
+ "IP-Address: %s\r\n\r\n",
+ Invcookie, ipaddr);
+ info->sendPacket( "MSG", "N %d\r\n%s", nBytes, command );
+ }
+ return;
+ }
+
+ if ( Appname != NULL && !strcmpi( Appname,"NetMeeting" )) { // netmeeting receive 1
+ char command[ 1024 ];
+ int nBytes;
+
+ mir_snprintf( command, sizeof( command ), "Accept NetMeeting request from %s?", email );
+
+ if ( MessageBoxA( NULL, command, "MSN Protocol", MB_YESNO | MB_ICONQUESTION ) == IDYES ) {
+ char ipaddr[256];
+ MSN_GetMyHostAsString( ipaddr, sizeof( ipaddr ));
+
+ nBytes = mir_snprintf( command, sizeof( command ),
+ "MIME-Version: 1.0\r\n"
+ "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
+ "Invitation-Command: ACCEPT\r\n"
+ "Invitation-Cookie: %s\r\n"
+ "Session-ID: {A2ED5ACF-F784-4B47-A7D4-997CD8F643CC}\r\n"
+ "Session-Protocol: SM1\r\n"
+ "Launch-Application: TRUE\r\n"
+ "Request-Data: IP-Address:\r\n"
+ "IP-Address: %s\r\n\r\n",
+ Invcookie, ipaddr);
+ }
+ else {
+ nBytes = mir_snprintf( command, sizeof( command ),
+ "MIME-Version: 1.0\r\n"
+ "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
+ "Invitation-Command: CANCEL\r\n"
+ "Invitation-Cookie: %s\r\n"
+ "Cancel-Code: REJECT\r\n\r\n",
+ Invcookie);
+ }
+ info->sendPacket( "MSG", "N %d\r\n%s", nBytes, command );
+ return;
+ }
+
+ if ( IPAddress != NULL && Port == NULL && SessionID != NULL && SessionProtocol == NULL ) { // netmeeting receive 2
+ char ipaddr[256];
+ mir_snprintf( ipaddr, sizeof( ipaddr ), "callto://%s", IPAddress);
+ ShellExecuteA(NULL, "open", ipaddr, NULL, NULL, SW_SHOW);
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Processes any received MSG
+
+void MSN_ReceiveMessage( ThreadData* info, char* cmdString, char* params )
+{
+ union {
+ char* tWords[ 3 ];
+ struct { char *fromEmail, *fromNick, *strMsgBytes; } data;
+ };
+
+ if ( sttDivideWords( params, 3, tWords ) != 3 ) {
+ MSN_DebugLog( "Invalid %.3s command, ignoring", cmdString );
+ return;
+ }
+
+ int msgBytes = atol( data.strMsgBytes );
+
+ UrlDecode( data.fromEmail ); UrlDecode( data.fromNick );
+
+ char* msg = ( char* )alloca( msgBytes+1 );
+
+ int bytesFromData = min( info->mBytesInData, msgBytes );
+ memcpy( msg, info->mData, bytesFromData );
+ info->mBytesInData -= bytesFromData;
+ memmove( info->mData, info->mData + bytesFromData, info->mBytesInData );
+
+ while ( bytesFromData < msgBytes ) {
+ int recvResult;
+ recvResult = info->recv( msg + bytesFromData, msgBytes - bytesFromData );
+ if ( recvResult <= 0 )
+ return;
+
+ bytesFromData += recvResult;
+ }
+
+ msg[ msgBytes ] = 0;
+ MSN_DebugLog( "Message:\n%s", msg );
+
+ MimeHeaders tHeader;
+ const char* msgBody = tHeader.readFromBuffer( msg );
+
+ // message from the server (probably)
+ if (( strchr( data.fromEmail, '@' ) == NULL ) && strcmpi( data.fromEmail, "Hotmail" ))
+ return;
+
+ const char* tContentType = tHeader[ "Content-Type" ];
+ if ( tContentType == NULL )
+ return;
+
+ if ( !strnicmp( tContentType, "text/plain", 10 )) {
+ CCSDATA ccs;
+ HANDLE tContact = MSN_HContactFromEmail( data.fromEmail, data.fromNick, 1, 1 );
+
+ int isRtl = FALSE;
+ { const char* p = tHeader[ "X-MMS-IM-Format" ];
+ if ( p != NULL )
+ if ( strstr( p, "RL=1" ) != NULL )
+ isRtl = TRUE;
+ }
+
+ wchar_t* tRealBody = NULL;
+ int tRealBodyLen = 0;
+ if ( strstr( tContentType, "charset=UTF-8" ))
+ { Utf8Decode(( char* )msgBody, &tRealBody );
+ tRealBodyLen = wcslen( tRealBody );
+ }
+ int tMsgBodyLen = strlen( msgBody );
+
+ char* tPrefix = NULL;
+ int tPrefixLen = 0;
+
+ if ( info->mJoinedCount > 1 && info->mJoinedContacts != NULL ) {
+ if ( msnHaveChatDll )
+ MSN_ChatStart( info );
+ else if ( info->mJoinedContacts[0] != tContact ) {
+ for ( int j=1; j < info->mJoinedCount; j++ ) {
+ if ( info->mJoinedContacts[j] == tContact ) {
+ char* tNickName = MSN_GetContactName( info->mJoinedContacts[j] );
+ tPrefixLen = strlen( tNickName )+2;
+ tPrefix = ( char* )alloca( tPrefixLen+1 );
+ strcpy( tPrefix, "<" );
+ strcat( tPrefix, tNickName );
+ strcat( tPrefix, "> " );
+ ccs.hContact = info->mJoinedContacts[ 0 ];
+ break;
+ } } }
+ }
+ else ccs.hContact = tContact;
+
+ int tMsgBufLen = tMsgBodyLen+1 + (tRealBodyLen+1)*sizeof( wchar_t ) + tPrefixLen*(sizeof( wchar_t )+1);
+ char* tMsgBuf = ( char* )alloca( tMsgBufLen );
+ char* p = tMsgBuf;
+
+ if ( tPrefixLen != 0 ) {
+ memcpy( p, tPrefix, tPrefixLen );
+ p += tPrefixLen;
+ }
+ strcpy( p, msgBody );
+ p += tMsgBodyLen+1;
+
+ if ( tPrefixLen != 0 ) {
+ MultiByteToWideChar( CP_ACP, 0, tPrefix, tPrefixLen, ( wchar_t* )p, tPrefixLen );
+ p += tPrefixLen*sizeof( wchar_t );
+ }
+ if ( tRealBodyLen != 0 ) {
+ memcpy( p, tRealBody, sizeof( wchar_t )*( tRealBodyLen+1 ));
+ free( tRealBody );
+ }
+
+ if ( info->mChatID[0] ) {
+ GCDEST gcd = {0};
+ GCEVENT gce = {0};
+
+ gcd.pszModule = msnProtocolName;
+ gcd.pszID = info->mChatID;
+ gcd.iType = GC_EVENT_MESSAGE;
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ gce.pszUID = data.fromEmail;
+ gce.pszNick = MSN_GetContactName(MSN_HContactFromEmail(data.fromEmail, NULL, 1, 1));
+ gce.time = time(NULL);
+ gce.bIsMe = FALSE;
+ gce.pszText = (char*)EscapeChatTags(tMsgBuf);
+ //gce.pszText = tMsgBuf;
+ gce.bAddToLog = TRUE;
+ MSN_CallService(MS_GC_EVENT, NULL, (LPARAM)&gce);
+ free(( void* )gce.pszText);
+ }
+ else {
+ PROTORECVEVENT pre;
+ pre.szMessage = ( char* )tMsgBuf;
+ pre.flags = PREF_UNICODE + (( isRtl ) ? PREF_RTL : 0);
+ pre.timestamp = ( DWORD )time(NULL);
+ pre.lParam = 0;
+
+ ccs.szProtoService = PSR_MESSAGE;
+ ccs.wParam = 0;
+ ccs.lParam = ( LPARAM )&pre;
+ MSN_CallService( MS_PROTO_CHAINRECV, 0, ( LPARAM )&ccs );
+ }
+ return;
+ }
+
+ if ( !strnicmp( tContentType, "text/x-msmsgsprofile", 20 )) {
+ MimeHeaders tFileInfo;
+ tFileInfo.readFromBuffer( msg );
+ replaceStr( sid, tFileInfo[ "sid" ] );
+ replaceStr( kv, tFileInfo[ "kv" ] );
+ replaceStr( MSPAuth, tFileInfo[ "MSPAuth" ] );
+ replaceStr( msnExternalIP, tFileInfo[ "ClientIP" ] );
+
+ if ( msnExternalIP != NULL && MSN_GetByte( "AutoGetHost", 1 ))
+ MSN_SetString( NULL, "YourHost", msnExternalIP );
+
+ return;
+ }
+
+ if ( !strnicmp( tContentType, "text/x-msmsgscontrol", 20 )) {
+ MimeHeaders tFileInfo;
+ tFileInfo.readFromBuffer( msg );
+
+ char* tTypingUser = NULL;
+
+ for ( int j=0; j < tFileInfo.mCount; j++ )
+ if ( !strcmpi( tFileInfo.mVals[ j ].name, "TypingUser" ))
+ tTypingUser = tFileInfo.mVals[ j ].value;
+
+ if ( tTypingUser != NULL && info->mChatID[0] == 0 ) {
+ char userNick[ 388 ];
+ strcpy( userNick, tTypingUser );
+
+ HANDLE hContact = MSN_HContactFromEmail( tTypingUser, userNick, 1, 0 );
+ if ( hContact != NULL )
+ strcpy( userNick, MSN_GetContactName( hContact ));
+
+ MSN_CallService( MS_PROTO_CONTACTISTYPING, WPARAM( hContact ), 5 );
+
+ if ( MSN_GetByte( "DisplayTyping", 0 ))
+ MSN_ShowPopup( userNick, MSN_Translate( "typing..." ), 0 );
+ }
+
+ return;
+ }
+
+ //WIZZ
+ if ( !strnicmp( tContentType, "text/x-msnmsgr-datacast", 23 )) {
+ CCSDATA ccs;
+ HANDLE tContact = MSN_HContactFromEmail( data.fromEmail, data.fromNick, 1, 1 );
+
+ wchar_t* tRealBody = NULL;
+ int tRealBodyLen = 0;
+ if ( strstr( tContentType, "charset=UTF-8" ))
+ { Utf8Decode(( char* )msgBody, &tRealBody );
+ tRealBodyLen = wcslen( tRealBody );
+ }
+ int tMsgBodyLen = strlen( msgBody );
+
+ char* tPrefix = NULL;
+ int tPrefixLen = 0;
+
+ if ( info->mJoinedCount > 1 && info->mJoinedContacts != NULL ) {
+ if ( msnHaveChatDll )
+ MSN_ChatStart( info );
+ else if ( info->mJoinedContacts[0] != tContact ) {
+ for ( int j=1; j < info->mJoinedCount; j++ ) {
+ if ( info->mJoinedContacts[j] == tContact ) {
+ char* tNickName = MSN_GetContactName( info->mJoinedContacts[j] );
+ tPrefixLen = strlen( tNickName )+2;
+ tPrefix = ( char* )alloca( tPrefixLen+1 );
+ strcpy( tPrefix, "<" );
+ strcat( tPrefix, tNickName );
+ strcat( tPrefix, "> " );
+ ccs.hContact = info->mJoinedContacts[ 0 ];
+ break;
+ } } }
+ }
+ else ccs.hContact = tContact;
+
+ int tMsgBufLen = tMsgBodyLen+1 + (tRealBodyLen+1)*sizeof( wchar_t ) + tPrefixLen*(sizeof( wchar_t )+1);
+ char* tMsgBuf = ( char* )alloca( tMsgBufLen );
+ char* p = tMsgBuf;
+
+ if ( tPrefixLen != 0 ) {
+ memcpy( p, tPrefix, tPrefixLen );
+ p += tPrefixLen;
+ }
+ strcpy( p, msgBody );
+ p += tMsgBodyLen+1;
+
+ if ( tPrefixLen != 0 ) {
+ MultiByteToWideChar( CP_ACP, 0, tPrefix, tPrefixLen, ( wchar_t* )p, tPrefixLen );
+ p += tPrefixLen*sizeof( wchar_t );
+ }
+ if ( tRealBodyLen != 0 ) {
+ memcpy( p, tRealBody, sizeof( wchar_t )*( tRealBodyLen+1 ));
+ free( tRealBody );
+ }
+
+ if( !strnicmp(tMsgBuf,"ID: 1",5))
+ NotifyEventHooks(hMSNNudge,(WPARAM) tContact,0);
+ return;
+ }
+
+ if ( !strnicmp( tContentType,"text/x-msmsgsemailnotification", 30 ))
+ sttNotificationMessage( msgBody, false );
+ else if ( !strnicmp( tContentType, "text/x-msmsgsinitialemailnotification", 37 ))
+ sttNotificationMessage( msgBody, true );
+ else if ( !strnicmp( tContentType, "text/x-msmsgsinitialmdatanotification", 37 ))
+ sttNotificationMessage( msgBody, true );
+ else if ( !strnicmp( tContentType, "text/x-msmsgsinvite", 19 ))
+ sttInviteMessage( info, msgBody, data.fromEmail, data.fromNick );
+ else if ( !strnicmp( tContentType, "application/x-msnmsgrp2p", 24 ))
+ p2p_processMsg( info, msgBody );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Process user addition
+
+HANDLE sttProcessAdd( int trid, int listId, char* userEmail, char* userNick )
+{
+ if ( trid == msnSearchID ) {
+ msnNsThread->sendPacket( "REM", "BL %s", userEmail );
+
+ PROTOSEARCHRESULT isr;
+ memset( &isr, 0, sizeof( isr ));
+ isr.cbSize = sizeof( isr );
+ isr.nick = userNick;
+ isr.email = userEmail;
+ MSN_SendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, ( HANDLE )msnSearchID, ( LPARAM )&isr );
+ MSN_SendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE )msnSearchID, 0 );
+
+ msnSearchID = -1;
+ return NULL;
+ }
+
+ UrlDecode( userEmail ); UrlDecode( userNick );
+ if ( !IsValidListCode( listId ))
+ return NULL;
+
+ HANDLE hContact = MSN_HContactFromEmail( userEmail, userNick, 1, 1 );
+ Utf8Decode( userNick );
+ int mask = Lists_Add( listId, userEmail, userNick );
+
+ if ( listId == LIST_RL && ( mask & ( LIST_FL+LIST_AL+LIST_BL )) == 0 )
+ MSN_AddAuthRequest( hContact, userEmail, userNick );
+
+ return hContact;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_HandleCommands - process commands from the server
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static bool sttIsSync = false;
+static int sttListNumber = 0;
+static HANDLE sttListedContact = NULL;
+static long sttListedContactMask;
+
+static void sttDeleteUnusedSetting( long mask, const char* settingName )
+{ if (( sttListedContactMask & mask ) == 0 )
+ DBDeleteContactSetting( sttListedContact, msnProtocolName, settingName );
+}
+
+static void sttProcessListedContactMask()
+{
+ if ( sttListedContact == NULL )
+ return;
+
+ sttDeleteUnusedSetting( 0x0001, "Phone" );
+ sttDeleteUnusedSetting( 0x0002, "CompanyPhone" );
+ sttDeleteUnusedSetting( 0x0004, "Cellular" );
+ sttDeleteUnusedSetting( 0x0008, "OnMobile" );
+ sttDeleteUnusedSetting( 0x0010, "OnMsnMobile" );
+}
+
+static bool sttAddGroup( char* params, bool isFromBoot )
+{
+ union {
+ char* tWords[ 2 ];
+ struct { char *grpName, *grpId; } data;
+ };
+
+ if ( sttDivideWords( params, 2, tWords ) != 2 )
+ return false;
+
+ UrlDecode( data.grpName );
+ MSN_AddGroup( data.grpName, data.grpId );
+ if ( hGroupAddEvent != NULL )
+ SetEvent( hGroupAddEvent );
+
+ int i;
+ char str[ 10 ];
+
+ for ( i=0; true; i++ ) {
+ ltoa( i, str, 10 );
+
+ DBVARIANT dbv;
+ if ( DBGetContactSettingStringUtf( NULL, "CListGroups", str, &dbv ))
+ break;
+
+ bool result = !stricmp( dbv.pszVal+1, data.grpName );
+ MSN_FreeVariant( &dbv );
+ if ( result ) {
+ MSN_SetGroupNumber( data.grpId, i );
+ return true;
+ } }
+
+ if ( isFromBoot ) {
+ MSN_SetGroupNumber( data.grpId, i );
+
+ if ( MyOptions.ManageServer ) {
+ char szNewName[ 128 ];
+ mir_snprintf( szNewName, sizeof szNewName, "%c%s", 1 | GROUPF_EXPANDED, data.grpName );
+ DBWriteContactSettingStringUtf( NULL, "CListGroups", str, szNewName );
+ CallService( MS_CLUI_GROUPADDED, i, 0 );
+ } }
+ return true;
+}
+
+static void sttSwapInt64( LONGLONG* parValue )
+{
+ BYTE* p = ( BYTE* )parValue;
+ for ( int i=0; i < 4; i++ ) {
+ BYTE temp = p[i];
+ p[i] = p[7-i];
+ p[7-i] = temp;
+} }
+
+int MSN_HandleCommands( ThreadData* info, char* cmdString )
+{
+ char* params = "";
+ int trid = -1;
+ sttIsSync = false;
+
+ if ( cmdString[3] ) {
+ if ( isdigit(( BYTE )cmdString[ 4 ] )) {
+ trid = strtol( cmdString+4, &params, 10 );
+ switch ( *params ) {
+ case ' ': case '\0': case '\t': case '\n':
+ while ( *params == ' ' || *params == '\t' )
+ params++;
+ break;
+
+ default: params = cmdString+4;
+ } }
+ else params = cmdString+4;
+ }
+ MSN_DebugLog("%S", cmdString);
+
+ if ( info->mType == SERVER_NOTIFICATION )
+ msnPingTimeout = msnPingTimeoutCurrent;
+
+ switch(( *( PDWORD )cmdString & 0x00FFFFFF ) | 0x20000000 )
+ {
+ case ' KCA': //********* ACK: section 8.7 Instant Messages
+ if ( info->mP2PInitTrid == trid ) {
+ info->mP2PInitTrid = 0;
+ p2p_sendFeedStart( info->mP2pSession, info );
+ info->mP2pSession = NULL;
+ }
+ else if ( info->mJoinedCount > 0 && MyOptions.SlowSend )
+ MSN_SendBroadcast( info->mJoinedContacts[0], ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, ( HANDLE )trid, 0 );
+ break;
+
+ case ' CDA': // ADC - MSN v10 addition command
+ {
+ char* tWords[ 10 ];
+ char *userNick = NULL, *userEmail = NULL, *userId = NULL, *groupId = NULL;
+ int nTerms = sttDivideWords( params, 10, tWords );
+ if ( nTerms < 2 )
+ goto LBL_InvalidCommand;
+
+ for ( int i=1; i < nTerms; i++ ) {
+ char* p = tWords[ i ];
+ if ( *p == 'F' && p[1] == '=' )
+ userNick = p+2;
+ else if ( *p == 'N' && p[1] == '=' )
+ userEmail = p+2;
+ else if ( *p == 'C' && p[1] == '=' )
+ userId = p+2;
+ else
+ groupId = p;
+ }
+
+ HANDLE hContact;
+ if ( userEmail == NULL ) {
+ if ( userId == NULL || groupId == NULL )
+ goto LBL_InvalidCommand;
+ hContact = MSN_HContactById( userId );
+ }
+ else {
+ if ( userNick == NULL )
+ userNick = userEmail;
+
+ int listId = Lists_NameToCode( tWords[0] );
+ hContact = sttProcessAdd( trid, listId, userEmail, userNick );
+ }
+
+ if ( hContact != NULL ) {
+ if ( userId != NULL ) MSN_SetString( hContact, "ID", userId );
+ if ( groupId != NULL ) MSN_SetString( hContact, "GroupID", groupId );
+ }
+ break;
+ }
+ case ' DDA': //********* ADD: section 7.8 List Modifications
+ {
+ union {
+ char* tWords[ 4 ];
+ struct { char *list, *serial, *userEmail, *userNick; } data;
+ };
+
+ if ( sttDivideWords( params, 4, tWords ) != 4 ) {
+LBL_InvalidCommand:
+ MSN_DebugLog( "Invalid %.3s command, ignoring", cmdString );
+ break;
+ }
+
+ sttProcessAdd( trid, Lists_NameToCode( data.list ), data.userEmail, data.userNick );
+ break;
+ }
+ case ' GDA': //********* ADG: group addition
+ if ( !sttAddGroup( params, false ))
+ goto LBL_InvalidCommand;
+ break;
+
+ case ' SNA': //********* ANS: section 8.4 Getting Invited to a Switchboard Session
+ if ( info->mJoinedCount == 1 ) {
+ MsgQueueEntry E;
+ HANDLE hContact = info->mJoinedContacts[0];
+ if ( MsgQueue_GetNext( hContact, E ) != 0 ) {
+ do {
+ if ( E.msgSize == 0 ) {
+ info->sendMessage( E.msgType, E.message, E.flags );
+ MSN_SendBroadcast( hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, ( HANDLE )E.seq, 0 );
+ }
+ else info->sendRawMessage( E.msgType, E.message, E.msgSize );
+
+ free( E.message );
+
+ if ( E.ft != NULL ) {
+ info->mMsnFtp = E.ft;
+ info->mMsnFtp->mOwnsThread = true;
+ }
+ }
+ while (MsgQueue_GetNext( hContact, E ) != 0 );
+
+ if ( MSN_GetByte( "EnableDeliveryPopup", 1 ))
+ MSN_ShowPopup( MSN_GetContactName( hContact ), MSN_Translate( "First message delivered" ), 0 );
+ } }
+
+ break;
+
+ case ' PLB': //********* BLP: section 7.6 List Retrieval And Property Management
+ {
+ union {
+ char* tWords[ 2 ];
+ struct { char *junk, *listName; } data;
+ };
+
+ if ( sttDivideWords( params, 2, tWords ) == 1 )
+ data.listName = data.junk;
+
+ msnOtherContactsBlocked = stricmp( data.listName, "BL" ) == 0;
+ break;
+ }
+ case ' RPB': //********* BPR:
+ {
+ char* tWords[ 2 ];
+ if ( sttDivideWords( params, 2, tWords ) != 2 )
+ goto LBL_InvalidCommand;
+
+ if ( sttListedContact != NULL ) {
+ UrlDecode( tWords[1] );
+ if ( !strcmp( tWords[0], "PHH" )) {
+ MSN_SetString( sttListedContact, "Phone", tWords[1] );
+ sttListedContactMask |= 0x0001;
+ }
+ else if ( !strcmp( tWords[0], "PHW" )) {
+ MSN_SetString( sttListedContact, "CompanyPhone", tWords[1] );
+ sttListedContactMask |= 0x0002;
+ }
+ else if ( !strcmp( tWords[0], "PHM" )) {
+ MSN_SetString( sttListedContact, "Cellular", tWords[1] );
+ sttListedContactMask |= 0x0004;
+ }
+ else if ( !strcmp( tWords[0], "MOB" )) {
+ MSN_SetString( sttListedContact, "OnMobile", tWords[1] );
+ sttListedContactMask |= 0x0008;
+ }
+ else if ( !strcmp( tWords[0], "MBE" )) {
+ MSN_SetString( sttListedContact, "OnMsnMobile", tWords[1] );
+ sttListedContactMask |= 0x0010;
+ } }
+ break;
+ }
+ case ' EYB': //********* BYE: section 8.5 Session Participant Changes
+ {
+ union {
+ char* tWords[ 2 ];
+ // modified for chat, orginally param2 = junk
+ // param 2: quit due to idle = "1", normal quit = nothing
+ struct { char *userEmail, *isIdle; } data;
+ };
+
+ sttDivideWords( params, 2, tWords );
+ UrlDecode( data.userEmail );
+
+ if ( MSN_GetByte( "EnableSessionPopup", 0 ))
+ MSN_ShowPopup( data.userEmail, MSN_Translate( "Contact left channel" ), 0 );
+
+ // modified for chat
+ if ( msnHaveChatDll ) {
+ GCDEST gcd = {0};
+ gcd.pszModule = msnProtocolName;
+ gcd.pszID = info->mChatID;
+ gcd.iType = GC_EVENT_QUIT;
+
+ GCEVENT gce = {0};
+ gce.cbSize = sizeof( GCEVENT );
+ gce.pDest = &gcd;
+ gce.pszNick = MSN_GetContactName( MSN_HContactFromEmail( data.userEmail, NULL, 1, 1 ));
+ gce.pszUID = data.userEmail;
+ gce.time = time( NULL );
+ gce.bIsMe = FALSE;
+ gce.bAddToLog = TRUE;
+ MSN_CallService( MS_GC_EVENT, NULL, ( LPARAM )&gce );
+ }
+
+ // in here, the first contact is the chat ID, starting from the second will be actual contact
+ // if only 1 person left in conversation
+ int personleft = MSN_ContactLeft( info, MSN_HContactFromEmail( data.userEmail, NULL, 0, 0 ));
+ // see if the session is quit due to idleness
+ if ( personleft == 1 && !lstrcmpA( data.isIdle, "1" ) ) {
+ GCDEST gcd = {0};
+ gcd.pszModule = msnProtocolName;
+ gcd.pszID = info->mChatID;
+ gcd.iType = GC_EVENT_INFORMATION;
+
+ GCEVENT gce = {0};
+ gce.cbSize = sizeof( GCEVENT );
+ gce.pDest = &gcd;
+ gce.bIsMe = FALSE;
+ gce.time = time(NULL);
+ gce.bAddToLog = TRUE;
+ gce.pszText = Translate("This conversation has been inactive, participants will be removed.");
+ MSN_CallService( MS_GC_EVENT, NULL, ( LPARAM )&gce );
+ gce.pszText = Translate("To resume the conversation, please quit this session and start a new chat session.");
+ MSN_CallService( MS_GC_EVENT, NULL, ( LPARAM )&gce );
+ }
+ else if ( personleft == 2 && lstrcmpA( data.isIdle, "1" ) ) {
+ if ( MessageBoxA( NULL, Translate( "There is only 1 person left in the chat, do you want to switch back to standard message window?"), Translate("MSN Chat"), MB_YESNO|MB_ICONQUESTION) == IDYES) {
+ // kill chat dlg and open srmm dialog
+ GCEVENT gce = {0};
+ GCDEST gcd = {0};
+ gce.cbSize = sizeof( GCEVENT );
+ gce.pDest = &gcd;
+
+ // a flag to let the kill function know what to do
+ // if the value is 1, then it'll open up the srmm window
+ info->mJoinedCount--;
+
+ gcd.pszModule = msnProtocolName;
+ gcd.pszID = info->mChatID;
+ gcd.iType = GC_EVENT_CONTROL;
+ MSN_CallService( MS_GC_EVENT, WINDOW_OFFLINE, ( LPARAM )&gce );
+ MSN_CallService( MS_GC_EVENT, WINDOW_TERMINATE, ( LPARAM )&gce );
+ } }
+ // this is not in chat session, quit the session when everyone left
+ else if ( personleft == 0 )
+ return 1; // die
+
+ break;
+ }
+ case ' LAC': //********* CAL: section 8.3 Inviting Users to a Switchboard Session
+ break;
+
+ case ' GHC': //********* CHG: section 7.7 Client States
+ {
+ int oldMode = msnStatusMode;
+ msnStatusMode = MSNStatusToMiranda( params );
+
+ MSN_SendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS,( HANDLE )oldMode, msnStatusMode );
+ MSN_DebugLog( "Status change acknowledged: %s", params );
+ break;
+ }
+ case ' LHC': //********* CHL: Query from Server on MSNP7
+ {
+ char authChallengeInfo[ 30 ];
+ if ( sscanf( params, "%30s", authChallengeInfo ) < 1 )
+ goto LBL_InvalidCommand;
+
+ //Digest it
+ DWORD md5hash[ 4 ];
+ MD5_CTX context;
+ MD5Init(&context);
+ MD5Update(&context, ( BYTE* )authChallengeInfo, strlen( authChallengeInfo ));
+ MD5Update(&context, ( BYTE* )msnProtChallenge, strlen( msnProtChallenge ));
+ MD5Final(( BYTE* )md5hash, &context);
+
+ if ( MyOptions.UseMSNP11 ) {
+ LONGLONG hash1 = *( LONGLONG* )&md5hash[0], hash2 = *( LONGLONG* )&md5hash[2];
+ size_t i;
+ for ( i=0; i < 4; i++ )
+ md5hash[i] &= 0x7FFFFFFF;
+
+ char chlString[128];
+ _snprintf( chlString, sizeof( chlString ), "%s%s00000000", authChallengeInfo, msnProductID );
+ chlString[ (strlen(authChallengeInfo)+strlen(msnProductID)+7) & 0xF8 ] = 0;
+
+ LONGLONG high=0, low=0, bskey=0;
+ int* chlStringArray = ( int* )chlString;
+ for ( i=0; i < strlen( chlString )/4; i += 2) {
+ LONGLONG temp = chlStringArray[i];
+
+ temp = (0x0E79A9C1 * temp) % 0x7FFFFFFF;
+ temp += high;
+ temp = md5hash[0] * temp + md5hash[1];
+ temp = temp % 0x7FFFFFFF;
+
+ high = chlStringArray[i + 1];
+ high = (high + temp) % 0x7FFFFFFF;
+ high = md5hash[2] * high + md5hash[3];
+ high = high % 0x7FFFFFFF;
+
+ low = low + high + temp;
+ }
+ high = (high + md5hash[1]) % 0x7FFFFFFF;
+ low = (low + md5hash[3]) % 0x7FFFFFFF;
+
+ LONGLONG key = (low << 32) + high;
+ sttSwapInt64( &key );
+ sttSwapInt64( &hash1 );
+ sttSwapInt64( &hash2 );
+
+ info->sendPacket( "QRY", "%s 32\r\n%016I64x%016I64x", msnProductID, hash1 ^ key, hash2 ^ key );
+ }
+ else info->sendPacket( "QRY", "%s 32\r\n%08x%08x%08x%08x", msnProductID,
+ htonl( md5hash[0] ), htonl( md5hash[1] ), htonl( md5hash[2] ), htonl( md5hash[3] ));
+ break;
+ }
+ case ' RVC': //********* CVR: MSNP8
+ {
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ MSN_GetStaticString( "e-mail", NULL, tEmail, sizeof( tEmail ));
+ info->sendPacket( "USR", "TWN I %s", tEmail );
+ break;
+ }
+ case ' NLF': //********* FLN: section 7.9 Notification Messages
+ { HANDLE hContact;
+ UrlDecode( params );
+ if (( hContact = MSN_HContactFromEmail( params, NULL, 0, 0 )) != NULL )
+ {
+ MSN_SetWord( hContact, "Status", ID_STATUS_OFFLINE );
+ MsgQueue_Clear( hContact );
+ }
+ break;
+ }
+ case ' CTG': //********* GTC: section 7.6 List Retrieval And Property Management
+ break;
+
+ case ' FNI': //********* INF: section 7.2 Server Policy Information
+ {
+ char security1[ 10 ];
+ //can be more security packages on the end, comma delimited
+ if ( sscanf( params, "%9s", security1 ) < 1 )
+ goto LBL_InvalidCommand;
+
+ //SEND USR I packet, section 7.3 Authentication
+ if ( !strcmp( security1, "MD5" )) {
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( !MSN_GetStaticString( "e-mail", NULL, tEmail, sizeof( tEmail )))
+ info->sendPacket( "USR", "MD5 I %s", tEmail );
+ else
+ info->sendPacket( "USR", "MD5 I " ); //this will fail, of course
+ }
+ else {
+ MSN_DebugLog( "Unknown security package '%s'", security1 );
+ if ( info->mType == SERVER_NOTIFICATION || info->mType == SERVER_DISPATCH ) {
+ MSN_SendBroadcast(NULL,ACKTYPE_LOGIN,ACKRESULT_FAILED,NULL,LOGINERR_WRONGPROTOCOL);
+ MSN_GoOffline();
+ }
+ return 1;
+ }
+ break;
+ }
+ case ' NLI':
+ case ' NLN': //********* ILN/NLN: section 7.9 Notification Messages
+ {
+ union {
+ char* tWords[ 5 ];
+ struct { char *userStatus, *userEmail, *userNick, *objid, *cmdstring; } data;
+ };
+
+ int tArgs = sttDivideWords( params, 5, tWords );
+ if ( tArgs < 3 )
+ goto LBL_InvalidCommand;
+
+ UrlDecode( data.userEmail ); UrlDecode( data.userNick );
+
+ HANDLE hContact = MSN_HContactFromEmail( data.userEmail, NULL, 0, 0 );
+ if ( hContact != NULL) {
+ // is there an uninitialized switchboard for this contact?
+ ThreadData* T = MSN_GetUnconnectedThread( hContact );
+ if ( T != NULL )
+ if ( hContact == T->mInitialContact )
+ T->sendPacket( "CAL", "%s", data.userEmail );
+
+ MSN_SetStringUtf( hContact, "Nick", data.userNick );
+ MSN_SetWord( hContact, "Status", ( WORD )MSNStatusToMiranda( data.userStatus ));
+// DBDeleteContactSetting( hContact, "CList", "StatusMsg" );
+ }
+
+ MSN_SetString( hContact, "MirVer", "" );
+
+ if ( tArgs > 3 && tArgs <= 5 ) {
+ UrlDecode( data.cmdstring );
+ DWORD dwValue = ( DWORD )atol( data.objid );
+ MSN_SetDword( hContact, "FlagBits", dwValue );
+ if ( dwValue & 0x200 )
+ MSN_SetString( hContact, "MirVer", "Webmessenger" );
+ else if ( dwValue == 1342177280 )
+ MSN_SetString( hContact, "MirVer", "Miranda IM 0.5.x" );
+ else if ( dwValue == 805306404 )
+ MSN_SetString( hContact, "MirVer", "Miranda IM 0.4.x" );
+ else if (( dwValue & 0x60000000 ) == 0x60000000 )
+ MSN_SetString( hContact, "MirVer", "MSN 8.x" );
+ else if (( dwValue & 0x50000000 ) == 0x50000000 )
+ MSN_SetString( hContact, "MirVer", "MSN 7.5" );
+ else if ( dwValue & 0x40000000 )
+ MSN_SetString( hContact, "MirVer", "MSN 7.0" );
+ else if (( dwValue & 0x30000000 ) == 0x30000000 )
+ MSN_SetString( hContact, "MirVer", "MSN 6.2" );
+ else if ( dwValue & 0x20000000 )
+ MSN_SetString( hContact, "MirVer", "MSN 6.1" );
+ else if ( dwValue & 0x10000000 )
+ MSN_SetString( hContact, "MirVer", "MSN 6.0" );
+ else
+ MSN_SetString( hContact, "MirVer", "MSN 4.x-5.x" );
+
+ if ( data.cmdstring[0] ) {
+ int temp_status = MSN_GetWord(hContact, "Status", ID_STATUS_OFFLINE);
+ if (temp_status == (WORD)ID_STATUS_OFFLINE)
+ MSN_SetWord( hContact, "Status", (WORD)ID_STATUS_INVISIBLE);
+ MSN_SetString( hContact, "PictContext", data.cmdstring );
+ if ( hContact != NULL ) {
+ char szSavedContext[ 256 ];
+ int result = MSN_GetStaticString( "PictSavedContext", hContact, szSavedContext, sizeof szSavedContext );
+ if ( result || strcmp( szSavedContext, data.cmdstring ))
+ MSN_SendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, NULL );
+ } }
+ else {
+ DBDeleteContactSetting( hContact, msnProtocolName, "PictContext" );
+ DBDeleteContactSetting( hContact, msnProtocolName, "PictSavedContext" );
+ MSN_SendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, NULL );
+ } }
+
+ break;
+ }
+ case ' ORI': //********* IRO: section 8.4 Getting Invited to a Switchboard Session
+ {
+ union {
+ char* tWords[ 4 ];
+ struct { char *strThisContact, *totalContacts, *userEmail, *userNick; } data;
+ };
+
+ if ( sttDivideWords( params, 4, tWords ) != 4 )
+ goto LBL_InvalidCommand;
+
+ UrlDecode( data.userEmail );
+ UrlDecode( data.userNick );
+
+ MSN_ContactJoined( info, MSN_HContactFromEmail( data.userEmail, data.userNick, 1, 1 ));
+
+ int thisContact = atol( data.strThisContact );
+ if ( thisContact != 1 ) {
+ char* tContactName = MSN_GetContactName( info->mJoinedContacts[0] );
+ Utf8Decode( data.userNick );
+
+ char multichatmsg[256];
+ mir_snprintf( multichatmsg, sizeof( multichatmsg ),
+ MSN_Translate( "%s (%s) has joined the chat with %s" ),
+ data.userNick, data.userEmail, tContactName );
+
+ MSN_ShowPopup( tContactName, multichatmsg, MSN_ALLOW_MSGBOX );
+ }
+
+ // only start the chat session after all the IRO messages has been recieved
+ if ( msnHaveChatDll && info->mJoinedCount > 1 && !lstrcmpA(data.strThisContact, data.totalContacts) ) {
+ if ( info->mChatID[0] == 0 )
+ MSN_ChatStart(info);
+ }
+
+ break;
+ }
+ case ' IOJ': //********* JOI: section 8.5 Session Participant Changes
+ {
+ union {
+ char* tWords[ 2 ];
+ struct { char *userEmail, *userNick; } data;
+ };
+
+ if ( sttDivideWords( params, 2, tWords ) != 2 )
+ goto LBL_InvalidCommand;
+
+ UrlDecode( data.userEmail ); UrlDecode( data.userNick );
+ HANDLE hContact = MSN_HContactFromEmail( data.userEmail, data.userNick, 1, 1 );
+
+ Utf8Decode( data.userNick );
+ MSN_DebugLog( "New contact in channel %s %s", data.userEmail, data.userNick );
+
+ info->mInitialContact = NULL;
+ info->mMessageCount = 0;
+
+ if ( MSN_ContactJoined( info, hContact ) == 1 ) {
+ MsgQueueEntry E;
+ if ( MsgQueue_GetNext( hContact, E ) != 0 ) {
+ do {
+ if ( E.msgSize == 0 ) {
+ info->sendMessage( E.msgType, E.message, E.flags );
+ MSN_SendBroadcast( hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, ( HANDLE )E.seq, 0 );
+ }
+ else info->sendRawMessage( E.msgType, E.message, E.msgSize );
+
+ free( E.message );
+
+ if ( E.ft != NULL ) {
+ info->mMsnFtp = E.ft;
+ info->mMsnFtp->mOwnsThread = true;
+ }
+ }
+ while (MsgQueue_GetNext( hContact, E ) != 0 );
+
+ if ( MSN_GetByte( "EnableDeliveryPopup", 1 ))
+ MSN_ShowPopup( MSN_GetContactName( hContact ), MSN_Translate( "First message delivered" ), 0 );
+ } }
+ else {
+ char* tContactName = MSN_GetContactName( info->mJoinedContacts[0] );
+
+ char multichatmsg[ 256 ];
+ mir_snprintf(
+ multichatmsg, sizeof( multichatmsg ),
+ MSN_Translate( "%s (%s) has joined the chat with %s" ),
+ data.userNick, data.userEmail, tContactName );
+
+ MSN_ShowPopup( tContactName, multichatmsg, MSN_ALLOW_MSGBOX );
+
+ if ( msnHaveChatDll ) {
+ GCDEST gcd = {0};
+ GCEVENT gce = {0};
+
+ gcd.pszModule = msnProtocolName;
+ gcd.pszID = info->mChatID;
+ gcd.iType = GC_EVENT_JOIN;
+
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ gce.pszNick = MSN_GetContactName( MSN_HContactFromEmail( data.userEmail, NULL, 1, 1 ));
+ gce.pszUID = data.userEmail;
+ gce.pszStatus = Translate( "Others" );
+ gce.time = time(NULL);
+ gce.bIsMe = FALSE;
+ gce.bAddToLog = TRUE;
+ MSN_CallService( MS_GC_EVENT, NULL, ( LPARAM )&gce );
+ } }
+ return 0;
+ }
+
+ case ' GSL': //********* LSG: lists existing groups
+ if ( !sttAddGroup( params, true ))
+ goto LBL_InvalidCommand;
+ break;
+
+ case ' TSL': //********* LST: section 7.6 List Retrieval And Property Management
+ {
+ int listId;
+ char *userEmail = NULL, *userNick = NULL, *userId = NULL, *groupId = NULL;
+
+ union {
+ char* tWords[ 10 ];
+ struct { char *userEmail, *userNick, *list, *groupid; } data;
+ };
+
+ int tNumTokens = sttDivideWords( params, 10, tWords );
+
+ if ( --sttListNumber == 0 )
+ MSN_SetServerStatus( msnDesiredStatus );
+
+ for ( int i=0; i < tNumTokens; i++ ) {
+ char* p = tWords[ i ];
+ if ( *p == 'N' && p[1] == '=' )
+ userEmail = p+2;
+ else if ( *p == 'F' && p[1] == '=' )
+ userNick = p+2;
+ else if ( *p == 'C' && p[1] == '=' )
+ userId = p+2;
+ else {
+ listId = atol( p );
+ if ( i < tNumTokens-1 )
+ groupId = tWords[i+1];
+ break;
+ } }
+
+ if ( userEmail == NULL )
+ goto LBL_InvalidCommand;
+
+ if ( userNick == NULL )
+ userNick = userEmail;
+
+ UrlDecode( userEmail ); UrlDecode( userNick );
+
+ if ( !IsValidListCode( listId ) || !strcmp( userEmail, "messenger@microsoft.com" ))
+ break;
+
+ // add user if it wasn't included into a contact list
+ sttProcessListedContactMask();
+ sttListedContact = MSN_HContactFromEmail( userEmail, userNick, 1, 0 );
+
+ Utf8Decode( userNick );
+ Lists_Add( listId, userEmail, userNick );
+
+ if (( listId & ( LIST_AL + LIST_BL + LIST_FL )) == LIST_BL ) {
+ DBDeleteContactSetting( sttListedContact, "CList", "NotOnList" );
+ DBWriteContactSettingByte( sttListedContact, "CList", "Hidden", 1 );
+ }
+
+ if ( listId & LIST_PL ) {
+ if ( !Lists_IsInList( LIST_RL, userEmail )) {
+ MSN_AddUser( sttListedContact, userEmail, LIST_PL + LIST_REMOVE );
+ MSN_AddUser( sttListedContact, userEmail, LIST_RL );
+ }
+
+ if (( listId & ( LIST_AL + LIST_BL + LIST_FL )) == 0 )
+ MSN_AddAuthRequest( sttListedContact, userEmail, userNick );
+ }
+
+ if ( listId & ( LIST_BL | LIST_AL )) {
+ WORD tApparentMode = MSN_GetWord( sttListedContact, "ApparentMode", 0 );
+ if (( listId & LIST_BL ) && tApparentMode == 0 )
+ MSN_SetWord( sttListedContact, "ApparentMode", ID_STATUS_OFFLINE );
+ else if (( listId & LIST_AL ) && tApparentMode != 0 )
+ MSN_SetWord( sttListedContact, "ApparentMode", 0 );
+ }
+
+ if ( sttListedContact != NULL ) {
+ if ( userId != NULL )
+ MSN_SetString( sttListedContact, "ID", userId );
+
+ if ( MyOptions.ManageServer ) {
+ if ( groupId != NULL ) {
+ char* p = strchr( groupId, ',' );
+ if ( p != NULL )
+ *p = 0;
+
+ MSN_SetString( sttListedContact, "GroupID", groupId );
+
+ if (( p = ( char* )MSN_GetGroupById( groupId )) != NULL ) {
+ DBVARIANT dbv;
+ if ( !DBGetContactSettingStringUtf( sttListedContact, "CList", "Group", &dbv )) {
+ if ( strcmp( dbv.pszVal, p ))
+ DBWriteContactSettingStringUtf( sttListedContact, "CList", "Group", p );
+ MSN_FreeVariant( &dbv );
+ }
+ else DBWriteContactSettingStringUtf( sttListedContact, "CList", "Group", p );
+ } }
+ else {
+ DBDeleteContactSetting( sttListedContact, "CList", "Group" );
+ DBDeleteContactSetting( sttListedContact, msnProtocolName, "GroupID" );
+ } } }
+ break;
+ }
+ case ' GSM': //********* MSG: sections 8.7 Instant Messages, 8.8 Receiving an Instant Message
+ MSN_ReceiveMessage( info, cmdString, params );
+ break;
+
+ case ' KAN': //********* NAK: section 8.7 Instant Messages
+ MSN_DebugLog( "Message send failed (trid=%d)", trid );
+ break;
+
+ case ' TON': //********* NOT: notification message
+ {
+ char* buffer = ( char* )alloca( trid+1 );
+ BYTE* p = HReadBuffer( info ).surelyRead( trid );
+ if ( p != NULL ) {
+ memcpy( buffer, p, trid );
+ buffer[ trid ] = 0;
+ }
+ else buffer[0] = 0;
+
+ MSN_DebugLog( "Notification message: %s", buffer );
+ break;
+ }
+ case ' TUO': //********* OUT: sections 7.10 Connection Close, 8.6 Leaving a Switchboard Session
+ if ( !stricmp( params, "OTH" )) {
+ MSN_SendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_OTHERLOCATION );
+ MSN_DebugLog( "You have been disconnected from the MSN server because you logged on from another location using the same MSN passport." );
+ }
+
+ if ( !stricmp( params, "MIG" )) // ignore it
+ break;
+
+ return 1;
+
+ case ' PRP': //********* PRP: user property
+ {
+ union {
+ char* tWords[ 2 ];
+ struct { char *name, *value; } data;
+ };
+
+ if ( sttDivideWords( params, 2, tWords ) != 2 )
+ goto LBL_InvalidCommand;
+
+ UrlDecode( data.value );
+ if ( !stricmp( data.name, "MFN" ))
+ if ( !sttIsSync || !MSN_GetByte( "NeverUpdateNickname", 0 ))
+ MSN_SetStringUtf( NULL, "Nick", data.value );
+ break;
+ }
+ case ' YRQ': //********* QRY:
+ sttProcessListedContactMask();
+ break;
+
+ case ' GNQ': //********* QNG: reply to PNG
+ msnPingTimeoutCurrent = msnPingTimeout = trid;
+ if ( msnGetInfoContact != NULL ) {
+ MSN_SendBroadcast( msnGetInfoContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, ( HANDLE )1, 0 );
+ msnGetInfoContact = NULL;
+ }
+ break;
+
+ case ' GER': //********* REG: rename group
+ {
+ union {
+ char* tWords[ 2 ];
+ struct { char *id, *groupName; } data;
+ };
+
+ if ( sttDivideWords( params, 2, tWords ) != 2 )
+ goto LBL_InvalidCommand;
+
+ UrlDecode( data.groupName );
+ MSN_SetGroupName( data.id, data.groupName );
+ break;
+ }
+ case ' MER': //********* REM: section 7.8 List Modifications
+ {
+ union {
+ char* tWords[ 3 ];
+ struct { char *list, *serial, *groupId; } data;
+ };
+
+ if ( sttDivideWords( params, 3, tWords ) == 3 ) { // remove from a group
+ HANDLE hContact = MSN_HContactById( data.serial );
+ if ( hContact != NULL )
+ DBDeleteContactSetting( hContact, msnProtocolName, "GroupID" );
+ }
+ else { // remove a user from a list
+ int listId = Lists_NameToCode( data.list );
+ if ( IsValidListCode( listId )) {
+ if ( listId == LIST_FL ) {
+ HANDLE hContact = MSN_HContactById( data.serial );
+ if ( hContact != NULL ) {
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( !MSN_GetStaticString( "e-mail", hContact, tEmail, sizeof tEmail ))
+ Lists_Remove( listId, tEmail );
+ } }
+ else {
+ UrlDecode( data.serial );
+ Lists_Remove( listId, data.serial );
+ } } }
+ break;
+ }
+ case ' GMR': //********* RMG: remove a group
+ {
+ MSN_DeleteGroup( params );
+ break;
+ }
+ case ' GNR': //********* RNG: section 8.4 Getting Invited to a Switchboard Session
+ //note: unusual message encoding: trid==sessionid
+ {
+ union {
+ char* tWords[ 5 ];
+ struct { char *newServer, *security, *authChallengeInfo, *callerEmail, *callerNick; } data;
+ };
+
+ if ( sttDivideWords( params, 5, tWords ) != 5 )
+ goto LBL_InvalidCommand;
+
+ UrlDecode( data.newServer ); UrlDecode( data.callerEmail );
+ UrlDecode( data.callerNick ); Utf8Decode( data.callerNick );
+
+ if ( strcmp( data.security, "CKI" )) {
+ MSN_DebugLog( "Unknown security package in RNG command: %s", data.security );
+ break;
+ }
+
+ ThreadData* newThread = new ThreadData;
+ strcpy( newThread->mServer, data.newServer );
+ newThread->mType = SERVER_SWITCHBOARD;
+ MSN_ContactJoined( newThread, MSN_HContactFromEmail( data.callerEmail, data.callerNick, false, true ));
+ mir_snprintf( newThread->mCookie, sizeof( newThread->mCookie ), "%s %d", data.authChallengeInfo, trid );
+
+ MSN_DebugLog( "Opening caller's switchboard server '%s'...", data.newServer );
+ newThread->startThread(( pThreadFunc )MSNServerThread );
+ break;
+ }
+ case ' PBS': //********* SBP: Server Property was changed
+ break;
+
+ case ' NYS': //********* SYN: section 7.5 Client User Property Synchronization
+ {
+ char* tWords[ 4 ];
+ if ( sttDivideWords( params, 4, tWords ) != 4 )
+ goto LBL_InvalidCommand;
+
+ Lists_Wipe();
+ sttIsSync = true;
+ if (( sttListNumber = atol( tWords[ 2 ] )) == 0 )
+ MSN_SetServerStatus( msnDesiredStatus );
+
+ sttListedContact = NULL;
+ tridUrlInbox = msnNsThread->sendPacket( "URL", "INBOX" );
+ tridUrlEdit = msnNsThread->sendPacket( "URL", "PROFILE 0x%04x", GetUserDefaultLCID() );
+ break;
+ }
+ case ' XBU': // UBX : MSNP11+ User Status Message
+ {
+ union {
+ char* tWords[ 2 ];
+ struct { char *email, *datalen; } data;
+ };
+
+ if ( sttDivideWords( params, 2, tWords ) != 2 )
+ goto LBL_InvalidCommand;
+
+ HANDLE hContact = MSN_HContactFromEmail( data.email, data.email, 0, 0 );
+ if ( hContact == NULL )
+ break;
+
+ int len = atol( data.datalen );
+ if ( len < 0 || len > 4000 )
+ goto LBL_InvalidCommand;
+
+ char* dataBuf = ( char* )alloca( len+1 ), *p = dataBuf;
+ BYTE* buff = HReadBuffer( info, 0 ).surelyRead( len );
+ if ( buff != NULL ) {
+ memcpy( dataBuf, buff, len );
+ dataBuf[ len ] = 0;
+ }
+ else dataBuf[0] = 0;
+
+ p = strstr( dataBuf, "<PSM>" );
+ if ( p ) {
+ p += 5;
+ char* p1 = strstr( p, "</PSM>" );
+ if ( p1 ) {
+ *p1 = 0;
+ if ( *p != 0 ) {
+ HtmlDecode( p );
+ DBWriteContactSettingStringUtf( hContact, "CList", "StatusMsg", p );
+ }
+ else DBDeleteContactSetting( hContact, "CList", "StatusMsg" );
+ } }
+ break;
+ }
+ case ' LRU':
+ {
+ union {
+ char* tWords[ 3 ];
+ struct { char *rru, *passport, *urlID; } data;
+ };
+
+ if ( sttDivideWords( params, 3, tWords ) != 3 )
+ goto LBL_InvalidCommand;
+
+ if ( trid == tridUrlInbox ) {
+ replaceStr( passport, data.passport );
+ replaceStr( rru, data.rru );
+ tridUrlInbox = -1;
+ }
+ else if ( trid == tridUrlEdit ) {
+ replaceStr( profileURL, data.rru );
+ tridUrlEdit = -1;
+ }
+ break;
+ }
+ case ' RSU': //********* USR: sections 7.3 Authentication, 8.2 Switchboard Connections and Authentication
+ if ( info->mType == SERVER_SWITCHBOARD ) { //(section 8.2)
+ union {
+ char* tWords[ 3 ];
+ struct { char *status, *userHandle, *friendlyName; } data;
+ };
+
+ if ( sttDivideWords( params, 3, tWords ) != 3 )
+ goto LBL_InvalidCommand;
+
+ UrlDecode( data.userHandle ); UrlDecode( data.friendlyName );
+ Utf8Decode( data.friendlyName );
+
+ if ( strcmp( data.status, "OK" )) {
+ MSN_DebugLog( "Unknown status to USR command (SB): '%s'", data.status );
+ break;
+ }
+
+ HANDLE hContact = MsgQueue_GetNextRecipient();
+ if ( hContact == NULL ) { //can happen if both parties send first message at the same time
+ MSN_DebugLog( "USR (SB) internal: thread created for no reason" );
+ info->sendPacket( "OUT", NULL );
+ break;
+ }
+
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( MSN_GetStaticString( "e-mail", hContact, tEmail, sizeof( tEmail ))) {
+ MSN_DebugLog( "USR (SB) internal: Contact is not MSN" );
+ info->sendPacket( "OUT", NULL );
+ break;
+ }
+
+ info->mInitialContact = hContact;
+ info->sendPacket( "CAL", "%s", tEmail );
+ }
+ else //dispatch or notification server (section 7.3)
+ {
+ union {
+ char* tWords[ 3 ];
+ struct { char *security, *sequence, *authChallengeInfo; } data;
+ };
+
+ if ( sttDivideWords( params, 3, tWords ) != 3 )
+ goto LBL_InvalidCommand;
+
+ if ( !strcmp( data.security, "TWN" )) {
+ char* tAuth;
+ if ( MSN_GetPassportAuth( data.authChallengeInfo, tAuth )) {
+ MSN_SendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD );
+ MSN_GoOffline();
+ return 1;
+ }
+
+ info->sendPacket( "USR", "TWN S %s", tAuth );
+ free( tAuth );
+ }
+ else if ( !strcmp( data.security, "OK" )) {
+ UrlDecode( tWords[1] ); UrlDecode( tWords[2] );
+
+ if ( MSN_GetByte( "NeverUpdateNickname", 0 )) {
+ DBVARIANT dbv;
+ if ( !DBGetContactSettingTString( NULL, msnProtocolName, "Nick", &dbv )) {
+ MSN_SendNicknameT( dbv.ptszVal );
+ MSN_FreeVariant( &dbv );
+ }
+ }
+ else MSN_SetStringUtf( NULL, "Nick", tWords[2] );
+
+ msnLoggedIn = true;
+ sttListNumber = 0;
+ info->sendPacket( "SYN", "0 0" );
+ }
+ else {
+ MSN_DebugLog( "Unknown security package '%s'", data.security );
+
+ if ( info->mType == SERVER_NOTIFICATION || info->mType == SERVER_DISPATCH ) {
+ MSN_SendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPROTOCOL );
+ MSN_GoOffline();
+ }
+
+ return 1;
+ } }
+ break;
+
+ case ' XUU': // UUX: MSNP11 addition
+ break;
+
+ case ' REV': //******** VER: section 7.1 Protocol Versioning
+ {
+ char protocol1[ 7 ];
+ if ( sscanf( params, "%6s", protocol1 ) < 1 )
+ goto LBL_InvalidCommand;
+
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( MSN_GetStaticString( "e-mail", NULL, tEmail, sizeof( tEmail ))) {
+ MSN_ShowError( "You must specify your e-mail in Options/Network/MSN" );
+ return 1;
+ }
+
+ if ( !strcmp( protocol1, "MSNP10" )) {
+ info->sendPacket( "CVR","0x0409 winnt 5.1 i386 MSNMSGR 6.2.0205 MSMSGS %s", tEmail );
+ msnProtChallenge = "Q1P7W2E4J9R8U3S5";
+ msnProductID = "msmsgs@msnmsgr.com";
+ }
+ else if ( !strcmp( protocol1, "MSNP11" )) {
+ info->sendPacket( "CVR","0x0409 winnt 5.1 i386 MSNMSGR 7.5.0311 MSMSGS %s", tEmail );
+ msnProtChallenge = "YMM8C_H7KCQ2S_KL";
+ msnProductID = "PROD0090YUAUV{2B";
+ }
+ else {
+ MSN_ShowError( "Server has requested an unknown protocol set (%s)", params );
+
+ if ( info->mType == SERVER_NOTIFICATION || info->mType == SERVER_DISPATCH ) {
+ MSN_SendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPROTOCOL );
+ MSN_GoOffline();
+ }
+
+ return 1;
+ }
+ break;
+ }
+ case ' RFX': //******** XFR: sections 7.4 Referral, 8.1 Referral to Switchboard
+ {
+ union {
+ char* tWords[ 4 ];
+ struct { char *type, *newServer, *security, *authChallengeInfo; } data;
+ };
+
+ int numWords = sttDivideWords( params, 4, tWords );
+ if ( numWords < 2 )
+ goto LBL_InvalidCommand;
+
+ if ( !strcmp( data.type, "NS" )) { //notification server
+ UrlDecode( data.newServer );
+ ThreadData* newThread = new ThreadData;
+ strcpy( newThread->mServer, data.newServer );
+ newThread->mType = SERVER_NOTIFICATION;
+ newThread->mTrid = info->mTrid;
+ newThread->mIsMainThread = true;
+ info->mIsMainThread = false;
+
+ MSN_DebugLog( "Switching to notification server '%s'...", data.newServer );
+ newThread->startThread(( pThreadFunc )MSNServerThread );
+ return 1; //kill the old thread
+ }
+
+ if ( !strcmp( data.type, "SB" )) { //switchboard server
+ UrlDecode( data.newServer );
+
+ if ( numWords < 4 )
+ goto LBL_InvalidCommand;
+
+ if ( strcmp( data.security, "CKI" )) {
+ MSN_DebugLog( "Unknown XFR SB security package '%s'", data.security );
+ break;
+ }
+
+ ThreadData* newThread = new ThreadData;
+ strcpy( newThread->mServer, data.newServer );
+ newThread->mType = SERVER_SWITCHBOARD;
+ newThread->mCaller = 1;
+ strcpy( newThread->mCookie, data.authChallengeInfo );
+
+ MSN_DebugLog( "Opening switchboard server '%s'...", data.newServer );
+ newThread->startThread(( pThreadFunc )MSNServerThread );
+ }
+ else MSN_DebugLog( "Unknown referral server: %s", data.type );
+ break;
+ }
+
+ default:
+ MSN_DebugLog( "Unrecognised message: %s", cmdString );
+ break;
+ }
+
+ info->mMessageCount++;
+ return 0;
+}
diff --git a/miranda-wine/protocols/MSN/msn_contact.cpp b/miranda-wine/protocols/MSN/msn_contact.cpp
new file mode 100644
index 0000000..af19333
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_contact.cpp
@@ -0,0 +1,74 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "msn_global.h"
+
+HANDLE __stdcall MSN_HContactFromEmail( const char* msnEmail, const char* msnNick, int addIfNeeded, int temporary )
+{
+ HANDLE hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL )
+ {
+ char* szProto = ( char* )MSN_CallService( MS_PROTO_GETCONTACTBASEPROTO,( WPARAM )hContact, 0 );
+ if ( szProto != NULL && !strcmp( msnProtocolName, szProto )) {
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( !MSN_GetStaticString( "e-mail", hContact, tEmail, sizeof( tEmail )))
+ if ( !strcmpi( msnEmail, tEmail ))
+ return hContact;
+ }
+
+ hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM )hContact, 0 );
+ }
+
+ if ( addIfNeeded )
+ {
+ hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_ADD, 0, 0 );
+ MSN_CallService( MS_PROTO_ADDTOCONTACT, ( WPARAM )hContact, ( LPARAM )msnProtocolName );
+ MSN_SetString( hContact, "e-mail", msnEmail );
+ MSN_SetStringUtf( hContact, "Nick", ( char* )msnNick );
+ if ( temporary )
+ DBWriteContactSettingByte( hContact, "CList", "NotOnList", 1 );
+
+ return hContact;
+ }
+
+ return NULL;
+}
+
+HANDLE __stdcall MSN_HContactById( const char* szGuid )
+{
+ HANDLE hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL )
+ {
+ char* szProto = ( char* )MSN_CallService( MS_PROTO_GETCONTACTBASEPROTO,( WPARAM )hContact, 0 );
+ if ( szProto != NULL && !strcmp( msnProtocolName, szProto )) {
+ char tId[ 100 ];
+ if ( !MSN_GetStaticString( "ID", hContact, tId, sizeof tId ))
+ if ( !strcmpi( szGuid, tId ))
+ return hContact;
+ }
+
+ hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM )hContact, 0 );
+ }
+
+ return NULL;
+}
diff --git a/miranda-wine/protocols/MSN/msn_errors.cpp b/miranda-wine/protocols/MSN/msn_errors.cpp
new file mode 100644
index 0000000..af6c674
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_errors.cpp
@@ -0,0 +1,95 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "msn_global.h"
+
+extern int tridUrlInbox, tridUrlEdit;
+
+int MSN_HandleErrors( ThreadData* info, char* cmdString )
+{
+ int errorCode, packetID = -1;
+ sscanf( cmdString, "%d %d", &errorCode, &packetID );
+
+ if ( packetID == msnSearchID )
+ {
+ MSN_SendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)msnSearchID, 0 );
+ msnSearchID = -1;
+ }
+
+ MSN_DebugLog( "Server error:%s", cmdString );
+
+ switch( errorCode ) {
+ case ERR_INTERNAL_SERVER:
+ MSN_ShowError( "MSN Services are temporarily unavailable, please try to connect later" );
+ MSN_SendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NOSERVER );
+ return 1;
+
+ case ERR_SERVER_UNAVAILABLE:
+ MSN_ShowError( "MSN Services are too busy, please try to connect later" );
+ MSN_SendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NOSERVER );
+ return 1;
+
+ case ERR_NOT_ALLOWED_WHEN_OFFLINE:
+ MSN_ShowError( "MSN protocol does not allow you to communicate with others when you are invisible" );
+ return 0;
+
+ case ERR_LIST_FULL:
+ MSN_ShowError( "MSN plugin cannot add a new contact because the contact list is full" );
+ return 0;
+
+ case ERR_ALREADY_THERE:
+ MSN_ShowError( "User is already in your contact list" );
+ return 0;
+
+ case ERR_NOT_EXPECTED:
+ MSN_ShowError( "Your MSN account e-mail is unverified. Goto http://www.passport.com and verify the primary e-mail first" );
+ return 0;
+
+ case ERR_AUTHENTICATION_FAILED:
+ if ( info->mType != SERVER_SWITCHBOARD ) {
+ MSN_ShowError( "Your username or password is incorrect" );
+ MSN_SendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD );
+ }
+ return 1;
+
+ case 710:
+ if ( packetID == tridUrlInbox ) {
+ tridUrlInbox = -1;
+ return 0;
+ }
+
+ if ( packetID == tridUrlEdit ) {
+ tridUrlEdit = -1;
+ return 0;
+ }
+ // fall through
+
+ default:
+ MSN_DebugLog( "Unprocessed error: %s", cmdString );
+ if ( errorCode >= 500 ) //all these errors look fatal-ish
+ MSN_ShowError( "Unrecognised error %d. The server has closed our connection", errorCode );
+
+ break;
+ }
+ return 0;
+}
diff --git a/miranda-wine/protocols/MSN/msn_ftold.cpp b/miranda-wine/protocols/MSN/msn_ftold.cpp
new file mode 100644
index 0000000..24f6d82
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_ftold.cpp
@@ -0,0 +1,347 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "msn_global.h"
+
+#include <io.h>
+
+int MSN_HandleCommands(ThreadData *info,char *cmdString);
+int MSN_HandleErrors(ThreadData *info,char *cmdString);
+
+void msnftp_sendAcceptReject( filetransfer *ft, bool acc )
+{
+ ThreadData* thread = MSN_GetThreadByContact( ft->std.hContact );
+ if ( thread == NULL ) return;
+
+ if ( acc )
+ {
+ thread->sendPacket( "MSG",
+ "U %d\r\nMIME-Version: 1.0\r\n"
+ "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
+ "Invitation-Command: ACCEPT\r\n"
+ "Invitation-Cookie: %s\r\n"
+ "Launch-Application: FALSE\r\n"
+ "Request-Data: IP-Address:\r\n\r\n",
+ 172+4+strlen( ft->szInvcookie ), ft->szInvcookie );
+ }
+ else
+ {
+ thread->sendPacket( "MSG",
+ "U %d\r\nMIME-Version: 1.0\r\n"
+ "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
+ "Invitation-Command: CANCEL\r\n"
+ "Invitation-Cookie: %s\r\n"
+ "Cancel-Code: REJECT\r\n\r\n",
+ 172-33+4+strlen( ft->szInvcookie ), ft->szInvcookie );
+ }
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN File Transfer Protocol commands processing
+
+int MSN_HandleMSNFTP( ThreadData *info, char *cmdString )
+{
+ char* params = "";
+ filetransfer* ft = info->mMsnFtp;
+
+ if ( cmdString[ 3 ] )
+ params = cmdString+4;
+
+ switch((*(PDWORD)cmdString&0x00FFFFFF)|0x20000000)
+ {
+ case ' EYB': //********* BYE
+ {
+ ft->complete();
+ return 1;
+ }
+ case ' LIF': //********* FIL
+ {
+ char filesize[ 30 ];
+ if ( sscanf( params, "%s", filesize ) < 1 )
+ goto LBL_InvalidCommand;
+
+ info->mCaller = 1;
+ info->send( "TFR\r\n", 5 );
+ break;
+ }
+ case ' RFT': //********* TFR
+ {
+ char* sendpacket = ( char* )alloca( 2048 );
+ filetransfer* ft = info->mMsnFtp;
+
+ info->mCaller = 3;
+
+ while( ft->std.currentFileProgress < ft->std.currentFileSize )
+ {
+ if ( ft->bCanceled ) {
+ sendpacket[0] = 0x01;
+ sendpacket[1] = 0x00;
+ sendpacket[2] = 0x00;
+ info->send( sendpacket, 3 );
+ return 0;
+ }
+
+ int wPlace = 0;
+ sendpacket[ wPlace++ ] = 0x00;
+ int packetLen = ft->std.currentFileSize - ft->std.currentFileProgress;
+ if ( packetLen > 2045 )
+ packetLen = 2045;
+
+ sendpacket[ wPlace++ ] = packetLen & 0x00ff;
+ sendpacket[ wPlace++ ] = ( packetLen & 0xff00 ) >> 8;
+ _read( ft->fileId, &sendpacket[wPlace], packetLen );
+
+ info->send( &sendpacket[0], packetLen+3 );
+
+ ft->std.totalProgress += packetLen;
+ ft->std.currentFileProgress += packetLen;
+
+ MSN_SendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, ( LPARAM )&ft->std );
+ }
+
+ ft->complete();
+ break;
+ }
+ case ' RSU': //********* USR
+ {
+ char email[130],authcookie[14];
+ if ( sscanf(params,"%129s %13s",email,authcookie) < 2 )
+ {
+ MSN_DebugLog( "Invalid USR OK command, ignoring" );
+ break;
+ }
+
+ char tCommand[ 30 ];
+ mir_snprintf( tCommand, sizeof( tCommand ), "FIL %i\r\n", info->mMsnFtp->std.totalBytes );
+ info->send( tCommand, strlen( tCommand ));
+ break;
+ }
+ case ' REV': //********* VER
+ {
+ char protocol1[ 7 ];
+ if ( sscanf( params, "%6s", protocol1 ) < 1 )
+ {
+LBL_InvalidCommand:
+ MSN_DebugLog( "Invalid %.3s command, ignoring", cmdString );
+ break;
+ }
+
+ if ( strcmp( protocol1, "MSNFTP" ) != 0 )
+ {
+ int tempInt;
+ int tFieldCount = sscanf( params, "%d %6s", &tempInt, protocol1 );
+ if ( tFieldCount != 2 || strcmp( protocol1, "MSNFTP" ) != 0 )
+ {
+ MSN_DebugLog( "Another side requested the unknown protocol (%s), closing thread", params );
+ return 1;
+ } }
+
+ { DBVARIANT dbv;
+ if ( !DBGetContactSetting( NULL, msnProtocolName, "e-mail", &dbv ))
+ {
+ if ( info->mCaller == 0 ) //receive
+ {
+ char tCommand[ MSN_MAX_EMAIL_LEN + 50 ];
+ mir_snprintf( tCommand, sizeof( tCommand ), "USR %s %s\r\n", dbv.pszVal, info->mCookie );
+ info->send( tCommand, strlen( tCommand ));
+ }
+ else if ( info->mCaller == 2 ) //send
+ {
+ static char sttCommand[] = "VER MSNFTP\r\n";
+ info->send( sttCommand, strlen( sttCommand ));
+ }
+
+ MSN_FreeVariant( &dbv );
+ } }
+ break;
+ }
+ default: // receiving file
+ {
+ HReadBuffer tBuf( info, int( cmdString - info->mData ));
+
+ while ( true )
+ {
+ if ( ft->bCanceled )
+ { info->send( "CCL\r\n", 5 );
+ ft->close();
+ return 1;
+ }
+
+ BYTE* p = tBuf.surelyRead( 3 );
+ if ( p == NULL ) {
+LBL_Error: ft->close();
+ MSN_ShowError( "file transfer is canceled by remote host" );
+ return 1;
+ }
+
+ BYTE tIsTransitionFinished = *p++;
+ WORD dataLen = *p++;
+ dataLen |= (*p++ << 8);
+
+ if ( tIsTransitionFinished ) {
+LBL_Success:
+ static char sttCommand[] = "BYE 16777989\r\n";
+ info->send( sttCommand, strlen( sttCommand ));
+ return 1;
+ }
+
+ p = tBuf.surelyRead( dataLen );
+ if ( p == NULL )
+ goto LBL_Error;
+
+ _write( ft->fileId, p, dataLen );
+ ft->std.totalProgress += dataLen;
+ ft->std.currentFileProgress += dataLen;
+
+ MSN_SendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, ( LPARAM )&ft->std );
+
+ if ( ft->std.currentFileProgress == ft->std.totalBytes ) {
+ ft->complete();
+ goto LBL_Success;
+ } } } }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// ft_startFileSend - sends a file using the old f/t protocol
+
+static void __cdecl sttSendFileThread( ThreadData* info )
+{
+ MSN_DebugLog( "Waiting for an incoming connection to '%s'...", info->mServer );
+
+ filetransfer* ft = info->mMsnFtp;
+
+ switch( WaitForSingleObject( ft->hWaitEvent, 60000 )) {
+ case WAIT_TIMEOUT:
+ case WAIT_FAILED:
+ MSN_DebugLog( "Incoming connection timed out, closing file transfer" );
+ return;
+ }
+
+ info->mBytesInData = 0;
+
+ while ( TRUE ) {
+ int recvResult = info->recv( info->mData+info->mBytesInData, 1000 - info->mBytesInData );
+ if ( recvResult == SOCKET_ERROR || !recvResult )
+ break;
+
+ info->mBytesInData += recvResult;
+
+ //pull off each line for parsing
+ if ( info->mCaller == 3 && info->mType == SERVER_FILETRANS ) {
+ if ( MSN_HandleMSNFTP( info, info->mData ))
+ break;
+ }
+ else { // info->mType!=SERVER_FILETRANS
+ while ( TRUE ) {
+ char* peol = strchr(info->mData,'\r');
+ if ( peol == NULL )
+ break;
+
+ if ( info->mBytesInData < peol - info->mData + 2 )
+ break; //wait for full line end
+
+ char msg[ sizeof(info->mData) ];
+ memcpy( msg, info->mData, peol - info->mData ); msg[ peol - info->mData ] = 0;
+ if ( *++peol != '\n' )
+ MSN_DebugLog( "Dodgy line ending to command: ignoring" );
+ else
+ peol++;
+
+ info->mBytesInData -= peol - info->mData;
+ memmove( info->mData, peol, info->mBytesInData );
+
+ MSN_DebugLog( "RECV:%s", msg );
+
+ if ( !isalnum(msg[0]) || !isalnum(msg[1]) || !isalnum(msg[2]) || (msg[3] && msg[3]!=' ')) {
+ MSN_DebugLog( "Invalid command name");
+ continue;
+ }
+
+ if ( MSN_HandleMSNFTP( info, msg ))
+ break;
+ } }
+
+ if ( info->mBytesInData == sizeof( info->mData )) {
+ MSN_DebugLog( "sizeof(data) is too small: the longest line won't fit" );
+ break;
+ } }
+
+ MSN_DebugLog( "Closing file transfer thread" );
+}
+
+void ft_startFileSend( ThreadData* info, const char* Invcommand, const char* Invcookie )
+{
+ if ( strcmpi( Invcommand,"ACCEPT" ))
+ return;
+
+ bool bHasError = false;
+ NETLIBBIND nlb = {0};
+ char ipaddr[256];
+
+ filetransfer* ft = info->mMsnFtp; info->mMsnFtp = NULL;
+ if ( ft != NULL ) {
+ if ( MSN_GetMyHostAsString( ipaddr, sizeof ipaddr ))
+ bHasError = true;
+ else {
+ nlb.cbSize = sizeof nlb;
+ nlb.pfnNewConnectionV2 = MSN_ConnectionProc;
+ nlb.wPort = 0; // Use user-specified incoming port ranges, if available
+ if (( ft->mIncomingBoundPort = ( HANDLE )MSN_CallService( MS_NETLIB_BINDPORT, ( WPARAM )hNetlibUser, ( LPARAM )&nlb)) == NULL ) {
+ MSN_DebugLog( "Unable to bind the port for incoming transfers" );
+ bHasError = true;
+ }
+ else ft->mIncomingPort = nlb.wPort;
+ } }
+ else bHasError = true;
+
+ char command[ 1024 ];
+ int nBytes = mir_snprintf( command, sizeof( command ),
+ "MIME-Version: 1.0\r\n"
+ "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
+ "Invitation-Command: %s\r\n"
+ "Invitation-Cookie: %s\r\n"
+ "IP-Address: %s\r\n"
+ "Port: %i\r\n"
+ "AuthCookie: %i\r\n"
+ "Launch-Application: FALSE\r\n"
+ "Request-Data: IP-Address:\r\n\r\n",
+ ( bHasError ) ? "CANCEL" : "ACCEPT",
+ Invcookie, ipaddr, nlb.wExPort, WORD((( double )rand() / ( double )RAND_MAX ) * 4294967295 ));
+ info->sendPacket( "MSG", "N %d\r\n%s", nBytes, command );
+
+ if ( bHasError ) {
+ delete ft;
+ return;
+ }
+
+ ft->hWaitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+
+ ThreadData* newThread = new ThreadData;
+ newThread->mType = SERVER_FILETRANS;
+ newThread->mCaller = 2;
+ newThread->mMsnFtp = ft;
+ newThread->startThread(( pThreadFunc )sttSendFileThread );
+}
diff --git a/miranda-wine/protocols/MSN/msn_global.h b/miranda-wine/protocols/MSN/msn_global.h
new file mode 100644
index 0000000..9e7e894
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_global.h
@@ -0,0 +1,641 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 <malloc.h>
+
+#if defined(UNICODE) && !defined(_UNICODE)
+ #define _UNICODE
+#endif
+
+#ifdef _DEBUG
+ #define _CRTDBG_MAP_ALLOC
+ #include <stdlib.h>
+ #include <crtdbg.h>
+#endif
+
+#define _WIN32_WINNT 0x0400
+#include <windows.h>
+#include <commctrl.h>
+
+#include <process.h>
+#include <stdio.h>
+#include <time.h>
+
+#include <newpluginapi.h>
+
+#include <m_clc.h>
+#include <m_clist.h>
+#include <m_clui.h>
+#include <m_message.h>
+#include <m_options.h>
+#include <m_png.h>
+#include <m_protocols.h>
+#include <m_protomod.h>
+#include <m_protosvc.h>
+#include <m_skin.h>
+#include <m_system.h>
+#include <m_userinfo.h>
+#include <m_utils.h>
+#include <win2k.h>
+
+#include <m_database.h>
+#include <m_langpack.h>
+#include <m_netlib.h>
+#include <m_popup.h>
+
+#include "SDK/m_chat.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN error codes
+
+#define ERR_SYNTAX_ERROR 200
+#define ERR_INVALID_PARAMETER 201
+#define ERR_INVALID_USER 205
+#define ERR_FQDN_MISSING 206
+#define ERR_ALREADY_LOGIN 207
+#define ERR_INVALID_USERNAME 208
+#define ERR_INVALID_FRIENDLY_NAME 209
+#define ERR_LIST_FULL 210
+#define ERR_ALREADY_THERE 215
+#define ERR_NOT_ON_LIST 216
+#define ERR_ALREADY_IN_THE_MODE 218
+#define ERR_ALREADY_IN_OPPOSITE_LIST 219
+#define ERR_SWITCHBOARD_FAILED 280
+#define ERR_NOTIFY_XFR_FAILED 281
+#define ERR_REQUIRED_FIELDS_MISSING 300
+#define ERR_NOT_LOGGED_IN 302
+#define ERR_INTERNAL_SERVER 500
+#define ERR_DB_SERVER 501
+#define ERR_FILE_OPERATION 510
+#define ERR_MEMORY_ALLOC 520
+#define ERR_SERVER_BUSY 600
+#define ERR_SERVER_UNAVAILABLE 601
+#define ERR_PEER_NS_DOWN 602
+#define ERR_DB_CONNECT 603
+#define ERR_SERVER_GOING_DOWN 604
+#define ERR_CREATE_CONNECTION 707
+#define ERR_BLOCKING_WRITE 711
+#define ERR_SESSION_OVERLOAD 712
+#define ERR_USER_TOO_ACTIVE 713
+#define ERR_TOO_MANY_SESSIONS 714
+#define ERR_NOT_EXPECTED 715
+#define ERR_BAD_FRIEND_FILE 717
+#define ERR_AUTHENTICATION_FAILED 911
+#define ERR_NOT_ALLOWED_WHEN_OFFLINE 913
+#define ERR_NOT_ACCEPTING_NEW_USERS 920
+#define ERR_EMAIL_ADDRESS_NOT_VERIFIED 924
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Global definitions
+
+#define MSN_MAX_EMAIL_LEN 128
+#define MSN_GUID_LEN 40
+
+#define MSN_DEFAULT_PORT 1863
+#define MSN_DEFAULT_LOGIN_SERVER "messenger.hotmail.com"
+#define MSN_DEFAULT_GATEWAY "gateway.messenger.hotmail.com"
+#define MSN_USER_AGENT "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"
+
+#define MSN_BLOCK "/BlockCommand"
+#define MSN_INVITE "/InviteCommand"
+#define MSN_NETMEETING "/NetMeeting"
+#define MSN_VIEW_PROFILE "/ViewProfile"
+#define MSN_SEND_NUDGE "/SendNudge"
+
+#define MENU_ITEMS_COUNT 2
+#define MS_GOTO_INBOX "/GotoInbox"
+#define MS_EDIT_PROFILE "/EditProfile"
+#define MS_SET_AVATAR "/SetAvatar"
+#define MS_VIEW_STATUS "/ViewMsnStatus"
+#define MS_SET_NICKNAME_UI "/SetNicknameUI"
+#define MS_SET_AVATAR_UI "/SetAvatarUI"
+
+#define MSN_SET_NICKNAME "/SetNickname"
+#define MSN_SET_AVATAR "/SetAvatar"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN plugin functions
+
+#define NEWSTR_ALLOCA(A) (A==NULL)?NULL:strcpy((char*)alloca(strlen(A)+1),A)
+
+#define MSN_ALLOW_MSGBOX 1
+#define MSN_ALLOW_ENTER 2
+#define MSN_HOTMAIL_POPUP 4
+#define MSN_SHOW_ERROR 8
+void __stdcall MSN_ShowPopup( const char* nickname, const char* msg, int flags );
+
+LONG __stdcall MSN_SendPacket( HANDLE, const char* cmd, const char* params, ... );
+char* __stdcall MirandaStatusToMSN( int status );
+int __stdcall MSNStatusToMiranda( const char* status );
+void __stdcall HtmlDecode( char* str );
+char* __stdcall HtmlEncode( const char* str );
+void __stdcall UrlDecode( char*str );
+void __stdcall UrlEncode( const char* src, char* dest, int cbDest );
+void __stdcall Utf8Decode( char* str, wchar_t** = NULL );
+char* __stdcall Utf8Encode( const char* src );
+char* __stdcall Utf8EncodeUcs2( const wchar_t* src );
+
+HANDLE __stdcall MSN_HContactFromEmail( const char* msnEmail, const char* msnNick, int addIfNeeded, int temporary );
+HANDLE __stdcall MSN_HContactById( const char* szGuid );
+
+int __stdcall MSN_AddContact( char* uhandle,char* nick ); //returns clist ID
+int __stdcall MSN_AddUser( HANDLE hContact, const char* email, int flags );
+void __stdcall MSN_AddAuthRequest( HANDLE hContact, const char *email, const char *nick );
+int __stdcall MSN_ContactFromHandle( char* uhandle ); //get cclist id from Uhandle
+void __stdcall MSN_DebugLog( const char* fmt, ... );
+void __stdcall MSN_DumpMemory( const char* buffer, int bufSize );
+void __stdcall MSN_HandleFromContact( unsigned long uin, char* uhandle );
+int __stdcall MSN_GetMyHostAsString( char* parBuf, int parBufSize );
+
+void __cdecl MSN_ConnectionProc( HANDLE hNewConnection, DWORD dwRemoteIP, void* );
+void __stdcall MSN_GoOffline( void );
+void __stdcall MSN_GetAvatarFileName( HANDLE hContact, char* pszDest, int cbLen );
+LPTSTR __stdcall MSN_GetErrorText( DWORD parErrorCode );
+void __stdcall MSN_SendStatusMessage( const char* msg );
+void __stdcall MSN_SetServerStatus( int newStatus );
+char* __stdcall MSN_StoreLen( char* dest, char* last );
+void __stdcall LoadOptions( void );
+
+int __stdcall MSN_SendNickname(char *nickname);
+#if defined( _UNICODE )
+ int __stdcall MSN_SendNicknameW( WCHAR* nickname);
+ #define MSN_SendNicknameT MSN_SendNicknameW
+#else
+ #define MSN_SendNicknameT MSN_SendNickname
+#endif
+
+#if defined( _DEBUG )
+#define MSN_CallService CallService
+#else
+int __stdcall MSN_CallService( const char* szSvcName, WPARAM wParam, LPARAM lParam );
+#endif
+
+HANDLE __stdcall MSN_CreateProtoServiceFunction( const char*, MIRANDASERVICE );
+void __stdcall MSN_EnableMenuItems( BOOL );
+void __fastcall MSN_FreeVariant( DBVARIANT* dbv );
+char* __stdcall MSN_GetContactName( HANDLE hContact );
+TCHAR* __stdcall MSN_GetContactNameT( HANDLE hContact );
+DWORD __stdcall MSN_GetDword( HANDLE hContact, const char* valueName, DWORD parDefltValue );
+DWORD __stdcall MSN_GetByte( const char* valueName, int parDefltValue );
+int __stdcall MSN_GetStaticString( const char* valueName, HANDLE hContact, char* dest, int dest_len );
+WORD __stdcall MSN_GetWord( HANDLE hContact, const char* valueName, int parDefltValue );
+int __stdcall MSN_SendBroadcast( HANDLE hContact, int type, int result, HANDLE hProcess, LPARAM lParam );
+DWORD __stdcall MSN_SetByte( const char* valueName, int parValue );
+DWORD __stdcall MSN_SetDword( HANDLE hContact, const char* valueName, DWORD parValue );
+DWORD __stdcall MSN_SetWord( HANDLE hContact, const char* valueName, int parValue );
+DWORD __stdcall MSN_SetString( HANDLE hContact, const char* valueName, const char* parValue );
+DWORD __stdcall MSN_SetStringT( HANDLE hContact, const char* valueName, const TCHAR* parValue );
+DWORD __stdcall MSN_SetStringUtf( HANDLE hContact, const char* valueName, char* parValue );
+void __cdecl MSN_ShowError( const char* msgtext, ... );
+char* __stdcall MSN_Translate( const char* str );
+
+int __stdcall MSN_EnterBitmapFileName( char* szDest );
+int __stdcall MSN_SaveBitmapAsAvatar( HBITMAP hBitmap, const char* szFileName );
+HBITMAP __stdcall MSN_StretchBitmap( HBITMAP hBitmap );
+
+char* EscapeChatTags(char* pszText);
+char* UnEscapeChatTags(char* str_in);
+
+VOID CALLBACK MSNMainTimerProc( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime );
+LRESULT CALLBACK NullWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+DWORD WINAPI MsnShowMailThread( LPVOID );
+
+int IsWinver( void );
+
+void replaceStr( char*& dest, const char* src );
+char* rtrim( char *string );
+void strdel( char* parBuffer, int len );
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// PNG library interface
+
+BOOL __stdcall MSN_LoadPngModule( void );
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MIME headers processing
+
+struct MimeHeader
+{
+ char* name;
+ char* value;
+};
+
+struct MimeHeaders
+{
+ MimeHeaders();
+ MimeHeaders( int );
+ ~MimeHeaders();
+
+ const char* readFromBuffer( const char* pSrc );
+ const char* operator[]( const char* fieldName );
+
+ void addString( const char* name, const char* szValue );
+ void addLong( const char* name, long lValue );
+
+ int getLength( void );
+ char* writeToBuffer( char* pDest );
+
+ int mCount;
+ MimeHeader* mVals;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// File transfer helper
+
+struct ThreadData;
+
+struct P2P_Header
+{
+ DWORD mSessionID;
+ DWORD mID;
+ __int64 mOffset;
+ __int64 mTotalSize;
+ DWORD mPacketLen;
+ DWORD mFlags;
+ DWORD mAckSessionID;
+ DWORD mAckUniqueID;
+ __int64 mAckDataSize;
+};
+
+struct HReadBuffer
+{
+ HReadBuffer( ThreadData* info, int iStart = 0 );
+ ~HReadBuffer();
+
+ BYTE* surelyRead( int parBytes );
+
+ ThreadData* owner;
+ BYTE* buffer;
+ int totalDataSize;
+ int startOffset;
+};
+
+struct filetransfer
+{
+ filetransfer();
+ ~filetransfer( void );
+
+ void close();
+ void complete();
+ int create();
+
+ PROTOFILETRANSFERSTATUS std;
+
+ bool bCanceled; // flag to interrupt a transfer
+ bool bCompleted; // was a FT ever completed?
+ bool inmemTransfer; // flag: the file being received is to be stored in memory
+
+ union {
+ int fileId; // handle of file being transferring (r/w)
+ char* fileBuffer; // buffer of memory to handle the file
+ };
+
+ bool mOwnsThread, // thread was created specifically for that file transfer
+ mIsFirst; // set for the first transfer for a contact
+ LONG mThreadId; // unique id of the parent thread
+
+ WORD mIncomingPort;
+ HANDLE mIncomingBoundPort;
+ HANDLE hWaitEvent;
+
+ unsigned p2p_sessionid; // session id
+ unsigned p2p_msgid; // message id
+ unsigned p2p_acksessid; // acknowledged session id
+ unsigned p2p_sendmsgid; // send message id
+ unsigned p2p_byemsgid; // bye message id
+ unsigned p2p_ackID; // number of ack's state
+ unsigned p2p_appID; // application id: 1 = avatar, 2 = file transfer
+ char* p2p_branch; // header Branch: field
+ char* p2p_callID; // header Call-ID: field
+ char* p2p_dest; // destination e-mail address
+
+ //---- receiving a file
+ wchar_t* wszFileName; // file name in Unicode, for receiving
+ char* szInvcookie; // cookie for receiving
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Thread handling functions and datatypes
+
+#define MAX_THREAD_COUNT 64
+
+typedef void ( __cdecl* pThreadFunc )( void* );
+
+enum TInfoType
+{
+ SERVER_DISPATCH,
+ SERVER_NOTIFICATION,
+ SERVER_SWITCHBOARD,
+ SERVER_FILETRANS,
+ SERVER_P2P_DIRECT
+};
+
+struct TQueueItem
+{
+ TQueueItem* next;
+ int datalen;
+ char data[1];
+};
+
+#define MSG_DISABLE_HDR 1
+#define MSG_REQUIRE_ACK 2
+#define MSG_RTL 4
+
+struct ThreadData
+{
+ ThreadData();
+ ~ThreadData();
+
+ TInfoType mType; // thread type
+ char mServer[80]; // server name
+ LONG mUniqueID; // unique thread ID
+
+ HANDLE s; // NetLib connection for the thread
+ char mChatID[10];
+ bool mIsMainThread;
+ int mWaitPeriod;
+
+ //----| for gateways |----------------------------------------------------------------
+ char mSessionID[ 50 ]; // Gateway session ID
+ char mGatewayIP[ 80 ]; // Gateway IP address
+ int mGatewayTimeout;
+ char* mReadAheadBuffer;
+ int mEhoughData;
+ TQueueItem* mFirstQueueItem;
+
+ //----| for switchboard servers only |------------------------------------------------
+ int mCaller;
+ char mCookie[130]; // for switchboard servers only
+ HANDLE mInitialContact; // initial switchboard contact
+ HANDLE* mJoinedContacts; // another contacts
+ int mJoinedCount; // another contacts count
+ int mMessageCount; // message counter
+ LONG mTrid; // current message ID
+ bool mIsCalSent; // is CAL already sent?
+
+ //----| for file transfers only |-----------------------------------------------------
+ filetransfer* mMsnFtp; // file transfer block
+ filetransfer* mP2pSession; // new styled transfer
+ ThreadData* mParentThread; // thread that began the f/t
+ LONG mP2PInitTrid;
+
+ //----| internal data buffer |--------------------------------------------------------
+ int mBytesInData; // bytes available in data buffer
+ char mData[4096]; // data buffer for connection
+
+ //----| methods |---------------------------------------------------------------------
+ void applyGatewayData( HANDLE hConn, bool isPoll );
+ void getGatewayUrl( char* dest, int destlen, bool isPoll );
+ void processSessionData( const char* );
+ void startThread( pThreadFunc );
+
+ int send( char* data, int datalen );
+ int recv( char* data, long datalen );
+ int recv_dg( char* data, long datalen );
+
+ LONG sendMessage( int msgType, const char* msg, int parFlags );
+ LONG sendRawMessage( int msgType, const char* data, int datLen );
+ LONG sendPacket( const char* cmd, const char* fmt, ... );
+};
+
+void __stdcall MSN_CloseConnections( void );
+void __stdcall MSN_CloseThreads( void );
+int __stdcall MSN_ContactJoined( ThreadData* parInfo, HANDLE hContact );
+int __stdcall MSN_ContactLeft( ThreadData* parInfo, HANDLE hContact );
+void __stdcall MSN_InitThreads( void );
+int __stdcall MSN_GetChatThreads( ThreadData** parResult );
+int __stdcall MSN_GetActiveThreads( ThreadData** );
+ThreadData* __stdcall MSN_GetThreadByConnection( HANDLE hConn );
+ThreadData* __stdcall MSN_GetThreadByContact( HANDLE hContact );
+ThreadData* __stdcall MSN_GetThreadByPort( WORD wPort );
+ThreadData* __stdcall MSN_GetUnconnectedThread( HANDLE hContact );
+ThreadData* __stdcall MSN_GetThreadByID( LONG id );
+ThreadData* __stdcall MSN_GetOtherContactThread( ThreadData* thread );
+void __stdcall MSN_PingParentThread( ThreadData*, filetransfer* ft );
+void __stdcall MSN_StartThread( pThreadFunc parFunc, void* arg );
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN P2P session support
+
+#define MSN_APPID_AVATAR 1
+#define MSN_APPID_FILE 2
+
+void __stdcall p2p_ackOtherFiles( ThreadData* info );
+void __stdcall p2p_invite( HANDLE hContact, int iAppID, filetransfer* ft = NULL );
+void __stdcall p2p_processMsg( ThreadData* info, const char* msgbody );
+void __stdcall p2p_sendAck( filetransfer* ft, ThreadData* info, P2P_Header* hdrdata );
+void __stdcall p2p_sendStatus( filetransfer* ft, ThreadData* info, long lStatus );
+void __stdcall p2p_sendBye( ThreadData* info, filetransfer* ft );
+void __stdcall p2p_sendCancel( ThreadData* info, filetransfer* ft );
+
+void __stdcall p2p_sendFeedStart( filetransfer* ft, ThreadData* T );
+long __stdcall p2p_sendPortion( filetransfer* ft, ThreadData* T );
+
+void __stdcall p2p_registerSession( filetransfer* ft );
+void __stdcall p2p_unregisterSession( filetransfer* ft );
+void __stdcall p2p_unregisterThreadSession( LONG threadID );
+
+filetransfer* __stdcall p2p_getAnotherContactSession( filetransfer* ft );
+filetransfer* __stdcall p2p_getFirstSession( HANDLE hContact );
+filetransfer* __stdcall p2p_getSessionByID( unsigned ID );
+filetransfer* __stdcall p2p_getSessionByMsgID( unsigned ID );
+filetransfer* __stdcall p2p_getSessionByCallID( const char* CallID );
+
+BOOL __stdcall p2p_sessionRegistered( filetransfer* ft );
+
+void ft_startFileSend( ThreadData* info, const char* Invcommand, const char* Invcookie );
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Message queue
+
+#define MSGQUE_RAW 1
+
+struct MsgQueueEntry
+{
+ HANDLE hContact;
+ char* message;
+ int msgType;
+ int msgSize;
+ filetransfer* ft;
+ int seq;
+ int allocatedToThread;
+ int timeout;
+ int flags;
+};
+
+int __stdcall MsgQueue_Add( HANDLE hContact, int msgType, const char* msg, int msglen, filetransfer* ft = NULL, int flags = 0 );
+HANDLE __stdcall MsgQueue_CheckContact( HANDLE hContact );
+HANDLE __stdcall MsgQueue_GetNextRecipient( void );
+int __stdcall MsgQueue_GetNext( HANDLE hContact, MsgQueueEntry& retVal );
+void __stdcall MsgQueue_Clear( HANDLE hContact = NULL );
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// User lists
+
+#define LIST_FL 0x0001
+#define LIST_AL 0x0002
+#define LIST_BL 0x0004
+#define LIST_RL 0x0008
+#define LIST_PL 0x0010
+
+#define LIST_REMOVE 0x0100
+
+#define IsValidListCode(n) ((n)!=0)
+
+int __stdcall Lists_NameToCode( const char* name );
+int __stdcall Lists_Add( int list, const char* email, const char* nick );
+int __stdcall Lists_IsInList( int list, const char* email );
+int __stdcall Lists_GetMask( const char* email );
+void __stdcall Lists_Remove( int list, const char* email );
+void __stdcall Lists_Wipe( void );
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN server groups
+
+bool MSN_AddGroup( const char* pName, const char* pId );
+void MSN_AddServerGroup( const char* pszGroupName );
+void MSN_DeleteGroup( const char* pId );
+void MSN_FreeGroups( void );
+LPCSTR MSN_GetGroupById( const char* pId );
+LPCSTR MSN_GetGroupByName( const char* pName );
+LPCSTR MSN_GetGroupByNumber( int pNumber );
+void MSN_MoveContactToGroup( HANDLE hContact, const char* grpName );
+void MSN_RenameServerGroup( int iNumber, LPCSTR szId, const char* newName );
+void MSN_SetGroupName( const char* pId, const char* pName );
+void MSN_SetGroupNumber( const char* pId, int pNumber );
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN plugin options
+
+typedef struct
+{
+ COLORREF BGColour;
+ COLORREF TextColour;
+ BOOL UseWinColors;
+
+ BOOL EnableSounds;
+
+ DWORD PopupTimeoutHotmail;
+ DWORD PopupTimeoutOther;
+
+ BOOL DisableMenu;
+ BOOL UseGateway;
+ BOOL UseProxy;
+ BOOL KeepConnectionAlive;
+ BOOL ShowErrorsAsPopups;
+ BOOL AwayAsBrb;
+ BOOL SlowSend;
+ BOOL ManageServer;
+ BOOL EnableAvatars;
+
+ BOOL UseMSNP11;
+}
+ MYOPTIONS;
+
+extern MYOPTIONS MyOptions;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Windows error class
+
+struct TWinErrorCode
+{
+ WINAPI TWinErrorCode();
+ WINAPI ~TWinErrorCode();
+
+ char* WINAPI getText();
+
+ long mErrorCode;
+ char* mErrorText;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// External variables
+
+#define MSN_NUM_MODES 7
+
+struct MSN_StatusMessage
+{
+ int m_mode;
+ char* m_msg;
+};
+
+extern MSN_StatusMessage msnModeMsgs[ MSN_NUM_MODES ];
+
+extern ThreadData* volatile msnNsThread;
+extern bool volatile msnLoggedIn;
+
+extern char* msnProtocolName;
+extern HANDLE msnMenuItems[ MENU_ITEMS_COUNT ];
+extern int msnSearchID;
+extern char* msnExternalIP;
+extern int msnStatusMode,
+ msnDesiredStatus;
+
+extern char* msnProtChallenge;
+extern char* msnProductID;
+
+extern char* ModuleName;
+extern char* mailsoundname;
+extern HANDLE msnGetInfoContact;
+
+extern char* sid;
+extern char* kv;
+extern char* passport;
+extern char* MSPAuth;
+
+extern HANDLE hNetlibUser;
+extern HINSTANCE hInst;
+extern int msnOtherContactsBlocked;
+
+extern bool msnHaveChatDll;
+
+extern HANDLE hGroupAddEvent;
+
+///////////////////////////////////////////////////////////////////////////////
+// memory manager
+
+extern struct MM_INTERFACE memoryManagerInterface;
+
+#define mir_alloc(n) memoryManagerInterface.mmi_malloc(n)
+#define mir_free(ptr) memoryManagerInterface.mmi_free(ptr)
+#define mir_realloc(ptr,size) memoryManagerInterface.mmi_realloc(ptr,size)
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF8 encode helper
+
+class UTFEncoder {
+ char* m_body;
+
+public:
+ __forceinline UTFEncoder( const char* pSrc ) :
+ m_body( Utf8Encode( pSrc ))
+ {}
+
+ __forceinline ~UTFEncoder()
+ { free( m_body );
+ }
+
+ __forceinline const char* str() const { return m_body; }
+};
+
+#define UTF8(A) UTFEncoder(A).str()
diff --git a/miranda-wine/protocols/MSN/msn_http.cpp b/miranda-wine/protocols/MSN/msn_http.cpp
new file mode 100644
index 0000000..711925a
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_http.cpp
@@ -0,0 +1,97 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "msn_global.h"
+
+//=======================================================================================
+// Fake function - it does nothing but confirms successful session initialization
+//=======================================================================================
+
+int msn_httpGatewayInit(HANDLE hConn, NETLIBOPENCONNECTION* nloc, NETLIBHTTPREQUEST* nlhr)
+{
+ NETLIBHTTPPROXYINFO nlhpi = {0};
+ nlhpi.cbSize = sizeof(nlhpi);
+ nlhpi.szHttpGetUrl = NULL;
+ nlhpi.szHttpPostUrl = "messenger.hotmail.com";
+ nlhpi.flags = NLHPIF_HTTP11;
+ return MSN_CallService(MS_NETLIB_SETHTTPPROXYINFO, (WPARAM)hConn, (LPARAM)&nlhpi);
+}
+
+//=======================================================================================
+// Prepares the szHttpPostUrl. If it's the very first send (mSessionID is void), this
+// function generates the initial URL depending on a thread type
+//=======================================================================================
+
+int msn_httpGatewayWrapSend(HANDLE hConn, PBYTE buf, int len, int flags, MIRANDASERVICE pfnNetlibSend)
+{
+ ThreadData* T = MSN_GetThreadByConnection( hConn );
+ if ( T != NULL )
+ T->applyGatewayData( hConn, len == 0 );
+
+ NETLIBBUFFER tBuf = { ( char* )buf, len, flags };
+ return pfnNetlibSend(( LPARAM )hConn, WPARAM( &tBuf ));
+}
+
+//=======================================================================================
+// Processes the results of the command execution. Parses HTTP headers to get the next
+// SessionID & gateway IP values
+//=======================================================================================
+
+PBYTE msn_httpGatewayUnwrapRecv( NETLIBHTTPREQUEST* nlhr, PBYTE buf, int len, int *outBufLen, void *(*NetlibRealloc)(void *, size_t))
+{
+ *outBufLen = len;
+
+ ThreadData* T = MSN_GetThreadByConnection( nlhr->nlc );
+ if ( T == NULL )
+ return buf;
+
+ bool tIsSessionClosed = false;
+
+ for ( int i=0; i < nlhr->headersCount; i++ )
+ {
+ NETLIBHTTPHEADER& tHeader = nlhr->headers[ i ];
+ if ( stricmp( tHeader.szName, "X-MSN-Messenger" ) != 0 )
+ continue;
+
+ if ( strstr( tHeader.szValue, "Session=close" ) != 0 )
+ { tIsSessionClosed = true;
+ break;
+ }
+
+ T->processSessionData( tHeader.szValue );
+ T->applyGatewayData( nlhr->nlc, false );
+ }
+
+ if ( tIsSessionClosed || nlhr->resultCode != 200)
+ { *outBufLen = 0;
+ buf = ( PBYTE )mir_alloc( 1 );
+ *buf = 0;
+ }
+ else if ( buf == NULL && len == 0 )
+ { *outBufLen = 1;
+ buf = ( PBYTE )mir_alloc( 1 );
+ *buf = 0;
+ }
+
+ return buf;
+}
diff --git a/miranda-wine/protocols/MSN/msn_libstr.cpp b/miranda-wine/protocols/MSN/msn_libstr.cpp
new file mode 100644
index 0000000..5a0c688
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_libstr.cpp
@@ -0,0 +1,54 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "msn_global.h"
+
+void replaceStr( char*& dest, const char* src )
+{
+ if ( src != NULL ) {
+ if ( dest != NULL )
+ free( dest );
+ dest = strdup( src );
+} }
+
+char* rtrim( char *string )
+{
+ char* p = string + strlen( string ) - 1;
+
+ while ( p >= string )
+ { if ( *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r' )
+ break;
+
+ *p-- = 0;
+ }
+ return string;
+}
+
+void strdel( char* parBuffer, int len )
+{
+ char *p;
+ for ( p = parBuffer+len; *p != 0; p++ )
+ p[ -len ] = *p;
+
+ p[ -len ] = '\0';
+}
diff --git a/miranda-wine/protocols/MSN/msn_lists.cpp b/miranda-wine/protocols/MSN/msn_lists.cpp
new file mode 100644
index 0000000..d6015d1
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_lists.cpp
@@ -0,0 +1,346 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "msn_global.h"
+
+#include <mbstring.h>
+
+#include "resource.h"
+
+struct MsnContact
+{
+ int list;
+ char *email,*nick;
+};
+
+static int count;
+static MsnContact* lists;
+static CRITICAL_SECTION csLists;
+
+void Lists_Init(void)
+{
+ lists = NULL;
+ count = 0;
+ InitializeCriticalSection( &csLists );
+}
+
+void Lists_Uninit(void)
+{
+ for ( int i=0; i < count; i++ ) {
+ free( lists[i].email );
+ free( lists[i].nick );
+ }
+
+ if ( lists != NULL )
+ free( lists );
+
+ DeleteCriticalSection( &csLists );
+}
+
+int __stdcall Lists_NameToCode( const char *name )
+{
+ if ( name[2] )
+ return 0;
+
+ switch( *( PWORD )name ) {
+ case 'LA': return LIST_AL;
+ case 'LB': return LIST_BL;
+ case 'LR': return LIST_RL;
+ case 'LF': return LIST_FL;
+ case 'LP': return LIST_PL;
+ }
+
+ return 0;
+}
+
+void __stdcall Lists_Wipe( void )
+{
+ EnterCriticalSection( &csLists );
+ for ( int i=0; i < count; i++ ) {
+ free( lists[i].email );
+ free( lists[i].nick );
+ }
+
+ if ( lists != NULL ) {
+ free( lists );
+ lists = NULL;
+ }
+
+ count = 0;
+ LeaveCriticalSection( &csLists );
+}
+
+int __stdcall Lists_IsInList( int list, const char* email )
+{
+ int i;
+ EnterCriticalSection( &csLists );
+ for ( i=0; i < count; i++ )
+ if ( !strcmp( lists[i].email, email ))
+ break;
+
+ if ( list != -1 && i != count )
+ if (( lists[ i ].list & list ) != list )
+ i = count;
+
+ LeaveCriticalSection( &csLists );
+ return ( i == count ) ? 0 : i+1;
+}
+
+int __stdcall Lists_GetMask( const char* email )
+{
+ int i;
+ EnterCriticalSection( &csLists );
+ for ( i=0; i < count; i++ )
+ if ( !strcmp( lists[i].email, email )) {
+ LeaveCriticalSection( &csLists );
+ return lists[i].list;
+ }
+
+ LeaveCriticalSection( &csLists );
+ return 0;
+}
+
+int __stdcall Lists_Add( int list, const char* email, const char* nick )
+{
+ EnterCriticalSection( &csLists );
+
+ MsnContact* C;
+ int idx = Lists_IsInList( -1, email );
+ if ( idx == 0 )
+ {
+ lists = ( MsnContact* )realloc( lists, sizeof( MsnContact )*( count+1 ));
+ C = &lists[ count++ ];
+ C->list = 0;
+ C->email = strdup( email );
+ C->nick = ( char* )strdup( nick );
+ }
+ else C = &lists[ idx-1 ];
+
+ int result = ( C->list |= list );
+ LeaveCriticalSection( &csLists );
+ return result;
+}
+
+void __stdcall Lists_Remove( int list, const char* email )
+{
+ EnterCriticalSection( &csLists );
+ int i = Lists_IsInList( -1, email );
+ if ( i != 0 ) {
+ MsnContact* C = &lists[ --i ];
+
+ C->list &= ~list;
+ if ( C->list == 0 ) {
+ free( C->email );
+ free( C->nick );
+ count--;
+ memmove( lists+i, lists+i+1, sizeof( MsnContact )*( count-i ));
+ lists = ( MsnContact* )realloc( lists, sizeof( MsnContact )*count );
+ } }
+
+ LeaveCriticalSection( &csLists );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN Server List Manager dialog procedure
+
+static void ResetListOptions(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));
+ SetWindowLong(hwndList,GWL_STYLE,GetWindowLong(hwndList,GWL_STYLE)|CLS_SHOWHIDDEN);
+}
+
+static void SetAllContactIcons( HWND hwndList )
+{
+ HANDLE hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ do {
+ HANDLE hItem = ( HANDLE )SendMessage( hwndList, CLM_FINDCONTACT, ( WPARAM )hContact, 0 );
+ if ( hItem == NULL )
+ continue;
+
+ char* szProto = ( char* )MSN_CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact, 0 );
+ if ( szProto == NULL ) {
+LBL_Bad: SendMessage( hwndList, CLM_DELETEITEM, ( WPARAM )hItem, 0 );
+ continue;
+ }
+
+ if ( strcmp( szProto, msnProtocolName ))
+ goto LBL_Bad;
+
+ char szEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( MSN_GetStaticString( "e-mail", hContact, szEmail, sizeof szEmail ))
+ goto LBL_Bad;
+
+ DWORD dwMask = Lists_GetMask( szEmail );
+ if ( SendMessage( hwndList, CLM_GETEXTRAIMAGE, ( WPARAM )hItem, MAKELPARAM(0,0)) == 0xFF )
+ SendMessage( hwndList, CLM_SETEXTRAIMAGE,( WPARAM )hItem, MAKELPARAM(0,( dwMask & LIST_FL )?1:0));
+ if ( SendMessage( hwndList, CLM_GETEXTRAIMAGE, ( WPARAM )hItem, MAKELPARAM(1,0)) == 0xFF )
+ SendMessage( hwndList, CLM_SETEXTRAIMAGE,( WPARAM )hItem, MAKELPARAM(1,( dwMask & LIST_AL )?2:0));
+ if ( SendMessage( hwndList, CLM_GETEXTRAIMAGE, ( WPARAM )hItem, MAKELPARAM(2,0)) == 0xFF )
+ SendMessage( hwndList, CLM_SETEXTRAIMAGE,( WPARAM )hItem, MAKELPARAM(2,( dwMask & LIST_BL )?3:0));
+ if ( SendMessage( hwndList, CLM_GETEXTRAIMAGE, ( WPARAM )hItem, MAKELPARAM(3,0)) == 0xFF )
+ SendMessage( hwndList, CLM_SETEXTRAIMAGE,( WPARAM )hItem, MAKELPARAM(3,( dwMask & LIST_RL )?4:0));
+ }
+ while( hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM )hContact, 0 ));
+}
+
+static void SaveListItem( HANDLE hContact, const char* szEmail, int list, int iPrevValue, int iNewValue )
+{
+ if ( iPrevValue == iNewValue )
+ return;
+
+ if ( iNewValue == 0 )
+ list += LIST_REMOVE;
+ MSN_AddUser( hContact, szEmail, list );
+}
+
+static void SaveSettings( HWND hwndList )
+{
+ HANDLE hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ do {
+ HANDLE hItem = ( HANDLE )SendMessage( hwndList, CLM_FINDCONTACT, ( WPARAM )hContact, 0 );
+ if ( hItem == NULL )
+ continue;
+
+ char* szProto = ( char* )MSN_CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact, 0 );
+ if ( szProto == NULL ) continue;
+ if ( strcmp( szProto, msnProtocolName )) continue;
+
+ char szEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( MSN_GetStaticString( "e-mail", hContact, szEmail, sizeof szEmail ))
+ continue;
+
+ DWORD dwMask = Lists_GetMask( szEmail );
+ SaveListItem( hContact, szEmail, LIST_FL, ( dwMask & LIST_FL ) != 0, SendMessage( hwndList, CLM_GETEXTRAIMAGE, ( WPARAM )hItem, MAKELPARAM(0,0)));
+ SaveListItem( hContact, szEmail, LIST_AL, ( dwMask & LIST_AL ) != 0, SendMessage( hwndList, CLM_GETEXTRAIMAGE, ( WPARAM )hItem, MAKELPARAM(1,0)));
+ SaveListItem( hContact, szEmail, LIST_BL, ( dwMask & LIST_BL ) != 0, SendMessage( hwndList, CLM_GETEXTRAIMAGE, ( WPARAM )hItem, MAKELPARAM(2,0)));
+ }
+ while( hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM )hContact, 0 ));
+}
+
+BOOL CALLBACK DlgProcMsnServLists(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static HANDLE hItemAll;
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ {
+ HIMAGELIST hIml = ImageList_Create(
+ GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
+ ILC_MASK | (IsWinVerXPPlus() ? ILC_COLOR32 : ILC_COLOR16 ), 5, 5 );
+ ImageList_AddIcon( hIml,LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(211)));
+ ImageList_AddIcon( hIml, LoadIcon( hInst, MAKEINTRESOURCE( IDI_LIST_FL )));
+ ImageList_AddIcon( hIml, LoadIcon( hInst, MAKEINTRESOURCE( IDI_LIST_AL )));
+ ImageList_AddIcon( hIml, LoadIcon( hInst, MAKEINTRESOURCE( IDI_LIST_BL )));
+ ImageList_AddIcon( hIml, LoadIcon( hInst, MAKEINTRESOURCE( IDI_LIST_RL )));
+ SendDlgItemMessage( hwndDlg, IDC_LIST, CLM_SETEXTRAIMAGELIST, 0, (LPARAM)hIml );
+ }
+ ResetListOptions( GetDlgItem( hwndDlg, IDC_LIST ));
+ SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_SETEXTRACOLUMNS,4,0);
+ SetAllContactIcons(GetDlgItem(hwndDlg,IDC_LIST));
+ return TRUE;
+
+ case WM_SETFOCUS:
+ SetFocus(GetDlgItem(hwndDlg,IDC_LIST));
+ break;
+
+ case WM_COMMAND:
+ break;
+
+ case WM_NOTIFY:
+ if (((LPNMHDR)lParam)->idFrom == 0 && ((LPNMHDR)lParam)->code == PSN_APPLY ) {
+ SaveSettings(GetDlgItem(hwndDlg,IDC_LIST));
+ break;
+ }
+
+ if (((LPNMHDR)lParam)->idFrom != IDC_LIST )
+ break;
+
+ switch (((LPNMHDR)lParam)->code) {
+ case CLN_NEWCONTACT:
+ case CLN_LISTREBUILT:
+ SetAllContactIcons(GetDlgItem(hwndDlg,IDC_LIST));
+ //fall through
+ case CLN_OPTIONSCHANGED:
+ ResetListOptions(GetDlgItem(hwndDlg,IDC_LIST));
+ break;
+
+ case NM_CLICK:
+ HANDLE hItem;
+ NMCLISTCONTROL *nm=(NMCLISTCONTROL*)lParam;
+ DWORD hitFlags;
+ int iImage;
+ int itemType;
+
+ // Make sure we have an extra column, also we can't change RL list
+ if ( nm->iColumn == -1 || nm->iColumn == 3 )
+ break;
+
+ // Find clicked item
+ hItem = (HANDLE)SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_HITTEST, (WPARAM)&hitFlags, MAKELPARAM(nm->pt.x,nm->pt.y));
+ // Nothing was clicked
+ if ( hItem == NULL )
+ break;
+
+ // It was not our extended icon
+ if ( !( hitFlags & CLCHT_ONITEMEXTRA ))
+ break;
+
+ // Get image in clicked column (0=none, 1=FL, 2=AL, 3=BL, 4=RL)
+ iImage = SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(nm->iColumn, 0));
+ if ( iImage == 0 )
+ iImage = nm->iColumn + 1;
+ else
+ iImage = 0;
+
+ // Get item type (contact, group, etc...)
+ itemType = SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_GETITEMTYPE, (WPARAM)hItem, 0);
+ if ( itemType == CLCIT_CONTACT ) { // A contact
+ SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(nm->iColumn, iImage));
+ if (iImage && SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM( 3-nm->iColumn, 0)) != 0xFF )
+ if ( nm->iColumn == 1 || nm->iColumn == 2 )
+ SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM( 3-nm->iColumn, 0));
+ }
+
+ // Activate Apply button
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ break;
+
+ case WM_DESTROY:
+ HIMAGELIST hIml=(HIMAGELIST)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETEXTRAIMAGELIST,0,0);
+ ImageList_Destroy(hIml);
+ break;
+ }
+
+ return FALSE;
+}
diff --git a/miranda-wine/protocols/MSN/msn_md5.h b/miranda-wine/protocols/MSN/msn_md5.h
new file mode 100644
index 0000000..57dcc17
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_md5.h
@@ -0,0 +1,59 @@
+/* MD5.H - header file for MD5C.C
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* PROTOTYPES should be set to one if and only if the compiler supports
+ function argument prototyping.
+The following makes PROTOTYPES default to 0 if it has not already
+ been defined with C compiler flags.
+ */
+#ifndef PROTOTYPES
+#define PROTOTYPES 0
+#endif
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+
+/* UINT2 defines a two byte word */
+typedef unsigned short int UINT2;
+
+/* UINT4 defines a four byte word */
+typedef unsigned long int UINT4;
+
+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+ returns an empty list.
+ */
+
+/* MD5 context. */
+typedef struct {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD5_CTX;
+
+void MD5Init( MD5_CTX* );
+void MD5Update( MD5_CTX *, unsigned char *, unsigned int );
+void MD5Final(unsigned char [16], MD5_CTX * );
+
diff --git a/miranda-wine/protocols/MSN/msn_md5c.cpp b/miranda-wine/protocols/MSN/msn_md5c.cpp
new file mode 100644
index 0000000..3826ac4
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_md5c.cpp
@@ -0,0 +1,287 @@
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+#include "msn_global.h"
+#include "msn_md5.h"
+
+/* Constants for MD5Transform routine.
+ */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform( UINT4[4], unsigned char[64] );
+static void Encode( unsigned char *, UINT4 *, unsigned int );
+static void Decode( UINT4 *, unsigned char *, unsigned int );
+
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+void MD5Init( MD5_CTX* context)
+{
+ context->count[0] = context->count[1] = 0;
+ /* Load magic initialization constants.
+ */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+void MD5Update( MD5_CTX* context, unsigned char* input, unsigned int inputLen)
+{
+ unsigned int i, index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4) inputLen << 3)) <
+ ((UINT4) inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4) inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /* Transform as many times as possible.
+ */
+ if (inputLen >= partLen)
+ {
+ memcpy((POINTER) & context->buffer[index], (POINTER) input, partLen);
+ MD5Transform(context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform(context->state, &input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ memcpy((POINTER) & context->buffer[index], (POINTER) & input[i], inputLen - i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+void MD5Final( unsigned char* digest, MD5_CTX* context )
+{
+ unsigned char bits[8];
+ unsigned int index, padLen;
+
+ /* Save number of bits */
+ Encode(bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+ */
+ index = (unsigned int) ((context->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ MD5Update(context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5Update(context, bits, 8);
+ /* Store state in digest */
+ Encode(digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+ */
+ memset((POINTER) context, 0, sizeof(*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform( UINT4 state[4], unsigned char block[64] )
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode(x, block, 64);
+
+ /* Round 1 */
+ FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
+ FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
+ FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
+ FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
+ FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
+ FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
+ FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
+ FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
+ FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
+ FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
+ FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
+ GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
+ GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
+ GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
+ GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
+ GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
+ GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
+ GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
+ GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
+ GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
+ GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
+ HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
+ HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
+ HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
+ HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
+ HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
+ HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
+ HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
+ HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
+ HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
+ II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
+ II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
+ II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
+ II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
+ II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
+ II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
+ II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
+ II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
+ II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+ */
+ memset((POINTER) x, 0, sizeof(x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+static void Encode( unsigned char* output, UINT4 *input, unsigned int len )
+{
+ unsigned int i, j;
+
+ for ( i = 0, j = 0; j < len; i++, j += 4 )
+ {
+ output[j] = (unsigned char) (input[i] & 0xff);
+ output[j + 1] = (unsigned char) ((input[i] >> 8) & 0xff);
+ output[j + 2] = (unsigned char) ((input[i] >> 16) & 0xff);
+ output[j + 3] = (unsigned char) ((input[i] >> 24) & 0xff);
+} }
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+ */
+static void Decode( UINT4 *output, unsigned char *input, unsigned int len )
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] =
+ ((UINT4) input[j]) | (((UINT4) input[j + 1]) << 8) |
+ (((UINT4) input[j + 2]) << 16) | (((UINT4) input[j + 3]) << 24);
+}
diff --git a/miranda-wine/protocols/MSN/msn_mime.cpp b/miranda-wine/protocols/MSN/msn_mime.cpp
new file mode 100644
index 0000000..f8a9d3b
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_mime.cpp
@@ -0,0 +1,162 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "msn_global.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// constructors and destructor
+
+MimeHeaders::MimeHeaders() :
+ mCount( 0 ),
+ mVals( NULL )
+{
+}
+
+MimeHeaders::MimeHeaders( int iInitCount ) :
+ mCount( 0 )
+{
+ mVals = ( MimeHeader* )malloc( iInitCount * sizeof( MimeHeader ));
+}
+
+MimeHeaders::~MimeHeaders()
+{
+ if ( mCount == NULL )
+ return;
+
+ for ( int i=0; i < mCount; i++ ) {
+ MimeHeader& H = mVals[ i ];
+ free( H.name );
+ free( H.value );
+ }
+
+ free( mVals );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// add various values
+
+void MimeHeaders::addString( const char* name, const char* szValue )
+{
+ MimeHeader& H = mVals[ mCount++ ];
+ H.name = strdup( name );
+ H.value = strdup( szValue );
+}
+
+void MimeHeaders::addLong( const char* name, long lValue )
+{
+ MimeHeader& H = mVals[ mCount++ ];
+ H.name = strdup( name );
+
+ char szBuffer[ 20 ];
+ ltoa( lValue, szBuffer, 10 );
+ H.value = strdup( szBuffer );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// write all values to a buffer
+
+int MimeHeaders::getLength()
+{
+ int iResult = 0;
+ for ( int i=0; i < mCount; i++ ) {
+ MimeHeader& H = mVals[ i ];
+ iResult += strlen( H.name ) + strlen( H.value ) + 4;
+ }
+
+ return iResult;
+}
+
+char* MimeHeaders::writeToBuffer( char* pDest )
+{
+ for ( int i=0; i < mCount; i++ ) {
+ MimeHeader& H = mVals[ i ];
+ pDest += sprintf( pDest, "%s: %s\r\n", H.name, H.value );
+ }
+
+ return pDest;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// read set of values from buffer
+
+const char* MimeHeaders::readFromBuffer( const char* parString )
+{
+ int headerCount = 0;
+ MimeHeader headers[ 100 ];
+ char line[ 4096 ];
+
+ while ( true ) {
+ if ( parString[0] == '\r' && parString[1] == '\n' ) {
+ parString += 2;
+ break;
+ }
+
+ const char* peol = strchr( parString, '\r' );
+ if ( peol == NULL )
+ break;
+
+ int cbLen = int( peol - parString );
+ if ( cbLen > sizeof( line ))
+ break;
+
+ memcpy( line, parString, cbLen );
+ line[ cbLen ] = 0;
+
+ if ( *++peol == '\n' )
+ peol++;
+
+ parString = peol;
+
+ char* delim = strchr( line, ':' );
+ if ( delim == NULL ) {
+ MSN_DebugLog( "MSG: Invalid MIME header: '%s'", line );
+ continue;
+ }
+
+ *delim++ = '\0';
+ while ( *delim == ' ' || *delim == '\t' )
+ delim++;
+
+ MimeHeader& H = headers[ headerCount ];
+ H.name = strdup( line );
+ H.value = strdup( delim );
+ headerCount++;
+ }
+
+ if (( mCount = headerCount ) != 0 ) {
+ mVals = ( MimeHeader* )malloc( sizeof( MimeHeader )*headerCount );
+ memcpy( mVals, headers, sizeof( MimeHeader )*headerCount );
+ }
+ return parString;
+}
+
+const char* MimeHeaders::operator[]( const char* szFieldName )
+{
+ for ( int i=0; i < mCount; i++ ) {
+ MimeHeader& MH = mVals[i];
+ if ( !strcmp( MH.name, szFieldName ))
+ return MH.value;
+ }
+
+ return NULL;
+}
diff --git a/miranda-wine/protocols/MSN/msn_misc.cpp b/miranda-wine/protocols/MSN/msn_misc.cpp
new file mode 100644
index 0000000..86c46c3
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_misc.cpp
@@ -0,0 +1,1069 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 <stdio.h>
+#include <stdarg.h>
+
+#include "msn_global.h"
+
+#include <direct.h>
+#include <io.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include "msn_md5.h"
+#include "resource.h"
+
+typedef LONG ( WINAPI pIncrementFunc )( PLONG );
+
+static pIncrementFunc MyInterlockedIncrement95;
+static pIncrementFunc MyInterlockedIncrementInit;
+
+pIncrementFunc *MyInterlockedIncrement = MyInterlockedIncrementInit;
+
+static CRITICAL_SECTION csInterlocked95;
+extern HANDLE msnMainThread;
+extern bool msnUseExtendedPopups;
+extern char* msnPreviousUUX;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MirandaStatusToMSN - status helper functions
+
+char* __stdcall MirandaStatusToMSN( int status )
+{
+ switch(status)
+ {
+ case ID_STATUS_OFFLINE: return "FLN";
+ case ID_STATUS_NA: return ( MyOptions.AwayAsBrb ) ? (char *)"AWY" : (char *)"BRB";
+ case ID_STATUS_AWAY: return ( MyOptions.AwayAsBrb ) ? (char *)"BRB" : (char *)"AWY";
+ case ID_STATUS_DND:
+ case ID_STATUS_OCCUPIED: return "BSY";
+ case ID_STATUS_ONTHEPHONE: return "PHN";
+ case ID_STATUS_OUTTOLUNCH: return "LUN";
+ case ID_STATUS_INVISIBLE: return "HDN";
+// case ID_STATUS_IDLE: return "IDL";
+ default: return "NLN";
+} }
+
+int __stdcall MSNStatusToMiranda(const char *status)
+{
+ switch((*(PDWORD)status&0x00FFFFFF)|0x20000000) {
+ case ' NLN': return ID_STATUS_ONLINE;
+ case ' YWA': return ( MyOptions.AwayAsBrb ) ? ID_STATUS_NA : ID_STATUS_AWAY;
+ case ' LDI': //return ID_STATUS_IDLE;
+ case ' BRB': return ( MyOptions.AwayAsBrb ) ? ID_STATUS_AWAY : ID_STATUS_NA;
+ case ' YSB': return ID_STATUS_OCCUPIED;
+ case ' NHP': return ID_STATUS_ONTHEPHONE;
+ case ' NUL': return ID_STATUS_OUTTOLUNCH;
+ case ' NDH': return ID_STATUS_INVISIBLE;
+ default: return ID_STATUS_OFFLINE;
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_AddUser - adds a e-mail address to one of the MSN server lists
+
+int __stdcall MSN_AddUser( HANDLE hContact, const char* email, int flags )
+{
+ if ( flags & LIST_REMOVE )
+ {
+ if ( !Lists_IsInList( flags & 0xFF, email ))
+ return 0;
+ }
+ else if ( Lists_IsInList( flags, email ))
+ return 0;
+
+ char* listName;
+
+ switch( flags & 0xFF )
+ {
+ case LIST_AL: listName = "AL"; break;
+ case LIST_BL: listName = "BL"; break;
+ case LIST_FL: listName = "FL"; break;
+ case LIST_RL: listName = "RL"; break;
+ case LIST_PL: listName = "PL"; break;
+ default:
+ return -1;
+ }
+
+ int msgid;
+ if (( flags & 0xFF ) == LIST_FL ) {
+ if ( flags & LIST_REMOVE ) {
+ if ( hContact == NULL )
+ if (( hContact = MSN_HContactFromEmail( email, NULL, 0, 0 )) == NULL )
+ return -1;
+
+ char id[ MSN_GUID_LEN ];
+ if ( !MSN_GetStaticString( "ID", hContact, id, sizeof id ))
+ msgid = msnNsThread->sendPacket( "REM", "%s %s", listName, id );
+ }
+ else msgid = msnNsThread->sendPacket( "ADC", "%s N=%s F=%s", listName, email, email );
+ }
+ else {
+ if ( flags & LIST_REMOVE )
+ msgid = msnNsThread->sendPacket( "REM", "%s %s", listName, email );
+ else
+ msgid = msnNsThread->sendPacket( "ADC", "%s N=%s", listName, email );
+ }
+
+ return msgid;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_AddAuthRequest - adds the authorization event to the database
+
+void __stdcall MSN_AddAuthRequest( HANDLE hContact, const char *email, const char *nick )
+{
+ //blob is: UIN=0(DWORD), hContact(DWORD), nick(ASCIIZ), ""(ASCIIZ), ""(ASCIIZ), email(ASCIIZ), ""(ASCIIZ)
+
+ DBEVENTINFO dbei = { 0 };
+ dbei.cbSize = sizeof( dbei );
+ dbei.szModule = msnProtocolName;
+ dbei.timestamp = (DWORD)time(NULL);
+ dbei.flags = 0;
+ dbei.eventType = EVENTTYPE_AUTHREQUEST;
+ dbei.cbBlob = sizeof(DWORD)*2+strlen(nick)+strlen(email)+5;
+
+ PBYTE pCurBlob = dbei.pBlob = ( PBYTE )malloc( dbei.cbBlob );
+ *( PDWORD )pCurBlob = 0; pCurBlob+=sizeof( DWORD );
+ *( PDWORD )pCurBlob = ( DWORD )hContact; pCurBlob+=sizeof( DWORD );
+ strcpy(( char* )pCurBlob, nick); pCurBlob += strlen( nick )+1;
+ *pCurBlob = '\0'; pCurBlob++; //firstName
+ *pCurBlob = '\0'; pCurBlob++; //lastName
+ strcpy(( char* )pCurBlob, email ); pCurBlob += strlen( email )+1;
+ *pCurBlob = '\0'; //reason
+ MSN_CallService( MS_DB_EVENT_ADD, NULL,( LPARAM )&dbei );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_AddServerGroup - adds a group to the server list
+
+void MSN_AddServerGroup( const char* pszGroupName )
+{
+ char szBuf[ 200 ];
+ UrlEncode( pszGroupName, szBuf, sizeof szBuf );
+
+ if ( hGroupAddEvent == NULL )
+ hGroupAddEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+
+ msnNsThread->sendPacket( "ADG", "%s", szBuf );
+
+ WaitForSingleObject( hGroupAddEvent, INFINITE );
+ CloseHandle( hGroupAddEvent ); hGroupAddEvent = NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_DebugLog - writes a line of comments to the network log
+
+void __stdcall MSN_DebugLog( const char *fmt, ... )
+{
+ char str[ 4096 ];
+ va_list vararg;
+
+ va_start( vararg, fmt );
+ int tBytes = _vsnprintf( str, sizeof(str)-1, fmt, vararg );
+ if ( tBytes == 0 )
+ return;
+
+ if ( tBytes > 0 )
+ str[ tBytes ] = 0;
+ else
+ str[ sizeof(str)-1 ] = 0;
+
+ MSN_CallService( MS_NETLIB_LOG, ( WPARAM )hNetlibUser, ( LPARAM )str );
+ va_end( vararg );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_DumpMemory - dumps a memory block to the network log
+
+void __stdcall MSN_DumpMemory( const char* buffer, int bufSize )
+{
+ char TmpBuffer[ 256 ];
+ long Ptr = 0;
+
+ while ( Ptr < bufSize ) {
+ char* bufferPtr = TmpBuffer + sprintf( TmpBuffer, "%04X ", Ptr );
+ int i;
+
+ for ( i=0; Ptr+i < bufSize && i < 16; i++ )
+ bufferPtr += sprintf( bufferPtr, "%02X ", BYTE( buffer[Ptr+i] ));
+
+ while ( i++ < 17 ) {
+ strcat( bufferPtr, " " );
+ bufferPtr += 3;
+ }
+
+ for ( i=0; Ptr < bufSize && i < 16; i++, Ptr++ )
+ *bufferPtr++ = ( BYTE( buffer[ Ptr ]) >= ' ' ) ? buffer[ Ptr ] : '.';
+
+ *bufferPtr = 0;
+
+ MSN_CallService( MS_NETLIB_LOG, ( WPARAM )hNetlibUser, ( LPARAM )TmpBuffer );
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_GetAvatarFileName - gets a file name for an contact's avatar
+
+void __stdcall MSN_GetAvatarFileName( HANDLE hContact, char* pszDest, int cbLen )
+{
+ MSN_CallService( MS_DB_GETPROFILEPATH, cbLen, LPARAM( pszDest ));
+
+ int tPathLen = strlen( pszDest );
+ tPathLen += mir_snprintf( pszDest + tPathLen, MAX_PATH - tPathLen, "\\MSN\\" );
+ CreateDirectoryA( pszDest, NULL );
+
+ if ( hContact != NULL ) {
+ char szEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( MSN_GetStaticString( "e-mail", hContact, szEmail, sizeof( szEmail )))
+ ltoa(( long )hContact, szEmail, 10 );
+
+ long digest[ 4 ];
+ MD5_CTX ctx;
+ MD5Init( &ctx );
+ MD5Update( &ctx, ( BYTE* )szEmail, strlen( szEmail ));
+ MD5Final(( BYTE* )digest, &ctx );
+
+ tPathLen += mir_snprintf( pszDest + tPathLen, MAX_PATH - tPathLen, "%08lX%08lX%08lX%08lX",
+ digest[0], digest[1], digest[2], digest[3] );
+
+ strcat( pszDest + tPathLen, ".bmp" );
+ }
+ else mir_snprintf( pszDest + tPathLen, MAX_PATH - tPathLen, "%s avatar.png", msnProtocolName );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_GoOffline - performs several actions when a server goes offline
+
+void __stdcall MSN_GoOffline()
+{
+ int msnOldStatus = msnStatusMode; msnStatusMode = ID_STATUS_OFFLINE;
+ MSN_SendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)msnOldStatus, ID_STATUS_OFFLINE );
+
+ msnLoggedIn = false;
+
+ free(msnPreviousUUX);
+ msnPreviousUUX = NULL;
+
+ if ( !Miranda_Terminated() )
+ MSN_EnableMenuItems( FALSE );
+ MSN_CloseConnections();
+ MSN_FreeGroups();
+ MsgQueue_Clear();
+
+ HANDLE hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL )
+ {
+ if ( !lstrcmpA( msnProtocolName, (char*)MSN_CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact, 0 )))
+ if ( ID_STATUS_OFFLINE != MSN_GetWord( hContact, "Status", ID_STATUS_OFFLINE ))
+ MSN_SetWord( hContact, "Status", ID_STATUS_OFFLINE );
+
+ hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM )hContact, 0 );
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_SendMessage - formats and sends a MSG packet through the server
+
+char sttHeaderStart[] = "MIME-Version: 1.0\r\n";
+
+LONG ThreadData::sendMessage( int msgType, const char* parMsg, int parFlags )
+{
+ char tHeader[ 1024 ];
+ strcpy( tHeader, sttHeaderStart );
+
+ if (( parFlags & MSG_DISABLE_HDR ) == 0 ) {
+ char tFontName[ 100 ], tFontStyle[ 3 ];
+ DWORD tFontColor;
+
+ strcpy( tFontName, "Arial" );
+
+ if ( MSN_GetByte( "SendFontInfo", 1 )) {
+ char* p;
+
+ DBVARIANT dbv;
+ if ( !DBGetContactSetting( NULL, "SRMsg", "Font0", &dbv )) {
+ for ( p = dbv.pszVal; *p; p++ )
+ if ( BYTE( *p ) >= 128 || *p < 32 )
+ break;
+
+ if ( *p == 0 ) {
+ UrlEncode( dbv.pszVal, tFontName, sizeof( tFontName ));
+ MSN_FreeVariant( &dbv );
+ } }
+
+ { BYTE tStyle = DBGetContactSettingByte( NULL, "SRMsg", "Font0Sty", 0 );
+ p = tFontStyle;
+ if ( tStyle & 1 ) *p++ = 'B';
+ if ( tStyle & 2 ) *p++ = 'I';
+ *p = 0;
+ }
+
+ tFontColor = DBGetContactSettingDword( NULL, "SRMsg", "Font0Col", 0 );
+ }
+ else {
+ tFontColor = 0;
+ tFontStyle[ 0 ] = 0;
+ }
+
+ mir_snprintf( tHeader + sizeof( sttHeaderStart )-1, sizeof( tHeader )-sizeof( sttHeaderStart ),
+ "Content-Type: text/plain; charset=UTF-8\r\n"
+ "X-MMS-IM-Format: FN=%s; EF=%s; CO=%x; CS=0; PF=31%s\r\n\r\n",
+ tFontName, tFontStyle, tFontColor, (parFlags & MSG_RTL) ? ";RL=1" : "" );
+ }
+
+ return sendPacket( "MSG", "%c %d\r\n%s%s", msgType, strlen( parMsg )+strlen( tHeader ), tHeader, parMsg );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_SendRawPacket - sends a packet accordingly to the MSN protocol
+
+LONG ThreadData::sendRawMessage( int msgType, const char* data, int datLen )
+{
+ if ( data == NULL )
+ data = "";
+
+ if ( datLen == -1 )
+ datLen = strlen( data );
+
+ char* buf = ( char* )alloca( datLen + 100 );
+
+ LONG thisTrid = MyInterlockedIncrement( &mTrid );
+ int nBytes = mir_snprintf( buf, 100, "MSG %d %c %d\r\n%s",
+ thisTrid, msgType, datLen + sizeof(sttHeaderStart)-1, sttHeaderStart );
+ memcpy( buf + nBytes, data, datLen );
+ send( buf, nBytes + datLen );
+
+ return thisTrid;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_RenameServerGroup - renames a group at the server
+
+void MSN_RenameServerGroup( int iNumber, LPCSTR szId, const char* newName )
+{
+ LPCSTR oldId = MSN_GetGroupByName( newName );
+ if ( oldId == NULL ) {
+ char szNewName[ 256 ];
+ UrlEncode( newName, szNewName, sizeof szNewName );
+ msnNsThread->sendPacket( "REG", "%s %s", szId, szNewName );
+ }
+ else MSN_SetGroupNumber( oldId, iNumber );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Msn_SendNickname - update our own nickname on the server
+
+int __stdcall MSN_SendNickname(char *nickname)
+{
+ char urlNick[ 387 ];
+ UrlEncode( UTF8(nickname), urlNick, sizeof( urlNick ));
+ msnNsThread->sendPacket( "PRP", "MFN %s", urlNick );
+ return 0;
+}
+
+int __stdcall MSN_SendNicknameW( WCHAR* nickname)
+{
+ char* nickutf = Utf8EncodeUcs2( nickname );
+
+ char urlNick[ 387 ];
+ UrlEncode( nickutf, urlNick, sizeof( urlNick ));
+ msnNsThread->sendPacket( "PRP", "MFN %s", urlNick );
+
+ free( nickutf );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_SendStatusMessage - notify a server about the status message change
+
+void __stdcall MSN_SendStatusMessage( const char* msg )
+{
+ if ( !msnLoggedIn || !MyOptions.UseMSNP11 )
+ return;
+
+ char* msgEnc = HtmlEncode(( msg == NULL ) ? "" : msg );
+ char szMsg[ 1024 ], szEmail[ MSN_MAX_EMAIL_LEN ];
+ mir_snprintf( szMsg, sizeof szMsg, "<Data><PSM>%s</PSM><CurrentMedia></CurrentMedia></Data>", UTF8(msgEnc));
+ free( msgEnc );
+
+ if ( !lstrcmpA( msnPreviousUUX, szMsg ))
+ return;
+
+ replaceStr( msnPreviousUUX, szMsg );
+ if ( !MSN_GetStaticString( "e-mail", NULL, szEmail, sizeof szEmail ))
+ msnNsThread->sendPacket( "UUX", "%d\r\n%s", strlen( szMsg ), szMsg );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_SendPacket - sends a packet accordingly to the MSN protocol
+
+LONG ThreadData::sendPacket( const char* cmd, const char* fmt,...)
+{
+ if ( this == NULL ) // :)
+ return 0;
+
+ if ( !strcmp( cmd, "CAL" ) && mIsCalSent )
+ return 0;
+
+ va_list vararg;
+ va_start( vararg, fmt );
+
+ int strsize = 512;
+ char* str = ( char* )malloc( strsize );
+
+ LONG thisTrid = MyInterlockedIncrement( &mTrid );
+
+ if ( fmt == NULL || fmt[0] == '\0' )
+ sprintf( str, "%s %d", cmd, thisTrid );
+ else {
+ int paramStart = sprintf( str, "%s %d ", cmd, thisTrid );
+ while ( _vsnprintf( str+paramStart, strsize-paramStart-2, fmt, vararg ) == -1 )
+ str = (char*)realloc( str, strsize += 512 );
+ }
+
+ if ( strcmp( cmd, "MSG" ) && strcmp( cmd, "QRY" ) && strcmp( cmd, "UUX" ))
+ strcat( str,"\r\n" );
+
+ if ( !strcmp( cmd, "CAL" ))
+ mIsCalSent = true;
+
+ int result = send( str, strlen( str ));
+ free( str );
+ return ( result > 0 ) ? thisTrid : -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_SetServerStatus - changes plugins status at the server
+
+void __stdcall MSN_SetServerStatus( int newStatus )
+{
+ MSN_DebugLog( "Setting MSN server status %d, logged in = %d", newStatus, msnLoggedIn );
+
+ if ( !msnLoggedIn )
+ return;
+
+ char* szStatusName = MirandaStatusToMSN( newStatus );
+
+ if ( newStatus != ID_STATUS_OFFLINE ) {
+ char szMsnObject[ 1000 ];
+ if ( MSN_GetStaticString( "PictObject", NULL, szMsnObject, sizeof szMsnObject ))
+ szMsnObject[ 0 ] = 0;
+
+ //here we say what functions can be used with this plugins : http://siebe.bot2k3.net/docs/?url=clientid.html
+ msnNsThread->sendPacket( "CHG", "%s 1342177280 %s", szStatusName, szMsnObject );
+
+ if ( MyOptions.UseMSNP11 ) {
+ for ( int i=0; i < MSN_NUM_MODES; i++ ) {
+ if ( msnModeMsgs[ i ].m_mode == newStatus ) {
+ MSN_SendStatusMessage( msnModeMsgs[ i ].m_msg );
+ break;
+ } } }
+ }
+ else msnNsThread->sendPacket( "CHG", szStatusName );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_ShowError - shows an error
+
+void __cdecl MSN_ShowError( const char* msgtext, ... )
+{
+ char tBuffer[ 4096 ];
+ va_list tArgs;
+
+ va_start( tArgs, msgtext );
+ mir_vsnprintf( tBuffer, sizeof( tBuffer ), MSN_Translate( msgtext ), tArgs );
+ va_end( tArgs );
+
+ if ( MyOptions.ShowErrorsAsPopups )
+ MSN_ShowPopup( msnProtocolName, tBuffer, MSN_ALLOW_MSGBOX | MSN_SHOW_ERROR );
+ else
+ MessageBoxA( NULL, tBuffer, msnProtocolName, MB_OK );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_ShowPopup - popup plugin support
+
+void CALLBACK sttMainThreadCallback( ULONG dwParam )
+{
+ POPUPDATAEX* ppd = ( POPUPDATAEX* )dwParam;
+
+ if ( msnUseExtendedPopups )
+ MSN_CallService( MS_POPUP_ADDPOPUPEX, ( WPARAM )ppd, 0 );
+ else
+ MSN_CallService( MS_POPUP_ADDPOPUP, ( WPARAM )ppd, 0 );
+
+ free( ppd );
+}
+
+void __stdcall MSN_ShowPopup( const char* nickname, const char* msg, int flags )
+{
+ if ( !ServiceExists( MS_POPUP_ADDPOPUP )) {
+ if ( flags & MSN_ALLOW_MSGBOX )
+ MessageBoxA( NULL, msg, "MSN Protocol", MB_OK + ( flags & MSN_SHOW_ERROR ) ? MB_ICONERROR : MB_ICONINFORMATION );
+
+ return;
+ }
+
+ POPUPDATAEX* ppd = ( POPUPDATAEX* )calloc( sizeof( POPUPDATAEX ), 1 );
+
+ ppd->lchContact = NULL;
+ ppd->lchIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_MSN ));
+ strcpy( ppd->lpzContactName, nickname );
+ strcpy( ppd->lpzText, msg );
+
+ if ( flags & MSN_SHOW_ERROR ) {
+ ppd->lchIcon = LoadIcon( NULL, IDI_WARNING );
+ if ( ServiceExists( MS_POPUP_ADDCLASS ))
+ ppd->lpzClass = _T(POPUP_CLASS_WARNING);
+ else {
+ ppd->colorBack = RGB(191,0,0); //Red
+ ppd->colorText = RGB(255,245,225); //Yellow
+ }
+
+ ppd->iSeconds = 60;
+ }
+ else {
+ ppd->colorBack = ( MyOptions.UseWinColors ) ? GetSysColor( COLOR_BTNFACE ) : MyOptions.BGColour;
+ ppd->colorText = ( MyOptions.UseWinColors ) ? GetSysColor( COLOR_WINDOWTEXT ) : MyOptions.TextColour;
+ if ( msnUseExtendedPopups )
+ ppd->iSeconds = ( flags & MSN_HOTMAIL_POPUP ) ? MyOptions.PopupTimeoutHotmail : MyOptions.PopupTimeoutOther;
+ }
+
+ ppd->PluginWindowProc = ( WNDPROC )NullWindowProc;
+ ppd->PluginData = ( flags & MSN_ALLOW_ENTER ) ? &ppd : NULL;
+
+ QueueUserAPC( sttMainThreadCallback , msnMainThread, ( ULONG )ppd );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_StoreLen - stores a message's length in a buffer
+
+char* __stdcall MSN_StoreLen( char* dest, char* last )
+{
+ char tBuffer[ 20 ];
+ ltoa( short( last-dest )-7, tBuffer, 10 );
+ int cbDigits = strlen( tBuffer );
+ memcpy( dest, tBuffer, cbDigits );
+ memmove( dest + cbDigits, dest + 5, int( last-dest )-7 );
+ return last - ( 5 - cbDigits );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// UrlDecode - converts URL chars like %20 into printable characters
+
+static int SingleHexToDecimal(char c)
+{
+ if ( c >= '0' && c <= '9' ) return c-'0';
+ if ( c >= 'a' && c <= 'f' ) return c-'a'+10;
+ if ( c >= 'A' && c <= 'F' ) return c-'A'+10;
+ return -1;
+}
+
+void __stdcall UrlDecode( char* str )
+{
+ char* s = str, *d = str;
+
+ while( *s )
+ {
+ if ( *s != '%' ) {
+ *d++ = *s++;
+ continue;
+ }
+
+ int digit1 = SingleHexToDecimal( s[1] ), digit2 = SingleHexToDecimal( s[2] );
+ if ( digit1 == -1 || digit2 == -1 ) {
+ *d++ = *s++;
+ continue;
+ }
+
+ s += 3;
+ *d++ = ( digit1 << 4 ) + digit2;
+ }
+
+ *d = 0;
+}
+
+void __stdcall HtmlDecode( char* str )
+{
+ char* p, *q;
+
+ if ( str == NULL )
+ return;
+
+ for ( p=q=str; *p!='\0'; p++,q++ ) {
+ if ( *p == '&' ) {
+ if ( !strncmp( p, "&amp;", 5 )) { *q = '&'; p += 4; }
+ else if ( !strncmp( p, "&apos;", 6 )) { *q = '\''; p += 5; }
+ else if ( !strncmp( p, "&gt;", 4 )) { *q = '>'; p += 3; }
+ else if ( !strncmp( p, "&lt;", 4 )) { *q = '<'; p += 3; }
+ else if ( !strncmp( p, "&quot;", 6 )) { *q = '"'; p += 5; }
+ else { *q = *p; }
+ }
+ else {
+ *q = *p;
+ }
+ }
+ *q = '\0';
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// HtmlEncode - replaces special HTML chars
+
+char* __stdcall HtmlEncode( 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* )malloc( c+1 )) != NULL ) {
+ for ( p=( char* )str,q=s; *p!='\0'; p++ ) {
+ switch ( *p ) {
+ case '&': strcpy( q, "&amp;" ); q += 5; break;
+ case '\'': strcpy( q, "&apos;" ); q += 6; break;
+ case '>': strcpy( q, "&gt;" ); q += 4; break;
+ case '<': strcpy( q, "&lt;" ); q += 4; break;
+ case '"': strcpy( q, "&quot;" ); q += 6; break;
+ default: *q = *p; q++; break;
+ }
+ }
+ *q = '\0';
+ }
+
+ return s;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// UrlEncode - converts printable characters into URL chars like %20
+
+void __stdcall UrlEncode( const char* src,char* dest, int cbDest )
+{
+ BYTE* d = ( BYTE* )dest;
+ int i = 0;
+
+ for( const BYTE* s = ( const BYTE* )src; *s; s++ ) {
+ if (( *s < '0' && *s != '.' && *s != '-' ) ||
+ ( *s >= ':' && *s <= '?' ) ||
+ ( *s >= '[' && *s <= '`' && *s != '_' ))
+ {
+ if ( i >= cbDest-4 )
+ break;
+
+ *d++ = '%';
+ _itoa( *s, ( char* )d, 16 );
+ d += 2;
+ i += 3;
+ }
+ else
+ {
+ *d++ = *s;
+ if ( i++ == cbDest-1 )
+ break;
+ } }
+
+ *d = '\0';
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Utf8Decode - converts UTF8-encoded string to the UCS2/MBCS format
+
+void __stdcall Utf8Decode( char* str, wchar_t** ucs2 )
+{
+ if ( str == NULL )
+ return;
+
+ int len = strlen( str );
+ if ( len < 2 ) {
+ if ( ucs2 != NULL ) {
+ *ucs2 = ( wchar_t* )malloc(( len+1 )*sizeof( wchar_t ));
+ MultiByteToWideChar( CP_ACP, 0, str, len, *ucs2, len );
+ ( *ucs2 )[ len ] = 0;
+ }
+ return;
+ }
+
+ wchar_t* tempBuf = ( wchar_t* )alloca(( len+1 )*sizeof( wchar_t ));
+ {
+ wchar_t* d = tempBuf;
+ BYTE* s = ( BYTE* )str;
+
+ while( *s )
+ {
+ if (( *s & 0x80 ) == 0 ) {
+ *d++ = *s++;
+ continue;
+ }
+
+ if (( s[0] & 0xE0 ) == 0xE0 && ( s[1] & 0xC0 ) == 0x80 && ( s[2] & 0xC0 ) == 0x80 ) {
+ *d++ = (( WORD )( s[0] & 0x0F) << 12 ) + ( WORD )(( s[1] & 0x3F ) << 6 ) + ( WORD )( s[2] & 0x3F );
+ s += 3;
+ continue;
+ }
+
+ if (( s[0] & 0xE0 ) == 0xC0 && ( s[1] & 0xC0 ) == 0x80 ) {
+ *d++ = ( WORD )(( s[0] & 0x1F ) << 6 ) + ( WORD )( s[1] & 0x3F );
+ s += 2;
+ continue;
+ }
+
+ *d++ = *s++;
+ }
+
+ *d = 0;
+ }
+
+ if ( ucs2 != NULL ) {
+ int fullLen = ( len+1 )*sizeof( wchar_t );
+ *ucs2 = ( wchar_t* )malloc( fullLen );
+ memcpy( *ucs2, tempBuf, fullLen );
+ }
+
+ WideCharToMultiByte( CP_ACP, 0, tempBuf, -1, str, len, NULL, NULL );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Utf8Encode - converts MBCS string to the UTF8-encoded format
+
+char* __stdcall Utf8Encode( const char* src )
+{
+ if ( src == NULL )
+ return NULL;
+
+ int len = strlen( src );
+ char* result = ( char* )malloc( len*3 + 1 );
+ if ( result == NULL )
+ return NULL;
+
+ wchar_t* tempBuf = ( wchar_t* )alloca(( len+1 )*sizeof( wchar_t ));
+ MultiByteToWideChar( CP_ACP, 0, src, -1, tempBuf, len );
+ tempBuf[ len ] = 0;
+ {
+ wchar_t* s = tempBuf;
+ BYTE* d = ( BYTE* )result;
+
+ while( *s ) {
+ int U = *s++;
+
+ if ( U < 0x80 ) {
+ *d++ = ( BYTE )U;
+ }
+ else if ( U < 0x800 ) {
+ *d++ = 0xC0 + (( U >> 6 ) & 0x3F );
+ *d++ = 0x80 + ( U & 0x003F );
+ }
+ else {
+ *d++ = 0xE0 + ( U >> 12 );
+ *d++ = 0x80 + (( U >> 6 ) & 0x3F );
+ *d++ = 0x80 + ( U & 0x3F );
+ } }
+
+ *d = 0;
+ }
+
+ return result;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Utf8Encode - converts UCS2 string to the UTF8-encoded format
+
+char* __stdcall Utf8EncodeUcs2( const wchar_t* src )
+{
+ int len = wcslen( src );
+ char* result = ( char* )malloc( len*3 + 1 );
+ if ( result == NULL )
+ return NULL;
+
+ { const wchar_t* s = src;
+ BYTE* d = ( BYTE* )result;
+
+ while( *s ) {
+ int U = *s++;
+
+ if ( U < 0x80 ) {
+ *d++ = ( BYTE )U;
+ }
+ else if ( U < 0x800 ) {
+ *d++ = 0xC0 + (( U >> 6 ) & 0x3F );
+ *d++ = 0x80 + ( U & 0x003F );
+ }
+ else {
+ *d++ = 0xE0 + ( U >> 12 );
+ *d++ = 0x80 + (( U >> 6 ) & 0x3F );
+ *d++ = 0x80 + ( U & 0x3F );
+ } }
+
+ *d = 0;
+ }
+
+ return result;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// filetransfer class members
+
+filetransfer::filetransfer()
+{
+ memset( this, 0, sizeof( filetransfer ));
+ fileId = -1;
+ hWaitEvent = INVALID_HANDLE_VALUE;
+ std.cbSize = sizeof( std );
+}
+
+filetransfer::~filetransfer()
+{
+ MSN_DebugLog( "Destroying file transfer session %lu", p2p_sessionid );
+
+ if ( !bCompleted ) {
+ std.files = NULL;
+ std.totalFiles = 0;
+ MSN_SendBroadcast( std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, this, 0);
+ }
+
+ if ( inmemTransfer ) {
+ if ( fileBuffer != NULL )
+ LocalFree( fileBuffer );
+ }
+ else if ( fileId != -1 )
+ _close( fileId );
+
+ if ( mIncomingBoundPort != NULL ) {
+ ThreadData* T = MSN_GetThreadByPort(mIncomingPort);
+ if ( T != NULL && T->s != NULL )
+ {
+ Netlib_CloseHandle( T->s );
+ T->s = NULL;
+ }
+ Netlib_CloseHandle( mIncomingBoundPort );
+ }
+
+ if ( hWaitEvent != INVALID_HANDLE_VALUE )
+ CloseHandle( hWaitEvent );
+
+ if ( p2p_branch != NULL ) free( p2p_branch );
+ if ( p2p_callID != NULL ) free( p2p_callID );
+ if ( p2p_dest != NULL ) free( p2p_dest );
+
+ if ( std.currentFile != NULL ) free( std.currentFile );
+ if ( std.workingDir != NULL ) free( std.workingDir );
+ if ( std.files != NULL ) {
+ for ( int i=0; i < std.totalFiles; i++ )
+ mir_free( std.files[ i ] );
+ mir_free( std.files );
+ }
+
+ if ( wszFileName != NULL ) free( wszFileName );
+ if ( szInvcookie != NULL ) free( szInvcookie );
+}
+
+void filetransfer::close()
+{
+ if ( !inmemTransfer && fileId != -1 ) {
+ _close( fileId );
+ fileId = -1;
+} }
+
+void filetransfer::complete()
+{
+ close();
+
+ bCompleted = true;
+ MSN_SendBroadcast( std.hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, this, 0);
+}
+
+int filetransfer::create()
+{
+ if ( inmemTransfer ) {
+ if ( fileBuffer == NULL ) {
+ if ( std.totalBytes == 0 ) {
+ MSN_DebugLog( "Zero buffer size was requested for avatar" );
+ return -1;
+ }
+
+ if (( fileBuffer = ( char* )LocalAlloc( LPTR, DWORD( std.totalBytes ))) == NULL ) {
+ MSN_DebugLog( "Not enough memory to receive file '%s'", std.currentFile );
+ return -1;
+ } }
+
+ return ( int )fileBuffer;
+ }
+
+ #if defined( _UNICODE )
+ if ( wszFileName != NULL ) {
+ WCHAR wszTemp[ MAX_PATH ];
+ _snwprintf( wszTemp, sizeof wszTemp, L"%S\\%s", std.workingDir, wszFileName );
+ wszTemp[ MAX_PATH-1 ] = 0;
+ fileId = _wopen( wszTemp, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE);
+ if ( fileId != -1 ) {
+ WIN32_FIND_DATAW data;
+ HANDLE hFind = FindFirstFileW( wszFileName, &data );
+ if ( hFind != INVALID_HANDLE_VALUE ) {
+ free( std.currentFile );
+
+ char tShortName[ 20 ];
+ WideCharToMultiByte( CP_ACP, 0,
+ ( data.cAlternateFileName[0] != 0 ) ? data.cAlternateFileName : data.cFileName,
+ -1, tShortName, sizeof tShortName, 0, 0 );
+ char filefull[ MAX_PATH ];
+ mir_snprintf( filefull, sizeof( filefull ), "%s\\%s", std.workingDir, tShortName );
+ std.currentFile = strdup( filefull );
+ FindClose( hFind );
+ } }
+ }
+ else fileId = _open( std.currentFile, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE );
+ #else
+ fileId = _open( std.currentFile, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE );
+ #endif
+
+ if ( fileId == -1 )
+ MSN_DebugLog( "Cannot create file '%s' during a file transfer", std.currentFile );
+// else if ( std.currentFileSize != 0 )
+// _chsize( fileId, std.currentFileSize );
+
+ return fileId;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// TWinErrorCode class
+
+TWinErrorCode::TWinErrorCode() :
+ mErrorText( NULL )
+{
+ mErrorCode = ::GetLastError();
+}
+
+TWinErrorCode::~TWinErrorCode()
+{
+ if ( mErrorText != NULL )
+ ::LocalFree( mErrorText );
+}
+
+char* TWinErrorCode::getText()
+{
+ if ( mErrorText == NULL )
+ {
+ int tBytes = 0;
+
+ if ( mErrorCode >= 12000 && mErrorCode < 12500 )
+ tBytes = FormatMessageA(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
+ ::GetModuleHandleA( "WININET.DLL" ),
+ mErrorCode, LANG_NEUTRAL, (LPSTR)&mErrorText, 0, NULL );
+
+ if ( tBytes == 0 )
+ tBytes = FormatMessageA(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
+ mErrorCode, LANG_NEUTRAL, (LPSTR)&mErrorText, 0, NULL );
+
+ if ( tBytes == 0 )
+ {
+ mErrorText = ( LPSTR )LocalAlloc( LMEM_FIXED, 100 );
+ tBytes = mir_snprintf( mErrorText, 100, "unknown Windows error code %d", mErrorCode );
+ }
+
+ *mErrorText = tolower( *mErrorText );
+
+ if ( mErrorText[ tBytes-1 ] == '\n' )
+ mErrorText[ --tBytes ] = 0;
+ if ( mErrorText[ tBytes-1 ] == '\r' )
+ mErrorText[ --tBytes ] = 0;
+ if ( mErrorText[ tBytes-1 ] == '.' )
+ mErrorText[ tBytes-1 ] = 0;
+ }
+
+ return mErrorText;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// InterlockedIncrement emulation
+
+//I hate Microsoft (c) cyreve
+
+static LONG WINAPI MyInterlockedIncrement95(PLONG pVal)
+{
+ DWORD ret;
+ EnterCriticalSection(&csInterlocked95);
+ ret=++*pVal;
+ LeaveCriticalSection(&csInterlocked95);
+ return ret;
+}
+
+//there's a possible hole here if too many people call this at the same time, but that doesn't happen
+
+static LONG WINAPI MyInterlockedIncrementInit(PLONG pVal)
+{
+ DWORD ver = GetVersion();
+ if (( ver & 0x80000000 ) && LOWORD( ver ) == 0x0004 )
+ {
+ InitializeCriticalSection( &csInterlocked95 );
+ MyInterlockedIncrement = MyInterlockedIncrement95;
+ }
+ else MyInterlockedIncrement = ( pIncrementFunc* )InterlockedIncrement;
+
+ return MyInterlockedIncrement( pVal );
+}
+
+// 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)
+char* EscapeChatTags(char* pszText)
+{
+ int nChars = 0;
+ for ( char* p = pszText; ( p = strchr( p, '%' )) != NULL; p++ )
+ nChars++;
+
+ if ( nChars == 0 )
+ return _strdup( pszText );
+
+ char* pszNewText = (char*)malloc( strlen( pszText ) + 1 + nChars ), *s, *d;
+ if ( pszNewText == NULL )
+ return _strdup( pszText );
+
+ for ( s = pszText, d = pszNewText; *s; s++ ) {
+ if ( *s == '%' )
+ *d++ = '%';
+ *d++ = *s;
+ }
+ *d = 0;
+ return pszNewText;
+}
+
+char* UnEscapeChatTags(char* str_in)
+{
+ char* s = str_in, *d = str_in;
+ while ( *s ) {
+ if (( *s == '%' && s[1] == '%' ) || ( *s == '\n' && s[1] == '\n' ))
+ s++;
+ *d++ = *s++;
+ }
+ *d = 0;
+ return str_in;
+}
diff --git a/miranda-wine/protocols/MSN/msn_msgqueue.cpp b/miranda-wine/protocols/MSN/msn_msgqueue.cpp
new file mode 100644
index 0000000..9fc9458
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_msgqueue.cpp
@@ -0,0 +1,162 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "msn_global.h"
+
+//a few little functions to manage queuing send message requests until the
+//connection is established
+
+static MsgQueueEntry* msgQueue;
+static int msgQueueCount;
+static CRITICAL_SECTION csMsgQueue;
+static int msgQueueSeq;
+
+void MsgQueue_Init( void )
+{
+ msgQueueCount = 0;
+ msgQueue = NULL;
+ msgQueueSeq = 1;
+ InitializeCriticalSection( &csMsgQueue );
+}
+
+void MsgQueue_Uninit( void )
+{
+ MsgQueue_Clear( NULL );
+ DeleteCriticalSection( &csMsgQueue );
+}
+
+int __stdcall MsgQueue_Add( HANDLE hContact, int msgType, const char* msg, int msgSize, filetransfer* ft, int flags )
+{
+ EnterCriticalSection( &csMsgQueue );
+ msgQueue = ( MsgQueueEntry* )realloc( msgQueue, sizeof( MsgQueueEntry )*( msgQueueCount+1 ));
+
+ int seq = msgQueueSeq++;
+
+ MsgQueueEntry& E = msgQueue[ msgQueueCount++ ];
+ E.hContact = hContact;
+ E.msgSize = msgSize;
+ E.msgType = msgType;
+ if ( msgSize <= 0 )
+ E.message = strdup( msg );
+ else
+ memcpy( E.message = ( char* )malloc( msgSize ), msg, msgSize );
+ E.ft = ft;
+ E.seq = seq;
+ E.flags = flags;
+ E.allocatedToThread = 0;
+ E.timeout = DBGetContactSettingDword(NULL, "SRMM", "MessageTimeout", 10000)/1000;
+
+ LeaveCriticalSection( &csMsgQueue );
+ return seq;
+}
+
+// shall we create another session?
+HANDLE __stdcall MsgQueue_CheckContact( HANDLE hContact )
+{
+ EnterCriticalSection( &csMsgQueue );
+
+ HANDLE ret = NULL;
+ for( int i=0; i < msgQueueCount; i++ )
+ {
+ if ( msgQueue[ i ].hContact == hContact )
+ { ret = hContact;
+ break;
+ } }
+
+ LeaveCriticalSection( &csMsgQueue );
+ return ret;
+}
+
+//for threads to determine who they should connect to
+HANDLE __stdcall MsgQueue_GetNextRecipient(void)
+{
+ EnterCriticalSection( &csMsgQueue );
+
+ HANDLE ret = NULL;
+ for( int i=0; i < msgQueueCount; i++ )
+ {
+ MsgQueueEntry& E = msgQueue[ i ];
+ if ( !E.allocatedToThread )
+ {
+ E.allocatedToThread = 1;
+ ret = E.hContact;
+
+ while( ++i < msgQueueCount )
+ if ( msgQueue[i].hContact == ret )
+ msgQueue[i].allocatedToThread = 1;
+
+ break;
+ } }
+
+ LeaveCriticalSection( &csMsgQueue );
+ return ret;
+}
+
+//deletes from list. Must free() return value
+int __stdcall MsgQueue_GetNext( HANDLE hContact, MsgQueueEntry& retVal )
+{
+ int i;
+
+ EnterCriticalSection( &csMsgQueue );
+ for( i=0; i < msgQueueCount; i++ )
+ if ( msgQueue[ i ].hContact == hContact )
+ break;
+
+ if ( i == msgQueueCount )
+ { LeaveCriticalSection(&csMsgQueue);
+ return 0;
+ }
+
+ retVal = msgQueue[ i ];
+
+ msgQueueCount--;
+ memmove( msgQueue+i, msgQueue+i+1, sizeof( MsgQueueEntry )*( msgQueueCount-i ));
+ msgQueue = ( MsgQueueEntry* )realloc( msgQueue, sizeof( MsgQueueEntry )*msgQueueCount );
+ LeaveCriticalSection( &csMsgQueue );
+ return i+1;
+}
+
+void __stdcall MsgQueue_Clear( HANDLE hContact )
+{
+ int i;
+
+ if (hContact == NULL)
+ {
+ EnterCriticalSection( &csMsgQueue );
+
+ for( i=0; i < msgQueueCount; i++ )
+ free ( msgQueue[ i ].message );
+ free( msgQueue );
+
+ msgQueueCount = 0;
+ msgQueue = NULL;
+ msgQueueSeq = 1;
+ LeaveCriticalSection( &csMsgQueue );
+ }
+ else
+ {
+ MsgQueueEntry E;
+ while (MsgQueue_GetNext(hContact, E) != 0)
+ free( E.message );
+ }
+}
diff --git a/miranda-wine/protocols/MSN/msn_opts.cpp b/miranda-wine/protocols/MSN/msn_opts.cpp
new file mode 100644
index 0000000..f47b317
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_opts.cpp
@@ -0,0 +1,866 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "msn_global.h"
+
+#include <commdlg.h>
+#include <direct.h>
+
+#include "resource.h"
+#include "msn_md5.h"
+#include "uxtheme.h"
+
+#define STYLE_DEFAULTBGCOLOUR RGB(173,206,247)
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// External data declarations
+
+extern unsigned long sl;
+extern char *rru;
+
+static BOOL (WINAPI *pfnEnableThemeDialogTexture)(HANDLE, DWORD) = 0;
+
+BOOL CALLBACK DlgProcMsnServLists(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+static void __cdecl sttUploadGroups( void* )
+{
+ HANDLE hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL ) {
+ if ( !lstrcmpA( msnProtocolName, ( char* )MSN_CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact,0 ))) {
+ DBVARIANT dbv;
+ if ( !DBGetContactSettingStringUtf( hContact, "CList", "Group", &dbv )) {
+ MSN_MoveContactToGroup( hContact, dbv.pszVal );
+ MSN_FreeVariant( &dbv );
+ } }
+
+ hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDNEXT,( WPARAM )hContact, 0 );
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN Options dialog procedure
+
+static BOOL CALLBACK DlgProcMsnOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch ( msg ) {
+ case WM_INITDIALOG: {
+ TranslateDialogDefault( hwndDlg );
+
+ char tBuffer[ MAX_PATH ];
+ if ( !MSN_GetStaticString( "e-mail", NULL, tBuffer, sizeof( tBuffer )))
+ SetDlgItemTextA( hwndDlg, IDC_HANDLE, tBuffer );
+
+ if ( !MSN_GetStaticString( "Password", NULL, tBuffer, sizeof( tBuffer ))) {
+ MSN_CallService( MS_DB_CRYPT_DECODESTRING, strlen( tBuffer )+1, ( LPARAM )tBuffer );
+ tBuffer[ 16 ] = 0;
+ SetDlgItemTextA( hwndDlg, IDC_PASSWORD, tBuffer );
+ }
+ SendDlgItemMessage( hwndDlg, IDC_PASSWORD, EM_SETLIMITTEXT, 16, 0 );
+
+ HWND wnd = GetDlgItem( hwndDlg, IDC_HANDLE2 );
+ DBVARIANT dbv;
+ if ( !DBGetContactSettingTString( NULL, msnProtocolName, "Nick", &dbv )) {
+ SetWindowText( wnd, dbv.ptszVal );
+ MSN_FreeVariant( &dbv );
+ }
+ if ( !msnLoggedIn )
+ EnableWindow( wnd, FALSE );
+
+ CheckDlgButton( hwndDlg, IDC_DISABLE_MAIN_MENU, MSN_GetByte( "DisableSetNickname", 0 ));
+ CheckDlgButton( hwndDlg, IDC_ENABLE_AVATARS, MSN_GetByte( "EnableAvatars", 0 ));
+ CheckDlgButton( hwndDlg, IDC_SENDFONTINFO, MSN_GetByte( "SendFontInfo", 1 ));
+ CheckDlgButton( hwndDlg, IDC_USE_OWN_NICKNAME, MSN_GetByte( "NeverUpdateNickname", 0 ));
+ CheckDlgButton( hwndDlg, IDC_AWAY_AS_BRB, MSN_GetByte( "AwayAsBrb", 0 ));
+ CheckDlgButton( hwndDlg, IDC_MANAGEGROUPS, MSN_GetByte( "ManageServer", 0 ));
+
+ int tValue = MSN_GetByte( "RunMailerOnHotmail", 0 );
+ CheckDlgButton( hwndDlg, IDC_RUN_APP_ON_HOTMAIL, tValue );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_MAILER_APP ), tValue );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_ENTER_MAILER_APP ), tValue );
+
+ if ( !MSN_GetStaticString( "MailerPath", NULL, tBuffer, sizeof( tBuffer )))
+ SetDlgItemTextA( hwndDlg, IDC_MAILER_APP, tBuffer );
+
+ if ( !msnLoggedIn ) {
+ EnableWindow( GetDlgItem( hwndDlg, IDC_MANAGEGROUPS ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_DISABLE_ANOTHER_CONTACTS ), FALSE );
+ }
+ else CheckDlgButton( hwndDlg, IDC_DISABLE_ANOTHER_CONTACTS, msnOtherContactsBlocked );
+ return TRUE;
+ }
+
+ case WM_COMMAND:
+ if ( LOWORD( wParam ) == IDC_NEWMSNACCOUNTLINK ) {
+ MSN_CallService( MS_UTILS_OPENURL, 1, ( LPARAM )"http://lc2.law13.hotmail.passport.com/cgi-bin/register" );
+ return TRUE;
+ }
+
+ if ( HIWORD( wParam ) == EN_CHANGE && ( HWND )lParam == GetFocus()) {
+ switch( LOWORD( wParam )) {
+ case IDC_HANDLE: case IDC_PASSWORD: case IDC_LOGINSERVER:
+ case IDC_MSNPORT: case IDC_YOURHOST: case IDC_HANDLE2:
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ } }
+
+ if ( HIWORD( wParam ) == BN_CLICKED )
+ switch( LOWORD( wParam )) {
+ case IDC_ENABLE_AVATARS: {
+ BYTE tIsChosen = IsDlgButtonChecked( hwndDlg, IDC_ENABLE_AVATARS );
+ if ( tIsChosen && MSN_LoadPngModule() == NULL ) {
+ CheckDlgButton( hwndDlg, IDC_ENABLE_AVATARS, 0 );
+ break;
+ }
+
+ EnableWindow( GetDlgItem( hwndDlg, IDC_SETAVATAR ), tIsChosen );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_DELETEAVATAR ), tIsChosen );
+ }
+
+ case IDC_DISABLE_MAIN_MENU: case IDC_SENDFONTINFO:
+ case IDC_DISABLE_ANOTHER_CONTACTS: case IDC_USE_OWN_NICKNAME:
+ case IDC_AWAY_AS_BRB:
+ LBL_Apply:
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ break;
+
+ case IDC_MANAGEGROUPS:
+ if ( IsDlgButtonChecked( hwndDlg, IDC_MANAGEGROUPS ))
+ if ( IDYES == MessageBox( hwndDlg,
+ TranslateT( "Server groups import may change your contact list layout after next login. Do you want to upload your groups to the server?" ),
+ TranslateT( "MSN Protocol" ), MB_YESNOCANCEL ))
+ (new ThreadData())->startThread( sttUploadGroups );
+ goto LBL_Apply;
+
+ case IDC_RUN_APP_ON_HOTMAIL: {
+ BYTE tIsChosen = IsDlgButtonChecked( hwndDlg, IDC_RUN_APP_ON_HOTMAIL );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_MAILER_APP ), tIsChosen );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_ENTER_MAILER_APP ), tIsChosen );
+ goto LBL_Apply;
+ }
+
+ case IDC_ENTER_MAILER_APP: {
+ HWND tEditField = GetDlgItem( hwndDlg, IDC_MAILER_APP );
+
+ char szFile[ MAX_PATH+2 ];
+ GetWindowTextA( tEditField, szFile, sizeof( szFile ));
+
+ int tSelectLen = 0;
+
+ if ( szFile[0] == '\"' ) {
+ char* p = strchr( szFile+1, '\"' );
+ if ( p != NULL ) {
+ *p = '\0';
+ strdel( szFile, 1 );
+ tSelectLen += 2;
+ goto LBL_Continue;
+ } }
+
+ { char* p = strchr( szFile, ' ' );
+ if ( p != NULL )
+ *p = '\0';
+ }
+LBL_Continue:
+ tSelectLen += strlen( szFile );
+
+ OPENFILENAMEA ofn = { 0 };
+ ofn.lStructSize = sizeof( ofn );
+ ofn.hwndOwner = hwndDlg;
+ ofn.nMaxFile = sizeof( szFile );
+ ofn.lpstrFile = szFile;
+ ofn.Flags = OFN_FILEMUSTEXIST;
+ if ( GetOpenFileNameA( &ofn ) != TRUE )
+ break;
+
+ if ( strchr( szFile, ' ' ) != NULL ) {
+ char tmpBuf[ MAX_PATH+2 ];
+ mir_snprintf( tmpBuf, sizeof( tmpBuf ), "\"%s\"", szFile );
+ strcpy( szFile, tmpBuf );
+ }
+
+ SendMessage( tEditField, EM_SETSEL, 0, tSelectLen );
+ SendMessage( tEditField, EM_REPLACESEL, TRUE, LPARAM( szFile ));
+ goto LBL_Apply;
+ } }
+
+ break;
+
+ case WM_NOTIFY:
+ if (((LPNMHDR)lParam)->code == PSN_APPLY ) {
+ bool reconnectRequired = false, restartRequired = false;
+ TCHAR screenStr[ MAX_PATH ], dbStr[ MAX_PATH ];
+ char password[ 100 ];
+ DBVARIANT dbv;
+
+ GetDlgItemText( hwndDlg, IDC_HANDLE, screenStr, sizeof( screenStr ));
+ if ( DBGetContactSettingTString( "e-mail", msnProtocolName, NULL, &dbv ))
+ dbv.ptszVal = NULL;
+ if ( lstrcmp( screenStr, dbStr ))
+ reconnectRequired = true;
+ MSN_SetStringT( NULL, "e-mail", screenStr );
+ MSN_FreeVariant( &dbv );
+
+ GetDlgItemTextA( hwndDlg, IDC_PASSWORD, password, sizeof( password ));
+ MSN_CallService( MS_DB_CRYPT_ENCODESTRING, sizeof( password ),( LPARAM )password );
+ if ( DBGetContactSetting( "Password", msnProtocolName, NULL, &dbv ))
+ dbv.pszVal = NULL;
+ if ( lstrcmp( screenStr, dbStr ))
+ reconnectRequired = true;
+ MSN_SetString( NULL, "Password", password );
+ MSN_FreeVariant( &dbv );
+
+ GetDlgItemText( hwndDlg, IDC_HANDLE2, screenStr, sizeof( screenStr ));
+ if ( !DBGetContactSettingTString( NULL, msnProtocolName, "Nick", &dbv )) {
+ if ( lstrcmp( dbv.ptszVal, screenStr ))
+ MSN_SendNicknameT( screenStr );
+ MSN_FreeVariant( &dbv );
+ }
+ MSN_SetStringT( NULL, "Nick", screenStr );
+
+ BYTE tValue = IsDlgButtonChecked( hwndDlg, IDC_DISABLE_ANOTHER_CONTACTS );
+ if ( tValue != msnOtherContactsBlocked && msnLoggedIn ) {
+ msnNsThread->sendPacket( "BLP", ( tValue ) ? "BL" : "AL" );
+ break;
+ }
+
+ MSN_SetByte( "EnableAvatars", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_ENABLE_AVATARS ));
+ MSN_SetByte( "SendFontInfo", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_SENDFONTINFO ));
+ MSN_SetByte( "RunMailerOnHotmail", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_RUN_APP_ON_HOTMAIL ));
+ MSN_SetByte( "NeverUpdateNickname", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_USE_OWN_NICKNAME ));
+ MSN_SetByte( "DisableSetNickname", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_DISABLE_MAIN_MENU ));
+ MSN_SetByte( "AwayAsBrb", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_AWAY_AS_BRB ));
+ MSN_SetByte( "ManageServer", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_MANAGEGROUPS ));
+
+ GetDlgItemText( hwndDlg, IDC_MAILER_APP, screenStr, sizeof( screenStr ));
+ MSN_SetStringT( NULL, "MailerPath", screenStr );
+
+ if ( reconnectRequired && msnLoggedIn )
+ MessageBox( hwndDlg, TranslateT( "The changes you have made require you to reconnect to the MSN Messenger network before they take effect"), _T("MSN Options"), MB_OK );
+
+ LoadOptions();
+ return TRUE;
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN Connection Options dialog procedure
+
+static BOOL CALLBACK DlgProcMsnConnOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ DBVARIANT dbv;
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ {
+ int tUseGateway = MSN_GetByte( "UseGateway", 0 );
+ CheckDlgButton( hwndDlg, IDC_USEGATEWAY, tUseGateway );
+ if ( tUseGateway ) {
+ SetDlgItemTextA( hwndDlg, IDC_LOGINSERVER, MSN_DEFAULT_GATEWAY );
+ SetDlgItemInt( hwndDlg, IDC_MSNPORT, 80, FALSE );
+ }
+ else {
+ if ( !DBGetContactSetting( NULL, msnProtocolName, "LoginServer", &dbv )) {
+ SetDlgItemTextA( hwndDlg, IDC_LOGINSERVER, dbv.pszVal );
+ MSN_FreeVariant( &dbv );
+ }
+ else SetDlgItemTextA( hwndDlg, IDC_LOGINSERVER, MSN_DEFAULT_LOGIN_SERVER );
+
+ SetDlgItemInt( hwndDlg, IDC_MSNPORT, MSN_GetWord( NULL, "MSNMPort", 1863 ), FALSE );
+ } }
+
+ CheckDlgButton( hwndDlg, IDC_KEEPALIVE, MSN_GetByte( "KeepAlive", 0 ));
+ CheckDlgButton( hwndDlg, IDC_AUTOGETHOST, MSN_GetByte( "AutoGetHost", 1 ));
+ CheckDlgButton( hwndDlg, IDC_USEIEPROXY, MSN_GetByte( "UseIeProxy", 0 ));
+ CheckDlgButton( hwndDlg, IDC_SLOWSEND, MSN_GetByte( "SlowSend", 0 ));
+ CheckDlgButton( hwndDlg, IDC_USEMSNP11, MSN_GetByte( "UseMSNP11", 0 ));
+ CheckDlgButton( hwndDlg, IDC_USEOPENSSL, MSN_GetByte( "UseOpenSSL", 0 ));
+
+ {
+ DWORD ptype = MSN_GetByte( "NLProxyType", 0 );
+ BOOL httpproxy = MyOptions.UseProxy && (ptype == PROXYTYPE_HTTP || ptype == PROXYTYPE_HTTPS);
+ EnableWindow( GetDlgItem( hwndDlg, IDC_USEGATEWAY ), !httpproxy);
+ }
+
+ if ( !DBGetContactSetting( NULL, msnProtocolName, "YourHost", &dbv )) {
+ if ( !MSN_GetByte( "AutoGetHost", 1 ))
+ SetDlgItemTextA( hwndDlg, IDC_YOURHOST, dbv.pszVal );
+ else {
+ if ( msnExternalIP == NULL ) {
+ char ipaddr[ 256 ];
+ gethostname( ipaddr, sizeof( ipaddr ));
+ SetDlgItemTextA( hwndDlg, IDC_YOURHOST, ipaddr );
+ }
+ else SetDlgItemTextA( hwndDlg, IDC_YOURHOST, msnExternalIP );
+ }
+ MSN_FreeVariant( &dbv );
+ }
+ else {
+ char ipaddr[256];
+ gethostname( ipaddr, sizeof( ipaddr ));
+ SetDlgItemTextA( hwndDlg, IDC_YOURHOST, ipaddr );
+ }
+
+ if ( MSN_GetByte( "AutoGetHost", 1 ))
+ EnableWindow( GetDlgItem( hwndDlg, IDC_YOURHOST), FALSE );
+
+ if ( MyOptions.UseGateway ) {
+ EnableWindow( GetDlgItem( hwndDlg, IDC_LOGINSERVER ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_MSNPORT ), FALSE );
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_RESETSERVER:
+ SetDlgItemTextA( hwndDlg, IDC_LOGINSERVER, MSN_DEFAULT_LOGIN_SERVER );
+ SetDlgItemInt( hwndDlg, IDC_MSNPORT, 1863, FALSE );
+ goto LBL_Apply;
+ }
+
+ if ( HIWORD( wParam ) == EN_CHANGE && ( HWND )lParam == GetFocus())
+ switch( LOWORD( wParam )) {
+ case IDC_LOGINSERVER: case IDC_MSNPORT:
+ case IDC_YOURHOST:
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+
+ if ( HIWORD( wParam ) == BN_CLICKED )
+ switch( LOWORD( wParam )) {
+ case IDC_AUTOGETHOST:
+ { int tValue = IsDlgButtonChecked( hwndDlg, IDC_AUTOGETHOST ) ? FALSE : TRUE;
+ EnableWindow( GetDlgItem( hwndDlg, IDC_YOURHOST), tValue );
+ }
+
+ case IDC_KEEPALIVE: case IDC_USEIEPROXY: case IDC_SLOWSEND:
+ case IDC_USEMSNP11: case IDC_USEOPENSSL:
+ LBL_Apply:
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ break;
+
+ case IDC_USEGATEWAY: {
+ bool tValue = !IsDlgButtonChecked( hwndDlg, IDC_USEGATEWAY );
+
+ HWND tWindow = GetDlgItem( hwndDlg, IDC_LOGINSERVER );
+ if ( !tValue ) {
+ SetWindowTextA( tWindow, MSN_DEFAULT_GATEWAY );
+ SetDlgItemInt( hwndDlg, IDC_MSNPORT, 80, FALSE );
+ }
+ else {
+ if ( !DBGetContactSetting( NULL, msnProtocolName, "LoginServer", &dbv )) {
+ SetWindowTextA( tWindow, dbv.pszVal );
+ MSN_FreeVariant( &dbv );
+ }
+ else SetWindowTextA( tWindow, MSN_DEFAULT_LOGIN_SERVER );
+
+ SetDlgItemInt( hwndDlg, IDC_MSNPORT, MSN_GetWord( NULL, "MSNMPort", 1863 ), FALSE );
+ }
+
+ EnableWindow( tWindow, tValue );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_MSNPORT ), tValue );
+ goto LBL_Apply;
+ } }
+ break;
+
+ case WM_NOTIFY:
+ if (((LPNMHDR)lParam)->code == PSN_APPLY ) {
+ bool restartRequired = false, reconnectRequired = false;
+ char str[ MAX_PATH ];
+
+ BYTE tValue = ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_USEGATEWAY );
+ if ( MyOptions.UseGateway != tValue ) {
+ MSN_SetByte( "UseGateway", tValue );
+ restartRequired = true;
+ }
+ if ( !tValue ) {
+ GetDlgItemTextA( hwndDlg, IDC_LOGINSERVER, str, sizeof( str ));
+ MSN_SetString( NULL, "LoginServer", str );
+
+ MSN_SetWord( NULL, "MSNMPort", GetDlgItemInt( hwndDlg, IDC_MSNPORT, NULL, FALSE ));
+ }
+
+ tValue = ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_USEMSNP11 );
+ if ( MyOptions.UseMSNP11 != tValue ) {
+ MSN_SetByte( "UseMSNP11", tValue );
+ if ( msnLoggedIn )
+ reconnectRequired = true;
+ }
+
+ tValue = ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_USEOPENSSL );
+ if ( MSN_GetByte( "UseOpenSSL", 0 ) != tValue ) {
+ MSN_SetByte( "UseOpenSSL", tValue );
+ if ( msnLoggedIn )
+ reconnectRequired = true;
+ }
+
+ MSN_SetByte( "UseIeProxy", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_USEIEPROXY ));
+ MSN_SetByte( "KeepAlive", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_KEEPALIVE ));
+ MSN_SetByte( "AutoGetHost", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_AUTOGETHOST ));
+ MSN_SetByte( "SlowSend", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_SLOWSEND ));
+
+ GetDlgItemTextA( hwndDlg, IDC_YOURHOST, str, sizeof( str ));
+ MSN_SetString( NULL, "YourHost", str );
+
+ if ( restartRequired )
+ MessageBox( hwndDlg, TranslateT( "The changes you have made require you to restart Miranda IM before they take effect"), TranslateT( "MSN Options" ), MB_OK );
+ else if ( reconnectRequired && msnLoggedIn )
+ MessageBox( hwndDlg, TranslateT( "The changes you have made require you to reconnect to the MSN Messenger network before they take effect"), TranslateT( "MSN Options" ), MB_OK );
+
+ LoadOptions();
+ return TRUE;
+ } }
+
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// PopUp Options Dialog: style, position, color, font...
+
+static BOOL CALLBACK DlgProcHotmailPopUpOpts( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ static bool bEnabled;
+
+ switch( msg ) {
+ case WM_INITDIALOG: {
+ TranslateDialogDefault(hwndDlg);
+ bEnabled = false;
+
+ //Colours. First step is configuring the colours.
+ SendDlgItemMessage( hwndDlg, IDC_BGCOLOUR, CPM_SETCOLOUR, 0, MyOptions.BGColour );
+ SendDlgItemMessage( hwndDlg, IDC_TEXTCOLOUR, CPM_SETCOLOUR, 0, MyOptions.TextColour);
+
+ //Second step is disabling them if we want to use default Windows ones.
+ CheckDlgButton( hwndDlg, IDC_USEWINCOLORS, MyOptions.UseWinColors ? BST_CHECKED : BST_UNCHECKED );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_BGCOLOUR), !MyOptions.UseWinColors );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_TEXTCOLOUR), !MyOptions.UseWinColors );
+
+ if ( !ServiceExists( MS_POPUP_ADDPOPUPEX ))
+ EnableWindow( GetDlgItem( hwndDlg, IDC_POPUP_TIMEOUT ), FALSE );
+ else
+ SetDlgItemInt( hwndDlg, IDC_POPUP_TIMEOUT, MyOptions.PopupTimeoutHotmail, FALSE );
+
+ CheckDlgButton( hwndDlg, IDC_DISABLEHOTMAIL, MSN_GetByte( "DisableHotmail", 0 ));
+ CheckDlgButton( hwndDlg, IDC_DISABLEHOTJUNK, MSN_GetByte( "DisableHotmailJunk", 0 ));
+ CheckDlgButton( hwndDlg, IDC_NOTIFY_USERTYPE, MSN_GetByte( "DisplayTyping", 0 ));
+ CheckDlgButton( hwndDlg, IDC_NOTIFY_ENDSESSION, MSN_GetByte( "EnableSessionPopup", 0 ));
+ CheckDlgButton( hwndDlg, IDC_NOTIFY_FIRSTMSG, MSN_GetByte( "EnableDeliveryPopup", 1 ));
+ CheckDlgButton( hwndDlg, IDC_ERRORS_USING_POPUPS, MSN_GetByte( "ShowErrorsAsPopups", 0 ));
+
+ int tTimeout = MSN_GetDword( NULL, "PopupTimeout", 3 );
+ SetDlgItemInt( hwndDlg, IDC_POPUP_TIMEOUT, tTimeout, FALSE );
+ SetDlgItemInt( hwndDlg, IDC_POPUP_TIMEOUT2, MSN_GetDword( NULL, "PopupTimeoutOther", tTimeout ), FALSE );
+ if ( !ServiceExists( MS_POPUP_ADDPOPUPEX )) {
+ EnableWindow( GetDlgItem( hwndDlg, IDC_POPUP_TIMEOUT ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_POPUP_TIMEOUT2 ), FALSE );
+ }
+ bEnabled = true;
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch( LOWORD( wParam )) {
+ case IDC_DISABLEHOTMAIL: {
+ HWND wnd = GetDlgItem( hwndDlg, IDC_DISABLEHOTJUNK );
+ BOOL toSet;
+ if ( SendMessage( HWND( lParam ), BM_GETCHECK, 0, 0 ) == BST_CHECKED ) {
+ SendMessage( wnd, BM_GETCHECK, BST_CHECKED, 0 );
+ toSet = FALSE;
+ }
+ else toSet = TRUE;
+
+ EnableWindow( wnd, toSet );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_POPUP_TIMEOUT ), toSet );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_PREVIEW ), toSet );
+ }
+
+ case IDC_DISABLEHOTJUNK:
+ case IDC_NOTIFY_USERTYPE:
+ case IDC_NOTIFY_ENDSESSION:
+ case IDC_POPUP_TIMEOUT:
+ case IDC_POPUP_TIMEOUT2:
+ case IDC_NOTIFY_FIRSTMSG:
+ case IDC_ERRORS_USING_POPUPS:
+ if ( bEnabled )
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ break;
+
+ case IDC_BGCOLOUR: //Fall through
+ case IDC_TEXTCOLOUR:
+ if ( HIWORD( wParam ) == CPN_COLOURCHANGED ) {
+ MyOptions.BGColour = SendDlgItemMessage( hwndDlg, IDC_BGCOLOUR, CPM_GETCOLOUR, 0, 0 );
+ MyOptions.TextColour = SendDlgItemMessage( hwndDlg, IDC_TEXTCOLOUR, CPM_GETCOLOUR, 0, 0 );
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ break;
+
+ case IDC_USEWINCOLORS:
+ MyOptions.UseWinColors = IsDlgButtonChecked( hwndDlg, IDC_USEWINCOLORS );
+
+ EnableWindow( GetDlgItem( hwndDlg, IDC_BGCOLOUR ), !( MyOptions.UseWinColors ));
+ EnableWindow( GetDlgItem( hwndDlg, IDC_TEXTCOLOUR ), !( MyOptions.UseWinColors ));
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ break;
+
+ case IDC_PREVIEW:
+ MSN_ShowPopup( MSN_Translate( "A New Hotmail has come!" ), MSN_Translate( "Test: Arrival Hotmail" ), MSN_HOTMAIL_POPUP );
+ break;
+
+ case IDC_PREVIEW2:
+ MSN_ShowPopup( "vasya.pupkin@hotmail.com", MSN_Translate( "First message delivered" ), 0 );
+ break;
+ }
+ break;
+
+ case WM_NOTIFY: //Here we have pressed either the OK or the APPLY button.
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_RESET:
+ LoadOptions();
+ return TRUE;
+
+ case PSN_APPLY:
+ MyOptions.TextColour = SendDlgItemMessage(hwndDlg,IDC_TEXTCOLOUR,CPM_GETCOLOUR,0,0);
+ DBWriteContactSettingDword(NULL, ModuleName, "TextColour",MyOptions.TextColour);
+
+ MyOptions.BGColour = SendDlgItemMessage(hwndDlg,IDC_BGCOLOUR,CPM_GETCOLOUR,0,0);
+ DBWriteContactSettingDword(NULL, ModuleName, "BackgroundColour",MyOptions.BGColour);
+
+ if ( ServiceExists( MS_POPUP_ADDPOPUPEX )) {
+ MyOptions.PopupTimeoutHotmail = GetDlgItemInt( hwndDlg, IDC_POPUP_TIMEOUT, NULL, FALSE );
+ MSN_SetDword( NULL, "PopupTimeout", MyOptions.PopupTimeoutHotmail );
+
+ MyOptions.PopupTimeoutOther = GetDlgItemInt( hwndDlg, IDC_POPUP_TIMEOUT2, NULL, FALSE );
+ MSN_SetDword( NULL, "PopupTimeoutOther", MyOptions.PopupTimeoutOther );
+ }
+
+ MyOptions.ShowErrorsAsPopups = ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_ERRORS_USING_POPUPS );
+ MSN_SetByte( "ShowErrorsAsPopups", MyOptions.ShowErrorsAsPopups );
+
+ MSN_SetByte( "UseWinColors", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_USEWINCOLORS ));
+ MSN_SetByte( "DisplayTyping", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_NOTIFY_USERTYPE ));
+ MSN_SetByte( "DisableHotmail", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_DISABLEHOTMAIL ));
+ MSN_SetByte( "DisableHotmailJunk",( BYTE )IsDlgButtonChecked( hwndDlg, IDC_DISABLEHOTJUNK ));
+ MSN_SetByte( "EnableDeliveryPopup", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_NOTIFY_FIRSTMSG ));
+ MSN_SetByte( "EnableSessionPopup", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_NOTIFY_ENDSESSION ));
+ return TRUE;
+ }
+ break;
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+static HWND hwndAcc = 0, hwndConn = 0, hwndSrvList = 0;
+
+static void SetOptionsDlgToType(HWND hwnd, int iExpert)
+{
+ TCITEM tci;
+ RECT rcClient;
+ HWND hwndTab = GetDlgItem(hwnd, IDC_OPTIONSTAB), hwndEnum;
+ int iPages = 0;
+
+ if(!hwndAcc)
+ hwndAcc = CreateDialog(hInst,MAKEINTRESOURCE(IDD_OPT_MSN), hwnd, DlgProcMsnOpts);
+
+ hwndEnum = GetWindow(hwndAcc, GW_CHILD);
+
+ while(hwndEnum) {
+ ShowWindow(hwndEnum, iExpert ? SW_SHOW : SW_HIDE);
+ hwndEnum = GetWindow(hwndEnum, GW_HWNDNEXT);
+ }
+ if(!iExpert) {
+ hwndEnum = GetDlgItem(hwndAcc, IDC_STMSNGROUP);
+ ShowWindow(hwndEnum, SW_SHOW);
+ hwndEnum = GetWindow(hwndEnum, GW_HWNDNEXT);
+ do {
+ ShowWindow(hwndEnum, SW_SHOW);
+ hwndEnum = GetWindow(hwndEnum, GW_HWNDNEXT);
+ } while(hwndEnum && hwndEnum != GetDlgItem(hwndAcc, IDC_NEWMSNACCOUNTLINK));
+ }
+ ShowWindow(hwndEnum, SW_SHOW);
+ GetClientRect(hwnd, &rcClient);
+ TabCtrl_DeleteAllItems(hwndTab);
+
+ tci.mask = TCIF_PARAM|TCIF_TEXT;
+ tci.lParam = (LPARAM)hwndAcc;
+ tci.pszText = TranslateT("Account");
+ TabCtrl_InsertItem(hwndTab, 0, &tci);
+ MoveWindow((HWND)tci.lParam,5,26,rcClient.right-8,rcClient.bottom-29,1);
+ iPages++;
+
+ if(!hwndConn)
+ hwndConn = CreateDialog(hInst,MAKEINTRESOURCE(IDD_OPT_MSN_CONN),hwnd,DlgProcMsnConnOpts);
+
+ if(!hwndSrvList)
+ hwndSrvList = CreateDialog(hInst,MAKEINTRESOURCE(IDD_LISTSMGR),hwnd,DlgProcMsnServLists);
+
+ if(pfnEnableThemeDialogTexture) {
+ if(hwndAcc)
+ pfnEnableThemeDialogTexture(hwndAcc, ETDT_ENABLETAB);
+ if(hwndConn)
+ pfnEnableThemeDialogTexture(hwndConn, ETDT_ENABLETAB);
+ if(hwndSrvList)
+ pfnEnableThemeDialogTexture(hwndSrvList, ETDT_ENABLETAB);
+ }
+
+ ShowWindow(hwndConn, SW_HIDE);
+ ShowWindow(hwndSrvList, SW_HIDE);
+ ShowWindow(hwndAcc, SW_SHOW);
+
+ if(iExpert) {
+ tci.lParam = (LPARAM)hwndConn;
+ tci.pszText = TranslateT("Connection");
+ TabCtrl_InsertItem(hwndTab, iPages++, &tci);
+ MoveWindow((HWND)tci.lParam,5,26,rcClient.right-8,rcClient.bottom-29,1);
+
+ tci.lParam = (LPARAM)hwndSrvList;
+ tci.pszText = TranslateT("Server list");
+ TabCtrl_InsertItem(hwndTab, iPages++, &tci);
+ MoveWindow((HWND)tci.lParam,5,26,rcClient.right-8,rcClient.bottom-29,1);
+ }
+ TabCtrl_SetCurSel(hwndTab, 0);
+}
+
+// handle tabbed options dialog
+
+static BOOL CALLBACK OptionsDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static int iInit = TRUE;
+
+ switch(msg) {
+ case WM_INITDIALOG:
+ {
+ iInit = TRUE;
+ int iExpert = SendMessage(GetParent(hwnd), PSM_ISEXPERT, 0, 0);
+ SetOptionsDlgToType(hwnd, iExpert);
+ iInit = FALSE;
+ return FALSE;
+ }
+ case WM_DESTROY:
+ hwndAcc = hwndConn = hwndSrvList = 0;
+ break;
+ case PSM_CHANGED: // used so tabs dont have to call SendMessage(GetParent(GetParent(hwnd)), PSM_CHANGED, 0, 0);
+ if(!iInit)
+ SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_APPLY:
+ {
+ TCITEM tci;
+ int i,count = TabCtrl_GetItemCount(GetDlgItem(hwnd,IDC_OPTIONSTAB));
+ tci.mask = TCIF_PARAM;
+ for (i=0;i<count;i++) {
+ TabCtrl_GetItem(GetDlgItem(hwnd,IDC_OPTIONSTAB),i,&tci);
+ SendMessage((HWND)tci.lParam,WM_NOTIFY,0,lParam);
+ } }
+ break;
+ case PSN_EXPERTCHANGED:
+ {
+ int iExpert = SendMessage(GetParent(hwnd), PSM_ISEXPERT, 0, 0);
+ SetOptionsDlgToType(hwnd, iExpert);
+ break;
+ } }
+ break;
+ case IDC_OPTIONSTAB:
+ switch (((LPNMHDR)lParam)->code) {
+ case TCN_SELCHANGING:
+ {
+ TCITEM tci;
+ tci.mask = TCIF_PARAM;
+ TabCtrl_GetItem(GetDlgItem(hwnd,IDC_OPTIONSTAB),TabCtrl_GetCurSel(GetDlgItem(hwnd,IDC_OPTIONSTAB)),&tci);
+ ShowWindow((HWND)tci.lParam,SW_HIDE);
+ break;
+ }
+ case TCN_SELCHANGE:
+ {
+ TCITEM tci;
+ tci.mask = TCIF_PARAM;
+ TabCtrl_GetItem(GetDlgItem(hwnd,IDC_OPTIONSTAB),TabCtrl_GetCurSel(GetDlgItem(hwnd,IDC_OPTIONSTAB)),&tci);
+ ShowWindow((HWND)tci.lParam,SW_SHOW);
+ break;
+ } }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Initialize options pages
+
+int MsnOptInit(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ HMODULE hUxTheme = 0;
+
+ if(IsWinVerXPPlus()) {
+ hUxTheme = GetModuleHandle(_T("uxtheme.dll"));
+
+ if(hUxTheme)
+ pfnEnableThemeDialogTexture = (BOOL (WINAPI *)(HANDLE, DWORD))GetProcAddress(hUxTheme, "EnableThemeDialogTexture");
+ }
+
+ odp.cbSize = sizeof(odp);
+ odp.position = -790000000;
+ odp.hInstance = hInst;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_MSNMAIN);
+ odp.pszTitle = msnProtocolName;
+ odp.pszGroup = "Network";
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.pfnDlgProc = OptionsDlgProc;
+ MSN_CallService( MS_OPT_ADDPAGE, wParam,( LPARAM )&odp );
+
+ if ( ServiceExists( MS_POPUP_ADDPOPUP )) {
+ memset( &odp, 0, sizeof( odp ));
+ odp.cbSize = sizeof( odp );
+ odp.position = 100000000;
+ odp.hInstance = hInst;
+ odp.pszTemplate = MAKEINTRESOURCEA( IDD_HOTMAIL_OPT_POPUP );
+ odp.pszTitle = msnProtocolName;
+ odp.pszGroup = "Popups";
+ odp.groupPosition = 910000000;
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.pfnDlgProc = DlgProcHotmailPopUpOpts;
+ MSN_CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Load resident option values into memory
+
+void __stdcall LoadOptions()
+{
+ memset( &MyOptions, 0, sizeof( MyOptions ));
+
+ //PopUp Options
+ MyOptions.BGColour =
+ DBGetContactSettingDword( NULL, ModuleName, "BackgroundColour", STYLE_DEFAULTBGCOLOUR );
+ MyOptions.TextColour =
+ DBGetContactSettingDword( NULL, ModuleName, "TextColour", GetSysColor( COLOR_WINDOWTEXT ));
+
+ MyOptions.AwayAsBrb = MSN_GetByte( "AwayAsBrb", FALSE );
+ MyOptions.DisableMenu = MSN_GetByte( "DisableSetNickname", FALSE );
+ MyOptions.EnableAvatars = MSN_GetByte( "EnableAvatars", FALSE );
+ MyOptions.KeepConnectionAlive = MSN_GetByte( "KeepAlive", FALSE );
+ MyOptions.ManageServer = MSN_GetByte( "ManageServer", FALSE );
+ MyOptions.PopupTimeoutHotmail = MSN_GetDword( NULL, "PopupTimeout", 3 );
+ MyOptions.PopupTimeoutOther = MSN_GetDword( NULL, "PopupTimeoutOther", MyOptions.PopupTimeoutHotmail );
+ MyOptions.ShowErrorsAsPopups = MSN_GetByte( "ShowErrorsAsPopups", FALSE );
+ MyOptions.SlowSend = MSN_GetByte( "SlowSend", FALSE );
+ MyOptions.UseMSNP11 = MSN_GetByte( "UseMSNP11", FALSE );
+ MyOptions.UseProxy = MSN_GetByte( "NLUseProxy", FALSE );
+ MyOptions.UseGateway = MSN_GetByte( "UseGateway", FALSE );
+ MyOptions.UseWinColors = MSN_GetByte( "UseWinColors", FALSE );
+
+ DWORD ptype = MSN_GetByte( "NLProxyType", 0 );
+ BOOL httpproxy = MyOptions.UseProxy && (ptype == PROXYTYPE_HTTP || ptype == PROXYTYPE_HTTPS);
+ if ( httpproxy && !MyOptions.UseGateway)
+ {
+ MyOptions.UseGateway = TRUE;
+ MSN_SetByte( "UseGateway", TRUE );
+ }
+
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Display Hotmail Inbox thread
+
+DWORD WINAPI MsnShowMailThread( LPVOID )
+{
+ DBVARIANT dbv;
+
+ DBGetContactSetting( NULL, msnProtocolName, "e-mail", &dbv );
+ char* email = ( char* )alloca( strlen( dbv.pszVal )*3 );
+ UrlEncode( dbv.pszVal, email, strlen( dbv.pszVal )*3 );
+ MSN_FreeVariant( &dbv );
+
+ DBGetContactSetting( NULL, msnProtocolName, "Password", &dbv );
+ MSN_CallService( MS_DB_CRYPT_DECODESTRING, strlen( dbv.pszVal )+1, ( LPARAM )dbv.pszVal );
+ char* passwd = ( char* )alloca( strlen( dbv.pszVal )*3 );
+ UrlEncode( dbv.pszVal, passwd, strlen( dbv.pszVal )*3 );
+ MSN_FreeVariant( &dbv );
+
+ // for hotmail access
+ int tm = time(NULL) - sl;
+
+ char hippy[ 2048 ];
+ long challen = mir_snprintf( hippy, sizeof( hippy ), "%s%lu%s", MSPAuth, tm, passwd );
+
+ //Digest it
+ unsigned char digest[16];
+ MD5_CTX context;
+ MD5Init( &context);
+ MD5Update( &context, ( BYTE* )hippy, challen );
+ MD5Final( digest, &context );
+
+ if ( rru && passport )
+ {
+ char rruenc[256];
+ UrlEncode(rru, rruenc, sizeof(rruenc));
+
+ mir_snprintf(hippy, sizeof(hippy),
+ "%s&auth=%s&creds=%08x%08x%08x%08x&sl=%d&username=%s&mode=ttl"
+ "&sid=%s&id=2&rru=%s&svc=mail&js=yes",
+ passport, MSPAuth, htonl(*(PDWORD)(digest+0)),htonl(*(PDWORD)(digest+4)),
+ htonl(*(PDWORD)(digest+8)),htonl(*(PDWORD)(digest+12)),
+ tm, email, sid, rruenc);
+ }
+ else
+ strcpy( hippy, "http://go.msn.com/0/1" );
+
+ MSN_DebugLog( "Starting URL: '%s'", hippy );
+ MSN_CallService( MS_UTILS_OPENURL, 1, ( LPARAM )hippy );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Popup plugin window proc
+
+LRESULT CALLBACK NullWindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
+{
+ switch( message ) {
+ case WM_COMMAND: {
+ void* tData = PUGetPluginData( hWnd );
+ if ( tData != NULL ) {
+ DWORD tThreadID;
+ CreateThread( NULL, 0, MsnShowMailThread, hWnd, 0, &tThreadID );
+ PUDeletePopUp( hWnd );
+ }
+ break;
+ }
+
+ case WM_CONTEXTMENU:
+ PUDeletePopUp( hWnd );
+ break;
+ }
+
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
diff --git a/miranda-wine/protocols/MSN/msn_p2p.cpp b/miranda-wine/protocols/MSN/msn_p2p.cpp
new file mode 100644
index 0000000..bde0c9b
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_p2p.cpp
@@ -0,0 +1,1433 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "msn_global.h"
+
+#include <direct.h>
+#include <io.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+struct p2p_threadParams
+{
+ HANDLE s;
+ filetransfer* ft;
+};
+
+static char sttP2Pheader[] =
+ "Content-Type: application/x-msnmsgrp2p\r\n"
+ "P2P-Dest: %s\r\n\r\n";
+
+static char sttVoidNonce[] = "{00000000-0000-0000-0000-000000000000}";
+
+static void sttLogHeader( P2P_Header* hdrdata )
+{
+ MSN_DebugLog( "--- Printing message header" );
+ MSN_DebugLog( " SessionID = %lu", hdrdata->mSessionID );
+ MSN_DebugLog( " MessageID = %lu", hdrdata->mID );
+ MSN_DebugLog( " Offset of data = %I64u", hdrdata->mOffset );
+ MSN_DebugLog( " Total amount of data = %I64u", hdrdata->mTotalSize );
+ MSN_DebugLog( " Data in packet = %lu bytes", hdrdata->mPacketLen );
+ MSN_DebugLog( " Flags = %08X", hdrdata->mFlags );
+ MSN_DebugLog( " Acknowledged session ID: %lu", hdrdata->mAckSessionID );
+ MSN_DebugLog( " Acknowledged message ID: %lu", hdrdata->mAckUniqueID );
+ MSN_DebugLog( " Acknowledged data size: %I64u", hdrdata->mAckDataSize );
+ MSN_DebugLog( "------------------------" );
+}
+
+static bool sttIsCancelCommand( const BYTE* p )
+{
+ if ( !memcmp( p, "BYE MSNMSGR:", 12 ))
+ return true;
+
+ return ( memcmp( p, "MSNSLP/1.0 603 ", 15 ) == 0 );
+}
+
+static char* getNewUuid()
+{
+ BYTE* p;
+ UUID id;
+
+ UuidCreate( &id );
+ UuidToStringA( &id, &p );
+ int len = strlen(( const char* )p );
+ char* result = ( char* )malloc( len+3 );
+ result[0]='{';
+ memcpy( result+1, p, len );
+ result[ len+1 ] = '}';
+ result[ len+2 ] = 0;
+ strupr( result );
+ RpcStringFreeA( &p );
+ return result;
+}
+
+static int sttCreateListener(
+ ThreadData* info,
+ filetransfer* ft,
+ pThreadFunc thrdFunc,
+ char* szBody, size_t cbBody )
+{
+ char ipaddr[256];
+ if ( MSN_GetMyHostAsString( ipaddr, sizeof( ipaddr ))) {
+ MSN_DebugLog( "Cannot detect my host address" );
+ return 0;
+ }
+
+ NETLIBBIND nlb = {0};
+ nlb.cbSize = sizeof( nlb );
+ nlb.pfnNewConnectionV2 = MSN_ConnectionProc;
+ nlb.wPort = 0; // Use user-specified incoming port ranges, if available
+ if (( ft->mIncomingBoundPort = (HANDLE) MSN_CallService(MS_NETLIB_BINDPORT, (WPARAM) hNetlibUser, ( LPARAM )&nlb)) == NULL ) {
+ MSN_DebugLog( "Unable to bind the port for incoming transfers" );
+ return 0;
+ }
+
+ ft->mIncomingPort = nlb.wPort;
+
+ char* szUuid = getNewUuid();
+ {
+ ThreadData* newThread = new ThreadData;
+ newThread->mType = SERVER_P2P_DIRECT;
+ newThread->mCaller = 3;
+ newThread->mP2pSession = ft;
+ newThread->mParentThread = info;
+ strncpy( newThread->mCookie, ( char* )szUuid, sizeof( newThread->mCookie ));
+ ft->hWaitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+
+ newThread->startThread( thrdFunc );
+ }
+
+ char hostname[256];
+
+ gethostname( hostname, sizeof( hostname ));
+ PHOSTENT he = gethostbyname( hostname );
+
+ hostname[0] = 0;
+ for( unsigned i=0; i<sizeof( hostname )/16 && he->h_addr_list[i] ; ++i ) {
+ if ( i != 0 ) strcat( hostname, " " );
+ strcat( hostname, inet_ntoa( *( PIN_ADDR )he->h_addr_list[i] ));
+ }
+
+ int cbBodyLen = mir_snprintf( szBody, cbBody,
+ "Bridge: TCPv1\r\n"
+ "Listening: true\r\n"
+ "Nonce: %s\r\n"
+ "IPv4External-Addrs: %s\r\n"
+ "IPv4External-Port: %u\r\n"
+ "IPv4Internal-Addrs: %s\r\n"
+ "IPv4Internal-Port: %u\r\n"
+ "SessionID: %lu\r\n"
+ "SChannelState: 0\r\n\r\n%c",
+ szUuid,
+ ipaddr, nlb.wExPort,
+ hostname, ft->mIncomingPort,
+ ft->p2p_sessionid, 0 );
+ free( szUuid );
+
+ return cbBodyLen;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// sttSavePicture2disk - final handler for avatars downloading
+
+static void sttSavePicture2disk( ThreadData* info, filetransfer* ft )
+{
+ if ( !ft->inmemTransfer )
+ return;
+
+ //---- Save temporary PNG image to disk --------------------
+ #if defined( _DEBUG )
+ char* Path = getenv( "TEMP" );
+ if ( Path == NULL )
+ Path = getenv( "TMP" );
+
+ char tPathName[ MAX_PATH ];
+ if ( Path == NULL ) {
+ MSN_DebugLog( "Temporary file is created in the current directory: %s",
+ getcwd( tPathName, sizeof( tPathName )));
+ }
+ else {
+ MSN_DebugLog( "Temporary path found: %s", Path );
+ strcpy( tPathName, Path );
+ }
+
+ strcat( tPathName, "\\avatar.png" );
+ MSN_DebugLog( "Opening temporary file '%s'", tPathName );
+ { FILE* out = fopen( tPathName, "wb" );
+ if ( out ) {
+ fwrite( ft->fileBuffer, ft->std.totalBytes, 1, out );
+ fclose( out );
+ } }
+ #endif
+
+ //---- Converting memory buffer to bitmap and saving it to disk
+ if ( !MSN_LoadPngModule() )
+ return;
+
+ BITMAPINFOHEADER* pDib;
+ PNG2DIB convert;
+ convert.pSource = (BYTE*)ft->fileBuffer;
+ convert.cbSourceSize = ft->std.totalBytes;
+ convert.pResult = &pDib;
+ if ( !CallService( MS_PNG2DIB, 0, (LPARAM)&convert ))
+ return;
+
+ HANDLE hContact;
+ if ( info->mJoinedContacts == NULL ) {
+ if ( info->mParentThread == NULL )
+ goto LBL_Exit;
+
+ if ( info->mParentThread->mJoinedContacts == NULL )
+ goto LBL_Exit;
+
+ hContact = info->mParentThread->mJoinedContacts[0];
+ }
+ else hContact = info->mJoinedContacts[0];
+
+ if ( hContact != NULL ) {
+ PROTO_AVATAR_INFORMATION AI;
+ AI.cbSize = sizeof( AI );
+ AI.format = PA_FORMAT_BMP;
+ AI.hContact = hContact;
+ MSN_GetAvatarFileName( hContact, AI.filename, sizeof( AI.filename ));
+ FILE* out = fopen( AI.filename, "wb" );
+ if ( out != NULL ) {
+ BITMAPFILEHEADER tHeader = { 0 };
+ tHeader.bfType = 0x4d42;
+ tHeader.bfOffBits = sizeof( tHeader ) + sizeof( BITMAPINFOHEADER );
+ tHeader.bfSize = tHeader.bfOffBits + pDib->biSizeImage;
+ fwrite( &tHeader, sizeof( tHeader ), 1, out );
+ fwrite( pDib, sizeof( BITMAPINFOHEADER ), 1, out );
+ fwrite( pDib+1, pDib->biSizeImage, 1, out );
+ fclose( out );
+
+ MSN_SendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, HANDLE( &AI ), NULL );
+ }
+ else MSN_SendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, HANDLE( &AI ), NULL );
+ }
+
+LBL_Exit:
+ GlobalFree( pDib );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// p2p_sendAck - sends MSN P2P acknowledgement to the received message
+
+static char sttVoidSession[] = "ACHTUNG!!! an attempt made to send a message via the empty session";
+
+void __stdcall p2p_sendAck( filetransfer* ft, ThreadData* info, P2P_Header* hdrdata )
+{
+ if ( ft == NULL || info == NULL ) {
+ MSN_DebugLog( sttVoidSession );
+ return;
+ }
+
+ char* buf = ( char* )alloca( 1000 + strlen( ft->p2p_dest ));
+ char* p = buf + sprintf( buf, sttP2Pheader, ft->p2p_dest );
+
+ P2P_Header* tHdr = ( P2P_Header* )p; p += sizeof( P2P_Header );
+ memset( tHdr, 0, sizeof( P2P_Header ));
+ tHdr->mSessionID = hdrdata->mSessionID;
+ tHdr->mID = ++ft->p2p_msgid;
+ tHdr->mAckDataSize = hdrdata->mTotalSize;
+ tHdr->mTotalSize = hdrdata->mTotalSize;
+ tHdr->mFlags = 2;
+ tHdr->mAckSessionID = hdrdata->mID;
+ tHdr->mAckUniqueID = hdrdata->mAckSessionID;
+ *( long* )p = 0; p += sizeof( long );
+
+ if ( info->mType == SERVER_P2P_DIRECT ) {
+ DWORD *p2pPacket = (DWORD*)tHdr-1;
+ *p2pPacket = sizeof( P2P_Header );
+ info->send(( char* )p2pPacket, sizeof( P2P_Header ) + sizeof( DWORD ));
+ }
+ else info->sendRawMessage( 'D', buf, int( p - buf ));
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// p2p_sendEndSession - sends MSN P2P file transfer end packet
+
+static void __stdcall p2p_sendEndSession( ThreadData* info, filetransfer* ft )
+{
+ if ( ft == NULL || info == NULL ) {
+ MSN_DebugLog( sttVoidSession );
+ return;
+ }
+
+ char* buf = ( char* )alloca( 1000 + strlen( ft->p2p_dest ));
+ char* p = buf + sprintf( buf, sttP2Pheader, ft->p2p_dest );
+
+ P2P_Header* tHdr = ( P2P_Header* )p; p += sizeof( P2P_Header );
+ memset( tHdr, 0, sizeof( P2P_Header ));
+ tHdr->mSessionID = ft->p2p_sessionid;
+
+ tHdr->mAckSessionID = ft->p2p_sendmsgid;
+
+ if ( ft->std.sending)
+ {
+ tHdr->mFlags = 0x40;
+ tHdr->mID = ++ft->p2p_msgid;
+ tHdr->mAckSessionID = tHdr->mID - 2;
+ }
+ else
+ {
+ tHdr->mID = ++ft->p2p_msgid;
+ tHdr->mAckUniqueID = 0x8200000f;
+ tHdr->mFlags = 0x80;
+ tHdr->mAckDataSize = ft->std.currentFileSize;
+ }
+
+ if ( info->mType == SERVER_P2P_DIRECT ) {
+ DWORD *p2pPacket = (DWORD*)tHdr-1;
+ *p2pPacket = sizeof( P2P_Header );
+ info->send(( char* )p2pPacket, sizeof( P2P_Header ) + sizeof( DWORD ));
+ }
+ else info->sendRawMessage( 'D', buf, int( p - buf ));
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// p2p_sendSlp - send MSN P2P SLP packet
+
+void __stdcall p2p_sendSlp(
+ ThreadData* info,
+ filetransfer* ft,
+ MimeHeaders& pHeaders,
+ int iKind,
+ const char* szContent,
+ size_t szContLen )
+{
+ if ( ft == NULL ) {
+ MSN_DebugLog( sttVoidSession );
+ return;
+ }
+
+ char szMyEmail[ MSN_MAX_EMAIL_LEN ];
+ MSN_GetStaticString( "e-mail", NULL, szMyEmail, sizeof( szMyEmail ));
+
+ char* buf = ( char* )alloca( 1000 + szContLen + pHeaders.getLength());
+ char* p = buf;
+
+ if ( info == NULL || info->mType != SERVER_P2P_DIRECT )
+ p += sprintf( p, sttP2Pheader, ft->p2p_dest );
+ else
+ p += sizeof( DWORD );
+
+ P2P_Header* tHdr = ( P2P_Header* )p; p += sizeof( P2P_Header );
+ memset( tHdr, 0, sizeof( P2P_Header ));
+
+ char* pktStart = p;
+
+ switch ( iKind ) {
+ case 200: p += sprintf( p, "MSNSLP/1.0 200 OK" ); break;
+ case 603: p += sprintf( p, "MSNSLP/1.0 603 DECLINE" ); break;
+ case -1: p += sprintf( p, "BYE MSNMSGR:%s MSNSLP/1.0", ft->p2p_dest ); break;
+ case -2: p += sprintf( p, "INVITE MSNMSGR:%s MSNSLP/1.0", ft->p2p_dest ); break;
+ default: return;
+ }
+
+ p += sprintf( p,
+ "\r\nTo: <msnmsgr:%s>\r\n"
+ "From: <msnmsgr:%s>\r\n"
+ "Via: MSNSLP/1.0/TLP ;branch=%s\r\n", ft->p2p_dest, szMyEmail, ft->p2p_branch );
+
+ p = pHeaders.writeToBuffer( p );
+
+ p += sprintf( p, "Content-Length: %d\r\n\r\n", szContLen );
+ memcpy( p, szContent, szContLen );
+ p += szContLen;
+ tHdr->mID = ++ft->p2p_msgid;
+ tHdr->mAckSessionID = ft->p2p_acksessid;
+ tHdr->mTotalSize = tHdr->mPacketLen = int( p - pktStart );
+
+ if (iKind == 603)
+ ft->p2p_byemsgid = ft->p2p_msgid;
+
+ *( DWORD* )p = 0; p += sizeof( DWORD );
+
+ if ( info == NULL ) {
+ MsgQueue_Add( ft->std.hContact, 'D', buf, int( p - buf ), NULL );
+ msnNsThread->sendPacket( "XFR", "SB" );
+ }
+ else if ( info->mType == SERVER_P2P_DIRECT ) {
+ DWORD *p2pPacket = (DWORD*)tHdr-1;
+ *p2pPacket = p - buf - 2 * sizeof( DWORD );
+ info->send(( char* )p2pPacket, *p2pPacket + sizeof( DWORD ));
+ }
+ else info->sendRawMessage( 'D', buf, int( p - buf ));
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// p2p_sendBye - closes P2P session
+
+void __stdcall p2p_sendBye( ThreadData* info, filetransfer* ft )
+{
+ if ( ft == NULL || info == NULL ) {
+ MSN_DebugLog( sttVoidSession );
+ return;
+ }
+
+ MimeHeaders tHeaders(5);
+ tHeaders.addString( "CSeq", "0 " );
+ tHeaders.addString( "Call-ID", ft->p2p_callID );
+ tHeaders.addLong( "Max-Forwards", 0 );
+ tHeaders.addString( "Content-Type", "application/x-msnmsgr-sessionclosebody" );
+
+ char szContents[ 50 ];
+ p2p_sendSlp( info, ft, tHeaders, -1, szContents,
+ mir_snprintf( szContents, sizeof( szContents ), "SessionID: %lu\r\nSChannelState: 0\r\n\r\n%c",
+ ft->p2p_sessionid, 0 ));
+ ft->p2p_byemsgid = ft->p2p_msgid;
+}
+
+void __stdcall p2p_sendCancel( ThreadData* info, filetransfer* ft )
+{
+ p2p_sendBye(info, ft);
+ p2p_sendEndSession(info, ft);
+ ft->bCanceled = true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// p2p_sendStatus - send MSN P2P status and its description
+
+void __stdcall p2p_sendStatus( filetransfer* ft, ThreadData* info, long lStatus )
+{
+ if ( ft == NULL || info == NULL ) {
+ MSN_DebugLog( sttVoidSession );
+ return;
+ }
+
+ MimeHeaders tHeaders( 5 );
+ tHeaders.addString( "CSeq", "1 " );
+ tHeaders.addString( "Call-ID", ft->p2p_callID );
+ tHeaders.addLong( "Max-Forwards", 0 );
+ tHeaders.addString( "Content-Type", "application/x-msnmsgr-sessionreqbody" );
+
+ char szContents[ 50 ];
+ p2p_sendSlp( info, ft, tHeaders, lStatus, szContents,
+ mir_snprintf( szContents, sizeof( szContents ), "SessionID: %lu\r\nSChannelState: 0\r\n\r\n%c",
+ ft->p2p_sessionid, 0 ));
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// p2p_connectTo - connects to a remote P2P server
+
+static char p2p_greeting[8] = { 4, 0, 0, 0, 'f', 'o', 'o', 0 };
+
+static void sttSendPacket( ThreadData* T, P2P_Header& hdr )
+{
+ DWORD len = sizeof( P2P_Header );
+ T->send(( char* )&len, sizeof( DWORD ));
+ T->send(( char* )&hdr, sizeof( P2P_Header ));
+}
+
+bool p2p_connectTo( ThreadData* info )
+{
+ filetransfer* ft = info->mP2pSession;
+
+ NETLIBOPENCONNECTION tConn = { 0 };
+ tConn.cbSize = sizeof( tConn );
+ tConn.flags = NLOCF_V2;
+ tConn.szHost = info->mServer;
+ tConn.timeout = 5;
+ {
+ char* tPortDelim = strrchr( info->mServer, ':' );
+ if ( tPortDelim != NULL ) {
+ *tPortDelim = '\0';
+ tConn.wPort = ( WORD )atol( tPortDelim+1 );
+ } }
+
+ while( true ) {
+ char* pSpace = strchr( info->mServer, ' ' );
+ if ( pSpace != NULL )
+ *pSpace = 0;
+
+ MSN_DebugLog( "Connecting to %s:%d", info->mServer, tConn.wPort );
+
+ HANDLE h = ( HANDLE )MSN_CallService( MS_NETLIB_OPENCONNECTION, ( WPARAM )hNetlibUser, ( LPARAM )&tConn );
+ if ( h != NULL ) {
+ info->s = h;
+ ft->mThreadId = info->mUniqueID;
+ break;
+ }
+ { TWinErrorCode err;
+ MSN_DebugLog( "Connection Failed (%d): %s", err.mErrorCode, err.getText() );
+ }
+
+ if ( pSpace == NULL ) {
+ if ( ft->std.sending )
+ MSN_PingParentThread( info->mParentThread, ft );
+ return false;
+ }
+
+ strdel( info->mServer, int( pSpace - info->mServer )+1 );
+ }
+
+ info->send( p2p_greeting, sizeof( p2p_greeting ));
+
+ P2P_Header reply;
+ memset( &reply, 0, sizeof( P2P_Header ));
+ reply.mID = ++ft->p2p_msgid;
+ reply.mFlags = 0x100;
+
+ strdel( info->mCookie, 1 );
+ info->mCookie[ strlen( info->mCookie )-1 ] = 0;
+ UuidFromStringA(( BYTE* )info->mCookie, ( UUID* )&reply.mAckSessionID );
+ sttSendPacket( info, reply );
+
+ long cbPacketLen;
+ HReadBuffer buf( info, 0 );
+ BYTE* p;
+ if (( p = buf.surelyRead( 4 )) == NULL ) {
+ MSN_DebugLog( "Error reading data, closing filetransfer" );
+ return false;
+ }
+
+ cbPacketLen = *( long* )p;
+ if (( p = buf.surelyRead( cbPacketLen )) == NULL )
+ return false;
+
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// p2p_listen - acts like a local P2P server
+
+bool p2p_listen( ThreadData* info )
+{
+ filetransfer* ft = info->mP2pSession;
+ DWORD ftID = ft->p2p_sessionid;
+
+ switch( WaitForSingleObject( ft->hWaitEvent, 5000 )) {
+ case WAIT_TIMEOUT:
+ case WAIT_FAILED:
+ MSN_DebugLog( "Incoming connection timed out, closing file transfer" );
+ if (( ft = p2p_getSessionByID( ftID )) != NULL )
+ if ( ft->std.sending )
+ MSN_PingParentThread( info->mParentThread, ft );
+LBL_Error:
+ MSN_DebugLog( "File transfer failed" );
+ return false;
+ }
+
+ HReadBuffer buf( info, 0 );
+ BYTE* p;
+
+ ft->mThreadId = info->mUniqueID;
+
+ if (( p = buf.surelyRead( 8 )) == NULL )
+ goto LBL_Error;
+
+ if ( memcmp( p, p2p_greeting, 8 ) != NULL ) {
+ MSN_DebugLog( "Invalid input data, exiting" );
+ goto LBL_Error;
+ }
+
+ if (( p = buf.surelyRead( 4 )) == NULL ) {
+ MSN_DebugLog( "Error reading data, closing filetransfer" );
+ goto LBL_Error;
+ }
+
+ long cbPacketLen = *( long* )p;
+ if (( p = buf.surelyRead( cbPacketLen )) == NULL )
+ goto LBL_Error;
+
+ UUID uuidCookie;
+ strdel( info->mCookie, 1 );
+ info->mCookie[ strlen(info->mCookie)-1 ] = 0;
+ UuidFromStringA(( BYTE* )info->mCookie, &uuidCookie );
+
+ P2P_Header* pCookie = ( P2P_Header* )p;
+ if ( memcmp( &pCookie->mAckSessionID, &uuidCookie, sizeof( UUID ))) {
+ MSN_DebugLog( "Invalid input cookie, exiting" );
+ goto LBL_Error;
+ }
+
+ pCookie->mID = ++ft->p2p_msgid;
+ sttSendPacket( info, *pCookie );
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// p2p_sendFeedThread - sends a file via server
+
+void __cdecl p2p_sendFeedThread( ThreadData* info )
+{
+ HANDLE s = info->s; info->s = NULL;
+ filetransfer* ft = info->mP2pSession;
+
+ if ( ft->p2p_sendmsgid == 0 )
+ ft->p2p_sendmsgid = ++ft->p2p_msgid;
+
+ while ( ft->std.currentFileProgress < ft->std.currentFileSize )
+ {
+ if ( ft->bCanceled ) {
+ MSN_DebugLog( "File transfer canceled" );
+ break;
+ }
+
+ ThreadData* T = MSN_GetThreadByConnection( s );
+ if ( T == NULL || p2p_sendPortion( ft, T ) == 0 ) {
+ MSN_DebugLog( "File transfer failed" );
+ break;
+} } }
+
+void __stdcall p2p_sendFeedStart( filetransfer* ft, ThreadData* T )
+{
+ if ( ft->std.sending )
+ {
+ ThreadData* newThread = new ThreadData;
+ newThread->mType = SERVER_FILETRANS;
+ newThread->mP2pSession = ft;
+ newThread->s = T->s;
+ newThread->startThread(( pThreadFunc )p2p_sendFeedThread );
+} }
+
+LONG __stdcall p2p_sendPortion( filetransfer* ft, ThreadData* T )
+{
+ LONG trid;
+ char databuf[ 1500 ], *p = databuf;
+
+ // Compute the amount of data to send
+ const long fportion = T->mType == SERVER_P2P_DIRECT ? 1352 : 1202;
+ const unsigned long portion =
+ ( fportion + ft->std.currentFileProgress > ft->std.currentFileSize ) ?
+ ft->std.currentFileSize - ft->std.currentFileProgress : fportion;
+
+ // Fill data size for direct transfer
+
+ if ( T->mType != SERVER_P2P_DIRECT )
+ p += sprintf( p, sttP2Pheader, ft->p2p_dest );
+ else
+ {
+ *( unsigned long* )p = portion + sizeof( P2P_Header );
+ p += sizeof( unsigned long );
+ }
+
+ // Fill P2P header
+ P2P_Header* H = ( P2P_Header* ) p;
+ p += sizeof( P2P_Header );
+
+ memset( H, 0, sizeof( P2P_Header ));
+ H->mSessionID = ft->p2p_sessionid;
+ H->mID = ft->p2p_sendmsgid;
+ H->mFlags = ft->p2p_appID == 2 ? 0x01000030 : 0x20;
+ H->mTotalSize = ft->std.currentFileSize;
+ H->mOffset = ft->std.currentFileProgress;
+ H->mPacketLen = portion;
+ H->mAckSessionID = ft->p2p_acksessid;
+
+ // Fill data (payload) for transfer
+ ::read( ft->fileId, p, portion );
+ p += portion;
+
+ if ( T->mType == SERVER_P2P_DIRECT )
+ trid = T->send( databuf, p - databuf);
+ else
+ {
+ // Define packet footer for server transfer
+ *( unsigned long * )p = htonl(ft->p2p_appID);
+ p += sizeof( unsigned long );
+
+ trid = T->sendRawMessage( 'D', ( char * )databuf, p - databuf);
+ }
+
+ ft->std.totalProgress += portion;
+ ft->std.currentFileProgress += portion;
+ if ( ft->p2p_appID == 2 )
+ MSN_SendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, ( LPARAM )&ft->std );
+
+ return trid;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// p2p_sendFileDirectly - sends a file via MSN P2P protocol
+
+void p2p_sendRecvFileDirectly( ThreadData* info )
+{
+ BYTE* p;
+
+ p2p_sendFeedStart( info->mP2pSession, info );
+
+ HReadBuffer buf( info, 0 );
+ for ( ;; ) {
+ if (( p = buf.surelyRead( 4 )) == NULL ) {
+ info->mP2pSession->bCanceled = true;
+ MSN_DebugLog( "File transfer failed" );
+ break;
+ }
+
+ long cbPacketLen = *( long* )p;
+ if (( p = buf.surelyRead( cbPacketLen )) == NULL ) {
+ info->mP2pSession->bCanceled = true;
+ MSN_DebugLog( "File transfer failed" );
+ break;
+ }
+
+ p2p_processMsg( info, (char*)p );
+
+ if ( !p2p_sessionRegistered( info->mP2pSession ))
+ break;
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// bunch of thread functions to cover all variants of P2P file transfers
+
+void __cdecl p2p_fileActiveThread( ThreadData* info )
+{
+ MSN_DebugLog( "p2p_fileActiveThread() started: connecting to '%s'", info->mServer );
+
+ if ( p2p_connectTo( info ))
+ p2p_sendRecvFileDirectly( info );
+}
+
+void __cdecl p2p_filePassiveThread( ThreadData* info )
+{
+ MSN_DebugLog( "p2p_filePassiveThread() started: listening" );
+
+ if ( p2p_listen( info ))
+ p2p_sendRecvFileDirectly( info );
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// p2p_processMsg - processes all MSN P2P incoming messages
+
+static void sttInitFileTransfer(
+ P2P_Header* hdrdata,
+ ThreadData* info,
+ MimeHeaders& tFileInfo,
+ MimeHeaders& tFileInfo2,
+ const char* msgbody )
+{
+ char szMyEmail[ MSN_MAX_EMAIL_LEN ], szContactEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( MSN_GetStaticString( "e-mail", info->mJoinedContacts[0], szContactEmail, sizeof( szContactEmail )))
+ return;
+
+ MSN_GetStaticString( "e-mail", NULL, szMyEmail, sizeof( szMyEmail ));
+
+ const char *szCallID = tFileInfo[ "Call-ID" ],
+ *szBranch = tFileInfo[ "Via" ];
+
+ if ( szBranch != NULL ) {
+ szBranch = strstr( szBranch, "branch=" );
+ if ( szBranch != NULL )
+ szBranch += 7;
+ }
+ if ( szCallID == NULL || szBranch == NULL ) {
+ MSN_DebugLog( "Ignoring invalid invitation: CallID='%s', szBranch='%s'", szCallID, szBranch );
+ return;
+ }
+
+ char* szContext = NULL;
+ long dwAppID = -1;
+
+ const char *szSessionID = tFileInfo2[ "SessionID" ],
+ *szEufGuid = tFileInfo2[ "EUF-GUID" ];
+ { const char* p = tFileInfo2[ "AppID" ];
+ if ( p )
+ dwAppID = atol( p );
+ if ( dwAppID == 12 )
+ dwAppID = 1;
+ }
+ { const char* p = tFileInfo2[ "Context" ];
+ if ( p ) {
+ int cbLen = strlen( p );
+ szContext = ( char* )alloca( cbLen+1 );
+
+ NETLIBBASE64 nlb = { ( char* )p, cbLen, ( PBYTE )szContext, cbLen };
+ MSN_CallService( MS_NETLIB_BASE64DECODE, 0, LPARAM( &nlb ));
+ } }
+
+ if ( szContext == NULL && memcmp( msgbody, "Context: ", 9 ) == 0 ) {
+ msgbody += 9;
+ int cbLen = strlen( msgbody );
+ if ( cbLen > 252 )
+ cbLen = 252;
+ szContext = ( char* )alloca( cbLen+1 );
+
+ NETLIBBASE64 nlb = { ( char* )msgbody, cbLen, ( PBYTE )szContext, cbLen };
+ MSN_CallService( MS_NETLIB_BASE64DECODE, 0, LPARAM( &nlb ));
+ }
+
+ if ( szSessionID == NULL || dwAppID == -1 || szEufGuid == NULL ) {
+ MSN_DebugLog( "Ignoring invalid invitation: SessionID='%s', AppID=%ld, Branch='%s'", szSessionID, dwAppID, szEufGuid );
+ return;
+ }
+
+ srand( time( NULL ));
+
+ filetransfer* ft = new filetransfer();
+ ft->p2p_appID = dwAppID;
+ ft->p2p_acksessid = 0x024F0000 + rand();
+ ft->p2p_sessionid = strtoul( szSessionID, NULL, 10 );
+ ft->p2p_msgid = ft->p2p_acksessid + 5;
+ ft->p2p_ackID = ft->p2p_appID * 1000;
+ replaceStr( ft->p2p_callID, szCallID );
+ replaceStr( ft->p2p_branch, szBranch );
+ ft->p2p_dest = strdup( szContactEmail );
+ ft->mThreadId = info->mUniqueID;
+ ft->mOwnsThread = info->mMessageCount == 0;
+
+ p2p_sendAck( ft, info, hdrdata );
+
+ if ( dwAppID == 1 && !strcmp( szEufGuid, "{A4268EEC-FEC5-49E5-95C3-F126696BDBF6}" )) {
+ char szFileName[ MAX_PATH ];
+ MSN_GetAvatarFileName( NULL, szFileName, sizeof( szFileName ));
+ ft->fileId = _open( szFileName, O_RDONLY | _O_BINARY, _S_IREAD );
+ if ( ft->fileId == -1 ) {
+ p2p_sendStatus( ft, info, 603 );
+ MSN_DebugLog( "Unable to open avatar file '%s', error %d", szFileName, errno );
+ delete ft;
+ return;
+ }
+ MSN_DebugLog( "My avatar file opened for %s as %08p::%d", szContactEmail, ft, ft->fileId );
+ ft->std.totalBytes = ft->std.currentFileSize = filelength( ft->fileId );
+ ft->std.sending = true;
+
+ ft->p2p_msgid -= 3;
+
+ //---- send 200 OK Message
+ p2p_sendStatus( ft, info, 200 );
+ p2p_registerSession( ft );
+ return;
+ }
+
+ if ( dwAppID == 2 && !strcmp( szEufGuid, "{5D3E02AB-6190-11D3-BBBB-00C04F795683}" )) {
+ WCHAR* wszFileName = ( WCHAR* )&szContext[ 20 ];
+ { for ( WCHAR* p = wszFileName; *p != 0; p++ )
+ { switch( *p ) {
+ case ':': case '?': case '/': case '\\': case '*':
+ *p = '_';
+ } } }
+
+ #if defined( _UNICODE )
+ ft->wszFileName = _wcsdup( wszFileName );
+ #endif
+
+ char szFileName[ MAX_PATH ];
+ char cDefaultChar = '_';
+ WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
+ wszFileName, -1, szFileName, MAX_PATH, &cDefaultChar, 0 );
+ MSN_DebugLog( "File name: '%s'", szFileName );
+
+ ft->std.hContact = info->mJoinedContacts[0];
+ replaceStr( ft->std.currentFile, szFileName );
+ ft->std.totalBytes = ft->std.currentFileSize = *( long* )&szContext[ 8 ];
+ ft->std.totalFiles = 1;
+
+ p2p_registerSession( ft );
+
+ if ( !ft->mIsFirst ) {
+ filetransfer* parentFt = p2p_getFirstSession( ft->std.hContact );
+ if ( parentFt != NULL )
+ ft->p2p_acksessid = parentFt->p2p_acksessid;
+ }
+
+ ft->p2p_msgid -= 3;
+
+ int tFileNameLen = strlen( ft->std.currentFile );
+ char tComment[ 40 ];
+ int tCommentLen = mir_snprintf( tComment, sizeof( tComment ), "%ld bytes", ft->std.currentFileSize );
+ char* szBlob = ( char* )alloca( sizeof( DWORD ) + tFileNameLen + tCommentLen + 2 );
+ *( PDWORD )szBlob = ( DWORD )ft;
+ strcpy( szBlob + sizeof( DWORD ), ft->std.currentFile );
+ strcpy( szBlob + sizeof( DWORD ) + tFileNameLen + 1, tComment );
+
+ PROTORECVEVENT pre;
+ pre.flags = 0;
+ pre.timestamp = ( DWORD )time( NULL );
+ pre.szMessage = ( char* )szBlob;
+ pre.lParam = ( LPARAM )( char* )"";
+
+ CCSDATA ccs;
+ ccs.hContact = info->mJoinedContacts[0];
+ ccs.szProtoService = PSR_FILE;
+ ccs.wParam = 0;
+ ccs.lParam = ( LPARAM )&pre;
+ MSN_CallService( MS_PROTO_CHAINRECV, 0, ( LPARAM )&ccs );
+ return;
+ }
+
+ if ( dwAppID == 4 ) {
+ if ( !strcmp( szEufGuid, "{4BD96FC0-AB17-4425-A14A-439185962DC8}" )) {
+ MSN_ShowPopup( MSN_GetContactName( info->mJoinedContacts[0] ),
+ MSN_Translate( "Contact tried to send its webcam data (currently not supported)" ), MSN_ALLOW_MSGBOX );
+ return;
+ }
+ if ( !strcmp( szEufGuid, "{1C9AA97E-9C05-4583-A3BD-908A196F1E92}" )) {
+ MSN_ShowPopup( MSN_GetContactName( info->mJoinedContacts[0] ),
+ MSN_Translate( "Contact tried to view our webcam data (currently not supported)" ), MSN_ALLOW_MSGBOX );
+ return;
+ } }
+
+ delete ft;
+ MSN_DebugLog( "Invalid or unknown AppID/EUF-GUID combination: %ld/%s", dwAppID, szEufGuid );
+}
+
+static void sttInitDirectTransfer(
+ P2P_Header* hdrdata,
+ ThreadData* info,
+ MimeHeaders& tFileInfo,
+ MimeHeaders& tFileInfo2 )
+{
+ const char *szCallID = tFileInfo[ "Call-ID" ],
+ *szBranch = tFileInfo[ "Via" ];
+
+ if ( szBranch != NULL ) {
+ szBranch = strstr( szBranch, "branch=" );
+ if ( szBranch != NULL )
+ szBranch += 7;
+ }
+ if ( szCallID == NULL || szBranch == NULL ) {
+ MSN_DebugLog( "Ignoring invalid invitation: CallID='%s', Branch='%s', SessionID=%s", szCallID, szBranch );
+ return;
+ }
+
+ filetransfer* ft = p2p_getSessionByCallID( szCallID );
+ if ( ft == NULL )
+ return;
+
+ ++ft->p2p_msgid;
+ p2p_sendAck( ft, info, hdrdata );
+
+ replaceStr( ft->p2p_callID, szCallID );
+ replaceStr( ft->p2p_branch, szBranch );
+ ft->p2p_acksessid = 0x024B0000 + rand();
+
+ const char *szConnType = tFileInfo2[ "Conn-Type" ],
+ *szUPnPNat = tFileInfo2[ "UPnPNat" ],
+ *szNetID = tFileInfo2[ "NetID" ],
+ *szICF = tFileInfo2[ "ICF" ];
+
+ if ( szConnType == NULL || szUPnPNat == NULL || szICF == NULL || szNetID == NULL ) {
+ MSN_DebugLog( "Ignoring invalid invitation: ConnType='%s', UPnPNat='%s', ICF='%s', NetID='%s'",
+ szConnType, szUPnPNat, szICF, szNetID );
+ return;
+ }
+
+ MSN_SendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, ft, 0);
+
+ bool bUseDirect = false, bActAsServer = false;
+ if ( atol( szNetID ) == 0 ) {
+ if ( !strcmp( szConnType, "Direct-Connect" ) || !strcmp( szConnType, "Firewall" ))
+ bUseDirect = true;
+ }
+
+ if ( MSN_GetByte( "NLSpecifyIncomingPorts", 0 )) {
+ MSN_DebugLog( "My machine can accept incoming connections" );
+ bUseDirect = bActAsServer = true;
+ }
+
+ MimeHeaders tResult(20);
+ tResult.addString( "CSeq", "1 " );
+ tResult.addString( "Call-ID", ft->p2p_callID );
+ tResult.addLong( "Max-Forwards", 0 );
+ if ( bUseDirect )
+ tResult.addString( "Content-Type", "application/x-msnmsgr-transrespbody" );
+ else
+ tResult.addString( "Content-Type", "application/x-msnmsgr-transreqbody" );
+
+ char szBody[ 512 ];
+ int cbBodyLen = 0;
+ if ( bActAsServer )
+ cbBodyLen = sttCreateListener( info, ft, ( pThreadFunc )p2p_filePassiveThread, szBody, sizeof( szBody ));
+
+ if ( !cbBodyLen )
+ cbBodyLen = mir_snprintf( szBody, sizeof( szBody ),
+ "Bridge: TCPv1\r\n"
+ "Listening: false\r\n"
+ "Nonce: %s\r\n\r\n%c", sttVoidNonce, 0 );
+
+ ft->p2p_msgid -= 2;
+ p2p_sendSlp( info, ft, tResult, 200, szBody, cbBodyLen );
+ ++ft->p2p_msgid;
+}
+
+static void sttInitDirectTransfer2(
+ P2P_Header* hdrdata,
+ ThreadData* info,
+ MimeHeaders& tFileInfo,
+ MimeHeaders& tFileInfo2 )
+{
+ filetransfer* ft = p2p_getSessionByCallID( tFileInfo[ "Call-ID" ] );
+ if ( ft == NULL )
+ return;
+
+ const char *szInternalAddress = tFileInfo2[ "IPv4Internal-Addrs" ],
+ *szInternalPort = tFileInfo2[ "IPv4Internal-Port" ],
+ *szExternalAddress = tFileInfo2[ "IPv4External-Addrs" ],
+ *szExternalPort = tFileInfo2[ "IPv4External-Port" ],
+ *szNonce = tFileInfo2[ "Nonce" ],
+ *szListening = tFileInfo2[ "Listening" ];
+
+ if ( szNonce == NULL || szListening == NULL ) {
+ MSN_DebugLog( "Ignoring invalid invitation: Listening='%s', Nonce=%s", szNonce, szListening );
+ return;
+ }
+
+ MSN_SendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, ft, 0);
+ p2p_sendAck( ft, info, hdrdata );
+
+ if ( !strcmp( szListening, "true" ) && strcmp( szNonce, sttVoidNonce )) {
+ ThreadData* newThread = new ThreadData;
+ newThread->mType = SERVER_P2P_DIRECT;
+ newThread->mP2pSession = ft;
+ newThread->mParentThread = info;
+ strncpy( newThread->mCookie, szNonce, sizeof( newThread->mCookie ));
+ mir_snprintf( newThread->mServer, sizeof( newThread->mServer ), "%s:%s", szInternalAddress, szInternalPort );
+ newThread->startThread(( pThreadFunc )p2p_fileActiveThread );
+ }
+ else p2p_sendStatus( ft, info, 603 );
+}
+
+static void sttAcceptTransfer(
+ P2P_Header* hdrdata,
+ ThreadData* info,
+ MimeHeaders& tFileInfo,
+ MimeHeaders& tFileInfo2 )
+{
+ filetransfer* ft = p2p_getSessionByCallID( tFileInfo[ "Call-ID" ] );
+ if ( ft == NULL )
+ return;
+
+ ft->mThreadId = info->mUniqueID;
+
+ ++ft->p2p_msgid;
+ p2p_sendAck( ft, info, hdrdata );
+
+ const char *szCallID = tFileInfo[ "Call-ID" ], *szBranch = tFileInfo[ "Via" ];
+ if ( szBranch != NULL ) {
+ szBranch = strstr( szBranch, "branch=" );
+ if ( szBranch != NULL )
+ szBranch += 7;
+ }
+
+ if ( szCallID == NULL || szBranch == NULL ) {
+ MSN_DebugLog( "Ignoring invalid invitation: CallID='%s', szBranch='%s'", szCallID, szBranch );
+LBL_Close:
+ p2p_sendBye( info, ft );
+ return;
+ }
+
+ if ( !ft->std.sending ) {
+ replaceStr( ft->p2p_branch, szBranch );
+ replaceStr( ft->p2p_callID, szCallID );
+ return;
+ }
+
+ const char* szOldContentType = tFileInfo[ "Content-Type" ];
+ if ( szOldContentType == NULL )
+ goto LBL_Close;
+
+ bool bAllowIncoming = ( MSN_GetByte( "NLSpecifyIncomingPorts", 0 ) != 0 );
+
+ MimeHeaders tResult(20);
+ tResult.addString( "CSeq", "0 " );
+ tResult.addString( "Call-ID", ft->p2p_callID );
+ tResult.addLong( "Max-Forwards", 0 );
+
+ char* szBody = ( char* )alloca( 1024 );
+ int cbBody = 0;
+ if ( !strcmp( szOldContentType, "application/x-msnmsgr-sessionreqbody" )) {
+ tResult.addString( "Content-Type", "application/x-msnmsgr-transreqbody" );
+ cbBody = mir_snprintf( szBody, 1024,
+ "Bridges: TCPv1\r\nNetID: 0\r\nConn-Type: %s\r\nUPnPNat: false\r\nICF: false\r\n\r\n%c",
+// "Nonce: %s\r\nSessionID: %lu\r\nSChannelState: 0\r\n\r\n%c",
+ ( bAllowIncoming ) ? "Direct-Connect" : "Unknown-Connect", 0 );
+ }
+ else if ( !strcmp( szOldContentType, "application/x-msnmsgr-transrespbody" )) {
+ const char *szListening = tFileInfo2[ "Listening" ],
+ *szNonce = tFileInfo2[ "Nonce" ],
+ *szExternalAddress = tFileInfo2[ "IPv4External-Addrs" ],
+ *szExternalPort = tFileInfo2[ "IPv4External-Port" ],
+ *szInternalAddress = tFileInfo2[ "IPv4Internal-Addrs" ],
+ *szInternalPort = tFileInfo2[ "IPv4Internal-Port" ];
+ if ( szListening == NULL || szNonce == NULL ) {
+ MSN_DebugLog( "Invalid data packet, exiting..." );
+ goto LBL_Close;
+ }
+
+ // another side reported that it will be a server.
+ if ( !strcmp( szListening, "true" ) && strcmp( szNonce, sttVoidNonce )) {
+ bool extOk = szExternalAddress != NULL && szExternalPort != NULL;
+ bool intOk = szInternalAddress != NULL && szInternalPort != NULL;
+
+ ThreadData* newThread = new ThreadData;
+
+ char ipaddr[256] = "";
+ MSN_GetMyHostAsString( ipaddr, sizeof( ipaddr ));
+
+ if ( extOk && ( strcmp( szExternalAddress, ipaddr ) || !intOk ))
+ mir_snprintf( newThread->mServer, sizeof( newThread->mServer ), "%s:%s", szExternalAddress, szExternalPort );
+ else if ( intOk )
+ mir_snprintf( newThread->mServer, sizeof( newThread->mServer ), "%s:%s", szInternalAddress, szInternalPort );
+ else {
+ MSN_DebugLog( "Invalid data packet, exiting..." );
+ delete newThread;
+ goto LBL_Close;
+ }
+
+ newThread->mType = SERVER_P2P_DIRECT;
+ newThread->mP2pSession = ft;
+ newThread->mParentThread = info;
+ strncpy( newThread->mCookie, szNonce, sizeof( newThread->mCookie ));
+ newThread->startThread(( pThreadFunc )p2p_fileActiveThread );
+ return;
+ }
+
+ // can we be a server?
+ if ( bAllowIncoming )
+ cbBody = sttCreateListener( info, ft, ( pThreadFunc )p2p_filePassiveThread, szBody, 1024 );
+
+ // no, send a file via server
+ if ( cbBody == 0 ) {
+ p2p_sendFeedStart( ft, info );
+ return;
+ }
+
+ tResult.addString( "Content-Type", "application/x-msnmsgr-transrespbody" );
+ }
+ else if ( !strcmp( szOldContentType, "application/x-msnmsgr-transreqbody" )) {
+ // can we be a server?
+ if ( bAllowIncoming )
+ cbBody = sttCreateListener( info, ft, ( pThreadFunc )p2p_filePassiveThread, szBody, 1024 );
+
+ // no, send a file via server
+ if ( cbBody == 0 ) {
+ p2p_sendFeedStart( ft, info );
+ return;
+ }
+
+ tResult.addString( "Content-Type", "application/x-msnmsgr-transrespbody" );
+ }
+ else goto LBL_Close;
+
+ ft->p2p_msgid -= 2;
+ p2p_sendSlp( info, ft, tResult, -2, szBody, cbBody );
+ ++ft->p2p_msgid;
+}
+
+static void sttCloseTransfer( P2P_Header* hdrdata, ThreadData* info, MimeHeaders& tFileInfo )
+{
+ filetransfer* ft = p2p_getSessionByCallID( tFileInfo[ "Call-ID" ] );
+ if ( ft == NULL )
+ return;
+
+ p2p_sendAck( ft, info, hdrdata );
+ p2p_unregisterSession( ft );
+}
+
+void __stdcall p2p_processMsg( ThreadData* info, const char* msgbody )
+{
+ P2P_Header* hdrdata = ( P2P_Header* )msgbody; msgbody += sizeof( P2P_Header );
+ sttLogHeader( hdrdata );
+
+ //---- if we got a message
+ if ( hdrdata->mFlags == 0 )
+ {
+ int iMsgType = 0;
+ if ( !memcmp( msgbody, "INVITE MSNMSGR:", 15 ))
+ iMsgType = 1;
+ else if ( !memcmp( msgbody, "MSNSLP/1.0 200 ", 15 ))
+ iMsgType = 2;
+ else if ( !memcmp( msgbody, "BYE MSNMSGR:", 12 ))
+ iMsgType = 3;
+ else if ( !memcmp( msgbody, "MSNSLP/1.0 603 ", 15 ))
+ iMsgType = 4;
+
+ if ( iMsgType ) {
+ const char* peol = strstr( msgbody, "\r\n" );
+ if ( peol != NULL )
+ msgbody = peol+2;
+
+ MimeHeaders tFileInfo, tFileInfo2;
+ msgbody = tFileInfo.readFromBuffer( msgbody );
+ msgbody = tFileInfo2.readFromBuffer( msgbody );
+
+ const char* szContentType = tFileInfo[ "Content-Type" ];
+ if ( szContentType == NULL ) {
+ MSN_DebugLog( "Invalid or missing Content-Type field, exiting" );
+ return;
+ }
+
+ switch( iMsgType ) {
+ case 1:
+ if ( info->mType == SERVER_SWITCHBOARD) {
+ if ( !strcmp( szContentType, "application/x-msnmsgr-sessionreqbody" ))
+ sttInitFileTransfer( hdrdata, info, tFileInfo, tFileInfo2, msgbody );
+ else if ( iMsgType == 1 && !strcmp( szContentType, "application/x-msnmsgr-transreqbody" ))
+ sttInitDirectTransfer( hdrdata, info, tFileInfo, tFileInfo2 );
+ else if ( iMsgType == 1 && !strcmp( szContentType, "application/x-msnmsgr-transrespbody" ))
+ sttInitDirectTransfer2( hdrdata, info, tFileInfo, tFileInfo2 );
+ }
+ break;
+
+ case 2:
+ if ( info->mType == SERVER_SWITCHBOARD)
+ sttAcceptTransfer( hdrdata, info, tFileInfo, tFileInfo2 );
+ break;
+
+ case 3:
+ if ( !strcmp( szContentType, "application/x-msnmsgr-sessionclosebody" ))
+ {
+ filetransfer* ft = p2p_getSessionByCallID( tFileInfo[ "Call-ID" ] );
+ if ( ft != NULL )
+ {
+ p2p_sendAck( ft, info, hdrdata );
+ if ( ft->std.currentFileProgress < ft->std.currentFileSize )
+ {
+ p2p_sendEndSession(info, ft);
+ ft->bCanceled = true;
+ }
+ else if ( !ft->std.sending )
+ ft->complete();
+
+ p2p_unregisterSession( ft );
+ } }
+ break;
+
+ case 4:
+ sttCloseTransfer( hdrdata, info, tFileInfo );
+ break;
+ }
+ return;
+ } }
+
+ //---- receiving ack -----------
+ if ( hdrdata->mFlags == 0x02 ) {
+ filetransfer* ft = p2p_getSessionByID( hdrdata->mSessionID );
+ if ( ft == NULL )
+ if ((ft = p2p_getSessionByMsgID( hdrdata->mAckSessionID )) == NULL )
+ return;
+
+ if ( hdrdata->mAckSessionID == ft->p2p_sendmsgid )
+ {
+ if ( ft->p2p_appID == 2 )
+ {
+ ft->complete();
+ p2p_sendBye( info, ft );
+ }
+ return;
+ }
+
+ if ( hdrdata->mAckSessionID == ft->p2p_byemsgid )
+ {
+ if ( ft->p2p_appID == 1 ) {
+ sttSavePicture2disk( info, ft );
+
+ char tContext[ 256 ];
+ if ( !MSN_GetStaticString( "PictContext", ft->std.hContact, tContext, sizeof( tContext )))
+ MSN_SetString( ft->std.hContact, "PictSavedContext", tContext );
+ }
+
+ p2p_unregisterSession( ft );
+ if ( ft->mOwnsThread )
+ info->sendPacket( "OUT", NULL );
+ return;
+ }
+
+ switch( ft->p2p_ackID ) {
+ case 1000:
+ {
+ //---- send Data Preparation Message
+ char* buf = ( char* )alloca( 2000 + 3*strlen( ft->p2p_dest ));
+ char* p = buf + sprintf( buf, sttP2Pheader, ft->p2p_dest );
+ P2P_Header* tHdr = ( P2P_Header* )p; p += sizeof( P2P_Header );
+ memset( tHdr, 0, sizeof( P2P_Header ));
+ tHdr->mSessionID = ft->p2p_sessionid;
+ tHdr->mID = ++ft->p2p_msgid;
+ tHdr->mTotalSize = tHdr->mPacketLen = 4;
+ tHdr->mAckSessionID = ft->p2p_acksessid;
+ *( long* )p = 0; p += sizeof( long );
+ *( long* )p = htonl(ft->p2p_appID); p += sizeof( long );
+ info->sendRawMessage( 'D', buf, int( p - buf ));
+ }
+ break;
+
+ case 1001:
+ //---- send Data Messages
+ p2p_sendFeedStart( ft, info );
+ break;
+ }
+
+ ft->p2p_ackID++;
+ return;
+ }
+
+ filetransfer* ft = p2p_getSessionByID( hdrdata->mSessionID );
+ if ( ft == NULL )
+ return;
+
+ if ( hdrdata->mFlags == 0 ) {
+ //---- accept the data preparation message ------
+ long* pLongs = ( long* )msgbody;
+ if ( pLongs[0] == 0 && pLongs[1] == 0x01000000 && hdrdata->mPacketLen == 4 ) {
+ p2p_sendAck( ft, info, hdrdata );
+ return;
+ } }
+
+ //---- receiving data -----------
+ if ( hdrdata->mFlags == 0x01000030 || hdrdata->mFlags == 0x20 ) {
+
+ if ( hdrdata->mOffset + hdrdata->mPacketLen > hdrdata->mTotalSize )
+ hdrdata->mPacketLen = DWORD( hdrdata->mTotalSize - hdrdata->mOffset );
+
+ ft->p2p_sendmsgid = hdrdata->mID;
+ ft->std.totalBytes = ft->std.currentFileSize = ( long )hdrdata->mTotalSize;
+
+ if ( ft->inmemTransfer )
+ memcpy( ft->fileBuffer + hdrdata->mOffset, msgbody, hdrdata->mPacketLen );
+ else {
+ ::lseek( ft->fileId, long( hdrdata->mOffset ), SEEK_SET );
+ ::_write( ft->fileId, msgbody, hdrdata->mPacketLen );
+ }
+
+ ft->std.totalProgress += hdrdata->mPacketLen;
+ ft->std.currentFileProgress += hdrdata->mPacketLen;
+
+ if ( ft->p2p_appID == 2 )
+ MSN_SendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, ( LPARAM )&ft->std );
+
+ //---- send an ack: body was transferred correctly
+ MSN_DebugLog( "Transferred %lu bytes out of %lu", ft->std.currentFileProgress, hdrdata->mTotalSize );
+
+ if ( ft->std.currentFileProgress == hdrdata->mTotalSize ) {
+ p2p_sendAck( ft, info, hdrdata );
+ if ( ft->p2p_appID == 2 )
+ ft->complete();
+ else
+ p2p_sendBye( info, ft );
+ } }
+
+ if ( hdrdata->mFlags == 0x40 || hdrdata->mFlags == 0x80 ) {
+ if ( ft->mOwnsThread )
+ info->sendPacket( "OUT", NULL );
+ p2p_unregisterSession( ft );
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// p2p_invite - invite another side to transfer an avatar
+
+struct HFileContext
+{
+ DWORD len, dw1, dwSize, dw2, dw3;
+ WCHAR wszFileName[ MAX_PATH ];
+};
+
+void __stdcall p2p_invite( HANDLE hContact, int iAppID, filetransfer* ft )
+{
+ const char* szAppID;
+ switch( iAppID ) {
+ case MSN_APPID_FILE: szAppID = "{5D3E02AB-6190-11D3-BBBB-00C04F795683}"; break;
+ case MSN_APPID_AVATAR: szAppID = "{A4268EEC-FEC5-49E5-95C3-F126696BDBF6}"; break;
+ default:
+ return;
+ }
+
+ char szEmail[ MSN_MAX_EMAIL_LEN ];
+ MSN_GetStaticString( "e-mail", hContact, szEmail, sizeof( szEmail ));
+
+ ThreadData *thread = MSN_GetThreadByContact( hContact );
+
+ srand( (unsigned)time( NULL ) );
+ long sessionID = rand();
+
+ if ( ft == NULL ) {
+ ft = new filetransfer();
+ ft->std.hContact = hContact;
+ }
+ ft->p2p_appID = iAppID;
+ ft->p2p_msgid = rand();
+ ft->p2p_acksessid = rand();
+ ft->p2p_sessionid = sessionID;
+ ft->p2p_dest = strdup( szEmail );
+ ft->p2p_branch = getNewUuid();
+ ft->p2p_callID = getNewUuid();
+ p2p_registerSession( ft );
+
+ BYTE* pContext;
+ int cbContext;
+
+ if ( iAppID == MSN_APPID_AVATAR ) {
+ ft->inmemTransfer = true;
+ ft->fileBuffer = NULL;
+ ft->std.sending = false;
+
+ char tBuffer[ 256 ] = "";
+ MSN_GetStaticString( "PictContext", hContact, tBuffer, sizeof( tBuffer ));
+
+ char* p = strstr( tBuffer, "Size=\"" );
+ if ( p != NULL )
+ ft->std.totalBytes = ft->std.currentFileSize = atol( p+6 );
+
+ if (ft->create() == -1) {
+ MSN_DebugLog( "Avatar creation failed for MSNCTX=\'%s\'", tBuffer );
+ return;
+ }
+
+ pContext = ( BYTE* )tBuffer;
+ cbContext = strlen( tBuffer )+1;
+ }
+ else {
+ HFileContext ctx;
+ memset( &ctx, 0, sizeof( ctx ));
+ ctx.len = sizeof( ctx );
+ ctx.dwSize = ft->std.totalBytes;
+ if ( ft->wszFileName != NULL )
+ wcsncpy( ctx.wszFileName, ft->wszFileName, sizeof( ctx.wszFileName ));
+ else {
+ char* pszFiles = strrchr( ft->std.currentFile, '\\' );
+ if ( pszFiles )
+ pszFiles++;
+ else
+ pszFiles = ft->std.currentFile;
+
+ MultiByteToWideChar( CP_ACP, 0, pszFiles, -1, ctx.wszFileName, sizeof( ctx.wszFileName ));
+ }
+
+ pContext = ( BYTE* )&ctx;
+ cbContext = sizeof( ctx );
+ }
+
+ char* body = ( char* )alloca( 2000 );
+ int tBytes = mir_snprintf( body, 2000,
+ "EUF-GUID: %s\r\n"
+ "SessionID: %lu\r\n"
+ "AppID: %d\r\n"
+ "Context: ",
+ szAppID, sessionID, iAppID );
+
+ NETLIBBASE64 nlb = { body+tBytes, 2000-tBytes, pContext, cbContext };
+ MSN_CallService( MS_NETLIB_BASE64ENCODE, 0, LPARAM( &nlb ));
+ strcat( body, "\r\n\r\n" );
+ int cbBody = strlen( body );
+ body[ cbBody++ ] = 0;
+
+ MimeHeaders tResult(20);
+ tResult.addString( "CSeq", "0 " );
+ tResult.addString( "Call-ID", ft->p2p_callID );
+ tResult.addLong( "Max-Forwards", 0 );
+ tResult.addString( "Content-Type", "application/x-msnmsgr-sessionreqbody" );
+
+ p2p_sendSlp( MSN_GetThreadByContact( hContact ), ft, tResult, -2, body, cbBody );
+}
diff --git a/miranda-wine/protocols/MSN/msn_p2ps.cpp b/miranda-wine/protocols/MSN/msn_p2ps.cpp
new file mode 100644
index 0000000..55fd57e
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_p2ps.cpp
@@ -0,0 +1,248 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "msn_global.h"
+
+static int sessionCount = 0;
+static filetransfer** sessionList = NULL;
+static CRITICAL_SECTION sessionLock;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// add file session to a list
+
+void __stdcall p2p_registerSession( filetransfer* ft )
+{
+ EnterCriticalSection( &sessionLock );
+
+ bool bIsFirst = true;
+ for ( int i=0; i < sessionCount; i++ ) {
+ if ( sessionList[i]->std.hContact == ft->std.hContact ) {
+ bIsFirst = false;
+ break;
+ } }
+
+ sessionList = ( filetransfer** )realloc( sessionList, sizeof( void* ) * ( sessionCount+1 ));
+ sessionList[ sessionCount++ ] = ft;
+ ft->mIsFirst = bIsFirst;
+
+ LeaveCriticalSection( &sessionLock );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// remove file session from a list
+
+void __stdcall p2p_unregisterSession( filetransfer* ft )
+{
+ EnterCriticalSection( &sessionLock );
+
+ for ( int i=0; i < sessionCount; i++ ) {
+ if ( sessionList[i] == ft ) {
+ delete sessionList[i];
+ while( i < sessionCount-1 ) {
+ sessionList[ i ] = sessionList[ i+1 ];
+ i++;
+ }
+ sessionCount--;
+ break;
+ } }
+
+ LeaveCriticalSection( &sessionLock );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// remove file sessions for a thread
+
+void __stdcall p2p_unregisterThreadSession( LONG threadID )
+{
+ EnterCriticalSection( &sessionLock );
+
+ for ( int i=0; i < sessionCount; i++ ) {
+ if ( sessionList[i]->mThreadId == threadID ) {
+ delete sessionList[i];
+ while( i < sessionCount-1 ) {
+ sessionList[ i ] = sessionList[ i+1 ];
+ i++;
+ }
+ sessionCount--;
+ } }
+
+ LeaveCriticalSection( &sessionLock );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// get session by some parameter
+
+filetransfer* __stdcall p2p_getSessionByID( unsigned ID )
+{
+ if ( ID == 0 )
+ return NULL;
+
+ filetransfer* ft = NULL;
+ EnterCriticalSection( &sessionLock );
+
+ for ( int i=0; i < sessionCount; i++ ) {
+ filetransfer* FT = sessionList[i];
+ if ( FT->p2p_sessionid == ID ) {
+ ft = FT;
+ break;
+ } }
+
+ LeaveCriticalSection( &sessionLock );
+ if ( ft == NULL )
+ MSN_DebugLog( "Ignoring unknown session id %lu", ID );
+
+ return ft;
+}
+
+filetransfer* __stdcall p2p_getSessionByMsgID( unsigned ID )
+{
+ if ( ID == 0 )
+ return NULL;
+
+ filetransfer* ft = NULL;
+ EnterCriticalSection( &sessionLock );
+
+ for ( int i=0; i < sessionCount; i++ ) {
+ filetransfer* FT = sessionList[i];
+ if ( FT->p2p_msgid == ID || FT->p2p_msgid == (ID + 1) ) {
+ ft = FT;
+ break;
+ } }
+
+ LeaveCriticalSection( &sessionLock );
+ if ( ft == NULL )
+ MSN_DebugLog( "Ignoring unknown message id %lu", ID );
+
+ return ft;
+}
+
+filetransfer* __stdcall p2p_getAnotherContactSession( filetransfer* ft )
+{
+ filetransfer* result = NULL;
+ EnterCriticalSection( &sessionLock );
+
+ for ( int i=0; i < sessionCount; i++ ) {
+ filetransfer* FT = sessionList[i];
+ if ( FT->std.hContact == ft->std.hContact && FT != ft ) {
+ result = FT;
+ break;
+ } }
+
+ LeaveCriticalSection( &sessionLock );
+ return result;
+}
+
+BOOL __stdcall p2p_sessionRegistered( filetransfer* ft )
+{
+ BOOL result = FALSE;
+ EnterCriticalSection( &sessionLock );
+
+ for ( int i=0; i < sessionCount; i++ ) {
+ filetransfer* FT = sessionList[i];
+ if ( sessionList[i] == ft ) {
+ result = TRUE;
+ break;
+ } }
+
+ LeaveCriticalSection( &sessionLock );
+ return result;
+}
+
+filetransfer* __stdcall p2p_getFirstSession( HANDLE hContact )
+{
+ filetransfer* result = NULL;
+ EnterCriticalSection( &sessionLock );
+
+ for ( int i=0; i < sessionCount; i++ ) {
+ filetransfer* FT = sessionList[i];
+ if ( FT->std.hContact == hContact && FT->mIsFirst ) {
+ result = FT;
+ break;
+ } }
+
+ LeaveCriticalSection( &sessionLock );
+ return result;
+}
+
+filetransfer* __stdcall p2p_getSessionByCallID( const char* CallID )
+{
+ if ( CallID == NULL )
+ return NULL;
+
+ filetransfer* ft = NULL;
+ EnterCriticalSection( &sessionLock );
+
+ for ( int i=0; i < sessionCount; i++ ) {
+ filetransfer* FT = sessionList[i];
+ if ( FT->p2p_callID == NULL )
+ continue;
+
+ if ( !strcmp( FT->p2p_callID, CallID )) {
+ ft = FT;
+ break;
+ } }
+
+ LeaveCriticalSection( &sessionLock );
+ if ( ft == NULL )
+ MSN_DebugLog( "Ignoring unknown session call id %s", CallID );
+
+ return ft;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// push another file transfers
+
+void __stdcall p2p_ackOtherFiles( ThreadData* info )
+{
+ filetransfer* ft = info->mP2pSession;
+ EnterCriticalSection( &sessionLock );
+
+ for ( int i=0; i < sessionCount; i++ ) {
+ filetransfer* FT = sessionList[i];
+ if ( FT->std.hContact == ft->std.hContact && FT != ft )
+ p2p_sendStatus( FT, info->mParentThread, 200 );
+ }
+
+ LeaveCriticalSection( &sessionLock );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// external functions
+
+void P2pSessions_Init()
+{
+ InitializeCriticalSection( &sessionLock );
+}
+
+void P2pSessions_Uninit()
+{
+ EnterCriticalSection( &sessionLock );
+
+ for ( int i=0; i < sessionCount; i++ )
+ delete sessionList[i];
+ if ( sessionList != NULL )
+ free( sessionList );
+
+ LeaveCriticalSection( &sessionLock );
+ DeleteCriticalSection( &sessionLock );
+}
diff --git a/miranda-wine/protocols/MSN/msn_srv.cpp b/miranda-wine/protocols/MSN/msn_srv.cpp
new file mode 100644
index 0000000..80fb64e
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_srv.cpp
@@ -0,0 +1,184 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "msn_global.h"
+
+struct ServerGroupItem
+{
+ char* id;
+ char* name; // in UTF8
+ int number;
+
+ ServerGroupItem* next;
+};
+
+static ServerGroupItem* sttFirst = NULL;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_AddGroup - adds new server group to the list
+
+bool MSN_AddGroup( const char* pName, const char* pId )
+{
+ ServerGroupItem* p = new ServerGroupItem;
+ if ( p == NULL )
+ return false;
+
+ p->number = -1;
+ p->id = strdup( pId );
+ p->name = strdup( pName );
+ p->next = sttFirst;
+ sttFirst = p;
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_DeleteGroup - deletes a group from the list
+
+void MSN_DeleteGroup( const char* pId )
+{
+ ServerGroupItem* prev = NULL;
+
+ for ( ServerGroupItem* p = sttFirst; p != NULL; p = p->next ) {
+ if ( !strcmp( p->id, pId )) {
+ if ( prev == NULL ) sttFirst = p->next;
+ else prev->next = p->next;
+ free( p->id );
+ free( p->name );
+ delete p;
+ return;
+ }
+
+ prev = p;
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_FreeGroups - clears the server groups list
+
+void MSN_FreeGroups()
+{
+ ServerGroupItem* p1;
+
+ for ( ServerGroupItem* p = sttFirst; p != NULL; p = p1 ) {
+ p1 = p->next;
+
+ free( p->id );
+ free( p->name );
+ delete p;
+ }
+
+ sttFirst = NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_GetGroupById - tries to return a group name associated with given UUID
+
+LPCSTR MSN_GetGroupById( const char* pId )
+{
+ for ( ServerGroupItem* p = sttFirst; p != NULL; p = p->next )
+ if ( stricmp( p->id, pId ) == 0 )
+ return p->name;
+
+ return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_GetGroupByName - tries to return a group UUID associated with the given name
+
+LPCSTR MSN_GetGroupByName( const char* pName )
+{
+ for ( ServerGroupItem* p = sttFirst; p != NULL; p = p->next )
+ if ( strcmp( p->name, pName ) == 0 )
+ return p->id;
+
+ return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_GetGroupByNumber - tries to return a group UUID associated with the given id
+
+LPCSTR MSN_GetGroupByNumber( int pNumber )
+{
+ for ( ServerGroupItem* p = sttFirst; p != NULL; p = p->next )
+ if ( p->number == pNumber )
+ return p->id;
+
+ return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_MoveContactToGroup - sends a contact to the specified group
+
+void MSN_MoveContactToGroup( HANDLE hContact, const char* grpName )
+{
+ LPCSTR szId;
+ char szContactID[ 100 ], szGroupID[ 100 ];
+ if ( MSN_GetStaticString( "ID", hContact, szContactID, sizeof szContactID ))
+ return;
+
+ if ( MSN_GetStaticString( "GroupID", hContact, szGroupID, sizeof szGroupID ))
+ szGroupID[ 0 ] = 0;
+
+ bool bInsert = szGroupID[0] == 0, bDelete = szGroupID[0] != 0;
+
+ if ( grpName != NULL )
+ {
+ if (( szId = MSN_GetGroupByName( grpName )) == NULL ) {
+ MSN_AddServerGroup( grpName );
+ if (( szId = MSN_GetGroupByName( grpName )) == NULL )
+ return;
+ }
+
+ if ( !strcmp( szGroupID, szId )) bDelete = false;
+ else bInsert = true;
+ }
+ else bInsert = false;
+
+ if ( bInsert )
+ msnNsThread->sendPacket( "ADC", "FL C=%s %s", szContactID, szId );
+
+ if ( bDelete )
+ msnNsThread->sendPacket( "REM", "FL %s %s", szContactID, szGroupID );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_SetGroupName - sets a new name to a server group
+
+void MSN_SetGroupName( const char* pId, const char* pNewName )
+{
+ for ( ServerGroupItem* p = sttFirst; p != NULL; p = p->next ) {
+ if ( strcmp( p->id, pId ) == 0 ) {
+ free( p->name );
+ p->name = strdup( pNewName );
+ return;
+} } }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_SetGroupNumber - associate a server group with Miranda's group number
+
+void MSN_SetGroupNumber( const char* pId, int pNumber )
+{
+ for ( ServerGroupItem* p = sttFirst; p != NULL; p = p->next ) {
+ if ( strcmp( p->id, pId ) == 0 ) {
+ p->number = pNumber;
+ return;
+} } }
diff --git a/miranda-wine/protocols/MSN/msn_ssl.cpp b/miranda-wine/protocols/MSN/msn_ssl.cpp
new file mode 100644
index 0000000..7ad28ed
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_ssl.cpp
@@ -0,0 +1,667 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "msn_global.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Basic SSL operation class
+
+struct SSL_Base
+{
+ char* m_szEmail;
+
+ virtual ~SSL_Base() {}
+
+ virtual int init() = 0;
+ virtual char* getSslResult( char* parUrl, char* parAuthInfo ) = 0;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// WinInet class
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#define ERROR_FLAGS (FLAGS_ERROR_UI_FILTER_FOR_ERRORS | FLAGS_ERROR_UI_FLAGS_GENERATE_DATA | FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS )
+
+#include "wininet.h"
+
+#define SSL_BUF_SIZE 8192
+
+typedef BOOL ( WINAPI *ft_HttpQueryInfo )( HINTERNET, DWORD, LPVOID, LPDWORD, LPDWORD );
+typedef BOOL ( WINAPI *ft_HttpSendRequest )( HINTERNET, LPCSTR, DWORD, LPVOID, DWORD );
+typedef BOOL ( WINAPI *ft_InternetCloseHandle )( HINTERNET );
+typedef DWORD ( WINAPI *ft_InternetErrorDlg )( HWND, HINTERNET, DWORD, DWORD, LPVOID* );
+typedef BOOL ( WINAPI *ft_InternetSetOption )( HINTERNET, DWORD, LPVOID, DWORD );
+typedef BOOL ( WINAPI *ft_InternetReadFile )( HINTERNET, LPVOID, DWORD, LPDWORD );
+typedef BOOL ( WINAPI *ft_HttpAddRequestHeaders )( HINTERNET, LPCSTR, DWORD, DWORD );
+
+typedef HINTERNET ( WINAPI *ft_HttpOpenRequest )( HINTERNET, LPCSTR, LPCSTR, LPCSTR, LPCSTR, LPCSTR*, DWORD, DWORD );
+typedef HINTERNET ( WINAPI *ft_InternetConnect )( HINTERNET, LPCSTR, INTERNET_PORT, LPCSTR, LPCSTR, DWORD, DWORD, DWORD );
+typedef HINTERNET ( WINAPI *ft_InternetOpen )( LPCSTR, DWORD, LPCSTR, LPCSTR, DWORD );
+
+struct SSL_WinInet : public SSL_Base
+{
+ virtual ~SSL_WinInet();
+
+ virtual char* getSslResult( char* parUrl, char* parAuthInfo );
+ virtual int init();
+
+ void applyProxy( HINTERNET );
+ void readInput( HINTERNET );
+
+ //-----------------------------------------------------------------------------------
+ HMODULE m_dll;
+
+ ft_InternetCloseHandle f_InternetCloseHandle;
+ ft_InternetConnect f_InternetConnect;
+ ft_InternetErrorDlg f_InternetErrorDlg;
+ ft_InternetOpen f_InternetOpen;
+ ft_InternetReadFile f_InternetReadFile;
+ ft_InternetSetOption f_InternetSetOption;
+ ft_HttpOpenRequest f_HttpOpenRequest;
+ ft_HttpQueryInfo f_HttpQueryInfo;
+ ft_HttpSendRequest f_HttpSendRequest;
+ ft_HttpAddRequestHeaders f_HttpAddRequestHeaders;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int SSL_WinInet::init()
+{
+ if (( m_dll = LoadLibraryA( "WinInet.dll" )) == NULL )
+ return 10;
+
+ f_InternetCloseHandle = (ft_InternetCloseHandle)GetProcAddress( m_dll, "InternetCloseHandle" );
+ f_InternetConnect = (ft_InternetConnect)GetProcAddress( m_dll, "InternetConnectA" );
+ f_InternetErrorDlg = (ft_InternetErrorDlg)GetProcAddress( m_dll, "InternetErrorDlg" );
+ f_InternetOpen = (ft_InternetOpen)GetProcAddress( m_dll, "InternetOpenA" );
+ f_InternetReadFile = (ft_InternetReadFile)GetProcAddress( m_dll, "InternetReadFile" );
+ f_InternetSetOption = (ft_InternetSetOption)GetProcAddress( m_dll, "InternetSetOptionA" );
+ f_HttpOpenRequest = (ft_HttpOpenRequest)GetProcAddress( m_dll, "HttpOpenRequestA" );
+ f_HttpQueryInfo = (ft_HttpQueryInfo)GetProcAddress( m_dll, "HttpQueryInfoA" );
+ f_HttpSendRequest = (ft_HttpSendRequest)GetProcAddress( m_dll, "HttpSendRequestA" );
+ f_HttpAddRequestHeaders = (ft_HttpAddRequestHeaders)GetProcAddress( m_dll, "HttpAddRequestHeadersA" );
+ return 0;
+}
+
+SSL_WinInet::~SSL_WinInet()
+{
+ #if defined( _UNICODE )
+ FreeLibrary( m_dll ); // we free WININET.DLL only if we're under NT
+ #endif
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void SSL_WinInet::applyProxy( HINTERNET parHandle )
+{
+ char tBuffer[ 100 ];
+
+ MSN_DebugLog( "Applying proxy parameters..." );
+
+ if ( !MSN_GetStaticString( "NLProxyAuthUser", NULL, tBuffer, SSL_BUF_SIZE ))
+ f_InternetSetOption( parHandle, INTERNET_OPTION_PROXY_USERNAME, tBuffer, strlen( tBuffer )+1);
+ else
+ MSN_DebugLog( "Warning: proxy user name is required but missing" );
+
+ if ( !MSN_GetStaticString( "NLProxyAuthPassword", NULL, tBuffer, SSL_BUF_SIZE )) {
+ MSN_CallService( MS_DB_CRYPT_DECODESTRING, strlen( tBuffer ), ( LPARAM )tBuffer );
+ f_InternetSetOption( parHandle, INTERNET_OPTION_PROXY_PASSWORD, tBuffer, strlen( tBuffer )+1);
+ }
+ else MSN_DebugLog( "Warning: proxy user password is required but missing" );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void SSL_WinInet::readInput( HINTERNET hRequest )
+{
+ DWORD dwSize;
+
+ do {
+ char tmpbuf[100];
+ f_InternetReadFile( hRequest, tmpbuf, 50, &dwSize);
+ }
+ while (dwSize != 0);
+}
+
+char* SSL_WinInet::getSslResult( char* parUrl, char* parAuthInfo )
+{
+ DWORD tFlags =
+ INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS |
+ INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP |
+ INTERNET_FLAG_IGNORE_CERT_CN_INVALID |
+ INTERNET_FLAG_IGNORE_CERT_DATE_INVALID |
+ INTERNET_FLAG_KEEP_CONNECTION |
+ INTERNET_FLAG_NO_AUTO_REDIRECT |
+ INTERNET_FLAG_NO_CACHE_WRITE |
+ INTERNET_FLAG_NO_COOKIES |
+ INTERNET_FLAG_RELOAD |
+ INTERNET_FLAG_SECURE;
+
+ HINTERNET tNetHandle;
+ char* tBuffer = ( char* )alloca( SSL_BUF_SIZE );
+
+ int tUsesProxy = MSN_GetByte( "NLUseProxy", 0 );
+ if ( tUsesProxy ) {
+ DWORD ptype = MSN_GetByte( "NLProxyType", 0 );
+ if ( !MSN_GetByte( "UseIeProxy", 0 ) && ( ptype == PROXYTYPE_HTTP || ptype == PROXYTYPE_HTTPS )) {
+ char szProxy[ 100 ];
+ if ( MSN_GetStaticString( "NLProxyServer", NULL, szProxy, sizeof szProxy )) {
+ MSN_DebugLog( "Proxy server name should be set if proxy is used" );
+ return NULL;
+ }
+
+ int tPortNumber = MSN_GetWord( NULL, "NLProxyPort", -1 );
+ if ( tPortNumber == -1 ) {
+ MSN_DebugLog( "Proxy server port should be set if proxy is used" );
+ return NULL;
+ }
+
+ mir_snprintf( tBuffer, SSL_BUF_SIZE, "https=http://%s:%d http=http://%s:%d",
+ szProxy, tPortNumber, szProxy, tPortNumber );
+
+ tNetHandle = f_InternetOpen( "MSMSGS", INTERNET_OPEN_TYPE_PROXY, tBuffer, NULL, 0 );
+ }
+ else tNetHandle = f_InternetOpen( "MSMSGS", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );
+ }
+ else tNetHandle = f_InternetOpen( "MSMSGS", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0 );
+
+ if ( tNetHandle == NULL ) {
+ MSN_DebugLog( "InternetOpen() failed" );
+ return NULL;
+ }
+
+ MSN_DebugLog( "SSL request (%s): '%s'", ( tUsesProxy ) ? "using proxy": "direct connection", parUrl );
+
+ char* urlStart = strstr( parUrl, "://" );
+ if ( urlStart == NULL )
+ urlStart = parUrl;
+ else
+ urlStart += 3;
+
+ { int tLen = strlen( urlStart )+1;
+ parUrl = ( char* )alloca( tLen );
+ memcpy( parUrl, urlStart, tLen );
+ }
+
+ char* tObjectName = ( char* )strchr( parUrl, '/' );
+ if ( tObjectName != NULL ) {
+ int tLen = strlen( tObjectName )+1;
+ char* newBuf = ( char* )alloca( tLen );
+ memcpy( newBuf, tObjectName, tLen );
+
+ *tObjectName = 0;
+ tObjectName = newBuf;
+ }
+ else tObjectName = "/";
+
+ char* tSslAnswer = NULL;
+
+ HINTERNET tUrlHandle = f_InternetConnect( tNetHandle, parUrl, INTERNET_DEFAULT_HTTPS_PORT, "", "", INTERNET_SERVICE_HTTP, 0, 0 );
+ if ( tUrlHandle != NULL )
+ {
+ HINTERNET tRequest = f_HttpOpenRequest( tUrlHandle, "GET", tObjectName,
+ parAuthInfo ? NULL: HTTP_VERSIONA, NULL, NULL, tFlags, NULL );
+ if ( tRequest != NULL ) {
+ DWORD tBufSize;
+
+ unsigned tm = 3000;
+ f_InternetSetOption( tRequest, INTERNET_OPTION_CONNECT_TIMEOUT, &tm, sizeof(tm));
+ f_InternetSetOption( tRequest, INTERNET_OPTION_SEND_TIMEOUT, &tm, sizeof(tm));
+ f_InternetSetOption( tRequest, INTERNET_OPTION_RECEIVE_TIMEOUT, &tm, sizeof(tm));
+
+ if ( tUsesProxy && MSN_GetByte( "NLUseProxyAuth", 0 ))
+ applyProxy( tRequest );
+
+ char cclose[] = "Connection: close";
+ f_HttpAddRequestHeaders(tRequest, cclose, strlen(cclose), HTTP_ADDREQ_FLAG_ADD );
+LBL_Restart:
+ MSN_DebugLog( "Sending request..." );
+ DWORD tErrorCode = f_HttpSendRequest( tRequest, parAuthInfo, DWORD(-1), NULL, 0 );
+ if ( tErrorCode == 0 ) {
+ TWinErrorCode errCode;
+ MSN_DebugLog( "HttpSendRequest() failed with error %ld", errCode.mErrorCode );
+
+ if ( errCode.mErrorCode == 2 )
+ MSN_ShowError( "Internet Explorer is in the 'Offline' mode. Switch IE to the 'Online' mode and then try to relogin" );
+ else
+ MSN_ShowError( "MSN Passport verification failed with error %d: %s",
+ errCode.mErrorCode, errCode.getText());
+ }
+ else {
+ DWORD dwCode;
+ tBufSize = sizeof( dwCode );
+ f_HttpQueryInfo( tRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &dwCode, &tBufSize, 0 );
+
+ switch( dwCode ) {
+ case HTTP_STATUS_REDIRECT:
+ tBufSize = SSL_BUF_SIZE;
+ f_HttpQueryInfo( tRequest, HTTP_QUERY_LOCATION, tBuffer, &tBufSize, NULL );
+ MSN_DebugLog( "Redirected to '%s'", tBuffer );
+ tSslAnswer = getSslResult( tBuffer, parAuthInfo );
+ break;
+
+ case HTTP_STATUS_OK:
+ LBL_PrintHeaders:
+ tBufSize = SSL_BUF_SIZE;
+ f_HttpQueryInfo( tRequest, HTTP_QUERY_RAW_HEADERS_CRLF, tBuffer, &tBufSize, NULL );
+ MSN_DebugLog( "SSL response: '%s'", tBuffer );
+ tSslAnswer = dwCode == HTTP_STATUS_OK ? strdup( tBuffer ) : NULL;
+ break;
+
+ case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR:
+ case ERROR_INTERNET_INCORRECT_PASSWORD:
+ case ERROR_INTERNET_INVALID_CA:
+ case ERROR_INTERNET_POST_IS_NON_SECURE:
+ case ERROR_INTERNET_SEC_CERT_CN_INVALID:
+ case ERROR_INTERNET_SEC_CERT_DATE_INVALID:
+ case ERROR_INTERNET_SEC_CERT_ERRORS:
+ case ERROR_INTERNET_SEC_CERT_NO_REV:
+ case ERROR_INTERNET_SEC_CERT_REV_FAILED:
+ MSN_DebugLog( "HttpSendRequest returned error code %d", tErrorCode );
+ if ( ERROR_INTERNET_FORCE_RETRY == f_InternetErrorDlg( GetDesktopWindow(), tRequest, tErrorCode, ERROR_FLAGS, NULL )) {
+ readInput( tRequest );
+ goto LBL_Restart;
+ }
+
+ // else fall into the general error handling routine
+
+ default:
+ tBufSize = SSL_BUF_SIZE;
+ if ( !f_HttpQueryInfo( tRequest, HTTP_QUERY_STATUS_TEXT, tBuffer, &tBufSize, NULL ))
+ strcpy( tBuffer, "unknown error" );
+
+ MSN_ShowError( "Internet secure connection (SSL) failed with error %d: %s", dwCode, tBuffer );
+ MSN_DebugLog( "SSL error %d: '%s'", dwCode, tBuffer );
+ goto LBL_PrintHeaders;
+ } }
+
+ f_InternetCloseHandle( tRequest );
+ }
+
+ f_InternetCloseHandle( tUrlHandle );
+ }
+ else MSN_DebugLog( "InternetOpenUrl() failed" );
+
+ f_InternetCloseHandle( tNetHandle );
+ return tSslAnswer;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Performs the MSN Passport login via SSL3 using the OpenSSL library
+
+typedef int ( *PFN_SSL_int_void ) ( void );
+typedef PVOID ( *PFN_SSL_pvoid_void ) ( void );
+typedef PVOID ( *PFN_SSL_pvoid_pvoid ) ( PVOID );
+typedef void ( *PFN_SSL_void_pvoid ) ( PVOID );
+typedef int ( *PFN_SSL_int_pvoid_int ) ( PVOID, int );
+typedef int ( *PFN_SSL_int_pvoid ) ( PVOID );
+typedef int ( *PFN_SSL_int_pvoid_pvoid_int ) ( PVOID, PVOID, int );
+
+struct SSL_OpenSsl : public SSL_Base
+{
+ virtual char* getSslResult( char* parUrl, char* parAuthInfo );
+ virtual int init();
+
+ static PVOID sslCtx;
+
+ static HMODULE hLibSSL, hLibEAY;
+ static PFN_SSL_int_void pfn_SSL_library_init;
+ static PFN_SSL_pvoid_void pfn_SSLv23_client_method;
+ static PFN_SSL_pvoid_pvoid pfn_SSL_CTX_new;
+ static PFN_SSL_void_pvoid pfn_SSL_CTX_free;
+ static PFN_SSL_pvoid_pvoid pfn_SSL_new;
+ static PFN_SSL_void_pvoid pfn_SSL_free;
+ static PFN_SSL_int_pvoid_int pfn_SSL_set_fd;
+ static PFN_SSL_int_pvoid pfn_SSL_connect;
+ static PFN_SSL_int_pvoid_pvoid_int pfn_SSL_read;
+ static PFN_SSL_int_pvoid_pvoid_int pfn_SSL_write;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+PVOID SSL_OpenSsl::sslCtx = NULL;
+
+HMODULE SSL_OpenSsl::hLibSSL = NULL,
+ SSL_OpenSsl::hLibEAY = NULL;
+
+PFN_SSL_int_void SSL_OpenSsl::pfn_SSL_library_init;
+PFN_SSL_pvoid_void SSL_OpenSsl::pfn_SSLv23_client_method;
+PFN_SSL_pvoid_pvoid SSL_OpenSsl::pfn_SSL_CTX_new;
+PFN_SSL_void_pvoid SSL_OpenSsl::pfn_SSL_CTX_free;
+PFN_SSL_pvoid_pvoid SSL_OpenSsl::pfn_SSL_new;
+PFN_SSL_void_pvoid SSL_OpenSsl::pfn_SSL_free;
+PFN_SSL_int_pvoid_int SSL_OpenSsl::pfn_SSL_set_fd;
+PFN_SSL_int_pvoid SSL_OpenSsl::pfn_SSL_connect;
+PFN_SSL_int_pvoid_pvoid_int SSL_OpenSsl::pfn_SSL_read;
+PFN_SSL_int_pvoid_pvoid_int SSL_OpenSsl::pfn_SSL_write;
+
+int SSL_OpenSsl::init()
+{
+ if ( sslCtx != NULL )
+ return 0;
+
+ if ( hLibSSL == NULL ) {
+ if (( hLibEAY = LoadLibraryA( "LIBEAY32.DLL" )) == NULL ) {
+ MSN_ShowError( "Valid %s must be installed to perform the SSL login", "LIBEAY32.DLL" );
+ return 1;
+ }
+
+ if (( hLibSSL = LoadLibraryA( "LIBSSL32.DLL" )) == NULL ) {
+ MSN_ShowError( "Valid %s must be installed to perform the SSL login", "LIBSSL32.DLL" );
+ return 1;
+ } }
+
+ int retVal = 0;
+ if (( pfn_SSL_library_init = ( PFN_SSL_int_void )GetProcAddress( hLibSSL, "SSL_library_init" )) == NULL )
+ retVal = TRUE;
+ if (( pfn_SSLv23_client_method = ( PFN_SSL_pvoid_void )GetProcAddress( hLibSSL, "SSLv23_client_method" )) == NULL )
+ retVal = TRUE;
+ if (( pfn_SSL_CTX_new = ( PFN_SSL_pvoid_pvoid )GetProcAddress( hLibSSL, "SSL_CTX_new" )) == NULL )
+ retVal = TRUE;
+ if (( pfn_SSL_CTX_free = ( PFN_SSL_void_pvoid )GetProcAddress( hLibSSL, "SSL_CTX_free" )) == NULL )
+ retVal = TRUE;
+ if (( pfn_SSL_new = ( PFN_SSL_pvoid_pvoid )GetProcAddress( hLibSSL, "SSL_new" )) == NULL )
+ retVal = TRUE;
+ if (( pfn_SSL_free = ( PFN_SSL_void_pvoid )GetProcAddress( hLibSSL, "SSL_free" )) == NULL )
+ retVal = TRUE;
+ if (( pfn_SSL_set_fd = ( PFN_SSL_int_pvoid_int )GetProcAddress( hLibSSL, "SSL_set_fd" )) == NULL )
+ retVal = TRUE;
+ if (( pfn_SSL_connect = ( PFN_SSL_int_pvoid )GetProcAddress( hLibSSL, "SSL_connect" )) == NULL )
+ retVal = TRUE;
+ if (( pfn_SSL_read = ( PFN_SSL_int_pvoid_pvoid_int )GetProcAddress( hLibSSL, "SSL_read" )) == NULL )
+ retVal = TRUE;
+ if (( pfn_SSL_write = ( PFN_SSL_int_pvoid_pvoid_int )GetProcAddress( hLibSSL, "SSL_write" )) == NULL )
+ retVal = TRUE;
+
+ if ( retVal ) {
+ FreeLibrary( hLibSSL );
+ MSN_ShowError( "Valid %s must be installed to perform the SSL login", "LIBSSL32.DLL" );
+ return 1;
+ }
+
+ pfn_SSL_library_init();
+ sslCtx = pfn_SSL_CTX_new( pfn_SSLv23_client_method());
+ MSN_DebugLog( "OpenSSL context successully allocated" );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+char* SSL_OpenSsl::getSslResult( char* parUrl, char* parAuthInfo )
+{
+ if ( strnicmp( parUrl, "https://", 8 ) != 0 )
+ return NULL;
+
+ char* url = NEWSTR_ALLOCA( parUrl );
+ char* path = strchr( url+9, '//' );
+ if ( path == NULL ) {
+ MSN_DebugLog( "Invalid URL passed: '%s'", parUrl );
+ return NULL;
+ }
+ *path++ = 0;
+
+ NETLIBUSERSETTINGS nls = { 0 };
+ nls.cbSize = sizeof( nls );
+ MSN_CallService(MS_NETLIB_GETUSERSETTINGS,WPARAM(hNetlibUser),LPARAM(&nls));
+ int cpType = nls.proxyType;
+
+ if (cpType == PROXYTYPE_HTTP)
+ {
+ nls.proxyType = PROXYTYPE_HTTPS;
+ nls.szProxyServer = NEWSTR_ALLOCA(nls.szProxyServer);
+ nls.szIncomingPorts = NEWSTR_ALLOCA(nls.szIncomingPorts);
+ nls.szOutgoingPorts = NEWSTR_ALLOCA(nls.szOutgoingPorts);
+ nls.szProxyAuthPassword = NEWSTR_ALLOCA(nls.szProxyAuthPassword);
+ nls.szProxyAuthUser = NEWSTR_ALLOCA(nls.szProxyAuthUser);
+ MSN_CallService(MS_NETLIB_SETUSERSETTINGS,WPARAM(hNetlibUser),LPARAM(&nls));
+ }
+
+ NETLIBOPENCONNECTION tConn = { 0 };
+ tConn.cbSize = sizeof( tConn );
+ tConn.szHost = url+8;
+ tConn.wPort = 443;
+ HANDLE h = ( HANDLE )MSN_CallService( MS_NETLIB_OPENCONNECTION, ( WPARAM )hNetlibUser, ( LPARAM )&tConn );
+
+ if (cpType == PROXYTYPE_HTTP)
+ {
+ nls.proxyType = PROXYTYPE_HTTP;
+ nls.szProxyServer = NEWSTR_ALLOCA(nls.szProxyServer);
+ nls.szIncomingPorts = NEWSTR_ALLOCA(nls.szIncomingPorts);
+ nls.szOutgoingPorts = NEWSTR_ALLOCA(nls.szOutgoingPorts);
+ nls.szProxyAuthPassword = NEWSTR_ALLOCA(nls.szProxyAuthPassword);
+ nls.szProxyAuthUser = NEWSTR_ALLOCA(nls.szProxyAuthUser);
+ MSN_CallService(MS_NETLIB_SETUSERSETTINGS,WPARAM(hNetlibUser),LPARAM(&nls));
+ }
+
+ if ( h == NULL )
+ return NULL;
+
+ char* result = NULL;
+ PVOID ssl = pfn_SSL_new( sslCtx );
+ if ( ssl != NULL ) {
+ SOCKET s = MSN_CallService( MS_NETLIB_GETSOCKET, ( WPARAM )h, 0 );
+ if ( s != INVALID_SOCKET ) {
+ pfn_SSL_set_fd( ssl, s );
+ if ( pfn_SSL_connect( ssl ) > 0 ) {
+ MSN_DebugLog( "SSL connection succeeded" );
+
+ char *buf = ( char* )alloca( SSL_BUF_SIZE );
+
+ int nBytes = mir_snprintf( buf, SSL_BUF_SIZE,
+ "GET /%s HTTP/1.1\r\n"
+ "Accept: */*\r\n"
+ "Accept-Language: en;q=0.5\r\n"
+ "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\r\n"
+ "Host: %s\r\n"
+ "Connection: Keep-Alive\r\n", path, url+8 );
+
+ if ( parAuthInfo != NULL ) {
+ strcat( buf+nBytes, parAuthInfo );
+ strcat( buf+nBytes, "\r\n" );
+ }
+
+ strcat( buf+nBytes, "\r\n" );
+
+// MSN_DebugLog( "Sending SSL query:\n%s", buf );
+ pfn_SSL_write( ssl, buf, strlen( buf ));
+
+ nBytes = pfn_SSL_read( ssl, buf, SSL_BUF_SIZE );
+ if ( nBytes > 0 ) {
+ result = ( char* )malloc( nBytes+1 );
+ memcpy( result, buf, nBytes+1 );
+ result[ nBytes ] = 0;
+
+ MSN_DebugLog( "SSL read successfully read %d bytes:\n%s", nBytes, result );
+ }
+ else MSN_DebugLog( "SSL read failed" );
+ }
+ else MSN_DebugLog( "SSL connection failed" );
+ }
+ else MSN_DebugLog( "pfn_SSL_connect failed" );
+
+ pfn_SSL_free( ssl );
+ }
+ else MSN_DebugLog( "pfn_SSL_new failed" );
+
+ MSN_CallService( MS_NETLIB_CLOSEHANDLE, ( WPARAM )h, 0 );
+ return result;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Checks the MSN Passport redirector site
+
+int MSN_CheckRedirector()
+{
+ int retVal = 0;
+ SSL_Base* pAgent;
+ if ( MSN_GetByte( "UseOpenSSL", 0 ))
+ pAgent = new SSL_OpenSsl();
+ else
+ pAgent = new SSL_WinInet();
+ if ( pAgent == NULL )
+ return 1;
+
+ if ( pAgent->init() ) {
+ delete pAgent;
+ return 2;
+ }
+
+ char* msnLoginHost = pAgent->getSslResult( "https://nexus.passport.com/rdr/pprdr.asp", NULL );
+ if ( msnLoginHost == NULL ) {
+ retVal = 1;
+LBL_Exit:
+ delete pAgent;
+ MSN_DebugLog( "MSN_CheckRedirector exited with errorCode = %d", retVal );
+ return retVal;
+ }
+
+ char* p = strstr( msnLoginHost, "DALogin=" );
+ if ( p == NULL ) {
+ free( msnLoginHost ); msnLoginHost = NULL;
+ retVal = 2;
+ goto LBL_Exit;
+ }
+
+ strcpy( msnLoginHost, "https://" );
+ strdel( msnLoginHost+8, int( p-msnLoginHost ));
+ if (( p = strchr( msnLoginHost, ',' )) != 0 )
+ *p = 0;
+
+ MSN_SetString( NULL, "MsnPassportHost", msnLoginHost );
+ MSN_DebugLog( "MSN Passport login host is set to '%s'", msnLoginHost );
+ free( msnLoginHost );
+ goto LBL_Exit;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Performs the MSN Passport login via SSL3
+
+int MSN_GetPassportAuth( char* authChallengeInfo, char*& parResult )
+{
+ int retVal = 0;
+ parResult = NULL;
+ SSL_Base* pAgent;
+ if ( MSN_GetByte( "UseOpenSSL", 0 ))
+ pAgent = new SSL_OpenSsl();
+ else
+ pAgent = new SSL_WinInet();
+ if ( pAgent == NULL )
+ return 1;
+
+ if ( pAgent->init() ) {
+ delete pAgent;
+ return 2;
+ }
+
+ char szEmail[ MSN_MAX_EMAIL_LEN ];
+ MSN_GetStaticString( "e-mail", NULL, szEmail, MSN_MAX_EMAIL_LEN );
+ char* p = strchr( szEmail, '@' );
+ if ( p != NULL ) {
+ memmove( p+3, p+1, strlen( p ));
+ memcpy( p, "%40", 3 );
+ }
+
+ char szPassword[ 100 ];
+ MSN_GetStaticString( "Password", NULL, szPassword, sizeof szPassword );
+ MSN_CallService( MS_DB_CRYPT_DECODESTRING, strlen( szPassword )+1, ( LPARAM )szPassword );
+ szPassword[ 16 ] = 0;
+
+ char* szAuthInfo = ( char* )alloca( 1024 );
+ int nBytes = mir_snprintf( szAuthInfo, 1024,
+ "Authorization: Passport1.4 OrgVerb=GET,OrgURL=http%%3A%%2F%%2Fmessenger%%2Emsn%%2Ecom,sign-in=%s,pwd=",
+ szEmail );
+ UrlEncode( szPassword, szAuthInfo+nBytes, 1024-nBytes );
+ strcat( szAuthInfo+nBytes, "," );
+ strcat( szAuthInfo+nBytes, authChallengeInfo );
+
+ char szPassportHost[ 256 ];
+ if ( MSN_GetStaticString( "MsnPassportHost", NULL, szPassportHost, sizeof( szPassportHost ))) {
+ retVal = 3;
+LBL_Exit:
+ delete pAgent;
+ MSN_DebugLog( "MSN_CheckRedirector exited with errorCode = %d", retVal );
+ return retVal;
+ }
+
+ char* tResult;
+
+ for (;;)
+ {
+ tResult = pAgent->getSslResult( szPassportHost, szAuthInfo );
+ if ( tResult == NULL ) {
+ retVal = 4;
+ goto LBL_Exit;
+ }
+
+ int status = 0;
+ sscanf( tResult, "HTTP/1.1 %d", &status );
+ if ( status == 302 ) // Handle redirect
+ {
+ if (( p = strstr( tResult, "Location:" )) == NULL ) {
+ free( tResult );
+ retVal = 7;
+ goto LBL_Exit;
+ }
+ strdel( tResult, int( p-tResult )+10 );
+ if (( p = strchr( tResult, '\r' )) != NULL )
+ *p = 0;
+ strcpy(szPassportHost, tResult);
+ MSN_DebugLog( "Redirected to '%s'", tResult );
+ free( tResult );
+ }
+ else if (status != 200)
+ {
+ retVal = 6;
+ free( tResult );
+ goto LBL_Exit;
+ }
+ else break;
+ }
+
+ if (( p = strstr( tResult, "from-PP=" )) == NULL ) {
+ free( tResult );
+ retVal = 5;
+ goto LBL_Exit;
+ }
+
+ strdel( tResult, int( p-tResult )+9 );
+
+ if (( p = strchr( tResult, '\'' )) != NULL )
+ *p = 0;
+
+ parResult = tResult;
+ goto LBL_Exit;
+}
+
+void UninitSsl( void )
+{
+ if ( SSL_OpenSsl::hLibEAY )
+ FreeLibrary( SSL_OpenSsl::hLibEAY );
+
+ if ( SSL_OpenSsl::hLibSSL ) {
+ SSL_OpenSsl::pfn_SSL_CTX_free( SSL_OpenSsl::sslCtx );
+
+ MSN_DebugLog( "Free SSL library" );
+ FreeLibrary( SSL_OpenSsl::hLibSSL );
+} }
diff --git a/miranda-wine/protocols/MSN/msn_std.cpp b/miranda-wine/protocols/MSN/msn_std.cpp
new file mode 100644
index 0000000..c13af19
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_std.cpp
@@ -0,0 +1,158 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "msn_global.h"
+
+extern HANDLE msnBlockMenuItem;
+
+HANDLE __stdcall MSN_CreateProtoServiceFunction(
+ const char* szService,
+ MIRANDASERVICE serviceProc )
+{
+ char str[ MAXMODULELABELLENGTH ];
+ strcpy( str, msnProtocolName );
+ strcat( str, szService );
+ return CreateServiceFunction( str, serviceProc );
+}
+
+#if !defined( _DEBUG )
+int __stdcall MSN_CallService( const char* szSvcName, WPARAM wParam, LPARAM lParam )
+{
+ return CallService( szSvcName, wParam, lParam );
+}
+#endif
+
+void __stdcall MSN_EnableMenuItems( BOOL parEnable )
+{
+ CLISTMENUITEM clmi;
+ memset( &clmi, 0, sizeof( clmi ));
+ clmi.cbSize = sizeof( clmi );
+ clmi.flags = CMIM_FLAGS;
+ if ( !parEnable )
+ clmi.flags |= CMIF_GRAYED;
+
+ for ( int i=0; i < MENU_ITEMS_COUNT; i++ )
+ {
+ if ( msnMenuItems[i] == NULL )
+ continue;
+
+ MSN_CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )msnMenuItems[i], ( LPARAM )&clmi );
+ }
+
+ MSN_CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )msnBlockMenuItem, ( LPARAM )&clmi );
+}
+
+DWORD __stdcall MSN_GetByte( const char* valueName, int parDefltValue )
+{
+ return DBGetContactSettingByte( NULL, msnProtocolName, valueName, parDefltValue );
+}
+
+char* __stdcall MSN_GetContactName( HANDLE hContact )
+{
+ return ( char* )MSN_CallService( MS_CLIST_GETCONTACTDISPLAYNAME, WPARAM( hContact), 0 );
+}
+
+TCHAR* __stdcall MSN_GetContactNameT( HANDLE hContact )
+{
+ return ( TCHAR* )MSN_CallService( MS_CLIST_GETCONTACTDISPLAYNAME, WPARAM( hContact), GCDNF_TCHAR );
+}
+
+DWORD __stdcall MSN_GetDword( HANDLE hContact, const char* valueName, DWORD parDefltValue )
+{
+ return DBGetContactSettingDword( hContact, msnProtocolName, valueName, parDefltValue );
+}
+
+int __stdcall MSN_GetStaticString( 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 = msnProtocolName;
+ sVal.szSetting = valueName;
+ if ( MSN_CallService( MS_DB_CONTACT_GETSETTINGSTATIC, ( WPARAM )hContact, ( LPARAM )&sVal ) != 0 )
+ return 1;
+
+ return ( dbv.type != DBVT_ASCIIZ );
+}
+
+WORD __stdcall MSN_GetWord( HANDLE hContact, const char* valueName, int parDefltValue )
+{
+ return DBGetContactSettingWord( hContact, msnProtocolName, valueName, parDefltValue );
+}
+
+void __fastcall MSN_FreeVariant( DBVARIANT* dbv )
+{
+ DBFreeVariant( dbv );
+}
+
+int __stdcall MSN_SendBroadcast( HANDLE hContact, int type, int result, HANDLE hProcess, LPARAM lParam )
+{
+ ACKDATA ack = {0};
+ ack.cbSize = sizeof( ACKDATA );
+ ack.szModule = msnProtocolName;
+ ack.hContact = hContact;
+ ack.type = type;
+ ack.result = result;
+ ack.hProcess = hProcess;
+ ack.lParam = lParam;
+ return MSN_CallService( MS_PROTO_BROADCASTACK, 0, ( LPARAM )&ack );
+}
+
+DWORD __stdcall MSN_SetByte( const char* valueName, int parValue )
+{
+ return DBWriteContactSettingByte( NULL, msnProtocolName, valueName, parValue );
+}
+
+DWORD __stdcall MSN_SetDword( HANDLE hContact, const char* valueName, DWORD parValue )
+{
+ return DBWriteContactSettingDword( hContact, msnProtocolName, valueName, parValue );
+}
+
+DWORD __stdcall MSN_SetString( HANDLE hContact, const char* valueName, const char* parValue )
+{
+ return DBWriteContactSettingString( hContact, msnProtocolName, valueName, parValue );
+}
+
+DWORD __stdcall MSN_SetStringT( HANDLE hContact, const char* valueName, const TCHAR* parValue )
+{
+ return DBWriteContactSettingTString( hContact, msnProtocolName, valueName, parValue );
+}
+
+DWORD __stdcall MSN_SetStringUtf( HANDLE hContact, const char* valueName, char* parValue )
+{
+ return DBWriteContactSettingStringUtf( hContact, msnProtocolName, valueName, parValue );
+}
+
+DWORD __stdcall MSN_SetWord( HANDLE hContact, const char* valueName, int parValue )
+{
+ return DBWriteContactSettingWord( hContact, msnProtocolName, valueName, parValue );
+}
+
+char* __stdcall MSN_Translate( const char* str )
+{
+ return Translate( str );
+}
diff --git a/miranda-wine/protocols/MSN/msn_svcs.cpp b/miranda-wine/protocols/MSN/msn_svcs.cpp
new file mode 100644
index 0000000..1faac95
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_svcs.cpp
@@ -0,0 +1,1404 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "msn_global.h"
+
+#include <fcntl.h>
+#include <io.h>
+#include <sys/stat.h>
+
+#include "resource.h"
+
+void __cdecl MSNServerThread( ThreadData* info );
+void MSN_ChatStart(ThreadData* info);
+
+void msnftp_sendAcceptReject( filetransfer *ft, bool acc );
+
+HANDLE msnBlockMenuItem = NULL;
+extern char* profileURL;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnAddToList - adds contact to the server list
+
+static HANDLE AddToListByEmail( const char *email, DWORD flags )
+{
+ char urlEmail[ 255 ], *szProto;
+ UrlEncode( email, urlEmail, sizeof( urlEmail ));
+ HANDLE hContact;
+
+ //check not already on list
+ for ( hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ hContact != NULL;
+ hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM )hContact, 0 ))
+ {
+ szProto = ( char* )MSN_CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact, 0 );
+ if ( szProto != NULL && !strcmp( szProto, msnProtocolName )) {
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( MSN_GetStaticString( "e-mail", hContact, tEmail, sizeof( tEmail )))
+ continue;
+
+ if ( strcmp( tEmail, email ))
+ continue;
+
+ if ( !( flags & PALF_TEMPORARY ) && DBGetContactSettingByte( hContact, "CList", "NotOnList", 1 )) {
+ DBDeleteContactSetting( hContact, "CList", "NotOnList" );
+ DBDeleteContactSetting( hContact, "CList", "Hidden" );
+LBL_AddContact:
+ if ( msnLoggedIn ) {
+ MSN_AddUser( hContact, urlEmail, LIST_FL );
+ MSN_AddUser( hContact, urlEmail, LIST_BL + LIST_REMOVE );
+ MSN_AddUser( hContact, urlEmail, LIST_AL );
+ }
+ else hContact = NULL;
+ }
+
+ return hContact;
+ } }
+
+ //not already there: add
+ hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_ADD, 0, 0 );
+ MSN_CallService( MS_PROTO_ADDTOCONTACT, ( WPARAM )hContact,( LPARAM )msnProtocolName );
+ MSN_SetString( hContact, "e-mail", email );
+
+ if ( !( flags & PALF_TEMPORARY ))
+ goto LBL_AddContact;
+
+ DBWriteContactSettingByte( hContact, "CList", "NotOnList", 1 );
+ DBWriteContactSettingByte( hContact, "CList", "Hidden", 1 );
+ return hContact;
+}
+
+static int MsnAddToList(WPARAM wParam,LPARAM lParam)
+{
+ PROTOSEARCHRESULT *psr=(PROTOSEARCHRESULT*)lParam;
+
+ if ( psr->cbSize != sizeof( PROTOSEARCHRESULT ))
+ return NULL;
+
+ return ( int )AddToListByEmail( psr->email, wParam );
+}
+
+static int MsnAddToListByEvent(WPARAM wParam, LPARAM lParam)
+{
+ DBEVENTINFO dbei = {0};
+ dbei.cbSize = sizeof(dbei);
+ if (( dbei.cbBlob = MSN_CallService( MS_DB_EVENT_GETBLOBSIZE, lParam, 0 )) == (DWORD)(-1))
+ return 0;
+
+ dbei.pBlob=(PBYTE) alloca(dbei.cbBlob);
+ if ( MSN_CallService(MS_DB_EVENT_GET, lParam, ( LPARAM )&dbei)) return 0;
+ if ( strcmp(dbei.szModule, msnProtocolName)) return 0;
+ if ( dbei.eventType != EVENTTYPE_AUTHREQUEST) return 0;
+
+ char* nick = (char *) (dbei.pBlob + sizeof(DWORD) + sizeof(HANDLE));
+ char* firstName = nick + strlen(nick) + 1;
+ char* lastName = firstName + strlen(firstName) + 1;
+ char* email = lastName + strlen(lastName) + 1;
+
+ return ( int ) AddToListByEmail( email, 0 );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnAuthAllow - called after successful authorization
+
+static int MsnAuthAllow(WPARAM wParam,LPARAM lParam)
+{
+ if ( !msnLoggedIn )
+ return 1;
+
+ DBEVENTINFO dbei;
+ memset( &dbei, 0, sizeof( dbei ));
+ dbei.cbSize = sizeof( dbei );
+
+ if (( dbei.cbBlob = MSN_CallService( MS_DB_EVENT_GETBLOBSIZE, wParam, 0 )) == -1 )
+ return 1;
+
+ dbei.pBlob = ( PBYTE )alloca( dbei.cbBlob );
+ if ( MSN_CallService( MS_DB_EVENT_GET, wParam, ( LPARAM )&dbei ))
+ return 1;
+
+ if ( dbei.eventType != EVENTTYPE_AUTHREQUEST )
+ return 1;
+
+ if ( strcmp( dbei.szModule, msnProtocolName ))
+ return 1;
+
+ char* nick = ( char* )( dbei.pBlob + sizeof( DWORD )*2 );
+ char* firstName = nick + strlen( nick ) + 1;
+ char* lastName = firstName + strlen( firstName ) + 1;
+ char* email = lastName + strlen( lastName ) + 1;
+
+ char urlNick[388],urlEmail[130];
+
+ UrlEncode( UTF8( nick ), urlNick, sizeof( urlNick ));
+ UrlEncode( email, urlEmail, sizeof( urlEmail ));
+
+ AddToListByEmail( email, 0 );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnAuthDeny - called after unsuccessful authorization
+
+static int MsnAuthDeny(WPARAM wParam,LPARAM lParam)
+{
+ if ( !msnLoggedIn )
+ return 1;
+
+ DBEVENTINFO dbei;
+ memset( &dbei, 0, sizeof( dbei ));
+ dbei.cbSize = sizeof( dbei );
+
+ if (( dbei.cbBlob = MSN_CallService( MS_DB_EVENT_GETBLOBSIZE, wParam, 0 )) == -1 )
+ return 1;
+
+ dbei.pBlob = ( PBYTE )alloca( dbei.cbBlob );
+ if ( MSN_CallService( MS_DB_EVENT_GET, wParam, ( LPARAM )&dbei ))
+ return 1;
+
+ if ( dbei.eventType != EVENTTYPE_AUTHREQUEST )
+ return 1;
+
+ if ( strcmp( dbei.szModule, msnProtocolName ))
+ return 1;
+
+ char* nick = ( char* )( dbei.pBlob + sizeof( DWORD )*2 );
+ char* firstName = nick + strlen( nick ) + 1;
+ char* lastName = firstName + strlen( firstName ) + 1;
+ char* email = lastName + strlen( lastName ) + 1;
+
+ char urlNick[388],urlEmail[130];
+
+ UrlEncode( UTF8(nick), urlNick, sizeof( urlNick ));
+ UrlEncode( email, urlEmail, sizeof( urlEmail ));
+
+ MSN_AddUser( NULL, urlEmail, LIST_BL );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnBasicSearch - search contacts by e-mail
+
+static int MsnBasicSearch(WPARAM wParam,LPARAM lParam)
+{
+ if ( !msnLoggedIn || msnSearchID != -1 )
+ return 0;
+
+ char tEmail[ 256 ];
+ if ( !MSN_GetStaticString( "e-mail", NULL, tEmail, sizeof tEmail )) {
+ if ( !stricmp(( char* )lParam, tEmail )) {
+ MSN_ShowError( "You cannot add yourself to the contact list" );
+ return 0;
+ } }
+
+ UrlEncode(( char* )lParam, tEmail, sizeof( tEmail ));
+ return msnSearchID = msnNsThread->sendPacket( "ADC", "BL N=%s", tEmail );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Block command callback function
+
+static int MsnBlockCommand( WPARAM wParam, LPARAM lParam )
+{
+ if ( msnLoggedIn ) {
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( !MSN_GetStaticString( "e-mail", ( HANDLE )wParam, tEmail, sizeof( tEmail )))
+ MSN_SetWord(( HANDLE )wParam, "ApparentMode", ( Lists_IsInList( LIST_BL, tEmail )) ? 0 : ID_STATUS_OFFLINE );
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnContactDeleted - called when a contact is deleted from list
+
+static int MsnContactDeleted( WPARAM wParam, LPARAM lParam )
+{
+ if ( !msnLoggedIn ) //should never happen for MSN contacts
+ return 0;
+
+ char* szProto = ( char* )MSN_CallService( MS_PROTO_GETCONTACTBASEPROTO, wParam, 0 );
+ if ( szProto == NULL || strcmp( szProto, msnProtocolName ))
+ return 0;
+
+ HANDLE hContact = ( HANDLE )wParam;
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( !MSN_GetStaticString( "e-mail", hContact, tEmail, sizeof( tEmail ))) {
+ MSN_AddUser( hContact, tEmail, LIST_FL | LIST_REMOVE );
+ MSN_AddUser( hContact, tEmail, LIST_AL | LIST_REMOVE );
+
+ if ( !Lists_IsInList( LIST_RL, tEmail )) {
+ MSN_AddUser( hContact, tEmail, LIST_BL | LIST_REMOVE );
+ Lists_Remove( 0xFF, tEmail );
+ }
+ else {
+ MSN_AddUser( hContact, tEmail, LIST_BL );
+ Lists_Remove( LIST_FL, tEmail );
+ } }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnDbSettingChanged - look for contact's settings changes
+
+static int MsnDbSettingChanged(WPARAM wParam,LPARAM lParam)
+{
+ HANDLE hContact = ( HANDLE )wParam;
+ DBCONTACTWRITESETTING* cws = ( DBCONTACTWRITESETTING* )lParam;
+
+ if ( !msnLoggedIn )
+ return 0;
+
+ if ( hContact == NULL && MyOptions.ManageServer && !strcmp( cws->szModule, "CListGroups" )) {
+ int iNumber = atol( cws->szSetting );
+ LPCSTR szId = MSN_GetGroupByNumber( iNumber );
+ if ( szId == NULL ) {
+ if ( cws->value.type == DBVT_ASCIIZ )
+ MSN_AddServerGroup( cws->value.pszVal+1 );
+ return 0;
+ }
+
+ switch ( cws->value.type ) {
+ case DBVT_DELETED: msnNsThread->sendPacket( "RMG", szId ); break;
+ case DBVT_UTF8: MSN_RenameServerGroup( iNumber, szId, cws->value.pszVal+1 ); break;
+ case DBVT_ASCIIZ: MSN_RenameServerGroup( iNumber, szId, UTF8( cws->value.pszVal+1 )); break;
+ }
+ return 0;
+ }
+
+ if ( !strcmp( cws->szSetting, "ApparentMode" )) {
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( !MSN_GetStaticString( "e-mail", hContact, tEmail, sizeof( tEmail ))) {
+ int isBlocked = Lists_IsInList( LIST_BL, tEmail );
+
+ if ( !isBlocked && cws->value.wVal == ID_STATUS_OFFLINE ) {
+ MSN_AddUser( hContact, tEmail, LIST_AL + LIST_REMOVE );
+ MSN_AddUser( hContact, tEmail, LIST_BL );
+ }
+ else if ( isBlocked && cws->value.wVal == 0 ) {
+ MSN_AddUser( hContact, tEmail, LIST_BL + LIST_REMOVE );
+ MSN_AddUser( hContact, tEmail, LIST_AL );
+ } } }
+
+ if ( !strcmp( cws->szModule, "CList" ) && MyOptions.ManageServer ) {
+ char* szProto = ( char* )MSN_CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 );
+ if ( szProto == NULL || strcmp( szProto, msnProtocolName ))
+ return 0;
+
+ if ( !strcmp( cws->szSetting, "Group" )) {
+ switch( cws->value.type ) {
+ case DBVT_DELETED: MSN_MoveContactToGroup( hContact, NULL ); break;
+ case DBVT_ASCIIZ: MSN_MoveContactToGroup( hContact, UTF8(cws->value.pszVal)); break;
+ case DBVT_UTF8: MSN_MoveContactToGroup( hContact, cws->value.pszVal ); break;
+ }
+ return 0;
+ }
+
+ if ( !strcmp( cws->szSetting, "MyHandle" )) {
+ char szContactID[ 100 ], szNewNick[ 387 ];
+ if ( !MSN_GetStaticString( "ID", hContact, szContactID, sizeof( szContactID ))) {
+ if ( cws->value.type != DBVT_DELETED ) {
+ if ( cws->value.type == DBVT_UTF8 )
+ UrlEncode( cws->value.pszVal, szNewNick, sizeof( szNewNick ));
+ else
+ UrlEncode( UTF8(cws->value.pszVal), szNewNick, sizeof( szNewNick ));
+ msnNsThread->sendPacket( "SBP", "%s MFN %s", szContactID, szNewNick );
+ }
+ else {
+ MSN_GetStaticString( "e-mail", hContact, szNewNick, sizeof( szNewNick ));
+ msnNsThread->sendPacket( "SBP", "%s MFN %s", szContactID, szNewNick );
+ }
+ return 0;
+ } } }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnEditProfile - goes to the Profile section at the Hotmail.com
+
+static int MsnEditProfile( WPARAM, LPARAM )
+{
+ char tUrl[ 4096 ];
+ mir_snprintf( tUrl, sizeof( tUrl ), "%s&did=1&t=%s&js=yes", profileURL, MSPAuth );
+ MSN_CallService( MS_UTILS_OPENURL, TRUE, ( LPARAM )tUrl );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnFileAllow - starts the file transfer
+
+static void __cdecl MsnFileAckThread( void* arg )
+{
+ filetransfer* ft = (filetransfer*)arg;
+ if ( !ft->inmemTransfer )
+ {
+ char filefull[ MAX_PATH ];
+ mir_snprintf( filefull, sizeof filefull, "%s\\%s", ft->std.workingDir, ft->std.currentFile );
+ replaceStr( ft->std.currentFile, filefull );
+
+ if ( MSN_SendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, ft, ( LPARAM )&ft->std ))
+ return;
+
+ if ( ft->wszFileName != NULL ) {
+ free( ft->wszFileName );
+ ft->wszFileName = NULL;
+ } }
+
+ bool fcrt = ft->create() != -1;
+
+ if ( ft->p2p_appID != 0)
+ p2p_sendStatus( ft, MSN_GetThreadByID( ft->mThreadId ), fcrt ? 200 : 603 );
+ else
+ msnftp_sendAcceptReject (ft, fcrt);
+
+ MSN_SendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, ft, 0);
+}
+
+int MsnFileAllow(WPARAM wParam, LPARAM lParam)
+{
+ if ( !msnLoggedIn )
+ return 0;
+
+ CCSDATA* ccs = ( CCSDATA* )lParam;
+ filetransfer* ft = ( filetransfer* )ccs->wParam;
+
+ if (( ft->std.workingDir = strdup(( char* )ccs->lParam )) == NULL ) {
+ char szCurrDir[ MAX_PATH ];
+ GetCurrentDirectoryA( sizeof( szCurrDir ), szCurrDir );
+ ft->std.workingDir = strdup( szCurrDir );
+ }
+ else {
+ int len = strlen( ft->std.workingDir )-1;
+ if ( ft->std.workingDir[ len ] == '\\' )
+ ft->std.workingDir[ len ] = 0;
+ }
+
+ MSN_StartThread( MsnFileAckThread, ft );
+
+ return int( ft );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnFileCancel - cancels the active file transfer
+
+int MsnFileCancel(WPARAM wParam, LPARAM lParam)
+{
+ CCSDATA* ccs = ( CCSDATA* )lParam;
+ filetransfer* ft = ( filetransfer* )ccs->wParam;
+
+ if ( ft->hWaitEvent != INVALID_HANDLE_VALUE )
+ SetEvent( ft->hWaitEvent );
+
+ ThreadData* thread = MSN_GetThreadByID( ft->mThreadId );
+ if (!ft->std.sending && ft->fileId == -1)
+ {
+ if ( ft->p2p_appID != 0 )
+ p2p_sendStatus(ft, thread, 603);
+ else
+ msnftp_sendAcceptReject (ft, false);
+ }
+ else
+ {
+ if ( ft->p2p_appID != 0 )
+ p2p_sendCancel( thread, ft );
+ else
+ ft->bCanceled = true;
+ }
+
+ ft->std.files = NULL;
+ ft->std.totalFiles = 0;
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnFileDeny - rejects the file transfer request
+
+int MsnFileDeny( WPARAM wParam, LPARAM lParam )
+{
+ if ( !msnLoggedIn )
+ return 1;
+
+ CCSDATA* ccs = ( CCSDATA* )lParam;
+ filetransfer* ft = ( filetransfer* )ccs->wParam;
+
+ if ( ft->p2p_appID != 0 )
+ p2p_sendStatus( ft, MSN_GetThreadByID(ft->mThreadId), 603 );
+ else
+ msnftp_sendAcceptReject (ft, false);
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnFileResume - renames a file
+
+int MsnFileResume( WPARAM wParam, LPARAM lParam )
+{
+ filetransfer* ft = ( filetransfer* )wParam;
+ if ( !msnLoggedIn || ft == NULL )
+ return 1;
+
+ PROTOFILERESUME *pfr = (PROTOFILERESUME*)lParam;
+ switch (pfr->action)
+ {
+ case FILERESUME_SKIP:
+ if ( ft->p2p_appID != 0 )
+ p2p_sendStatus( ft, MSN_GetThreadByID( ft->mThreadId ), 603 );
+ else
+ msnftp_sendAcceptReject (ft, false);
+ break;
+
+ case FILERESUME_RENAME:
+ if ( ft->wszFileName != NULL ) {
+ free( ft->wszFileName );
+ ft->wszFileName = NULL;
+ }
+ replaceStr( ft->std.currentFile, pfr->szFilename );
+
+ default:
+ bool fcrt = ft->create() != -1;
+ if ( ft->p2p_appID != 0 )
+ p2p_sendStatus( ft, MSN_GetThreadByID( ft->mThreadId ), fcrt ? 200 : 603 );
+ else
+ msnftp_sendAcceptReject (ft, fcrt);
+
+ MSN_SendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, ft, 0);
+ break;
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnGetAvatarInfo - retrieve the avatar info
+
+static int MsnGetAvatarInfo(WPARAM wParam,LPARAM lParam)
+{
+ PROTO_AVATAR_INFORMATION* AI = ( PROTO_AVATAR_INFORMATION* )lParam;
+
+ if ( !MyOptions.EnableAvatars || ( MSN_GetDword( AI->hContact, "FlagBits", 0 ) & 0x40000000 ) == 0 )
+ return GAIR_NOAVATAR;
+
+ char szContext[ MAX_PATH ];
+ if ( MSN_GetStaticString(( AI->hContact == NULL ) ? "PictObject" : "PictContext", AI->hContact, szContext, sizeof szContext ))
+ return GAIR_NOAVATAR;
+
+ MSN_GetAvatarFileName( AI->hContact, AI->filename, sizeof AI->filename );
+ AI->format = ( AI->hContact == NULL ) ? PA_FORMAT_PNG : PA_FORMAT_BMP;
+
+ if ( ::access( AI->filename, 0 ) == 0 ) {
+ char szSavedContext[ 256 ];
+ if ( !MSN_GetStaticString( "PictSavedContext", AI->hContact, szSavedContext, sizeof szSavedContext ))
+ if ( !strcmp( szSavedContext, szContext ))
+ return GAIR_SUCCESS;
+ }
+
+ if (( wParam & GAIF_FORCE ) != 0 && AI->hContact != NULL ) {
+ p2p_invite( AI->hContact, MSN_APPID_AVATAR );
+ return GAIR_WAITFOR;
+ }
+
+ return GAIR_NOAVATAR;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnGetAwayMsg - reads the current status message for a user
+
+static void __cdecl MsnGetAwayMsgThread( HANDLE hContact )
+{
+ DBVARIANT dbv;
+ if ( !DBGetContactSetting( hContact, "CList", "StatusMsg", &dbv )) {
+ MSN_SendBroadcast( hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, ( HANDLE )1, ( LPARAM )dbv.pszVal );
+ MSN_FreeVariant( &dbv );
+ }
+ else MSN_SendBroadcast( hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, ( HANDLE )1, ( LPARAM )0 );
+}
+
+static int MsnGetAwayMsg(WPARAM wParam,LPARAM lParam)
+{
+ CCSDATA* ccs = ( CCSDATA* )lParam;
+ MSN_StartThread( MsnGetAwayMsgThread, ccs->hContact );
+ return 1;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnGetCaps - obtain the protocol capabilities
+
+static int MsnGetCaps(WPARAM wParam,LPARAM lParam)
+{
+ switch( wParam ) {
+ case PFLAGNUM_1:
+ { int result = PF1_IM | PF1_SERVERCLIST | PF1_AUTHREQ | PF1_BASICSEARCH |
+ PF1_ADDSEARCHRES | PF1_SEARCHBYEMAIL | PF1_USERIDISEMAIL |
+ PF1_FILESEND | PF1_FILERECV | PF1_URLRECV | PF1_VISLIST;
+ if ( MyOptions.UseMSNP11 )
+ result |= PF1_MODEMSG;
+ return result;
+ }
+ case PFLAGNUM_2:
+ return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND |
+ PF2_ONTHEPHONE | PF2_OUTTOLUNCH | PF2_INVISIBLE;
+
+ case PFLAGNUM_3:
+ return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND |
+ PF2_ONTHEPHONE | PF2_OUTTOLUNCH;
+
+ case PFLAGNUM_4:
+ return PF4_SUPPORTTYPING | PF4_AVATARS;
+
+ case PFLAG_UNIQUEIDTEXT:
+ return ( int )MSN_Translate( "E-mail address" );
+
+ case PFLAG_UNIQUEIDSETTING:
+ return ( int )"e-mail";
+
+ case PFLAG_MAXLENOFMESSAGE:
+ return 1202;
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnGetInfo - nothing to do, cause we cannot obtain information from the server
+
+HANDLE msnGetInfoContact = NULL;
+
+static int MsnGetInfo(WPARAM wParam,LPARAM lParam)
+{
+ if ( !msnLoggedIn )
+ return 0;
+
+ CCSDATA *ccs=(CCSDATA*)lParam;
+ msnGetInfoContact = ccs->hContact;
+ msnNsThread->send( "PNG\r\n", 5 );
+ return 1;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnGetName - obtain the protocol name
+
+static int MsnGetName( WPARAM wParam, LPARAM lParam )
+{
+ lstrcpynA(( char* )lParam, msnProtocolName, wParam );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnGetStatus - obtain the protocol status
+
+static int MsnGetStatus(WPARAM wParam,LPARAM lParam)
+{
+ return msnStatusMode;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnGotoInbox - goes to the Inbox folder at the Hotmail.com
+
+static int MsnGotoInbox( WPARAM, LPARAM )
+{
+ DWORD tThreadID;
+ CreateThread( NULL, 0, MsnShowMailThread, NULL, 0, &tThreadID );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnInviteCommand - invite command callback function
+
+static int MsnInviteCommand( WPARAM wParam, LPARAM lParam )
+{
+ ThreadData* tActiveThreads[ 64 ];
+ int tThreads = MSN_GetActiveThreads( tActiveThreads ), tChosenThread;
+// modified for chat
+
+
+ switch( tThreads ) {
+ case 0:
+ MessageBoxA(NULL, Translate("No active chat session is found."), Translate("MSN Chat"), MB_OK|MB_ICONINFORMATION);
+ return 0;
+
+ case 1:
+ tChosenThread = 0;
+ break;
+
+ default:
+ HMENU tMenu = ::CreatePopupMenu();
+
+ for ( int i=0; i < tThreads; i++ ) {
+ if (( long )tActiveThreads[i]->mJoinedContacts[0] < 0 ) {
+ char sessionName[ 255 ];
+ mir_snprintf( sessionName, sizeof( sessionName ), "%s%s",
+ Translate( "MSN Chat #" ), tActiveThreads[i]->mChatID );
+ ::AppendMenuA( tMenu, MF_STRING, ( UINT_PTR )( i+1 ), sessionName );
+ }
+ else ::AppendMenu( tMenu, MF_STRING, ( UINT_PTR )( i+1 ), MSN_GetContactNameT( *tActiveThreads[i]->mJoinedContacts ));
+ }
+
+ HWND tWindow = CreateWindow(_T("EDIT"),_T(""),0,1,1,1,1,NULL,NULL,hInst,NULL);
+
+ POINT pt;
+ ::GetCursorPos ( &pt );
+ tChosenThread = ::TrackPopupMenu( tMenu, TPM_NONOTIFY | TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD, pt.x, pt.y, 0, tWindow, NULL );
+ ::DestroyMenu( tMenu );
+ ::DestroyWindow( tWindow );
+ if ( !tChosenThread )
+ return 0;
+
+ tChosenThread--;
+ }
+
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( !MSN_GetStaticString( "e-mail", ( HANDLE )wParam, tEmail, sizeof( tEmail ))) {
+ for ( int j=0; j < tActiveThreads[ tChosenThread ]->mJoinedCount; j++ ) {
+ // if the user is already in the chat session
+ if ( tActiveThreads[ tChosenThread ]->mJoinedContacts[j] == ( HANDLE )wParam ) {
+ MessageBoxA(NULL, Translate("User is already in the chat session."), Translate("MSN Chat"), MB_OK|MB_ICONINFORMATION);
+ return 0;
+ } }
+
+ tActiveThreads[ tChosenThread ]->sendPacket( "CAL", tEmail );
+
+ if ( msnHaveChatDll )
+ MSN_ChatStart(tActiveThreads[ tChosenThread ]);
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnLoadIcon - obtain the protocol icon
+
+static int MsnLoadIcon(WPARAM wParam,LPARAM lParam)
+{
+ UINT id;
+
+ switch(wParam&0xFFFF) {
+ case PLI_PROTOCOL: id=IDI_MSN; break;
+ default: return (int)(HICON)NULL;
+ }
+
+ bool tIsSmall = ( wParam & PLIF_SMALL ) != 0;
+ return (int)LoadImage( hInst, MAKEINTRESOURCE(id), IMAGE_ICON,
+ GetSystemMetrics(tIsSmall ? SM_CXSMICON : SM_CXICON),
+ GetSystemMetrics(tIsSmall ? SM_CYSMICON : SM_CYICON), 0 );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnRebuildContactMenu - gray or ungray the block menus according to contact's status
+
+static int MsnRebuildContactMenu( WPARAM wParam, LPARAM lParam )
+{
+ char szEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( !MSN_GetStaticString( "e-mail", ( HANDLE )wParam, szEmail, sizeof szEmail )) {
+ CLISTMENUITEM clmi = { 0 };
+ clmi.cbSize = sizeof( clmi );
+ clmi.pszName = MSN_Translate( ( Lists_IsInList( LIST_BL, szEmail ) ? "&Unblock" : "&Block" ));
+ clmi.flags = CMIM_NAME;
+ MSN_CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )msnBlockMenuItem, ( LPARAM )&clmi );
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnRecvFile - creates a database event from the file request been received
+
+int MsnRecvFile( WPARAM wParam, LPARAM lParam )
+{
+ CCSDATA* ccs = ( CCSDATA* )lParam;
+ DBDeleteContactSetting( ccs->hContact, "CList", "Hidden" );
+
+ ThreadData* thread = MSN_GetThreadByContact( ccs->hContact );
+ if ( thread == NULL )
+ { msnNsThread->sendPacket( "XFR", "SB" );
+ return 0;
+ }
+
+ PROTORECVEVENT* pre = ( PROTORECVEVENT* )ccs->lParam;
+ char* szFile = pre->szMessage + sizeof( DWORD );
+ char* szDescr = szFile + strlen( szFile ) + 1;
+
+ DBEVENTINFO dbei;
+ memset( &dbei, 0, sizeof( dbei ));
+ dbei.cbSize = sizeof( dbei );
+ dbei.szModule = msnProtocolName;
+ dbei.timestamp = pre->timestamp;
+ dbei.flags = ( pre->flags & PREF_CREATEREAD ) ? DBEF_READ : 0;
+ dbei.eventType = EVENTTYPE_FILE;
+ dbei.cbBlob = sizeof( DWORD ) + strlen( szFile ) + strlen( szDescr ) + 2;
+ dbei.pBlob = ( PBYTE )pre->szMessage;
+ MSN_CallService( MS_DB_EVENT_ADD, ( WPARAM )ccs->hContact, ( LPARAM )&dbei );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnRecvMessage - creates a database event from the message been received
+
+static int MsnRecvMessage(WPARAM wParam,LPARAM lParam)
+{
+ CCSDATA* ccs = ( CCSDATA* )lParam;
+ PROTORECVEVENT* pre = ( PROTORECVEVENT* )ccs->lParam;
+
+ DBDeleteContactSetting( ccs->hContact, "CList", "Hidden" );
+
+ DBEVENTINFO dbei = { 0 };
+ dbei.cbSize = sizeof( dbei );
+ dbei.szModule = msnProtocolName;
+ dbei.timestamp = pre->timestamp;
+ dbei.flags = ( pre->flags & PREF_CREATEREAD ) ? DBEF_READ : 0;
+ if ( pre->flags & PREF_RTL )
+ dbei.flags |= DBEF_RTL;
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ dbei.cbBlob = strlen( pre->szMessage )+1;
+ if ( pre->flags & PREF_UNICODE )
+ dbei.cbBlob *= ( sizeof( wchar_t )+1 );
+
+ dbei.pBlob = ( PBYTE )pre->szMessage;
+ MSN_CallService( MS_DB_EVENT_ADD, ( WPARAM )ccs->hContact, ( LPARAM )&dbei );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnSendFile - initiates a file transfer
+
+static int MsnSendFile( WPARAM wParam, LPARAM lParam )
+{
+ if ( !msnLoggedIn )
+ return 0;
+
+ CCSDATA *ccs = ( CCSDATA* )lParam;
+ if ( MSN_GetWord( ccs->hContact, "Status", ID_STATUS_OFFLINE ) == ID_STATUS_OFFLINE )
+ return 0;
+
+ char** files = ( char** )ccs->lParam;
+ if ( files[1] != NULL ) {
+ MSN_ShowError( Translate( "MSN protocol allows only one file to be sent at a time" ));
+ return 0;
+ }
+
+ long tFileSize = 0;
+ { struct _stat statbuf;
+ if ( _stat( files[0], &statbuf ) == 0 )
+ tFileSize += statbuf.st_size;
+ }
+
+ filetransfer* sft = new filetransfer();
+ sft->std.totalFiles = 1;
+ sft->std.files = files;
+ sft->std.currentFile = strdup( files[0] );
+ sft->std.totalBytes = sft->std.currentFileSize = tFileSize;
+ sft->std.hContact = ccs->hContact;
+ sft->std.sending = 1;
+ sft->std.currentFileNumber = 0;
+
+ sft->fileId = _open( sft->std.currentFile, _O_BINARY | _O_RDONLY, _S_IREAD );
+ MSN_DebugLog( "Unable to open file '%s', error %d", sft->std.currentFile, errno );
+ if ( sft->fileId == -1 ) return NULL;
+
+ DWORD dwFlags = MSN_GetDword( ccs->hContact, "FlagBits", 0 );
+ if ( dwFlags & 0x70000000 )
+ p2p_invite( ccs->hContact, MSN_APPID_FILE, sft );
+ else {
+ ThreadData* thread = MSN_GetThreadByContact( ccs->hContact );
+ if ( thread != NULL ) {
+ thread->mMsnFtp = sft;
+ sft->mThreadId = thread->mUniqueID;
+ }
+ else msnNsThread->sendPacket( "XFR", "SB" );
+
+ char* pszFiles = strrchr( *files, '\\' ), msg[ 1024 ];
+ if ( pszFiles )
+ pszFiles++;
+ else
+ pszFiles = *files;
+
+ mir_snprintf( msg, sizeof( msg ),
+ "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
+ "Application-Name: File Transfer\r\n"
+ "Application-GUID: {5D3E02AB-6190-11d3-BBBB-00C04F795683}\r\n"
+ "Invitation-Command: INVITE\r\n"
+ "Invitation-Cookie: %i\r\n"
+ "Application-File: %s\r\n"
+ "Application-FileSize: %i\r\n\r\n",
+ ( WORD )(((double)rand()/(double)RAND_MAX)*4294967295), UTF8(pszFiles), tFileSize );
+
+ if ( thread == NULL )
+ MsgQueue_Add( ccs->hContact, 'S', msg, -1, sft );
+ else
+ thread->sendMessage( 'S', msg, MSG_DISABLE_HDR );
+ }
+
+ MSN_SendBroadcast( ccs->hContact, ACKTYPE_FILE, ACKRESULT_SENTREQUEST, sft, 0 );
+ return (int)(HANDLE)sft;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnSendMessage - sends the message to a server
+
+struct TFakeAckParams
+{
+ inline TFakeAckParams( HANDLE p1, HANDLE p2, LONG p3, LPCSTR p4 ) :
+ hEvent( p1 ),
+ hContact( p2 ),
+ id( p3 ),
+ msg( p4 )
+ {}
+
+ HANDLE hEvent;
+ HANDLE hContact;
+ LONG id;
+ LPCSTR msg;
+};
+
+static DWORD CALLBACK sttFakeAck( LPVOID param )
+{
+ TFakeAckParams* tParam = ( TFakeAckParams* )param;
+ WaitForSingleObject( tParam->hEvent, INFINITE );
+
+ Sleep( 100 );
+ if ( tParam->msg == NULL )
+ MSN_SendBroadcast( tParam->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, ( HANDLE )tParam->id, 0 );
+ else
+ MSN_SendBroadcast( tParam->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, ( HANDLE )tParam->id, LPARAM( tParam->msg ));
+
+ CloseHandle( tParam->hEvent );
+ delete tParam;
+ return 0;
+}
+
+static int MsnSendMessage( WPARAM wParam, LPARAM lParam )
+{
+ CCSDATA* ccs = ( CCSDATA* )lParam;
+ char *msg, *errMsg = NULL;
+
+ if ( ccs->wParam & PREF_UNICODE ) {
+ char* p = ( char* )ccs->lParam;
+ msg = Utf8EncodeUcs2(( wchar_t* )&p[ strlen(p)+1 ] );
+ }
+ else msg = Utf8Encode(( char* )ccs->lParam );
+
+ if ( strlen( msg ) > 1202 ) {
+ errMsg = MSN_Translate( "Message is too long: MSN messages are limited by 1202 UTF8 chars" );
+LBL_Error:
+ free( msg );
+
+ HANDLE hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+ DWORD dwThreadId;
+ CloseHandle( CreateThread( NULL, 0, sttFakeAck, new TFakeAckParams( hEvent, ccs->hContact, 999999, errMsg ), 0, &dwThreadId ));
+ SetEvent( hEvent );
+ return 999999;
+ }
+
+ int seq, msgType = ( MyOptions.SlowSend ) ? 'A' : 'N';
+ int rtlFlag = ( ccs->wParam & PREF_RTL ) ? MSG_RTL : 0;
+ ThreadData* thread = MSN_GetThreadByContact( ccs->hContact );
+ if ( thread == NULL )
+ {
+ WORD wStatus = MSN_GetWord( ccs->hContact, "Status", ID_STATUS_OFFLINE );
+ if ( wStatus == ID_STATUS_OFFLINE || msnStatusMode == ID_STATUS_INVISIBLE ) {
+ errMsg = MSN_Translate( "MSN protocol does not support offline messages" );
+ goto LBL_Error;
+ }
+
+ if ( MsgQueue_CheckContact( ccs->hContact ) == NULL )
+ msnNsThread->sendPacket( "XFR", "SB" );
+
+ seq = MsgQueue_Add( ccs->hContact, msgType, msg, 0, 0, rtlFlag );
+ }
+ else
+ { if ( thread->mJoinedCount == 0 )
+ seq = MsgQueue_Add( ccs->hContact, msgType, msg, 0, 0, rtlFlag );
+ else {
+ seq = thread->sendMessage( msgType, msg, rtlFlag );
+
+ if ( seq == -1 ) {
+ seq = MsgQueue_Add( ccs->hContact, msgType, msg, 0, 0, rtlFlag );
+ msnNsThread->sendPacket( "XFR", "SB" );
+ }
+ else if ( !MyOptions.SlowSend ) {
+ HANDLE hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+ DWORD dwThreadId;
+ CloseHandle( CreateThread( NULL, 0, sttFakeAck, new TFakeAckParams( hEvent, ccs->hContact, seq, 0 ), 0, &dwThreadId ));
+ SetEvent( hEvent );
+ } } }
+
+ free( msg );
+ return seq;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnSendNudge - Sending a nudge
+
+static int MsnSendNudge( WPARAM wParam, LPARAM lParam )
+{
+ if ( !msnLoggedIn ) return 0;
+
+ HANDLE hContact = ( HANDLE )wParam;
+ char msg[ 1024 ];
+
+ mir_snprintf( msg, sizeof( msg ),"N 69\r\nMIME-Version: 1.0\r\n"
+ "Content-Type: text/x-msnmsgr-datacast\r\n\r\n"
+ "ID: 1\r\n\r\n");
+
+ ThreadData* thread = MSN_GetThreadByContact( hContact );
+
+ if ( thread == NULL ) {
+ if ( MsgQueue_CheckContact( hContact ) == NULL )
+ {
+ MsgQueue_Add( hContact, 'N', msg, -1 );
+ msnNsThread->sendPacket( "XFR", "SB" );
+ }
+ }
+ else
+ thread->sendPacket( "MSG",msg);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnSendNetMeeting - Netmeeting callback function
+
+static int MsnSendNetMeeting( WPARAM wParam, LPARAM lParam )
+{
+ if ( !msnLoggedIn ) return 0;
+
+ ThreadData* thread = MSN_GetThreadByContact( HANDLE(wParam) );
+
+ if ( thread == NULL ) {
+ MessageBoxA( NULL, MSN_Translate( "You must be talking to start Netmeeting" ), "MSN Protocol", MB_OK | MB_ICONERROR );
+ return 0;
+ }
+
+ char msg[ 1024 ];
+
+ mir_snprintf( msg, sizeof( msg ),
+ "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
+ "Application-Name: NetMeeting\r\n"
+ "Application-GUID: {44BBA842-CC51-11CF-AAFA-00AA00B6015C}\r\n"
+ "Session-Protocol: SM1\r\n"
+ "Invitation-Command: INVITE\r\n"
+ "Invitation-Cookie: %i\r\n"
+ "Session-ID: {1A879604-D1B8-11D7-9066-0003FF431510}\r\n\r\n",
+ ( WORD )(((double)rand()/(double)RAND_MAX)*4294967295));
+
+ thread->sendMessage( 'N', msg, MSG_DISABLE_HDR );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnSetApparentMode - controls contact visibility
+
+static int MsnSetApparentMode( WPARAM wParam, LPARAM lParam )
+{
+ CCSDATA* ccs = ( CCSDATA* )lParam;
+ if ( ccs->wParam && ccs->wParam != ID_STATUS_OFFLINE )
+ return 1;
+
+ WORD oldMode = MSN_GetWord( ccs->hContact, "ApparentMode", 0 );
+ if ( ccs->wParam != oldMode )
+ MSN_SetWord( ccs->hContact, "ApparentMode", ( WORD )ccs->wParam );
+
+ return 1;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnSetAvatar - sets an avatar without UI
+
+static int MsnSetAvatar( WPARAM wParam, LPARAM lParam )
+{
+ HBITMAP hBitmap = ( HBITMAP )MSN_CallService( MS_UTILS_LOADBITMAP, 0, lParam );
+ if ( hBitmap == NULL )
+ return 1;
+
+ if (( hBitmap = MSN_StretchBitmap( hBitmap )) == NULL )
+ return 2;
+
+ MSN_SaveBitmapAsAvatar( hBitmap, (char *) lParam );
+ DeleteObject( hBitmap );
+ if ( msnLoggedIn )
+ MSN_SetServerStatus( msnStatusMode );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnSetAvatar - sets an avatar without UI
+
+static int MsnSetAvatarUI( WPARAM wParam, LPARAM lParam )
+{
+ char szFileName[ MAX_PATH ];
+ if ( MSN_EnterBitmapFileName( szFileName ) != ERROR_SUCCESS )
+ return 1;
+
+ return MsnSetAvatar( 0, ( LPARAM )szFileName );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnSetAwayMsg - sets the current status message for a user
+
+static int MsnSetAwayMsg(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+
+ for ( i=0; i < MSN_NUM_MODES; i++ )
+ if ( msnModeMsgs[i].m_mode == (int)wParam )
+ break;
+
+ if ( i == MSN_NUM_MODES )
+ return 1;
+
+ replaceStr( msnModeMsgs[i].m_msg, ( char* )lParam );
+
+ if ( (int)wParam == msnDesiredStatus )
+ MSN_SendStatusMessage(( char* )lParam );
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// SetNickname - sets a nick name without UI
+
+static int MsnSetNickName( WPARAM wParam, LPARAM lParam )
+{
+ MSN_SendNickname(( char* )lParam );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// SetNicknameCommand - sets nick name
+
+static BOOL CALLBACK DlgProcSetNickname(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch ( msg )
+ {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault( hwndDlg );
+ SendMessage( hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon( hInst, MAKEINTRESOURCE( IDI_MSN )));
+ SendMessage( GetDlgItem( hwndDlg, IDC_NICKNAME ), EM_LIMITTEXT, 129, 0 );
+
+ DBVARIANT dbv;
+ if ( !DBGetContactSettingTString( NULL, msnProtocolName, "Nick", &dbv )) {
+ SetDlgItemText( hwndDlg, IDC_NICKNAME, dbv.ptszVal );
+ MSN_FreeVariant( &dbv );
+ }
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch(wParam)
+ {
+ case IDOK:
+ if ( msnLoggedIn ) {
+ TCHAR str[ 130 ];
+ GetDlgItemText( hwndDlg, IDC_NICKNAME, str, SIZEOF( str ));
+ MSN_SendNicknameT( str );
+ }
+
+ case IDCANCEL:
+ DestroyWindow( hwndDlg );
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ DestroyWindow( hwndDlg );
+ break;
+ }
+ return FALSE;
+}
+
+static int SetNicknameUI( WPARAM wParam, LPARAM lParam )
+{
+ HWND hwndSetNickname = CreateDialog(hInst, MAKEINTRESOURCE( IDD_SETNICKNAME ), NULL, DlgProcSetNickname );
+
+ SetForegroundWindow( hwndSetNickname );
+ SetFocus( hwndSetNickname );
+ ShowWindow( hwndSetNickname, SW_SHOW );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnSetStatus - set the plugin's connection status
+
+static int MsnSetStatus( WPARAM wParam, LPARAM lParam )
+{
+ msnDesiredStatus = wParam;
+ MSN_DebugLog( "PS_SETSTATUS(%d,0)", wParam );
+
+ if ( msnDesiredStatus == ID_STATUS_OFFLINE )
+ {
+ MSN_GoOffline();
+ }
+ else if (!msnLoggedIn && !(msnStatusMode>=ID_STATUS_CONNECTING && msnStatusMode<ID_STATUS_CONNECTING+MAX_CONNECT_RETRIES))
+ {
+ ThreadData* newThread = new ThreadData;
+
+ WORD tServerPort = MSN_GetWord( NULL, "MSNMPort", 1863 );
+
+ char tServer[ sizeof( newThread->mServer ) ];
+ if ( MSN_GetStaticString( "LoginServer", NULL, tServer, sizeof( tServer )))
+ strcpy( tServer, MSN_DEFAULT_LOGIN_SERVER );
+
+ mir_snprintf( newThread->mServer, sizeof( newThread->mServer ), "%s:%i", tServer, tServerPort );
+ newThread->mServer[ sizeof(newThread->mServer)-1 ] = 0;
+
+ newThread->mType = SERVER_DISPATCH;
+ newThread->mIsMainThread = true;
+ { int oldMode = msnStatusMode;
+ msnStatusMode = ID_STATUS_CONNECTING;
+ MSN_SendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE )oldMode, msnStatusMode );
+ }
+ newThread->startThread(( pThreadFunc )MSNServerThread );
+ }
+ else MSN_SetServerStatus( msnDesiredStatus );
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnUserIsTyping - notify another contact that we're typing a message
+
+extern char sttHeaderStart[];
+
+static int MsnUserIsTyping(WPARAM wParam, LPARAM lParam)
+{
+ if ( !msnLoggedIn || lParam == PROTOTYPE_SELFTYPING_OFF )
+ return 0;
+
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( MSN_GetStaticString( "e-mail", NULL, tEmail, sizeof tEmail ))
+ return 0;
+
+ HANDLE hContact = ( HANDLE )wParam;
+ WORD wStatus = MSN_GetWord( hContact, "Status", ID_STATUS_OFFLINE );
+ if ( wStatus == ID_STATUS_OFFLINE || msnStatusMode == ID_STATUS_INVISIBLE )
+ return 0;
+
+ char tCommand[ 1024 ];
+ mir_snprintf( tCommand, sizeof( tCommand ),
+ "Content-Type: text/x-msmsgscontrol\r\n"
+ "TypingUser: %s\r\n\r\n\r\n", tEmail );
+
+ ThreadData* T = MSN_GetThreadByContact( hContact );
+ if ( T == NULL ) {
+ if ( MsgQueue_CheckContact( hContact ) == NULL ) {
+ MsgQueue_Add( hContact, 'U', tCommand, -1 );
+ msnNsThread->sendPacket( "XFR", "SB" );
+ }
+ }
+ else T->sendMessage( 'U', tCommand, MSG_DISABLE_HDR );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnViewProfile - view a contact's profile at http://members.msn.com
+
+static char sttUrlPrefix[] = "http://members.msn.com/";
+
+static int MsnViewProfile( WPARAM wParam, LPARAM lParam )
+{
+ char tUrl[ MSN_MAX_EMAIL_LEN + sizeof sttUrlPrefix ];
+ strcpy( tUrl, sttUrlPrefix );
+
+ if ( !MSN_GetStaticString( "e-mail", ( HANDLE )wParam, tUrl + sizeof sttUrlPrefix - 1, MSN_MAX_EMAIL_LEN ))
+ MSN_CallService( MS_UTILS_OPENURL, 1, ( LPARAM )tUrl );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnViewServiceStatus - display MSN services status
+
+static int MsnViewServiceStatus( WPARAM wParam, LPARAM lParam )
+{
+ MSN_CallService( MS_UTILS_OPENURL, 1, ( LPARAM )"http://messenger.msn.com/Status.aspx" );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Services initialization and destruction
+
+static HANDLE hHookSettingChanged = NULL;
+static HANDLE hHookContactDeleted = NULL;
+static HANDLE hHookRebuildCMenu = NULL;
+
+int LoadMsnServices( void )
+{
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Main menu initialization
+
+ char servicefunction[ 100 ];
+ strcpy( servicefunction, msnProtocolName );
+ char* tDest = servicefunction + strlen( servicefunction );
+ CLISTMENUITEM mi;
+
+ if ( !MSN_GetByte( "DisableSetNickname", 0 ))
+ {
+ strcpy( tDest, MS_SET_NICKNAME_UI );
+ CreateServiceFunction( servicefunction, SetNicknameUI );
+
+ memset( &mi, 0, sizeof( mi ));
+ mi.popupPosition = 500085000;
+ mi.pszPopupName = msnProtocolName;
+ mi.cbSize = sizeof( mi );
+ mi.position = 2000060000;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_MSN ));
+ mi.pszName = MSN_Translate( "Set &Nickname" );
+ mi.pszService = servicefunction;
+ msnMenuItems[ 0 ] = ( HANDLE )MSN_CallService( MS_CLIST_ADDMAINMENUITEM, 0, (LPARAM)&mi );
+
+ strcpy( tDest, MS_GOTO_INBOX );
+ CreateServiceFunction( servicefunction, MsnGotoInbox );
+
+ mi.position = 2000060001;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_INBOX ));
+ mi.pszName = MSN_Translate( "Display Hotmail &Inbox" );
+ mi.pszService = servicefunction;
+ MSN_CallService( MS_CLIST_ADDMAINMENUITEM, 0, (LPARAM)&mi );
+
+ strcpy( tDest, MS_EDIT_PROFILE );
+ CreateServiceFunction( servicefunction, MsnEditProfile );
+
+ mi.position = 2000060002;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_PROFILE ));
+ mi.pszName = MSN_Translate( "Edit MSN &Profile" );
+ mi.pszService = servicefunction;
+ msnMenuItems[ 1 ] = ( HANDLE )MSN_CallService( MS_CLIST_ADDMAINMENUITEM, 0, (LPARAM)&mi );
+
+ strcpy( tDest, MS_VIEW_STATUS );
+ CreateServiceFunction( servicefunction, MsnViewServiceStatus );
+
+ mi.position = 2000060003;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_SERVICES ));
+ mi.pszName = MSN_Translate( "View MSN Services &Status" );
+ mi.pszService = servicefunction;
+ MSN_CallService( MS_CLIST_ADDMAINMENUITEM, 0, (LPARAM)&mi );
+
+ strcpy( tDest, MS_SET_AVATAR_UI );
+ CreateServiceFunction( servicefunction, MsnSetAvatarUI );
+
+ mi.position = 2000060004;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_AVATAR ));
+ mi.pszName = MSN_Translate( "Set &Avatar" );
+ mi.pszService = servicefunction;
+ MSN_CallService( MS_CLIST_ADDMAINMENUITEM, 0, (LPARAM)&mi );
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Contact menu initialization
+
+ strcpy( tDest, MSN_BLOCK );
+ CreateServiceFunction( servicefunction, MsnBlockCommand );
+
+ memset( &mi, 0, sizeof( mi ));
+ mi.cbSize = sizeof( mi );
+ mi.position = -500050000;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_MSNBLOCK ));
+ mi.pszContactOwner = msnProtocolName;
+ mi.pszName = MSN_Translate( "&Block" );
+ mi.pszService = servicefunction;
+ msnBlockMenuItem = ( HANDLE )MSN_CallService( MS_CLIST_ADDCONTACTMENUITEM, 0, ( LPARAM )&mi );
+
+ strcpy( tDest, MSN_INVITE );
+ CreateServiceFunction( servicefunction, MsnInviteCommand );
+
+ mi.flags = CMIF_NOTOFFLINE;
+ mi.position = -500050001;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_INVITE ));
+ mi.pszName = MSN_Translate( "&Invite to chat" );
+ mi.pszService = servicefunction;
+ MSN_CallService( MS_CLIST_ADDCONTACTMENUITEM, 0, ( LPARAM )&mi );
+
+ strcpy( tDest, MSN_NETMEETING );
+ CreateServiceFunction( servicefunction, MsnSendNetMeeting );
+
+ mi.flags = CMIF_NOTOFFLINE;
+ mi.position = -500050002;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_NETMEETING ));
+ mi.pszName = MSN_Translate( "&Start Netmeeting" );
+ mi.pszService = servicefunction;
+ MSN_CallService( MS_CLIST_ADDCONTACTMENUITEM, 0, ( LPARAM )&mi );
+
+ strcpy( tDest, MSN_VIEW_PROFILE );
+ CreateServiceFunction( servicefunction, MsnViewProfile );
+
+ mi.flags = 0;
+ mi.position = -500050003;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_PROFILE ));
+ mi.pszName = MSN_Translate( "&View Profile" );
+ mi.pszService = servicefunction;
+ MSN_CallService( MS_CLIST_ADDCONTACTMENUITEM, 0, ( LPARAM )&mi );
+
+ MSN_EnableMenuItems( FALSE );
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Service creation
+
+ hHookContactDeleted = HookEvent( ME_DB_CONTACT_DELETED, MsnContactDeleted );
+ hHookSettingChanged = HookEvent( ME_DB_CONTACT_SETTINGCHANGED, MsnDbSettingChanged );
+ hHookRebuildCMenu = HookEvent( ME_CLIST_PREBUILDCONTACTMENU, MsnRebuildContactMenu );
+
+ MSN_CreateProtoServiceFunction( PS_ADDTOLIST, MsnAddToList );
+ MSN_CreateProtoServiceFunction( PS_ADDTOLISTBYEVENT, MsnAddToListByEvent );
+ MSN_CreateProtoServiceFunction( PS_AUTHALLOW, MsnAuthAllow );
+ MSN_CreateProtoServiceFunction( PS_AUTHDENY, MsnAuthDeny );
+ MSN_CreateProtoServiceFunction( PS_BASICSEARCH, MsnBasicSearch );
+ MSN_CreateProtoServiceFunction( PS_FILERESUME, MsnFileResume );
+ MSN_CreateProtoServiceFunction( PS_GETAVATARINFO, MsnGetAvatarInfo );
+ MSN_CreateProtoServiceFunction( PS_GETCAPS, MsnGetCaps );
+ MSN_CreateProtoServiceFunction( PS_GETNAME, MsnGetName );
+ MSN_CreateProtoServiceFunction( PS_GETSTATUS, MsnGetStatus );
+ MSN_CreateProtoServiceFunction( PS_LOADICON, MsnLoadIcon );
+ MSN_CreateProtoServiceFunction( PS_SEARCHBYEMAIL, MsnBasicSearch );
+ MSN_CreateProtoServiceFunction( PS_SETSTATUS, MsnSetStatus );
+
+ MSN_CreateProtoServiceFunction( PSR_FILE, MsnRecvFile );
+ MSN_CreateProtoServiceFunction( PSR_MESSAGE, MsnRecvMessage );
+
+ MSN_CreateProtoServiceFunction( PSS_FILE, MsnSendFile );
+ MSN_CreateProtoServiceFunction( PSS_FILEALLOW, MsnFileAllow );
+ MSN_CreateProtoServiceFunction( PSS_FILECANCEL, MsnFileCancel );
+ MSN_CreateProtoServiceFunction( PSS_FILEDENY, MsnFileDeny );
+ MSN_CreateProtoServiceFunction( PSS_GETINFO, MsnGetInfo );
+ MSN_CreateProtoServiceFunction( PSS_MESSAGE, MsnSendMessage );
+ MSN_CreateProtoServiceFunction( PSS_SETAPPARENTMODE, MsnSetApparentMode );
+ MSN_CreateProtoServiceFunction( PSS_USERISTYPING, MsnUserIsTyping );
+
+ if ( MyOptions.UseMSNP11 ) {
+ MSN_CreateProtoServiceFunction( PSS_GETAWAYMSG, MsnGetAwayMsg );
+ MSN_CreateProtoServiceFunction( PS_SETAWAYMSG, MsnSetAwayMsg );
+ }
+
+ MSN_CreateProtoServiceFunction( MSN_SET_AVATAR, MsnSetAvatar );
+ MSN_CreateProtoServiceFunction( MSN_SET_NICKNAME, MsnSetNickName );
+ MSN_CreateProtoServiceFunction( MSN_SEND_NUDGE, MsnSendNudge );
+ return 0;
+}
+
+void UnloadMsnServices( void )
+{
+ if ( hHookSettingChanged )
+ UnhookEvent( hHookSettingChanged );
+
+ if ( hHookContactDeleted )
+ UnhookEvent( hHookContactDeleted );
+
+ if ( hHookRebuildCMenu )
+ UnhookEvent( hHookRebuildCMenu );
+}
diff --git a/miranda-wine/protocols/MSN/msn_switchboard.cpp b/miranda-wine/protocols/MSN/msn_switchboard.cpp
new file mode 100644
index 0000000..4e96339
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_switchboard.cpp
@@ -0,0 +1,53 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "msn_global.h"
+
+int __stdcall MSN_ContactJoined( ThreadData* parInfo, HANDLE hContact )
+{
+ for ( int i=0; i < parInfo->mJoinedCount; i++ )
+ if ( parInfo->mJoinedContacts[i] == hContact )
+ return i+1;
+
+ int ret = ++parInfo->mJoinedCount;
+ parInfo->mJoinedContacts = ( HANDLE* )realloc( parInfo->mJoinedContacts, sizeof( HANDLE )*ret );
+ parInfo->mJoinedContacts[ ret-1 ] = hContact;
+ return ret;
+}
+
+int __stdcall MSN_ContactLeft( ThreadData* parInfo, HANDLE hContact )
+{
+ int i;
+
+ for ( i=0; i < parInfo->mJoinedCount; i++ )
+ if ( parInfo->mJoinedContacts[ i ] == hContact )
+ break;
+
+ if ( i == parInfo->mJoinedCount )
+ return i;
+
+ int ret = --parInfo->mJoinedCount;
+ memmove( parInfo->mJoinedContacts + i, parInfo->mJoinedContacts+i+1, sizeof( HANDLE )*( ret-i ));
+ parInfo->mJoinedContacts = ( HANDLE* )realloc( parInfo->mJoinedContacts, sizeof( HANDLE )*ret );
+ return ret;
+}
diff --git a/miranda-wine/protocols/MSN/msn_threads.cpp b/miranda-wine/protocols/MSN/msn_threads.cpp
new file mode 100644
index 0000000..7ce9ad2
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_threads.cpp
@@ -0,0 +1,723 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "msn_global.h"
+
+#include <direct.h>
+
+int MSN_HandleCommands(ThreadData *info,char *cmdString);
+int MSN_HandleErrors(ThreadData *info,char *cmdString);
+int MSN_HandleMSNFTP( ThreadData *info, char *cmdString );
+
+extern LONG (WINAPI *MyInterlockedIncrement)(PLONG pVal);
+extern unsigned long sl;
+
+HANDLE hKeepAliveThreadEvt = NULL;
+
+bool DoingNudge = false;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Keep-alive thread for the main connection
+
+int msnPingTimeout = 45, msnPingTimeoutCurrent = 45;
+
+void __cdecl msn_keepAliveThread( void* )
+{
+ msnPingTimeout = msnPingTimeoutCurrent;
+
+ while( TRUE )
+ {
+ while ( --msnPingTimeout > 0 ) {
+ if ( ::WaitForSingleObject( hKeepAliveThreadEvt, 1000 ) != WAIT_TIMEOUT ) {
+ ::CloseHandle( hKeepAliveThreadEvt ); hKeepAliveThreadEvt = NULL;
+ MSN_DebugLog( "Closing keep-alive thread" );
+ return;
+ } }
+
+ msnPingTimeout = msnPingTimeoutCurrent = 45;
+
+ /*
+ * if proxy is not used, every connection uses select() to send PNG
+ */
+
+ if ( msnLoggedIn && !MyOptions.UseGateway )
+ if ( MSN_GetByte( "KeepAlive", 0 ))
+ msnNsThread->send( "PNG\r\n", 5 );
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN redirector detection thread - refreshes the information about the redirector
+
+static bool sttRedirectorWasChecked = false;
+
+void __cdecl msn_RedirectorThread( ThreadData* info )
+{
+ extern int MSN_CheckRedirector();
+ MSN_CheckRedirector();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN server thread - read and process commands from a server
+
+void __cdecl MSNServerThread( ThreadData* info )
+{
+ if ( !sttRedirectorWasChecked ) {
+ sttRedirectorWasChecked = true;
+ MSN_StartThread(( pThreadFunc )msn_RedirectorThread, NULL );
+ }
+
+ NETLIBOPENCONNECTION tConn = { 0 };
+ tConn.cbSize = sizeof( tConn );
+ tConn.flags = NLOCF_V2;
+
+ char* tPortDelim = strrchr( info->mServer, ':' );
+ if ( tPortDelim != NULL )
+ *tPortDelim = '\0';
+
+ if ( MyOptions.UseGateway && !MyOptions.UseProxy ) {
+ tConn.szHost = MSN_DEFAULT_GATEWAY;
+ tConn.wPort = 80;
+ }
+ else {
+ tConn.szHost = info->mServer;
+ tConn.wPort = MSN_DEFAULT_PORT;
+
+ if ( tPortDelim != NULL ) {
+ int tPortNumber;
+ if ( sscanf( tPortDelim+1, "%d", &tPortNumber ) == 1 )
+ tConn.wPort = ( WORD )tPortNumber;
+ } }
+
+ MSN_DebugLog( "Thread started: server='%s', type=%d", tConn.szHost, info->mType );
+
+ info->s = ( HANDLE )MSN_CallService( MS_NETLIB_OPENCONNECTION, ( WPARAM )hNetlibUser, ( LPARAM )&tConn );
+ if ( info->s == NULL ) {
+ MSN_DebugLog( "Connection Failed (%d)", WSAGetLastError() );
+
+ switch ( info->mType ) {
+ case SERVER_NOTIFICATION:
+ case SERVER_DISPATCH:
+ MSN_SendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NOSERVER );
+ MSN_GoOffline();
+ break;
+ }
+
+ return;
+ }
+
+ if ( MyOptions.UseGateway )
+ MSN_CallService( MS_NETLIB_SETPOLLINGTIMEOUT, WPARAM( info->s ), 2 );
+
+ MSN_DebugLog( "Connected with handle=%08X", info->s );
+
+ if ( info->mType == SERVER_DISPATCH || info->mType == SERVER_NOTIFICATION ) {
+ if ( MyOptions.UseMSNP11 )
+ info->sendPacket( "VER", "MSNP11 MSNP10 CVR0" );
+ else
+ info->sendPacket( "VER", "MSNP10 MSNP9 CVR0" );
+ }
+ else if ( info->mType == SERVER_SWITCHBOARD ) {
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ MSN_GetStaticString( "e-mail", NULL, tEmail, sizeof( tEmail ));
+ info->sendPacket( info->mCaller ? "USR" : "ANS", "%s %s", tEmail, info->mCookie );
+ }
+ else if ( info->mType == SERVER_FILETRANS && info->mCaller == 0 ) {
+ info->send( "VER MSNFTP\r\n", 12 );
+ }
+
+ if ( info->mIsMainThread ) {
+ MSN_EnableMenuItems( TRUE );
+
+ sl = time(NULL); //for hotmail
+
+ msnPingTimeout = msnPingTimeoutCurrent;
+
+ msnNsThread = info;
+ if (hKeepAliveThreadEvt == NULL) {
+ hKeepAliveThreadEvt = ::CreateEvent( NULL, TRUE, FALSE, NULL );
+ MSN_StartThread(( pThreadFunc )msn_keepAliveThread, NULL );
+ } }
+
+ MSN_DebugLog( "Entering main recv loop" );
+ info->mBytesInData = 0;
+ while ( TRUE ) {
+ int handlerResult;
+
+ int recvResult = info->recv( info->mData + info->mBytesInData, sizeof( info->mData ) - info->mBytesInData );
+ if ( recvResult == SOCKET_ERROR ) {
+ MSN_DebugLog( "Connection %08p [%d] was abortively closed", info->s, GetCurrentThreadId());
+ break;
+ }
+
+ if ( !recvResult ) {
+ MSN_DebugLog( "Connection %08p [%d] was gracefully closed", info->s, GetCurrentThreadId());
+ break;
+ }
+
+ info->mBytesInData += recvResult;
+
+ if ( info->mCaller == 1 && info->mType == SERVER_FILETRANS ) {
+ handlerResult = MSN_HandleMSNFTP( info, info->mData );
+ if ( handlerResult )
+ break;
+ }
+ else {
+ while( TRUE ) {
+ char* peol = strchr(info->mData,'\r');
+ if ( peol == NULL )
+ break;
+
+ if ( info->mBytesInData < peol-info->mData+2 )
+ break; //wait for full line end
+
+ char msg[ sizeof(info->mData) ];
+ memcpy( msg, info->mData, peol-info->mData ); msg[ peol-info->mData ] = 0;
+
+ if ( *++peol != '\n' )
+ MSN_DebugLog( "Dodgy line ending to command: ignoring" );
+ else
+ peol++;
+
+ info->mBytesInData -= peol - info->mData;
+ memmove( info->mData, peol, info->mBytesInData );
+ MSN_DebugLog( "RECV:%s", msg );
+
+ if ( !isalnum( msg[0] ) || !isalnum(msg[1]) || !isalnum(msg[2]) || (msg[3] && msg[3]!=' ')) {
+ MSN_DebugLog( "Invalid command name" );
+ continue;
+ }
+
+ if ( info->mType != SERVER_FILETRANS ) {
+ if ( isdigit(msg[0]) && isdigit(msg[1]) && isdigit(msg[2])) //all error messages
+ handlerResult = MSN_HandleErrors( info, msg );
+ else
+ handlerResult = MSN_HandleCommands( info, msg );
+ }
+ else handlerResult = MSN_HandleMSNFTP( info, msg );
+
+ if ( handlerResult )
+ goto LBL_Exit;
+ } }
+
+ if ( info->mBytesInData == sizeof( info->mData )) {
+ MSN_DebugLog( "sizeof(data) is too small: the longest line won't fit" );
+ break;
+ } }
+
+LBL_Exit:
+ if ( info->mIsMainThread ) {
+ MSN_GoOffline();
+ msnNsThread = NULL;
+ if ( hKeepAliveThreadEvt )
+ SetEvent( hKeepAliveThreadEvt );
+ }
+ else if ( info->mType == SERVER_SWITCHBOARD ) {
+ if ( info->mJoinedContacts != NULL )
+ free( info->mJoinedContacts );
+ }
+
+ MSN_DebugLog( "Thread [%d] ending now", GetCurrentThreadId() );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Added by George B. Hazan (ghazan@postman.ru)
+// The following code is required to abortively stop all started threads upon exit
+
+static ThreadData* sttThreads[ MAX_THREAD_COUNT ]; // up to MAX_THREAD_COUNT threads
+static CRITICAL_SECTION sttLock;
+
+void __stdcall MSN_InitThreads()
+{
+ memset( sttThreads, 0, sizeof( sttThreads ));
+ InitializeCriticalSection( &sttLock );
+}
+
+void __stdcall MSN_CloseConnections()
+{
+ int i;
+
+ EnterCriticalSection( &sttLock );
+
+ for ( i=0; i < MAX_THREAD_COUNT; i++ ) {
+ ThreadData* T = sttThreads[ i ];
+ if ( T == NULL )
+ continue;
+
+ switch (T->mType) {
+ case SERVER_DISPATCH :
+ case SERVER_NOTIFICATION :
+ case SERVER_SWITCHBOARD :
+ if (T->s != NULL)
+ T->sendPacket( "OUT", NULL );
+ break;
+
+ case SERVER_P2P_DIRECT :
+ if (p2p_sessionRegistered(T->mP2pSession)) {
+ filetransfer *ft = T->mP2pSession;
+ if ( ft->hWaitEvent != INVALID_HANDLE_VALUE )
+ SetEvent( ft->hWaitEvent );
+
+ if ( ft->p2p_appID != 0 )
+ p2p_sendCancel( T, ft );
+
+ ft->std.files = NULL;
+ ft->std.totalFiles = 0;
+ }
+ break;
+ } }
+
+ LeaveCriticalSection( &sttLock );
+}
+
+void __stdcall MSN_CloseThreads()
+{
+ EnterCriticalSection( &sttLock );
+
+ for ( int i=0; i < MAX_THREAD_COUNT; i++ ) {
+ ThreadData* T = sttThreads[ i ];
+ if ( T == NULL || T->s == NULL )
+ continue;
+
+ SOCKET s = MSN_CallService( MS_NETLIB_GETSOCKET, LPARAM( T->s ), 0 );
+ if ( s != INVALID_SOCKET )
+ shutdown( s, 2 );
+ }
+
+ LeaveCriticalSection( &sttLock );
+}
+
+void Threads_Uninit( void )
+{
+ DeleteCriticalSection( &sttLock );
+}
+
+ThreadData* __stdcall MSN_GetThreadByContact( HANDLE hContact )
+{
+ EnterCriticalSection( &sttLock );
+
+ ThreadData* T = NULL;
+
+ for ( int i=0; i < MAX_THREAD_COUNT; i++ )
+ {
+ T = sttThreads[ i ];
+ if ( T == NULL )
+ continue;
+
+ if ( T->mJoinedCount == 0 || T->mJoinedContacts == NULL || T->s == NULL )
+ continue;
+
+ if ( T->mJoinedContacts[0] == hContact )
+ break;
+ }
+
+ LeaveCriticalSection( &sttLock );
+ return T;
+}
+
+ThreadData* __stdcall MSN_GetOtherContactThread( ThreadData* thread )
+{
+ EnterCriticalSection( &sttLock );
+
+ ThreadData* T = NULL;
+
+ for ( int i=0; i < MAX_THREAD_COUNT; i++ )
+ {
+ T = sttThreads[ i ];
+ if ( T == NULL )
+ continue;
+
+ if ( T->mJoinedCount == 0 || T->mJoinedContacts == NULL || T->s == NULL )
+ continue;
+
+ if ( T != thread && T->mJoinedContacts[0] == thread->mJoinedContacts[0] )
+ break;
+ }
+
+ LeaveCriticalSection( &sttLock );
+ return T;
+}
+
+ThreadData* __stdcall MSN_GetUnconnectedThread( HANDLE hContact )
+{
+ EnterCriticalSection( &sttLock );
+
+ ThreadData* T = NULL;
+
+ for ( int i=0; i < MAX_THREAD_COUNT; i++ )
+ {
+ T = sttThreads[ i ];
+ if ( T == NULL )
+ continue;
+
+ if ( T->mInitialContact == hContact )
+ break;
+ }
+
+ LeaveCriticalSection( &sttLock );
+ return T;
+}
+
+int __stdcall MSN_GetActiveThreads( ThreadData** parResult )
+{
+ int tCount = 0;
+ EnterCriticalSection( &sttLock );
+
+ for ( int i=0; i < MAX_THREAD_COUNT; i++ )
+ {
+ ThreadData* T = sttThreads[ i ];
+ if ( T == NULL )
+ continue;
+
+ if ( T->mType == SERVER_SWITCHBOARD && T->mJoinedCount != 0 && T->mJoinedContacts != NULL )
+ parResult[ tCount++ ] = T;
+ }
+
+ LeaveCriticalSection( &sttLock );
+ return tCount;
+}
+
+ThreadData* __stdcall MSN_GetThreadByConnection( HANDLE s )
+{
+ ThreadData* tResult = NULL;
+
+ EnterCriticalSection( &sttLock );
+
+ for ( int i=0; i < MAX_THREAD_COUNT; i++ )
+ {
+ ThreadData* T = sttThreads[ i ];
+ if ( T == NULL )
+ continue;
+
+ if ( T->s == s )
+ { tResult = T;
+ break;
+ } }
+
+ LeaveCriticalSection( &sttLock );
+ return tResult;
+}
+
+ThreadData* __stdcall MSN_GetThreadByID( LONG id )
+{
+ ThreadData* tResult = NULL;
+
+ EnterCriticalSection( &sttLock );
+
+ for ( int i=0; i < MAX_THREAD_COUNT; i++ )
+ {
+ ThreadData* T = sttThreads[ i ];
+ if ( T != NULL && T->mUniqueID == id )
+ { tResult = T;
+ break;
+ } }
+
+ LeaveCriticalSection( &sttLock );
+ return tResult;
+}
+
+ThreadData* __stdcall MSN_GetThreadByPort( WORD wPort )
+{
+ ThreadData* tResult = NULL;
+
+ EnterCriticalSection( &sttLock );
+
+ for ( int i=0; i < MAX_THREAD_COUNT; i++ )
+ {
+ ThreadData* T = sttThreads[ i ];
+ if ( T == NULL )
+ continue;
+
+ if ( T->mP2pSession != NULL && T->mP2pSession->mIncomingPort == wPort ) {
+ tResult = T;
+ break;
+ }
+
+ if ( T->mMsnFtp != NULL && T->mMsnFtp->mIncomingPort == wPort ) {
+ tResult = T;
+ break;
+ } }
+
+ LeaveCriticalSection( &sttLock );
+ return tResult;
+}
+
+void __stdcall MSN_PingParentThread( ThreadData* parentThread, filetransfer* ft )
+{
+ EnterCriticalSection( &sttLock );
+
+ for ( int i=0; i < MAX_THREAD_COUNT; i++ )
+ {
+ if ( sttThreads[ i ] == parentThread ) {
+ parentThread->mP2pSession = ft;
+ ft->p2p_sendmsgid = ++ft->p2p_msgid;
+ parentThread->mP2PInitTrid = p2p_sendPortion( ft, parentThread );
+ break;
+ } }
+
+ LeaveCriticalSection( &sttLock );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// class ThreadData members
+
+static LONG sttThreadID = 1;
+
+ThreadData::ThreadData()
+{
+ memset( this, 0, sizeof ThreadData );
+ mUniqueID = MyInterlockedIncrement( &sttThreadID );
+ mGatewayTimeout = 2;
+ mWaitPeriod = 60;
+ mIsMainThread = false;
+}
+
+ThreadData::~ThreadData()
+{
+ if ( s != NULL ) {
+ MSN_DebugLog( "Closing connection handle %08X", s );
+ Netlib_CloseHandle( s );
+ }
+
+ if ( mMsnFtp != NULL ) {
+ delete mMsnFtp;
+ mMsnFtp = NULL;
+ }
+
+ if ( mUniqueID )
+ p2p_unregisterThreadSession( mUniqueID );
+
+ while (mFirstQueueItem != NULL)
+ {
+ TQueueItem* QI = mFirstQueueItem;
+ mFirstQueueItem = mFirstQueueItem->next;
+ free(QI);
+} }
+
+void ThreadData::applyGatewayData( HANDLE hConn, bool isPoll )
+{
+ char szHttpPostUrl[300];
+ getGatewayUrl( szHttpPostUrl, sizeof( szHttpPostUrl ), isPoll );
+
+ MSN_DebugLog( "applying '%s' to %08X [%d]", szHttpPostUrl, this, GetCurrentThreadId() );
+
+ NETLIBHTTPPROXYINFO nlhpi = {0};
+ nlhpi.cbSize = sizeof(nlhpi);
+ nlhpi.flags = NLHPIF_HTTP11;
+ nlhpi.szHttpGetUrl = NULL;
+ nlhpi.szHttpPostUrl = szHttpPostUrl;
+ nlhpi.firstPostSequence = 1;
+ MSN_CallService( MS_NETLIB_SETHTTPPROXYINFO, (WPARAM)hConn, (LPARAM)&nlhpi);
+}
+
+static char sttFormatString[] = "http://gateway.messenger.hotmail.com/gateway/gateway.dll?Action=open&Server=%s&IP=%s";
+
+void ThreadData::getGatewayUrl( char* dest, int destlen, bool isPoll )
+{
+ if ( mSessionID[0] == 0 ) {
+ if ( mType == SERVER_NOTIFICATION || mType == SERVER_DISPATCH )
+ mir_snprintf( dest, destlen, sttFormatString, "NS", "messenger.hotmail.com" );
+ else
+ mir_snprintf( dest, destlen, sttFormatString, "SB", mServer );
+ strcpy( mGatewayIP, MSN_DEFAULT_GATEWAY );
+ }
+ else mir_snprintf( dest, destlen, "http://%s/gateway/gateway.dll?%sSessionID=%s",
+ mGatewayIP, ( isPoll ) ? "Action=poll&" : "", mSessionID );
+}
+
+void ThreadData::processSessionData( const char* str )
+{
+ char tSessionID[40], tGateIP[ 40 ];
+
+ char* tDelim = ( char* )strchr( str, ';' );
+ if ( tDelim == NULL )
+ return;
+
+ *tDelim = 0; tDelim += 2;
+
+ if ( !sscanf( str, "SessionID=%s", tSessionID ))
+ return;
+
+ char* tDelim2 = strchr( tDelim, ';' );
+ if ( tDelim2 != NULL )
+ *tDelim2 = '\0';
+
+ if ( !sscanf( tDelim, "GW-IP=%s", tGateIP ))
+ return;
+
+// MSN_DebugLog( "msn_httpGatewayUnwrapRecv printed '%s','%s' to %08X (%08X)", tSessionID, tGateIP, s, this );
+ strcpy( mGatewayIP, tGateIP );
+ strcpy( mSessionID, tSessionID );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// thread start code
+
+static void sttRegisterThread( ThreadData* s )
+{
+ EnterCriticalSection( &sttLock );
+
+ for ( int i=0; i < MAX_THREAD_COUNT; i++ )
+ if ( sttThreads[ i ] == NULL )
+ { sttThreads[ i ] = s;
+ break;
+ }
+
+ LeaveCriticalSection( &sttLock );
+}
+
+static void sttUnregisterThread( ThreadData* s )
+{
+ EnterCriticalSection( &sttLock );
+
+ for ( int i=0; i < MAX_THREAD_COUNT; i++ )
+ { if ( sttThreads[ i ] == s )
+ { sttThreads[ i ] = NULL;
+ break;
+ } }
+
+ LeaveCriticalSection( &sttLock );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+struct FORK_ARG {
+ HANDLE hEvent;
+ pThreadFunc threadcode;
+ ThreadData* arg;
+};
+
+static void __cdecl forkthread_r(struct FORK_ARG *fa)
+{
+ pThreadFunc callercode = fa->threadcode;
+ ThreadData* arg = fa->arg;
+ MSN_CallService(MS_SYSTEM_THREAD_PUSH, 0, 0);
+ sttRegisterThread( arg );
+ MSN_DebugLog( "Starting thread %08X (%08X)", GetCurrentThreadId(), callercode );
+ SetEvent(fa->hEvent);
+ __try {
+ callercode(arg);
+ } __finally {
+ MSN_DebugLog( "Leaving thread %08X (%08X)", GetCurrentThreadId(), callercode );
+ sttUnregisterThread( arg );
+ delete arg;
+
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
+ MSN_CallService(MS_SYSTEM_THREAD_POP, 0, 0);
+ }
+ return;
+}
+
+void ThreadData::startThread( pThreadFunc parFunc )
+{
+ FORK_ARG fa = { CreateEvent(NULL, FALSE, FALSE, NULL), parFunc, this };
+ unsigned long rc = _beginthread(( pThreadFunc )forkthread_r, 0, &fa );
+ if ((unsigned long) -1L != rc)
+ WaitForSingleObject(fa.hEvent, INFINITE);
+ CloseHandle(fa.hEvent);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+struct FORK_ARG2 {
+ HANDLE hEvent;
+ pThreadFunc threadcode;
+ void* arg;
+};
+
+static void __cdecl forkthread_r2(struct FORK_ARG2 *fa)
+{
+ pThreadFunc callercode = fa->threadcode;
+ void* arg = fa->arg;
+ MSN_CallService(MS_SYSTEM_THREAD_PUSH, 0, 0);
+ MSN_DebugLog( "Starting thread %08X (%08X)", GetCurrentThreadId(), callercode );
+ SetEvent(fa->hEvent);
+
+ __try {
+ callercode(arg);
+ } __finally {
+ MSN_DebugLog( "Leaving thread %08X (%08X)", GetCurrentThreadId(), callercode );
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
+ MSN_CallService(MS_SYSTEM_THREAD_POP, 0, 0);
+ }
+ return;
+}
+
+void __stdcall MSN_StartThread( pThreadFunc parFunc, void* arg )
+{
+ FORK_ARG2 fa = { CreateEvent(NULL, FALSE, FALSE, NULL), parFunc, arg };
+ unsigned long rc = _beginthread(( pThreadFunc )forkthread_r2, 0, &fa );
+ if ((unsigned long) -1L != rc)
+ WaitForSingleObject(fa.hEvent, INFINITE);
+ CloseHandle(fa.hEvent);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// HReadBuffer members
+
+HReadBuffer::HReadBuffer( ThreadData* T, int iStart )
+{
+ owner = T;
+ buffer = ( BYTE* )T->mData;
+ totalDataSize = T->mBytesInData;
+ startOffset = iStart;
+}
+
+HReadBuffer::~HReadBuffer()
+{
+ owner->mBytesInData = totalDataSize - startOffset;
+ if ( owner->mBytesInData != 0 )
+ memmove( owner->mData, owner->mData + startOffset, owner->mBytesInData );
+}
+
+BYTE* HReadBuffer::surelyRead( int parBytes )
+{
+ if ( startOffset + parBytes > totalDataSize )
+ {
+ int tNewLen = totalDataSize - startOffset;
+ if ( tNewLen > 0 )
+ memmove( buffer, buffer + startOffset, tNewLen );
+ else
+ tNewLen = 0;
+
+ startOffset = 0;
+ totalDataSize = tNewLen;
+ }
+
+ int bufferSize = sizeof owner->mData;
+ if ( parBytes > bufferSize - startOffset ) {
+ MSN_DebugLog( "HReadBuffer::surelyRead: not enough memory, %d %d %d", parBytes, bufferSize, startOffset );
+ return NULL;
+ }
+
+ while( totalDataSize - startOffset < parBytes )
+ {
+ int recvResult = owner->recv(( char* )buffer + totalDataSize, bufferSize - totalDataSize );
+ if ( recvResult <= 0 )
+ return NULL;
+
+ totalDataSize += recvResult;
+ }
+
+ BYTE* result = buffer + startOffset; startOffset += parBytes;
+ return result;
+}
diff --git a/miranda-wine/protocols/MSN/msn_useropts.cpp b/miranda-wine/protocols/MSN/msn_useropts.cpp
new file mode 100644
index 0000000..24cc1fb
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_useropts.cpp
@@ -0,0 +1,287 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+This file uses the 'Webhost sample' code
+Copyright(C) 2002 Chris Becke (http://www.mvps.org/user32/webhost.cab)
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "msn_global.h"
+
+#include <fcntl.h>
+#include <io.h>
+#include <sys/stat.h>
+
+#include "resource.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Loads PNG2DIB library to handle PNG images. If DLL isn't found or can't be loaded,
+// a special error dialog appears.
+
+static BOOL CALLBACK LoadPng2dibProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+ switch( uMsg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ {
+ RECT tRect;
+ GetWindowRect( hwndDlg, &tRect );
+ HDC tHDC = GetDC( hwndDlg );
+ int tXXXX = GetDeviceCaps( tHDC, HORZRES );
+ int tYYYY = GetDeviceCaps( tHDC, VERTRES );
+ ReleaseDC( hwndDlg, tHDC );
+ SetWindowPos( hwndDlg, HWND_TOP, tXXXX/2 - ( tRect.right-tRect.left )/2 - 1, tYYYY/2 - ( tRect.bottom-tRect.top )/2 - 1, 0, 0, SWP_NOSIZE );
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ if ( HIWORD( wParam ) == BN_CLICKED ) {
+ switch( LOWORD( wParam )) {
+ case IDC_BTN_INSTALL:
+ MSN_CallService( MS_UTILS_OPENURL, TRUE, ( LPARAM )"http://www.postman.ru/~ghazan/files/png2dib.mir" );
+ EndDialog( hwndDlg, 1 );
+ break;
+
+ case IDC_BTN_DOWNLOAD:
+ MSN_CallService( MS_UTILS_OPENURL, TRUE, ( LPARAM )"http://www.postman.ru/~ghazan/files/png2dib.zip" );
+ EndDialog( hwndDlg, 2 );
+ break;
+
+ case IDC_BTN_CANCEL:
+ EndDialog( hwndDlg, 3 );
+ break;
+ } } }
+
+ return FALSE;
+}
+
+BOOL __stdcall MSN_LoadPngModule()
+{
+ if ( !ServiceExists(MS_DIB2PNG) || !ServiceExists(MS_PNG2DIB)) {
+ DialogBox( hInst, MAKEINTRESOURCE( IDD_GET_PNG2DIB ), NULL, LoadPng2dibProc );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN contact option page dialog procedure.
+
+struct MsnDlgProcData
+{
+ HANDLE hContact;
+ HANDLE hEventHook;
+};
+
+#define HM_REBIND_AVATAR ( WM_USER + 1024 )
+
+BOOL CALLBACK MsnDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ {
+ MsnDlgProcData* pData = new MsnDlgProcData;
+ pData->hContact = ( HANDLE )lParam;
+ pData->hEventHook = HookEventMessage( ME_PROTO_ACK, hwndDlg, HM_REBIND_AVATAR );
+ SetWindowLong( hwndDlg, GWL_USERDATA, LONG( pData ));
+
+ char tBuffer[ MAX_PATH ];
+ if ( MSN_GetStaticString( "OnMobile", pData->hContact, tBuffer, sizeof tBuffer ))
+ strcpy( tBuffer, "N" );
+ SetDlgItemTextA( hwndDlg, IDC_MOBILE, tBuffer );
+
+ if ( MSN_GetStaticString( "OnMsnMobile", pData->hContact, tBuffer, sizeof tBuffer ))
+ strcpy( tBuffer, "N" );
+ SetDlgItemTextA( hwndDlg, IDC_MSN_MOBILE, tBuffer );
+
+ DWORD dwFlagBits = MSN_GetDword( pData->hContact, "FlagBits", 0 );
+ SetDlgItemTextA( hwndDlg, IDC_WEBMESSENGER, ( dwFlagBits & 0x200 ) ? "Y" : "N" );
+
+ if ( MyOptions.EnableAvatars ) {
+ MSN_GetAvatarFileName(( HANDLE )lParam, tBuffer, sizeof tBuffer );
+
+ if ( access( tBuffer, 0 )) {
+LBL_Reread: DBWriteContactSettingString( pData->hContact, "ContactPhoto", "File", tBuffer );
+ p2p_invite( pData->hContact, MSN_APPID_AVATAR );
+ return TRUE;
+ }
+
+ char tSavedContext[ 256 ], tNewContext[ 256 ];
+ if ( MSN_GetStaticString( "PictContext", pData->hContact, tNewContext, sizeof( tNewContext )) ||
+ MSN_GetStaticString( "PictSavedContext", pData->hContact, tSavedContext, sizeof( tSavedContext )))
+ goto LBL_Reread;
+
+ if ( stricmp( tNewContext, tSavedContext ))
+ goto LBL_Reread;
+
+ SendDlgItemMessageA( hwndDlg, IDC_MSN_PICT, STM_SETIMAGE, IMAGE_BITMAP,
+ ( LPARAM )LoadImageA( ::GetModuleHandle(NULL), tBuffer, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ));
+ } }
+ return TRUE;
+
+ case HM_REBIND_AVATAR:
+ { MsnDlgProcData* pData = ( MsnDlgProcData* )GetWindowLong( hwndDlg, GWL_USERDATA );
+
+ ACKDATA* ack = ( ACKDATA* )lParam;
+ if ( ack->type == ACKTYPE_AVATAR && ack->hContact == pData->hContact ) {
+ if ( ack->result == ACKRESULT_SUCCESS ) {
+ PROTO_AVATAR_INFORMATION* AI = ( PROTO_AVATAR_INFORMATION* )ack->hProcess;
+ SendDlgItemMessageA( hwndDlg, IDC_MSN_PICT, STM_SETIMAGE, IMAGE_BITMAP,
+ ( LPARAM )LoadImageA( ::GetModuleHandle(NULL), AI->filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ));
+ }
+ else if ( ack->result == ACKRESULT_STATUS )
+ p2p_invite( ack->hContact, MSN_APPID_AVATAR );
+ } }
+ break;
+
+ case WM_DESTROY:
+ MsnDlgProcData* pData = ( MsnDlgProcData* )GetWindowLong( hwndDlg, GWL_USERDATA );
+ UnhookEvent( pData->hEventHook );
+ delete pData;
+ }
+
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// AvatarDlgProc - MSN avatar option page dialog procedure.
+
+static HBITMAP hAvatar = NULL;
+
+static bool sttSetAvatar( HWND hwndDlg )
+{
+ char szFileName[ MAX_PATH ];
+ if ( MSN_EnterBitmapFileName( szFileName ) != ERROR_SUCCESS )
+ return false;
+
+ HBITMAP hBitmap = ( HBITMAP )MSN_CallService( MS_UTILS_LOADBITMAP, 0, ( LPARAM )szFileName );
+ if ( hBitmap == NULL )
+ return false;
+
+ if (( hBitmap = MSN_StretchBitmap( hBitmap )) == NULL )
+ return false;
+
+ if ( hAvatar != NULL ) {
+ DeleteObject( hAvatar );
+ hAvatar = NULL;
+ }
+
+ MSN_SaveBitmapAsAvatar( hAvatar = hBitmap, szFileName );
+
+ if ( msnLoggedIn )
+ MSN_SetServerStatus( msnStatusMode );
+
+ return true;
+}
+
+BOOL CALLBACK AvatarDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static RECT r;
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+
+ hAvatar = NULL;
+ if ( MSN_GetByte( "EnableAvatars", 0 )) {
+ if ( MSN_LoadPngModule() ) {
+ char tBuffer[ MAX_PATH ];
+ MSN_GetAvatarFileName( NULL, tBuffer, sizeof tBuffer );
+ hAvatar = ( HBITMAP )MSN_CallService( MS_UTILS_LOADBITMAP, 0, ( LPARAM )tBuffer );
+ if ( hAvatar != NULL )
+ SendDlgItemMessage(hwndDlg, IDC_AVATAR, STM_SETIMAGE, IMAGE_BITMAP, (WPARAM)hAvatar );
+ }
+ else MSN_SetByte( "EnableAvatars", 0 );
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ if ( HIWORD( wParam ) == BN_CLICKED ) {
+ switch( LOWORD( wParam )) {
+ case IDC_SETAVATAR:
+ if ( sttSetAvatar( hwndDlg ))
+ SendDlgItemMessage(hwndDlg, IDC_AVATAR, STM_SETIMAGE, IMAGE_BITMAP, (WPARAM)hAvatar );
+ break;
+
+ case IDC_DELETEAVATAR:
+ if ( hAvatar != NULL ) {
+ DeleteObject( hAvatar );
+ hAvatar = NULL;
+ }
+
+ char tFileName[ MAX_PATH ];
+ MSN_GetAvatarFileName( NULL, tFileName, sizeof tFileName );
+ DeleteFileA( tFileName );
+ DBDeleteContactSetting( NULL, msnProtocolName, "PictObject" );
+ InvalidateRect( hwndDlg, NULL, TRUE );
+ break;
+ } }
+ break;
+
+ case WM_DESTROY:
+ if ( hAvatar != NULL )
+ DeleteObject( hAvatar );
+ break;
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnOnDetailsInit - initializes user info dialog pages.
+
+int MsnOnDetailsInit( WPARAM wParam, LPARAM lParam )
+{
+ OPTIONSDIALOGPAGE odp = {0};
+ odp.cbSize = sizeof(odp);
+ odp.hIcon = NULL;
+ odp.hInstance = hInst;
+
+ HANDLE hContact = ( HANDLE )lParam;
+ if ( hContact == NULL ) {
+ if ( MyOptions.EnableAvatars ) {
+ char szTitle[256];
+ mir_snprintf( szTitle, sizeof( szTitle ), "%s %s", msnProtocolName, MSN_Translate( "Avatar" ));
+
+ odp.pfnDlgProc = AvatarDlgProc;
+ odp.position = 1900000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_SETAVATAR);
+ odp.pszTitle = szTitle;
+ MSN_CallService(MS_USERINFO_ADDPAGE, wParam, (LPARAM)&odp);
+ }
+ return 0;
+ }
+
+ char* szProto = ( char* )MSN_CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact, 0 );
+ if ( lstrcmpA( szProto, msnProtocolName ))
+ return 0;
+
+ if ( MyOptions.EnableAvatars && MSN_GetDword( hContact, "FlagBits", 0 )) {
+ odp.pfnDlgProc = MsnDlgProc;
+ odp.position = -1900000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_USEROPTS);
+ odp.pszTitle = Translate(msnProtocolName);
+ MSN_CallService(MS_USERINFO_ADDPAGE, wParam, (LPARAM)&odp);
+ }
+ return 0;
+}
diff --git a/miranda-wine/protocols/MSN/msn_ws.cpp b/miranda-wine/protocols/MSN/msn_ws.cpp
new file mode 100644
index 0000000..274b4be
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_ws.cpp
@@ -0,0 +1,324 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "msn_global.h"
+
+static char sttGatewayHeader[] =
+ "POST %s HTTP/1.1\r\n"
+ "Accept: */*\r\n"
+ "Content-Type: text/xml; charset=utf-8\r\n"
+ "Content-Length: %d\r\n"
+ "User-Agent: %s\r\n"
+ "Host: %s\r\n"
+ "Connection: Keep-Alive\r\n"
+ "Cache-Control: no-cache\r\n\r\n";
+
+//=======================================================================================
+
+int ThreadData::send( char* data, int datalen )
+{
+ if ( this == NULL )
+ return 0;
+
+ NETLIBBUFFER nlb = { data, datalen, 0 };
+
+ mWaitPeriod = 60;
+
+ if ( MyOptions.UseGateway && !( mType == SERVER_FILETRANS && mP2pSession != NULL )) {
+ mGatewayTimeout = 2;
+
+ if ( !MyOptions.UseProxy ) {
+ TQueueItem* tNewItem = ( TQueueItem* )malloc( datalen + sizeof( void* ) + sizeof( int ) + 1 );
+ tNewItem->datalen = datalen;
+ memcpy( tNewItem->data, data, datalen );
+ tNewItem->data[datalen] = 0;
+
+ TQueueItem* p = mFirstQueueItem;
+ if ( p != NULL ) {
+ while ( p->next != NULL )
+ p = p->next;
+
+ p ->next = tNewItem;
+ }
+ else mFirstQueueItem = tNewItem;
+
+ tNewItem->next = NULL;
+ return TRUE;
+ }
+
+ MSN_CallService( MS_NETLIB_SETPOLLINGTIMEOUT, WPARAM( s ), mGatewayTimeout );
+ }
+
+ int rlen = MSN_CallService( MS_NETLIB_SEND, ( WPARAM )s, ( LPARAM )&nlb );
+ if ( rlen == SOCKET_ERROR ) {
+ // should really also check if sendlen is the same as datalen
+ MSN_DebugLog( "Send failed: %d", WSAGetLastError() );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+//=======================================================================================
+// Receving data
+//=======================================================================================
+
+int ThreadData::recv_dg( char* data, long datalen )
+{
+ if ( mReadAheadBuffer != NULL ) {
+ int tBytesToCopy = ( datalen >= mEhoughData ) ? mEhoughData : datalen;
+ memcpy( data, mReadAheadBuffer, tBytesToCopy );
+ mEhoughData -= tBytesToCopy;
+ if ( mEhoughData == 0 ) {
+ free( mReadAheadBuffer );
+ mReadAheadBuffer = NULL;
+ }
+ else memmove( mReadAheadBuffer, mReadAheadBuffer + tBytesToCopy, mEhoughData );
+
+ return tBytesToCopy;
+ }
+
+ bool bCanPeekMsg = true;
+
+LBL_RecvAgain:
+ int ret = 0;
+ {
+ NETLIBSELECT tSelect = {0};
+ tSelect.cbSize = sizeof( tSelect );
+ tSelect.dwTimeout = 1000;
+ tSelect.hReadConns[ 0 ] = ( HANDLE )s;
+
+ for ( int i=0; i < mGatewayTimeout || !bCanPeekMsg; i++ ) {
+ if ( bCanPeekMsg ) {
+ TQueueItem* QI = mFirstQueueItem;
+ if ( QI != NULL )
+ {
+ char szHttpPostUrl[300];
+ getGatewayUrl( szHttpPostUrl, sizeof( szHttpPostUrl ), QI->datalen == 0 );
+
+ char* tBuffer = ( char* )alloca( QI->datalen+400 );
+ int cbBytes = mir_snprintf( tBuffer, QI->datalen+400, sttGatewayHeader,
+ szHttpPostUrl, QI->datalen, MSN_USER_AGENT, mGatewayIP);
+ memcpy( tBuffer+cbBytes, QI->data, QI->datalen );
+ cbBytes += QI->datalen;
+ tBuffer[ cbBytes ] = 0;
+
+ NETLIBBUFFER nlb = { tBuffer, cbBytes, 0 };
+ ret = MSN_CallService( MS_NETLIB_SEND, ( WPARAM )s, ( LPARAM )&nlb );
+ if ( ret == SOCKET_ERROR ) {
+ MSN_DebugLog( "Send failed: %d", WSAGetLastError() );
+ return 0;
+ }
+
+ mFirstQueueItem = QI->next;
+ free( QI );
+
+ ret = 1;
+ break;
+ } }
+
+ ret = MSN_CallService( MS_NETLIB_SELECT, 0, ( LPARAM )&tSelect );
+ if ( ret != 0 )
+ break;
+ // Timeout switchboard session if inactive
+ if ( !mIsMainThread && mJoinedCount <= 1 && --mWaitPeriod <= 0 )
+ {
+ if (mJoinedCount == 0 || p2p_getFirstSession(mJoinedContacts[0]) == NULL)
+ {
+ MSN_DebugLog( "Dropping the idle switchboard due to the 60 sec timeout" );
+ return 0;
+ }
+ else
+ mWaitPeriod = 60;
+ }
+ }
+ }
+
+ bCanPeekMsg = false;
+
+ if ( ret == 0 ) {
+ mGatewayTimeout += 2;
+ if ( mGatewayTimeout > 8 )
+ mGatewayTimeout = 8;
+
+ char szHttpPostUrl[300];
+ getGatewayUrl( szHttpPostUrl, sizeof( szHttpPostUrl ), true );
+
+ char szCommand[ 400 ];
+ int cbBytes = mir_snprintf( szCommand, sizeof( szCommand ),
+ sttGatewayHeader, szHttpPostUrl, 0, MSN_USER_AGENT, mGatewayIP);
+
+ NETLIBBUFFER nlb = { szCommand, cbBytes, 0 };
+ MSN_CallService( MS_NETLIB_SEND, ( WPARAM )s, ( LPARAM )&nlb );
+ goto LBL_RecvAgain;
+ }
+
+ NETLIBBUFFER nlb = { data, datalen, 0 };
+ ret = MSN_CallService( MS_NETLIB_RECV, ( WPARAM )s, ( LPARAM )&nlb );
+ if ( ret == 0 ) {
+ MSN_DebugLog( "Connection closed gracefully");
+ return 0;
+ }
+
+ if ( ret < 0 ) {
+ MSN_DebugLog( "Connection abortively closed, error %d", WSAGetLastError() );
+ return ret;
+ }
+
+ bCanPeekMsg = true;
+
+ char* p = strstr( data, "\r\n" );
+ if ( p == NULL ) {
+ MSN_DebugLog( "ACHTUNG! it's not a valid header: '%s'", data );
+ goto LBL_RecvAgain;
+ }
+
+ int status = 0;
+ sscanf( data, "HTTP/1.1 %d", &status );
+ if ( status == 100 )
+ goto LBL_RecvAgain;
+
+ int tContentLength = 0, hdrLen;
+ {
+ MimeHeaders tHeaders;
+ const char* rest = tHeaders.readFromBuffer( p+2 );
+ if ( *rest == '\r' )
+ rest += 2;
+
+ for ( int i=0; i < tHeaders.mCount; i++ )
+ {
+ MimeHeader& H = tHeaders.mVals[i];
+
+ if ( stricmp( H.name, "X-MSN-Messenger" ) == 0 ) {
+ if ( strstr( H.value, "Session=close" ) != 0 ) {
+ return 0;
+ }
+
+ processSessionData( H.value );
+ }
+
+ if ( stricmp( H.name, "Content-Length" ) == 0 )
+ tContentLength = atol( H.value );
+ }
+
+ hdrLen = int( rest - data );
+ }
+
+ if ( tContentLength == 0 )
+ goto LBL_RecvAgain;
+ else
+ {
+ mGatewayTimeout = 1;
+ mWaitPeriod = 60;
+ }
+
+ ret -= hdrLen;
+ if ( ret <= 0 ) {
+ nlb.buf = data;
+ nlb.len = datalen;
+ ret = MSN_CallService( MS_NETLIB_RECV, ( WPARAM )s, ( LPARAM )&nlb );
+ if ( ret <= 0 )
+ return ret;
+ }
+ else memmove( data, data+hdrLen, ret );
+
+ if ( tContentLength > ret ) {
+ tContentLength -= ret;
+
+ mReadAheadBuffer = ( char* )calloc( tContentLength+1, 1 );
+ mReadAheadBuffer[ tContentLength ] = 0;
+ mEhoughData = tContentLength;
+ nlb.buf = mReadAheadBuffer;
+
+ while ( tContentLength > 0 ) {
+ nlb.len = tContentLength;
+ int ret2 = MSN_CallService( MS_NETLIB_RECV, ( WPARAM )s, ( LPARAM )&nlb );
+ if ( ret2 <= 0 )
+ { free( mReadAheadBuffer );
+ mReadAheadBuffer = NULL;
+ return ret2;
+ }
+
+ tContentLength -= ret2;
+ nlb.buf += ret2;
+ } }
+
+ return ret;
+}
+
+int ThreadData::recv( char* data, long datalen )
+{
+ if ( MyOptions.UseGateway && !MyOptions.UseProxy )
+ if ( mType != SERVER_FILETRANS || mP2pSession == 0 )
+ return recv_dg( data, datalen );
+
+ NETLIBBUFFER nlb = { data, datalen, 0 };
+
+LBL_RecvAgain:
+ if ( !mIsMainThread && !MyOptions.UseGateway && !MyOptions.UseProxy ) {
+ mWaitPeriod = 60;
+ while ( --mWaitPeriod >= 0 ) {
+ NETLIBSELECT nls = { 0 };
+ nls.cbSize = sizeof( nls );
+ nls.dwTimeout = 1000;
+ nls.hReadConns[0] = s;
+ if ( MSN_CallService( MS_NETLIB_SELECT, 0, ( LPARAM )&nls ) != 0 )
+ break;
+ }
+
+ if ( mWaitPeriod < 0 && mJoinedCount <= 1 ) {
+ if (mJoinedCount == 0 || p2p_getFirstSession(mJoinedContacts[0]) == NULL) {
+ MSN_DebugLog( "Dropping the idle switchboard due to the 60 sec timeout" );
+ return 0;
+ }
+ else mWaitPeriod = 60;
+ } }
+
+ int ret = MSN_CallService( MS_NETLIB_RECV, ( WPARAM )s, ( LPARAM )&nlb );
+ if ( ret == 0 ) {
+ MSN_DebugLog( "Connection closed gracefully" );
+ return 0;
+ }
+
+ if ( ret < 0 ) {
+ MSN_DebugLog( "Connection abortively closed, error %d", WSAGetLastError() );
+ return ret;
+ }
+
+ if ( MyOptions.UseGateway)
+ {
+ if ( ret == 1 && *data == 0 )
+ {
+ int tOldTimeout = MSN_CallService( MS_NETLIB_SETPOLLINGTIMEOUT, WPARAM( s ), 2 );
+ tOldTimeout += 2;
+ if ( tOldTimeout > 8 )
+ tOldTimeout = 8;
+
+ MSN_CallService( MS_NETLIB_SETPOLLINGTIMEOUT, WPARAM( s ), tOldTimeout );
+ goto LBL_RecvAgain;
+ }
+ else MSN_CallService( MS_NETLIB_SETPOLLINGTIMEOUT, WPARAM( s ), 1 );
+ }
+
+ return ret;
+}
diff --git a/miranda-wine/protocols/MSN/resource.h b/miranda-wine/protocols/MSN/resource.h
new file mode 100644
index 0000000..25ab3ed
--- /dev/null
+++ b/miranda-wine/protocols/MSN/resource.h
@@ -0,0 +1,111 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by msn.rc
+//
+#define IDI_MSN 1
+#define IDD_USEROPTS 105
+#define IDD_OPT_MSN_CONN 106
+#define IDD_HOTMAIL_OPT_POPUP 107
+#define IDI_MSNBLOCK 108
+#define IDI_INBOX 112
+#define IDI_INVITE 113
+#define IDI_NETMEETING 114
+#define IDI_PROFILE 115
+#define IDD_GET_PNG2DIB 118
+#define IDD_LISTSMGR 119
+#define IDI_LIST_FL 120
+#define IDI_LIST_AL 121
+#define IDI_LIST_BL 122
+#define IDI_LIST_RL 123
+#define IDI_AVATAR 125
+#define IDI_NUDGE 128
+#define IDI_SERVICES 129
+#define IDI_ICON2 130
+#define IDD_DIALOG1 131
+#define IDD_SETAVATAR 132
+#define IDD_OPT_MSNMAIN 184
+#define IDC_OPTIONSTAB 101
+#define IDD_OPT_MSN 185
+#define IDD_SETNICKNAME 226
+#define IDC_STMSNGROUP 1002
+#define IDC_EDIT1 1003
+#define IDC_USERTYPING 1004
+#define IDC_USEIEPROXY 1005
+#define IDC_ENABLE_AVATARS 1006
+#define IDC_USEWINCOLORS 1007
+#define IDC_ENABLE_NUDGE 1007
+#define IDC_MSN_PICT 1008
+#define IDC_NUDGE_MESSAGE 1008
+#define IDC_CUSTOM1 1009
+#define IDC_NUDGE_POPUP 1009
+#define IDC_USE_OWN_NICKNAME 1010
+#define IDC_BTN_INSTALL 1011
+#define IDC_NUDGE_CLIST 1011
+#define IDC_BTN_DOWNLOAD 1012
+#define IDC_NUDGE_CHAT 1012
+#define IDC_BTN_CANCEL 1013
+#define IDC_NUDGE_POPUP2 1013
+#define IDC_NUDGE_SOUND 1013
+#define IDC_MSNLISTS 1014
+#define IDC_LIST 1015
+#define IDC_ICON_FL 1016
+#define IDC_ICON_RL 1017
+#define IDC_ICON_AL 1018
+#define IDC_ICON_BL 1019
+#define IDC_PASSWORD 1020
+#define IDC_AVATAR 1021
+#define IDC_HANDLE 1022
+#define IDC_HANDLE2 1023
+#define IDC_SETAVATAR 1024
+#define IDC_DELETEAVATAR 1025
+#define IDC_BGCOLOUR 1026
+#define IDC_KEEPALIVE 1027
+#define IDC_TEXTCOLOUR 1028
+#define IDC_AWAY_AS_BRB 1029
+#define IDC_PREVIEW 1030
+#define IDC_PREVIEW2 1031
+#define IDC_ENABLE 1032
+#define IDC_SLOWSEND 1033
+#define IDC_MANAGEGROUPS 1034
+#define IDC_NOTIFY_ENDSESSION 1035
+#define IDC_CHECK1 1036
+#define IDC_USEOPENSSL 1036
+#define IDC_USEMSNP11 1037
+#define IDC_STMSNEXTRAGROUP 1037
+#define IDC_SENDFONTINFO 1046
+#define IDC_NOTIFY_USERTYPE 1047
+#define IDC_NICKNAME 1048
+#define IDC_DISABLEHOTJUNK 1049
+#define IDC_DEBUG 1050
+#define IDC_POPUP_TIMEOUT 1051
+#define IDC_POPUP_TIMEOUT2 1052
+#define IDC_NOTIFY_FIRSTMSG 1053
+#define IDC_DISABLE_ANOTHER_CONTACTS 1054
+#define IDC_ERRORS_USING_POPUPS 1056
+#define IDC_MAILER_APP 1057
+#define IDC_RUN_APP_ON_HOTMAIL 1058
+#define IDC_ENTER_MAILER_APP 1059
+#define IDC_MOBILE 1060
+#define IDC_MSN_MOBILE 1061
+#define IDC_WEBMESSENGER 1062
+#define IDC_LOGINSERVER 1171
+#define IDC_YOURHOST 1172
+#define IDC_MSNPORT 1174
+#define IDC_USEGATEWAY 1175
+#define IDC_DISABLEHOTMAIL 1301
+#define IDC_AUTOGETHOST 1302
+#define IDC_DISABLE_MAIN_MENU 1303
+#define IDC_NEWMSNACCOUNTLINK 1438
+#define IDC_RESETSERVER 1472
+#define IDC_STATIC -1
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 133
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1038
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/miranda-wine/protocols/MSN/resource.rc b/miranda-wine/protocols/MSN/resource.rc
new file mode 100644
index 0000000..3e562dc
--- /dev/null
+++ b/miranda-wine/protocols/MSN/resource.rc
@@ -0,0 +1,2 @@
+#include "msn.rc"
+#include "version.rc"
diff --git a/miranda-wine/protocols/MSN/sha1.c b/miranda-wine/protocols/MSN/sha1.c
new file mode 100644
index 0000000..887c54a
--- /dev/null
+++ b/miranda-wine/protocols/MSN/sha1.c
@@ -0,0 +1,419 @@
+/*
+
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+*/
+
+/*
+ * sha1.c
+ *
+ * Description:
+ * This file implements the Secure Hashing Algorithm 1 as
+ * defined in FIPS PUB 180-1 published April 17, 1995.
+ *
+ * The SHA-1, produces a 160-bit message digest for a given
+ * data stream. It should take about 2**n steps to find a
+ * message with the same digest as a given message and
+ * 2**(n/2) to find any two messages with the same digest,
+ * when n is the digest size in bits. Therefore, this
+ * algorithm can serve as a means of providing a
+ * "fingerprint" for a message.
+ *
+ * Portability Issues:
+ * SHA-1 is defined in terms of 32-bit "words". This code
+ * uses <stdint.h> (included via "sha1.h" to define 32 and 8
+ * bit unsigned integer types. If your C compiler does not
+ * support 32 bit unsigned integers, this code is not
+ * appropriate.
+ *
+ * Caveats:
+ * SHA-1 is designed to work with messages less than 2^64 bits
+ * long. Although SHA-1 allows a message digest to be generated
+ * for messages of any number of bits less than 2^64, this
+ * implementation only works with messages with a length that is
+ * a multiple of the size of an 8-bit character.
+ *
+ */
+
+#include "sha1.h"
+
+/*
+ * Define the SHA1 circular left shift macro
+ */
+#define SHA1CircularShift(bits,word) \
+ (((word) << (bits)) | ((word) >> (32-(bits))))
+
+/* Local Function Prototyptes */
+void SHA1PadMessage(SHA1Context *);
+void SHA1ProcessMessageBlock(SHA1Context *);
+
+/*
+ * SHA1Reset
+ *
+ * Description:
+ * This function will initialize the SHA1Context in preparation
+ * for computing a new SHA1 message digest.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to reset.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA1Reset(SHA1Context *context)
+{
+ if (!context)
+ {
+ return shaNull;
+ }
+
+ context->Length_Low = 0;
+ context->Length_High = 0;
+ context->Message_Block_Index = 0;
+
+ context->Intermediate_Hash[0] = 0x67452301;
+ context->Intermediate_Hash[1] = 0xEFCDAB89;
+ context->Intermediate_Hash[2] = 0x98BADCFE;
+ context->Intermediate_Hash[3] = 0x10325476;
+ context->Intermediate_Hash[4] = 0xC3D2E1F0;
+
+ context->Computed = 0;
+ context->Corrupted = 0;
+
+ return shaSuccess;
+}
+
+/*
+ * SHA1Result
+ *
+ * Description:
+ * This function will return the 160-bit message digest into the
+ * Message_Digest array provided by the caller.
+ * NOTE: The first octet of hash is stored in the 0th element,
+ * the last octet of hash in the 19th element.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to use to calculate the SHA-1 hash.
+ * Message_Digest: [out]
+ * Where the digest is returned.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA1Result( SHA1Context *context,
+ uint8_t Message_Digest[SHA1HashSize])
+{
+ int i;
+
+ if (!context || !Message_Digest)
+ {
+ return shaNull;
+ }
+
+ if (context->Corrupted)
+ {
+ return context->Corrupted;
+ }
+
+ if (!context->Computed)
+ {
+ SHA1PadMessage(context);
+ for(i=0; i<64; ++i)
+ {
+ /* message may be sensitive, clear it out */
+ context->Message_Block[i] = 0;
+ }
+ context->Length_Low = 0; /* and clear length */
+ context->Length_High = 0;
+ context->Computed = 1;
+
+ }
+
+ for(i = 0; i < SHA1HashSize; ++i)
+ {
+ Message_Digest[i] = (uint8_t) (context->Intermediate_Hash[i>>2]
+ >> 8 * ( 3 - ( i & 0x03 ) ));
+ }
+
+ return shaSuccess;
+}
+
+/*
+ * SHA1Input
+ *
+ * Description:
+ * This function accepts an array of octets as the next portion
+ * of the message.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The SHA context to update
+ * message_array: [in]
+ * An array of characters representing the next portion of
+ * the message.
+ * length: [in]
+ * The length of the message in message_array
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA1Input( SHA1Context *context,
+ const uint8_t *message_array,
+ unsigned length)
+{
+ if (!length)
+ {
+ return shaSuccess;
+ }
+
+ if (!context || !message_array)
+ {
+ return shaNull;
+ }
+
+ if (context->Computed)
+ {
+ context->Corrupted = shaStateError;
+
+ return shaStateError;
+ }
+
+ if (context->Corrupted)
+ {
+ return context->Corrupted;
+ }
+ while(length-- && !context->Corrupted)
+ {
+ context->Message_Block[context->Message_Block_Index++] =
+ (*message_array & 0xFF);
+
+ context->Length_Low += 8;
+ if (context->Length_Low == 0)
+ {
+ context->Length_High++;
+ if (context->Length_High == 0)
+ {
+ /* Message is too long */
+ context->Corrupted = 1;
+ }
+ }
+
+ if (context->Message_Block_Index == 64)
+ {
+ SHA1ProcessMessageBlock(context);
+ }
+
+ message_array++;
+ }
+
+ return shaSuccess;
+}
+
+/*
+ * SHA1ProcessMessageBlock
+ *
+ * Description:
+ * This function will process the next 512 bits of the message
+ * stored in the Message_Block array.
+ *
+ * Parameters:
+ * None.
+ *
+ * Returns:
+ * Nothing.
+ *
+ * Comments:
+
+ * Many of the variable names in this code, especially the
+ * single character names, were used because those were the
+ * names used in the publication.
+ *
+ *
+ */
+void SHA1ProcessMessageBlock(SHA1Context *context)
+{
+ const uint32_t K[] = { /* Constants defined in SHA-1 */
+ 0x5A827999,
+ 0x6ED9EBA1,
+ 0x8F1BBCDC,
+ 0xCA62C1D6
+ };
+ int t; /* Loop counter */
+ uint32_t temp; /* Temporary word value */
+ uint32_t W[80]; /* Word sequence */
+ uint32_t A, B, C, D, E; /* Word buffers */
+
+ /*
+ * Initialize the first 16 words in the array W
+ */
+ for(t = 0; t < 16; t++)
+ {
+ W[t] = context->Message_Block[t * 4] << 24;
+ W[t] |= context->Message_Block[t * 4 + 1] << 16;
+ W[t] |= context->Message_Block[t * 4 + 2] << 8;
+ W[t] |= context->Message_Block[t * 4 + 3];
+ }
+
+ for(t = 16; t < 80; t++)
+ {
+ W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+ }
+
+ A = context->Intermediate_Hash[0];
+ B = context->Intermediate_Hash[1];
+ C = context->Intermediate_Hash[2];
+ D = context->Intermediate_Hash[3];
+ E = context->Intermediate_Hash[4];
+
+ for(t = 0; t < 20; t++)
+ {
+ temp = SHA1CircularShift(5,A) +
+ ((B & C) | ((~B) & D)) + E + W[t] + K[0];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+
+ B = A;
+ A = temp;
+ }
+
+ for(t = 20; t < 40; t++)
+ {
+ temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ for(t = 40; t < 60; t++)
+ {
+ temp = SHA1CircularShift(5,A) +
+ ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ for(t = 60; t < 80; t++)
+ {
+ temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ context->Intermediate_Hash[0] += A;
+ context->Intermediate_Hash[1] += B;
+ context->Intermediate_Hash[2] += C;
+ context->Intermediate_Hash[3] += D;
+ context->Intermediate_Hash[4] += E;
+
+ context->Message_Block_Index = 0;
+}
+
+/*
+ * SHA1PadMessage
+ *
+
+ * Description:
+ * According to the standard, the message must be padded to an even
+ * 512 bits. The first padding bit must be a '1'. The last 64
+ * bits represent the length of the original message. All bits in
+ * between should be 0. This function will pad the message
+ * according to those rules by filling the Message_Block array
+ * accordingly. It will also call the ProcessMessageBlock function
+ * provided appropriately. When it returns, it can be assumed that
+ * the message digest has been computed.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to pad
+ * ProcessMessageBlock: [in]
+ * The appropriate SHA*ProcessMessageBlock function
+ * Returns:
+ * Nothing.
+ *
+ */
+
+void SHA1PadMessage(SHA1Context *context)
+{
+ /*
+ * Check to see if the current message block is too small to hold
+ * the initial padding bits and length. If so, we will pad the
+ * block, process it, and then continue padding into a second
+ * block.
+ */
+ if (context->Message_Block_Index > 55)
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0x80;
+ while(context->Message_Block_Index < 64)
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0;
+ }
+
+ SHA1ProcessMessageBlock(context);
+
+ while(context->Message_Block_Index < 56)
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0;
+ }
+ }
+ else
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0x80;
+ while(context->Message_Block_Index < 56)
+ {
+
+ context->Message_Block[context->Message_Block_Index++] = 0;
+ }
+ }
+
+ /*
+ * Store the message length as the last 8 octets
+ */
+ context->Message_Block[56] = (uint8_t) (context->Length_High >> 24);
+ context->Message_Block[57] = (uint8_t) (context->Length_High >> 16);
+ context->Message_Block[58] = (uint8_t) (context->Length_High >> 8);
+ context->Message_Block[59] = (uint8_t) (context->Length_High);
+ context->Message_Block[60] = (uint8_t) (context->Length_Low >> 24);
+ context->Message_Block[61] = (uint8_t) (context->Length_Low >> 16);
+ context->Message_Block[62] = (uint8_t) (context->Length_Low >> 8);
+ context->Message_Block[63] = (uint8_t) (context->Length_Low);
+
+ SHA1ProcessMessageBlock(context);
+} \ No newline at end of file
diff --git a/miranda-wine/protocols/MSN/sha1.h b/miranda-wine/protocols/MSN/sha1.h
new file mode 100644
index 0000000..553f542
--- /dev/null
+++ b/miranda-wine/protocols/MSN/sha1.h
@@ -0,0 +1,114 @@
+/*
+
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+*/
+
+/*
+ * sha1.h
+ *
+ * Description:
+ * This is the header file for code which implements the Secure
+ * Hashing Algorithm 1 as defined in FIPS PUB 180-1 published
+ * April 17, 1995.
+ *
+ * Many of the variable names in this code, especially the
+ * single character names, were used because those were the names
+ * used in the publication.
+ *
+ * Please read the file sha1.c for more information.
+ *
+ */
+
+#ifndef _SHA1_H_
+#define _SHA1_H_
+
+//#include <stdint.h>
+typedef unsigned __int32 uint32_t;
+typedef unsigned char uint8_t;
+typedef __int32 int_least16_t;
+/*
+ * If you do not have the ISO standard stdint.h header file, then you
+ * must typdef the following:
+ * name meaning
+ * uint32_t unsigned 32 bit integer
+ * uint8_t unsigned 8 bit integer (i.e., unsigned char)
+ * int_least16_t integer of >= 16 bits
+ *
+ */
+
+#ifndef _SHA_enum_
+#define _SHA_enum_
+enum
+{
+ shaSuccess = 0,
+ shaNull, /* Null pointer parameter */
+ shaInputTooLong, /* input data too long */
+ shaStateError /* called Input after Result */
+};
+#endif
+#define SHA1HashSize 20
+
+/*
+ * This structure will hold context information for the SHA-1
+ * hashing operation
+ */
+typedef struct SHA1Context
+{
+ uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */
+
+ uint32_t Length_Low; /* Message length in bits */
+ uint32_t Length_High; /* Message length in bits */
+
+ /* Index into message block array */
+ int_least16_t Message_Block_Index;
+ uint8_t Message_Block[64]; /* 512-bit message blocks */
+
+ int Computed; /* Is the digest computed? */
+ int Corrupted; /* Is the message digest corrupted? */
+} SHA1Context;
+
+/*
+ * Function Prototypes
+ */
+
+#if defined __cplusplus
+extern "C"
+{
+#endif
+
+ int SHA1Reset( SHA1Context *);
+ int SHA1Input( SHA1Context *,
+ const uint8_t *,
+ unsigned int);
+ int SHA1Result( SHA1Context *,
+ uint8_t Message_Digest[SHA1HashSize]);
+#if defined __cplusplus
+}
+#endif
+
+#endif
diff --git a/miranda-wine/protocols/MSN/version.h b/miranda-wine/protocols/MSN/version.h
new file mode 100644
index 0000000..def2e71
--- /dev/null
+++ b/miranda-wine/protocols/MSN/version.h
@@ -0,0 +1,3 @@
+#define __FILEVERSION_STRING 0,6,0,1
+#define __VERSION_STRING "0.6.0.1"
+#define __VERSION_DWORD 0x00060001
diff --git a/miranda-wine/protocols/MSN/version.rc b/miranda-wine/protocols/MSN/version.rc
new file mode 100644
index 0000000..61791aa
--- /dev/null
+++ b/miranda-wine/protocols/MSN/version.rc
@@ -0,0 +1,36 @@
+
+#include <windows.h>
+#include "version.h"
+
+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 "CompanyName", " "
+ VALUE "FileDescription", "Miranda MSN Messenger plugin"
+ VALUE "FileVersion", __VERSION_STRING
+ VALUE "InternalName", "msn"
+ VALUE "LegalCopyright", "Copyright c 2002-2005 George Hazan"
+ VALUE "OriginalFilename", "msn.dll"
+ VALUE "ProductName", "Miranda"
+ VALUE "ProductVersion", __VERSION_STRING
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0, 1200
+ END
+END
diff --git a/miranda-wine/protocols/Yahoo/Yahoo.rc b/miranda-wine/protocols/Yahoo/Yahoo.rc
new file mode 100644
index 0000000..4e4551d
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/Yahoo.rc
@@ -0,0 +1,124 @@
+/*
+ * $Id: Yahoo.rc 3465 2006-08-06 01:26:35Z gena01 $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+#include <winresrc.h>
+
+#include "resource.h"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_OPT_YAHOO DIALOGEX 0, 0, 296, 220
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ // Yahoo Login Information [Top Box]
+ GROUPBOX "Yahoo",IDC_STYAHOOGROUP,8,10,280,72,WS_GROUP
+ RTEXT "ID:",IDC_STATIC,16,20,52,8
+ EDITTEXT IDC_HANDLE,72,18,100,12,ES_AUTOHSCROLL
+ RTEXT "Password:",IDC_STATIC,16,36,52,8
+ EDITTEXT IDC_PASSWORD,72,34,100,12,ES_PASSWORD | ES_AUTOHSCROLL
+ RTEXT "Nick:",IDC_STATIC,16,52,52,8
+ EDITTEXT IDC_NICK,72,50,100,12,ES_AUTOHSCROLL
+ CONTROL "Create a new Yahoo account using the Yahoo website",
+ IDC_NEWYAHOOACCOUNTLINK,"Hyperlink",WS_TABSTOP,21,66,208,8
+
+ // Expert Section [Server/Port/etc]
+ GROUPBOX "Expert",IDC_STATIC,8,84,150,136, WS_GROUP
+
+ LTEXT "Login server:",IDC_STATIC,16,98,52,10
+ EDITTEXT IDC_LOGINSERVER,68,90,80,12,ES_AUTOHSCROLL
+ LTEXT "Port:",IDC_STATIC,16,112,25,10
+ EDITTEXT IDC_YAHOOPORT,68,110,29,12,ES_AUTOHSCROLL | ES_NUMBER
+ PUSHBUTTON "Reset",IDC_RESETSERVER,100,110,34,12
+
+ CONTROL "Yahoo Japan",IDC_YAHOO_JAPAN,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,16,128,140,10
+
+
+ CONTROL "Disable main menu (needs restart)",IDC_DISMAINMENU,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,16,148,140,10
+
+ CONTROL "Use Yahoo Address Book (YAB)",IDC_USE_YAB,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,16,158,140,10
+
+ CONTROL "Show Avatars",IDC_SHOW_AVATARS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,16,168,120,10
+
+ CONTROL "AutoLogin to Yahoo ",IDC_MAIL_AUTOLOGIN,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,16,178,120,10
+
+ CONTROL "Display Yahoo notifications", IDC_DISABLEYAHOOMAIL,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,16,188,120,10
+
+ CONTROL "Show Errors",IDC_SHOW_ERRORS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,16,198,120,10
+
+ GROUPBOX "Yahoo Ignore List",IDC_STIGNGROUP,158,84,130,136,WS_GROUP
+
+ EDITTEXT IDC_YIGN_EDIT,164,98,84,13,ES_AUTOHSCROLL
+ PUSHBUTTON "&Add",IDC_IGN_ADD,250,98,34,12
+
+ LISTBOX IDC_YIGN_LIST,164,114,84,103, LBS_NOTIFY | LBS_HASSTRINGS | LBS_SORT | WS_BORDER | WS_VSCROLL
+
+ PUSHBUTTON "&Remove", IDC_IGN_REMOVE, 250,204,34,12
+
+END
+
+IDD_SETCUSTSTAT DIALOGEX 0, 0, 187, 51
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Set Custom Status"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ EDITTEXT IDC_CUSTSTAT,5,5,177,12,ES_AUTOHSCROLL
+ CONTROL "Show as busy",
+ IDC_CUSTSTATBUSY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 5,21,120,10
+ DEFPUSHBUTTON "OK",IDOK,36,34,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,102,34,50,14
+END
+
+IDD_INFO_AVATAR DIALOGEX 0, 0, 222, 131
+STYLE DS_3DLOOK | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "",IDC_AVATAR,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ SS_SUNKEN,9,11,96,96
+ PUSHBUTTON "Set",IDC_SETAVATAR,9,112,45,13,WS_VISIBLE
+ PUSHBUTTON "Delete",IDC_DELETEAVATAR,61,112,45,13,WS_VISIBLE
+
+ CONTROL "Share Avatar",IDC_SHARE_AVATAR,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,16,130,120,10
+END
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_MAIN ICON "icos\\yahoo.ico"
+IDI_YAHOO ICON "icos\\yahoo.ico"
+IDI_INBOX ICON "icos\\inbox.ico"
+IDI_PROFILE ICON "icos\\profile.ico"
+IDI_REFRESH ICON "icos\\refresh.ico"
+IDI_YAB ICON "icos\\address_book.ico"
+IDI_SET_STATUS ICON "icos\\set_status.ico"
+IDI_CALENDAR ICON "icos\\calendar.ico"
+
+#include "version.rc"
+
diff --git a/miranda-wine/protocols/Yahoo/avatar.c b/miranda-wine/protocols/Yahoo/avatar.c
new file mode 100644
index 0000000..2fc4588
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/avatar.c
@@ -0,0 +1,1142 @@
+/*
+ * $Id: avatar.c 3676 2006-09-01 18:02:28Z gena01 $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+#include <time.h>
+#include <malloc.h>
+#include <sys/stat.h>
+#include <io.h>
+
+#include "yahoo.h"
+#include "resource.h"
+
+#include <m_langpack.h>
+#include <m_options.h>
+#include <m_userinfo.h>
+#include <m_png.h>
+
+#include "avatar.h"
+#include "file_transfer.h"
+
+static BOOL CALLBACK AvatarDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+extern yahoo_local_account *ylad;
+
+int OnDetailsInit(WPARAM wParam, LPARAM lParam)
+{
+ char* szProto;
+ OPTIONSDIALOGPAGE odp;
+ char szAvtCaption[MAX_PATH+8];
+
+ szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, lParam, 0);
+ if ((lstrcmp(szProto, yahooProtocolName)) && lParam)
+ return 0;
+
+ if ((lParam == 0) && YAHOO_GetByte( "ShowAvatars", 0 ))
+ {
+ // Avatar page only for valid contacts
+ odp.cbSize = sizeof(odp);
+ odp.hIcon = NULL;
+ odp.hInstance = hinstance;
+ odp.pfnDlgProc = AvatarDlgProc;
+ odp.position = -1899999997;
+ odp.pszTemplate = MAKEINTRESOURCE(IDD_INFO_AVATAR);
+ snprintf(szAvtCaption, sizeof(szAvtCaption), "%s %s", Translate(yahooProtocolName), Translate("Avatar"));
+ odp.pszTitle = szAvtCaption;
+
+ CallService(MS_USERINFO_ADDPAGE, wParam, (LPARAM)&odp);
+ }
+
+ return 0;
+}
+
+static char* ChooseAvatarFileName()
+{
+ char* szDest = (char*)malloc(MAX_PATH+0x10);
+ char str[MAX_PATH];
+ char szFilter[512];
+ OPENFILENAME ofn = {0};
+ str[0] = 0;
+ szDest[0]='\0';
+ CallService(MS_UTILS_GETBITMAPFILTERSTRINGS,sizeof(szFilter),(LPARAM)szFilter);
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.lpstrFilter = szFilter;
+ //ofn.lpstrFilter = "PNG Bitmaps (*.png)\0*.png\0";
+ ofn.lpstrFile = szDest;
+ ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
+ ofn.nMaxFile = MAX_PATH;
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.lpstrDefExt = "png";
+ if (!GetOpenFileName(&ofn)){
+ free(szDest);
+ return NULL;
+ }
+
+ return szDest;
+}
+
+/*
+ *31 bit hash function - this is based on g_string_hash function from glib
+ */
+int YAHOO_avt_hash(const char *key, long ksize)
+{
+ const char *p = key;
+ int h = *p;
+ long l = 0;
+
+ if (h)
+ for (p += 1; l < ksize; p++, l++)
+ h = (h << 5) - h + *p;
+
+ return h;
+}
+
+int calcMD5Hash(char* szFile)
+{
+ if (szFile) {
+ HANDLE hFile = NULL, hMap = NULL;
+ BYTE* ppMap = NULL;
+ long cbFileSize = 0;
+ int ck = 0;
+
+ if ((hFile = CreateFile(szFile, 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){
+ ck = YAHOO_avt_hash((char *)ppMap, cbFileSize);
+ }
+
+ if (ppMap != NULL) UnmapViewOfFile(ppMap);
+ if (hMap != NULL) CloseHandle(hMap);
+ if (hFile != NULL) CloseHandle(hFile);
+
+ if (ck) return ck;
+ }
+
+ return 0;
+}
+
+void upload_avt(int id, int fd, int error, void *data);
+
+/**************** Send Avatar ********************/
+
+HBITMAP YAHOO_SetAvatar(const char *szFile)
+{
+ char szMyFile[MAX_PATH+1];
+ HBITMAP avt;
+
+ avt = (HBITMAP)CallService(MS_UTILS_LOADBITMAP, 0, (WPARAM)szFile);
+
+ if (avt == NULL)
+ return NULL;
+
+ if (( avt = YAHOO_StretchBitmap( avt )) == NULL )
+ return NULL;
+
+ GetAvatarFileName(NULL, szMyFile, MAX_PATH, 2);
+
+ if (avt && YAHOO_SaveBitmapAsAvatar( avt, szMyFile) == 0) {
+ unsigned int hash;
+
+ hash = calcMD5Hash(szMyFile);
+ if (hash) {
+ LOG(("[YAHOO_SetAvatar] File: '%s' CK: %d", szMyFile, hash));
+
+ /* now check and make sure we don't reupload same thing over again */
+ if (hash != YAHOO_GetDword("AvatarHash", 0)) {
+ YAHOO_SetString(NULL, "AvatarFile", szMyFile);
+ DBWriteContactSettingDword(NULL, yahooProtocolName, "TMPAvatarHash", hash);
+
+ YAHOO_SendAvatar(szMyFile);
+ } else {
+ LOG(("[YAHOO_SetAvatar] Same checksum and avatar on YahooFT. Not Reuploading."));
+ }
+ }
+ }
+
+ return avt;
+}
+
+static BOOL CALLBACK AvatarDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ //MessageBox(NULL, "HALLO AVATARS!!", "AA", MB_OK);
+ TranslateDialogDefault(hwndDlg);
+ {
+ DBVARIANT dbv;
+ char szAvatar[MAX_PATH];
+
+ ShowWindow(GetDlgItem(hwndDlg, -1), SW_SHOW);
+ if (!yahooLoggedIn){
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SETAVATAR), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_DELETEAVATAR), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SHARE_AVATAR), FALSE);
+ }
+
+ SetButtonCheck( hwndDlg, IDC_SHARE_AVATAR, YAHOO_GetByte( "ShareAvatar", 0 ) == 2 );
+
+ if (!DBGetContactSetting(NULL, yahooProtocolName, "AvatarFile", &dbv)) {
+ HBITMAP avt;
+
+ lstrcpy(szAvatar, dbv.pszVal);
+ DBFreeVariant(&dbv);
+
+ avt = (HBITMAP)CallService(MS_UTILS_LOADBITMAP, 0, (WPARAM)szAvatar);
+ if (avt) {
+ avt = (HBITMAP)SendDlgItemMessage(hwndDlg, IDC_AVATAR, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)avt);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SHARE_AVATAR), TRUE);
+ if (avt) DeleteObject(avt); // we release old avatar if any
+ }
+ } else {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_DELETEAVATAR), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SHARE_AVATAR), FALSE);
+ }
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ switch(LOWORD(wParam))
+ {
+ case IDC_SETAVATAR:
+ {
+ char* szFile;
+ HBITMAP avt;
+
+ if ((szFile = ChooseAvatarFileName()) != NULL) {
+ avt = YAHOO_SetAvatar(szFile);
+
+ free(szFile);
+
+ if (avt){
+ avt = (HBITMAP)SendDlgItemMessage(hwndDlg, IDC_AVATAR, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)avt);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_DELETEAVATAR), TRUE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SHARE_AVATAR), TRUE);
+ }
+ if (avt) DeleteObject(avt); // we release old avatar if any
+ }
+
+ }
+ break;
+ case IDC_DELETEAVATAR:
+ {
+ HBITMAP avt;
+
+ YAHOO_DebugLog("[Deleting Avatar Info]");
+
+ avt = (HBITMAP)SendDlgItemMessage(hwndDlg, IDC_AVATAR, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)NULL);
+ if (avt) DeleteObject(avt); // we release old avatar if any
+
+ /* remove ALL our Avatar Info Keys */
+ DBDeleteContactSetting(NULL, yahooProtocolName, "AvatarFile");
+ DBDeleteContactSetting(NULL, yahooProtocolName, "AvatarHash");
+ DBDeleteContactSetting(NULL, yahooProtocolName, "AvatarURL");
+ DBDeleteContactSetting(NULL, yahooProtocolName, "AvatarTS");
+
+ /* Send a Yahoo packet saying we don't got an avatar anymore */
+ YAHOO_set_avatar(0);
+
+ /* clear the avatar window */
+ InvalidateRect( hwndDlg, NULL, TRUE );
+
+ YAHOO_SetByte("ShareAvatar",0);
+ SetButtonCheck(hwndDlg, IDC_SHARE_AVATAR, 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_DELETEAVATAR), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SHARE_AVATAR), FALSE);
+ }
+ break;
+ case IDC_SHARE_AVATAR:
+ YAHOO_SetByte("ShareAvatar",IsDlgButtonChecked(hwndDlg, IDC_SHARE_AVATAR) ? 2 : 0);
+ /* Send a Yahoo packet saying we don't got an avatar anymore */
+ YAHOO_set_avatar(YAHOO_GetByte( "ShareAvatar", 0 )? 2 : 0);
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+/*
+ * YAHOO_StretchBitmap (copied from MSN, Thanks George)
+ */
+HBITMAP YAHOO_StretchBitmap( HBITMAP hBitmap )
+{
+ BITMAPINFO bmStretch;
+ BITMAP bmp;
+ UINT* ptPixels;
+ HDC hDC, hBmpDC;
+ HBITMAP hOldBitmap1, hOldBitmap2, hStretchedBitmap;
+ int side, dx, dy;
+
+ ZeroMemory(&bmStretch, sizeof(bmStretch));
+ bmStretch.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmStretch.bmiHeader.biWidth = 96;
+ bmStretch.bmiHeader.biHeight = 96;
+ bmStretch.bmiHeader.biPlanes = 1;
+ bmStretch.bmiHeader.biBitCount = 32;
+
+ hStretchedBitmap = CreateDIBSection( NULL, &bmStretch, DIB_RGB_COLORS, ( void* )&ptPixels, NULL, 0);
+ if ( hStretchedBitmap == NULL ) {
+ YAHOO_DebugLog( "Bitmap creation failed with error %ld", GetLastError() );
+ return NULL;
+ }
+
+ hDC = CreateCompatibleDC( NULL );
+ hOldBitmap1 = ( HBITMAP )SelectObject( hDC, hBitmap );
+ GetObject( hBitmap, sizeof( BITMAP ), &bmp );
+
+ hBmpDC = CreateCompatibleDC( hDC );
+ hOldBitmap2 = ( HBITMAP )SelectObject( hBmpDC, hStretchedBitmap );
+
+ if ( bmp.bmWidth > bmp.bmHeight ) {
+ side = bmp.bmHeight;
+ dx = ( bmp.bmWidth - bmp.bmHeight )/2;
+ dy = 0;
+ }
+ else {
+ side = bmp.bmWidth;
+ dx = 0;
+ dy = ( bmp.bmHeight - bmp.bmWidth )/2;
+ }
+
+ SetStretchBltMode( hBmpDC, HALFTONE );
+ StretchBlt( hBmpDC, 0, 0, 96, 96, hDC, dx, dy, side, side, SRCCOPY );
+
+ SelectObject( hDC, hOldBitmap1 );
+ DeleteObject( hBitmap );
+ DeleteDC( hDC );
+
+ SelectObject( hBmpDC, hOldBitmap2 );
+ DeleteDC( hBmpDC );
+ return hStretchedBitmap;
+}
+
+/*
+ * YAHOO_SaveBitmapAsAvatar - updates the avatar database settings and file from a bitmap
+ */
+int YAHOO_SaveBitmapAsAvatar( HBITMAP hBitmap, const char* szFileName )
+{
+ BITMAPINFO* bmi;
+ HDC hdc;
+ HBITMAP hOldBitmap;
+ BITMAPINFOHEADER* pDib;
+ BYTE* pDibBits;
+ long dwPngSize = 0;
+ DIB2PNG convertor;
+
+ if ( !ServiceExists(MS_DIB2PNG)) {
+ MessageBox( NULL, Translate( "Your png2dib.dll is either obsolete or damaged. " ),
+ Translate( "Error" ), MB_OK | MB_ICONSTOP );
+ return 1;
+ }
+
+ hdc = CreateCompatibleDC( NULL );
+ hOldBitmap = ( HBITMAP )SelectObject( hdc, hBitmap );
+
+ bmi = ( BITMAPINFO* )_alloca( sizeof( BITMAPINFO ) + sizeof( RGBQUAD )*256 );
+ memset( bmi, 0, sizeof (BITMAPINFO ));
+ bmi->bmiHeader.biSize = 0x28;
+ if ( GetDIBits( hdc, hBitmap, 0, 96, NULL, bmi, DIB_RGB_COLORS ) == 0 ) {
+ return 2;
+ }
+
+ pDib = ( BITMAPINFOHEADER* )GlobalAlloc( LPTR, sizeof( BITMAPINFO ) + sizeof( RGBQUAD )*256 + bmi->bmiHeader.biSizeImage );
+ if ( pDib == NULL )
+ return 3;
+
+ memcpy( pDib, bmi, sizeof( BITMAPINFO ) + sizeof( RGBQUAD )*256 );
+ pDibBits = (( BYTE* )pDib ) + sizeof( BITMAPINFO ) + sizeof( RGBQUAD )*256;
+
+ GetDIBits( hdc, hBitmap, 0, pDib->biHeight, pDibBits, ( BITMAPINFO* )pDib, DIB_RGB_COLORS );
+ SelectObject( hdc, hOldBitmap );
+ DeleteDC( hdc );
+
+ convertor.pbmi = ( BITMAPINFO* )pDib;
+ convertor.pDiData = pDibBits;
+ convertor.pResult = NULL;
+ convertor.pResultLen = &dwPngSize;
+ if ( !CallService( MS_DIB2PNG, 0, (LPARAM)&convertor )) {
+ GlobalFree( pDib );
+ return 2;
+ }
+
+ convertor.pResult = (char *)malloc(dwPngSize);
+ CallService( MS_DIB2PNG, 0, (LPARAM)&convertor );
+
+ GlobalFree( pDib );
+ {
+ FILE* out;
+
+ out = fopen( szFileName, "wb" );
+ if ( out != NULL ) {
+ fwrite( convertor.pResult, dwPngSize, 1, out );
+ fclose( out );
+ }
+ }
+ free(convertor.pResult);
+
+ return ERROR_SUCCESS;
+}
+
+void upload_avt(int id, int fd, int error, void *data)
+{
+ y_filetransfer *sf = (y_filetransfer*) data;
+ long size = 0;
+ char buf[1024];
+ int rw; /* */
+ DWORD dw; /* needed for ReadFile */
+ HANDLE myhFile;
+
+ if (fd < 1 || error) {
+ LOG(("[get_fd] Connect Failed!"));
+ return;
+ }
+
+ myhFile = CreateFile(sf->filename,
+ GENERIC_READ,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
+ 0);
+
+ if (myhFile == INVALID_HANDLE_VALUE) {
+ LOG(("[get_fd] Can't open file for reading?!"));
+ return;
+ }
+
+ LOG(("Sending file: %s size: %ld", sf->filename, sf->fsize));
+
+ do {
+ rw = ReadFile(myhFile, buf, sizeof(buf), &dw, NULL);
+
+ if (rw != 0) {
+ rw = Netlib_Send((HANDLE)fd, buf, dw, MSG_NODUMP);
+
+ if (rw < 1) {
+ LOG(("Upload Failed. Send error?"));
+ break;
+ }
+
+ size += rw;
+ }
+ } while (rw >= 0 && size < sf->fsize);
+
+ CloseHandle(myhFile);
+
+ do {
+ rw = Netlib_Recv((HANDLE)fd, buf, sizeof(buf), 0);
+ LOG(("Got: %d bytes", rw));
+ } while (rw > 0);
+
+ LOG(("File send complete!"));
+}
+
+void __cdecl yahoo_send_avt_thread(void *psf)
+{
+ y_filetransfer *sf = psf;
+
+ if (sf == NULL) {
+ YAHOO_DebugLog("[yahoo_send_avt_thread] SF IS NULL!!!");
+ return;
+ }
+
+ YAHOO_SetByte("AvatarUL", 1);
+ yahoo_send_avatar(ylad->id, sf->filename, sf->fsize, &upload_avt, sf);
+
+ free(sf->filename);
+ free(sf);
+ if (YAHOO_GetByte("AvatarUL", 1) == 1) YAHOO_SetByte("AvatarUL", 0);
+}
+
+void YAHOO_SendAvatar(const char *szFile)
+{
+ y_filetransfer *sf;
+ struct _stat statbuf;
+
+ if ( _stat( szFile, &statbuf ) != 0 ) {
+ LOG(("[YAHOO_SendAvatar] Error reading File information?!"));
+ return;
+ }
+
+ sf = (y_filetransfer*) malloc(sizeof(y_filetransfer));
+ sf->filename = strdup(szFile);
+ sf->cancel = 0;
+ sf->fsize = statbuf.st_size;
+
+ YAHOO_DebugLog("[Uploading avatar] filename: %s size: %ld", sf->filename, sf->fsize);
+
+ pthread_create(yahoo_send_avt_thread, sf);
+}
+
+struct avatar_info{
+ char *who;
+ char *pic_url;
+ int cksum;
+};
+
+static void __cdecl yahoo_recv_avatarthread(void *pavt)
+{
+ PROTO_AVATAR_INFORMATION AI;
+ struct avatar_info *avt = pavt;
+ int error = 0;
+ HANDLE hContact = 0;
+ char buf[4096];
+
+ if (avt == NULL) {
+ YAHOO_DebugLog("AVT IS NULL!!!");
+ return;
+ }
+
+ if (!yahooLoggedIn) {
+ YAHOO_DebugLog("We are not logged in!!!");
+ return;
+ }
+
+// ProtoBroadcastAck(yahooProtocolName, hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE) 1, 0);
+
+ LOG(("yahoo_recv_avatarthread who:%s url:%s checksum: %d", avt->who, avt->pic_url, avt->cksum));
+
+ hContact = getbuddyH(avt->who);
+
+ if (!hContact){
+ LOG(("ERROR: Can't find buddy: %s", avt->who));
+ error = 1;
+ } else if (!error) {
+ DBWriteContactSettingDword(hContact, yahooProtocolName, "PictCK", avt->cksum);
+ DBWriteContactSettingDword(hContact, yahooProtocolName, "PictLoading", 1);
+ }
+
+ if(!error) {
+
+ NETLIBHTTPREQUEST nlhr={0},*nlhrReply;
+
+ nlhr.cbSize = sizeof(nlhr);
+ nlhr.requestType= REQUEST_GET;
+ nlhr.flags = NLHRF_NODUMP|NLHRF_GENERATEHOST|NLHRF_SMARTAUTHHEADER;
+ nlhr.szUrl = avt->pic_url;
+
+ nlhrReply=(NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION,(WPARAM)hNetlibUser,(LPARAM)&nlhr);
+
+ if(nlhrReply) {
+
+ if (nlhrReply->resultCode != 200) {
+ LOG(("Update server returned '%d' instead of 200. It also sent the following: %s", nlhrReply->resultCode, nlhrReply->szResultDescr));
+ // make sure it's a real problem and not a problem w/ our connection
+ yahoo_send_picture_info(ylad->id, avt->who, 3, avt->pic_url, avt->cksum);
+ error = 1;
+ } else if (nlhrReply->dataLength < 1 || nlhrReply->pData == NULL) {
+ LOG(("No data??? Got %d bytes.", nlhrReply->dataLength));
+ error = 1;
+ } else {
+ HANDLE myhFile;
+
+ GetAvatarFileName(hContact, buf, 1024, DBGetContactSettingByte(hContact, yahooProtocolName,"AvatarType", 0));
+ DeleteFile(buf);
+
+ LOG(("Saving file: %s size: %u", buf, nlhrReply->dataLength));
+ myhFile = CreateFile(buf,
+ GENERIC_WRITE,
+ FILE_SHARE_WRITE,
+ NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+
+ if(myhFile !=INVALID_HANDLE_VALUE) {
+ DWORD c;
+
+ WriteFile(myhFile, nlhrReply->pData, nlhrReply->dataLength, &c, NULL );
+ CloseHandle(myhFile);
+
+ DBWriteContactSettingString(hContact, "ContactPhoto", "File", buf);
+ DBWriteContactSettingDword(hContact, yahooProtocolName, "PictLastCheck", 0);
+ } else {
+ LOG(("Can not open file for writing: %s", buf));
+ error = 1;
+ }
+ }
+ CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT,0,(LPARAM)nlhrReply);
+ }
+ }
+
+ if (DBGetContactSettingDword(hContact, yahooProtocolName, "PictCK", 0) != avt->cksum) {
+ LOG(("WARNING: Checksum updated during download?!"));
+ error = 1; /* don't use this one? */
+ }
+
+ DBWriteContactSettingDword(hContact, yahooProtocolName, "PictLoading", 0);
+ LOG(("File download complete!?"));
+
+ if (error)
+ buf[0]='\0';
+
+ free(avt->who);
+ free(avt->pic_url);
+ free(avt);
+
+ AI.cbSize = sizeof AI;
+ AI.format = PA_FORMAT_PNG;
+ AI.hContact = hContact;
+ lstrcpy(AI.filename,buf);
+
+ if (error)
+ DBWriteContactSettingDword(hContact, yahooProtocolName, "PictCK", 0);
+
+ ProtoBroadcastAck(yahooProtocolName, hContact, ACKTYPE_AVATAR, !error ? ACKRESULT_SUCCESS:ACKRESULT_FAILED,(HANDLE) &AI, 0);
+
+}
+
+void YAHOO_get_avatar(const char *who, const char *pic_url, long cksum)
+{
+ struct avatar_info *avt;
+
+ avt = malloc(sizeof(struct avatar_info));
+ avt->who = _strdup(who);
+ avt->pic_url = _strdup(pic_url);
+ avt->cksum = cksum;
+
+ pthread_create(yahoo_recv_avatarthread, (void *) avt);
+}
+
+void ext_yahoo_got_picture(int id, const char *me, const char *who, const char *pic_url, int cksum, int type)
+{
+ HANDLE hContact = 0;
+
+ LOG(("[ext_yahoo_got_picture] for %s with url %s (checksum: %d) type: %d", who, pic_url, cksum, type));
+
+
+ /*
+ Type:
+
+ 1 - Send Avatar Info
+ 2 - Got Avatar Info
+ 3 - YIM6 didn't like my avatar? Expired? We need to invalidate and re-load
+ */
+ switch (type) {
+ case 1:
+ {
+ int cksum=0;
+ DBVARIANT dbv;
+
+ /* need to send avatar info */
+ if (!YAHOO_GetByte( "ShowAvatars", 0 )) {
+ LOG(("[ext_yahoo_got_picture] We are not using/showing avatars!"));
+ yahoo_send_picture_update(id, who, 0); // no avatar (disabled)
+ return;
+ }
+
+ LOG(("[ext_yahoo_got_picture] Getting ready to send info!"));
+ /* need to read CheckSum */
+ cksum = YAHOO_GetDword("AvatarHash", 0);
+ if (cksum) {
+ if (!DBGetContactSetting(NULL, yahooProtocolName, "AvatarURL", &dbv)) {
+ LOG(("[ext_yahoo_got_picture] Sending url: %s checksum: %d to '%s'!", dbv.pszVal, cksum, who));
+ //void yahoo_send_picture_info(int id, const char *me, const char *who, const char *pic_url, int cksum)
+ yahoo_send_picture_info(id, who, 2, dbv.pszVal, cksum);
+ DBFreeVariant(&dbv);
+ } else if (YAHOO_GetByte("AvatarUL", 0) != 1){
+ // NO avatar URL??
+ if (!DBGetContactSetting(NULL, yahooProtocolName, "AvatarFile", &dbv)) {
+ DBWriteContactSettingString(NULL, yahooProtocolName, "AvatarInv", who);
+ YAHOO_SendAvatar(dbv.pszVal);
+ DBFreeVariant(&dbv);
+ } else {
+ LOG(("[ext_yahoo_got_picture] No Local Avatar File??? "));
+ }
+ } else
+ LOG(("[ext_yahoo_got_picture] Another avatar upload in progress?"));
+ }
+ }
+ break;
+ case 2: /*
+ * We got Avatar Info for our buddy.
+ */
+ if (!YAHOO_GetByte( "ShowAvatars", 0 )) {
+ LOG(("[ext_yahoo_got_picture] We are not using/showing avatars!"));
+ return;
+ }
+
+ /* got avatar info, so set miranda up */
+ hContact = getbuddyH(who);
+
+ if (!hContact) {
+ LOG(("[ext_yahoo_got_picture] Buddy not on my buddy list?."));
+ return;
+ }
+
+ if (!cksum || cksum == -1) {
+ LOG(("[ext_yahoo_got_picture] Resetting avatar."));
+ DBWriteContactSettingDword(hContact, yahooProtocolName, "PictCK", 0);
+
+ yahoo_reset_avatar(hContact);
+ } else {
+ char z[1024];
+
+ if (pic_url == NULL) {
+ LOG(("[ext_yahoo_got_picture] WARNING: Empty URL for avatar?"));
+ return;
+ }
+
+ GetAvatarFileName(hContact, z, 1024, DBGetContactSettingByte(hContact, yahooProtocolName,"AvatarType", 0));
+
+ if (DBGetContactSettingDword(hContact, yahooProtocolName,"PictCK", 0) != cksum || _access( z, 0 ) != 0 ) {
+
+ YAHOO_DebugLog("[ext_yahoo_got_picture] Checksums don't match or avatar file is missing. Current: %d, New: %d",(int)DBGetContactSettingDword(hContact, yahooProtocolName,"PictCK", 0), cksum);
+
+ YAHOO_get_avatar(who, pic_url, cksum);
+ }
+ }
+
+ break;
+ case 3:
+ /*
+ * Our Avatar is not good anymore? Need to re-upload??
+ */
+ /* who, pic_url, cksum */
+ {
+ int mcksum=0;
+ DBVARIANT dbv;
+
+ /* need to send avatar info */
+ if (!YAHOO_GetByte( "ShowAvatars", 0 )) {
+ LOG(("[ext_yahoo_got_picture] We are not using/showing avatars!"));
+ yahoo_send_picture_update(id, who, 0); // no avatar (disabled)
+ return;
+ }
+
+ LOG(("[ext_yahoo_got_picture] Getting ready to send info!"));
+ /* need to read CheckSum */
+ mcksum = YAHOO_GetDword("AvatarHash", 0);
+ if (mcksum == 0) {
+ /* this should NEVER Happen??? */
+ LOG(("[ext_yahoo_got_picture] No personal checksum? and Invalidate?!"));
+ yahoo_send_picture_update(id, who, 0); // no avatar (disabled)
+ return;
+ }
+
+ LOG(("[ext_yahoo_got_picture] My Checksum: %d", mcksum));
+
+ if (!DBGetContactSetting(NULL, yahooProtocolName, "AvatarURL", &dbv)){
+ if (mcksum == cksum && lstrcmpi(pic_url, dbv.pszVal) == 0) {
+ DBVARIANT dbv2;
+
+ LOG(("[ext_yahoo_got_picture] Buddy: %s told us this is bad??Expired??. Re-uploading", who));
+ DBDeleteContactSetting(NULL, yahooProtocolName, "AvatarURL");
+
+
+ if (!DBGetContactSetting(NULL, yahooProtocolName, "AvatarFile", &dbv2)) {
+ DBWriteContactSettingString(NULL, yahooProtocolName, "AvatarInv", who);
+ YAHOO_SendAvatar(dbv2.pszVal);
+ DBFreeVariant(&dbv2);
+ } else {
+ LOG(("[ext_yahoo_got_picture] No Local Avatar File??? "));
+ }
+ } else {
+ LOG(("[ext_yahoo_got_picture] URLs or checksums don't match? Tell them the right thing!!!"));
+ yahoo_send_picture_info(id, who, 2, dbv.pszVal, mcksum);
+ }
+ // don't leak stuff
+ DBFreeVariant(&dbv);
+ } else {
+ LOG(("[ext_yahoo_got_picture] no AvatarURL?"));
+ }
+ }
+ break;
+ default:
+ LOG(("[ext_yahoo_got_picture] Unknown request/packet type exiting!"));
+ }
+
+ LOG(("ext_yahoo_got_picture exiting"));
+}
+
+void ext_yahoo_got_picture_checksum(int id, const char *me, const char *who, int cksum)
+{
+ HANDLE hContact = 0;
+
+ LOG(("ext_yahoo_got_picture_checksum for %s checksum: %d", who, cksum));
+
+ hContact = getbuddyH(who);
+ if (hContact == NULL) {
+ LOG(("Buddy Not Found. Skipping avatar update"));
+ return;
+ }
+
+ /* Last thing check the checksum and request new one if we need to */
+ if (!cksum || cksum == -1) {
+ DBWriteContactSettingDword(hContact, yahooProtocolName, "PictCK", 0);
+
+ yahoo_reset_avatar(hContact);
+ } else {
+ if (DBGetContactSettingDword(hContact, yahooProtocolName,"PictCK", 0) != cksum) {
+ char szFile[MAX_PATH];
+
+ // Now save the new checksum. No rush requesting new avatar yet.
+ DBWriteContactSettingDword(hContact, yahooProtocolName, "PictCK", cksum);
+
+ // Need to delete the Avatar File!!
+ GetAvatarFileName(hContact, szFile, sizeof szFile, 0);
+ DeleteFile(szFile);
+
+ // Reset the avatar and cleanup.
+ yahoo_reset_avatar(hContact);
+ }
+ }
+
+}
+
+void ext_yahoo_got_picture_update(int id, const char *me, const char *who, int buddy_icon)
+{
+ HANDLE hContact = 0;
+
+ LOG(("ext_yahoo_got_picture_update for %s buddy_icon: %d", who, buddy_icon));
+
+ hContact = getbuddyH(who);
+ if (hContact == NULL) {
+ LOG(("Buddy Not Found. Skipping avatar update"));
+ return;
+ }
+
+ DBWriteContactSettingByte(hContact, yahooProtocolName, "AvatarType", buddy_icon);
+
+ /* Last thing check the checksum and request new one if we need to */
+ yahoo_reset_avatar(hContact);
+}
+
+void ext_yahoo_got_avatar_update(int id, const char *me, const char *who, int buddy_icon)
+{
+ HANDLE hContact = 0;
+
+ LOG(("ext_yahoo_got_avatar_update for %s buddy_icon: %d", who, buddy_icon));
+
+ hContact = getbuddyH(who);
+ if (hContact == NULL) {
+ LOG(("Buddy Not Found. Skipping avatar update"));
+ return;
+ }
+
+ DBWriteContactSettingByte(hContact, yahooProtocolName, "AvatarType", buddy_icon);
+
+ /* Last thing check the checksum and request new one if we need to */
+ yahoo_reset_avatar(hContact);
+}
+
+void yahoo_reset_avatar(HANDLE hContact)
+{
+ LOG(("[YAHOO_RESET_AVATAR]"));
+
+ // STUPID SCRIVER Doesn't listen to ACKTYPE_AVATAR. so remove the file reference!
+ //DBDeleteContactSetting(hContact, "ContactPhoto", "File");
+
+ ProtoBroadcastAck(yahooProtocolName, hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, 0);
+}
+
+void YAHOO_request_avatar(const char* who)
+{
+ time_t last_chk, cur_time;
+ HANDLE hContact = 0;
+ char szFile[MAX_PATH];
+
+ if (!YAHOO_GetByte( "ShowAvatars", 0 )) {
+ LOG(("Avatars disabled, but available for: %s", who));
+ return;
+ }
+
+ hContact = getbuddyH(who);
+
+ if (!hContact)
+ return;
+
+
+ GetAvatarFileName(hContact, szFile, sizeof szFile, DBGetContactSettingByte(hContact, yahooProtocolName,"AvatarType", 0));
+ DeleteFile(szFile);
+
+ time(&cur_time);
+ last_chk = DBGetContactSettingDword(hContact, yahooProtocolName, "PictLastCheck", 0);
+
+ /*
+ * time() - in seconds ( 60*60 = 1 hour)
+ */
+ if (DBGetContactSettingDword(hContact, yahooProtocolName,"PictCK", 0) == 0 ||
+ last_chk == 0 || (cur_time - last_chk) > 60) {
+
+ DBWriteContactSettingDword(hContact, yahooProtocolName, "PictLastCheck", cur_time);
+
+ LOG(("Requesting Avatar for: %s", who));
+ yahoo_request_buddy_avatar(ylad->id, who);
+ } else {
+ LOG(("Avatar Not Available for: %s Last Check: %ld Current: %ld (Flood Check in Effect)", who, last_chk, cur_time));
+ }
+}
+
+void YAHOO_bcast_picture_update(int buddy_icon)
+{
+ HANDLE hContact;
+ char *szProto;
+
+ /* need to get online buddies and then send then picture_update packets (ARGH YAHOO!)*/
+ for ( hContact = ( HANDLE )YAHOO_CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ hContact != NULL;
+ hContact = ( HANDLE )YAHOO_CallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM )hContact, 0 ))
+ {
+ szProto = ( char* )YAHOO_CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact, 0 );
+ if ( szProto != NULL && !lstrcmp( szProto, yahooProtocolName ))
+ {
+ if (YAHOO_GetWord(hContact, "Status", ID_STATUS_OFFLINE)!=ID_STATUS_OFFLINE) {
+ DBVARIANT dbv;
+
+ if ( DBGetContactSetting( hContact, yahooProtocolName, YAHOO_LOGINID, &dbv ))
+ continue;
+
+ yahoo_send_picture_update(ylad->id, dbv.pszVal, buddy_icon);
+ DBFreeVariant( &dbv );
+ }
+ }
+ }
+}
+
+void YAHOO_set_avatar(int buddy_icon)
+{
+ yahoo_send_avatar_update(ylad->id,buddy_icon);
+
+ YAHOO_bcast_picture_update(buddy_icon);
+}
+
+void YAHOO_bcast_picture_checksum(int cksum)
+{
+ HANDLE hContact;
+ char *szProto;
+
+ yahoo_send_picture_checksum(ylad->id, NULL, cksum);
+
+ /* need to get online buddies and then send then picture_update packets (ARGH YAHOO!)*/
+ for ( hContact = ( HANDLE )YAHOO_CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ hContact != NULL;
+ hContact = ( HANDLE )YAHOO_CallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM )hContact, 0 ))
+ {
+ szProto = ( char* )YAHOO_CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact, 0 );
+ if ( szProto != NULL && !lstrcmp( szProto, yahooProtocolName ))
+ {
+ if (YAHOO_GetWord(hContact, "Status", ID_STATUS_OFFLINE)!=ID_STATUS_OFFLINE) {
+ DBVARIANT dbv;
+
+ if ( DBGetContactSetting( hContact, yahooProtocolName, YAHOO_LOGINID, &dbv ))
+ continue;
+
+ yahoo_send_picture_checksum(ylad->id, dbv.pszVal, cksum);
+ DBFreeVariant( &dbv );
+ }
+ }
+ }
+}
+
+void GetAvatarFileName(HANDLE hContact, char* pszDest, int cbLen, int type)
+{
+ int tPathLen;
+ DBVARIANT dbv;
+
+ CallService(MS_DB_GETPROFILEPATH, cbLen, (LPARAM)pszDest);
+
+ tPathLen = lstrlen(pszDest);
+ _snprintf(pszDest + tPathLen, MAX_PATH-tPathLen, "\\%s\\", yahooProtocolName);
+ CreateDirectory(pszDest, NULL);
+
+ if (hContact != NULL && !DBGetContactSetting(hContact, yahooProtocolName, YAHOO_LOGINID, &dbv)) {
+ lstrcat(pszDest, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }else {
+ lstrcat(pszDest, "avatar");
+ }
+
+ if (type == 1) {
+ lstrcat(pszDest, ".swf" );
+ } else
+ lstrcat(pszDest, ".png" );
+
+}
+
+int YahooGetAvatarInfo(WPARAM wParam,LPARAM lParam)
+{
+ PROTO_AVATAR_INFORMATION* AI = ( PROTO_AVATAR_INFORMATION* )lParam;
+
+ DBVARIANT dbv;
+ int avtType;
+
+ if (!DBGetContactSetting(AI->hContact, yahooProtocolName, YAHOO_LOGINID, &dbv)) {
+ YAHOO_DebugLog("[YAHOO_GETAVATARINFO] For: %s", dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }else {
+ YAHOO_DebugLog("[YAHOO_GETAVATARINFO]");
+ }
+
+ if (!YAHOO_GetByte( "ShowAvatars", 0 ) || !yahooLoggedIn) {
+ YAHOO_DebugLog("[YAHOO_GETAVATARINFO] %s", yahooLoggedIn ? "We are not using/showing avatars!" : "We are not logged in. Can't load avatars now!");
+
+ /*if (DBGetContactSettingDword(AI->hContact, yahooProtocolName,"PictCK", 0) != 0) {
+ YAHOO_DebugLog("[YAHOO_GETAVATARINFO] Removing avatar information!");
+
+ DBWriteContactSettingDword(AI->hContact, yahooProtocolName, "PictCK", 0);
+ DBWriteContactSettingDword(AI->hContact, yahooProtocolName, "PictLastCheck", 0);
+ DBWriteContactSettingDword(AI->hContact, yahooProtocolName, "PictLoading", 0);
+ //GetAvatarFileName(AI->hContact, AI->filename, sizeof AI->filename);
+ //DeleteFile(AI->filename);
+ }*/
+
+ return GAIR_NOAVATAR;
+ }
+
+ avtType = DBGetContactSettingByte(AI->hContact, yahooProtocolName,"AvatarType", 0);
+ YAHOO_DebugLog("[YAHOO_GETAVATARINFO] Avatar Type: %d", avtType);
+
+ if ( avtType != 2) {
+ if (avtType != 0)
+ YAHOO_DebugLog("[YAHOO_GETAVATARINFO] Not handling this type yet!");
+
+ return GAIR_NOAVATAR;
+ }
+
+ if (DBGetContactSettingDword(AI->hContact, yahooProtocolName,"PictCK", 0) != 0) {
+
+ GetAvatarFileName(AI->hContact, AI->filename, sizeof AI->filename,DBGetContactSettingByte(AI->hContact, yahooProtocolName,"AvatarType", 0));
+ //if ( access( AI->filename, 0 ) == 0 ) {
+ AI->format = PA_FORMAT_PNG;
+ YAHOO_DebugLog("[YAHOO_GETAVATARINFO] filename: %s", AI->filename);
+
+ if (_access( AI->filename, 0 ) == 0 ) {
+ return GAIR_SUCCESS;
+ } else {
+ /* need to request it again? */
+ if (YAHOO_GetWord(AI->hContact, "PictLoading", 0) != 0 &&
+ (time(NULL) - YAHOO_GetWord(AI->hContact, "PictLastCK", 0) < 500)) {
+ YAHOO_DebugLog("[YAHOO_GETAVATARINFO] Waiting for avatar to load!");
+ return GAIR_WAITFOR;
+ } else if ( yahooLoggedIn ) {
+ DBVARIANT dbv;
+
+ if (!DBGetContactSetting(AI->hContact, yahooProtocolName, YAHOO_LOGINID, &dbv)) {
+ YAHOO_DebugLog("[YAHOO_GETAVATARINFO] Requesting avatar!");
+
+ YAHOO_request_avatar(dbv.pszVal/*who */);
+ DBFreeVariant(&dbv);
+ return GAIR_WAITFOR;
+ } else {
+ YAHOO_DebugLog("[YAHOO_GETAVATARINFO] Can't retrieve user id?!");
+ }
+ }
+ }
+ }
+
+ YAHOO_DebugLog("[YAHOO_GETAVATARINFO] NO AVATAR???");
+ return GAIR_NOAVATAR;
+}
+
+/*
+ * --=[ AVS / LoadAvatars API/Services ]=--
+ */
+
+/*
+Optional. Will pass PNG or BMP if this is not found
+wParam = 0
+lParam = PA_FORMAT_* // avatar format
+return = 1 (supported) or 0 (not supported)
+*/
+int YahooAvatarFormatSupported(WPARAM wParam, LPARAM lParam)
+{
+ YAHOO_DebugLog("[YahooAvatarFormatSupported]");
+
+ if (lParam == PA_FORMAT_PNG)
+ return 1;
+ else
+ return 0;
+}
+
+/*
+Service: /GetMyAvatarMaxSize
+wParam=(int *)max width of avatar
+lParam=(int *)max height of avatar
+return=0
+*/
+int YahooGetAvatarSize(WPARAM wParam, LPARAM lParam)
+{
+ YAHOO_DebugLog("[YahooGetAvatarSize]");
+
+ if (wParam != 0) *((int*) wParam) = 96;
+ if (lParam != 0) *((int*) lParam) = 96;
+
+ return 0;
+}
+
+/*
+Service: /GetMyAvatar
+wParam=(char *)Buffer to file name
+lParam=(int)Buffer size
+return=0 on success, else on error
+*/
+int YahooGetMyAvatar(WPARAM wParam, LPARAM lParam)
+{
+ char *buffer = (char *)wParam;
+ int size = (int)lParam;
+
+ YAHOO_DebugLog("[YahooGetMyAvatar]");
+
+ if (buffer == NULL || size <= 0)
+ return -1;
+
+
+ if (!YAHOO_GetByte( "ShowAvatars", 0 ))
+ return -2;
+
+ {
+ DBVARIANT dbv;
+ int ret = -3;
+
+ if (YAHOO_GetDword("AvatarHash", 0)){
+
+ if (!DBGetContactSetting(NULL, yahooProtocolName, "AvatarFile", &dbv)){
+ if (access(dbv.pszVal, 0) == 0){
+ strncpy(buffer, dbv.pszVal, size-1);
+ buffer[size-1] = '\0';
+
+ ret = 0;
+ }
+ DBFreeVariant(&dbv);
+ }
+ }
+
+ return ret;
+ }
+}
+
+/*
+#define PS_SETMYAVATAR "/SetMyAvatar"
+wParam=0
+lParam=(const char *)Avatar file name
+return=0 for sucess
+*/
+
+int YahooSetMyAvatar(WPARAM wParam, LPARAM lParam)
+{
+ char *szFile = (char *)lParam;
+ HANDLE avt;
+
+ YAHOO_DebugLog("[YahooSetMyAvatar]");
+
+ avt = YAHOO_SetAvatar(szFile);
+ if (avt) {
+ DeleteObject(avt); // we release old avatar if any
+ return 0;
+ } else
+ return 1; /* error for now */
+}
+
+/*
+ * --=[ ]=--
+ */
diff --git a/miranda-wine/protocols/Yahoo/avatar.h b/miranda-wine/protocols/Yahoo/avatar.h
new file mode 100644
index 0000000..04a3ab4
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/avatar.h
@@ -0,0 +1,66 @@
+/*
+ * $Id: avatar.h 3646 2006-08-29 20:38:45Z gena01 $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+#ifndef _YAHOO_AVATAR_H_
+#define _YAHOO_AVATAR_H_
+
+void YAHOO_request_avatar(const char* who);
+void GetAvatarFileName(HANDLE hContact, char* pszDest, int cbLen, int type);
+
+void YAHOO_SendAvatar(const char *szFile);
+
+void YAHOO_set_avatar(int buddy_icon);
+
+void YAHOO_bcast_picture_update(int buddy_icon);
+
+void YAHOO_bcast_picture_checksum(int cksum);
+
+int YAHOO_SaveBitmapAsAvatar( HBITMAP hBitmap, const char* szFileName );
+
+HBITMAP YAHOO_StretchBitmap( HBITMAP hBitmap );
+
+void yahoo_reset_avatar(HANDLE hContact);
+
+HBITMAP YAHOO_SetAvatar(const char *szFile);
+
+void YAHOO_get_avatar(const char *who, const char *pic_url, long cksum);
+
+/**
+ * AVS Services - loadavatars.dll uses these to get the info from us
+ */
+#define PS_ISAVATARFORMATSUPPORTED "/IsAvatarFormatSupported"
+#define PS_GETMYAVATARMAXSIZE "/GetMyAvatarMaxSize"
+#define PS_SETMYAVATAR "/SetMyAvatar"
+#define PS_GETMYAVATAR "/GetMyAvatar"
+
+int YahooGetAvatarInfo(WPARAM wParam,LPARAM lParam);
+
+int YahooAvatarFormatSupported(WPARAM wParam, LPARAM lParam);
+
+int YahooGetAvatarSize(WPARAM wParam, LPARAM lParam);
+
+int YahooGetMyAvatar(WPARAM wParam, LPARAM lParam);
+
+int YahooSetMyAvatar(WPARAM wParam, LPARAM lParam);
+
+/**
+ * Callbacks for libyahoo2
+ */
+void ext_yahoo_got_picture(int id, const char *me, const char *who, const char *pic_url, int cksum, int type);
+
+void ext_yahoo_got_picture_checksum(int id, const char *me, const char *who, int cksum);
+
+void ext_yahoo_got_picture_update(int id, const char *me, const char *who, int buddy_icon);
+
+void ext_yahoo_got_avatar_update(int id, const char *me, const char *who, int buddy_icon);
+
+#endif
diff --git a/miranda-wine/protocols/Yahoo/chat.c b/miranda-wine/protocols/Yahoo/chat.c
new file mode 100644
index 0000000..3263218
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/chat.c
@@ -0,0 +1,77 @@
+/*
+ * $Id: chat.c 3659 2006-08-30 19:43:41Z gena01 $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+#include "yahoo.h"
+#include <m_protosvc.h>
+#include <m_langpack.h>
+#include <m_message.h>
+
+extern yahoo_local_account * ylad;
+
+void ext_yahoo_got_im(int id, const char *me, const char *who, const char *msg, long tm, int stat, int utf8, int buddy_icon);
+
+/* Conference handlers */
+void ext_yahoo_got_conf_invite(int id, const char *me, const char *who, const char *room, const char *msg, YList *members)
+{
+ char z[1024];
+
+ _snprintf(z, sizeof(z), Translate("[miranda] Got conference invite to room: %s with msg: %s"), room ?room:"", msg ?msg:"");
+ LOG(("[ext_yahoo_got_conf_invite] %s", z));
+ ext_yahoo_got_im(id, "me", who, z, 0, 0, 1, -1);
+
+ yahoo_conference_decline(ylad->id, NULL, members, room, Translate("I am sorry, but i can't join your conference since this feature is not currently implemented in my client."));
+}
+
+void ext_yahoo_conf_userdecline(int id, const char *me, const char *who, const char *room, const char *msg)
+{
+}
+
+void ext_yahoo_conf_userjoin(int id, const char *me, const char *who, const char *room)
+{
+}
+
+void ext_yahoo_conf_userleave(int id, const char *me, const char *who, const char *room)
+{
+}
+
+void ext_yahoo_conf_message(int id, const char *me, const char *who, const char *room, const char *msg, int utf8)
+{
+}
+
+/* chat handlers */
+void ext_yahoo_chat_cat_xml(int id, const char *xml)
+{
+}
+
+void ext_yahoo_chat_join(int id, const char *me, const char *room, const char * topic, YList *members, int fd)
+{
+}
+
+void ext_yahoo_chat_userjoin(int id, const char *me, const char *room, struct yahoo_chat_member *who)
+{
+}
+
+void ext_yahoo_chat_userleave(int id, const char *me, const char *room, const char *who)
+{
+}
+void ext_yahoo_chat_message(int id, const char *me, const char *who, const char *room, const char *msg, int msgtype, int utf8)
+{
+}
+
+void ext_yahoo_chat_yahoologout(int id, const char *me)
+{
+ LOG(("got chat logout"));
+}
+void ext_yahoo_chat_yahooerror(int id, const char *me)
+{
+ LOG(("got chat error"));
+}
diff --git a/miranda-wine/protocols/Yahoo/chat.h b/miranda-wine/protocols/Yahoo/chat.h
new file mode 100644
index 0000000..33927ec
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/chat.h
@@ -0,0 +1,42 @@
+/*
+ * $Id: chat.h 3627 2006-08-28 16:11:15Z gena01 $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+#ifndef _YAHOO_CHAT_H_
+#define _YAHOO_CHAT_H_
+
+/* Conference handlers */
+void ext_yahoo_got_conf_invite(int id, const char *me, const char *who, const char *room, const char *msg, YList *members);
+
+void ext_yahoo_conf_userdecline(int id, const char *me, const char *who, const char *room, const char *msg);
+
+void ext_yahoo_conf_userjoin(int id, const char *me, const char *who, const char *room);
+
+void ext_yahoo_conf_userleave(int id, const char *me, const char *who, const char *room);
+
+void ext_yahoo_conf_message(int id, const char *me, const char *who, const char *room, const char *msg, int utf8);
+
+/* chat handlers */
+void ext_yahoo_chat_cat_xml(int id, const char *xml);
+
+void ext_yahoo_chat_join(int id, const char *me, const char *room, const char * topic, YList *members, int fd);
+
+void ext_yahoo_chat_userjoin(int id, const char *me, const char *room, struct yahoo_chat_member *who);
+
+void ext_yahoo_chat_userleave(int id, const char *me, const char *room, const char *who);
+
+void ext_yahoo_chat_message(int id, const char *me, const char *who, const char *room, const char *msg, int msgtype, int utf8);
+
+void ext_yahoo_chat_yahoologout(int id, const char *me);
+
+void ext_yahoo_chat_yahooerror(int id, const char *me);
+
+#endif
diff --git a/miranda-wine/protocols/Yahoo/file_transfer.c b/miranda-wine/protocols/Yahoo/file_transfer.c
new file mode 100644
index 0000000..f546a43
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/file_transfer.c
@@ -0,0 +1,613 @@
+/*
+ * $Id: file_transfer.c 3659 2006-08-30 19:43:41Z gena01 $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+#include <time.h>
+#include <sys/stat.h>
+
+#include "yahoo.h"
+#include <m_protosvc.h>
+#include "file_transfer.h"
+
+extern yahoo_local_account * ylad;
+
+void get_fd(int id, int fd, int error, void *data)
+{
+ y_filetransfer *sf = (y_filetransfer*) data;
+ char buf[1024];
+ long size = 0;
+ DWORD dw = 0;
+ int rw = 0;
+ struct _stat statbuf;
+
+ if (fd < 0) {
+ LOG(("[get_fd] Connect Failed!"));
+ error = 1;
+ }
+
+ if (_stat( sf->filename, &statbuf ) != 0 )
+ error = 1;
+
+ if(!error) {
+ HANDLE myhFile = CreateFile(sf->filename,
+ GENERIC_READ,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
+ 0);
+
+
+ if(myhFile !=INVALID_HANDLE_VALUE) {
+ PROTOFILETRANSFERSTATUS pfts;
+
+ DWORD lNotify = GetTickCount();
+ LOG(("proto: %s, hContact: %p", yahooProtocolName, sf->hContact));
+
+ LOG(("Sending file: %s", sf->filename));
+ //ProtoBroadcastAck(yahooProtocolName, sf->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, sf, 0);
+ ProtoBroadcastAck(yahooProtocolName, sf->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, sf, 0);
+ ProtoBroadcastAck(yahooProtocolName, sf->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTED, sf, 0);
+ //ProtoBroadcastAck(yahooProtocolName, sf->hContact, ACKTYPE_FILE, ACKRESULT_SENTREQUEST, sf, 0);
+ //ProtoBroadcastAck(yahooProtocolName, sf->hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, sf, 0);
+
+ ZeroMemory(&pfts, sizeof(PROTOFILETRANSFERSTATUS));
+ pfts.cbSize = sizeof(PROTOFILETRANSFERSTATUS);
+ pfts.hContact = sf->hContact;
+ pfts.sending = 1;
+ pfts.files = &sf->filename;
+ pfts.totalFiles = 1;
+ pfts.currentFileNumber = 0;
+ pfts.totalBytes = statbuf.st_size;
+ pfts.workingDir = NULL;
+ pfts.currentFile = sf->filename;
+ pfts.currentFileSize = statbuf.st_size;
+ pfts.currentFileTime = 0;
+
+ do {
+ ReadFile(myhFile, buf, sizeof(buf), &dw, NULL);
+
+ if (dw) {
+ rw = Netlib_Send((HANDLE)fd, buf, dw, MSG_NODUMP);
+
+ if (rw < 1) {
+ LOG(("Upload Failed. Send error? Got: %d", rw));
+ error = 1;
+ break;
+ } else
+ size += rw;
+
+ if(GetTickCount() >= lNotify + 500 || rw < 1024 || size == statbuf.st_size) {
+ LOG(("DOING UI Notify. Got %lu/%lu", size, statbuf.st_size));
+ pfts.totalProgress = size;
+ pfts.currentFileProgress = size;
+
+ ProtoBroadcastAck(yahooProtocolName, sf->hContact, ACKTYPE_FILE, ACKRESULT_DATA, sf, (LPARAM) & pfts);
+ lNotify = GetTickCount();
+ }
+
+ }
+
+ if (sf->cancel) {
+ LOG(("Upload Cancelled! "));
+ error = 1;
+ break;
+ }
+ } while ( rw > 0 && dw > 0 && !error);
+
+ CloseHandle(myhFile);
+
+ pfts.totalProgress = size;
+ pfts.currentFileProgress = size;
+
+ ProtoBroadcastAck(yahooProtocolName, sf->hContact, ACKTYPE_FILE, ACKRESULT_DATA, sf, (LPARAM) & pfts);
+
+ }
+ }
+
+ if (fd > 0) {
+ int tr = 0;
+
+ do {
+ rw = Netlib_Recv((HANDLE)fd, buf, sizeof(buf), 0);
+ LOG(("Got: %d bytes", rw));
+
+ if (tr == 0) {
+ //"HTTP/1.1 999" 12
+ // 012345678901
+ if (rw > 12) {
+ if (buf[9] != '2' || buf[10] != '0' || buf[11] != '0') {
+ LOG(("File Transfer Failed: %c%c%c", buf[9], buf[10], buf[11]));
+ error=1;
+ }
+ }
+ }
+ tr +=rw;
+ } while (rw > 0);
+
+ Netlib_CloseHandle((HANDLE)fd);
+ }
+
+ LOG(("File send complete!"));
+
+ ProtoBroadcastAck(yahooProtocolName, sf->hContact, ACKTYPE_FILE, !error ? ACKRESULT_SUCCESS:ACKRESULT_FAILED, sf, 0);
+}
+
+void YAHOO_SendFile(y_filetransfer *sf)
+{
+ long tFileSize = 0;
+ { struct _stat statbuf;
+ if ( _stat( sf->filename, &statbuf ) == 0 )
+ tFileSize += statbuf.st_size;
+ }
+
+ yahoo_send_file(ylad->id, sf->who, sf->msg, sf->filename, tFileSize, &get_fd, sf);
+}
+
+void YAHOO_FT_cancel(const char *buddy, const char *filename, const char *ft_token, int command)
+{
+ yahoo_ftdc_cancel(ylad->id, buddy, filename, ft_token, command);
+}
+
+void get_url(int id, int fd, int error, const char *filename, unsigned long size, void *data)
+{
+ y_filetransfer *sf = (y_filetransfer*) data;
+ char buf[1024];
+ long rsize = 0;
+ DWORD dw, c;
+
+ if (fd < 0) {
+ LOG(("[get_url] Connect Failed!"));
+
+ if (sf->ftoken != NULL) {
+ LOG(("[get_url] DC Detected: asking sender to upload to Yahoo FileServers!"));
+ YAHOO_FT_cancel(sf->who, sf->filename, sf->ftoken, 3);
+ }
+
+ error = 1;
+ }
+
+ if(!error) {
+ HANDLE myhFile;
+ PROTOFILETRANSFERSTATUS pfts;
+
+ ZeroMemory(&pfts, sizeof(PROTOFILETRANSFERSTATUS));
+ pfts.cbSize = sizeof(PROTOFILETRANSFERSTATUS);
+ pfts.hContact = sf->hContact;
+ pfts.sending = 0;
+ pfts.files = (char**)&filename;
+ pfts.totalFiles = 1;//ntohs(1);
+ pfts.currentFileNumber = 0;
+ pfts.totalBytes = size;
+
+ pfts.workingDir = sf->savepath;//ft->savepath;
+ pfts.currentFileSize = size; //ntohl(ft->hdr.size);
+
+ LOG(("dir: %s, file: %s", sf->savepath, sf->filename ));
+ wsprintf(buf, "%s\\%s", sf->savepath, sf->filename);
+
+ pfts.currentFile = _strdup(buf);
+ LOG(("Saving: %s", pfts.currentFile));
+
+ if ( sf->hWaitEvent != INVALID_HANDLE_VALUE )
+ CloseHandle( sf->hWaitEvent );
+
+ sf->hWaitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+
+ if ( YAHOO_SendBroadcast( sf->hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, (void *)sf, ( LPARAM )&pfts )) {
+ WaitForSingleObject( sf->hWaitEvent, INFINITE );
+
+ switch(sf->action){
+ case FILERESUME_RENAME:
+ case FILERESUME_OVERWRITE:
+ case FILERESUME_RESUME:
+ // no action needed at this point, just break out of the switch statement
+ break;
+
+ case FILERESUME_CANCEL :
+ sf->cancel = 1;
+ break;
+
+ case FILERESUME_SKIP :
+ default:
+ //delete this; // per usual dcc objects destroy themselves when they fail or when connection is closed
+ //return FALSE;
+ sf->cancel = 2;
+ break;
+ }
+ }
+
+ free(pfts.currentFile);
+
+ if (! sf->cancel) {
+
+ if (sf->action != FILERESUME_RENAME ) {
+ LOG(("dir: %s, file: %s", sf->savepath, sf->filename ));
+
+ wsprintf(buf, "%s\\%s", sf->savepath, sf->filename);
+ } else {
+ LOG(("file: %s", sf->filename ));
+ //wsprintf(buf, "%s\%s", sf->filename);
+ lstrcpy(buf, sf->filename);
+ }
+
+ //pfts.files = &buf;
+ pfts.currentFile = _strdup(buf);
+
+ LOG(("Getting file: %s", buf));
+ myhFile = CreateFile(buf,
+ GENERIC_WRITE,
+ FILE_SHARE_WRITE,
+ NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+
+ if(myhFile !=INVALID_HANDLE_VALUE) {
+ DWORD lNotify = GetTickCount();
+
+ SetEndOfFile(myhFile);
+
+ LOG(("proto: %s, hContact: %p", yahooProtocolName, sf->hContact));
+
+ ProtoBroadcastAck(yahooProtocolName, sf->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTED, sf, 0);
+
+ do {
+ dw = Netlib_Recv((HANDLE)fd, buf, 1024, MSG_NODUMP);
+
+ if (dw > 0) {
+ WriteFile(myhFile, buf, dw, &c, NULL);
+ rsize += dw;
+
+ /*LOG(("Got %d/%d", rsize, size));*/
+ if(GetTickCount() >= lNotify + 500 || dw <= 0 || rsize == size) {
+
+ LOG(("DOING UI Notify. Got %lu/%lu", rsize, size));
+
+ pfts.totalProgress = rsize;
+ pfts.currentFileTime = time(NULL);//ntohl(ft->hdr.modtime);
+ pfts.currentFileProgress = rsize;
+
+ ProtoBroadcastAck(yahooProtocolName, sf->hContact, ACKTYPE_FILE, ACKRESULT_DATA, sf, (LPARAM) & pfts);
+ lNotify = GetTickCount();
+ }
+ } else {
+ LOG(("Recv Failed! Socket Error?"));
+ error = 1;
+ break;
+ }
+
+ if (sf->cancel) {
+ LOG(("Recv Cancelled! "));
+ error = 1;
+ break;
+ }
+ } while ( dw > 0 && rsize < size);
+
+ LOG(("[Finished DL] Got %lu/%lu", rsize, size));
+ CloseHandle(myhFile);
+
+ } else {
+ LOG(("Can not open file for writing: %s", buf));
+ error = 1;
+ }
+
+ free(pfts.currentFile);
+ }
+
+ }
+
+ if (fd > 0) {
+ LOG(("Closing connection: %d", fd));
+ Netlib_CloseHandle((HANDLE)fd);
+ }
+
+ LOG(("File download complete!"));
+
+ ProtoBroadcastAck(yahooProtocolName, sf->hContact, ACKTYPE_FILE, !error ? ACKRESULT_SUCCESS:ACKRESULT_FAILED, sf, 0);
+}
+
+void YAHOO_RecvFile(y_filetransfer *ft)
+{
+ yahoo_get_url_handle(ylad->id, ft->url, &get_url, ft);
+}
+
+void ext_yahoo_got_file(int id, const char *me, const char *who, const char *url, long expires, const char *msg, const char *fname, unsigned long fesize, const char *ft_token, int y7)
+{
+ CCSDATA ccs;
+ PROTORECVEVENT pre;
+ HANDLE hContact;
+ char *szBlob;
+ y_filetransfer *ft;
+
+ LOG(("[ext_yahoo_got_file] id: %i, ident:%s, who: %s, url: %s, expires: %lu, msg: %s, fname: %s, fsize: %lu ftoken: %s y7: %d", id, me, who, url, expires, msg, fname, fesize, ft_token == NULL ? "NULL" : ft_token, y7));
+
+ hContact = getbuddyH(who);
+ if (hContact == NULL)
+ hContact = add_buddy(who, who, PALF_TEMPORARY);
+
+ ft= (y_filetransfer*) malloc(sizeof(y_filetransfer));
+ ft->id = id;
+ ft->who = strdup(who);
+ ft->hWaitEvent = INVALID_HANDLE_VALUE;
+ if (msg != NULL)
+ ft->msg = strdup(msg);
+ else
+ ft->msg = strdup("[no description given]");
+
+ ft->hContact = hContact;
+ if (fname != NULL)
+ ft->filename = strdup(fname);
+ else {
+ char *start, *end;
+
+ /* based on how gaim does this */
+ start = strrchr(url, '/');
+ if (start)
+ start++;
+
+ end = strrchr(url, '?');
+
+ if (start && *start && end) {
+ /* argh WINDOWS SUCKS!!! */
+ //ft->filename = strndup(start, end-start);
+ ft->filename = (char *)malloc(end - start + 1);
+ strncpy(ft->filename, start, end-start);
+ ft->filename[end-start] = '\0';
+ } else
+ ft->filename = strdup("filename.ext");
+ }
+
+ ft->url = strdup(url);
+ ft->fsize = fesize;
+ ft->cancel = 0;
+ ft->y7 = y7;
+ ft->ftoken = (ft_token == NULL) ? NULL : strdup(ft_token);
+
+ // blob is DWORD(*ft), ASCIIZ(filenames), ASCIIZ(description)
+ szBlob = (char *) malloc(sizeof(DWORD) + lstrlen(ft->filename) + lstrlen(ft->msg) + 2);
+ *((PDWORD) szBlob) = (DWORD) ft;
+ strcpy(szBlob + sizeof(DWORD), ft->filename);
+ strcpy(szBlob + sizeof(DWORD) + lstrlen(ft->filename) + 1, ft->msg);
+
+ pre.flags = 0;
+ pre.timestamp = time(NULL);
+ pre.szMessage = szBlob;
+ pre.lParam = 0;
+ ccs.szProtoService = PSR_FILE;
+ ccs.hContact = ft->hContact;
+ ccs.wParam = 0;
+ ccs.lParam = (LPARAM) & pre;
+ CallService(MS_PROTO_CHAINRECV, 0, (LPARAM) & ccs);
+ free(szBlob);
+}
+
+//=======================================================
+//File Transfer
+//=======================================================
+static void __cdecl yahoo_recv_filethread(void *psf)
+{
+ y_filetransfer *sf = psf;
+
+// ProtoBroadcastAck(yahooProtocolName, hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE) 1, 0);
+ if (sf == NULL) {
+ YAHOO_DebugLog("SF IS NULL!!!");
+ return;
+ }
+ YAHOO_DebugLog("who %s, msg: %s, filename: %s ", sf->who, sf->msg, sf->filename);
+
+ YAHOO_RecvFile(sf);
+ if ( sf->hWaitEvent != INVALID_HANDLE_VALUE )
+ CloseHandle( sf->hWaitEvent );
+
+ free(sf->who);
+ free(sf->msg);
+ free(sf->filename);
+ free(sf->url);
+ free(sf->savepath);
+ free(sf);
+
+}
+
+/**************** Receive File ********************/
+int YahooFileAllow(WPARAM wParam,LPARAM lParam)
+{
+ CCSDATA *ccs = (CCSDATA *) lParam;
+ y_filetransfer *ft = (y_filetransfer *) ccs->wParam;
+ int len;
+
+ YAHOO_DebugLog("[YahooFileAllow]");
+
+ if (ft->y7) {
+ YAHOO_DebugLog("[YahooFileAllow] We don't handle y7 stuff yet.");
+ //void yahoo_ft7dc_accept(int id, const char *buddy, const char *ft_token);
+ yahoo_ft7dc_accept(ft->id, ft->who, ft->ftoken);
+
+ return ccs->wParam;
+ }
+ //LOG(LOG_INFO, "[%s] Requesting file from %s", ft->cookie, ft->user);
+ ft->savepath = _strdup((char *) ccs->lParam);
+
+ len = lstrlen(ft->savepath) - 1;
+ if (ft->savepath[len] == '\\')
+ ft->savepath[len] = '\0';
+
+ pthread_create(yahoo_recv_filethread, (void *) ft);
+
+ return ccs->wParam;
+}
+
+int YahooFileDeny(WPARAM wParam,LPARAM lParam)
+{
+ /* deny file receive request.. just ignore it! */
+ CCSDATA *ccs = (CCSDATA *) lParam;
+ y_filetransfer *ft = (y_filetransfer *) ccs->wParam;
+
+ YAHOO_DebugLog("[YahooFileDeny]");
+
+ if ( !yahooLoggedIn || ft == NULL ) {
+ YAHOO_DebugLog("[YahooFileResume] Not logged-in or some other error!");
+ return 1;
+ }
+
+ if (ft->y7) {
+ YAHOO_DebugLog("[YahooFileDeny] We don't handle y7 stuff yet.");
+ //void yahoo_ft7dc_accept(int id, const char *buddy, const char *ft_token);
+ yahoo_ft7dc_cancel(ft->id, ft->who, ft->ftoken);
+ return 0;
+ }
+
+ if (ft->ftoken != NULL) {
+ YAHOO_DebugLog("[] DC Detected: Denying File Transfer!");
+ YAHOO_FT_cancel(ft->who, ft->filename, ft->ftoken, 2);
+ }
+ return 0;
+}
+
+int YahooFileResume( WPARAM wParam, LPARAM lParam )
+{
+ PROTOFILERESUME *pfr;
+ y_filetransfer *ft = (y_filetransfer *) wParam;
+
+ YAHOO_DebugLog("[YahooFileResume]");
+
+ if ( !yahooLoggedIn || ft == NULL ) {
+ YAHOO_DebugLog("[YahooFileResume] Not loggedin or some other error!");
+ return 1;
+ }
+
+ pfr = (PROTOFILERESUME*)lParam;
+
+ ft->action = pfr->action;
+
+ YAHOO_DebugLog("[YahooFileResume] Action: %d", pfr->action);
+
+ if ( pfr->action == FILERESUME_RENAME ) {
+ YAHOO_DebugLog("[YahooFileResume] Renamed file!");
+ if ( ft->filename != NULL ) {
+ free( ft->filename );
+ ft->filename = NULL;
+ }
+
+ ft->filename = strdup( pfr->szFilename );
+ }
+
+
+ SetEvent( ft->hWaitEvent );
+ return 0;
+}
+
+/**************** Send File ********************/
+static void __cdecl yahoo_send_filethread(void *psf)
+{
+ y_filetransfer *sf = psf;
+
+// ProtoBroadcastAck(yahooProtocolName, hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE) 1, 0);
+ if (sf == NULL) {
+ YAHOO_DebugLog("SF IS NULL!!!");
+ return;
+ }
+ YAHOO_DebugLog("who %s, msg: %s, filename: %s ", sf->who, sf->msg, sf->filename);
+
+ YAHOO_SendFile(sf);
+ free(sf->who);
+ free(sf->msg);
+ free(sf->filename);
+ free(sf);
+
+}
+
+int YahooFileCancel(WPARAM wParam,LPARAM lParam)
+{
+ CCSDATA* ccs = ( CCSDATA* )lParam;
+ y_filetransfer* ft = (y_filetransfer*)ccs->wParam;
+
+ YAHOO_DebugLog("[YahooFileCancel]");
+
+ if ( ft->hWaitEvent != INVALID_HANDLE_VALUE )
+ SetEvent( ft->hWaitEvent );
+
+ ft->action = FILERESUME_CANCEL;
+ ft->cancel = 1;
+ return 0;
+}
+
+/*
+ *
+ */
+int YahooSendFile(WPARAM wParam,LPARAM lParam)
+{
+ DBVARIANT dbv;
+ y_filetransfer *sf;
+ CCSDATA *ccs;
+ char** files;
+
+ YAHOO_DebugLog("YahooSendFile");
+
+ if ( !yahooLoggedIn )
+ return 0;
+
+ YAHOO_DebugLog("Gathering Data");
+
+ ccs = ( CCSDATA* )lParam;
+ //if ( YAHOO_GetWord( ccs->hContact, "Status", ID_STATUS_OFFLINE ) == ID_STATUS_OFFLINE )
+ // return 0;
+
+ YAHOO_DebugLog("Getting Files");
+
+ files = ( char** )ccs->lParam;
+ if ( files[1] != NULL ){
+ MessageBox(NULL, "YAHOO protocol allows only one file to be sent at a time", "Yahoo", MB_OK | MB_ICONINFORMATION);
+ return 0;
+ }
+
+ YAHOO_DebugLog("Getting Yahoo ID");
+
+ if (!DBGetContactSetting(ccs->hContact, yahooProtocolName, YAHOO_LOGINID, &dbv)) {
+
+ sf = (y_filetransfer*) malloc(sizeof(y_filetransfer));
+ sf->who = strdup(dbv.pszVal);
+ sf->msg = strdup(( char* )ccs->wParam );
+ sf->filename = strdup(files[0]);
+ sf->hContact = ccs->hContact;
+ sf->cancel = 0;
+
+ YAHOO_DebugLog("who: %s, msg: %s, filename: %s", sf->who, sf->msg, sf->filename);
+ pthread_create(yahoo_send_filethread, sf);
+
+ DBFreeVariant(&dbv);
+ YAHOO_DebugLog("Exiting SendRequest...");
+ return (int)(HANDLE)sf;
+ }
+
+ YAHOO_DebugLog("Exiting SendFile");
+ return 0;
+}
+
+int YahooRecvFile(WPARAM wParam,LPARAM lParam)
+{
+ DBEVENTINFO dbei;
+ CCSDATA *ccs = (CCSDATA *) lParam;
+ PROTORECVEVENT *pre = (PROTORECVEVENT *) ccs->lParam;
+ char *szDesc, *szFile;
+
+ DBDeleteContactSetting(ccs->hContact, "CList", "Hidden");
+ szFile = pre->szMessage + sizeof(DWORD);
+ szDesc = szFile + lstrlen(szFile) + 1;
+ ZeroMemory(&dbei, sizeof(dbei));
+ dbei.cbSize = sizeof(dbei);
+ dbei.szModule = yahooProtocolName;
+ dbei.timestamp = pre->timestamp;
+ dbei.flags = pre->flags & (PREF_CREATEREAD ? DBEF_READ : 0);
+ dbei.eventType = EVENTTYPE_FILE;
+ dbei.cbBlob = sizeof(DWORD) + lstrlen(szFile) + lstrlen(szDesc) + 2;
+ dbei.pBlob = (PBYTE) pre->szMessage;
+ CallService(MS_DB_EVENT_ADD, (WPARAM) ccs->hContact, (LPARAM) & dbei);
+ return 0;
+}
+
diff --git a/miranda-wine/protocols/Yahoo/file_transfer.h b/miranda-wine/protocols/Yahoo/file_transfer.h
new file mode 100644
index 0000000..72854a7
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/file_transfer.h
@@ -0,0 +1,48 @@
+/*
+ * $Id: file_transfer.h 3632 2006-08-28 20:33:30Z gena01 $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+#ifndef _YAHOO_FILE_TRANSFER_H_
+#define _YAHOO_FILE_TRANSFER_H_
+
+#define FILERESUME_CANCEL 11
+
+typedef struct {
+ int id;
+ char *who;
+ char *msg;
+ char *filename;
+ char *ftoken;
+ HANDLE hContact;
+ int cancel;
+ char *url;
+ char *savepath;
+ unsigned long fsize;
+ HANDLE hWaitEvent;
+ DWORD action;
+ int y7;
+} y_filetransfer;
+
+void YAHOO_SendFile(y_filetransfer *ft);
+void YAHOO_RecvFile(y_filetransfer *ft);
+void YAHOO_FT_cancel(const char *buddy, const char *filename, const char *ft_token, int command);
+
+void ext_yahoo_got_file(int id, const char *me, const char *who, const char *url, long expires, const char *msg, const char *fname, unsigned long fesize, const char *ft_token, int y7);
+
+/* service functions */
+int YahooFileAllow(WPARAM wParam,LPARAM lParam);
+int YahooFileDeny(WPARAM wParam, LPARAM lParam);
+int YahooFileResume(WPARAM wParam, LPARAM lParam);
+int YahooFileCancel(WPARAM wParam, LPARAM lParam);
+int YahooSendFile(WPARAM wParam, LPARAM lParam);
+int YahooRecvFile(WPARAM wParam, LPARAM lParam);
+
+#endif
diff --git a/miranda-wine/protocols/Yahoo/http_gateway.c b/miranda-wine/protocols/Yahoo/http_gateway.c
new file mode 100644
index 0000000..110cc0a
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/http_gateway.c
@@ -0,0 +1,88 @@
+/*
+ * $Id: http_gateway.c 3566 2006-08-22 01:55:32Z gena01 $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+#ifdef HTTP_GATEWAY
+
+#include <windows.h>
+#include "yahoo.h"
+
+extern yahoo_local_account * ylad;
+
+int YAHOO_httpGatewayInit(HANDLE hConn, NETLIBOPENCONNECTION *nloc, NETLIBHTTPREQUEST *nlhr)
+{
+ NETLIBHTTPPROXYINFO nlhpi;
+
+ YAHOO_DebugLog("YAHOO_httpGatewayInit!!!");
+
+ ZeroMemory(&nlhpi, sizeof(nlhpi) );
+ nlhpi.cbSize = sizeof(nlhpi);
+ nlhpi.szHttpPostUrl = "http://shttp.msg.yahoo.com/notify/";
+
+ //CallService( MS_NETLIB_SETPOLLINGTIMEOUT, (WPARAM) hConn, 15 );
+
+ return CallService(MS_NETLIB_SETHTTPPROXYINFO, (WPARAM)hConn, (LPARAM)&nlhpi);
+}
+
+int YAHOO_httpGatewayWrapSend(HANDLE hConn, PBYTE buf, int len, int flags, MIRANDASERVICE pfnNetlibSend)
+{
+ YAHOO_DebugLog("YAHOO_httpGatewayWrapSend!!! Len: %d", len);
+
+ if (len == 0 && ylad != NULL) { // we need to send something!!!
+ int n;
+ char *z = yahoo_webmessenger_idle_packet(ylad->id, &n);
+ int ret = 0;
+
+ if (z != NULL) {
+ YAHOO_DebugLog("YAHOO_httpGatewayWrapSend!!! Got Len: %d", n);
+ NETLIBBUFFER tBuf = { ( char* )z, n, flags };
+ ret = pfnNetlibSend(( LPARAM )hConn, (WPARAM) &tBuf );
+ FREE(z);
+ } else {
+ YAHOO_DebugLog("YAHOO_httpGatewayWrapSend!!! GOT NULL???");
+ }
+
+ return ret;
+ } else {
+ NETLIBBUFFER tBuf = { ( char* )buf, len, flags };
+
+ return pfnNetlibSend(( LPARAM )hConn, (WPARAM) &tBuf );
+ }
+}
+
+PBYTE YAHOO_httpGatewayUnwrapRecv(NETLIBHTTPREQUEST *nlhr, PBYTE buf, int len, int *outBufLen, void *(*NetlibRealloc)(void *, size_t))
+{
+ YAHOO_DebugLog("YAHOO_httpGatewayUnwrapRecv!!! Len: %d", len);
+
+ YAHOO_DebugLog("Got headers: %d", nlhr->headersCount);
+ /* we need to get the first 4 bytes! */
+ if (len < 4)
+ return NULL;
+
+ if (ylad != NULL) {
+ ylad->rpkts = buf[0] + buf[1] *256;
+ YAHOO_DebugLog("Got packets: %d", ylad->rpkts);
+ }
+
+ if (len == 4){
+ *outBufLen = 0;
+ return buf;
+ } else if ( (buf[4] == 'Y') && (buf[5] == 'M') && (buf[6] == 'S') && (buf[7] == 'G') ) {
+ MoveMemory( buf, buf + 4, len - 4);
+ *outBufLen = len-4;// we take off 4 bytes from the beginning
+
+ return buf;
+ } else
+ return NULL; /* Break connection, something went wrong! */
+
+}
+
+#endif
diff --git a/miranda-wine/protocols/Yahoo/http_gateway.h b/miranda-wine/protocols/Yahoo/http_gateway.h
new file mode 100644
index 0000000..43aa4c1
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/http_gateway.h
@@ -0,0 +1,24 @@
+/*
+ * $Id: http_gateway.h 3541 2006-08-18 21:18:33Z gena01 $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+
+#ifndef _YAHOO_HTTP_GATEWAY_H_
+#define _YAHOO_HTTP_GATEWAY_H_
+
+#define HTTP_PROXY_VERSION 0x0443
+
+int YAHOO_httpGatewayInit(HANDLE hConn, NETLIBOPENCONNECTION *nloc, NETLIBHTTPREQUEST *nlhr);
+int YAHOO_httpGatewayWrapSend(HANDLE hConn, PBYTE buf, int len, int flags, MIRANDASERVICE pfnNetlibSend);
+PBYTE YAHOO_httpGatewayUnwrapRecv(NETLIBHTTPREQUEST *nlhr, PBYTE buf, int bufLen, int *outBufLen, void *(*NetlibRealloc)(void *, size_t));
+
+#endif
+
diff --git a/miranda-wine/protocols/Yahoo/icos/address_book.ico b/miranda-wine/protocols/Yahoo/icos/address_book.ico
new file mode 100644
index 0000000..9ab54fa
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/icos/address_book.ico
Binary files differ
diff --git a/miranda-wine/protocols/Yahoo/icos/calendar.ico b/miranda-wine/protocols/Yahoo/icos/calendar.ico
new file mode 100644
index 0000000..9eef326
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/icos/calendar.ico
Binary files differ
diff --git a/miranda-wine/protocols/Yahoo/icos/inbox.ico b/miranda-wine/protocols/Yahoo/icos/inbox.ico
new file mode 100644
index 0000000..55097a1
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/icos/inbox.ico
Binary files differ
diff --git a/miranda-wine/protocols/Yahoo/icos/invite.ico b/miranda-wine/protocols/Yahoo/icos/invite.ico
new file mode 100644
index 0000000..2efc4dc
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/icos/invite.ico
Binary files differ
diff --git a/miranda-wine/protocols/Yahoo/icos/profile.ico b/miranda-wine/protocols/Yahoo/icos/profile.ico
new file mode 100644
index 0000000..a2c16ae
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/icos/profile.ico
Binary files differ
diff --git a/miranda-wine/protocols/Yahoo/icos/refresh.ico b/miranda-wine/protocols/Yahoo/icos/refresh.ico
new file mode 100644
index 0000000..77a399e
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/icos/refresh.ico
Binary files differ
diff --git a/miranda-wine/protocols/Yahoo/icos/set_status.ico b/miranda-wine/protocols/Yahoo/icos/set_status.ico
new file mode 100644
index 0000000..ac2d356
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/icos/set_status.ico
Binary files differ
diff --git a/miranda-wine/protocols/Yahoo/icos/yahoo.ico b/miranda-wine/protocols/Yahoo/icos/yahoo.ico
new file mode 100644
index 0000000..fc54d7b
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/icos/yahoo.ico
Binary files differ
diff --git a/miranda-wine/protocols/Yahoo/im.c b/miranda-wine/protocols/Yahoo/im.c
new file mode 100644
index 0000000..85212c6
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/im.c
@@ -0,0 +1,333 @@
+/*
+ * $Id: im.c 3659 2006-08-30 19:43:41Z gena01 $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+#include <time.h>
+#include <malloc.h>
+#include <sys/stat.h>
+
+#include "yahoo.h"
+
+#include <m_langpack.h>
+#include <m_protosvc.h>
+
+#include "avatar.h"
+#include "im.h"
+
+extern yahoo_local_account *ylad;
+extern HANDLE hYahooNudge;
+
+static void yahoo_send_msg(const char *id, const char *msg, int utf8)
+{
+ int buddy_icon = 0;
+ LOG(("yahoo_send_msg: %s: %s, utf: %d", id, msg, utf8));
+
+ buddy_icon = (YAHOO_GetDword("AvatarHash", 0) != 0) ? 2: 0;
+
+ yahoo_send_im(ylad->id, NULL, id, msg, utf8, buddy_icon);
+}
+
+void ext_yahoo_got_im(int id, const char *me, const char *who, const char *msg, long tm, int stat, int utf8, int buddy_icon)
+{
+ char *umsg;
+ const char *c = msg;
+ int oidx = 0;
+ wchar_t* tRealBody = NULL;
+ int tRealBodyLen = 0;
+ int msgLen;
+ char* tMsgBuf = NULL;
+ char* p = NULL;
+ CCSDATA ccs;
+ PROTORECVEVENT pre;
+ HANDLE hContact;
+
+
+ LOG(("YAHOO_GOT_IM id:%s %s: %s tm:%lu stat:%i utf8:%i buddy_icon: %i", me, who, msg, tm, stat, utf8, buddy_icon));
+
+ if(stat == 2) {
+ char z[1024];
+
+ snprintf(z, sizeof z, "Error sending message to %s", who);
+ LOG((z));
+ YAHOO_ShowError(Translate("Yahoo Error"), z);
+ return;
+ }
+
+ if(!msg) {
+ LOG(("Empty Incoming Message, exiting."));
+ return;
+ }
+
+ {
+ YList *l;
+
+ /* show our current ignore list */
+ l = (YList *)YAHOO_GetIgnoreList();
+ while (l != NULL) {
+ struct yahoo_buddy *b = (struct yahoo_buddy *) l->data;
+
+ //MessageBox(NULL, b->id, "ID", MB_OK);
+ //SendMessage(GetDlgItem(hwndDlg,IDC_YIGN_LIST), LB_INSERTSTRING, 0, (LPARAM)b->id);
+ if (lstrcmpi(b->id, who) == 0) {
+ LOG(("User '%s' on our Ignore List. Dropping Message.", who));
+ return;
+ }
+ l = l->next;
+ }
+
+ }
+
+ umsg = (char *) alloca(lstrlen(msg) * 2 + 1); /* double size to be on the safe side */
+ while ( *c != '\0') {
+ // Strip the font and font size tag
+ if (!strnicmp(c,"<font face=",11) || !strnicmp(c,"<font size=",11) ||
+ !strnicmp(c, "<font color=",12) || !strnicmp(c,"</font>",6) ||
+ // strip the fade tag
+ !strnicmp(c, "<FADE ",6) || !strnicmp(c,"</FADE>",7) ||
+ // strip the alternate colors tag
+ !strnicmp(c, "<ALT ",5) || !strnicmp(c, "</ALT>",6)){
+ while ((*c++ != '>') && (*c != '\0'));
+ } else
+ // strip ANSI color combination
+ if ((*c == 0x1b) && (*(c+1) == '[')){
+ while ((*c++ != 'm') && (*c != '\0'));
+ } else
+
+ if (*c != '\0'){
+ umsg[oidx++] = *c;
+
+ /* Adding \r to \r\n conversion */
+ if (*c == '\r' && *(c + 1) != '\n')
+ umsg[oidx++] = '\n';
+
+ c++;
+ }
+ }
+
+ umsg[oidx++]= '\0';
+
+ /* Need to strip off formatting stuff first. Then do all decoding/converting */
+ if (utf8){
+ Utf8Decode( umsg, 0, &tRealBody );
+ tRealBodyLen = wcslen( tRealBody );
+ }
+
+ LOG(("%s: %s", who, umsg));
+
+ //if(!strcmp(umsg, "<ding>"))
+ // :P("\a");
+
+ if (utf8)
+ msgLen = (lstrlen(umsg) + 1) * (sizeof(wchar_t) + 1);
+ else
+ msgLen = (lstrlen(umsg) + 1);
+
+ tMsgBuf = ( char* )alloca( msgLen );
+ p = tMsgBuf;
+
+ // MSGBUF Blob: <ASCII> \0 <UNICODE> \0
+ strcpy( p, umsg );
+
+ p += lstrlen(umsg) + 1;
+
+ if ( tRealBodyLen != 0 ) {
+ memcpy( p, tRealBody, sizeof( wchar_t )*( tRealBodyLen+1 ));
+ free( tRealBody );
+ }
+
+ ccs.szProtoService = PSR_MESSAGE;
+ ccs.hContact = hContact = add_buddy(who, who, PALF_TEMPORARY);
+ ccs.wParam = 0;
+ ccs.lParam = (LPARAM) &pre;
+ pre.flags = (utf8) ? PREF_UNICODE : 0;
+
+ if (tm) {
+ HANDLE hEvent = (HANDLE)CallService(MS_DB_EVENT_FINDLAST, (WPARAM)hContact, 0);
+
+ if (hEvent) { // contact has events
+ DBEVENTINFO dbei;
+ DWORD dummy;
+
+ dbei.cbSize = sizeof (DBEVENTINFO);
+ dbei.pBlob = (char*)&dummy;
+ dbei.cbBlob = 2;
+ if (!CallService(MS_DB_EVENT_GET, (WPARAM)hEvent, (LPARAM)&dbei))
+ // got that event, if newer than ts then reset to current time
+ if (tm < dbei.timestamp) tm = time(NULL);
+ }
+
+ pre.timestamp = tm;
+ } else
+ pre.timestamp = time(NULL);
+
+ pre.szMessage = tMsgBuf;
+ pre.lParam = 0;
+
+ // Turn off typing
+ CallService(MS_PROTO_CONTACTISTYPING, (WPARAM) hContact, PROTOTYPE_CONTACTTYPING_OFF);
+ CallService(MS_PROTO_CHAINRECV, 0, (LPARAM) & ccs);
+
+ if (buddy_icon < 0) return;
+
+ //?? Don't generate floods!!
+ DBWriteContactSettingByte(hContact, yahooProtocolName, "AvatarType", buddy_icon);
+ if (buddy_icon != 2) {
+ yahoo_reset_avatar(hContact);
+ } else if (DBGetContactSettingDword(hContact, yahooProtocolName,"PictCK", 0) == 0) {
+ /* request the buddy image */
+ YAHOO_request_avatar(who);
+ }
+}
+
+
+static void __cdecl yahoo_im_sendacksuccess(HANDLE hContact)
+{
+ ProtoBroadcastAck(yahooProtocolName, hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE) 1, 0);
+}
+
+static void __cdecl yahoo_im_sendackfail(HANDLE hContact)
+{
+ SleepEx(1000, TRUE);
+ ProtoBroadcastAck(yahooProtocolName, hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE) 1,
+ (LPARAM) Translate("The message send timed out."));
+}
+
+static void __cdecl yahoo_im_sendackfail_longmsg(HANDLE hContact)
+{
+ SleepEx(1000, TRUE);
+ ProtoBroadcastAck(yahooProtocolName, hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE) 1,
+ (LPARAM)Translate("Message is too long: Yahoo messages are limited by 800 UTF8 chars"));
+}
+
+//=======================================================
+//Send a message
+//=======================================================
+//#define MSG_LEN 2048
+int YahooSendMessage(WPARAM wParam, LPARAM lParam)
+{
+ CCSDATA *ccs = (CCSDATA *) lParam;
+ DBVARIANT dbv;
+ char *msg = (char *) ccs->lParam;
+
+ if (!yahooLoggedIn) {/* don't send message if we not connected! */
+ pthread_create(yahoo_im_sendackfail, ccs->hContact);
+ return 1;
+ }
+
+ if (lstrlen(msg) > 800) {/* don't send message if we not connected! */
+ pthread_create( yahoo_im_sendackfail_longmsg, ccs->hContact);
+ return 1;
+ }
+
+ if (!DBGetContactSetting(ccs->hContact, yahooProtocolName, YAHOO_LOGINID, &dbv)) {
+ yahoo_send_msg(dbv.pszVal, msg, 0);
+ DBFreeVariant(&dbv);
+
+ pthread_create(yahoo_im_sendacksuccess, ccs->hContact);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+int YahooSendMessageW(WPARAM wParam, LPARAM lParam)
+{
+ CCSDATA *ccs = (CCSDATA *) lParam;
+ DBVARIANT dbv;
+
+ if (!yahooLoggedIn) {/* don't send message if we not connected! */
+ pthread_create(yahoo_im_sendackfail, ccs->hContact);
+ return 1;
+ }
+
+
+ if (!DBGetContactSetting(ccs->hContact, yahooProtocolName, YAHOO_LOGINID, &dbv)) {
+ char* p = ( char* )ccs->lParam;
+ char* msg = Utf8EncodeUcs2(( wchar_t* )&p[ strlen(p)+1 ] );
+
+ if (lstrlen(msg) > 800) {/* don't send message if we not connected! */
+ pthread_create(yahoo_im_sendackfail_longmsg, ccs->hContact);
+ } else {
+ yahoo_send_msg(dbv.pszVal, msg, 1);
+ pthread_create(yahoo_im_sendacksuccess, ccs->hContact);
+ }
+
+ DBFreeVariant(&dbv);
+ free(msg);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+//=======================================================
+//Receive a message
+//=======================================================
+int YahooRecvMessage(WPARAM wParam, LPARAM lParam)
+{
+ DBEVENTINFO dbei;
+ CCSDATA *ccs = (CCSDATA *) lParam;
+ PROTORECVEVENT *pre = (PROTORECVEVENT *) ccs->lParam;
+
+ DBDeleteContactSetting(ccs->hContact, "CList", "Hidden");
+
+ // NUDGES
+ if( !lstrcmp(pre->szMessage, "<ding>") && ServiceExists("NUDGE/Send")){
+ YAHOO_DebugLog("[YahooRecvMessage] Doing Nudge Service!");
+ NotifyEventHooks(hYahooNudge, (WPARAM) ccs->hContact, 0);
+ return 0;
+ }
+
+ ZeroMemory(&dbei, sizeof(dbei));
+ dbei.cbSize = sizeof(dbei);
+ dbei.szModule = yahooProtocolName;
+ dbei.timestamp = pre->timestamp;
+ dbei.flags = pre->flags & (PREF_CREATEREAD ? DBEF_READ : 0);
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ dbei.cbBlob = (!lstrcmp(pre->szMessage, "<ding>"))? lstrlen("BUZZ!!!")+1:lstrlen(pre->szMessage) + 1;
+ if ( pre->flags & PREF_UNICODE )
+ dbei.cbBlob *= ( sizeof( wchar_t )+1 );
+
+
+ dbei.pBlob = (PBYTE) (!lstrcmp(pre->szMessage, "<ding>"))? "BUZZ!!!":pre->szMessage;
+ CallService(MS_DB_EVENT_ADD, (WPARAM) ccs->hContact, (LPARAM) & dbei);
+ return 0;
+}
+
+//=======================================================
+//Send a nudge
+//=======================================================
+int YahooSendNudge(WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hContact = (HANDLE) wParam;
+ DBVARIANT dbv;
+
+ YAHOO_DebugLog("[YAHOO_SENDNUDGE]");
+
+ if (!yahooLoggedIn) {/* don't send nudge if we not connected! */
+ pthread_create(yahoo_im_sendackfail, hContact);
+ return 1;
+ }
+
+ if (!DBGetContactSetting(hContact, yahooProtocolName, YAHOO_LOGINID, &dbv)) {
+ yahoo_send_msg(dbv.pszVal, "<ding>", 0);
+ DBFreeVariant(&dbv);
+
+ pthread_create(yahoo_im_sendacksuccess, hContact);
+
+ return 1;
+ }
+
+ return 0;
+}
+
diff --git a/miranda-wine/protocols/Yahoo/im.h b/miranda-wine/protocols/Yahoo/im.h
new file mode 100644
index 0000000..2c6a509
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/im.h
@@ -0,0 +1,23 @@
+/*
+ * $Id: im.h 3632 2006-08-28 20:33:30Z gena01 $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+#ifndef _YAHOO_IM_H_
+#define _YAHOO_IM_H_
+
+void ext_yahoo_got_im(int id, const char *me, const char *who, const char *msg, long tm, int stat, int utf8, int buddy_icon);
+
+int YahooSendNudge(WPARAM wParam, LPARAM lParam);
+int YahooRecvMessage(WPARAM wParam, LPARAM lParam);
+int YahooSendMessageW(WPARAM wParam, LPARAM lParam);
+int YahooSendMessage(WPARAM wParam, LPARAM lParam);
+
+#endif
diff --git a/miranda-wine/protocols/Yahoo/libyahoo2/config.h b/miranda-wine/protocols/Yahoo/libyahoo2/config.h
new file mode 100644
index 0000000..de46a4f
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/libyahoo2/config.h
@@ -0,0 +1,35 @@
+#define HAVE_STRING_H 1
+#define STDC_HEADERS 1
+#define HAVE_STRCHR 1
+#define HAVE_MEMCPY 1
+
+#define PACKAGE "libyahoo2"
+#define VERSION "0.7.5"
+
+/* Add some WIN32 size savers */
+#include <windows.h>
+#include <stdio.h>
+
+#define strlen lstrlen
+#define strcat lstrcat
+#define strcmp lstrcmp
+#define strcpy lstrcpy
+
+#ifdef _MSC_VER
+
+#define strncasecmp strnicmp
+
+#define wsnprintf _wsnprintf
+#define snprintf _snprintf
+#define vsnprintf _vsnprintf
+
+#endif
+
+#define USE_STRUCT_CALLBACKS
+
+#define write(a,b,c) send(a,b,c,0)
+#define read(a,b,c) recv(a,b,c,0)
+
+#include <newpluginapi.h>
+#include <m_netlib.h>
+#define close(a) Netlib_CloseHandle((HANDLE)a)
diff --git a/miranda-wine/protocols/Yahoo/libyahoo2/crypt.c b/miranda-wine/protocols/Yahoo/libyahoo2/crypt.c
new file mode 100644
index 0000000..981be0d
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/libyahoo2/crypt.c
@@ -0,0 +1,207 @@
+/* One way encryption based on MD5 sum.
+ Copyright (C) 1996, 1997, 1999, 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/* warmenhoven took this file and made it work with the md5.[ch] we
+ * already had. isn't that lovely. people should just use linux or
+ * freebsd, crypt works properly on those systems. i hate solaris */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#if HAVE_STRING_H
+# include <string.h>
+#elif HAVE_STRINGS_H
+# include <strings.h>
+#endif
+
+#include <stdlib.h>
+#include "yahoo_util.h"
+
+#include "md5.h"
+
+/* Define our magic string to mark salt for MD5 "encryption"
+ replacement. This is meant to be the same as for other MD5 based
+ encryption implementations. */
+static const char md5_salt_prefix[] = "$1$";
+
+/* Table with characters for base64 transformation. */
+static const char b64t[64] =
+"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+char *yahoo_crypt(char *key, char *salt)
+{
+ char *buffer = NULL;
+ int buflen = 0;
+ int needed = 3 + strlen (salt) + 1 + 26 + 1;
+
+ md5_byte_t alt_result[16];
+ md5_state_t ctx;
+ md5_state_t alt_ctx;
+ size_t salt_len;
+ size_t key_len;
+ size_t cnt;
+ char *cp;
+
+ if (buflen < needed) {
+ buflen = needed;
+ if ((buffer = realloc(buffer, buflen)) == NULL)
+ return NULL;
+ }
+
+ /* Find beginning of salt string. The prefix should normally always
+ be present. Just in case it is not. */
+ if (strncmp (md5_salt_prefix, salt, sizeof (md5_salt_prefix) - 1) == 0)
+ /* Skip salt prefix. */
+ salt += sizeof (md5_salt_prefix) - 1;
+
+ salt_len = MIN (strcspn (salt, "$"), 8);
+ key_len = strlen (key);
+
+ /* Prepare for the real work. */
+ md5_init(&ctx);
+
+ /* Add the key string. */
+ md5_append(&ctx, (md5_byte_t *)key, key_len);
+
+ /* Because the SALT argument need not always have the salt prefix we
+ add it separately. */
+ md5_append(&ctx, (md5_byte_t *)md5_salt_prefix, sizeof (md5_salt_prefix) - 1);
+
+ /* The last part is the salt string. This must be at most 8
+ characters and it ends at the first `$' character (for
+ compatibility which existing solutions). */
+ md5_append(&ctx, (md5_byte_t *)salt, salt_len);
+
+ /* Compute alternate MD5 sum with input KEY, SALT, and KEY. The
+ final result will be added to the first context. */
+ md5_init(&alt_ctx);
+
+ /* Add key. */
+ md5_append(&alt_ctx, (md5_byte_t *)key, key_len);
+
+ /* Add salt. */
+ md5_append(&alt_ctx, (md5_byte_t *)salt, salt_len);
+
+ /* Add key again. */
+ md5_append(&alt_ctx, (md5_byte_t *)key, key_len);
+
+ /* Now get result of this (16 bytes) and add it to the other
+ context. */
+ md5_finish(&alt_ctx, alt_result);
+
+ /* Add for any character in the key one byte of the alternate sum. */
+ for (cnt = key_len; cnt > 16; cnt -= 16)
+ md5_append(&ctx, alt_result, 16);
+ md5_append(&ctx, alt_result, cnt);
+
+ /* For the following code we need a NUL byte. */
+ alt_result[0] = '\0';
+
+ /* The original implementation now does something weird: for every 1
+ bit in the key the first 0 is added to the buffer, for every 0
+ bit the first character of the key. This does not seem to be
+ what was intended but we have to follow this to be compatible. */
+ for (cnt = key_len; cnt > 0; cnt >>= 1)
+ md5_append(&ctx, (cnt & 1) != 0 ? alt_result : (md5_byte_t *)key, 1);
+
+ /* Create intermediate result. */
+ md5_finish(&ctx, alt_result);
+
+ /* Now comes another weirdness. In fear of password crackers here
+ comes a quite long loop which just processes the output of the
+ previous round again. We cannot ignore this here. */
+ for (cnt = 0; cnt < 1000; ++cnt) {
+ /* New context. */
+ md5_init(&ctx);
+
+ /* Add key or last result. */
+ if ((cnt & 1) != 0)
+ md5_append(&ctx, (md5_byte_t *)key, key_len);
+ else
+ md5_append(&ctx, alt_result, 16);
+
+ /* Add salt for numbers not divisible by 3. */
+ if (cnt % 3 != 0)
+ md5_append(&ctx, (md5_byte_t *)salt, salt_len);
+
+ /* Add key for numbers not divisible by 7. */
+ if (cnt % 7 != 0)
+ md5_append(&ctx, (md5_byte_t *)key, key_len);
+
+ /* Add key or last result. */
+ if ((cnt & 1) != 0)
+ md5_append(&ctx, alt_result, 16);
+ else
+ md5_append(&ctx, (md5_byte_t *)key, key_len);
+
+ /* Create intermediate result. */
+ md5_finish(&ctx, alt_result);
+ }
+
+ /* Now we can construct the result string. It consists of three
+ parts. */
+
+ strncpy(buffer, md5_salt_prefix, MAX (0, buflen));
+ cp = buffer + strlen(buffer);
+ buflen -= sizeof (md5_salt_prefix);
+
+ strncpy(cp, salt, MIN ((size_t) buflen, salt_len));
+ cp = cp + strlen(cp);
+ buflen -= MIN ((size_t) buflen, salt_len);
+
+ if (buflen > 0) {
+ *cp++ = '$';
+ --buflen;
+ }
+
+#define b64_from_24bit(B2, B1, B0, N) \
+ do { \
+ unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0); \
+ int n = (N); \
+ while (n-- > 0 && buflen > 0) { \
+ *cp++ = b64t[w & 0x3f]; \
+ --buflen; \
+ w >>= 6; \
+ }\
+ } while (0)
+
+ b64_from_24bit (alt_result[0], alt_result[6], alt_result[12], 4);
+ b64_from_24bit (alt_result[1], alt_result[7], alt_result[13], 4);
+ b64_from_24bit (alt_result[2], alt_result[8], alt_result[14], 4);
+ b64_from_24bit (alt_result[3], alt_result[9], alt_result[15], 4);
+ b64_from_24bit (alt_result[4], alt_result[10], alt_result[5], 4);
+ b64_from_24bit (0, 0, alt_result[11], 2);
+ if (buflen <= 0) {
+ FREE(buffer);
+ } else
+ *cp = '\0'; /* Terminate the string. */
+
+ /* Clear the buffer for the intermediate result so that people
+ attaching to processes or reading core dumps cannot get any
+ information. We do it in this way to clear correct_words[]
+ inside the MD5 implementation as well. */
+ md5_init(&ctx);
+ md5_finish(&ctx, alt_result);
+ memset (&ctx, '\0', sizeof (ctx));
+ memset (&alt_ctx, '\0', sizeof (alt_ctx));
+
+ return buffer;
+}
diff --git a/miranda-wine/protocols/Yahoo/libyahoo2/libyahoo2.c b/miranda-wine/protocols/Yahoo/libyahoo2/libyahoo2.c
new file mode 100644
index 0000000..d749d62
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/libyahoo2/libyahoo2.c
@@ -0,0 +1,6319 @@
+/*
+ * libyahoo2: libyahoo2.c
+ *
+ * Some code copyright (C) 2002-2004, Philip S Tellis <philip.tellis AT gmx.net>
+ *
+ * Yahoo Search copyright (C) 2003, Konstantin Klyagin <konst AT konst.org.ua>
+ *
+ * Much of this code was taken and adapted from the yahoo module for
+ * gaim released under the GNU GPL. This code is also released under the
+ * GNU GPL.
+ *
+ * This code is derivitive of Gaim <http://gaim.sourceforge.net>
+ * copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
+ * 1998-1999, Adam Fritzler <afritz@marko.net>
+ * 1998-2002, Rob Flynn <rob@marko.net>
+ * 2000-2002, Eric Warmenhoven <eric@warmenhoven.org>
+ * 2001-2002, Brian Macke <macke@strangelove.net>
+ * 2001, Anand Biligiri S <abiligiri@users.sf.net>
+ * 2001, Valdis Kletnieks
+ * 2002, Sean Egan <bj91704@binghamton.edu>
+ * 2002, Toby Gray <toby.gray@ntlworld.com>
+ *
+ * This library also uses code from other libraries, namely:
+ * Portions from libfaim copyright 1998, 1999 Adam Fritzler
+ * <afritz@auk.cx>
+ * Portions of Sylpheed copyright 2000-2002 Hiroyuki Yamamoto
+ * <hiro-y@kcn.ne.jp>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifndef _WIN32
+# include <unistd.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#if STDC_HEADERS
+# include <string.h>
+#else
+# if !HAVE_STRCHR
+# define strchr index
+# define strrchr rindex
+# endif
+char *strchr (), *strrchr ();
+# if !HAVE_MEMCPY
+# define memcpy(d, s, n) bcopy ((s), (d), (n))
+# define memmove(d, s, n) bcopy ((s), (d), (n))
+# endif
+#endif
+
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "sha.h"
+#include "md5.h"
+#include "yahoo2.h"
+#include "yahoo_httplib.h"
+#include "yahoo_util.h"
+#include "yahoo_fn.h"
+
+#include "yahoo2_callbacks.h"
+#include "yahoo_debug.h"
+
+#ifdef USE_STRUCT_CALLBACKS
+struct yahoo_callbacks *yc=NULL;
+
+void yahoo_register_callbacks(struct yahoo_callbacks * tyc)
+{
+ yc = tyc;
+}
+
+#define YAHOO_CALLBACK(x) yc->x
+#else
+#define YAHOO_CALLBACK(x) x
+#endif
+
+static int yahoo_send_data(int fd, void *data, int len);
+
+int yahoo_log_message(char * fmt, ...)
+{
+ char out[1024];
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(out, sizeof(out), fmt, ap);
+ va_end(ap);
+ return YAHOO_CALLBACK(ext_yahoo_log)("%s", out);
+}
+
+int yahoo_connect(char * host, int port, int type)
+{
+ return YAHOO_CALLBACK(ext_yahoo_connect)(host, port, type);
+}
+
+static enum yahoo_log_level log_level = YAHOO_LOG_NONE;
+
+enum yahoo_log_level yahoo_get_log_level()
+{
+ return log_level;
+}
+
+int yahoo_set_log_level(enum yahoo_log_level level)
+{
+ enum yahoo_log_level l = log_level;
+ log_level = level;
+ return l;
+}
+
+/* default values for servers */
+static char pager_host[] = "scs.msg.yahoo.com";
+static int pager_port = 5050;
+static int fallback_ports[]={23, 25, 80, 20, 119, 8001, 8002, 5050, 0};
+static char filetransfer_host[]="filetransfer.msg.yahoo.com";
+static int filetransfer_port=80;
+static char webcam_host[]="webcam.yahoo.com";
+static int webcam_port=5100;
+static char webcam_description[]="";
+static char local_host[]="";
+static int conn_type=Y_WCM_DSL;
+
+static char profile_url[] = "http://profiles.yahoo.com/";
+
+enum yahoo_service { /* these are easier to see in hex */
+ YAHOO_SERVICE_LOGON = 1,
+ YAHOO_SERVICE_LOGOFF,
+ YAHOO_SERVICE_ISAWAY,
+ YAHOO_SERVICE_ISBACK,
+ YAHOO_SERVICE_IDLE, /* 5 (placemarker) */
+ YAHOO_SERVICE_MESSAGE,
+ YAHOO_SERVICE_IDACT,
+ YAHOO_SERVICE_IDDEACT,
+ YAHOO_SERVICE_MAILSTAT,
+ YAHOO_SERVICE_USERSTAT, /* 0xa */
+ YAHOO_SERVICE_NEWMAIL,
+ YAHOO_SERVICE_CHATINVITE,
+ YAHOO_SERVICE_CALENDAR,
+ YAHOO_SERVICE_NEWPERSONALMAIL,
+ YAHOO_SERVICE_NEWCONTACT,
+ YAHOO_SERVICE_ADDIDENT, /* 0x10 */
+ YAHOO_SERVICE_ADDIGNORE,
+ YAHOO_SERVICE_PING,
+ YAHOO_SERVICE_GOTGROUPRENAME, /* < 1, 36(old), 37(new) */
+ YAHOO_SERVICE_SYSMESSAGE = 0x14,
+ YAHOO_SERVICE_SKINNAME = 0x15,
+ YAHOO_SERVICE_PASSTHROUGH2 = 0x16,
+ YAHOO_SERVICE_CONFINVITE = 0x18,
+ YAHOO_SERVICE_CONFLOGON,
+ YAHOO_SERVICE_CONFDECLINE,
+ YAHOO_SERVICE_CONFLOGOFF,
+ YAHOO_SERVICE_CONFADDINVITE,
+ YAHOO_SERVICE_CONFMSG,
+ YAHOO_SERVICE_CHATLOGON,
+ YAHOO_SERVICE_CHATLOGOFF,
+ YAHOO_SERVICE_CHATMSG = 0x20,
+ YAHOO_SERVICE_GAMELOGON = 0x28,
+ YAHOO_SERVICE_GAMELOGOFF,
+ YAHOO_SERVICE_GAMEMSG = 0x2a,
+ YAHOO_SERVICE_FILETRANSFER = 0x46,
+ YAHOO_SERVICE_VOICECHAT = 0x4A,
+ YAHOO_SERVICE_NOTIFY,
+ YAHOO_SERVICE_VERIFY,
+ YAHOO_SERVICE_P2PFILEXFER,
+ YAHOO_SERVICE_PEERTOPEER = 0x4F, /* Checks if P2P possible */
+ YAHOO_SERVICE_WEBCAM,
+ YAHOO_SERVICE_AUTHRESP = 0x54,
+ YAHOO_SERVICE_LIST,
+ YAHOO_SERVICE_AUTH = 0x57,
+ YAHOO_SERVICE_ADDBUDDY = 0x83,
+ YAHOO_SERVICE_REMBUDDY,
+ YAHOO_SERVICE_IGNORECONTACT, /* > 1, 7, 13 < 1, 66, 13, 0*/
+ YAHOO_SERVICE_REJECTCONTACT,
+ YAHOO_SERVICE_GROUPRENAME = 0x89, /* > 1, 65(new), 66(0), 67(old) */
+ /* YAHOO_SERVICE_??? = 0x8A, ?? 0 - id and that's it?? */
+ YAHOO_SERVICE_CHATONLINE = 0x96, /* > 109(id), 1, 6(abcde) < 0,1*/
+ YAHOO_SERVICE_CHATGOTO,
+ YAHOO_SERVICE_CHATJOIN, /* > 1 104-room 129-1600326591 62-2 */
+ YAHOO_SERVICE_CHATLEAVE,
+ YAHOO_SERVICE_CHATEXIT = 0x9b,
+ YAHOO_SERVICE_CHATADDINVITE = 0x9d,
+ YAHOO_SERVICE_CHATLOGOUT = 0xa0,
+ YAHOO_SERVICE_CHATPING,
+ YAHOO_SERVICE_COMMENT = 0xa8,
+ YAHOO_SERVICE_GAME_INVITE = 0xb7,
+ YAHOO_SERVICE_STEALTH_PERM = 0xb9,
+ YAHOO_SERVICE_STEALTH_SESSION = 0xba,
+ YAHOO_SERVICE_AVATAR = 0xbc,
+ YAHOO_SERVICE_PICTURE_CHECKSUM = 0xbd,
+ YAHOO_SERVICE_PICTURE = 0xbe,
+ YAHOO_SERVICE_PICTURE_UPDATE = 0xc1,
+ YAHOO_SERVICE_PICTURE_UPLOAD = 0xc2,
+ YAHOO_SERVICE_YAB_UPDATE = 0xc4,
+ YAHOO_SERVICE_Y6_VISIBLE_TOGGLE = 0xc5, /* YMSG13, key 13: 2 = invisible, 1 = visible */
+ YAHOO_SERVICE_Y6_STATUS_UPDATE = 0xc6, /* YMSG13 */
+ /* Kopete Calls YAHOO_SERVICE_AVATAR_UPDATE = ServicePictureStatus ? */
+ YAHOO_SERVICE_AVATAR_UPDATE = 0xc7, /* YMSG13, key 213: 0 = none, 1 = avatar, 2 = picture */
+ YAHOO_SERVICE_VERIFY_ID_EXISTS = 0xc8,
+ YAHOO_SERVICE_AUDIBLE = 0xd0,
+ YAHOO_SERVICE_Y7_PHOTO_SHARING = 0xd2,
+ YAHOO_SERVICE_Y7_CONTACT_DETAILS = 0xd3, /* YMSG13 */
+ YAHOO_SERVICE_Y7_CHAT_SESSION = 0xd4,
+ YAHOO_SERVICE_Y7_AUTHORIZATION = 0xd6, /* YMSG13 */
+ YAHOO_SERVICE_Y7_FILETRANSFER = 0xdc, /* YMSG13 */
+ YAHOO_SERVICE_Y7_FILETRANSFERINFO, /* YMSG13 */
+ YAHOO_SERVICE_Y7_FILETRANSFERACCEPT, /* YMSG13 */
+ YAHOO_SERVICE_Y7_CHANGE_GROUP = 0xe7, /* YMSG13 */
+ YAHOO_SERVICE_WEBLOGIN = 0x0226,
+ YAHOO_SERVICE_SMS_MSG = 0x02ea
+};
+
+typedef struct {
+ int key;
+ char *name;
+}value_string;
+
+static const value_string ymsg_service_vals[] = {
+ {YAHOO_SERVICE_LOGON, "Pager Logon"},
+ {YAHOO_SERVICE_LOGOFF, "Pager Logoff"},
+ {YAHOO_SERVICE_ISAWAY, "Is Away"},
+ {YAHOO_SERVICE_ISBACK, "Is Back"},
+ {YAHOO_SERVICE_IDLE, "Idle"},
+ {YAHOO_SERVICE_MESSAGE, "Message"},
+ {YAHOO_SERVICE_IDACT, "Activate Identity"},
+ {YAHOO_SERVICE_IDDEACT, "Deactivate Identity"},
+ {YAHOO_SERVICE_MAILSTAT, "Mail Status"},
+ {YAHOO_SERVICE_USERSTAT, "User Status"},
+ {YAHOO_SERVICE_NEWMAIL, "New Mail"},
+ {YAHOO_SERVICE_CHATINVITE, "Chat Invitation"},
+ {YAHOO_SERVICE_CALENDAR, "Calendar Reminder"},
+ {YAHOO_SERVICE_NEWPERSONALMAIL, "New Personals Mail"},
+ {YAHOO_SERVICE_NEWCONTACT, "New Friend"},
+ {YAHOO_SERVICE_ADDIDENT, "Add Identity"},
+ {YAHOO_SERVICE_ADDIGNORE, "Add Ignore"},
+ {YAHOO_SERVICE_PING, "Ping"},
+ {YAHOO_SERVICE_GOTGROUPRENAME, "YAHOO_SERVICE_GOTGROUPRENAME"},
+ {YAHOO_SERVICE_SYSMESSAGE, "System Message"},
+ {YAHOO_SERVICE_PASSTHROUGH2, "Passthrough 2"},
+ {YAHOO_SERVICE_CONFINVITE, "Conference Invitation"},
+ {YAHOO_SERVICE_CONFLOGON, "Conference Logon"},
+ {YAHOO_SERVICE_CONFDECLINE, "Conference Decline"},
+ {YAHOO_SERVICE_CONFLOGOFF, "Conference Logoff"},
+ {YAHOO_SERVICE_CONFADDINVITE, "Conference Additional Invitation"},
+ {YAHOO_SERVICE_CONFMSG, "Conference Message"},
+ {YAHOO_SERVICE_CHATLOGON, "Chat Logon"},
+ {YAHOO_SERVICE_CHATLOGOFF, "Chat Logoff"},
+ {YAHOO_SERVICE_CHATMSG, "Chat Message"},
+ {YAHOO_SERVICE_GAMELOGON, "Game Logon"},
+ {YAHOO_SERVICE_GAMELOGOFF, "Game Logoff"},
+ {YAHOO_SERVICE_GAMEMSG, "Game Message"},
+ {YAHOO_SERVICE_FILETRANSFER, "File Transfer"},
+ {YAHOO_SERVICE_VOICECHAT, "Voice Chat"},
+ {YAHOO_SERVICE_NOTIFY, "YAHOO_SERVICE_NOTIFY"},
+ {YAHOO_SERVICE_VERIFY, "YAHOO_SERVICE_VERIFY"},
+ {YAHOO_SERVICE_P2PFILEXFER, "YAHOO_SERVICE_P2PFILEXFER"},
+ {YAHOO_SERVICE_PEERTOPEER, "YAHOO_SERVICE_PEERTOPEER"},
+ {YAHOO_SERVICE_AUTHRESP, "YAHOO_SERVICE_AUTHRESP"},
+ {YAHOO_SERVICE_LIST, "YAHOO_SERVICE_LIST"},
+ {YAHOO_SERVICE_AUTH, "YAHOO_SERVICE_AUTH"},
+ {YAHOO_SERVICE_ADDBUDDY, "YAHOO_SERVICE_ADDBUDDY"},
+ {YAHOO_SERVICE_REMBUDDY, "YAHOO_SERVICE_REMBUDDY"},
+ {YAHOO_SERVICE_IGNORECONTACT, "YAHOO_SERVICE_IGNORECONTACT"},
+ {YAHOO_SERVICE_REJECTCONTACT, "YAHOO_SERVICE_REJECTCONTACT"},
+ {YAHOO_SERVICE_GROUPRENAME, "Group Renamed"},
+ {YAHOO_SERVICE_CHATONLINE, "YAHOO_SERVICE_CHATONLINE"},
+ {YAHOO_SERVICE_CHATGOTO, "YAHOO_SERVICE_CHATGOTO"},
+ {YAHOO_SERVICE_CHATJOIN, "YAHOO_SERVICE_CHATJOIN"},
+ {YAHOO_SERVICE_CHATLEAVE, "YAHOO_SERVICE_CHATLEAVE"},
+ {YAHOO_SERVICE_CHATEXIT, "YAHOO_SERVICE_CHATEXIT"},
+ {YAHOO_SERVICE_CHATLOGOUT, "YAHOO_SERVICE_CHATLOGOUT"},
+ {YAHOO_SERVICE_CHATPING, "YAHOO_SERVICE_CHATPING"},
+ {YAHOO_SERVICE_COMMENT, "YAHOO_SERVICE_COMMENT"},
+ {YAHOO_SERVICE_GAME_INVITE,"YAHOO_SERVICE_GAME_INVITE "},
+ {YAHOO_SERVICE_STEALTH_PERM, "YAHOO_SERVICE_STEALTH_PERM"},
+ {YAHOO_SERVICE_STEALTH_SESSION, "YAHOO_SERVICE_STEALTH_SESSION"},
+ {YAHOO_SERVICE_AVATAR,"YAHOO_SERVICE_AVATAR"},
+ {YAHOO_SERVICE_PICTURE_CHECKSUM,"YAHOO_SERVICE_PICTURE_CHECKSUM"},
+ {YAHOO_SERVICE_PICTURE,"YAHOO_SERVICE_PICTURE"},
+ {YAHOO_SERVICE_YAB_UPDATE,"YAHOO_SERVICE_YAB_UPDATE"},
+ {YAHOO_SERVICE_PICTURE_UPDATE,"YAHOO_SERVICE_PICTURE_UPDATE"},
+ {YAHOO_SERVICE_PICTURE_UPLOAD,"YAHOO_SERVICE_PICTURE_UPLOAD"},
+ {YAHOO_SERVICE_Y6_VISIBLE_TOGGLE, "YAHOO_SERVICE_Y6_VISIBLE_TOGGLE"},
+ {YAHOO_SERVICE_Y6_STATUS_UPDATE,"YAHOO_SERVICE_Y6_STATUS_UPDATE"},
+ {YAHOO_SERVICE_AVATAR_UPDATE,"YAHOO_SERVICE_AVATAR_UPDATE"},
+ {YAHOO_SERVICE_AUDIBLE,"YAHOO_SERVICE_AUDIBLE"},
+ {YAHOO_SERVICE_Y7_CONTACT_DETAILS,"YAHOO_SERVICE_Y7_CONTACT_DETAILS"},
+ {YAHOO_SERVICE_Y7_CHAT_SESSION, "YAHOO_SERVICE_Y7_CHAT_SESSION"},
+ {YAHOO_SERVICE_Y7_AUTHORIZATION,"YAHOO_SERVICE_Y7_AUTHORIZATION"},
+ {YAHOO_SERVICE_Y7_FILETRANSFER,"YAHOO_SERVICE_Y7_FILETRANSFER"},
+ {YAHOO_SERVICE_Y7_FILETRANSFERINFO,"YAHOO_SERVICE_Y7_FILETRANSFERINFO"},
+ {YAHOO_SERVICE_Y7_FILETRANSFERACCEPT,"YAHOO_SERVICE_Y7_FILETRANSFERACCEPT"},
+ {YAHOO_SERVICE_Y7_CHANGE_GROUP, "YAHOO_SERVICE_Y7_CHANGE_GROUP"},
+ {YAHOO_SERVICE_WEBLOGIN,"YAHOO_SERVICE_WEBLOGIN"},
+ {YAHOO_SERVICE_SMS_MSG,"YAHOO_SERVICE_SMS_MSG"},
+ {0, NULL}
+};
+
+static const value_string ymsg_status_vals[] = {
+ {YAHOO_STATUS_DISCONNECTED, "YAHOO_STATUS_DISCONNECTED"},
+ {YAHOO_STATUS_AVAILABLE, "YAHOO_STATUS_AVAILABLE"},
+ {YAHOO_STATUS_BRB, "YAHOO_STATUS_BRB"},
+ {YAHOO_STATUS_BUSY, "YAHOO_STATUS_BUSY"},
+ {YAHOO_STATUS_NOTATHOME, "YAHOO_STATUS_NOTATHOME"},
+ {YAHOO_STATUS_NOTATDESK, "YAHOO_STATUS_NOTATDESK"},
+ {YAHOO_STATUS_NOTINOFFICE, "YAHOO_STATUS_NOTINOFFICE"},
+ {YAHOO_STATUS_ONPHONE, "YAHOO_STATUS_ONPHONE"},
+ {YAHOO_STATUS_ONVACATION, "YAHOO_STATUS_ONVACATION"},
+ {YAHOO_STATUS_OUTTOLUNCH, "YAHOO_STATUS_OUTTOLUNCH"},
+ {YAHOO_STATUS_STEPPEDOUT, "YAHOO_STATUS_STEPPEDOUT"},
+ {YAHOO_STATUS_INVISIBLE, "YAHOO_STATUS_INVISIBLE"},
+ {YAHOO_STATUS_CUSTOM, "YAHOO_STATUS_CUSTOM"},
+ {YAHOO_STATUS_IDLE, "YAHOO_STATUS_IDLE"},
+ {YAHOO_STATUS_OFFLINE, "YAHOO_STATUS_OFFLINE"},
+ {YAHOO_STATUS_NOTIFY, "YAHOO_STATUS_NOTIFY"},
+ {YAHOO_STATUS_WEBLOGIN, "YAHOO_STATUS_WEBLOGIN"},
+ {0, NULL}
+};
+
+static const value_string packet_keys[]={
+ { 0, "identity" },
+ { 1, "ID" },
+ { 2, "id?" },
+ { 3, "my id"},
+ { 4, "ID/Nick"},
+ { 5, "To"},
+ { 6, "auth token 1"},
+ { 7, "Buddy" },
+ { 8, "# buddies"},
+ { 9, "# mails"},
+ { 10, "state"},
+ { 11, "session"},
+ { 12, "reverse ip? [gaim]"},
+ { 13, "stat/location"}, // bitnask: 0 = pager, 1 = chat, 2 = game
+ { 14, "ind/msg"},
+ { 15, "time"},
+ { 16, "Error msg"},
+ { 17, "chat"},
+ { 18, "subject/topic?"},
+ { 19, "custom msg"},
+ { 20, "url"},
+ { 24, "session timestamp"},
+ { 27, "filename"},
+ { 28, "filesize"},
+ { 31, "visibility?"},
+ { 38, "expires"},
+ { 42, "email"},
+ { 43, "email who"},
+ { 47, "away"},
+ { 49, "service"},
+ { 50, "conf host"},
+ { 52, "conf invite"},
+ { 53, "conf logon"},
+ { 54, "conf decline"},
+ { 55, "conf unavail"},
+ { 56, "conf logoff"},
+ { 57, "conf room"},
+ { 58, "conf joinmsg"},
+ { 59, "cookies"},
+ { 60, "SMS/Mobile"},
+ { 61, "Cookie?"},
+ { 63, "imvironment name;num"},
+ { 64, "imvironment enabled/avail"},
+ { 65, "group"},
+ { 66, "login status"},
+ { 73, "user name"},
+ { 87, "buds/groups"},
+ { 88, "ignore list"},
+ { 89, "identities"},
+ { 94, "auth seed"},
+ { 96, "auth token 2"},
+ { 97, "utf8"},
+ {104, "room name"},
+ {105, "chat topic"},
+ {108, "chat nbuddies"},
+ {109, "chat from"},
+ {110, "chat age"},
+ {113, "chat attrs"},
+ {117, "chat msg"},
+ {124, "chat msg type"},
+ {128, "chat room category?"},
+ {129, "chat room serial 2"},
+ {130, "first join/chat room cookie"},
+ {135, "YIM version"},
+ {137, "idle time"},
+ {138, "idle?"},
+ {142, "chat location"},
+ {185, "stealth/hide?"},
+ {192, "Pictures/Buddy Icons"},
+ {197, "Avatars"},
+ {203, "YAB data?"},
+ {206, "display image type"},
+ {213, "share avatar type"},
+ {216, "first name"},
+ {219, "cookie separator?"},
+ {222, "FT7 Service"},
+ {223, "authorized?"},
+ {230, "the audible, in foo.bar.baz format"},
+ {231, "audible text"},
+ {232, "weird number (md5 hash?) [audible]"},
+ {244, "YIM6/YIM7 detection.(278527 - YIM6, 524223 - YIM7)"},
+ {254, "last name"},
+ {265, "FT7 Token"},
+ {1002, "YIM6+"},
+ {10093, "YIM7 (sets it to 4)"},
+ {10097, "Region (SMS?)"},
+ { -1, "" }
+};
+
+const char *dbg_key(int key)
+{
+ int i=0;
+
+ while ((packet_keys[i].key >=0) && (packet_keys[i].key != key) )
+ i++;
+
+ if (packet_keys[i].key != key)
+ return NULL;
+ else
+ return packet_keys[i].name;
+}
+
+const char *dbg_service(int key)
+{
+ int i=0;
+
+ while ((ymsg_service_vals[i].key > 0) && (ymsg_service_vals[i].key != key) )
+ i++;
+
+ if (ymsg_service_vals[i].key != key)
+ return NULL;
+ else
+ return ymsg_service_vals[i].name;
+}
+
+const char *dbg_status(int key)
+{
+ int i;
+
+ for (i = 0; ymsg_status_vals[i].name != NULL; i++ ) {
+ if (ymsg_status_vals[i].key == key)
+ return ymsg_status_vals[i].name;
+ }
+
+ return NULL;
+}
+
+struct yahoo_pair {
+ int key;
+ char *value;
+};
+
+struct yahoo_packet {
+ unsigned short int service;
+ unsigned int status;
+ unsigned int id;
+ YList *hash;
+};
+
+struct yahoo_search_state {
+ int lsearch_type;
+ char *lsearch_text;
+ int lsearch_gender;
+ int lsearch_agerange;
+ int lsearch_photo;
+ int lsearch_yahoo_only;
+ int lsearch_nstart;
+ int lsearch_nfound;
+ int lsearch_ntotal;
+};
+
+struct data_queue {
+ unsigned char *queue;
+ int len;
+};
+
+struct yahoo_input_data {
+ struct yahoo_data *yd;
+ struct yahoo_webcam *wcm;
+ struct yahoo_webcam_data *wcd;
+ struct yahoo_search_state *ys;
+
+ int fd;
+ enum yahoo_connection_type type;
+
+ unsigned char *rxqueue;
+ int rxlen;
+ int read_tag;
+
+ YList *txqueues;
+ int write_tag;
+};
+
+struct yahoo_server_settings {
+ char *pager_host;
+ int pager_port;
+ char *filetransfer_host;
+ int filetransfer_port;
+ char *webcam_host;
+ int webcam_port;
+ char *webcam_description;
+ char *local_host;
+ int conn_type;
+ int pic_cksum;
+ int web_messenger;
+};
+
+static void * _yahoo_default_server_settings()
+{
+ struct yahoo_server_settings *yss = y_new0(struct yahoo_server_settings, 1);
+
+ yss->pager_host = strdup(pager_host);
+ yss->pager_port = pager_port;
+ yss->filetransfer_host = strdup(filetransfer_host);
+ yss->filetransfer_port = filetransfer_port;
+ yss->webcam_host = strdup(webcam_host);
+ yss->webcam_port = webcam_port;
+ yss->webcam_description = strdup(webcam_description);
+ yss->local_host = strdup(local_host);
+ yss->conn_type = conn_type;
+ yss->pic_cksum = -1;
+
+ return yss;
+}
+
+static void * _yahoo_assign_server_settings(va_list ap)
+{
+ struct yahoo_server_settings *yss = _yahoo_default_server_settings();
+ char *key;
+ char *svalue;
+ int nvalue;
+
+ while(1) {
+ key = va_arg(ap, char *);
+ if(key == NULL)
+ break;
+
+ if(!strcmp(key, "pager_host")) {
+ svalue = va_arg(ap, char *);
+ free(yss->pager_host);
+ yss->pager_host = strdup(svalue);
+ } else if(!strcmp(key, "pager_port")) {
+ nvalue = va_arg(ap, int);
+ yss->pager_port = nvalue;
+ } else if(!strcmp(key, "filetransfer_host")) {
+ svalue = va_arg(ap, char *);
+ free(yss->filetransfer_host);
+ yss->filetransfer_host = strdup(svalue);
+ } else if(!strcmp(key, "filetransfer_port")) {
+ nvalue = va_arg(ap, int);
+ yss->filetransfer_port = nvalue;
+ } else if(!strcmp(key, "webcam_host")) {
+ svalue = va_arg(ap, char *);
+ free(yss->webcam_host);
+ yss->webcam_host = strdup(svalue);
+ } else if(!strcmp(key, "webcam_port")) {
+ nvalue = va_arg(ap, int);
+ yss->webcam_port = nvalue;
+ } else if(!strcmp(key, "webcam_description")) {
+ svalue = va_arg(ap, char *);
+ free(yss->webcam_description);
+ yss->webcam_description = strdup(svalue);
+ } else if(!strcmp(key, "local_host")) {
+ svalue = va_arg(ap, char *);
+ free(yss->local_host);
+ yss->local_host = strdup(svalue);
+ } else if(!strcmp(key, "conn_type")) {
+ nvalue = va_arg(ap, int);
+ yss->conn_type = nvalue;
+ } else if(!strcmp(key, "picture_checksum")) {
+ nvalue = va_arg(ap, int);
+ yss->pic_cksum = nvalue;
+ } else if(!strcmp(key, "web_messenger")) {
+ nvalue = va_arg(ap, int);
+ yss->web_messenger = nvalue;
+ } else {
+ WARNING(("Unknown key passed to yahoo_init, "
+ "perhaps you didn't terminate the list "
+ "with NULL"));
+ }
+ }
+
+ return yss;
+}
+
+static void yahoo_free_server_settings(struct yahoo_server_settings *yss)
+{
+ if(!yss)
+ return;
+
+ free(yss->pager_host);
+ free(yss->filetransfer_host);
+ free(yss->webcam_host);
+ free(yss->webcam_description);
+ free(yss->local_host);
+
+ free(yss);
+}
+
+static YList *conns=NULL;
+static YList *inputs=NULL;
+static int last_id=0;
+
+static void add_to_list(struct yahoo_data *yd)
+{
+ conns = y_list_prepend(conns, yd);
+}
+static struct yahoo_data * find_conn_by_id(int id)
+{
+ YList *l;
+ for(l = conns; l; l = y_list_next(l)) {
+ struct yahoo_data *yd = l->data;
+ if(yd->client_id == id)
+ return yd;
+ }
+ return NULL;
+}
+static void del_from_list(struct yahoo_data *yd)
+{
+ conns = y_list_remove(conns, yd);
+}
+
+/* call repeatedly to get the next one */
+/*
+static struct yahoo_input_data * find_input_by_id(int id)
+{
+ YList *l;
+ for(l = inputs; l; l = y_list_next(l)) {
+ struct yahoo_input_data *yid = l->data;
+ if(yid->yd->client_id == id)
+ return yid;
+ }
+ return NULL;
+}
+*/
+
+static struct yahoo_input_data * find_input_by_id_and_webcam_user(int id, const char * who)
+{
+ YList *l;
+ LOG(("find_input_by_id_and_webcam_user"));
+ for(l = inputs; l; l = y_list_next(l)) {
+ struct yahoo_input_data *yid = l->data;
+ if(yid->type == YAHOO_CONNECTION_WEBCAM && yid->yd->client_id == id
+ && yid->wcm &&
+ ((who && yid->wcm->user && !strcmp(who, yid->wcm->user)) ||
+ !(yid->wcm->user && !who)))
+ return yid;
+ }
+ return NULL;
+}
+
+static struct yahoo_input_data * find_input_by_id_and_type(int id, enum yahoo_connection_type type)
+{
+ YList *l;
+ LOG(("[find_input_by_id_and_type] id: %d, type: %d", id, type));
+ for(l = inputs; l; l = y_list_next(l)) {
+ struct yahoo_input_data *yid = l->data;
+ if(yid->type == type && yid->yd->client_id == id) {
+ LOG(("[find_input_by_id_and_type] Got it!!!"));
+ return yid;
+ }
+ }
+ return NULL;
+}
+
+static struct yahoo_input_data * find_input_by_id_and_fd(int id, int fd)
+{
+ YList *l;
+ LOG(("find_input_by_id_and_fd"));
+ for(l = inputs; l; l = y_list_next(l)) {
+ struct yahoo_input_data *yid = l->data;
+ if(yid->fd == fd && yid->yd->client_id == id)
+ return yid;
+ }
+ return NULL;
+}
+
+static int count_inputs_with_id(int id)
+{
+ int c=0;
+ YList *l;
+ LOG(("counting %d", id));
+ for(l = inputs; l; l = y_list_next(l)) {
+ struct yahoo_input_data *yid = l->data;
+ if(yid->yd->client_id == id)
+ c++;
+ }
+ LOG(("%d", c));
+ return c;
+}
+
+
+extern char *yahoo_crypt(char *, char *);
+
+/* Free a buddy list */
+static void yahoo_free_buddies(YList * list)
+{
+ YList *l;
+
+ for(l = list; l; l = l->next)
+ {
+ struct yahoo_buddy *bud = l->data;
+ if(!bud)
+ continue;
+
+ FREE(bud->group);
+ FREE(bud->id);
+ FREE(bud->real_name);
+ if(bud->yab_entry) {
+ FREE(bud->yab_entry->fname);
+ FREE(bud->yab_entry->lname);
+ FREE(bud->yab_entry->nname);
+ FREE(bud->yab_entry->id);
+ FREE(bud->yab_entry->email);
+ FREE(bud->yab_entry->hphone);
+ FREE(bud->yab_entry->wphone);
+ FREE(bud->yab_entry->mphone);
+ FREE(bud->yab_entry);
+ }
+ FREE(bud);
+ l->data = bud = NULL;
+ }
+
+ y_list_free(list);
+}
+
+/* Free an identities list */
+static void yahoo_free_identities(YList * list)
+{
+ while (list) {
+ YList *n = list;
+ FREE(list->data);
+ list = y_list_remove_link(list, list);
+ y_list_free_1(n);
+ }
+}
+
+/* Free webcam data */
+static void yahoo_free_webcam(struct yahoo_webcam *wcm)
+{
+ if (wcm) {
+ FREE(wcm->user);
+ FREE(wcm->server);
+ FREE(wcm->key);
+ FREE(wcm->description);
+ FREE(wcm->my_ip);
+ }
+ FREE(wcm);
+}
+
+static void yahoo_free_data(struct yahoo_data *yd)
+{
+ FREE(yd->user);
+ FREE(yd->password);
+ FREE(yd->cookie_y);
+ FREE(yd->cookie_t);
+ FREE(yd->cookie_c);
+ FREE(yd->login_cookie);
+ FREE(yd->login_id);
+ FREE(yd->rawstealthlist);
+
+ yahoo_free_buddies(yd->buddies);
+ yahoo_free_buddies(yd->ignore);
+ yahoo_free_identities(yd->identities);
+
+ yahoo_free_server_settings(yd->server_settings);
+
+ FREE(yd);
+}
+
+#define YAHOO_PACKET_HDRLEN (4 + 2 + 2 + 2 + 2 + 4 + 4)
+
+static struct yahoo_packet *yahoo_packet_new(enum yahoo_service service,
+ enum yahoo_status status, int id)
+{
+ struct yahoo_packet *pkt = y_new0(struct yahoo_packet, 1);
+
+ pkt->service = service;
+ pkt->status = status;
+ pkt->id = id;
+
+ return pkt;
+}
+
+static void yahoo_packet_hash(struct yahoo_packet *pkt, int key, const char *value)
+{
+ struct yahoo_pair *pair = y_new0(struct yahoo_pair, 1);
+ pair->key = key;
+ pair->value = strdup(value);
+ pkt->hash = y_list_append(pkt->hash, pair);
+}
+
+static int yahoo_packet_length(struct yahoo_packet *pkt)
+{
+ YList *l;
+
+ int len = 0;
+
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ int tmp = pair->key;
+ do {
+ tmp /= 10;
+ len++;
+ } while (tmp);
+ len += 2;
+ len += strlen(pair->value);
+ len += 2;
+ }
+
+ return len;
+}
+
+#define yahoo_put16(buf, data) ( \
+ (*(buf) = (unsigned char)((data)>>8)&0xff), \
+ (*((buf)+1) = (unsigned char)(data)&0xff), \
+ 2)
+#define yahoo_get16(buf) ((((*(buf))&0xff)<<8) + ((*((buf)+1)) & 0xff))
+#define yahoo_put32(buf, data) ( \
+ (*((buf)) = (unsigned char)((data)>>24)&0xff), \
+ (*((buf)+1) = (unsigned char)((data)>>16)&0xff), \
+ (*((buf)+2) = (unsigned char)((data)>>8)&0xff), \
+ (*((buf)+3) = (unsigned char)(data)&0xff), \
+ 4)
+#define yahoo_get32(buf) ((((*(buf) )&0xff)<<24) + \
+ (((*((buf)+1))&0xff)<<16) + \
+ (((*((buf)+2))&0xff)<< 8) + \
+ (((*((buf)+3))&0xff)))
+
+static void yahoo_packet_read(struct yahoo_packet *pkt, unsigned char *data, int len)
+{
+ int pos = 0;
+
+ DEBUG_MSG(("[Reading packet] len: %d", len));
+ while (pos + 1 < len) {
+ char *key, *value = NULL;
+ int accept;
+ int x;
+
+ struct yahoo_pair *pair = y_new0(struct yahoo_pair, 1);
+
+ key = malloc(len + 1);
+ x = 0;
+ while (pos + 1 < len) {
+ if (data[pos] == 0xc0 && data[pos + 1] == 0x80)
+ break;
+ key[x++] = data[pos++];
+ }
+ key[x] = 0;
+ pos += 2;
+ pair->key = strtol(key, NULL, 10);
+ free(key);
+
+ accept = x;
+ /* if x is 0 there was no key, so don't accept it */
+ if (accept)
+ value = malloc(len - pos + 1);
+ x = 0;
+ while (pos + 1 < len) {
+ if (data[pos] == 0xc0 && data[pos + 1] == 0x80)
+ break;
+ if (accept)
+ value[x++] = data[pos++];
+ }
+ if (accept)
+ value[x] = 0;
+ pos += 2;
+ if (accept) {
+ pair->value = strdup(value);
+ FREE(value);
+ pkt->hash = y_list_append(pkt->hash, pair);
+
+ DEBUG_MSG1(("Key: %s (%d) \tValue: '%s'", dbg_key(pair->key), pair->key, pair->value));
+ } else {
+ FREE(pair);
+ }
+ }
+
+ DEBUG_MSG(("[Reading packet done]"));
+}
+
+static void yahoo_packet_write(struct yahoo_packet *pkt, unsigned char *data)
+{
+ YList *l;
+ int pos = 0;
+
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ unsigned char buf[100];
+
+ snprintf((char *)buf, sizeof(buf), "%d", pair->key);
+ strcpy((char *)data + pos, (char *)buf);
+ pos += strlen((char *)buf);
+ data[pos++] = 0xc0;
+ data[pos++] = 0x80;
+
+ strcpy((char *)data + pos, pair->value);
+ pos += strlen(pair->value);
+ data[pos++] = 0xc0;
+ data[pos++] = 0x80;
+ }
+}
+
+static void yahoo_dump_unhandled(struct yahoo_packet *pkt)
+{
+ YList *l;
+
+ NOTICE(("Service: %s (0x%02x)\tStatus: %s (%d)", dbg_service(pkt->service),pkt->service, dbg_status(pkt->status), pkt->status));
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ NOTICE(("\t%d => %s", pair->key, pair->value));
+ }
+}
+
+
+static void yahoo_packet_dump(unsigned char *data, int len)
+{
+ if(yahoo_get_log_level() >= YAHOO_LOG_DEBUG) {
+ char z[4096], t[10];
+ int i;
+
+ z[0]='\0';
+
+ for (i = 0; i < len; i++) {
+ if ((i % 8 == 0) && i)
+ //YAHOO_CALLBACK(ext_yahoo_log)(" ");
+ lstrcat(z, " ");
+ if ((i % 16 == 0) && i)
+ lstrcat(z, "\n");
+
+ wsprintf(t, "%02x ", data[i]);
+ lstrcat(z, t);
+ }
+ lstrcat(z, "\n");
+ YAHOO_CALLBACK(ext_yahoo_log)(z);
+
+ z[0]='\0';
+ for (i = 0; i < len; i++) {
+ if ((i % 8 == 0) && i)
+ //YAHOO_CALLBACK(ext_yahoo_log)(" ");
+ lstrcat(z, " ");
+ if ((i % 16 == 0) && i)
+ //YAHOO_CALLBACK(ext_yahoo_log)("\n");
+ lstrcat(z, "\n");
+ if (isprint(data[i])) {
+ //YAHOO_CALLBACK(ext_yahoo_log)(" %c ", data[i]);
+ wsprintf(t, " %c ", data[i]);
+ lstrcat(z, t);
+ } else
+ //YAHOO_CALLBACK(ext_yahoo_log)(" . ");
+ lstrcat(z, " . ");
+ }
+ //YAHOO_CALLBACK(ext_yahoo_log)("\n");
+ lstrcat(z, "\n");
+ YAHOO_CALLBACK(ext_yahoo_log)(z);
+ }
+}
+
+static char base64digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789._";
+static void to_y64(unsigned char *out, const unsigned char *in, int inlen)
+/* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */
+{
+ for (; inlen >= 3; inlen -= 3)
+ {
+ *out++ = base64digits[in[0] >> 2];
+ *out++ = base64digits[((in[0]<<4) & 0x30) | (in[1]>>4)];
+ *out++ = base64digits[((in[1]<<2) & 0x3c) | (in[2]>>6)];
+ *out++ = base64digits[in[2] & 0x3f];
+ in += 3;
+ }
+ if (inlen > 0)
+ {
+ unsigned char fragment;
+
+ *out++ = base64digits[in[0] >> 2];
+ fragment = (in[0] << 4) & 0x30;
+ if (inlen > 1)
+ fragment |= in[1] >> 4;
+ *out++ = base64digits[fragment];
+ *out++ = (inlen < 2) ? '-'
+ : base64digits[(in[1] << 2) & 0x3c];
+ *out++ = '-';
+ }
+ *out = '\0';
+}
+
+static void yahoo_add_to_send_queue(struct yahoo_input_data *yid, void *data, int length)
+{
+ struct data_queue *tx = y_new0(struct data_queue, 1);
+ tx->queue = y_new0(unsigned char, length);
+ tx->len = length;
+ memcpy(tx->queue, data, length);
+
+ yid->txqueues = y_list_append(yid->txqueues, tx);
+
+ if(!yid->write_tag)
+ yid->write_tag=YAHOO_CALLBACK(ext_yahoo_add_handler)(yid->yd->client_id, yid->fd, YAHOO_INPUT_WRITE, yid);
+}
+
+static void yahoo_send_packet(struct yahoo_input_data *yid, struct yahoo_packet *pkt, int extra_pad)
+{
+ int pktlen = yahoo_packet_length(pkt);
+ int len = YAHOO_PACKET_HDRLEN + pktlen;
+ unsigned char *data;
+ int pos = 0;
+
+ if (yid->fd < 0)
+ return;
+
+ data = y_new0(unsigned char, len + 1);
+
+ memcpy(data + pos, "YMSG", 4); pos += 4;
+ pos += yahoo_put16(data + pos, YAHOO_PROTO_VER); /* version [latest 12 0x000c] */
+ pos += yahoo_put16(data + pos, 0x0000); /* HIWORD pkt length??? */
+ pos += yahoo_put16(data + pos, pktlen + extra_pad); /* LOWORD pkt length? */
+ pos += yahoo_put16(data + pos, pkt->service); /* service */
+ pos += yahoo_put32(data + pos, pkt->status); /* status [4bytes] */
+ pos += yahoo_put32(data + pos, pkt->id); /* session [4bytes] */
+
+ yahoo_packet_write(pkt, data + pos);
+
+ //yahoo_packet_dump(data, len);
+ DEBUG_MSG(("Sending Packet:"));
+ DEBUG_MSG(("Yahoo Service: %s (0x%02x) Status: %s (%d)", dbg_service(pkt->service), pkt->service,
+ dbg_status(pkt->status),pkt->status));
+
+ yahoo_packet_read(pkt, data + pos, len - pos);
+
+/* if( yid->type == YAHOO_CONNECTION_FT )
+ yahoo_send_data(yid->fd, data, len);
+ else
+ yahoo_add_to_send_queue(yid, data, len);
+ */
+ yahoo_send_data(yid->fd, data, len);
+
+ FREE(data);
+}
+
+static void yahoo_packet_free(struct yahoo_packet *pkt)
+{
+ while (pkt->hash) {
+ struct yahoo_pair *pair = pkt->hash->data;
+ YList *tmp;
+ FREE(pair->value);
+ FREE(pair);
+ tmp = pkt->hash;
+ pkt->hash = y_list_remove_link(pkt->hash, pkt->hash);
+ y_list_free_1(tmp);
+ }
+ FREE(pkt);
+}
+
+static int yahoo_send_data(int fd, void *data, int len)
+{
+ int ret;
+ int e;
+
+ if (fd < 0)
+ return -1;
+
+ //yahoo_packet_dump(data, len);
+
+ do {
+ ret = write(fd, data, len);
+ } while(ret == -1 && errno==EINTR);
+ e=errno;
+
+ if (ret == -1) {
+ LOG(("wrote data: ERR %s", strerror(errno)));
+ } else {
+ LOG(("wrote data: OK"));
+ }
+
+ errno=e;
+ return ret;
+}
+
+void yahoo_close(int id)
+{
+ struct yahoo_data *yd = find_conn_by_id(id);
+ if(!yd)
+ return;
+
+ del_from_list(yd);
+
+ yahoo_free_data(yd);
+ if(id == last_id)
+ last_id--;
+}
+
+static void yahoo_input_close(struct yahoo_input_data *yid)
+{
+ inputs = y_list_remove(inputs, yid);
+
+ LOG(("yahoo_input_close(read)"));
+ YAHOO_CALLBACK(ext_yahoo_remove_handler)(yid->yd->client_id, yid->read_tag);
+ LOG(("yahoo_input_close(write)"));
+ YAHOO_CALLBACK(ext_yahoo_remove_handler)(yid->yd->client_id, yid->write_tag);
+ yid->read_tag = yid->write_tag = 0;
+ if(yid->fd)
+ close(yid->fd);
+ yid->fd = 0;
+ FREE(yid->rxqueue);
+ if(count_inputs_with_id(yid->yd->client_id) == 0) {
+ LOG(("closing %d", yid->yd->client_id));
+ yahoo_close(yid->yd->client_id);
+ }
+ yahoo_free_webcam(yid->wcm);
+ if(yid->wcd)
+ FREE(yid->wcd);
+ if(yid->ys) {
+ FREE(yid->ys->lsearch_text);
+ FREE(yid->ys);
+ }
+ FREE(yid);
+}
+
+static int is_same_bud(const void * a, const void * b) {
+ const struct yahoo_buddy *subject = a;
+ const struct yahoo_buddy *object = b;
+
+ return strcmp(subject->id, object->id);
+}
+
+static YList * bud_str2list(char *rawlist)
+{
+ YList * l = NULL;
+
+ char **lines;
+ char **split;
+ char **buddies;
+ char **tmp, **bud;
+
+ lines = y_strsplit(rawlist, "\n", -1);
+ for (tmp = lines; *tmp; tmp++) {
+ struct yahoo_buddy *newbud;
+
+ split = y_strsplit(*tmp, ":", 2);
+ if (!split)
+ continue;
+ if (!split[0] || !split[1]) {
+ y_strfreev(split);
+ continue;
+ }
+ buddies = y_strsplit(split[1], ",", -1);
+
+ for (bud = buddies; bud && *bud; bud++) {
+ newbud = y_new0(struct yahoo_buddy, 1);
+ newbud->id = strdup(*bud);
+ newbud->group = strdup(split[0]);
+
+ if(y_list_find_custom(l, newbud, is_same_bud)) {
+ FREE(newbud->id);
+ FREE(newbud->group);
+ FREE(newbud);
+ continue;
+ }
+
+ newbud->real_name = NULL;
+
+ l = y_list_append(l, newbud);
+
+ NOTICE(("Added buddy %s to group %s", newbud->id, newbud->group));
+ }
+
+ y_strfreev(buddies);
+ y_strfreev(split);
+ }
+ y_strfreev(lines);
+
+ return l;
+}
+
+char * getcookie(char *rawcookie)
+{
+ char * cookie=NULL;
+ char * tmpcookie;
+ char * cookieend;
+
+ if (strlen(rawcookie) < 2)
+ return NULL;
+
+ tmpcookie = strdup(rawcookie+2);
+ cookieend = strchr(tmpcookie, ';');
+
+ if(cookieend)
+ *cookieend = '\0';
+
+ cookie = strdup(tmpcookie);
+ FREE(tmpcookie);
+ /* cookieend=NULL; not sure why this was there since the value is not preserved in the stack -dd */
+
+ return cookie;
+}
+
+static char * getlcookie(char *cookie)
+{
+ char *tmp;
+ char *tmpend;
+ char *login_cookie = NULL;
+
+ tmpend = strstr(cookie, "n=");
+ if(tmpend) {
+ tmp = strdup(tmpend+2);
+ tmpend = strchr(tmp, '&');
+ if(tmpend)
+ *tmpend='\0';
+ login_cookie = strdup(tmp);
+ FREE(tmp);
+ }
+
+ return login_cookie;
+}
+
+static void yahoo_process_notify(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ struct yahoo_data *yd = yid->yd;
+ char *msg = NULL;
+ char *from = NULL;
+ char *to = NULL;
+ int stat = 0;
+ int accept = 0;
+ char *ind = NULL;
+ YList *l;
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ if (pair->key == 4)
+ from = pair->value;
+ if (pair->key == 5)
+ to = pair->value;
+ if (pair->key == 49)
+ msg = pair->value;
+ if (pair->key == 13)
+ stat = atoi(pair->value);
+ if (pair->key == 14)
+ ind = pair->value;
+ if (pair->key == 16) { /* status == -1 */
+ NOTICE((pair->value));
+ return;
+ }
+
+ }
+
+ if (!msg)
+ return;
+
+ if (!strncasecmp(msg, "TYPING", strlen("TYPING")))
+ YAHOO_CALLBACK(ext_yahoo_typing_notify)(yd->client_id, to, from, stat);
+ else if (!strncasecmp(msg, "GAME", strlen("GAME")))
+ YAHOO_CALLBACK(ext_yahoo_game_notify)(yd->client_id, to, from, stat, ind);
+ else if (!strncasecmp(msg, "WEBCAMINVITE", strlen("WEBCAMINVITE")))
+ {
+ if (!strcmp(ind, " ")) {
+ YAHOO_CALLBACK(ext_yahoo_webcam_invite)(yd->client_id, to, from);
+ } else {
+ accept = atoi(ind);
+ /* accept the invitation (-1 = deny 1 = accept) */
+ if (accept < 0)
+ accept = 0;
+ YAHOO_CALLBACK(ext_yahoo_webcam_invite_reply)(yd->client_id, to, from, accept);
+ }
+ }
+ else
+ LOG(("Got unknown notification: %s", msg));
+}
+
+static void yahoo_process_filetransfer(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ struct yahoo_data *yd = yid->yd;
+ char *from=NULL;
+ char *to=NULL;
+ char *msg=NULL;
+ char *url=NULL;
+ long expires=0;
+
+ char *service=NULL;
+ char *ft_token=NULL;
+ char *filename=NULL;
+ unsigned long filesize=0L;
+
+ YList *l;
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ if (pair->key == 4)
+ from = pair->value;
+ if (pair->key == 5)
+ to = pair->value;
+ if (pair->key == 14)
+ msg = pair->value;
+ if (pair->key == 20)
+ url = pair->value;
+ if (pair->key == 38)
+ expires = atol(pair->value);
+
+ if (pair->key == 27)
+ filename = pair->value;
+
+ if (pair->key == 28)
+ filesize = atol(pair->value);
+
+ if (pair->key == 49)
+ service = pair->value;
+
+ if (pair->key == 53)
+ ft_token = pair->value;
+ }
+
+ if(pkt->service == YAHOO_SERVICE_P2PFILEXFER) {
+ if(strcmp("FILEXFER", service) != 0) {
+ WARNING(("unhandled service 0x%02x", pkt->service));
+ yahoo_dump_unhandled(pkt);
+ return;
+ }
+ }
+
+ if(msg) {
+ char *tmp;
+ tmp = strchr(msg, '\006');
+ if(tmp)
+ *tmp = '\0';
+ }
+ if(url && from)
+ YAHOO_CALLBACK(ext_yahoo_got_file)(yd->client_id, to, from, url, expires, msg, filename, filesize, ft_token, 0);
+ else if (strcmp(from, "FILE_TRANSFER_SYSTEM") == 0 && msg != NULL)
+ YAHOO_CALLBACK(ext_yahoo_system_message)(yd->client_id, to, from, msg);
+}
+
+static void yahoo_process_filetransfer7(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ struct yahoo_data *yd = yid->yd;
+ char *from=NULL;
+ char *to=NULL;
+ char *msg=NULL;
+ char *url=NULL;
+ long expires=0;
+
+ int service=0;
+ char *ft_token=NULL;
+ char *filename=NULL;
+ unsigned long filesize=0L;
+
+ YList *l;
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ switch (pair->key) {
+ case 4:
+ from = pair->value;
+ break;
+ case 5:
+ to = pair->value;
+ break;
+ case 27:
+ filename = pair->value;
+ break;
+
+ case 28:
+ filesize = atol(pair->value);
+ break;
+
+ case 222:
+ service = atol(pair->value);
+ break;
+ case 265:
+ ft_token = pair->value;
+ break;
+ }
+ }
+
+ switch (service) {
+ case 1: // FT7
+ YAHOO_CALLBACK(ext_yahoo_got_file)(yd->client_id, to, from, url, expires, msg, filename, filesize, ft_token, 1);
+ break;
+ case 2: // FT7 Cancelled
+ break;
+ }
+}
+
+static void yahoo_process_filetransfer7info(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ struct yahoo_data *yd = yid->yd;
+ char *from=NULL;
+ char *to=NULL;
+ int service=0;
+ char *ft_token=NULL;
+ char *filename=NULL;
+ char *host = NULL;
+ char *token = NULL;
+ unsigned long filesize=0L;
+
+ YList *l;
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ switch (pair->key) {
+ case 4:
+ from = pair->value;
+ break;
+ case 5:
+ to = pair->value;
+ break;
+ case 27:
+ filename = pair->value;
+ break;
+
+ case 28:
+ filesize = atol(pair->value);
+ break;
+
+ case 249:
+ service = atol(pair->value);
+ break;
+ case 250:
+ host = pair->value;
+ break;
+ case 251:
+ token = pair->value;
+ break;
+ case 265:
+ ft_token = pair->value;
+ break;
+ }
+ }
+
+ switch (service) {
+ case 1: // P2P
+ //YAHOO_CALLBACK(ext_yahoo_got_file)(yd->client_id, to, from, url, expires, msg, filename, filesize, ft_token, 1);
+ {
+ /*
+ * From Kopete: deny P2P
+ */
+ struct yahoo_packet *pkt1 = NULL;
+
+ pkt1 = yahoo_packet_new(YAHOO_SERVICE_Y7_FILETRANSFERACCEPT, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_packet_hash(pkt1, 1, yd->user);
+ yahoo_packet_hash(pkt1, 5, from);
+ yahoo_packet_hash(pkt1,265, ft_token);
+ yahoo_packet_hash(pkt1,66, "-3");
+
+ yahoo_send_packet(yid, pkt1, 0);
+ yahoo_packet_free(pkt1);
+
+ }
+ break;
+ case 3: // Relay
+ {
+ /*
+ * From Kopete: accept the info?
+ */
+ struct yahoo_packet *pkt1 = NULL;
+
+ pkt1 = yahoo_packet_new(YAHOO_SERVICE_Y7_FILETRANSFERACCEPT, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_packet_hash(pkt1, 1, yd->user);
+ yahoo_packet_hash(pkt1, 5, from);
+ yahoo_packet_hash(pkt1,265, ft_token);
+ yahoo_packet_hash(pkt1,27, filename);
+ yahoo_packet_hash(pkt1,249, "3"); // use reflection server
+ yahoo_packet_hash(pkt1,251, token);
+
+ yahoo_send_packet(yid, pkt1, 0);
+ yahoo_packet_free(pkt1);
+
+ }
+ break;
+ }
+}
+
+static void yahoo_process_conference(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ struct yahoo_data *yd = yid->yd;
+ char *msg = NULL;
+ char *host = NULL;
+ char *who = NULL;
+ char *room = NULL;
+ char *id = NULL;
+ int utf8 = 0;
+ YList *members = NULL;
+ YList *l;
+
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ if (pair->key == 50)
+ host = pair->value;
+
+ if (pair->key == 52) { /* invite */
+ members = y_list_append(members, strdup(pair->value));
+ }
+ if (pair->key == 53) /* logon */
+ who = pair->value;
+ if (pair->key == 54) /* decline */
+ who = pair->value;
+ if (pair->key == 55) /* unavailable (status == 2) */
+ who = pair->value;
+ if (pair->key == 56) /* logoff */
+ who = pair->value;
+
+ if (pair->key == 57)
+ room = pair->value;
+
+ if (pair->key == 58) /* join message */
+ msg = pair->value;
+ if (pair->key == 14) /* decline/conf message */
+ msg = pair->value;
+
+ if (pair->key == 13)
+ ;
+ if (pair->key == 16) /* error */
+ msg = pair->value;
+
+ if (pair->key == 1) /* my id */
+ id = pair->value;
+ if (pair->key == 3) /* message sender */
+ who = pair->value;
+
+ if (pair->key == 97)
+ utf8 = atoi(pair->value);
+ }
+
+ if(!room)
+ return;
+
+ if(host) {
+ for(l = members; l; l = l->next) {
+ char * w = l->data;
+ if(!strcmp(w, host))
+ break;
+ }
+ if(!l)
+ members = y_list_append(members, strdup(host));
+ }
+ /* invite, decline, join, left, message -> status == 1 */
+
+ switch(pkt->service) {
+ case YAHOO_SERVICE_CONFINVITE:
+ if(pkt->status == 2)
+ ;
+ else if(members)
+ YAHOO_CALLBACK(ext_yahoo_got_conf_invite)(yd->client_id, id, host, room, msg, members);
+ else if(msg)
+ YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, msg, 0, E_CONFNOTAVAIL);
+ break;
+ case YAHOO_SERVICE_CONFADDINVITE:
+ if(pkt->status == 2)
+ ;
+ else
+ YAHOO_CALLBACK(ext_yahoo_got_conf_invite)(yd->client_id, id, host, room, msg, members);
+ break;
+ case YAHOO_SERVICE_CONFDECLINE:
+ if(who)
+ YAHOO_CALLBACK(ext_yahoo_conf_userdecline)(yd->client_id, id, who, room, msg);
+ break;
+ case YAHOO_SERVICE_CONFLOGON:
+ if(who)
+ YAHOO_CALLBACK(ext_yahoo_conf_userjoin)(yd->client_id, id, who, room);
+ break;
+ case YAHOO_SERVICE_CONFLOGOFF:
+ if(who)
+ YAHOO_CALLBACK(ext_yahoo_conf_userleave)(yd->client_id, id, who, room);
+ break;
+ case YAHOO_SERVICE_CONFMSG:
+ if(who)
+ YAHOO_CALLBACK(ext_yahoo_conf_message)(yd->client_id, id, who, room, msg, utf8);
+ break;
+ }
+}
+
+static void yahoo_process_chat(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ char *msg = NULL;
+ char *id = NULL;
+ char *who = NULL;
+ char *room = NULL;
+ char *topic = NULL;
+ YList *members = NULL;
+ struct yahoo_chat_member *currentmember = NULL;
+ int msgtype = 1;
+ int utf8 = 0;
+ int firstjoin = 0;
+ int membercount = 0;
+ int chaterr=0;
+ YList *l;
+
+ yahoo_dump_unhandled(pkt);
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+
+ if (pair->key == 1) {
+ /* My identity */
+ id = pair->value;
+ }
+
+ if (pair->key == 104) {
+ /* Room name */
+ room = pair->value;
+ }
+
+ if (pair->key == 105) {
+ /* Room topic */
+ topic = pair->value;
+ }
+
+ if (pair->key == 108) {
+ /* Number of members in this packet */
+ membercount = atoi(pair->value);
+ }
+
+ if (pair->key == 109) {
+ /* message sender */
+ who = pair->value;
+
+ if (pkt->service == YAHOO_SERVICE_CHATJOIN) {
+ currentmember = y_new0(struct yahoo_chat_member, 1);
+ currentmember->id = strdup(pair->value);
+ members = y_list_append(members, currentmember);
+ }
+ }
+
+ if (pair->key == 110) {
+ /* age */
+ if (pkt->service == YAHOO_SERVICE_CHATJOIN)
+ currentmember->age = atoi(pair->value);
+ }
+
+ if (pair->key == 113) {
+ /* attribs */
+ if (pkt->service == YAHOO_SERVICE_CHATJOIN)
+ currentmember->attribs = atoi(pair->value);
+ }
+
+ if (pair->key == 141) {
+ /* alias */
+ if (pkt->service == YAHOO_SERVICE_CHATJOIN)
+ currentmember->alias = strdup(pair->value);
+ }
+
+ if (pair->key == 142) {
+ /* location */
+ if (pkt->service == YAHOO_SERVICE_CHATJOIN)
+ currentmember->location = strdup(pair->value);
+ }
+
+
+ if (pair->key == 130) {
+ /* first join */
+ firstjoin = 1;
+ }
+
+ if (pair->key == 117) {
+ /* message */
+ msg = pair->value;
+ }
+
+ if (pair->key == 124) {
+ /* Message type */
+ msgtype = atoi(pair->value);
+ }
+ if (pair->key == 114) {
+ /* message error not sure what all the pair values mean */
+ /* but -1 means no session in room */
+ chaterr= atoi(pair->value);
+ }
+ }
+
+ if(!room) {
+ if (pkt->service == YAHOO_SERVICE_CHATLOGOUT) { /* yahoo originated chat logout */
+ YAHOO_CALLBACK(ext_yahoo_chat_yahoologout)(yid->yd->client_id, id);
+ return ;
+ }
+ if (pkt->service == YAHOO_SERVICE_COMMENT && chaterr) {
+ YAHOO_CALLBACK(ext_yahoo_chat_yahooerror)(yid->yd->client_id, id);
+ return ;
+ }
+
+ WARNING(("We didn't get a room name, ignoring packet"));
+ return;
+ }
+
+ switch(pkt->service) {
+ case YAHOO_SERVICE_CHATJOIN:
+ if(y_list_length(members) != membercount) {
+ WARNING(("Count of members doesn't match No. of members we got"));
+ }
+ if(firstjoin && members) {
+ YAHOO_CALLBACK(ext_yahoo_chat_join)(yid->yd->client_id, id, room, topic, members, yid->fd);
+ } else if(who) {
+ if(y_list_length(members) != 1) {
+ WARNING(("Got more than 1 member on a normal join"));
+ }
+ /* this should only ever have one, but just in case */
+ while(members) {
+ YList *n = members->next;
+ currentmember = members->data;
+ YAHOO_CALLBACK(ext_yahoo_chat_userjoin)(yid->yd->client_id, id, room, currentmember);
+ y_list_free_1(members);
+ members=n;
+ }
+ }
+ break;
+ case YAHOO_SERVICE_CHATEXIT:
+ if(who) {
+ YAHOO_CALLBACK(ext_yahoo_chat_userleave)(yid->yd->client_id, id, room, who);
+ }
+ break;
+ case YAHOO_SERVICE_COMMENT:
+ if(who) {
+ YAHOO_CALLBACK(ext_yahoo_chat_message)(yid->yd->client_id, id, who, room, msg, msgtype, utf8);
+ }
+ break;
+ }
+}
+
+static void yahoo_process_message(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ struct yahoo_data *yd = yid->yd;
+ YList *l;
+ YList * messages = NULL;
+
+ struct m {
+ int i_31;
+ int i_32;
+ char *to;
+ char *from;
+ long tm;
+ char *msg;
+ int utf8;
+ int buddy_icon;
+ } *message = y_new0(struct m, 1);
+
+ message->buddy_icon = -1; // no info
+
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ if (pair->key == 1 || pair->key == 4)
+ {
+ if(!message->from)
+ message->from = pair->value;
+ }
+ else if (pair->key == 5)
+ message->to = pair->value;
+ else if (pair->key == 15)
+ message->tm = strtol(pair->value, NULL, 10);
+ else if (pair->key == 206)
+ message->buddy_icon = atoi(pair->value);
+ else if (pair->key == 97)
+ message->utf8 = atoi(pair->value);
+ /* user message */ /* sys message */
+ else if (pair->key == 14 || pair->key == 16)
+ message->msg = pair->value;
+ else if (pair->key == 31) {
+ if(message->i_31) {
+ messages = y_list_append(messages, message);
+ message = y_new0(struct m, 1);
+ }
+ message->i_31 = atoi(pair->value);
+ }
+ else if (pair->key == 32)
+ message->i_32 = atoi(pair->value);
+ else
+ LOG(("yahoo_process_message: status: %d, key: %d, value: %s",
+ pkt->status, pair->key, pair->value));
+ }
+
+ messages = y_list_append(messages, message);
+
+ for (l = messages; l; l=l->next) {
+ message = l->data;
+ if (pkt->service == YAHOO_SERVICE_SYSMESSAGE) {
+ YAHOO_CALLBACK(ext_yahoo_system_message)(yd->client_id, message->to, message->from, message->msg);
+ } else if (pkt->status <= 2 || pkt->status == 5) {
+ YAHOO_CALLBACK(ext_yahoo_got_im)(yd->client_id, message->to, message->from, message->msg, message->tm, pkt->status, message->utf8, message->buddy_icon);
+ } else if (pkt->status == 0xffffffff) {
+ YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, message->msg, 0, E_SYSTEM);
+ }
+ free(message);
+ }
+
+ y_list_free(messages);
+}
+
+static void yahoo_process_logon(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ YList *l;
+ struct yahoo_data *yd = yid->yd;
+ char *name = NULL;
+ int state = 0;
+ int away = 0;
+ int idle = 0;
+ int mobile = 0;
+ int cksum = 0;
+ int buddy_icon = -1;
+ long client_version = 0;
+ char *msg = NULL;
+
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+
+ switch (pair->key) {
+ case 0: /* we won't actually do anything with this */
+ NOTICE(("key %d:%s", pair->key, pair->value));
+ break;
+ case 1: /* we don't get the full buddy list here. */
+ if (!yd->logged_in) {
+ yd->logged_in = TRUE;
+ if(yd->current_status < 0)
+ yd->current_status = yd->initial_status;
+ YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_OK, NULL);
+ }
+ break;
+ case 7: /* the current buddy */
+ if (name != NULL) {
+ YAHOO_CALLBACK(ext_yahoo_status_logon)(yd->client_id, name, state, msg, away, idle, mobile, cksum, buddy_icon, client_version);
+ msg = NULL;
+ client_version = cksum = state = away = idle = mobile = 0;
+ buddy_icon = -1;
+ }
+ name = pair->value;
+ break;
+ case 8: /* how many online buddies we have */
+ NOTICE(("key %d:%s", pair->key, pair->value));
+ break;
+ case 10: /* state */
+ state = strtol(pair->value, NULL, 10);
+ break;
+ case 11: /* this is the buddy's session id */
+ NOTICE(("key %d:%s", pair->key, pair->value));
+ break;
+ case 13: /* bitmask, bit 0 = pager, bit 1 = chat, bit 2 = game */
+ if (strtol(pair->value, NULL, 10) == 0) {
+ YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, name, YAHOO_STATUS_OFFLINE, NULL, 1, 0, 0);
+ name = NULL;
+ break;
+ }
+ break;
+ case 16: /* Custom error message */
+ YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, pair->value, 0, E_CUSTOM);
+ break;
+ case 17: /* in chat? */
+ break;
+ case 19: /* custom status message */
+ msg = pair->value;
+ break;
+ case 24: /* session timestamp */
+ yd->session_timestamp = atol(pair->value);
+ break;
+ case 47: /* is it an away message or not */
+ away = atoi(pair->value);
+ break;
+ case 60: /* SMS -> 1 MOBILE USER */
+ /* sometimes going offline makes this 2, but invisible never sends it */
+ NOTICE(("key %d:%s", pair->key, pair->value));
+ if (atoi(pair->value) > 0 )
+ mobile = 1;
+ break;
+ case 137: /* seconds idle */
+ idle = atoi(pair->value);
+ break;
+ case 138: /* either we're not idle, or we are but won't say how long */
+ /* thanx Gaim.. I am seeing 138 -> 1. so don't do idle at all for miranda
+ since we don't have idle w/o time :( */
+ idle = 0;
+ break;
+
+ case 192: /* Pictures aka BuddyIcon checksum*/
+ cksum = strtol(pair->value, NULL, 10);
+ break;
+
+ case 197: /* avatar base64 encodded [Ignored by Gaim?] */
+ /*avatar = pair->value;*/
+ break;
+
+ case 213: /* Pictures aka BuddyIcon type 0-none, 1-avatar, 2-picture*/
+ buddy_icon = strtol(pair->value, NULL, 10);
+ break;
+
+ case 244: /* client version number. Yahoo Client Detection */
+ client_version = strtol(pair->value, NULL, 10);
+ break;
+
+ default:
+ WARNING(("unknown status key %d:%s", pair->key, pair->value));
+ break;
+ }
+ }
+
+ if (name != NULL)
+ YAHOO_CALLBACK(ext_yahoo_status_logon)(yd->client_id, name, state, msg, away, idle, mobile, cksum, buddy_icon, client_version);
+
+}
+
+static void yahoo_process_status(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ YList *l;
+ struct yahoo_data *yd = yid->yd;
+ char *name = NULL;
+ int state = 0;
+ int away = 0;
+ int idle = 0;
+ int mobile = 0;
+ int login_status=YAHOO_LOGIN_LOGOFF;
+ char *msg = NULL;
+ char *errmsg = NULL;
+
+ /*if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == YAHOO_STATUS_DISCONNECTED) {
+ YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_DUPL, NULL);
+ return;
+ }*/
+
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+
+ switch (pair->key) {
+ case 0: /* we won't actually do anything with this */
+ NOTICE(("key %d:%s", pair->key, pair->value));
+ break;
+ case 1: /* we don't get the full buddy list here. */
+ if (!yd->logged_in) {
+ yd->logged_in = TRUE;
+ if(yd->current_status < 0)
+ yd->current_status = yd->initial_status;
+ YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_OK, NULL);
+ }
+ break;
+ case 8: /* how many online buddies we have */
+ NOTICE(("key %d:%s", pair->key, pair->value));
+ break;
+ case 7: /* the current buddy */
+ if (name != NULL) {
+ YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, name, state, msg, away, idle, mobile);
+ msg = NULL;
+ state = away = idle = mobile = 0;
+ }
+ name = pair->value;
+ break;
+ case 10: /* state */
+ state = strtol(pair->value, NULL, 10);
+ break;
+ case 19: /* custom status message */
+ msg = pair->value;
+ break;
+ case 47: /* is it an away message or not */
+ away = atoi(pair->value);
+ break;
+ case 137: /* seconds idle */
+ idle = atoi(pair->value);
+ break;
+ case 138: /* either we're not idle, or we are but won't say how long */
+ /* thanx Gaim.. I am seeing 138 -> 1. so don't do idle at all for miranda
+ since we don't have idle w/o time :( */
+ idle = 0;
+ break;
+ case 11: /* this is the buddy's session id */
+ NOTICE(("key %d:%s", pair->key, pair->value));
+ break;
+ case 17: /* in chat? */
+ break;
+ case 13: /* bitmask, bit 0 = pager, bit 1 = chat, bit 2 = game */
+ if (pkt->service == YAHOO_SERVICE_LOGOFF || strtol(pair->value, NULL, 10) == 0) {
+ YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, name, YAHOO_STATUS_OFFLINE, NULL, 1, 0, 0);
+ name = NULL;
+ break;
+ }
+ break;
+ case 60: /* SMS -> 1 MOBILE USER */
+ /* sometimes going offline makes this 2, but invisible never sends it */
+ NOTICE(("key %d:%s", pair->key, pair->value));
+ if (atoi(pair->value) > 0 )
+ mobile = 1;
+ break;
+ case 16: /* Custom error message */
+ errmsg = pair->value;
+ break;
+ case 66: /* login status */
+ {
+ int i = atoi(pair->value);
+
+ switch(i) {
+ case 42: /* duplicate login */
+ login_status = YAHOO_LOGIN_DUPL;
+ break;
+ case 28: /* session expired */
+
+ break;
+ }
+ }
+ break;
+ default:
+ WARNING(("unknown status key %d:%s", pair->key, pair->value));
+ break;
+ }
+ }
+
+ if (name != NULL)
+ YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, name, state, msg, away, idle, mobile);
+ else if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == YAHOO_STATUS_DISCONNECTED)
+ //
+ //Key: Error msg (16) Value: 'Session expired. Please relogin'
+ //Key: login status (66) Value: '28'
+ //
+ YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, login_status, NULL);
+ else if (errmsg != NULL)
+ YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, errmsg, 0, E_CUSTOM);
+ else if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == YAHOO_STATUS_AVAILABLE && pkt->hash == NULL)
+ // Server Acking our Logoff (close connection)
+ yahoo_input_close(yid);
+}
+
+static void yahoo_process_list(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ struct yahoo_data *yd = yid->yd;
+ YList *l;
+
+ /* we could be getting multiple packets here */
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+
+ switch(pair->key) {
+ case 87: /* buddies */
+ if(!yd->rawbuddylist)
+ yd->rawbuddylist = strdup(pair->value);
+ else {
+ yd->rawbuddylist = y_string_append(yd->rawbuddylist, pair->value);
+ }
+ break;
+
+ case 88: /* ignore list */
+ if(!yd->ignorelist)
+ yd->ignorelist = strdup("Ignore:");
+ yd->ignorelist = y_string_append(yd->ignorelist, pair->value);
+ break;
+
+ case 89: /* identities */
+ {
+ char **identities = y_strsplit(pair->value, ",", -1);
+ int i;
+ for(i=0; identities[i]; i++)
+ yd->identities = y_list_append(yd->identities,
+ strdup(identities[i]));
+ y_strfreev(identities);
+ }
+ YAHOO_CALLBACK(ext_yahoo_got_identities)(yd->client_id, yd->identities);
+ break;
+ case 59: /* cookies */
+ if(pair->value[0]=='Y') {
+ FREE(yd->cookie_y);
+ FREE(yd->login_cookie);
+
+ yd->cookie_y = getcookie(pair->value);
+ yd->login_cookie = getlcookie(yd->cookie_y);
+
+ } else if(pair->value[0]=='T') {
+ FREE(yd->cookie_t);
+ yd->cookie_t = getcookie(pair->value);
+
+ } else if(pair->value[0]=='C') {
+ FREE(yd->cookie_c);
+ yd->cookie_c = getcookie(pair->value);
+ }
+
+ break;
+ case 3: /* my id */
+ case 90: /* 1 */
+ case 100: /* 0 */
+ case 101: /* NULL */
+ case 102: /* NULL */
+ case 93: /* 86400/1440 */
+ break;
+ case 185: /* stealth list */
+ if(!yd->rawstealthlist)
+ yd->rawstealthlist = strdup(pair->value);
+ else {
+ yd->rawstealthlist = y_string_append(yd->rawstealthlist, pair->value);
+ }
+
+ WARNING(("Got stealth list: %s", yd->rawstealthlist));
+ YAHOO_CALLBACK(ext_yahoo_got_stealthlist)(yd->client_id, yd->rawstealthlist);
+ break;
+ case 213: /* my current avatar setting */
+ {
+ int buddy_icon = strtol(pair->value, NULL, 10);
+
+ YAHOO_CALLBACK(ext_yahoo_got_avatar_share)(yd->client_id, buddy_icon);
+ }
+ break;
+ case 217: /*??? Seems like last key */
+
+ break;
+ }
+ }
+
+ /* we could be getting multiple packets here */
+ if (pkt->status != 0) /* Thanks for the fix GAIM */
+ return;
+
+ if (!yd->rawstealthlist)
+ YAHOO_CALLBACK(ext_yahoo_got_stealthlist)(yd->client_id, yd->rawstealthlist);
+
+ if(yd->ignorelist) {
+ yd->ignore = bud_str2list(yd->ignorelist);
+ FREE(yd->ignorelist);
+ YAHOO_CALLBACK(ext_yahoo_got_ignore)(yd->client_id, yd->ignore);
+ }
+
+ if(yd->rawbuddylist) {
+ yd->buddies = bud_str2list(yd->rawbuddylist);
+ FREE(yd->rawbuddylist);
+
+ YAHOO_CALLBACK(ext_yahoo_got_buddies)(yd->client_id, yd->buddies);
+ }
+
+
+ if(yd->cookie_y && yd->cookie_t && yd->cookie_c)
+ YAHOO_CALLBACK(ext_yahoo_got_cookies)(yd->client_id);
+
+ /*** We login at the very end of the packet communication */
+ if (!yd->logged_in) {
+ yd->logged_in = TRUE;
+ if(yd->current_status < 0)
+ yd->current_status = yd->initial_status;
+ YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_OK, NULL);
+ }
+}
+
+static void yahoo_process_verify(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ struct yahoo_data *yd = yid->yd;
+
+ if(pkt->status != 0x01) {
+ DEBUG_MSG(("expected status: 0x01, got: %d", pkt->status));
+ YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_LOCK, "");
+ return;
+ }
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH, YAHOO_STATUS_AVAILABLE, yd->session_id);
+
+ yahoo_packet_hash(pkt, 1, yd->user);
+ yahoo_send_packet(yid, pkt, 0);
+
+ yahoo_packet_free(pkt);
+
+}
+
+static void yahoo_process_auth_pre_0x0b(struct yahoo_input_data *yid,
+ const char *seed, const char *sn)
+{
+ struct yahoo_data *yd = yid->yd;
+
+ /* So, Yahoo has stopped supporting its older clients in India, and
+ * undoubtedly will soon do so in the rest of the world.
+ *
+ * The new clients use this authentication method. I warn you in
+ * advance, it's bizzare, convoluted, inordinately complicated.
+ * It's also no more secure than crypt() was. The only purpose this
+ * scheme could serve is to prevent third part clients from connecting
+ * to their servers.
+ *
+ * Sorry, Yahoo.
+ */
+
+ struct yahoo_packet *pack;
+
+ md5_byte_t result[16];
+ md5_state_t ctx;
+ char *crypt_result;
+ unsigned char *password_hash = malloc(25);
+ unsigned char *crypt_hash = malloc(25);
+ unsigned char *hash_string_p = malloc(50 + strlen(sn));
+ unsigned char *hash_string_c = malloc(50 + strlen(sn));
+
+ char checksum;
+
+ int sv;
+
+ unsigned char *result6 = malloc(25);
+ unsigned char *result96 = malloc(25);
+
+ sv = seed[15];
+ sv = (sv % 8) % 5;
+
+ md5_init(&ctx);
+ md5_append(&ctx, (md5_byte_t *)yd->password, strlen(yd->password));
+ md5_finish(&ctx, result);
+ to_y64(password_hash, result, 16);
+
+ md5_init(&ctx);
+ crypt_result = yahoo_crypt(yd->password, "$1$_2S43d5f$");
+ md5_append(&ctx, (md5_byte_t *)crypt_result, strlen(crypt_result));
+ md5_finish(&ctx, result);
+ to_y64(crypt_hash, result, 16);
+ free(crypt_result);
+
+ switch (sv) {
+ case 0:
+ checksum = seed[seed[7] % 16];
+ snprintf((char *)hash_string_p, strlen(sn) + 50,
+ "%c%s%s%s", checksum, password_hash, yd->user, seed);
+ snprintf((char *)hash_string_c, strlen(sn) + 50,
+ "%c%s%s%s", checksum, crypt_hash, yd->user, seed);
+ break;
+ case 1:
+ checksum = seed[seed[9] % 16];
+ snprintf((char *)hash_string_p, strlen(sn) + 50,
+ "%c%s%s%s", checksum, yd->user, seed, password_hash);
+ snprintf((char *)hash_string_c, strlen(sn) + 50,
+ "%c%s%s%s", checksum, yd->user, seed, crypt_hash);
+ break;
+ case 2:
+ checksum = seed[seed[15] % 16];
+ snprintf((char *)hash_string_p, strlen(sn) + 50,
+ "%c%s%s%s", checksum, seed, password_hash, yd->user);
+ snprintf((char *)hash_string_c, strlen(sn) + 50,
+ "%c%s%s%s", checksum, seed, crypt_hash, yd->user);
+ break;
+ case 3:
+ checksum = seed[seed[1] % 16];
+ snprintf((char *)hash_string_p, strlen(sn) + 50,
+ "%c%s%s%s", checksum, yd->user, password_hash, seed);
+ snprintf((char *)hash_string_c, strlen(sn) + 50,
+ "%c%s%s%s", checksum, yd->user, crypt_hash, seed);
+ break;
+ case 4:
+ checksum = seed[seed[3] % 16];
+ snprintf((char *)hash_string_p, strlen(sn) + 50,
+ "%c%s%s%s", checksum, password_hash, seed, yd->user);
+ snprintf((char *)hash_string_c, strlen(sn) + 50,
+ "%c%s%s%s", checksum, crypt_hash, seed, yd->user);
+ break;
+ }
+
+ md5_init(&ctx);
+ md5_append(&ctx, (md5_byte_t *)hash_string_p, strlen((char *)hash_string_p));
+ md5_finish(&ctx, result);
+ to_y64(result6, result, 16);
+
+ md5_init(&ctx);
+ md5_append(&ctx, (md5_byte_t *)hash_string_c, strlen((char *)hash_string_c));
+ md5_finish(&ctx, result);
+ to_y64(result96, result, 16);
+
+ pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yd->initial_status, yd->session_id);
+ yahoo_packet_hash(pack, 0, yd->user);
+ yahoo_packet_hash(pack, 6, (char *)result6);
+ yahoo_packet_hash(pack, 96, (char *)result96);
+ yahoo_packet_hash(pack, 1, yd->user);
+
+ yahoo_send_packet(yid, pack, 0);
+
+ FREE(result6);
+ FREE(result96);
+ FREE(password_hash);
+ FREE(crypt_hash);
+ FREE(hash_string_p);
+ FREE(hash_string_c);
+
+ yahoo_packet_free(pack);
+
+}
+
+/*
+ * New auth protocol cracked by Cerulean Studios and sent in to Gaim
+ */
+static void yahoo_process_auth_0x0b(struct yahoo_input_data *yid, const char *seed, const char *sn)
+{
+ struct yahoo_packet *pack = NULL;
+ struct yahoo_data *yd = yid->yd;
+ struct yahoo_server_settings *yss;
+
+ md5_byte_t result[16];
+ md5_state_t ctx;
+
+ SHA_CTX ctx1;
+ SHA_CTX ctx2;
+
+ char *alphabet1 = "FBZDWAGHrJTLMNOPpRSKUVEXYChImkwQ";
+ char *alphabet2 = "F0E1D2C3B4A59687abcdefghijklmnop";
+
+ char *challenge_lookup = "qzec2tb3um1olpar8whx4dfgijknsvy5";
+ char *operand_lookup = "+|&%/*^-";
+ char *delimit_lookup = ",;";
+
+ unsigned char *password_hash = malloc(25);
+ unsigned char *crypt_hash = malloc(25);
+ char *crypt_result = NULL;
+ unsigned char pass_hash_xor1[64];
+ unsigned char pass_hash_xor2[64];
+ unsigned char crypt_hash_xor1[64];
+ unsigned char crypt_hash_xor2[64];
+ unsigned char chal[7];
+ char resp_6[100];
+ char resp_96[100];
+
+ unsigned char digest1[20];
+ unsigned char digest2[20];
+ unsigned char magic_key_char[4];
+ const unsigned char *magic_ptr;
+
+ unsigned int magic[64];
+ unsigned int magic_work=0;
+
+ char comparison_src[20];
+ char z[22];
+
+ int x, j, i;
+ int cnt = 0;
+ int magic_cnt = 0;
+ int magic_len;
+ int depth =0, table =0;
+
+ memset(&pass_hash_xor1, 0, 64);
+ memset(&pass_hash_xor2, 0, 64);
+ memset(&crypt_hash_xor1, 0, 64);
+ memset(&crypt_hash_xor2, 0, 64);
+ memset(&digest1, 0, 20);
+ memset(&digest2, 0, 20);
+ memset(&magic, 0, 64);
+ memset(&resp_6, 0, 100);
+ memset(&resp_96, 0, 100);
+ memset(&magic_key_char, 0, 4);
+
+ /*
+ * Magic: Phase 1. Generate what seems to be a 30
+ * byte value (could change if base64
+ * ends up differently? I don't remember and I'm
+ * tired, so use a 64 byte buffer.
+ */
+
+ magic_ptr = (unsigned char *)seed;
+
+ while (*magic_ptr != (int)NULL) {
+ char *loc;
+
+ /* Ignore parentheses. */
+
+ if (*magic_ptr == '(' || *magic_ptr == ')') {
+ magic_ptr++;
+ continue;
+ }
+
+ /* Characters and digits verify against
+ the challenge lookup.
+ */
+
+ if (isalpha(*magic_ptr) || isdigit(*magic_ptr)) {
+ loc = strchr(challenge_lookup, *magic_ptr);
+ if (!loc) {
+ /* This isn't good */
+ continue;
+ }
+
+ /* Get offset into lookup table and lsh 3. */
+
+ magic_work = loc - challenge_lookup;
+ magic_work <<= 3;
+
+ magic_ptr++;
+ continue;
+ } else {
+ unsigned int local_store;
+
+ loc = strchr(operand_lookup, *magic_ptr);
+ if (!loc) {
+ /* Also not good. */
+ continue;
+ }
+
+ local_store = loc - operand_lookup;
+
+ /* Oops; how did this happen? */
+ if (magic_cnt >= 64)
+ break;
+
+ magic[magic_cnt++] = magic_work | local_store;
+ magic_ptr++;
+ continue;
+ }
+ }
+
+ magic_len = magic_cnt;
+ magic_cnt = 0;
+
+ /* Magic: Phase 2. Take generated magic value and
+ * sprinkle fairy dust on the values. */
+
+ for (magic_cnt = magic_len-2; magic_cnt >= 0; magic_cnt--) {
+ unsigned char byte1;
+ unsigned char byte2;
+
+ /* Bad. Abort.
+ */
+ if (magic_cnt >= magic_len) {
+ WARNING(("magic_cnt(%d) magic_len(%d)", magic_cnt, magic_len))
+ break;
+ }
+
+ byte1 = magic[magic_cnt];
+ byte2 = magic[magic_cnt+1];
+
+ byte1 *= 0xcd;
+ byte1 ^= byte2;
+
+ magic[magic_cnt+1] = byte1;
+ }
+
+ /* Magic: Phase 3. This computes 20 bytes. The first 4 bytes are used as our magic
+ * key (and may be changed later); the next 16 bytes are an MD5 sum of the magic key
+ * plus 3 bytes. The 3 bytes are found by looping, and they represent the offsets
+ * into particular functions we'll later call to potentially alter the magic key.
+ *
+ * %-)
+ */
+
+ magic_cnt = 1;
+ x = 0;
+
+ do {
+ unsigned int bl = 0;
+ unsigned int cl = magic[magic_cnt++];
+
+ if (magic_cnt >= magic_len)
+ break;
+
+ if (cl > 0x7F) {
+ if (cl < 0xe0)
+ bl = cl = (cl & 0x1f) << 6;
+ else {
+ bl = magic[magic_cnt++];
+ cl = (cl & 0x0f) << 6;
+ bl = ((bl & 0x3f) + cl) << 6;
+ }
+
+ cl = magic[magic_cnt++];
+ bl = (cl & 0x3f) + bl;
+ } else
+ bl = cl;
+
+ comparison_src[x++] = (bl & 0xff00) >> 8;
+ comparison_src[x++] = bl & 0xff;
+ } while (x < 20);
+
+ /* Dump magic key into a char for SHA1 action. */
+
+
+ for(x = 0; x < 4; x++)
+ magic_key_char[x] = comparison_src[x];
+
+ /* Compute values for recursive function table! */
+ memcpy( chal, magic_key_char, 4 );
+ x = 1;
+ for( i = 0; i < 0xFFFF && x; i++ )
+ {
+ for( j = 0; j < 5 && x; j++ )
+ {
+ chal[4] = i;
+ chal[5] = i >> 8;
+ chal[6] = j;
+ md5_init( &ctx );
+ md5_append( &ctx, chal, 7 );
+ md5_finish( &ctx, result );
+ if( memcmp( comparison_src + 4, result, 16 ) == 0 )
+ {
+ depth = i;
+ table = j;
+ x = 0;
+ }
+ }
+ }
+
+ /* Transform magic_key_char using transform table */
+ x = magic_key_char[3] << 24 | magic_key_char[2] << 16
+ | magic_key_char[1] << 8 | magic_key_char[0];
+ x = yahoo_xfrm( table, depth, x );
+ x = yahoo_xfrm( table, depth, x );
+ magic_key_char[0] = x & 0xFF;
+ magic_key_char[1] = x >> 8 & 0xFF;
+ magic_key_char[2] = x >> 16 & 0xFF;
+ magic_key_char[3] = x >> 24 & 0xFF;
+
+ /* Get password and crypt hashes as per usual. */
+ md5_init(&ctx);
+ md5_append(&ctx, (md5_byte_t *)yd->password, strlen(yd->password));
+ md5_finish(&ctx, result);
+ to_y64(password_hash, result, 16);
+
+ md5_init(&ctx);
+ crypt_result = yahoo_crypt(yd->password, "$1$_2S43d5f$");
+ md5_append(&ctx, (md5_byte_t *)crypt_result, strlen(crypt_result));
+ md5_finish(&ctx, result);
+ to_y64(crypt_hash, result, 16);
+ free(crypt_result);
+
+ /* Our first authentication response is based off
+ * of the password hash. */
+
+ for (x = 0; x < (int)strlen((char *)password_hash); x++)
+ pass_hash_xor1[cnt++] = password_hash[x] ^ 0x36;
+
+ if (cnt < 64)
+ memset(&(pass_hash_xor1[cnt]), 0x36, 64-cnt);
+
+ cnt = 0;
+
+ for (x = 0; x < (int)strlen((char *)password_hash); x++)
+ pass_hash_xor2[cnt++] = password_hash[x] ^ 0x5c;
+
+ if (cnt < 64)
+ memset(&(pass_hash_xor2[cnt]), 0x5c, 64-cnt);
+
+ shaInit(&ctx1);
+ shaInit(&ctx2);
+
+ /* The first context gets the password hash XORed
+ * with 0x36 plus a magic value
+ * which we previously extrapolated from our
+ * challenge. */
+
+ shaUpdate(&ctx1, pass_hash_xor1, 64);
+ if (j >= 3)
+ ctx1.sizeLo = 0x1ff;
+ shaUpdate(&ctx1, magic_key_char, 4);
+ shaFinal(&ctx1, digest1);
+
+ /* The second context gets the password hash XORed
+ * with 0x5c plus the SHA-1 digest
+ * of the first context. */
+
+ shaUpdate(&ctx2, pass_hash_xor2, 64);
+ shaUpdate(&ctx2, digest1, 20);
+ shaFinal(&ctx2, digest2);
+
+ /* Now that we have digest2, use it to fetch
+ * characters from an alphabet to construct
+ * our first authentication response. */
+
+ for (x = 0; x < 20; x += 2) {
+ unsigned int val = 0;
+ unsigned int lookup = 0;
+ char byte[6];
+
+ memset(&byte, 0, 6);
+
+ /* First two bytes of digest stuffed
+ * together.
+ */
+
+ val = digest2[x];
+ val <<= 8;
+ val += digest2[x+1];
+
+ lookup = (val >> 0x0b);
+ lookup &= 0x1f;
+ if (lookup >= strlen(alphabet1))
+ break;
+ sprintf(byte, "%c", alphabet1[lookup]);
+ strcat(resp_6, byte);
+ strcat(resp_6, "=");
+
+ lookup = (val >> 0x06);
+ lookup &= 0x1f;
+ if (lookup >= strlen(alphabet2))
+ break;
+ sprintf(byte, "%c", alphabet2[lookup]);
+ strcat(resp_6, byte);
+
+ lookup = (val >> 0x01);
+ lookup &= 0x1f;
+ if (lookup >= strlen(alphabet2))
+ break;
+ sprintf(byte, "%c", alphabet2[lookup]);
+ strcat(resp_6, byte);
+
+ lookup = (val & 0x01);
+ if (lookup >= strlen(delimit_lookup))
+ break;
+ sprintf(byte, "%c", delimit_lookup[lookup]);
+ strcat(resp_6, byte);
+ }
+
+ /* Our second authentication response is based off
+ * of the crypto hash. */
+
+ cnt = 0;
+ memset(&digest1, 0, 20);
+ memset(&digest2, 0, 20);
+
+ for (x = 0; x < (int)strlen((char *)crypt_hash); x++)
+ crypt_hash_xor1[cnt++] = crypt_hash[x] ^ 0x36;
+
+ if (cnt < 64)
+ memset(&(crypt_hash_xor1[cnt]), 0x36, 64-cnt);
+
+ cnt = 0;
+
+ for (x = 0; x < (int)strlen((char *)crypt_hash); x++)
+ crypt_hash_xor2[cnt++] = crypt_hash[x] ^ 0x5c;
+
+ if (cnt < 64)
+ memset(&(crypt_hash_xor2[cnt]), 0x5c, 64-cnt);
+
+ shaInit(&ctx1);
+ shaInit(&ctx2);
+
+ /* The first context gets the password hash XORed
+ * with 0x36 plus a magic value
+ * which we previously extrapolated from our
+ * challenge. */
+
+ shaUpdate(&ctx1, crypt_hash_xor1, 64);
+ if (j >= 3)
+ ctx1.sizeLo = 0x1ff;
+ shaUpdate(&ctx1, magic_key_char, 4);
+ shaFinal(&ctx1, digest1);
+
+ /* The second context gets the password hash XORed
+ * with 0x5c plus the SHA-1 digest
+ * of the first context. */
+
+ shaUpdate(&ctx2, crypt_hash_xor2, 64);
+ shaUpdate(&ctx2, digest1, 20);
+ shaFinal(&ctx2, digest2);
+
+ /* Now that we have digest2, use it to fetch
+ * characters from an alphabet to construct
+ * our first authentication response. */
+
+ for (x = 0; x < 20; x += 2) {
+ unsigned int val = 0;
+ unsigned int lookup = 0;
+
+ char byte[6];
+
+ memset(&byte, 0, 6);
+
+ /* First two bytes of digest stuffed
+ * together. */
+
+ val = digest2[x];
+ val <<= 8;
+ val += digest2[x+1];
+
+ lookup = (val >> 0x0b);
+ lookup &= 0x1f;
+ if (lookup >= strlen(alphabet1))
+ break;
+ sprintf(byte, "%c", alphabet1[lookup]);
+ strcat(resp_96, byte);
+ strcat(resp_96, "=");
+
+ lookup = (val >> 0x06);
+ lookup &= 0x1f;
+ if (lookup >= strlen(alphabet2))
+ break;
+ sprintf(byte, "%c", alphabet2[lookup]);
+ strcat(resp_96, byte);
+
+ lookup = (val >> 0x01);
+ lookup &= 0x1f;
+ if (lookup >= strlen(alphabet2))
+ break;
+ sprintf(byte, "%c", alphabet2[lookup]);
+ strcat(resp_96, byte);
+
+ lookup = (val & 0x01);
+ if (lookup >= strlen(delimit_lookup))
+ break;
+ sprintf(byte, "%c", delimit_lookup[lookup]);
+ strcat(resp_96, byte);
+ }
+
+ yss = yd->server_settings;
+
+ pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, (yd->initial_status == YAHOO_STATUS_INVISIBLE) ?YAHOO_STATUS_INVISIBLE:YAHOO_STATUS_WEBLOGIN, yd->session_id);
+ yahoo_packet_hash(pack, 6, resp_6);
+ yahoo_packet_hash(pack, 96, resp_96);
+ yahoo_packet_hash(pack, 0, sn);
+ yahoo_packet_hash(pack, 2, sn);
+
+
+ snprintf(z, sizeof(z), "%d", yss->pic_cksum);
+ yahoo_packet_hash(pack, 192, z);// avatar support yet (EXPERIMENTAL)
+ //yahoo_packet_hash(pack, 192, "-1");// no avatar support yet
+ yahoo_packet_hash(pack, 2, "1");
+ yahoo_packet_hash(pack, 1, sn);
+ // A little experiment ;) HEHEHE
+ yahoo_packet_hash(pack, 244, "524223"); // Features??? I wonder...
+ /////////////
+ //yahoo_packet_hash(pack, 135, "6,0,0,1922");
+ yahoo_packet_hash(pack, 135, "7,0,2,120");
+ yahoo_packet_hash(pack, 148, "300"); // ???
+ /* mmmm GAIM does it differently???
+ yahoo_packet_hash(pack, 0, sn);
+ yahoo_packet_hash(pack, 6, resp_6);
+ yahoo_packet_hash(pack, 96, resp_96);
+ yahoo_packet_hash(pack, 1, sn);
+ yahoo_packet_hash(pack, 135, "6,0,0,1710");
+ yahoo_packet_hash(pack, 192, "-1");// no avatar support yet
+
+ */
+ yahoo_send_packet(yid, pack, 0);
+ yahoo_packet_free(pack);
+
+ free(password_hash);
+ free(crypt_hash);
+}
+
+static void yahoo_process_auth(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ char *seed = NULL;
+ char *sn = NULL;
+ YList *l = pkt->hash;
+ int m = 0;
+
+ while (l) {
+ struct yahoo_pair *pair = l->data;
+ if (pair->key == 94)
+ seed = pair->value;
+ if (pair->key == 1)
+ sn = pair->value;
+ if (pair->key == 13)
+ m = atoi(pair->value);
+ l = l->next;
+ }
+
+ if (!seed)
+ return;
+
+ switch (m) {
+ case 0:
+ yahoo_process_auth_pre_0x0b(yid, seed, sn);
+ break;
+ case 1:
+ yahoo_process_auth_0x0b(yid, seed, sn);
+ break;
+ default:
+ /* call error */
+ WARNING(("unknown auth type %d", m));
+ yahoo_process_auth_0x0b(yid, seed, sn);
+ break;
+ }
+}
+
+static void yahoo_process_auth_resp(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ struct yahoo_data *yd = yid->yd;
+ char *login_id;
+ char *handle;
+ char *url=NULL;
+ int login_status=0;
+
+ YList *l;
+
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ if (pair->key == 0)
+ login_id = pair->value;
+ else if (pair->key == 1)
+ handle = pair->value;
+ else if (pair->key == 20)
+ url = pair->value;
+ else if (pair->key == 66)
+ login_status = atoi(pair->value);
+ }
+
+ if(pkt->status == 0xffffffff) {
+ YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, login_status, url);
+ /* yahoo_logoff(yd->client_id);*/
+ }
+}
+
+static void yahoo_process_mail(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ struct yahoo_data *yd = yid->yd;
+ char *who = NULL;
+ char *email = NULL;
+ char *subj = NULL;
+ int count = 0;
+ YList *l;
+
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ if (pair->key == 9)
+ count = strtol(pair->value, NULL, 10);
+ else if (pair->key == 43)
+ who = pair->value;
+ else if (pair->key == 42)
+ email = pair->value;
+ else if (pair->key == 18)
+ subj = pair->value;
+ else
+ LOG(("key: %d => value: '%s'", pair->key, pair->value));
+ }
+
+ if (who && email && subj) {
+ char from[1024];
+ snprintf(from, sizeof(from), "%s (%s)", who, email);
+ YAHOO_CALLBACK(ext_yahoo_mail_notify)(yd->client_id, from, subj, count);
+ } else
+ YAHOO_CALLBACK(ext_yahoo_mail_notify)(yd->client_id, NULL, NULL, count);
+}
+
+static void yahoo_buddy_added_us(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ struct yahoo_data *yd = yid->yd;
+ char *id = NULL;
+ char *who = NULL;
+ char *msg = NULL;
+ long tm = 0L;
+ YList *l;
+
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ switch (pair->key) {
+ case 1:
+ id = pair->value;
+ break;
+ case 3:
+ who = pair->value;
+ break;
+ case 14:
+ msg = pair->value;
+ break;
+ case 15:
+ tm = strtol(pair->value, NULL, 10);
+ break;
+ default:
+ LOG(("key: %d => value: '%s'", pair->key, pair->value));
+ }
+ }
+
+ YAHOO_CALLBACK(ext_yahoo_contact_added)(yd->client_id, id, who, NULL, NULL, msg);
+}
+
+static void yahoo_buddy_denied_our_add(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ struct yahoo_data *yd = yid->yd;
+ char *who = NULL;
+ char *msg = NULL;
+ YList *l;
+
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ switch (pair->key) {
+ case 3:
+ who = pair->value;
+ break;
+ case 14:
+ msg = pair->value;
+ break;
+ default:
+ LOG(("key: %d => value: '%s'", pair->key, pair->value));
+ }
+ }
+
+ YAHOO_CALLBACK(ext_yahoo_rejected)(yd->client_id, who, msg);
+}
+
+static void yahoo_process_contact(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ switch (pkt->status) {
+ case 1:
+ yahoo_process_status(yid, pkt);
+ return;
+ case 3:
+ yahoo_buddy_added_us(yid, pkt);
+ break;
+ case 7:
+ yahoo_buddy_denied_our_add(yid, pkt);
+ break;
+ default:
+ LOG(("Unknown status value: '%s'", pkt->status));
+ }
+
+}
+
+static void yahoo_process_authorization(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ struct yahoo_data *yd = yid->yd;
+ char *who = NULL,
+ *msg = NULL,
+ *fname = NULL,
+ *lname = NULL,
+ *id = NULL;
+ int state = 0, utf8 = 0;
+ YList *l;
+
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ switch (pair->key) {
+ case 4: /* who added us */
+ who = pair->value;
+ break;
+
+ case 5: /* our identity */
+ id = pair->value;
+ break;
+
+ case 13: /* which type of request this is */
+ state = strtol(pair->value, NULL, 10);
+ break;
+
+ case 14: /* was there a message ? */
+ msg = pair->value;
+ break;
+
+ case 97: /* Unicode flag? */
+ utf8 = strtol(pair->value, NULL, 10);
+ break;
+
+ case 216: /* first name */
+ fname = pair->value;
+ break;
+
+ case 254: /* last name */
+ lname = pair->value;
+ break;
+
+ default:
+ LOG(("key: %d => value: '%s'", pair->key, pair->value));
+ }
+ }
+
+ switch (state) {
+ case 1: /* Authorization Accepted */
+
+ break;
+ case 2: /* Authorization Denied */
+ YAHOO_CALLBACK(ext_yahoo_rejected)(yd->client_id, who, msg);
+ break;
+ default: /* Authorization Request? */
+ YAHOO_CALLBACK(ext_yahoo_contact_added)(yd->client_id, id, who, fname, lname, msg);
+
+ }
+
+}
+
+static void yahoo_process_buddyadd(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ struct yahoo_data *yd = yid->yd;
+ char *who = NULL;
+ char *where = NULL;
+ int status = 0, auth = 0;
+ char *me = NULL;
+
+ struct yahoo_buddy *bud=NULL;
+
+ YList *l;
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+
+ switch (pair->key){
+ case 1:
+ me = pair->value;
+ break;
+ case 7:
+ who = pair->value;
+ break;
+ case 65:
+ where = pair->value;
+ break;
+ case 66:
+ status = strtol(pair->value, NULL, 10);
+ break;
+ case 223:
+ auth = strtol(pair->value, NULL, 10);
+ break;
+ }
+ }
+
+ //yahoo_dump_unhandled(pkt);
+
+ if(!who)
+ return;
+ if(!where)
+ where = "Unknown";
+
+ bud = y_new0(struct yahoo_buddy, 1);
+ bud->id = strdup(who);
+ bud->group = strdup(where);
+ bud->real_name = NULL;
+
+ yd->buddies = y_list_append(yd->buddies, bud);
+
+ YAHOO_CALLBACK(ext_yahoo_buddy_added)(yd->client_id, me, who, where, status, auth);
+/* YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, who, status, NULL, (status==YAHOO_STATUS_AVAILABLE?0:1)); */
+}
+
+static void yahoo_process_buddydel(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ struct yahoo_data *yd = yid->yd;
+ char *who = NULL;
+ char *where = NULL;
+ int unk_66 = 0;
+ char *me = NULL;
+ struct yahoo_buddy *bud;
+
+ YList *buddy;
+
+ YList *l;
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ if (pair->key == 1)
+ me = pair->value;
+ else if (pair->key == 7)
+ who = pair->value;
+ else if (pair->key == 65)
+ where = pair->value;
+ else if (pair->key == 66)
+ unk_66 = strtol(pair->value, NULL, 10);
+ else
+ DEBUG_MSG(("unknown key: %d = %s", pair->key, pair->value));
+ }
+
+ if(!who || !where)
+ return;
+
+ bud = y_new0(struct yahoo_buddy, 1);
+ bud->id = strdup(who);
+ bud->group = strdup(where);
+
+ buddy = y_list_find_custom(yd->buddies, bud, is_same_bud);
+
+ FREE(bud->id);
+ FREE(bud->group);
+ FREE(bud);
+
+ if(buddy) {
+ bud = buddy->data;
+ yd->buddies = y_list_remove_link(yd->buddies, buddy);
+ y_list_free_1(buddy);
+
+ FREE(bud->id);
+ FREE(bud->group);
+ FREE(bud->real_name);
+ FREE(bud);
+
+ bud=NULL;
+ }
+}
+static void yahoo_process_yahoo7_change_group(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ struct yahoo_data *yd = yid->yd;
+ char *who = NULL;
+ char *me = NULL;
+ char *old_group = NULL;
+ char *new_group = NULL;
+
+ YList *l;
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+
+ switch (pair->key){
+ case 1:
+ me = pair->value;
+ break;
+ case 7:
+ who = pair->value;
+ break;
+ case 224:
+ old_group = pair->value;
+ break;
+ case 264:
+ new_group = pair->value;
+ break;
+ }
+ }
+
+ YAHOO_CALLBACK(ext_yahoo_buddy_group_changed)(yd->client_id, me, who, old_group, new_group);
+}
+
+static void yahoo_process_ignore(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ struct yahoo_data *yd = yid->yd;
+ char *who = NULL;
+ int status = 0;
+ char *me = NULL;
+ int un_ignore = 0;
+
+ YList *l;
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ if (pair->key == 0)
+ who = pair->value;
+ if (pair->key == 1)
+ me = pair->value;
+ if (pair->key == 13) /* 1 == ignore, 2 == unignore */
+ un_ignore = strtol(pair->value, NULL, 10);
+ if (pair->key == 66)
+ status = strtol(pair->value, NULL, 10);
+ }
+
+
+ /*
+ * status
+ * 0 - ok
+ * 2 - already in ignore list, could not add
+ * 3 - not in ignore list, could not delete
+ * 12 - is a buddy, could not add
+ */
+
+ if(status) {
+ YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, who, 0, status);
+ } else {
+ /* we adding or removing to the ignore list */
+ if (un_ignore == 1) { /* ignore */
+ struct yahoo_buddy *bud = y_new0(struct yahoo_buddy, 1);
+
+ bud->id = strdup(who);
+ bud->group = NULL;
+ bud->real_name = NULL;
+
+ yd->ignore = y_list_append(yd->ignore, bud);
+
+ } else { /* unignore */
+ YList *buddy;
+
+ buddy = yd->ignore;
+
+ while (buddy) {
+ struct yahoo_buddy *b = (struct yahoo_buddy *) buddy->data;
+
+ if (lstrcmpi(b->id, who) == 0)
+ break;
+
+ buddy = buddy->next;
+ }
+
+ if(buddy) {
+ struct yahoo_buddy *bud = buddy->data;
+ yd->ignore = y_list_remove_link(yd->ignore, buddy);
+ y_list_free_1(buddy);
+
+ FREE(bud->id);
+ FREE(bud->group);
+ FREE(bud->real_name);
+ FREE(bud);
+
+ bud=NULL;
+ }
+ }
+ }
+}
+
+static void yahoo_process_stealth(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ //struct yahoo_data *yd = yid->yd;
+ char *who = NULL;
+ int status = 0;
+
+ YList *l;
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ if (pair->key == 7)
+ who = pair->value;
+
+ if (pair->key == 31)
+ status = strtol(pair->value, NULL, 10);
+ }
+
+ NOTICE(("got %s stealth info for %s with value: %d", pkt->service == YAHOO_SERVICE_STEALTH_PERM ? "permanent": "session" , who, status == 1));
+}
+
+static void yahoo_process_voicechat(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ char *who = NULL;
+ char *me = NULL;
+ char *room = NULL;
+ char *voice_room = NULL;
+
+ YList *l;
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ if (pair->key == 4)
+ who = pair->value;
+ if (pair->key == 5)
+ me = pair->value;
+ if (pair->key == 13)
+ voice_room=pair->value;
+ if (pair->key == 57)
+ room=pair->value;
+ }
+
+ NOTICE(("got voice chat invite from %s in %s to identity %s", who, room, me));
+ /*
+ * send: s:0 1:me 5:who 57:room 13:1
+ * ???? s:4 5:who 10:99 19:-1615114531
+ * gotr: s:4 5:who 10:99 19:-1615114615
+ * ???? s:1 5:me 4:who 57:room 13:3room
+ * got: s:1 5:me 4:who 57:room 13:1room
+ * rej: s:0 1:me 5:who 57:room 13:3
+ * rejr: s:4 5:who 10:99 19:-1617114599
+ */
+}
+
+static void yahoo_process_picture(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ char *who = NULL;
+ char *me = NULL;
+ char *pic_url = NULL;
+ int cksum = 0;
+ int type = 0;
+
+ YList *l;
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+
+ /* based on GAIM code */
+ switch (pair->key) {
+ case 1:
+ case 4:
+ who = pair->value;
+ break;
+ case 5:
+ me = pair->value;
+ break;
+ case 13:
+ type = strtol(pair->value, NULL, 10);
+ break;
+ case 20:
+ pic_url=pair->value;
+ break;
+ case 192:
+ cksum = strtol(pair->value, NULL, 10);
+ break;
+ } /*switch */
+
+ }
+ NOTICE(("got picture packet"));
+ YAHOO_CALLBACK(ext_yahoo_got_picture)(yid->yd->client_id, me, who, pic_url, cksum, type);
+}
+
+void yahoo_send_picture_info(int id, const char *who, int type, const char *pic_url, int cksum)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt = NULL;
+ struct yahoo_server_settings *yss;
+ char buf[15];
+
+ if(!yid)
+ return;
+
+ yd = yid->yd;
+ yss = yd->server_settings;
+ pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE, YAHOO_STATUS_AVAILABLE, yd->session_id);
+
+ yahoo_packet_hash(pkt, 1, yd->user);
+ //yahoo_packet_hash(pkt, 4, yd->user);
+ yahoo_packet_hash(pkt, 5, who);
+
+ snprintf(buf, sizeof(buf), "%d", type); // 2 info, 3 invalidate
+ yahoo_packet_hash(pkt, 13, buf);
+
+ yahoo_packet_hash(pkt, 20, pic_url);
+
+ snprintf(buf, sizeof(buf), "%d", cksum);
+ yahoo_packet_hash(pkt, 192, buf);
+ yahoo_send_packet(yid, pkt, 0);
+
+ if (yss->web_messenger) {
+ char z[128];
+
+ yahoo_packet_hash(pkt, 0, yd->user);
+ wsprintf(z, "%d", yd->session_timestamp);
+ yahoo_packet_hash(pkt, 24, z);
+ }
+
+ yahoo_packet_free(pkt);
+}
+
+void yahoo_send_picture_update(int id, const char *who, int type)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt = NULL;
+ struct yahoo_server_settings *yss;
+ char buf[2];
+
+ if(!yid)
+ return;
+
+ yd = yid->yd;
+ yss = yd->server_settings;
+ pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_UPDATE, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_packet_hash(pkt, 1, yd->user);
+ yahoo_packet_hash(pkt, 5, who);
+
+ snprintf(buf, sizeof(buf), "%d", type);
+ yahoo_packet_hash(pkt, 206, buf);
+ yahoo_send_packet(yid, pkt, 0);
+
+ if (yss->web_messenger) {
+ char z[128];
+
+ yahoo_packet_hash(pkt, 0, yd->user);
+ wsprintf(z, "%d", yd->session_timestamp);
+ yahoo_packet_hash(pkt, 24, z);
+ }
+
+ yahoo_packet_free(pkt);
+}
+
+
+void yahoo_send_picture_checksum(int id, const char *who, int cksum)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt = NULL;
+ struct yahoo_server_settings *yss;
+ char buf[22];
+
+ if(!yid)
+ return;
+
+ yd = yid->yd;
+ yss = yd->server_settings;
+ pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_CHECKSUM, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_packet_hash(pkt, 1, yd->user);
+
+ if (who)
+ yahoo_packet_hash(pkt, 5, who); // ?
+
+ yahoo_packet_hash(pkt, 212, "1"); // ?
+
+ snprintf(buf, sizeof(buf), "%d", cksum);
+ yahoo_packet_hash(pkt, 192, buf); // checksum
+ yahoo_send_packet(yid, pkt, 0);
+
+ if (yss->web_messenger) {
+ char z[128];
+
+ yahoo_packet_hash(pkt, 0, yd->user);
+ wsprintf(z, "%d", yd->session_timestamp);
+ yahoo_packet_hash(pkt, 24, z);
+ }
+
+ yahoo_packet_free(pkt);
+
+ /* weird YIM7 sends another packet! See avatar_update below*/
+}
+
+void yahoo_send_avatar_update(int id, int buddy_icon)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt = NULL;
+ struct yahoo_server_settings *yss;
+ char buf[2];
+
+ if(!yid)
+ return;
+
+ yd = yid->yd;
+ yss = yd->server_settings;
+ pkt = yahoo_packet_new(YAHOO_SERVICE_AVATAR_UPDATE, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_packet_hash(pkt, 3, yd->user);
+ snprintf(buf, sizeof(buf), "%d", buddy_icon);
+ yahoo_packet_hash(pkt, 213, buf);
+
+ if (yss->web_messenger) {
+ char z[128];
+
+ yahoo_packet_hash(pkt, 0, yd->user);
+ wsprintf(z, "%d", yd->session_timestamp);
+ yahoo_packet_hash(pkt, 24, z);
+ }
+
+ yahoo_send_packet(yid, pkt, 0);
+
+ yahoo_packet_free(pkt);
+}
+
+static void yahoo_process_picture_checksum(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ char *who = NULL;
+ char *me = NULL;
+ int cksum = 0;
+
+ YList *l;
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ if (pair->key == 4)
+ who = pair->value;
+ if (pair->key == 5)
+ me = pair->value;
+ if (pair->key == 192)
+ cksum = strtol(pair->value, NULL, 10);
+
+ }
+ NOTICE(("got picture_checksum packet"));
+ YAHOO_CALLBACK(ext_yahoo_got_picture_checksum)(yid->yd->client_id, me, who, cksum);
+}
+
+static void yahoo_process_picture_update(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ char *who = NULL;
+ char *me = NULL;
+ int buddy_icon = -1;
+
+ YList *l;
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ if (pair->key == 4)
+ who = pair->value;
+ if (pair->key == 5)
+ me = pair->value;
+ if (pair->key == 206)
+ buddy_icon = strtol(pair->value, NULL, 10);
+
+ }
+ NOTICE(("got picture_update packet"));
+ YAHOO_CALLBACK(ext_yahoo_got_picture_update)(yid->yd->client_id, me, who, buddy_icon);
+}
+
+static void yahoo_process_picture_upload(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ char *url = NULL;
+ char *me = NULL;
+ unsigned int ts = 0;
+
+ YList *l;
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ switch (pair->key){
+ case 5: /* our id */
+ me = pair->value;
+ break;
+ case 27: /* filename on our computer */
+ break;
+ case 20: /* url at yahoo */
+ url = pair->value;
+ break;
+ case 38: /* timestamp */
+ ts = strtol(pair->value, NULL, 10);
+ break;
+ }
+ }
+ NOTICE(("got picture_upload packet"));
+ YAHOO_CALLBACK(ext_yahoo_got_picture_upload)(yid->yd->client_id, me, url, ts);
+}
+
+static void yahoo_process_avatar_update(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ char *who = NULL;
+ char *me = NULL;
+ int buddy_icon = -1;
+
+ YList *l;
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ switch (pair->key){
+ case 5: /* our id */
+ me = pair->value;
+ break;
+ case 4: /* who is notifying all */
+ who = pair->value;
+ break;
+ case 213: /* picture = 0-none, 1-?, 2=picture */
+ buddy_icon = strtol(pair->value, NULL, 10);
+ break;
+ }
+ }
+ NOTICE(("got picture_upload packet"));
+ if (who) // sometimes we just get a confirmation without the WHO.(ack on our avt update)
+ YAHOO_CALLBACK(ext_yahoo_got_avatar_update)(yid->yd->client_id, me, who, buddy_icon);
+}
+
+static void yahoo_process_audible(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ char *who = NULL;
+ char *me = NULL;
+ char *aud_hash=NULL;
+ char *msg = NULL;
+ char *aud = NULL;
+
+ YList *l;
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ switch (pair->key){
+ case 5: /* our id */
+ me = pair->value;
+ break;
+ case 4: /* who is notifying all */
+ who = pair->value;
+ break;
+ case 230: /* file class name
+ GAIM: the audible, in foo.bar.baz format
+
+ Actually this is the filename.
+ Full URL:
+
+ http://us.dl1.yimg.com/download.yahoo.com/dl/aud/us/aud.swf
+
+ where aud in foo.bar.baz format
+ */
+ aud = pair->value;
+ break;
+ case 231: /*audible text*/
+ msg = pair->value;
+ break;
+ case 232: /* weird number (md5 hash?) */
+ aud_hash = pair->value;
+ break;
+ }
+ }
+ NOTICE(("got picture_upload packet"));
+ if (who) // sometimes we just get a confirmation without the WHO.(ack on our send/update)
+ YAHOO_CALLBACK(ext_yahoo_got_audible)(yid->yd->client_id, me, who, aud, msg, aud_hash);
+}
+
+static void yahoo_process_calendar(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ char *msg = NULL;
+ char *url = NULL;
+ int svc = -1, type = -1;
+
+ YList *l;
+
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ switch (pair->key){
+ case 20: /* url to calendar reminder/event */
+ if (pair->value[0] != '\0')
+ url = pair->value;
+ break;
+ case 21: /* type? number seems to be 0? */
+ type = atol(pair->value);
+ break;
+ case 14: /* index msg/title ? */
+ if (pair->value[0] != '\0')
+ msg = pair->value;
+ break;
+ case 13: /* service # ? */
+ svc = atol(pair->value);
+ break;
+ }
+ }
+
+ if (url) // sometimes we just get a reminder w/o the URL
+ YAHOO_CALLBACK(ext_yahoo_got_calendar)(yid->yd->client_id, url, type, msg, svc);
+}
+
+
+static void yahoo_process_ping(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ char *errormsg = NULL;
+
+ YList *l;
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ if (pair->key == 16)
+ errormsg = pair->value;
+ }
+
+ NOTICE(("got ping packet"));
+ YAHOO_CALLBACK(ext_yahoo_got_ping)(yid->yd->client_id, errormsg);
+}
+
+static void yahoo_process_yab_update(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ char *who=NULL,*yentry=NULL;
+ int svc=0;
+ YList *l;
+
+ /*
+ [15:42:00 YAHOO] Yahoo Service: (null) (0xc4) Status: YAHOO_STATUS_AVAILABLE (0)
+[15:42:00 YAHOO]
+[15:42:00 YAHOO] libyahoo2/libyahoo2.c:900: debug:
+[15:42:00 YAHOO] [Reading packet] len: 309
+[15:42:00 YAHOO]
+[15:42:00 YAHOO] Key: To (5) Value: 'xxxxxxx'
+[15:42:00 YAHOO]
+[15:42:00 YAHOO] Key: (null) (203) Value: '<?xml version="1.0" encoding="ISO-8859-1"?>
+ <ab k="aaaaaaa" cc="1" ec="1" rs="OK"><ct e="1" id="1" mt="1147894756" cr="1090811437" fn="ZZZ" ln="XXX"
+ e0="aaaa@yahoo.com" nn="AAAA" ca="Unfiled" yi="xxxxxxx" pr="0" cm="Some personal notes here."
+ imm="xxxxxx@hotmail.com"/></ab>'
+[15:42:00 YAHOO]
+[15:42:00 YAHOO] Key: stat/location (13) Value: '1'
+
+ */
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ switch (pair->key) {
+ case 5: /* who */
+ who = pair->value;
+ break;
+ case 203: /* yab entry */
+ yentry = pair->value;
+ break;
+ case 13: /* type of update */
+ svc = atoi(pair->value);
+ }
+ }
+
+ NOTICE(("got YAB Update packet"));
+ //YAHOO_CALLBACK(ext_yahoo_got_ping)(yid->yd->client_id, errormsg);
+}
+
+static void _yahoo_webcam_get_server_connected(int fd, int error, void *d)
+{
+ struct yahoo_input_data *yid = d;
+ char *who = yid->wcm->user;
+ char *data = NULL;
+ char *packet = NULL;
+ unsigned char magic_nr[] = {0, 1, 0};
+ unsigned char header_len = 8;
+ unsigned int len = 0;
+ unsigned int pos = 0;
+
+ if(error || fd <= 0) {
+ FREE(who);
+ FREE(yid);
+ return;
+ }
+
+ yid->fd = fd;
+ inputs = y_list_prepend(inputs, yid);
+
+ /* send initial packet */
+ if (who)
+ data = strdup("<RVWCFG>");
+ else
+ data = strdup("<RUPCFG>");
+ yahoo_add_to_send_queue(yid, data, strlen(data));
+ FREE(data);
+
+ /* send data */
+ if (who)
+ {
+ data = strdup("g=");
+ data = y_string_append(data, who);
+ data = y_string_append(data, "\r\n");
+ } else {
+ data = strdup("f=1\r\n");
+ }
+ len = strlen(data);
+ packet = y_new0(char, header_len + len);
+ packet[pos++] = header_len;
+ memcpy(packet + pos, magic_nr, sizeof(magic_nr));
+ pos += sizeof(magic_nr);
+ pos += yahoo_put32(packet + pos, len);
+ memcpy(packet + pos, data, len);
+ pos += len;
+ yahoo_add_to_send_queue(yid, packet, pos);
+ FREE(packet);
+ FREE(data);
+
+ yid->read_tag=YAHOO_CALLBACK(ext_yahoo_add_handler)(yid->yd->client_id, fd, YAHOO_INPUT_READ, yid);
+}
+
+static void yahoo_webcam_get_server(struct yahoo_input_data *y, char *who, char *key)
+{
+ struct yahoo_input_data *yid = y_new0(struct yahoo_input_data, 1);
+ struct yahoo_server_settings *yss = y->yd->server_settings;
+
+ yid->type = YAHOO_CONNECTION_WEBCAM_MASTER;
+ yid->yd = y->yd;
+ yid->wcm = y_new0(struct yahoo_webcam, 1);
+ yid->wcm->user = who?strdup(who):NULL;
+ yid->wcm->direction = who?YAHOO_WEBCAM_DOWNLOAD:YAHOO_WEBCAM_UPLOAD;
+ yid->wcm->key = strdup(key);
+
+ YAHOO_CALLBACK(ext_yahoo_connect_async)(yid->yd->client_id, yss->webcam_host, yss->webcam_port, yid->type,
+ _yahoo_webcam_get_server_connected, yid);
+
+}
+
+static YList *webcam_queue=NULL;
+static void yahoo_process_webcam_key(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ char *me = NULL;
+ char *key = NULL;
+ char *who = NULL;
+
+ YList *l;
+ yahoo_dump_unhandled(pkt);
+ for (l = pkt->hash; l; l = l->next) {
+ struct yahoo_pair *pair = l->data;
+ if (pair->key == 5)
+ me = pair->value;
+ if (pair->key == 61)
+ key=pair->value;
+ }
+
+ l = webcam_queue;
+ if(!l)
+ return;
+ who = l->data;
+ webcam_queue = y_list_remove_link(webcam_queue, webcam_queue);
+ y_list_free_1(l);
+ yahoo_webcam_get_server(yid, who, key);
+ FREE(who);
+}
+
+static void yahoo_packet_process(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+ DEBUG_MSG(("yahoo_packet_process: 0x%02x", pkt->service));
+ switch (pkt->service)
+ {
+ case YAHOO_SERVICE_LOGON:
+ yahoo_process_logon(yid, pkt);
+ break;
+ case YAHOO_SERVICE_USERSTAT:
+ case YAHOO_SERVICE_LOGOFF:
+ case YAHOO_SERVICE_ISAWAY:
+ case YAHOO_SERVICE_ISBACK:
+ case YAHOO_SERVICE_GAMELOGON:
+ case YAHOO_SERVICE_GAMELOGOFF:
+ case YAHOO_SERVICE_IDACT:
+ case YAHOO_SERVICE_IDDEACT:
+ case YAHOO_SERVICE_Y6_STATUS_UPDATE:
+ yahoo_process_status(yid, pkt);
+ break;
+ case YAHOO_SERVICE_NOTIFY:
+ yahoo_process_notify(yid, pkt);
+ break;
+ case YAHOO_SERVICE_MESSAGE:
+ case YAHOO_SERVICE_GAMEMSG:
+ case YAHOO_SERVICE_SYSMESSAGE:
+ yahoo_process_message(yid, pkt);
+ break;
+ case YAHOO_SERVICE_NEWMAIL:
+ yahoo_process_mail(yid, pkt);
+ break;
+ case YAHOO_SERVICE_NEWCONTACT:
+ yahoo_process_contact(yid, pkt);
+ break;
+ case YAHOO_SERVICE_LIST:
+ yahoo_process_list(yid, pkt);
+ break;
+ case YAHOO_SERVICE_VERIFY:
+ yahoo_process_verify(yid, pkt);
+ break;
+ case YAHOO_SERVICE_AUTH:
+ yahoo_process_auth(yid, pkt);
+ break;
+ case YAHOO_SERVICE_AUTHRESP:
+ yahoo_process_auth_resp(yid, pkt);
+ break;
+ case YAHOO_SERVICE_CONFINVITE:
+ case YAHOO_SERVICE_CONFADDINVITE:
+ case YAHOO_SERVICE_CONFDECLINE:
+ case YAHOO_SERVICE_CONFLOGON:
+ case YAHOO_SERVICE_CONFLOGOFF:
+ case YAHOO_SERVICE_CONFMSG:
+ yahoo_process_conference(yid, pkt);
+ break;
+ case YAHOO_SERVICE_CHATONLINE:
+ case YAHOO_SERVICE_CHATGOTO:
+ case YAHOO_SERVICE_CHATJOIN:
+ case YAHOO_SERVICE_CHATLEAVE:
+ case YAHOO_SERVICE_CHATEXIT:
+ case YAHOO_SERVICE_CHATLOGOUT:
+ case YAHOO_SERVICE_CHATPING:
+ case YAHOO_SERVICE_COMMENT:
+ yahoo_process_chat(yid, pkt);
+ break;
+ case YAHOO_SERVICE_P2PFILEXFER:
+ case YAHOO_SERVICE_FILETRANSFER:
+ yahoo_process_filetransfer(yid, pkt);
+ break;
+ case YAHOO_SERVICE_ADDBUDDY:
+ yahoo_process_buddyadd(yid, pkt);
+ break;
+ case YAHOO_SERVICE_REMBUDDY:
+ yahoo_process_buddydel(yid, pkt);
+ break;
+ case YAHOO_SERVICE_IGNORECONTACT:
+ yahoo_process_ignore(yid, pkt);
+ break;
+ case YAHOO_SERVICE_STEALTH_PERM:
+ case YAHOO_SERVICE_STEALTH_SESSION:
+ yahoo_process_stealth(yid, pkt);
+ break;
+ case YAHOO_SERVICE_VOICECHAT:
+ yahoo_process_voicechat(yid, pkt);
+ break;
+ case YAHOO_SERVICE_WEBCAM:
+ yahoo_process_webcam_key(yid, pkt);
+ break;
+ case YAHOO_SERVICE_PING:
+ yahoo_process_ping(yid, pkt);
+ break;
+ case YAHOO_SERVICE_PICTURE:
+ yahoo_process_picture(yid, pkt);
+ break;
+ case YAHOO_SERVICE_PICTURE_CHECKSUM:
+ yahoo_process_picture_checksum(yid, pkt);
+ break;
+ case YAHOO_SERVICE_PICTURE_UPDATE:
+ yahoo_process_picture_update(yid, pkt);
+ break;
+ case YAHOO_SERVICE_PICTURE_UPLOAD:
+ yahoo_process_picture_upload(yid, pkt);
+ break;
+ case YAHOO_SERVICE_YAB_UPDATE:
+ yahoo_process_yab_update(yid, pkt);
+ break;
+ case YAHOO_SERVICE_AVATAR_UPDATE:
+ yahoo_process_avatar_update(yid, pkt);
+ break;
+ case YAHOO_SERVICE_AUDIBLE:
+ yahoo_process_audible(yid, pkt);
+ break;
+ case YAHOO_SERVICE_CALENDAR:
+ yahoo_process_calendar(yid, pkt);
+ break;
+ case YAHOO_SERVICE_Y7_AUTHORIZATION:
+ yahoo_process_authorization(yid, pkt);
+ break;
+ case YAHOO_SERVICE_Y7_FILETRANSFER:
+ yahoo_process_filetransfer7(yid, pkt);
+ break;
+ case YAHOO_SERVICE_Y7_FILETRANSFERINFO:
+ yahoo_process_filetransfer7info(yid, pkt);
+ break;
+ case YAHOO_SERVICE_Y7_CHANGE_GROUP:
+ yahoo_process_yahoo7_change_group(yid, pkt);
+ break;
+ case YAHOO_SERVICE_IDLE:
+ case YAHOO_SERVICE_MAILSTAT:
+ case YAHOO_SERVICE_CHATINVITE:
+ case YAHOO_SERVICE_NEWPERSONALMAIL:
+ case YAHOO_SERVICE_ADDIDENT:
+ case YAHOO_SERVICE_ADDIGNORE:
+ case YAHOO_SERVICE_GOTGROUPRENAME:
+ case YAHOO_SERVICE_GROUPRENAME:
+ case YAHOO_SERVICE_PASSTHROUGH2:
+ case YAHOO_SERVICE_CHATLOGON:
+ case YAHOO_SERVICE_CHATLOGOFF:
+ case YAHOO_SERVICE_CHATMSG:
+ case YAHOO_SERVICE_REJECTCONTACT:
+ case YAHOO_SERVICE_PEERTOPEER:
+ WARNING(("unhandled service 0x%02x", pkt->service));
+ yahoo_dump_unhandled(pkt);
+ break;
+ default:
+ WARNING(("unknown service 0x%02x", pkt->service));
+ yahoo_dump_unhandled(pkt);
+ break;
+ }
+}
+
+static struct yahoo_packet * yahoo_getdata(struct yahoo_input_data * yid)
+{
+ struct yahoo_packet *pkt;
+ struct yahoo_data *yd = yid->yd;
+ int pos = 0;
+ int pktlen;
+
+ if(!yd)
+ return NULL;
+
+ DEBUG_MSG(("rxlen is %d", yid->rxlen));
+ if (yid->rxlen < YAHOO_PACKET_HDRLEN) {
+ DEBUG_MSG(("len < YAHOO_PACKET_HDRLEN"));
+ return NULL;
+ }
+
+ /*DEBUG_MSG(("Dumping Packet Header:"));
+ yahoo_packet_dump(yid->rxqueue + pos, YAHOO_PACKET_HDRLEN);
+ DEBUG_MSG(("--- Done Dumping Packet Header ---"));*/
+ {
+ char *buf = yid->rxqueue + pos;
+
+ if (buf[0] != 'Y' || buf[1] != 'M' || buf[2] != 'S' || buf[3] != 'G') {
+ DEBUG_MSG(("Not a YMSG packet?"));
+ return NULL;
+ }
+ }
+ pos += 4; /* YMSG */
+ pos += 2;
+ pos += 2;
+
+ pktlen = yahoo_get16(yid->rxqueue + pos); pos += 2;
+ DEBUG_MSG(("%d bytes to read, rxlen is %d",
+ pktlen, yid->rxlen));
+
+ if (yid->rxlen < (YAHOO_PACKET_HDRLEN + pktlen)) {
+ DEBUG_MSG(("len < YAHOO_PACKET_HDRLEN + pktlen"));
+ return NULL;
+ }
+
+ LOG(("reading packet"));
+ //yahoo_packet_dump(yid->rxqueue, YAHOO_PACKET_HDRLEN + pktlen);
+
+ pkt = yahoo_packet_new(0, 0, 0);
+
+ pkt->service = yahoo_get16(yid->rxqueue + pos); pos += 2;
+ pkt->status = yahoo_get32(yid->rxqueue + pos); pos += 4;
+ DEBUG_MSG(("Yahoo Service: %s (0x%02x) Status: %s (%d)", dbg_service(pkt->service), pkt->service,
+ dbg_status(pkt->status),pkt->status));
+ pkt->id = yahoo_get32(yid->rxqueue + pos); pos += 4;
+
+ yd->session_id = pkt->id;
+
+ yahoo_packet_read(pkt, yid->rxqueue + pos, pktlen);
+
+ yid->rxlen -= YAHOO_PACKET_HDRLEN + pktlen;
+ //DEBUG_MSG(("rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
+ if (yid->rxlen>0) {
+ unsigned char *tmp = y_memdup(yid->rxqueue + YAHOO_PACKET_HDRLEN
+ + pktlen, yid->rxlen);
+ FREE(yid->rxqueue);
+ yid->rxqueue = tmp;
+ //DEBUG_MSG(("new rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
+ } else {
+ //DEBUG_MSG(("freed rxqueue == %p", yid->rxqueue));
+ FREE(yid->rxqueue);
+ }
+
+ return pkt;
+}
+
+static void yahoo_yab_read(struct yab *yab, unsigned char *d, int len)
+{
+ char *st, *en;
+ char *data = (char *)d;
+ data[len]='\0';
+
+ DEBUG_MSG(("Got yab: %s", data));
+ st = en = strstr(data, "userid=\"");
+ if(st) {
+ st += strlen("userid=\"");
+ en = strchr(st, '"'); *en++ = '\0';
+ yab->id = yahoo_xmldecode(st);
+ }
+
+ st = strstr(en, "fname=\"");
+ if(st) {
+ st += strlen("fname=\"");
+ en = strchr(st, '"'); *en++ = '\0';
+ yab->fname = yahoo_xmldecode(st);
+ }
+
+ st = strstr(en, "lname=\"");
+ if(st) {
+ st += strlen("lname=\"");
+ en = strchr(st, '"'); *en++ = '\0';
+ yab->lname = yahoo_xmldecode(st);
+ }
+
+ st = strstr(en, "nname=\"");
+ if(st) {
+ st += strlen("nname=\"");
+ en = strchr(st, '"'); *en++ = '\0';
+ yab->nname = yahoo_xmldecode(st);
+ }
+
+ st = strstr(en, "email=\"");
+ if(st) {
+ st += strlen("email=\"");
+ en = strchr(st, '"'); *en++ = '\0';
+ yab->email = yahoo_xmldecode(st);
+ }
+
+ st = strstr(en, "hphone=\"");
+ if(st) {
+ st += strlen("hphone=\"");
+ en = strchr(st, '"'); *en++ = '\0';
+ yab->hphone = yahoo_xmldecode(st);
+ }
+
+ st = strstr(en, "wphone=\"");
+ if(st) {
+ st += strlen("wphone=\"");
+ en = strchr(st, '"'); *en++ = '\0';
+ yab->wphone = yahoo_xmldecode(st);
+ }
+
+ st = strstr(en, "mphone=\"");
+ if(st) {
+ st += strlen("mphone=\"");
+ en = strchr(st, '"'); *en++ = '\0';
+ yab->mphone = yahoo_xmldecode(st);
+ }
+
+ st = strstr(en, "dbid=\"");
+ if(st) {
+ st += strlen("dbid=\"");
+ en = strchr(st, '"'); *en++ = '\0';
+ yab->dbid = atoi(st);
+ }
+}
+
+static struct yab * yahoo_getyab(struct yahoo_input_data *yid)
+{
+ struct yab *yab = NULL;
+ int pos = 0, end=0;
+ struct yahoo_data *yd = yid->yd;
+
+ if(!yd)
+ return NULL;
+
+ DEBUG_MSG(("rxlen is %d", yid->rxlen));
+
+ if(yid->rxlen <= strlen("<record"))
+ return NULL;
+
+ /* start with <record */
+ while(pos < yid->rxlen-strlen("<record")+1
+ && memcmp(yid->rxqueue + pos, "<record", strlen("<record")))
+ pos++;
+
+ if(pos >= yid->rxlen-1)
+ return NULL;
+
+ end = pos+2;
+ /* end with /> */
+ while(end < yid->rxlen-strlen("/>")+1 && memcmp(yid->rxqueue + end, "/>", strlen("/>")))
+ end++;
+
+ if(end >= yid->rxlen-1)
+ return NULL;
+
+ yab = y_new0(struct yab, 1);
+ yahoo_yab_read(yab, yid->rxqueue + pos, end+2-pos);
+
+
+ yid->rxlen -= end+1;
+ //DEBUG_MSG(("rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
+ if (yid->rxlen>0) {
+ unsigned char *tmp = y_memdup(yid->rxqueue + end + 1, yid->rxlen);
+ FREE(yid->rxqueue);
+ yid->rxqueue = tmp;
+ //DEBUG_MSG(("new rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
+ } else {
+ //DEBUG_MSG(("freed rxqueue == %p", yid->rxqueue));
+ FREE(yid->rxqueue);
+ }
+
+
+ return yab;
+}
+
+static char * yahoo_getwebcam_master(struct yahoo_input_data *yid)
+{
+ unsigned int pos=0;
+ unsigned int len=0;
+ unsigned int status=0;
+ char *server=NULL;
+ struct yahoo_data *yd = yid->yd;
+
+ if(!yid || !yd)
+ return NULL;
+
+ DEBUG_MSG(("rxlen is %d", yid->rxlen));
+
+ len = yid->rxqueue[pos++];
+ if (yid->rxlen < len)
+ return NULL;
+
+ /* extract status (0 = ok, 6 = webcam not online) */
+ status = yid->rxqueue[pos++];
+
+ if (status == 0)
+ {
+ pos += 2; /* skip next 2 bytes */
+ server = y_memdup(yid->rxqueue+pos, 16);
+ pos += 16;
+ }
+ else if (status == 6)
+ {
+ YAHOO_CALLBACK(ext_yahoo_webcam_closed)
+ (yd->client_id, yid->wcm->user, 4);
+ }
+
+ /* skip rest of the data */
+
+ yid->rxlen -= len;
+ DEBUG_MSG(("rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
+ if (yid->rxlen>0) {
+ unsigned char *tmp = y_memdup(yid->rxqueue + pos, yid->rxlen);
+ FREE(yid->rxqueue);
+ yid->rxqueue = tmp;
+ DEBUG_MSG(("new rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
+ } else {
+ DEBUG_MSG(("freed rxqueue == %p", yid->rxqueue));
+ FREE(yid->rxqueue);
+ }
+
+ return server;
+}
+
+static int yahoo_get_webcam_data(struct yahoo_input_data *yid)
+{
+ unsigned char reason=0;
+ unsigned int pos=0;
+ unsigned int begin=0;
+ unsigned int end=0;
+ unsigned int closed=0;
+ unsigned char header_len=0;
+ char *who;
+ int connect=0;
+ struct yahoo_data *yd = yid->yd;
+
+ if(!yd)
+ return -1;
+
+ if(!yid->wcm || !yid->wcd || !yid->rxlen)
+ return -1;
+
+ DEBUG_MSG(("rxlen is %d", yid->rxlen));
+
+ /* if we are not reading part of image then read header */
+ if (!yid->wcd->to_read)
+ {
+ header_len=yid->rxqueue[pos++];
+ yid->wcd->packet_type=0;
+
+ if (yid->rxlen < header_len)
+ return 0;
+
+ if (header_len >= 8)
+ {
+ reason = yid->rxqueue[pos++];
+ /* next 2 bytes should always be 05 00 */
+ pos += 2;
+ yid->wcd->data_size = yahoo_get32(yid->rxqueue + pos);
+ pos += 4;
+ yid->wcd->to_read = yid->wcd->data_size;
+ }
+ if (header_len >= 13)
+ {
+ yid->wcd->packet_type = yid->rxqueue[pos++];
+ yid->wcd->timestamp = yahoo_get32(yid->rxqueue + pos);
+ pos += 4;
+ }
+
+ /* skip rest of header */
+ pos = header_len;
+ }
+
+ begin = pos;
+ pos += yid->wcd->to_read;
+ if (pos > yid->rxlen) pos = yid->rxlen;
+
+ /* if it is not an image then make sure we have the whole packet */
+ if (yid->wcd->packet_type != 0x02) {
+ if ((pos - begin) != yid->wcd->data_size) {
+ yid->wcd->to_read = 0;
+ return 0;
+ } else {
+ yahoo_packet_dump(yid->rxqueue + begin, pos - begin);
+ }
+ }
+
+ DEBUG_MSG(("packet type %.2X, data length %d", yid->wcd->packet_type,
+ yid->wcd->data_size));
+
+ /* find out what kind of packet we got */
+ switch (yid->wcd->packet_type)
+ {
+ case 0x00:
+ /* user requests to view webcam (uploading) */
+ if (yid->wcd->data_size &&
+ yid->wcm->direction == YAHOO_WEBCAM_UPLOAD) {
+ end = begin;
+ while (end <= yid->rxlen &&
+ yid->rxqueue[end++] != 13);
+ if (end > begin)
+ {
+ who = y_memdup(yid->rxqueue + begin, end - begin);
+ who[end - begin - 1] = 0;
+ YAHOO_CALLBACK(ext_yahoo_webcam_viewer)(yd->client_id, who + 2, 2);
+ FREE(who);
+ }
+ }
+
+ if (yid->wcm->direction == YAHOO_WEBCAM_DOWNLOAD) {
+ /* timestamp/status field */
+ /* 0 = declined viewing permission */
+ /* 1 = accepted viewing permission */
+ if (yid->wcd->timestamp == 0) {
+ YAHOO_CALLBACK(ext_yahoo_webcam_closed)(yd->client_id, yid->wcm->user, 3);
+ }
+ }
+ break;
+ case 0x01: /* status packets?? */
+ /* timestamp contains status info */
+ /* 00 00 00 01 = we have data?? */
+ break;
+ case 0x02: /* image data */
+ YAHOO_CALLBACK(ext_yahoo_got_webcam_image)(yd->client_id,
+ yid->wcm->user, yid->rxqueue + begin,
+ yid->wcd->data_size, pos - begin,
+ yid->wcd->timestamp);
+ break;
+ case 0x05: /* response packets when uploading */
+ if (!yid->wcd->data_size) {
+ YAHOO_CALLBACK(ext_yahoo_webcam_data_request)(yd->client_id, yid->wcd->timestamp);
+ }
+ break;
+ case 0x07: /* connection is closing */
+ switch(reason)
+ {
+ case 0x01: /* user closed connection */
+ closed = 1;
+ break;
+ case 0x0F: /* user cancelled permission */
+ closed = 2;
+ break;
+ }
+ YAHOO_CALLBACK(ext_yahoo_webcam_closed)(yd->client_id, yid->wcm->user, closed);
+ break;
+ case 0x0C: /* user connected */
+ case 0x0D: /* user disconnected */
+ if (yid->wcd->data_size) {
+ who = y_memdup(yid->rxqueue + begin, pos - begin + 1);
+ who[pos - begin] = 0;
+ if (yid->wcd->packet_type == 0x0C)
+ connect=1;
+ else
+ connect=0;
+ YAHOO_CALLBACK(ext_yahoo_webcam_viewer)(yd->client_id, who, connect);
+ FREE(who);
+ }
+ break;
+ case 0x13: /* user data */
+ /* i=user_ip (ip of the user we are viewing) */
+ /* j=user_ext_ip (external ip of the user we */
+ /* are viewing) */
+ break;
+ case 0x17: /* ?? */
+ break;
+ }
+ yid->wcd->to_read -= pos - begin;
+
+ yid->rxlen -= pos;
+ DEBUG_MSG(("rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
+ if (yid->rxlen>0) {
+ unsigned char *tmp = y_memdup(yid->rxqueue + pos, yid->rxlen);
+ FREE(yid->rxqueue);
+ yid->rxqueue = tmp;
+ DEBUG_MSG(("new rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
+ } else {
+ DEBUG_MSG(("freed rxqueue == %p", yid->rxqueue));
+ FREE(yid->rxqueue);
+ }
+
+ /* If we read a complete packet return success */
+ if (!yid->wcd->to_read)
+ return 1;
+
+ return 0;
+}
+
+int yahoo_write_ready(int id, int fd, void *data)
+{
+ struct yahoo_input_data *yid = data;
+ int len;
+ struct data_queue *tx;
+
+ LOG(("write callback: id=%d fd=%d data=%p", id, fd, data));
+ if(!yid || !yid->txqueues)
+ return -2;
+
+ tx = yid->txqueues->data;
+ LOG(("writing %d bytes", tx->len));
+ len = yahoo_send_data(fd, tx->queue, MIN(1024, tx->len));
+
+ if(len == -1 && errno == EAGAIN)
+ return 1;
+
+ if(len <= 0) {
+ int e = errno;
+ DEBUG_MSG(("len == %d (<= 0)", len));
+ while(yid->txqueues) {
+ YList *l=yid->txqueues;
+ tx = l->data;
+ free(tx->queue);
+ free(tx);
+ yid->txqueues = y_list_remove_link(yid->txqueues, yid->txqueues);
+ y_list_free_1(l);
+ }
+ LOG(("yahoo_write_ready(%d, %d) len < 0", id, fd));
+ YAHOO_CALLBACK(ext_yahoo_remove_handler)(id, yid->write_tag);
+ yid->write_tag = 0;
+ errno=e;
+ return 0;
+ }
+
+
+ tx->len -= len;
+ LOG(("yahoo_write_ready(%d, %d) tx->len: %d, len: %d", id, fd, tx->len, len));
+ if(tx->len > 0) {
+ unsigned char *tmp = y_memdup(tx->queue + len, tx->len);
+ FREE(tx->queue);
+ tx->queue = tmp;
+ } else {
+ YList *l=yid->txqueues;
+ free(tx->queue);
+ free(tx);
+ yid->txqueues = y_list_remove_link(yid->txqueues, yid->txqueues);
+ y_list_free_1(l);
+ if(!yid->txqueues) {
+ LOG(("yahoo_write_ready(%d, %d) !txqueues", id, fd));
+ YAHOO_CALLBACK(ext_yahoo_remove_handler)(id, yid->write_tag);
+ yid->write_tag = 0;
+ }
+ }
+
+ return 1;
+}
+
+static void yahoo_process_pager_connection(struct yahoo_input_data *yid, int over)
+{
+ struct yahoo_packet *pkt;
+ struct yahoo_data *yd = yid->yd;
+ int id = yd->client_id;
+
+ if(over)
+ return;
+
+ while (find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER)
+ && (pkt = yahoo_getdata(yid)) != NULL) {
+
+ yahoo_packet_process(yid, pkt);
+
+ yahoo_packet_free(pkt);
+ }
+}
+
+static void yahoo_process_ft_connection(struct yahoo_input_data *yid, int over)
+{
+}
+
+static void yahoo_process_chatcat_connection(struct yahoo_input_data *yid, int over)
+{
+ if(over)
+ return;
+
+ if (strstr((char*)yid->rxqueue+(yid->rxlen-20), "</content>")) {
+ YAHOO_CALLBACK(ext_yahoo_chat_cat_xml)(yid->yd->client_id, (char*)yid->rxqueue);
+ }
+}
+
+static void yahoo_process_yab_connection(struct yahoo_input_data *yid, int over)
+{
+ struct yahoo_data *yd = yid->yd;
+ struct yab *yab;
+ YList *buds;
+ int changed=0;
+ int id = yd->client_id;
+
+ if(over)
+ return;
+
+ while(find_input_by_id_and_type(id, YAHOO_CONNECTION_YAB)
+ && (yab = yahoo_getyab(yid)) != NULL) {
+ if(!yab->id)
+ continue;
+ changed=1;
+ for(buds = yd->buddies; buds; buds=buds->next) {
+ struct yahoo_buddy * bud = buds->data;
+ if(!strcmp(bud->id, yab->id)) {
+ bud->yab_entry = yab;
+ if(yab->nname) {
+ bud->real_name = strdup(yab->nname);
+ } else if(yab->fname && yab->lname) {
+ bud->real_name = y_new0(char,
+ strlen(yab->fname)+
+ strlen(yab->lname)+2
+ );
+ sprintf(bud->real_name, "%s %s",
+ yab->fname, yab->lname);
+ } else if(yab->fname) {
+ bud->real_name = strdup(yab->fname);
+ }
+ break; /* for */
+ }
+ }
+ }
+
+ if(changed)
+ YAHOO_CALLBACK(ext_yahoo_got_buddies)(yd->client_id, yd->buddies);
+}
+
+static void yahoo_process_search_connection(struct yahoo_input_data *yid, int over)
+{
+ struct yahoo_found_contact *yct=NULL;
+ char *p = (char *)yid->rxqueue, *np, *cp;
+ int k, n;
+ int start=0, found=0, total=0;
+ YList *contacts=NULL;
+ struct yahoo_input_data *pyid;
+
+ LOG(("[yahoo_process_search_connection] over:%d", over));
+
+ pyid = find_input_by_id_and_type(yid->yd->client_id, YAHOO_CONNECTION_PAGER);
+
+ if(!over || !pyid) {
+ LOG(("yahoo_process_search_connection] ?? Not Done yet? Waiting for more packets!"));
+ return;
+ }
+
+ if(p && (p=strstr(p, "\r\n\r\n"))) {
+ p += 4;
+
+ for(k = 0; (p = strchr(p, 4)) && (k < 4); k++) {
+ p++;
+ n = atoi(p);
+ switch(k) {
+ case 0: found = pyid->ys->lsearch_nfound = n; break;
+ case 2: start = pyid->ys->lsearch_nstart = n; break;
+ case 3: total = pyid->ys->lsearch_ntotal = n; break;
+ }
+ }
+
+ if(p)
+ p++;
+
+ k=0;
+ while(p && *p) {
+ cp = p;
+ np = strchr(p, 4);
+
+ if(!np)
+ break;
+ *np = 0;
+ p = np+1;
+
+ switch(k++) {
+ case 1:
+ if(strlen(cp) > 2 && y_list_length(contacts) < total) {
+ yct = y_new0(struct yahoo_found_contact, 1);
+ contacts = y_list_append(contacts, yct);
+ yct->id = cp+2;
+ } else {
+ *p = 0;
+ }
+ break;
+ case 2:
+ yct->online = !strcmp(cp, "2") ? 1 : 0;
+ break;
+ case 3:
+ yct->gender = cp;
+ break;
+ case 4:
+ yct->age = atoi(cp);
+ break;
+ case 5:
+ if(cp != "\005")
+ yct->location = cp;
+ k = 0;
+ break;
+ }
+ }
+ }
+
+ YAHOO_CALLBACK(ext_yahoo_got_search_result)(yid->yd->client_id, found, start, total, contacts);
+
+ while(contacts) {
+ YList *node = contacts;
+ contacts = y_list_remove_link(contacts, node);
+ free(node->data);
+ y_list_free_1(node);
+ }
+}
+
+static void _yahoo_webcam_connected(int fd, int error, void *d)
+{
+ struct yahoo_input_data *yid = d;
+ struct yahoo_webcam *wcm = yid->wcm;
+ struct yahoo_data *yd = yid->yd;
+ char conn_type[100];
+ char *data=NULL;
+ char *packet=NULL;
+ unsigned char magic_nr[] = {1, 0, 0, 0, 1};
+ unsigned header_len=0;
+ unsigned int len=0;
+ unsigned int pos=0;
+
+ if(error || fd <= 0) {
+ FREE(yid);
+ return;
+ }
+
+ yid->fd = fd;
+ inputs = y_list_prepend(inputs, yid);
+
+ LOG(("Connected"));
+ /* send initial packet */
+ switch (wcm->direction)
+ {
+ case YAHOO_WEBCAM_DOWNLOAD:
+ data = strdup("<REQIMG>");
+ break;
+ case YAHOO_WEBCAM_UPLOAD:
+ data = strdup("<SNDIMG>");
+ break;
+ default:
+ return;
+ }
+ yahoo_add_to_send_queue(yid, data, strlen(data));
+ FREE(data);
+
+ /* send data */
+ switch (wcm->direction)
+ {
+ case YAHOO_WEBCAM_DOWNLOAD:
+ header_len = 8;
+ data = strdup("a=2\r\nc=us\r\ne=21\r\nu=");
+ data = y_string_append(data, yd->user);
+ data = y_string_append(data, "\r\nt=");
+ data = y_string_append(data, wcm->key);
+ data = y_string_append(data, "\r\ni=");
+ data = y_string_append(data, wcm->my_ip);
+ data = y_string_append(data, "\r\ng=");
+ data = y_string_append(data, wcm->user);
+ data = y_string_append(data, "\r\no=w-2-5-1\r\np=");
+ snprintf(conn_type, sizeof(conn_type), "%d", wcm->conn_type);
+ data = y_string_append(data, conn_type);
+ data = y_string_append(data, "\r\n");
+ break;
+ case YAHOO_WEBCAM_UPLOAD:
+ header_len = 13;
+ data = strdup("a=2\r\nc=us\r\nu=");
+ data = y_string_append(data, yd->user);
+ data = y_string_append(data, "\r\nt=");
+ data = y_string_append(data, wcm->key);
+ data = y_string_append(data, "\r\ni=");
+ data = y_string_append(data, wcm->my_ip);
+ data = y_string_append(data, "\r\no=w-2-5-1\r\np=");
+ snprintf(conn_type, sizeof(conn_type), "%d", wcm->conn_type);
+ data = y_string_append(data, conn_type);
+ data = y_string_append(data, "\r\nb=");
+ data = y_string_append(data, wcm->description);
+ data = y_string_append(data, "\r\n");
+ break;
+ }
+
+ len = strlen(data);
+ packet = y_new0(char, header_len + len);
+ packet[pos++] = header_len;
+ packet[pos++] = 0;
+ switch (wcm->direction)
+ {
+ case YAHOO_WEBCAM_DOWNLOAD:
+ packet[pos++] = 1;
+ packet[pos++] = 0;
+ break;
+ case YAHOO_WEBCAM_UPLOAD:
+ packet[pos++] = 5;
+ packet[pos++] = 0;
+ break;
+ }
+
+ pos += yahoo_put32(packet + pos, len);
+ if (wcm->direction == YAHOO_WEBCAM_UPLOAD)
+ {
+ memcpy(packet + pos, magic_nr, sizeof(magic_nr));
+ pos += sizeof(magic_nr);
+ }
+ memcpy(packet + pos, data, len);
+ yahoo_add_to_send_queue(yid, packet, header_len + len);
+ FREE(packet);
+ FREE(data);
+
+ yid->read_tag=YAHOO_CALLBACK(ext_yahoo_add_handler)(yid->yd->client_id, yid->fd, YAHOO_INPUT_READ, yid);
+}
+
+static void yahoo_webcam_connect(struct yahoo_input_data *y)
+{
+ struct yahoo_webcam *wcm = y->wcm;
+ struct yahoo_input_data *yid;
+ struct yahoo_server_settings *yss;
+
+ if (!wcm || !wcm->server || !wcm->key)
+ return;
+
+ yid = y_new0(struct yahoo_input_data, 1);
+ yid->type = YAHOO_CONNECTION_WEBCAM;
+ yid->yd = y->yd;
+
+ /* copy webcam data to new connection */
+ yid->wcm = y->wcm;
+ y->wcm = NULL;
+
+ yss = y->yd->server_settings;
+
+ yid->wcd = y_new0(struct yahoo_webcam_data, 1);
+
+ LOG(("Connecting to: %s:%d", wcm->server, wcm->port));
+ YAHOO_CALLBACK(ext_yahoo_connect_async)(y->yd->client_id, wcm->server, wcm->port, yid->type,
+ _yahoo_webcam_connected, yid);
+
+}
+
+static void yahoo_process_webcam_master_connection(struct yahoo_input_data *yid, int over)
+{
+ char* server;
+ struct yahoo_server_settings *yss;
+
+ if(over)
+ return;
+
+ server = yahoo_getwebcam_master(yid);
+
+ if (server)
+ {
+ yss = yid->yd->server_settings;
+ yid->wcm->server = strdup(server);
+ yid->wcm->port = yss->webcam_port;
+ yid->wcm->conn_type = yss->conn_type;
+ yid->wcm->my_ip = strdup(yss->local_host);
+ if (yid->wcm->direction == YAHOO_WEBCAM_UPLOAD)
+ yid->wcm->description = strdup(yss->webcam_description);
+ yahoo_webcam_connect(yid);
+ FREE(server);
+ }
+}
+
+static void yahoo_process_webcam_connection(struct yahoo_input_data *yid, int over)
+{
+ int id = yid->yd->client_id;
+ int fd = yid->fd;
+
+ if(over)
+ return;
+
+ /* as long as we still have packets available keep processing them */
+ while (find_input_by_id_and_fd(id, fd)
+ && yahoo_get_webcam_data(yid) == 1);
+}
+
+static void (*yahoo_process_connection[])(struct yahoo_input_data *, int over) = {
+ yahoo_process_pager_connection,
+ yahoo_process_ft_connection,
+ yahoo_process_yab_connection,
+ yahoo_process_webcam_master_connection,
+ yahoo_process_webcam_connection,
+ yahoo_process_chatcat_connection,
+ yahoo_process_search_connection
+};
+
+int yahoo_read_ready(int id, int fd, void *data)
+{
+ struct yahoo_input_data *yid = data;
+ struct yahoo_server_settings *yss;
+ char buf[1024];
+ int len;
+
+ LOG(("read callback: id=%d fd=%d data=%p", id, fd, data));
+ if(!yid)
+ return -2;
+
+
+ do {
+ len = read(fd, buf, sizeof(buf));
+
+ LOG(("read callback: id=%d fd=%d len=%d", id, fd, len));
+
+ } while(len == -1 && errno == EINTR);
+
+ if(len == -1 && errno == EAGAIN) /* we'll try again later */
+ return 1;
+
+ if (len <= 0) {
+ int e = errno;
+ DEBUG_MSG(("len == %d (<= 0)", len));
+
+ if(yid->type == YAHOO_CONNECTION_PAGER) {
+ yss = yid->yd->server_settings;
+
+ if (yss->web_messenger && len == 0)
+ return 1; // try again later.. just nothing here yet
+
+ YAHOO_CALLBACK(ext_yahoo_error)(yid->yd->client_id, "Connection closed by server", 1, E_CONNECTION);
+ }
+
+ yahoo_process_connection[yid->type](yid, 1);
+ yahoo_input_close(yid);
+
+ /* no need to return an error, because we've already fixed it */
+ if(len == 0)
+ return 1;
+
+ errno=e;
+ LOG(("read error: %s", strerror(errno)));
+ return -1;
+ }
+
+ yid->rxqueue = y_renew(unsigned char, yid->rxqueue, len + yid->rxlen + 1);
+ memcpy(yid->rxqueue + yid->rxlen, buf, len);
+ yid->rxlen += len;
+ yid->rxqueue[yid->rxlen] = 0; // zero terminate
+
+ yahoo_process_connection[yid->type](yid, 0);
+
+ return len;
+}
+
+int yahoo_init_with_attributes(const char *username, const char *password, ...)
+{
+ va_list ap;
+ struct yahoo_data *yd;
+
+ yd = y_new0(struct yahoo_data, 1);
+
+ if(!yd)
+ return 0;
+
+ yd->user = strdup(username);
+ yd->password = strdup(password);
+
+ yd->initial_status = -1;
+ yd->current_status = -1;
+
+ yd->client_id = ++last_id;
+
+ add_to_list(yd);
+
+ va_start(ap, password);
+ yd->server_settings = _yahoo_assign_server_settings(ap);
+ va_end(ap);
+
+ return yd->client_id;
+}
+
+int yahoo_init(const char *username, const char *password)
+{
+ return yahoo_init_with_attributes(username, password, NULL);
+}
+
+struct connect_callback_data {
+ struct yahoo_data *yd;
+ int tag;
+ int i;
+};
+
+static void yahoo_connected(int fd, int error, void *data)
+{
+ struct connect_callback_data *ccd = data;
+ struct yahoo_data *yd = ccd->yd;
+ struct yahoo_packet *pkt;
+ struct yahoo_input_data *yid;
+ struct yahoo_server_settings *yss = yd->server_settings;
+
+ if(error) {
+ if(fallback_ports[ccd->i]) {
+ int tag;
+ yss->pager_port = fallback_ports[ccd->i++];
+ tag = YAHOO_CALLBACK(ext_yahoo_connect_async)(yd->client_id, yss->pager_host, YAHOO_CONNECTION_PAGER,
+ yss->pager_port, yahoo_connected, ccd);
+
+ if(tag > 0)
+ ccd->tag=tag;
+ } else {
+ FREE(ccd);
+ YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_SOCK, NULL);
+ }
+ return;
+ }
+
+ FREE(ccd);
+
+ /* fd < 0 && error == 0 means connect was cancelled */
+ if(fd < 0)
+ return;
+
+ NOTICE(("web messenger: %d", yss->web_messenger));
+ if (yss->web_messenger) {
+ pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_packet_hash(pkt, 1, yd->user);
+ yahoo_packet_hash(pkt, 0, yd->user);
+ yahoo_packet_hash(pkt, 24, "0");
+
+ } else {
+ pkt = yahoo_packet_new(YAHOO_SERVICE_VERIFY, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ }
+ NOTICE(("Sending initial packet"));
+
+ yid = y_new0(struct yahoo_input_data, 1);
+ yid->yd = yd;
+ yid->fd = fd;
+ inputs = y_list_prepend(inputs, yid);
+
+ yahoo_send_packet(yid, pkt, 0);
+
+ yahoo_packet_free(pkt);
+
+ yid->read_tag=YAHOO_CALLBACK(ext_yahoo_add_handler)(yid->yd->client_id, yid->fd, YAHOO_INPUT_READ, yid);
+}
+
+void yahoo_login(int id, int initial)
+{
+ struct yahoo_data *yd = find_conn_by_id(id);
+ struct connect_callback_data *ccd;
+ struct yahoo_server_settings *yss;
+ int tag;
+
+ if(!yd)
+ return;
+
+ yss = yd->server_settings;
+
+ yd->initial_status = initial;
+
+ ccd = y_new0(struct connect_callback_data, 1);
+ ccd->yd = yd;
+ tag = YAHOO_CALLBACK(ext_yahoo_connect_async)(yd->client_id, yss->pager_host, yss->pager_port, YAHOO_CONNECTION_PAGER,
+ yahoo_connected, ccd);
+
+ /*
+ * if tag <= 0, then callback has already been called
+ * so ccd will have been freed
+ */
+ if(tag > 0)
+ ccd->tag = tag;
+ else if(tag < 0)
+ YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_SOCK, NULL);
+}
+
+
+int yahoo_get_fd(int id)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ if(!yid)
+ return 0;
+ else
+ return yid->fd;
+}
+
+void yahoo_send_im(int id, const char *from, const char *who, const char *what, int utf8, int buddy_icon)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_packet *pkt = NULL;
+ struct yahoo_data *yd;
+ struct yahoo_server_settings *yss;
+ char buf[2];
+
+ if(!yid)
+ return;
+
+ yd = yid->yd;
+ yss = yd->server_settings;
+ pkt = yahoo_packet_new(YAHOO_SERVICE_MESSAGE, YAHOO_STATUS_OFFLINE, yd->session_id);
+
+ if(from && strcmp(from, yd->user))
+ yahoo_packet_hash(pkt, 0, yd->user);
+ yahoo_packet_hash(pkt, 1, from?from:yd->user);
+ yahoo_packet_hash(pkt, 5, who);
+ yahoo_packet_hash(pkt, 14, what);
+
+ if(utf8)
+ yahoo_packet_hash(pkt, 97, "1");
+
+ /* GAIM does doodle so they allow/enable imvironments (that get rejected?)
+ 63 - imvironment string;11
+ 64 - imvironment enabled/allowed
+ 0 - enabled imwironment ;0 - no imvironment
+ 2 - disabled '' - empty cause we don;t do these
+ */
+ yahoo_packet_hash(pkt, 63, ""); /* imvironment name; or ;0 (doodle;11)*/
+ yahoo_packet_hash(pkt, 64, "2");
+
+ if (!yss->web_messenger) {
+ //yahoo_packet_hash(pkt, 1002, "1"); /* YIM6+ */
+ yahoo_packet_hash(pkt, 10093, "4"); /* YIM7? */
+ }
+ snprintf(buf, sizeof(buf), "%d", buddy_icon);
+ yahoo_packet_hash(pkt, 206, buf); /* buddy_icon, 0 = none, 1=avatar?, 2=picture */
+
+ if (yss->web_messenger) {
+ char z[128];
+
+ yahoo_packet_hash(pkt, 0, yd->user);
+ wsprintf(z, "%d", yd->session_timestamp);
+ yahoo_packet_hash(pkt, 24, z);
+ }
+ yahoo_send_packet(yid, pkt, 0);
+
+ yahoo_packet_free(pkt);
+}
+
+void yahoo_send_typing(int id, const char *from, const char *who, int typ)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt = NULL;
+ struct yahoo_server_settings *yss;
+
+ if(!yid)
+ return;
+
+ yd = yid->yd;
+ yss = yd->server_settings;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_NOTIFY, YAHOO_STATUS_NOTIFY, yd->session_id);
+
+ yahoo_packet_hash(pkt, 49, "TYPING");
+ yahoo_packet_hash(pkt, 1, from?from:yd->user);
+ yahoo_packet_hash(pkt, 14, " ");
+ yahoo_packet_hash(pkt, 13, typ ? "1" : "0");
+ yahoo_packet_hash(pkt, 5, who);
+
+ if (yss->web_messenger) {
+ char z[128];
+
+ yahoo_packet_hash(pkt, 0, yd->user);
+ wsprintf(z, "%d", yd->session_timestamp);
+ yahoo_packet_hash(pkt, 24, z);
+ } else {
+ //yahoo_packet_hash(pkt, 1002, "1"); /* YIM6+ */
+ yahoo_packet_hash(pkt, 10093, "4"); /* YIM7+ */
+ }
+
+ yahoo_send_packet(yid, pkt, 0);
+
+ yahoo_packet_free(pkt);
+}
+
+void yahoo_set_away(int id, enum yahoo_status state, const char *msg, int away)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt = NULL;
+ struct yahoo_server_settings *yss;
+ //int service;
+ char s[4];
+ enum yahoo_status cs;
+
+ if(!yid)
+ return;
+
+ yd = yid->yd;
+
+ //if (yd->current_status == state && state != YAHOO_STATUS_CUSTOM)
+ // return;
+
+ cs = yd->current_status;
+ yss = yd->server_settings;
+
+ if (state == YAHOO_STATUS_INVISIBLE) {
+ pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBLE_TOGGLE, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_packet_hash(pkt, 13, "2");
+ yd->current_status = state;
+ } else {
+ LOG(("yahoo_set_away: state: %d, msg: %s, away: %d", state, msg, away));
+
+ if (msg) {
+ yd->current_status = YAHOO_STATUS_CUSTOM;
+ } else {
+ yd->current_status = state;
+ }
+
+ //if (yd->current_status == YAHOO_STATUS_AVAILABLE)
+ // service = YAHOO_SERVICE_ISBACK;
+ //else
+ // service = YAHOO_SERVICE_ISAWAY;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_STATUS_UPDATE, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ if ((away == 2) && (yd->current_status == YAHOO_STATUS_AVAILABLE)) {
+ //pkt = yahoo_packet_new(YAHOO_SERVICE_ISAWAY, YAHOO_STATUS_BRB, yd->session_id);
+ yahoo_packet_hash(pkt, 10, "999");
+ yahoo_packet_hash(pkt, 47, "2");
+ }else {
+ //pkt = yahoo_packet_new(YAHOO_SERVICE_YAHOO6_STATUS_UPDATE, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ snprintf(s, sizeof(s), "%d", yd->current_status);
+ yahoo_packet_hash(pkt, 10, s);
+ if (yd->current_status == YAHOO_STATUS_CUSTOM) {
+ yahoo_packet_hash(pkt, 19, msg);
+ yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0");
+ } else {
+ yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0");
+ }
+
+ //yahoo_packet_hash(pkt, 187, "0"); // ???
+
+ }
+ }
+ if (yss->web_messenger) {
+ char z[128];
+
+ yahoo_packet_hash(pkt, 0, yd->user);
+ wsprintf(z, "%d", yd->session_timestamp);
+ yahoo_packet_hash(pkt, 24, z);
+ }
+
+ yahoo_send_packet(yid, pkt, 0);
+ yahoo_packet_free(pkt);
+
+ if (cs == YAHOO_STATUS_INVISIBLE && state != YAHOO_STATUS_INVISIBLE){
+ pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBLE_TOGGLE, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_packet_hash(pkt, 13, "1");
+ yd->current_status = state;
+
+ yahoo_send_packet(yid, pkt, 0);
+ yahoo_packet_free(pkt);
+ }
+}
+
+void yahoo_set_stealth(int id, const char *buddy, int add)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt = NULL;
+ //int service;
+ //char s[4];
+
+ if(!yid)
+ return;
+
+ yd = yid->yd;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_STEALTH_PERM, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_packet_hash(pkt, 1, yd->user);
+ yahoo_packet_hash(pkt, 31, add ? "1" : "2"); /*visibility? */
+ yahoo_packet_hash(pkt, 13, "2"); // function/service
+ yahoo_packet_hash(pkt, 7, buddy);
+ yahoo_send_packet(yid, pkt, 0);
+ yahoo_packet_free(pkt);
+}
+
+void yahoo_logoff(int id)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt = NULL;
+
+ if(!yid)
+ return;
+ yd = yid->yd;
+
+ LOG(("yahoo_logoff: current status: %d", yd->current_status));
+
+ if(yd->current_status != -1) {
+ struct yahoo_server_settings *yss = yd->server_settings;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_LOGOFF, YAHOO_STATUS_AVAILABLE, yd->session_id);
+
+ if (yss->web_messenger) {
+ char z[128];
+
+ yahoo_packet_hash(pkt, 0, yd->user);
+ wsprintf(z, "%d", yd->session_timestamp);
+ yahoo_packet_hash(pkt, 24, z);
+ }
+ yd->current_status = -1;
+
+ if (pkt) {
+ yahoo_send_packet(yid, pkt, 0);
+ yahoo_packet_free(pkt);
+ }
+ }
+
+
+/* do {
+ yahoo_input_close(yid);
+ } while((yid = find_input_by_id(id)));*/
+
+}
+
+void yahoo_get_list(int id)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt = NULL;
+
+ if(!yid)
+ return;
+ yd = yid->yd;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_LIST, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_packet_hash(pkt, 1, yd->user);
+ if (pkt) {
+ yahoo_send_packet(yid, pkt, 0);
+ yahoo_packet_free(pkt);
+ }
+}
+
+static void _yahoo_http_connected(int id, int fd, int error, void *data)
+{
+ struct yahoo_input_data *yid = data;
+ if(fd <= 0) {
+ inputs = y_list_remove(inputs, yid);
+ FREE(yid);
+ return;
+ }
+
+ yid->fd = fd;
+ yid->read_tag=YAHOO_CALLBACK(ext_yahoo_add_handler)(yid->yd->client_id, fd, YAHOO_INPUT_READ, yid);
+}
+
+void yahoo_get_yab(int id)
+{
+ struct yahoo_data *yd = find_conn_by_id(id);
+ struct yahoo_input_data *yid;
+ char url[1024];
+ char buff[1024];
+
+ if(!yd)
+ return;
+
+ yid = y_new0(struct yahoo_input_data, 1);
+ yid->yd = yd;
+ yid->type = YAHOO_CONNECTION_YAB;
+
+ snprintf(url, 1024, "http://insider.msg.yahoo.com/ycontent/?ab2=0");
+
+ snprintf(buff, sizeof(buff), "Y=%s; T=%s",
+ yd->cookie_y, yd->cookie_t);
+
+ inputs = y_list_prepend(inputs, yid);
+
+ yahoo_http_get(yid->yd->client_id, url, buff,
+ _yahoo_http_connected, yid);
+}
+
+void yahoo_set_yab(int id, struct yab * yab)
+{
+ struct yahoo_data *yd = find_conn_by_id(id);
+ struct yahoo_input_data *yid;
+ char url[1024];
+ char buff[1024];
+ char *temp;
+ int size = sizeof(url)-1;
+
+ if(!yd)
+ return;
+
+ yid = y_new0(struct yahoo_input_data, 1);
+ yid->type = YAHOO_CONNECTION_YAB;
+ yid->yd = yd;
+
+ strncpy(url, "http://insider.msg.yahoo.com/ycontent/?addab2=0", size);
+
+ if(yab->dbid) {
+ /* change existing yab */
+ char tmp[32];
+ strncat(url, "&ee=1&ow=1&id=", size - strlen(url));
+ snprintf(tmp, sizeof(tmp), "%d", yab->dbid);
+ strncat(url, tmp, size - strlen(url));
+ }
+
+ if(yab->fname) {
+ strncat(url, "&fn=", size - strlen(url));
+ temp = yahoo_urlencode(yab->fname);
+ strncat(url, temp, size - strlen(url));
+ free(temp);
+ }
+ if(yab->lname) {
+ strncat(url, "&ln=", size - strlen(url));
+ temp = yahoo_urlencode(yab->lname);
+ strncat(url, temp, size - strlen(url));
+ free(temp);
+ }
+ strncat(url, "&yid=", size - strlen(url));
+ temp = yahoo_urlencode(yab->id);
+ strncat(url, temp, size - strlen(url));
+ free(temp);
+ if(yab->nname) {
+ strncat(url, "&nn=", size - strlen(url));
+ temp = yahoo_urlencode(yab->nname);
+ strncat(url, temp, size - strlen(url));
+ free(temp);
+ }
+ if(yab->email) {
+ strncat(url, "&e=", size - strlen(url));
+ temp = yahoo_urlencode(yab->email);
+ strncat(url, temp, size - strlen(url));
+ free(temp);
+ }
+ if(yab->hphone) {
+ strncat(url, "&hp=", size - strlen(url));
+ temp = yahoo_urlencode(yab->hphone);
+ strncat(url, temp, size - strlen(url));
+ free(temp);
+ }
+ if(yab->wphone) {
+ strncat(url, "&wp=", size - strlen(url));
+ temp = yahoo_urlencode(yab->wphone);
+ strncat(url, temp, size - strlen(url));
+ free(temp);
+ }
+ if(yab->mphone) {
+ strncat(url, "&mp=", size - strlen(url));
+ temp = yahoo_urlencode(yab->mphone);
+ strncat(url, temp, size - strlen(url));
+ free(temp);
+ }
+ strncat(url, "&pp=0", size - strlen(url));
+
+ snprintf(buff, sizeof(buff), "Y=%s; T=%s",
+ yd->cookie_y, yd->cookie_t);
+
+ inputs = y_list_prepend(inputs, yid);
+
+ yahoo_http_get(yid->yd->client_id, url, buff,
+ _yahoo_http_connected, yid);
+}
+
+void yahoo_set_identity_status(int id, const char * identity, int active)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt = NULL;
+
+ if(!yid)
+ return;
+ yd = yid->yd;
+
+ pkt = yahoo_packet_new(active?YAHOO_SERVICE_IDACT:YAHOO_SERVICE_IDDEACT,
+ YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_packet_hash(pkt, 3, identity);
+ if (pkt) {
+ yahoo_send_packet(yid, pkt, 0);
+ yahoo_packet_free(pkt);
+ }
+}
+
+void yahoo_refresh(int id)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt = NULL;
+
+ if(!yid)
+ return;
+ yd = yid->yd;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_USERSTAT, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ if (pkt) {
+ yahoo_send_packet(yid, pkt, 0);
+ yahoo_packet_free(pkt);
+ }
+}
+
+void yahoo_keepalive(int id)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt=NULL;
+ if(!yid)
+ return;
+ yd = yid->yd;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_PING, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_send_packet(yid, pkt, 0);
+ yahoo_packet_free(pkt);
+}
+
+void yahoo_chat_keepalive (int id)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type (id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt = NULL;
+
+ if (!yid)
+ return;
+
+ yd = yid->yd;
+
+ pkt = yahoo_packet_new (YAHOO_SERVICE_CHATPING, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_send_packet (yid, pkt, 0);
+ yahoo_packet_free (pkt);
+}
+
+void yahoo_add_buddy(int id, const char *who, const char *group, const char *msg)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt;
+
+ if(!yid)
+ return;
+ yd = yid->yd;
+
+ if (!yd->logged_in)
+ return;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_packet_hash(pkt, 1, yd->user);
+ yahoo_packet_hash(pkt, 7, who);
+ yahoo_packet_hash(pkt, 65, group);
+ if (msg != NULL) // add message/request "it's me add me"
+ yahoo_packet_hash(pkt, 14, msg);
+
+ /* YIM7 does something weird here:
+ yahoo_packet_hash(pkt, 1, yd->user);
+ yahoo_packet_hash(pkt, 14, msg != NULL ? msg : "");
+ yahoo_packet_hash(pkt, 65, group);
+ yahoo_packet_hash(pkt, 97, 1); ?????
+ yahoo_packet_hash(pkt, 216, "First Name");???
+ yahoo_packet_hash(pkt, 254, "Last Name");???
+ yahoo_packet_hash(pkt, 7, who);
+
+ Server Replies with:
+ 1: ID
+ 66: 0
+ 7: who
+ 65: group
+ 223: 1 ??
+ */
+ yahoo_send_packet(yid, pkt, 0);
+ yahoo_packet_free(pkt);
+}
+
+void yahoo_remove_buddy(int id, const char *who, const char *group)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt = NULL;
+
+ if(!yid)
+ return;
+ yd = yid->yd;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id);
+
+ yahoo_packet_hash(pkt, 1, yd->user);
+ yahoo_packet_hash(pkt, 7, who);
+ yahoo_packet_hash(pkt, 65, group);
+ yahoo_send_packet(yid, pkt, 0);
+ yahoo_packet_free(pkt);
+}
+
+void yahoo_accept_buddy(int id, const char *who)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt;
+
+ if(!yid)
+ return;
+ yd = yid->yd;
+
+ if (!yd->logged_in)
+ return;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_Y7_AUTHORIZATION, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_packet_hash(pkt, 1, yd->user);
+ yahoo_packet_hash(pkt, 5, who);
+ yahoo_packet_hash(pkt, 13, "1"); // Reject Authorization
+
+ yahoo_send_packet(yid, pkt, 0);
+ yahoo_packet_free(pkt);
+}
+
+void yahoo_reject_buddy(int id, const char *who, const char *msg)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt;
+
+ if(!yid)
+ return;
+ yd = yid->yd;
+
+ if (!yd->logged_in)
+ return;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_Y7_AUTHORIZATION, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_packet_hash(pkt, 1, yd->user);
+ yahoo_packet_hash(pkt, 5, who);
+ yahoo_packet_hash(pkt, 13, "2"); // Reject Authorization
+
+ if (msg != NULL)
+ yahoo_packet_hash(pkt, 14, msg);
+
+ yahoo_send_packet(yid, pkt, 0);
+ yahoo_packet_free(pkt);
+}
+
+void yahoo_ignore_buddy(int id, const char *who, int unignore)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt;
+
+ if(!yid)
+ return;
+ yd = yid->yd;
+
+ if (!yd->logged_in)
+ return;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_IGNORECONTACT, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_packet_hash(pkt, 1, yd->user);
+ yahoo_packet_hash(pkt, 7, who);
+ yahoo_packet_hash(pkt, 13, unignore?"2":"1");
+ yahoo_send_packet(yid, pkt, 0);
+ yahoo_packet_free(pkt);
+}
+
+void yahoo_change_buddy_group(int id, const char *who, const char *old_group, const char *new_group)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt = NULL;
+
+ if(!yid)
+ return;
+ yd = yid->yd;
+
+ /*pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_packet_hash(pkt, 1, yd->user);
+ yahoo_packet_hash(pkt, 7, who);
+ yahoo_packet_hash(pkt, 14, "");
+ yahoo_packet_hash(pkt, 65, new_group);
+ yahoo_packet_hash(pkt, 97, "1");
+ yahoo_send_packet(yid, pkt, 0);
+ yahoo_packet_free(pkt);
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_packet_hash(pkt, 1, yd->user);
+ yahoo_packet_hash(pkt, 7, who);
+ yahoo_packet_hash(pkt, 65, old_group);
+ yahoo_send_packet(yid, pkt, 0);
+ yahoo_packet_free(pkt);*/
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_Y7_CHANGE_GROUP, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_packet_hash(pkt, 1, yd->user);
+ yahoo_packet_hash(pkt, 302, "240"); //???
+ yahoo_packet_hash(pkt, 300, "240"); //???
+ yahoo_packet_hash(pkt, 7, who);
+ yahoo_packet_hash(pkt, 224, old_group);
+ yahoo_packet_hash(pkt, 264, new_group);
+ yahoo_packet_hash(pkt, 301, "240"); //???
+ yahoo_packet_hash(pkt, 303, "240"); //???
+ yahoo_send_packet(yid, pkt, 0);
+ yahoo_packet_free(pkt);
+}
+
+void yahoo_group_rename(int id, const char *old_group, const char *new_group)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt = NULL;
+
+ if(!yid)
+ return;
+ yd = yid->yd;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_GROUPRENAME, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_packet_hash(pkt, 1, yd->user);
+ yahoo_packet_hash(pkt, 65, old_group);
+ yahoo_packet_hash(pkt, 67, new_group);
+
+ yahoo_send_packet(yid, pkt, 0);
+ yahoo_packet_free(pkt);
+}
+
+void yahoo_conference_addinvite(int id, const char * from, const char *who, const char *room, const YList * members, const char *msg)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt;
+
+ if(!yid)
+ return;
+ yd = yid->yd;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_CONFADDINVITE, YAHOO_STATUS_AVAILABLE, yd->session_id);
+
+ yahoo_packet_hash(pkt, 1, (from?from:yd->user));
+ yahoo_packet_hash(pkt, 51, who);
+ yahoo_packet_hash(pkt, 57, room);
+ yahoo_packet_hash(pkt, 58, msg);
+ yahoo_packet_hash(pkt, 13, "0");
+ for(; members; members = members->next) {
+ yahoo_packet_hash(pkt, 52, (char *)members->data);
+ yahoo_packet_hash(pkt, 53, (char *)members->data);
+ }
+ /* 52, 53 -> other members? */
+
+ yahoo_send_packet(yid, pkt, 0);
+
+ yahoo_packet_free(pkt);
+}
+
+void yahoo_conference_invite(int id, const char * from, YList *who, const char *room, const char *msg)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt;
+
+ if(!yid)
+ return;
+ yd = yid->yd;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_CONFINVITE, YAHOO_STATUS_AVAILABLE, yd->session_id);
+
+ yahoo_packet_hash(pkt, 1, (from?from:yd->user));
+ yahoo_packet_hash(pkt, 50, yd->user);
+ for(; who; who = who->next) {
+ yahoo_packet_hash(pkt, 52, (char *)who->data);
+ }
+ yahoo_packet_hash(pkt, 57, room);
+ yahoo_packet_hash(pkt, 58, msg);
+ yahoo_packet_hash(pkt, 13, "0");
+
+ yahoo_send_packet(yid, pkt, 0);
+
+ yahoo_packet_free(pkt);
+}
+
+void yahoo_conference_logon(int id, const char *from, YList *who, const char *room)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt;
+
+ if(!yid)
+ return;
+ yd = yid->yd;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_CONFLOGON, YAHOO_STATUS_AVAILABLE, yd->session_id);
+
+ yahoo_packet_hash(pkt, 1, (from?from:yd->user));
+ for(; who; who = who->next) {
+ yahoo_packet_hash(pkt, 3, (char *)who->data);
+ }
+ yahoo_packet_hash(pkt, 57, room);
+
+ yahoo_send_packet(yid, pkt, 0);
+
+ yahoo_packet_free(pkt);
+}
+
+void yahoo_conference_decline(int id, const char * from, YList *who, const char *room, const char *msg)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt;
+
+ if(!yid)
+ return;
+ yd = yid->yd;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_CONFDECLINE, YAHOO_STATUS_AVAILABLE, yd->session_id);
+
+ yahoo_packet_hash(pkt, 1, (from?from:yd->user));
+ for(; who; who = who->next) {
+ yahoo_packet_hash(pkt, 3, (char *)who->data);
+ }
+ yahoo_packet_hash(pkt, 57, room);
+ yahoo_packet_hash(pkt, 14, msg);
+
+ yahoo_send_packet(yid, pkt, 0);
+
+ yahoo_packet_free(pkt);
+}
+
+void yahoo_conference_logoff(int id, const char * from, YList *who, const char *room)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt;
+
+ if(!yid)
+ return;
+ yd = yid->yd;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_CONFLOGOFF, YAHOO_STATUS_AVAILABLE, yd->session_id);
+
+ yahoo_packet_hash(pkt, 1, (from?from:yd->user));
+ for(; who; who = who->next) {
+ yahoo_packet_hash(pkt, 3, (char *)who->data);
+ }
+ yahoo_packet_hash(pkt, 57, room);
+
+ yahoo_send_packet(yid, pkt, 0);
+
+ yahoo_packet_free(pkt);
+}
+
+void yahoo_conference_message(int id, const char * from, YList *who, const char *room, const char *msg, int utf8)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt;
+
+ if(!yid)
+ return;
+ yd = yid->yd;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_CONFMSG, YAHOO_STATUS_AVAILABLE, yd->session_id);
+
+ yahoo_packet_hash(pkt, 1, (from?from:yd->user));
+ for(; who; who = who->next) {
+ yahoo_packet_hash(pkt, 53, (char *)who->data);
+ }
+ yahoo_packet_hash(pkt, 57, room);
+ yahoo_packet_hash(pkt, 14, msg);
+
+ if(utf8)
+ yahoo_packet_hash(pkt, 97, "1");
+
+ yahoo_send_packet(yid, pkt, 0);
+
+ yahoo_packet_free(pkt);
+}
+
+void yahoo_get_chatrooms(int id, int chatroomid)
+{
+ struct yahoo_data *yd = find_conn_by_id(id);
+ struct yahoo_input_data *yid;
+ char url[1024];
+ char buff[1024];
+
+ if(!yd)
+ return;
+
+ yid = y_new0(struct yahoo_input_data, 1);
+ yid->yd = yd;
+ yid->type = YAHOO_CONNECTION_CHATCAT;
+
+ if (chatroomid == 0) {
+ snprintf(url, 1024, "http://insider.msg.yahoo.com/ycontent/?chatcat=0");
+ } else {
+ snprintf(url, 1024, "http://insider.msg.yahoo.com/ycontent/?chatroom_%d=0",chatroomid);
+ }
+
+ snprintf(buff, sizeof(buff), "Y=%s; T=%s", yd->cookie_y, yd->cookie_t);
+
+ inputs = y_list_prepend(inputs, yid);
+
+ yahoo_http_get(yid->yd->client_id, url, buff, _yahoo_http_connected, yid);
+}
+
+void yahoo_chat_logon(int id, const char *from, const char *room, const char *roomid)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt;
+
+ if(!yid)
+ return;
+
+ yd = yid->yd;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_CHATONLINE, YAHOO_STATUS_AVAILABLE, yd->session_id);
+
+ yahoo_packet_hash(pkt, 1, (from?from:yd->user));
+ yahoo_packet_hash(pkt, 109, yd->user);
+ yahoo_packet_hash(pkt, 6, "abcde");
+
+ yahoo_send_packet(yid, pkt, 0);
+
+ yahoo_packet_free(pkt);
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_CHATJOIN, YAHOO_STATUS_AVAILABLE, yd->session_id);
+
+ yahoo_packet_hash(pkt, 1, (from?from:yd->user));
+ yahoo_packet_hash(pkt, 104, room);
+ yahoo_packet_hash(pkt, 129, roomid);
+ yahoo_packet_hash(pkt, 62, "2"); /* ??? */
+
+ yahoo_send_packet(yid, pkt, 0);
+
+ yahoo_packet_free(pkt);
+}
+
+
+void yahoo_chat_message(int id, const char *from, const char *room, const char *msg, const int msgtype, const int utf8)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt;
+ char buf[2];
+
+ if(!yid)
+ return;
+
+ yd = yid->yd;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_COMMENT, YAHOO_STATUS_AVAILABLE, yd->session_id);
+
+ yahoo_packet_hash(pkt, 1, (from?from:yd->user));
+ yahoo_packet_hash(pkt, 104, room);
+ yahoo_packet_hash(pkt, 117, msg);
+
+ snprintf(buf, sizeof(buf), "%d", msgtype);
+ yahoo_packet_hash(pkt, 124, buf);
+
+ if(utf8)
+ yahoo_packet_hash(pkt, 97, "1");
+
+ yahoo_send_packet(yid, pkt, 0);
+
+ yahoo_packet_free(pkt);
+}
+
+
+void yahoo_chat_logoff(int id, const char *from)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt;
+
+ if(!yid)
+ return;
+
+ yd = yid->yd;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_CHATLOGOUT, YAHOO_STATUS_AVAILABLE, yd->session_id);
+
+ yahoo_packet_hash(pkt, 1, (from?from:yd->user));
+
+ yahoo_send_packet(yid, pkt, 0);
+
+ yahoo_packet_free(pkt);
+}
+
+void yahoo_webcam_close_feed(int id, const char *who)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_webcam_user(id, who);
+
+ if(yid)
+ yahoo_input_close(yid);
+}
+
+void yahoo_webcam_get_feed(int id, const char *who)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt;
+
+ if(!yid)
+ return;
+
+ /*
+ * add the user to the queue. this is a dirty hack, since
+ * the yahoo server doesn't tell us who's key it's returning,
+ * we have to just hope that it sends back keys in the same
+ * order that we request them.
+ * The queue is popped in yahoo_process_webcam_key
+ */
+ webcam_queue = y_list_append(webcam_queue, who?strdup(who):NULL);
+
+ yd = yid->yd;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_WEBCAM, YAHOO_STATUS_AVAILABLE, yd->session_id);
+
+ yahoo_packet_hash(pkt, 1, yd->user);
+ if (who != NULL)
+ yahoo_packet_hash(pkt, 5, who);
+ yahoo_send_packet(yid, pkt, 0);
+
+ yahoo_packet_free(pkt);
+}
+
+void yahoo_webcam_send_image(int id, unsigned char *image, unsigned int length, unsigned int timestamp)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_WEBCAM);
+ unsigned char *packet;
+ unsigned char header_len = 13;
+ unsigned int pos = 0;
+
+ if (!yid)
+ return;
+
+ packet = y_new0(unsigned char, header_len);
+
+ packet[pos++] = header_len;
+ packet[pos++] = 0;
+ packet[pos++] = 5; /* version byte?? */
+ packet[pos++] = 0;
+ pos += yahoo_put32(packet + pos, length);
+ packet[pos++] = 2; /* packet type, image */
+ pos += yahoo_put32(packet + pos, timestamp);
+ yahoo_add_to_send_queue(yid, packet, header_len);
+ FREE(packet);
+
+ if (length)
+ yahoo_add_to_send_queue(yid, image, length);
+}
+
+void yahoo_webcam_accept_viewer(int id, const char* who, int accept)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_WEBCAM);
+ char *packet = NULL;
+ char *data = NULL;
+ unsigned char header_len = 13;
+ unsigned int pos = 0;
+ unsigned int len = 0;
+
+ if (!yid)
+ return;
+
+ data = strdup("u=");
+ data = y_string_append(data, (char*)who);
+ data = y_string_append(data, "\r\n");
+ len = strlen(data);
+
+ packet = y_new0(char, header_len + len);
+ packet[pos++] = header_len;
+ packet[pos++] = 0;
+ packet[pos++] = 5; /* version byte?? */
+ packet[pos++] = 0;
+ pos += yahoo_put32(packet + pos, len);
+ packet[pos++] = 0; /* packet type */
+ pos += yahoo_put32(packet + pos, accept);
+ memcpy(packet + pos, data, len);
+ FREE(data);
+ yahoo_add_to_send_queue(yid, packet, header_len + len);
+ FREE(packet);
+}
+
+void yahoo_webcam_invite(int id, const char *who)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_packet *pkt;
+
+ if(!yid)
+ return;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_NOTIFY, YAHOO_STATUS_NOTIFY, yid->yd->session_id);
+
+ yahoo_packet_hash(pkt, 49, "WEBCAMINVITE");
+ yahoo_packet_hash(pkt, 14, " ");
+ yahoo_packet_hash(pkt, 13, "0");
+ yahoo_packet_hash(pkt, 1, yid->yd->user);
+ yahoo_packet_hash(pkt, 5, who);
+ yahoo_send_packet(yid, pkt, 0);
+
+ yahoo_packet_free(pkt);
+}
+
+static void yahoo_search_internal(int id, int t, const char *text, int g, int ar, int photo, int yahoo_only, int startpos, int total)
+{
+ struct yahoo_data *yd = find_conn_by_id(id);
+ struct yahoo_input_data *yid;
+ char url[1024];
+ char buff[1024];
+ char *ctext, *p;
+
+ if(!yd)
+ return;
+
+ yid = y_new0(struct yahoo_input_data, 1);
+ yid->yd = yd;
+ yid->type = YAHOO_CONNECTION_SEARCH;
+
+ /*
+ age range
+ .ar=1 - 13-18, 2 - 18-25, 3 - 25-35, 4 - 35-50, 5 - 50-70, 6 - 70+
+ */
+
+ snprintf(buff, sizeof(buff), "&.sq=%%20&.tt=%d&.ss=%d", total, startpos);
+
+ ctext = strdup(text);
+ while((p = strchr(ctext, ' ')))
+ *p = '+';
+
+ snprintf(url, 1024, "http://members.yahoo.com/interests?.oc=m&.kw=%s&.sb=%d&.g=%d&.ar=0%s%s%s",
+ ctext, t, g, photo ? "&.p=y" : "", yahoo_only ? "&.pg=y" : "",
+ startpos ? buff : "");
+
+ FREE(ctext);
+
+ snprintf(buff, sizeof(buff), "Y=%s; T=%s", yd->cookie_y, yd->cookie_t);
+ //snprintf(buff, sizeof(buff), "Y=%s; T=%s; C=%s", yd->cookie_y, yd->cookie_t, yd->cookie_c);
+
+ inputs = y_list_prepend(inputs, yid);
+ yahoo_http_get(yid->yd->client_id, url, buff, _yahoo_http_connected, yid);
+}
+
+void yahoo_search(int id, enum yahoo_search_type t, const char *text, enum yahoo_search_gender g, enum yahoo_search_agerange ar,
+ int photo, int yahoo_only)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_search_state *yss;
+
+ if(!yid)
+ return;
+
+ if(!yid->ys)
+ yid->ys = y_new0(struct yahoo_search_state, 1);
+
+ yss = yid->ys;
+
+ FREE(yss->lsearch_text);
+ yss->lsearch_type = t;
+ yss->lsearch_text = strdup(text);
+ yss->lsearch_gender = g;
+ yss->lsearch_agerange = ar;
+ yss->lsearch_photo = photo;
+ yss->lsearch_yahoo_only = yahoo_only;
+
+ yahoo_search_internal(id, t, text, g, ar, photo, yahoo_only, 0, 0);
+}
+
+void yahoo_search_again(int id, int start)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_search_state *yss;
+
+ if(!yid || !yid->ys)
+ return;
+
+ yss = yid->ys;
+
+ if(start == -1)
+ start = yss->lsearch_nstart + yss->lsearch_nfound;
+
+ yahoo_search_internal(id, yss->lsearch_type, yss->lsearch_text,
+ yss->lsearch_gender, yss->lsearch_agerange,
+ yss->lsearch_photo, yss->lsearch_yahoo_only,
+ start, yss->lsearch_ntotal);
+}
+
+struct send_file_data {
+ struct yahoo_packet *pkt;
+ yahoo_get_fd_callback callback;
+ void *user_data;
+};
+
+static void _yahoo_send_file_connected(int id, int fd, int error, void *data)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_FT);
+ struct send_file_data *sfd = data;
+ struct yahoo_packet *pkt = sfd->pkt;
+ unsigned char buff[1024];
+
+ if(fd <= 0) {
+ sfd->callback(id, fd, error, sfd->user_data);
+ FREE(sfd);
+ yahoo_packet_free(pkt);
+ inputs = y_list_remove(inputs, yid);
+ FREE(yid);
+ return;
+ }
+
+ yid->fd = fd;
+ yahoo_send_packet(yid, pkt, 8);
+ yahoo_packet_free(pkt);
+
+ snprintf((char *)buff, sizeof(buff), "29");
+ buff[2] = 0xc0;
+ buff[3] = 0x80;
+
+ write(yid->fd, buff, 4);
+
+/* YAHOO_CALLBACK(ext_yahoo_add_handler)(nyd->fd, YAHOO_INPUT_READ); */
+
+ sfd->callback(id, fd, error, sfd->user_data);
+ FREE(sfd);
+ inputs = y_list_remove(inputs, yid);
+ /*
+ while(yahoo_tcp_readline(buff, sizeof(buff), nyd->fd) > 0) {
+ if(!strcmp(buff, ""))
+ break;
+ }
+
+ */
+ yahoo_input_close(yid);
+}
+
+void yahoo_send_file(int id, const char *who, const char *msg,
+ const char *name, unsigned long size,
+ yahoo_get_fd_callback callback, void *data)
+{
+ struct yahoo_data *yd = find_conn_by_id(id);
+ struct yahoo_input_data *yid;
+ struct yahoo_server_settings *yss;
+ struct yahoo_packet *pkt = NULL;
+ char size_str[10];
+ long content_length=0;
+ unsigned char buff[1024];
+ char url[255];
+ struct send_file_data *sfd;
+ const char *s;
+
+ if(!yd)
+ return;
+
+ yss = yd->server_settings;
+
+ yid = y_new0(struct yahoo_input_data, 1);
+ yid->yd = yd;
+ yid->type = YAHOO_CONNECTION_FT;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANSFER, YAHOO_STATUS_AVAILABLE, yd->session_id);
+
+ snprintf(size_str, sizeof(size_str), "%lu", size);
+
+ yahoo_packet_hash(pkt, 0, yd->user);
+ yahoo_packet_hash(pkt, 5, who);
+ yahoo_packet_hash(pkt, 14, msg);
+
+ s = strrchr(name, '\\');
+ if (s == NULL)
+ s = name;
+ else
+ s++;
+
+ yahoo_packet_hash(pkt, 27, s);
+ yahoo_packet_hash(pkt, 28, size_str);
+
+ content_length = YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt);
+
+ snprintf(url, sizeof(url), "http://%s:%d/notifyft",
+ yss->filetransfer_host, yss->filetransfer_port);
+ snprintf((char *)buff, sizeof(buff), "Y=%s; T=%s; C=%s;",
+ yd->cookie_y, yd->cookie_t, yd->cookie_c);
+ inputs = y_list_prepend(inputs, yid);
+
+ sfd = y_new0(struct send_file_data, 1);
+ sfd->pkt = pkt;
+ sfd->callback = callback;
+ sfd->user_data = data;
+ yahoo_http_post(yid->yd->client_id, url, (char *)buff, content_length+4+size,
+ _yahoo_send_file_connected, sfd);
+}
+
+void yahoo_send_avatar(int id, const char *name, unsigned long size,
+ yahoo_get_fd_callback callback, void *data)
+{
+ struct yahoo_data *yd = find_conn_by_id(id);
+ struct yahoo_input_data *yid;
+ struct yahoo_server_settings *yss;
+ struct yahoo_packet *pkt = NULL;
+ char size_str[10];
+ long content_length=0;
+ unsigned char buff[1024];
+ char url[255];
+ struct send_file_data *sfd;
+ const char *s;
+
+ if(!yd)
+ return;
+
+ yss = yd->server_settings;
+
+ yid = y_new0(struct yahoo_input_data, 1);
+ yid->yd = yd;
+ yid->type = YAHOO_CONNECTION_FT;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_UPLOAD, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ /* 1 = me, 38 = expire time(?), 0 = me, 28 = size, 27 = filename, 14 = NULL, 29 = data */
+ snprintf(size_str, sizeof(size_str), "%lu", size);
+
+ yahoo_packet_hash(pkt, 1, yd->user);
+ yahoo_packet_hash(pkt, 38, "604800"); /* time to expire */
+ yahoo_packet_hash(pkt, 0, yd->user);
+
+ s = strrchr(name, '\\');
+ if (s == NULL)
+ s = name;
+ else
+ s++;
+ yahoo_packet_hash(pkt, 28, size_str);
+ yahoo_packet_hash(pkt, 27, s);
+ yahoo_packet_hash(pkt, 14, "");
+
+ content_length = YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt);
+
+ snprintf(url, sizeof(url), "http://%s:%d/notifyft",
+ yss->filetransfer_host, yss->filetransfer_port);
+ snprintf((char *)buff, sizeof(buff), "Y=%s; T=%s; C=%s;",
+ yd->cookie_y, yd->cookie_t, yd->cookie_c);
+ inputs = y_list_prepend(inputs, yid);
+
+ sfd = y_new0(struct send_file_data, 1);
+ sfd->pkt = pkt;
+ sfd->callback = callback;
+ sfd->user_data = data;
+ yahoo_http_post(yid->yd->client_id, url, (char *)buff, content_length+4+size,
+ _yahoo_send_file_connected, sfd);
+}
+
+enum yahoo_status yahoo_current_status(int id)
+{
+ struct yahoo_data *yd = find_conn_by_id(id);
+ if(!yd)
+ return YAHOO_STATUS_OFFLINE;
+ return yd->current_status;
+}
+
+const YList * yahoo_get_buddylist(int id)
+{
+ struct yahoo_data *yd = find_conn_by_id(id);
+ if(!yd)
+ return NULL;
+ return yd->buddies;
+}
+
+const YList * yahoo_get_ignorelist(int id)
+{
+ struct yahoo_data *yd = find_conn_by_id(id);
+ if(!yd)
+ return NULL;
+ return yd->ignore;
+}
+
+const YList * yahoo_get_identities(int id)
+{
+ struct yahoo_data *yd = find_conn_by_id(id);
+ if(!yd)
+ return NULL;
+ return yd->identities;
+}
+
+const char * yahoo_get_cookie(int id, const char *which)
+{
+ struct yahoo_data *yd = find_conn_by_id(id);
+ if(!yd)
+ return NULL;
+ if(!strncasecmp(which, "y", 1))
+ return yd->cookie_y;
+ if(!strncasecmp(which, "t", 1))
+ return yd->cookie_t;
+ if(!strncasecmp(which, "c", 1))
+ return yd->cookie_c;
+ if(!strncasecmp(which, "login", 5))
+ return yd->login_cookie;
+ if(!strncasecmp(which, "b", 1))
+ return yd->cookie_b;
+ return NULL;
+}
+
+void yahoo_get_url_handle(int id, const char *url,
+ yahoo_get_url_handle_callback callback, void *data)
+{
+ struct yahoo_data *yd = find_conn_by_id(id);
+ if(!yd)
+ return;
+
+ yahoo_get_url_fd(id, url, yd, callback, data);
+}
+
+const char * yahoo_get_profile_url( void )
+{
+ return profile_url;
+}
+
+void yahoo_request_buddy_avatar(int id, const char *buddy)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt = NULL;
+ struct yahoo_server_settings *yss;
+
+ if(!yid)
+ return;
+
+ yd = yid->yd;
+ yss = yd->server_settings;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_packet_hash(pkt, 1, yd->user);
+ yahoo_packet_hash(pkt, 5, buddy);
+ yahoo_packet_hash(pkt, 13, "1");
+
+ if (yss->web_messenger) {
+ char z[128];
+
+ yahoo_packet_hash(pkt, 0, yd->user);
+ wsprintf(z, "%d", yd->session_timestamp);
+ yahoo_packet_hash(pkt, 24, z);
+ }
+
+ yahoo_send_packet(yid, pkt, 0);
+ yahoo_packet_free(pkt);
+}
+
+void yahoo_ftdc_cancel(int id, const char *buddy, const char *filename, const char *ft_token, int command)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt = NULL;
+
+ if(!yid)
+ return;
+
+ yd = yid->yd;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_packet_hash(pkt, 5, buddy);
+ yahoo_packet_hash(pkt, 49, "FILEXFER");
+ yahoo_packet_hash(pkt, 1, yd->user);
+ yahoo_packet_hash(pkt, 13, (command == 2) ? "2" : "3");
+ yahoo_packet_hash(pkt, 27, filename);
+ yahoo_packet_hash(pkt, 53, ft_token);
+
+ yahoo_send_packet(yid, pkt, 0);
+ yahoo_packet_free(pkt);
+
+}
+
+void yahoo_ft7dc_accept(int id, const char *buddy, const char *ft_token)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt = NULL;
+
+ if(!yid)
+ return;
+
+ yd = yid->yd;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_Y7_FILETRANSFER, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_packet_hash(pkt, 1, yd->user);
+ yahoo_packet_hash(pkt, 5, buddy);
+ yahoo_packet_hash(pkt,265, ft_token);
+ yahoo_packet_hash(pkt,222, "3");
+
+ yahoo_send_packet(yid, pkt, 0);
+ yahoo_packet_free(pkt);
+
+}
+
+void yahoo_ft7dc_cancel(int id, const char *buddy, const char *ft_token)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt = NULL;
+
+ if(!yid)
+ return;
+
+ yd = yid->yd;
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_Y7_FILETRANSFER, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_packet_hash(pkt, 1, yd->user);
+ yahoo_packet_hash(pkt, 5, buddy);
+ yahoo_packet_hash(pkt,265, ft_token);
+ yahoo_packet_hash(pkt,222, "4");
+
+ yahoo_send_packet(yid, pkt, 0);
+ yahoo_packet_free(pkt);
+
+}
+
+char *yahoo_webmessenger_idle_packet(int id, int *len)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt = NULL;
+ char z[128];
+ int pktlen;
+ unsigned char *data;
+ int pos = 0;
+ int web_messenger = 1;
+
+ if(!yid) {
+ DEBUG_MSG(("NO Yahoo Input Data???"));
+ return NULL;
+ }
+
+ yd = yid->yd;
+
+ DEBUG_MSG(("[yahoo_webmessenger_idle_packet] Session: %d", yd->session_timestamp));
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_IDLE, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_packet_hash(pkt, 0, yd->user);
+
+ wsprintf(z, "%d", yd->session_timestamp);
+ yahoo_packet_hash(pkt, 24, z);
+
+ pktlen = yahoo_packet_length(pkt);
+ (*len) = YAHOO_PACKET_HDRLEN + pktlen;
+ data = y_new0(unsigned char, (*len) + 1);
+
+ memcpy(data + pos, "YMSG", 4); pos += 4;
+ pos += yahoo_put16(data + pos, web_messenger ? YAHOO_WEBMESSENGER_PROTO_VER : YAHOO_PROTO_VER); /* version [latest 12 0x000c */
+ pos += yahoo_put16(data + pos, 0x0000); /* HIWORD pkt length??? */
+ pos += yahoo_put16(data + pos, pktlen); /* LOWORD pkt length? */
+ pos += yahoo_put16(data + pos, pkt->service); /* service */
+ pos += yahoo_put32(data + pos, pkt->status); /* status [4bytes] */
+ pos += yahoo_put32(data + pos, pkt->id); /* session [4bytes] */
+
+ yahoo_packet_write(pkt, data + pos);
+
+ //yahoo_packet_dump(data, len);
+ DEBUG_MSG(("Sending Idle Packet:"));
+ DEBUG_MSG(("Yahoo Service: %s (0x%02x) Status: %s (%d)", dbg_service(pkt->service), pkt->service,
+ dbg_status(pkt->status),pkt->status));
+
+ yahoo_packet_read(pkt, data + pos, (*len) - pos);
+
+
+ return data;
+}
+
+void yahoo_send_idle_packet(int id)
+{
+ struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+ struct yahoo_data *yd;
+ struct yahoo_packet *pkt = NULL;
+ char z[128];
+
+ if(!yid) {
+ DEBUG_MSG(("NO Yahoo Input Data???"));
+ return;
+ }
+
+ yd = yid->yd;
+
+ DEBUG_MSG(("[yahoo_send_idle_packet] Session: %d", yd->session_timestamp));
+
+ pkt = yahoo_packet_new(YAHOO_SERVICE_IDLE, YAHOO_STATUS_AVAILABLE, yd->session_id);
+ yahoo_packet_hash(pkt, 0, yd->user);
+
+ wsprintf(z, "%d", yd->session_timestamp);
+ yahoo_packet_hash(pkt, 24, z);
+
+ yahoo_send_packet(yid, pkt, 0);
+ yahoo_packet_free(pkt);
+}
diff --git a/miranda-wine/protocols/Yahoo/libyahoo2/md5.c b/miranda-wine/protocols/Yahoo/libyahoo2/md5.c
new file mode 100644
index 0000000..88a0ed1
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/libyahoo2/md5.c
@@ -0,0 +1,408 @@
+/*
+ Copyright (C) 1999 Aladdin Enterprises. All rights reserved.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ L. Peter Deutsch
+ ghost@aladdin.com
+
+ */
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321.
+ It is derived directly from the text of the RFC and not from the
+ reference implementation.
+
+ The original and principal author of md5.c is L. Peter Deutsch
+ <ghost@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+ 1999-05-03 lpd Original version.
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "md5.h"
+
+#if STDC_HEADERS
+# include <string.h>
+#else
+# if !HAVE_STRCHR
+# define strchr index
+# define strrchr rindex
+# endif
+char *strchr (), *strrchr ();
+# if !HAVE_MEMCPY
+# define memcpy(d, s, n) bcopy ((s), (d), (n))
+# define memmove(d, s, n) bcopy ((s), (d), (n))
+# endif
+#endif
+
+#ifdef TEST
+/*
+ * Compile with -DTEST to create a self-contained executable test program.
+ * The test program should print out the same values as given in section
+ * A.5 of RFC 1321, reproduced below.
+ */
+main()
+{
+ static const char *const test[7] = {
+ "", /*d41d8cd98f00b204e9800998ecf8427e*/
+ "945399884.61923487334tuvga", /*0cc175b9c0f1b6a831c399e269772661*/
+ "abc", /*900150983cd24fb0d6963f7d28e17f72*/
+ "message digest", /*f96b697d7cb7938d525a2f31aaf161d0*/
+ "abcdefghijklmnopqrstuvwxyz", /*c3fcd3d76192e4007dfb496cca67e13b*/
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ /*d174ab98d277d9f5a5611c2c9f419d9f*/
+ "12345678901234567890123456789012345678901234567890123456789012345678901234567890" /*57edf4a22be3c955ac49da2e2107b67a*/
+ };
+ int i;
+
+ for (i = 0; i < 7; ++i) {
+ md5_state_t state;
+ md5_byte_t digest[16];
+ int di;
+
+ md5_init(&state);
+ md5_append(&state, (const md5_byte_t *)test[i], strlen(test[i]));
+ md5_finish(&state, digest);
+ printf("MD5 (\"%s\") = ", test[i]);
+ for (di = 0; di < 16; ++di)
+ printf("%02x", digest[di]);
+ printf("\n");
+ }
+ return 0;
+}
+#endif /* TEST */
+
+
+/*
+ * For reference, here is the program that computed the T values.
+ */
+#if 0
+#include <math.h>
+main()
+{
+ int i;
+ for (i = 1; i <= 64; ++i) {
+ unsigned long v = (unsigned long)(4294967296.0 * fabs(sin((double)i)));
+ printf("#define T%d 0x%08lx\n", i, v);
+ }
+ return 0;
+}
+#endif
+/*
+ * End of T computation program.
+ */
+#define T1 0xd76aa478
+#define T2 0xe8c7b756
+#define T3 0x242070db
+#define T4 0xc1bdceee
+#define T5 0xf57c0faf
+#define T6 0x4787c62a
+#define T7 0xa8304613
+#define T8 0xfd469501
+#define T9 0x698098d8
+#define T10 0x8b44f7af
+#define T11 0xffff5bb1
+#define T12 0x895cd7be
+#define T13 0x6b901122
+#define T14 0xfd987193
+#define T15 0xa679438e
+#define T16 0x49b40821
+#define T17 0xf61e2562
+#define T18 0xc040b340
+#define T19 0x265e5a51
+#define T20 0xe9b6c7aa
+#define T21 0xd62f105d
+#define T22 0x02441453
+#define T23 0xd8a1e681
+#define T24 0xe7d3fbc8
+#define T25 0x21e1cde6
+#define T26 0xc33707d6
+#define T27 0xf4d50d87
+#define T28 0x455a14ed
+#define T29 0xa9e3e905
+#define T30 0xfcefa3f8
+#define T31 0x676f02d9
+#define T32 0x8d2a4c8a
+#define T33 0xfffa3942
+#define T34 0x8771f681
+#define T35 0x6d9d6122
+#define T36 0xfde5380c
+#define T37 0xa4beea44
+#define T38 0x4bdecfa9
+#define T39 0xf6bb4b60
+#define T40 0xbebfbc70
+#define T41 0x289b7ec6
+#define T42 0xeaa127fa
+#define T43 0xd4ef3085
+#define T44 0x04881d05
+#define T45 0xd9d4d039
+#define T46 0xe6db99e5
+#define T47 0x1fa27cf8
+#define T48 0xc4ac5665
+#define T49 0xf4292244
+#define T50 0x432aff97
+#define T51 0xab9423a7
+#define T52 0xfc93a039
+#define T53 0x655b59c3
+#define T54 0x8f0ccc92
+#define T55 0xffeff47d
+#define T56 0x85845dd1
+#define T57 0x6fa87e4f
+#define T58 0xfe2ce6e0
+#define T59 0xa3014314
+#define T60 0x4e0811a1
+#define T61 0xf7537e82
+#define T62 0xbd3af235
+#define T63 0x2ad7d2bb
+#define T64 0xeb86d391
+
+static void
+md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
+{
+ md5_word_t
+ a = pms->abcd[0], b = pms->abcd[1],
+ c = pms->abcd[2], d = pms->abcd[3];
+ md5_word_t t;
+
+#ifndef ARCH_IS_BIG_ENDIAN
+# define ARCH_IS_BIG_ENDIAN 1 /* slower, default implementation */
+#endif
+#if ARCH_IS_BIG_ENDIAN
+
+ /*
+ * On big-endian machines, we must arrange the bytes in the right
+ * order. (This also works on machines of unknown byte order.)
+ */
+ md5_word_t X[16];
+ const md5_byte_t *xp = data;
+ int i;
+
+ for (i = 0; i < 16; ++i, xp += 4)
+ X[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+
+#else /* !ARCH_IS_BIG_ENDIAN */
+
+ /*
+ * On little-endian machines, we can process properly aligned data
+ * without copying it.
+ */
+ md5_word_t xbuf[16];
+ const md5_word_t *X;
+
+ if (!((data - (const md5_byte_t *)0) & 3)) {
+ /* data are properly aligned */
+ X = (const md5_word_t *)data;
+ } else {
+ /* not aligned */
+ memcpy(xbuf, data, 64);
+ X = xbuf;
+ }
+#endif
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+ /* Round 1. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + F(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 7, T1);
+ SET(d, a, b, c, 1, 12, T2);
+ SET(c, d, a, b, 2, 17, T3);
+ SET(b, c, d, a, 3, 22, T4);
+ SET(a, b, c, d, 4, 7, T5);
+ SET(d, a, b, c, 5, 12, T6);
+ SET(c, d, a, b, 6, 17, T7);
+ SET(b, c, d, a, 7, 22, T8);
+ SET(a, b, c, d, 8, 7, T9);
+ SET(d, a, b, c, 9, 12, T10);
+ SET(c, d, a, b, 10, 17, T11);
+ SET(b, c, d, a, 11, 22, T12);
+ SET(a, b, c, d, 12, 7, T13);
+ SET(d, a, b, c, 13, 12, T14);
+ SET(c, d, a, b, 14, 17, T15);
+ SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+ /* Round 2. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + G(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 1, 5, T17);
+ SET(d, a, b, c, 6, 9, T18);
+ SET(c, d, a, b, 11, 14, T19);
+ SET(b, c, d, a, 0, 20, T20);
+ SET(a, b, c, d, 5, 5, T21);
+ SET(d, a, b, c, 10, 9, T22);
+ SET(c, d, a, b, 15, 14, T23);
+ SET(b, c, d, a, 4, 20, T24);
+ SET(a, b, c, d, 9, 5, T25);
+ SET(d, a, b, c, 14, 9, T26);
+ SET(c, d, a, b, 3, 14, T27);
+ SET(b, c, d, a, 8, 20, T28);
+ SET(a, b, c, d, 13, 5, T29);
+ SET(d, a, b, c, 2, 9, T30);
+ SET(c, d, a, b, 7, 14, T31);
+ SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+ /* Round 3. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + H(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 5, 4, T33);
+ SET(d, a, b, c, 8, 11, T34);
+ SET(c, d, a, b, 11, 16, T35);
+ SET(b, c, d, a, 14, 23, T36);
+ SET(a, b, c, d, 1, 4, T37);
+ SET(d, a, b, c, 4, 11, T38);
+ SET(c, d, a, b, 7, 16, T39);
+ SET(b, c, d, a, 10, 23, T40);
+ SET(a, b, c, d, 13, 4, T41);
+ SET(d, a, b, c, 0, 11, T42);
+ SET(c, d, a, b, 3, 16, T43);
+ SET(b, c, d, a, 6, 23, T44);
+ SET(a, b, c, d, 9, 4, T45);
+ SET(d, a, b, c, 12, 11, T46);
+ SET(c, d, a, b, 15, 16, T47);
+ SET(b, c, d, a, 2, 23, T48);
+#undef SET
+
+ /* Round 4. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + I(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 6, T49);
+ SET(d, a, b, c, 7, 10, T50);
+ SET(c, d, a, b, 14, 15, T51);
+ SET(b, c, d, a, 5, 21, T52);
+ SET(a, b, c, d, 12, 6, T53);
+ SET(d, a, b, c, 3, 10, T54);
+ SET(c, d, a, b, 10, 15, T55);
+ SET(b, c, d, a, 1, 21, T56);
+ SET(a, b, c, d, 8, 6, T57);
+ SET(d, a, b, c, 15, 10, T58);
+ SET(c, d, a, b, 6, 15, T59);
+ SET(b, c, d, a, 13, 21, T60);
+ SET(a, b, c, d, 4, 6, T61);
+ SET(d, a, b, c, 11, 10, T62);
+ SET(c, d, a, b, 2, 15, T63);
+ SET(b, c, d, a, 9, 21, T64);
+#undef SET
+
+ /* Then perform the following additions. (That is increment each
+ of the four registers by the value it had before this block
+ was started.) */
+ pms->abcd[0] += a;
+ pms->abcd[1] += b;
+ pms->abcd[2] += c;
+ pms->abcd[3] += d;
+}
+
+void
+md5_init(md5_state_t *pms)
+{
+ pms->count[0] = pms->count[1] = 0;
+ pms->abcd[0] = 0x67452301;
+ pms->abcd[1] = 0xefcdab89;
+ pms->abcd[2] = 0x98badcfe;
+ pms->abcd[3] = 0x10325476;
+}
+
+void
+md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
+{
+ const md5_byte_t *p = data;
+ int left = nbytes;
+ int offset = (pms->count[0] >> 3) & 63;
+ md5_word_t nbits = (md5_word_t)(nbytes << 3);
+
+ if (nbytes <= 0)
+ return;
+
+ /* Update the message length. */
+ pms->count[1] += nbytes >> 29;
+ pms->count[0] += nbits;
+ if (pms->count[0] < nbits)
+ pms->count[1]++;
+
+ /* Process an initial partial block. */
+ if (offset) {
+ int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+ memcpy(pms->buf + offset, p, copy);
+ if (offset + copy < 64)
+ return;
+ p += copy;
+ left -= copy;
+ md5_process(pms, pms->buf);
+ }
+
+ /* Process full blocks. */
+ for (; left >= 64; p += 64, left -= 64)
+ md5_process(pms, p);
+
+ /* Process a final partial block. */
+ if (left)
+ memcpy(pms->buf, p, left);
+}
+
+void
+md5_finish(md5_state_t *pms, md5_byte_t digest[16])
+{
+ static const md5_byte_t pad[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ md5_byte_t data[8];
+ int i;
+
+ /* Save the length before padding. */
+ for (i = 0; i < 8; ++i)
+ data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+ /* Pad to 56 bytes mod 64. */
+ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+ /* Append the length. */
+ md5_append(pms, data, 8);
+ for (i = 0; i < 16; ++i)
+ digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
diff --git a/miranda-wine/protocols/Yahoo/libyahoo2/md5.h b/miranda-wine/protocols/Yahoo/libyahoo2/md5.h
new file mode 100644
index 0000000..04ea494
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/libyahoo2/md5.h
@@ -0,0 +1,93 @@
+/*
+ Copyright (C) 1999 Aladdin Enterprises. All rights reserved.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ L. Peter Deutsch
+ ghost@aladdin.com
+
+ */
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321.
+ It is derived directly from the text of the RFC and not from the
+ reference implementation.
+
+ The original and principal author of md5.h is L. Peter Deutsch
+ <ghost@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
+ added conditionalization for C++ compilation from Martin
+ Purschke <purschke@bnl.gov>.
+ 1999-05-03 lpd Original version.
+ */
+
+#ifndef md5_INCLUDED
+# define md5_INCLUDED
+
+/*
+ * This code has some adaptations for the Ghostscript environment, but it
+ * will compile and run correctly in any environment with 8-bit chars and
+ * 32-bit ints. Specifically, it assumes that if the following are
+ * defined, they have the same meaning as in Ghostscript: P1, P2, P3,
+ * ARCH_IS_BIG_ENDIAN.
+ */
+
+typedef unsigned char md5_byte_t; /* 8-bit byte */
+typedef unsigned int md5_word_t; /* 32-bit word */
+
+/* Define the state of the MD5 Algorithm. */
+typedef struct md5_state_s {
+ md5_word_t count[2]; /* message length in bits, lsw first */
+ md5_word_t abcd[4]; /* digest buffer */
+ md5_byte_t buf[64]; /* accumulate block */
+} md5_state_t;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Initialize the algorithm. */
+#ifdef P1
+void md5_init(P1(md5_state_t *pms));
+#else
+void md5_init(md5_state_t *pms);
+#endif
+
+/* Append a string to the message. */
+#ifdef P3
+void md5_append(P3(md5_state_t *pms, const md5_byte_t *data, int nbytes));
+#else
+void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
+#endif
+
+/* Finish the message and return the digest. */
+#ifdef P2
+void md5_finish(P2(md5_state_t *pms, md5_byte_t digest[16]));
+#else
+void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
+#endif
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+#endif /* md5_INCLUDED */
diff --git a/miranda-wine/protocols/Yahoo/libyahoo2/sha.c b/miranda-wine/protocols/Yahoo/libyahoo2/sha.c
new file mode 100644
index 0000000..0c579db
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/libyahoo2/sha.c
@@ -0,0 +1,161 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is SHA 180-1 Reference Implementation (Compact version).
+ *
+ * The Initial Developer of the Original Code is
+ * Paul Kocher of Cryptography Research.
+ * Portions created by the Initial Developer are Copyright (C) 1995-9
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "sha.h"
+
+static void shaHashBlock(SHA_CTX *ctx);
+
+void shaInit(SHA_CTX *ctx) {
+ int i;
+
+ ctx->lenW = 0;
+ ctx->sizeHi = ctx->sizeLo = 0;
+
+ /* Initialize H with the magic constants (see FIPS180 for constants)
+ */
+ ctx->H[0] = 0x67452301L;
+ ctx->H[1] = 0xefcdab89L;
+ ctx->H[2] = 0x98badcfeL;
+ ctx->H[3] = 0x10325476L;
+ ctx->H[4] = 0xc3d2e1f0L;
+
+ for (i = 0; i < 80; i++)
+ ctx->W[i] = 0;
+}
+
+
+void shaUpdate(SHA_CTX *ctx, unsigned char *dataIn, int len) {
+ int i;
+
+ /* Read the data into W and process blocks as they get full
+ */
+ for (i = 0; i < len; i++) {
+ ctx->W[ctx->lenW / 4] <<= 8;
+ ctx->W[ctx->lenW / 4] |= (unsigned long)dataIn[i];
+ if ((++ctx->lenW) % 64 == 0) {
+ shaHashBlock(ctx);
+ ctx->lenW = 0;
+ }
+ ctx->sizeLo += 8;
+ ctx->sizeHi += (ctx->sizeLo < 8);
+ }
+}
+
+
+void shaFinal(SHA_CTX *ctx, unsigned char hashout[20]) {
+ unsigned char pad0x80 = 0x80;
+ unsigned char pad0x00 = 0x00;
+ unsigned char padlen[8];
+ int i;
+
+ /* Pad with a binary 1 (e.g. 0x80), then zeroes, then length
+ */
+ padlen[0] = (unsigned char)((ctx->sizeHi >> 24) & 255);
+ padlen[1] = (unsigned char)((ctx->sizeHi >> 16) & 255);
+ padlen[2] = (unsigned char)((ctx->sizeHi >> 8) & 255);
+ padlen[3] = (unsigned char)((ctx->sizeHi >> 0) & 255);
+ padlen[4] = (unsigned char)((ctx->sizeLo >> 24) & 255);
+ padlen[5] = (unsigned char)((ctx->sizeLo >> 16) & 255);
+ padlen[6] = (unsigned char)((ctx->sizeLo >> 8) & 255);
+ padlen[7] = (unsigned char)((ctx->sizeLo >> 0) & 255);
+ shaUpdate(ctx, &pad0x80, 1);
+ while (ctx->lenW != 56)
+ shaUpdate(ctx, &pad0x00, 1);
+ shaUpdate(ctx, padlen, 8);
+
+ /* Output hash
+ */
+ for (i = 0; i < 20; i++) {
+ hashout[i] = (unsigned char)(ctx->H[i / 4] >> 24);
+ ctx->H[i / 4] <<= 8;
+ }
+
+ /*
+ * Re-initialize the context (also zeroizes contents)
+ */
+ shaInit(ctx);
+}
+
+
+void shaBlock(unsigned char *dataIn, int len, unsigned char hashout[20]) {
+ SHA_CTX ctx;
+
+ shaInit(&ctx);
+ shaUpdate(&ctx, dataIn, len);
+ shaFinal(&ctx, hashout);
+}
+
+
+#define SHA_ROTL(X,n) (((X) << (n)) | ((X) >> (32-(n))))
+
+static void shaHashBlock(SHA_CTX *ctx) {
+ int t;
+ unsigned long A,B,C,D,E,TEMP;
+
+ for (t = 16; t <= 79; t++)
+ ctx->W[t] =
+ SHA_ROTL(ctx->W[t-3] ^ ctx->W[t-8] ^ ctx->W[t-14] ^ ctx->W[t-16], 1);
+
+ A = ctx->H[0];
+ B = ctx->H[1];
+ C = ctx->H[2];
+ D = ctx->H[3];
+ E = ctx->H[4];
+
+ for (t = 0; t <= 19; t++) {
+ TEMP = SHA_ROTL(A,5) + (((C^D)&B)^D) + E + ctx->W[t] + 0x5a827999L;
+ E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
+ }
+ for (t = 20; t <= 39; t++) {
+ TEMP = SHA_ROTL(A,5) + (B^C^D) + E + ctx->W[t] + 0x6ed9eba1L;
+ E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
+ }
+ for (t = 40; t <= 59; t++) {
+ TEMP = SHA_ROTL(A,5) + ((B&C)|(D&(B|C))) + E + ctx->W[t] + 0x8f1bbcdcL;
+ E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
+ }
+ for (t = 60; t <= 79; t++) {
+ TEMP = SHA_ROTL(A,5) + (B^C^D) + E + ctx->W[t] + 0xca62c1d6L;
+ E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
+ }
+
+ ctx->H[0] += A;
+ ctx->H[1] += B;
+ ctx->H[2] += C;
+ ctx->H[3] += D;
+ ctx->H[4] += E;
+}
+
diff --git a/miranda-wine/protocols/Yahoo/libyahoo2/sha.h b/miranda-wine/protocols/Yahoo/libyahoo2/sha.h
new file mode 100644
index 0000000..fb58ea5
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/libyahoo2/sha.h
@@ -0,0 +1,49 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is SHA 180-1 Header File.
+ *
+ * The Initial Developer of the Original Code is
+ * Paul Kocher of Cryptography Research.
+ * Portions created by the Initial Developer are Copyright (C) 1995-9
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+typedef struct {
+ unsigned long H[5];
+ unsigned long W[80];
+ int lenW;
+ unsigned long sizeHi,sizeLo;
+} SHA_CTX;
+
+
+void shaInit(SHA_CTX *ctx);
+void shaUpdate(SHA_CTX *ctx, unsigned char *dataIn, int len);
+void shaFinal(SHA_CTX *ctx, unsigned char hashout[20]);
+void shaBlock(unsigned char *dataIn, int len, unsigned char hashout[20]);
+
diff --git a/miranda-wine/protocols/Yahoo/libyahoo2/yahoo2.h b/miranda-wine/protocols/Yahoo/libyahoo2/yahoo2.h
new file mode 100644
index 0000000..6d174bc
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/libyahoo2/yahoo2.h
@@ -0,0 +1,216 @@
+/*
+ * libyahoo2: yahoo2.h
+ *
+ * Copyright (C) 2002-2004, Philip S Tellis <philip.tellis AT gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 YAHOO2_H
+#define YAHOO2_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "yahoo2_types.h"
+
+/* returns the socket descriptor for a given pager connection. shouldn't be needed */
+int yahoo_get_fd(int id);
+
+/* says how much logging to do */
+/* see yahoo2_types.h for the different values */
+int yahoo_set_log_level(enum yahoo_log_level level);
+enum yahoo_log_level yahoo_get_log_level( void );
+
+/* these functions should be self explanatory */
+/* who always means the buddy you're acting on */
+/* id is the successful value returned by yahoo_init */
+
+
+/* init returns a connection id used to identify the connection hereon */
+/* or 0 on failure */
+/* you must call init before calling any other function */
+/*
+ * The optional parameters to init are key/value pairs that specify
+ * server settings to use. This list must be NULL terminated - even
+ * if the list is empty. If a parameter isn't set, a default value
+ * will be used. Parameter keys are strings, parameter values are
+ * either strings or ints, depending on the key. Values passed in
+ * are copied, so you can use const/auto/static/pointers/whatever
+ * you want. Parameters are:
+ * NAME TYPE DEFAULT
+ * pager_host char * scs.msg.yahoo.com
+ * pager_port int 5050
+ * filetransfer_host char * filetransfer.msg.yahoo.com
+ * filetransfer_port int 80
+ * webcam_host char * webcam.yahoo.com
+ * webcam_port int 5100
+ * webcam_description char * ""
+ * local_host char * ""
+ * conn_type int Y_WCM_DSL
+ *
+ * You should set at least local_host if you intend to use webcams
+ */
+int yahoo_init_with_attributes(const char *username, const char *password, ...);
+
+/* yahoo_init does the same as yahoo_init_with_attributes, assuming defaults
+ * for all attributes */
+int yahoo_init(const char *username, const char *password);
+
+
+
+/* release all resources held by this session */
+/* you need to call yahoo_close for a session only if
+ * yahoo_logoff is never called for it (ie, it was never logged in) */
+void yahoo_close(int id);
+/* login logs in to the server */
+/* initial is of type enum yahoo_status. see yahoo2_types.h */
+void yahoo_login(int id, int initial);
+void yahoo_logoff(int id);
+/* reloads status of all buddies */
+void yahoo_refresh(int id);
+/* activates/deactivates an identity */
+void yahoo_set_identity_status(int id, const char * identity, int active);
+/* regets the entire buddy list from the server */
+void yahoo_get_list(int id);
+/* download buddy contact information from your yahoo addressbook */
+void yahoo_get_yab(int id);
+/* add/modify an address book entry. if yab->dbid is set, it will */
+/* modify that entry else it creates a new entry */
+void yahoo_set_yab(int id, struct yab * yab);
+void yahoo_keepalive(int id);
+void yahoo_chat_keepalive(int id);
+
+/* from is the identity you're sending from. if NULL, the default is used */
+/* utf8 is whether msg is a utf8 string or not. */
+void yahoo_send_im(int id, const char *from, const char *who, const char *msg, int utf8, int buddy_icon);
+/* if type is true, send typing notice, else send stopped typing notice */
+void yahoo_send_typing(int id, const char *from, const char *who, int typ);
+
+/* used to set away/back status. */
+/* away says whether the custom message is an away message or a sig */
+void yahoo_set_away(int id, enum yahoo_status state, const char *msg, int away);
+void yahoo_set_stealth(int id, const char *buddy, int add);
+
+void yahoo_add_buddy(int id, const char *who, const char *group, const char *msg);
+void yahoo_remove_buddy(int id, const char *who, const char *group);
+void yahoo_accept_buddy(int id, const char *who);
+void yahoo_reject_buddy(int id, const char *who, const char *msg);
+/* if unignore is true, unignore, else ignore */
+void yahoo_ignore_buddy(int id, const char *who, int unignore);
+void yahoo_change_buddy_group(int id, const char *who, const char *old_group, const char *new_group);
+void yahoo_group_rename(int id, const char *old_group, const char *new_group);
+
+void yahoo_conference_invite(int id, const char * from, YList *who, const char *room, const char *msg);
+void yahoo_conference_addinvite(int id, const char * from, const char *who, const char *room, const YList * members, const char *msg);
+void yahoo_conference_decline(int id, const char * from, YList *who, const char *room, const char *msg);
+void yahoo_conference_message(int id, const char * from, YList *who, const char *room, const char *msg, int utf8);
+void yahoo_conference_logon(int id, const char * from, YList *who, const char *room);
+void yahoo_conference_logoff(int id, const char * from, YList *who, const char *room);
+
+/* Get a list of chatrooms */
+void yahoo_get_chatrooms(int id,int chatroomid);
+/* join room with specified roomname and roomid */
+void yahoo_chat_logon(int id, const char *from, const char *room, const char *roomid);
+/* Send message "msg" to room with specified roomname, msgtype is 1-normal message or 2-/me mesage */
+void yahoo_chat_message(int id, const char *from, const char *room, const char *msg, const int msgtype, const int utf8);
+/* Log off chat */
+void yahoo_chat_logoff(int id, const char *from);
+
+/* requests a webcam feed */
+/* who is the person who's webcam you would like to view */
+/* if who is null, then you're the broadcaster */
+void yahoo_webcam_get_feed(int id, const char *who);
+void yahoo_webcam_close_feed(int id, const char *who);
+
+/* sends an image when uploading */
+/* image points to a JPEG-2000 image, length is the length of the image */
+/* in bytes. The timestamp is the time in milliseconds since we started the */
+/* webcam. */
+void yahoo_webcam_send_image(int id, unsigned char *image, unsigned int length, unsigned int timestamp);
+
+/* this function should be called if we want to allow a user to watch the */
+/* webcam. Who is the user we want to accept. */
+/* Accept user (accept = 1), decline user (accept = 0) */
+void yahoo_webcam_accept_viewer(int id, const char* who, int accept);
+
+/* send an invitation to a user to view your webcam */
+void yahoo_webcam_invite(int id, const char *who);
+
+/* will set up a connection and initiate file transfer.
+ * callback will be called with the fd that you should write
+ * the file data to
+ */
+void yahoo_send_file(int id, const char *who, const char *msg, const char *name, unsigned long size,
+ yahoo_get_fd_callback callback, void *data);
+
+void yahoo_send_avatar(int id, const char *name, unsigned long size,
+ yahoo_get_fd_callback callback, void *data);
+
+/* send a search request
+ */
+void yahoo_search(int id, enum yahoo_search_type t, const char *text, enum yahoo_search_gender g, enum yahoo_search_agerange ar,
+ int photo, int yahoo_only);
+
+/* continue last search
+ * should be called if only (start+found >= total)
+ *
+ * where the above three are passed to ext_yahoo_got_search_result
+ */
+void yahoo_search_again(int id, int start);
+
+/* returns a socket fd to a url for downloading a file. */
+void yahoo_get_url_handle(int id, const char *url,
+ yahoo_get_url_handle_callback callback, void *data);
+
+/* these should be called when input is available on a fd */
+/* registered by ext_yahoo_add_handler */
+/* if these return negative values, errno may be set */
+int yahoo_read_ready(int id, int fd, void *data);
+int yahoo_write_ready(int id, int fd, void *data);
+
+/* utility functions. these do not hit the server */
+enum yahoo_status yahoo_current_status(int id);
+const YList * yahoo_get_buddylist(int id);
+const YList * yahoo_get_ignorelist(int id);
+const YList * yahoo_get_identities(int id);
+/* 'which' could be y, t, c or login. This may change in later versions. */
+const char * yahoo_get_cookie(int id, const char *which);
+
+/* returns the url used to get user profiles - you must append the user id */
+/* as of now this is http://profiles.yahoo.com/ */
+/* You'll have to do urlencoding yourself, but see yahoo_httplib.h first */
+const char * yahoo_get_profile_url( void );
+
+void yahoo_request_buddy_avatar(int id, const char *buddy);
+void yahoo_send_picture_checksum(int id, const char* who, int cksum);
+void yahoo_send_picture_info(int id, const char *who, int type, const char *pic_url, int cksum);
+void yahoo_send_avatar_update(int id, int buddy_icon);
+void yahoo_send_picture_update(int id, const char *who, int type);
+
+void yahoo_ftdc_cancel(int id, const char *buddy, const char *filename, const char *ft_token, int command);
+void yahoo_ft7dc_accept(int id, const char *buddy, const char *ft_token);
+void yahoo_ft7dc_cancel(int id, const char *buddy, const char *ft_token);
+char *yahoo_webmessenger_idle_packet(int id, int* len);
+void yahoo_send_idle_packet(int id);
+#include "yahoo_httplib.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/miranda-wine/protocols/Yahoo/libyahoo2/yahoo2_callbacks.h b/miranda-wine/protocols/Yahoo/libyahoo2/yahoo2_callbacks.h
new file mode 100644
index 0000000..ac4ede2
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/libyahoo2/yahoo2_callbacks.h
@@ -0,0 +1,790 @@
+/*
+ * libyahoo2: yahoo2_callbacks.h
+ *
+ * Copyright (C) 2002-2004, Philip S Tellis <philip.tellis AT gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/*
+ * The functions in this file *must* be defined in your client program
+ * If you want to use a callback structure instead of direct functions,
+ * then you must define USE_STRUCT_CALLBACKS in all files that #include
+ * this one.
+ *
+ * Register the callback structure by calling yahoo_register_callbacks -
+ * declared in this file and defined in libyahoo2.c
+ */
+
+
+#ifndef YAHOO2_CALLBACKS_H
+#define YAHOO2_CALLBACKS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "yahoo2_types.h"
+
+/*
+ * yahoo2_callbacks.h
+ *
+ * Callback interface for libyahoo2
+ */
+
+typedef enum {
+ YAHOO_INPUT_READ = 1 << 0,
+ YAHOO_INPUT_WRITE = 1 << 1,
+ YAHOO_INPUT_EXCEPTION = 1 << 2
+} yahoo_input_condition;
+
+/*
+ * A callback function called when an asynchronous connect completes.
+ *
+ * Params:
+ * fd - The file descriptor that has been connected, or -1 on error
+ * error - The value of errno set by the call to connect or 0 if no error
+ * Set both fd and error to 0 if the connect was cancelled by the
+ * user
+ * callback_data - the callback_data passed to the ext_yahoo_connect_async
+ * function
+ */
+typedef void (*yahoo_connect_callback)(int fd, int error, void *callback_data);
+
+
+/*
+ * The following functions need to be implemented in the client
+ * interface. They will be called by the library when each
+ * event occurs.
+ */
+
+/*
+ * should we use a callback structure or directly call functions
+ * if you want the structure, you *must* define USE_STRUCT_CALLBACKS
+ * both when you compile the library, and when you compile your code
+ * that uses the library
+ */
+
+#ifdef USE_STRUCT_CALLBACKS
+#define YAHOO_CALLBACK_TYPE(x) (*x)
+struct yahoo_callbacks {
+#else
+#define YAHOO_CALLBACK_TYPE(x) x
+#endif
+
+/*
+ * Name: ext_yahoo_login_response
+ * Called when the login process is complete
+ * Params:
+ * id - the id that identifies the server connection
+ * succ - enum yahoo_login_status
+ * url - url to reactivate account if locked
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_login_response)(int id, int succ, const char *url);
+
+
+/*
+ * Name: ext_yahoo_got_buddies
+ * Called when the contact list is got from the server
+ * Params:
+ * id - the id that identifies the server connection
+ * buds - the buddy list
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_got_buddies)(int id, YList * buds);
+
+
+/*
+ * Name: ext_yahoo_got_buddies
+ * Called when the contact list is got from the server
+ * Params:
+ * id - the id that identifies the server connection
+ * stealthlist - a string representing buddy ids to hide from
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_got_stealthlist)(int id, char *stealthlist);
+
+
+/*
+ * Name: ext_yahoo_got_avatar_share
+ * Called when the contact list is got from the server
+ * Params:
+ * id - the id that identifies the server connection
+ * buddyIcon - current setting of how we sharing avatars
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_got_avatar_share)(int id, int buddy_icon);
+
+
+/*
+ * Name: ext_yahoo_got_ignore
+ * Called when the ignore list is got from the server
+ * Params:
+ * id - the id that identifies the server connection
+ * igns - the ignore list
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_got_ignore)(int id, YList * igns);
+
+
+/*
+ * Name: ext_yahoo_got_identities
+ * Called when the contact list is got from the server
+ * Params:
+ * id - the id that identifies the server connection
+ * ids - the identity list
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_got_identities)(int id, YList * ids);
+
+
+/*
+ * Name: ext_yahoo_got_cookies
+ * Called when the cookie list is got from the server
+ * Params:
+ * id - the id that identifies the server connection
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_got_cookies)(int id);
+
+
+/*
+ * Name: ext_yahoo_got_ping
+ * Called when the ping packet is received from the server
+ * Params:
+ * id - the id that identifies the server connection
+ * errormsg - optional error message
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_got_ping)(int id, const char *errormsg);
+
+
+/*
+ * Name: ext_yahoo_status_logon
+ * Called when remote user's status changes to online.
+ * Params:
+ * id - the id that identifies the server connection
+ * who - the handle of the remote user
+ * stat - status code (enum yahoo_status)
+ * msg - the message if stat == YAHOO_STATUS_CUSTOM
+ * away - whether the contact is away or not (YAHOO_STATUS_CUSTOM)
+ * idle - this is the number of seconds he is idle [if he is idle]
+ * mobile - this is set for mobile users/buddies
+ * cksum - picture checksum [avatar support]
+ * buddy_icon - avatar type
+ * client_version - client version # (Yahoo sends some long numbers for different clients)
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_status_logon)(int id, const char *who, int stat, const char *msg, int away, int idle, int mobile, int cksum, int buddy_icon, long client_version);
+
+
+/*
+ * Name: ext_yahoo_status_changed
+ * Called when remote user's status changes.
+ * Params:
+ * id - the id that identifies the server connection
+ * who - the handle of the remote user
+ * stat - status code (enum yahoo_status)
+ * msg - the message if stat == YAHOO_STATUS_CUSTOM
+ * away - whether the contact is away or not (YAHOO_STATUS_CUSTOM)
+ * idle - this is the number of seconds he is idle [if he is idle]
+ * mobile - this is set for mobile users/buddies
+ * TODO: add support for pager, chat, and game states
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_status_changed)(int id, const char *who, int stat, const char *msg, int away, int idle, int mobile);
+
+
+/*
+ * Name: ext_yahoo_got_picture
+ * Called when we request picture URL.
+ * Params:
+ * id - the id that identifies the server connection
+ * me - the identity of mine being notified
+ * who - the handle of the remote user
+ * pic_url - URL to the buddy icon
+ * cksum - checksum
+ * type - type of packet (recv/send)
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_got_picture)(int id, const char *me, const char *who, const char *pic_url, int cksum, int type);
+
+
+/*
+ * Name: ext_yahoo_got_picture_checksum
+ * Called when our buddy changes his/hers buddy icon
+ * Params:
+ * id - the id that identifies the server connection
+ * me - the identity of mine being notified
+ * who - the handle of the remote user
+ * cksum - checksum
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_got_picture_checksum)(int id, const char *me, const char *who, int cksum);
+
+
+/*
+ * Name: ext_yahoo_got_picture_update
+ * Called when our buddy shares or stops sharing pictures with us.
+ * Params:
+ * id - the id that identifies the server connection
+ * me - the identity of mine being notified
+ * who - the handle of the remote user
+ * cksum - checksum
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_got_picture_update)(int id, const char *me, const char *who, int buddy_icon);
+
+
+/*
+ * Name: ext_yahoo_got_picture_upload
+ * Called when we just uploaded a picture to Yahoo File Servers
+ * Params:
+ * id - the id that identifies the server connection
+ * me - the identity of mine being notified
+ * who - the handle of the remote user
+ * cksum - checksum
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_got_picture_upload)(int id, const char *me, const char *url, unsigned int ts);
+
+
+/*
+ * Name: ext_yahoo_got_avatar_update (Apparently this is also a GLOBAL Notification.)
+ * GF Personal Notes: 2 Notifications?? 1 for Checksum, 1 for Global? To shut it off too?
+ * Called when our buddy shares or stops sharing pictures with us.
+ * Params:
+ * id - the id that identifies the server connection
+ * me - the identity of mine being notified
+ * who - the handle of the remote user
+ * cksum - checksum
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_got_avatar_update)(int id, const char *me, const char *who, int buddy_icon);
+
+
+/*
+ * Name: ext_yahoo_got_im
+ * Called when remote user sends you a message.
+ * Params:
+ * id - the id that identifies the server connection
+ * me - the identity the message was sent to
+ * who - the handle of the remote user
+ * msg - the message - NULL if stat == 2
+ * tm - timestamp of message if offline
+ * stat - message status - 0
+ * 1
+ * 2 == error sending message
+ * 5
+ * utf8 - whether the message is encoded as utf8 or not
+ * buddy_icon - whether the buddy has buddy_icon set or not.
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_got_im)(int id, const char *me, const char *who, const char *msg, long tm, int stat, int utf8, int buddy_icon);
+
+
+/*
+ * Name: ext_yahoo_got_audible
+ * Called when our buddy send an audible to us.
+ * Params:
+ * id - the id that identifies the server connection
+ * me - the identity of mine being notified
+ * who - the handle of the remote user
+ * aud - audible sent (filename?)
+ * msg - audible message
+ * aud_hash - md5 hash?
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_got_audible)(int id, const char *me, const char *who, const char *aud, const char *msg, const char *aud_hash);
+
+
+/*
+ * Name: ext_yahoo_got_calendar
+ * Called when our buddy send an audible to us.
+ * Params:
+ * id - the id that identifies the server connection
+ * url - the URL to the calendar reminder
+ * type - type of request?
+ * msg - string/description
+ * svc - service?
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_got_calendar)(int id, const char *url, int type, const char *msg, int svc);
+
+
+/*
+ * Name: ext_yahoo_got_conf_invite
+ * Called when remote user sends you a conference invitation.
+ * Params:
+ * id - the id that identifies the server connection
+ * me - the identity the invitation was sent to
+ * who - the user inviting you
+ * room - the room to join
+ * msg - the message
+ * members - the initial members of the conference (null terminated list)
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_got_conf_invite)(int id, const char *me, const char *who, const char *room, const char *msg, YList *members);
+
+
+/*
+ * Name: ext_yahoo_conf_userdecline
+ * Called when someone declines to join the conference.
+ * Params:
+ * id - the id that identifies the server connection
+ * me - the identity in the conference
+ * who - the user who has declined
+ * room - the room
+ * msg - the declining message
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_userdecline)(int id, const char *me, const char *who, const char *room, const char *msg);
+
+
+/*
+ * Name: ext_yahoo_conf_userjoin
+ * Called when someone joins the conference.
+ * Params:
+ * id - the id that identifies the server connection
+ * me - the identity in the conference
+ * who - the user who has joined
+ * room - the room joined
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_userjoin)(int id, const char *me, const char *who, const char *room);
+
+
+/*
+ * Name: ext_yahoo_conf_userleave
+ * Called when someone leaves the conference.
+ * Params:
+ * id - the id that identifies the server connection
+ * me - the identity in the conference
+ * who - the user who has left
+ * room - the room left
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_userleave)(int id, const char *me, const char *who, const char *room);
+
+
+/*
+ * Name: ext_yahoo_chat_cat_xml
+ * Called when ?
+ * Params:
+ * id - the id that identifies the server connection
+ * xml - ?
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_cat_xml)(int id, const char *xml);
+
+
+/*
+ * Name: ext_yahoo_chat_join
+ * Called when joining the chatroom.
+ * Params:
+ * id - the id that identifies the server connection
+ * me - the identity in the chatroom
+ * room - the room joined, used in all other chat calls, freed by
+ * library after call
+ * topic - the topic of the room, freed by library after call
+ * members - the initial members of the chatroom (null terminated YList
+ * of yahoo_chat_member's) Must be freed by the client
+ * fd - the socket where the connection is coming from (for tracking)
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_join)(int id, const char *me, const char *room, const char *topic, YList *members, int fd);
+
+
+/*
+ * Name: ext_yahoo_chat_userjoin
+ * Called when someone joins the chatroom.
+ * Params:
+ * id - the id that identifies the server connection
+ * me - the identity in the chatroom
+ * room - the room joined
+ * who - the user who has joined, Must be freed by the client
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_userjoin)(int id, const char *me, const char *room, struct yahoo_chat_member *who);
+
+
+/*
+ * Name: ext_yahoo_chat_userleave
+ * Called when someone leaves the chatroom.
+ * Params:
+ * id - the id that identifies the server connection
+ * me - the identity in the chatroom
+ * room - the room left
+ * who - the user who has left (Just the User ID)
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_userleave)(int id, const char *me, const char *room, const char *who);
+
+
+/*
+ * Name: ext_yahoo_chat_message
+ * Called when someone messages in the chatroom.
+ * Params:
+ * id - the id that identifies the server connection
+ * me - the identity in the chatroom
+ * room - the room
+ * who - the user who messaged (Just the user id)
+ * msg - the message
+ * msgtype - 1 = Normal message
+ * 2 = /me type message
+ * utf8 - whether the message is utf8 encoded or not
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_message)(int id, const char *me, const char *who, const char *room, const char *msg, int msgtype, int utf8);
+
+
+/*
+ *
+ * Name: ext_yahoo_chat_yahoologout
+ * called when yahoo disconnects your chat session
+ * Note this is called whenver a disconnect happens, client or server
+ * requested. Care should be taken to make sure you know the origin
+ * of the disconnect request before doing anything here (auto-join's etc)
+ * Params:
+ * id - the id that identifies this connection
+ * me - the identity in the chatroom
+ * Returns:
+ * nothing.
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_yahoologout)(int id, const char *me);
+
+
+/*
+ *
+ * Name: ext_yahoo_chat_yahooerror
+ * called when yahoo sends back an error to you
+ * Note this is called whenver chat message is sent into a room
+ * in error (fd not connected, room doesn't exists etc)
+ * Care should be taken to make sure you know the origin
+ * of the error before doing anything about it.
+ * Params:
+ * id - the id that identifies this connection
+ * me - the identity in the chatroom
+ * Returns:
+ * nothing.
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_yahooerror)(int id, const char *me);
+
+
+/*
+ * Name: ext_yahoo_conf_message
+ * Called when someone messages in the conference.
+ * Params:
+ * id - the id that identifies the server connection
+ * me - the identity the conf message was sent to
+ * who - the user who messaged
+ * room - the room
+ * msg - the message
+ * utf8 - whether the message is utf8 encoded or not
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_message)(int id, const char *me, const char *who, const char *room, const char *msg, int utf8);
+
+
+/*
+ * Name: ext_yahoo_got_file
+ * Called when someone sends you a file
+ * Params:
+ * id - the id that identifies the server connection
+ * me - the identity the file was sent to
+ * who - the user who sent the file
+ * url - the file url
+ * expires - the expiry date of the file on the server (timestamp)
+ * msg - the message
+ * fname- the file name if direct transfer
+ * fsize- the file size if direct transfer
+ * ftoken - file token
+ * y7 - flag signalling y7 transfer
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_got_file)(int id, const char *me, const char *who, const char *url, long expires, const char *msg, const char *fname, unsigned long fesize, const char *ft_token, int y7);
+
+
+/*
+ * Name: ext_yahoo_contact_added
+ * Called when a contact adds you to their list
+ * Params:
+ * id - the id that identifies the server connection
+ * myid - the identity he was added to
+ * who - who was added
+ * msg - any message sent
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_contact_added)(int id, char *myid, char *who, char *fname, char *lname, char *msg);
+
+
+/*
+ * Name: ext_yahoo_buddy_group_changed
+ * Called when a buddy is moved from one group into another
+ * Params:
+ * id - the id that identifies the server connection
+ * myid - the identity he was added to
+ * who - who was added
+ * from_group
+ * to_group
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_buddy_group_changed)(int id, char *myid, char *who, char *old_group, char *new_group);
+
+
+/*
+ * Name: ext_yahoo_buddy_added
+ * Called when a contact is added to our server list
+ * Params:
+ * id - the id that identifies the server connection
+ * myid - the identity he was added to
+ * who - who was added
+ * group - group buddy was added to
+ * status - status of the operation
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_buddy_added)(int id, char *myid, char *who, char *group, int status, int auth);
+
+
+/*
+ * Name: ext_yahoo_rejected
+ * Called when a contact rejects your add
+ * Params:
+ * id - the id that identifies the server connection
+ * who - who rejected you
+ * msg - any message sent
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_rejected)(int id, const char *who, const char *msg);
+
+
+/*
+ * Name: ext_yahoo_typing_notify
+ * Called when remote user starts or stops typing.
+ * Params:
+ * id - the id that identifies the server connection
+ * me - the handle of the identity the notification is sent to
+ * who - the handle of the remote user
+ * stat - 1 if typing, 0 if stopped typing
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_typing_notify)(int id, const char *me, const char *who, int stat);
+
+
+/*
+ * Name: ext_yahoo_game_notify
+ * Called when remote user starts or stops a game.
+ * Params:
+ * id - the id that identifies the server connection
+ * me - the handle of the identity the notification is sent to
+ * who - the handle of the remote user
+ * stat - 1 if game, 0 if stopped gaming
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_game_notify)(int id, const char *me, const char *who, int stat, const char *msg);
+
+
+/*
+ * Name: ext_yahoo_mail_notify
+ * Called when you receive mail, or with number of messages
+ * Params:
+ * id - the id that identifies the server connection
+ * from - who the mail is from - NULL if only mail count
+ * subj - the subject of the mail - NULL if only mail count
+ * cnt - mail count - 0 if new mail notification
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_mail_notify)(int id, const char *from, const char *subj, int cnt);
+
+
+/*
+ * Name: ext_yahoo_system_message
+ * System message
+ * Params:
+ * id - the id that identifies the server connection
+ * msg - the message
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_system_message)(int id, const char *me, const char *who, const char *msg);
+
+
+/*
+ * Name: ext_yahoo_got_webcam_image
+ * Called when you get a webcam update
+ * An update can either be receiving an image, a part of an image or
+ * just an update with a timestamp
+ * Params:
+ * id - the id that identifies the server connection
+ * who - the user who's webcam we're viewing
+ * image - image data
+ * image_size - length of the image in bytes
+ * real_size - actual length of image data
+ * timestamp - milliseconds since the webcam started
+ *
+ * If the real_size is smaller then the image_size then only part of
+ * the image has been read. This function will keep being called till
+ * the total amount of bytes in image_size has been read. The image
+ * received is in JPEG-2000 Code Stream Syntax (ISO/IEC 15444-1).
+ * The size of the image will be either 160x120 or 320x240.
+ * Each webcam image contains a timestamp. This timestamp should be
+ * used to keep the image in sync since some images can take longer
+ * to transport then others. When image_size is 0 we can still receive
+ * a timestamp to stay in sync
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_got_webcam_image)(int id, const char * who,
+ const unsigned char *image, unsigned int image_size, unsigned int real_size,
+ unsigned int timestamp);
+
+
+/*
+ * Name: ext_yahoo_webcam_invite
+ * Called when you get a webcam invitation
+ * Params:
+ * id - the id that identifies the server connection
+ * me - identity the invitation is to
+ * from - who the invitation is from
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_invite)(int id, const char *me, const char *from);
+
+
+/*
+ * Name: ext_yahoo_webcam_invite_reply
+ * Called when you get a response to a webcam invitation
+ * Params:
+ * id - the id that identifies the server connection
+ * me - identity the invitation response is to
+ * from - who the invitation response is from
+ * accept - 0 (decline), 1 (accept)
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_invite_reply)(int id, const char *me, const char *from, int accept);
+
+
+/*
+ * Name: ext_yahoo_webcam_closed
+ * Called when the webcam connection closed
+ * Params:
+ * id - the id that identifies the server connection
+ * who - the user who we where connected to
+ * reason - reason why the connection closed
+ * 1 = user stopped broadcasting
+ * 2 = user cancelled viewing permission
+ * 3 = user declines permission
+ * 4 = user does not have webcam online
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_closed)(int id, const char *who, int reason);
+
+
+/*
+ * Name: ext_yahoo_got_search_result
+ * Called when the search result received from server
+ * Params:
+ * id - the id that identifies the server connection
+ * found - total number of results returned in the current result set
+ * start - offset from where the current result set starts
+ * total - total number of results available (start + found <= total)
+ * contacts - the list of results as a YList of yahoo_found_contact
+ * these will be freed after this function returns, so
+ * if you need to use the information, make a copy
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_got_search_result)(int id, int found, int start, int total, YList *contacts);
+
+
+/*
+ * Name: ext_yahoo_error
+ * Called on error.
+ * Params:
+ * id - the id that identifies the server connection
+ * err - the error message
+ * fatal- whether this error is fatal to the connection or not
+ * num - Which error is this
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_error)(int id, const char *err, int fatal, int num);
+
+
+/*
+ * Name: ext_yahoo_webcam_viewer
+ * Called when a viewer disconnects/connects/requests to connect
+ * Params:
+ * id - the id that identifies the server connection
+ * who - the viewer
+ * connect - 0=disconnect 1=connect 2=request
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_viewer)(int id, const char *who, int connect);
+
+
+/*
+ * Name: ext_yahoo_webcam_data_request
+ * Called when you get a request for webcam images
+ * Params:
+ * id - the id that identifies the server connection
+ * send - whether to send images or not
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_data_request)(int id, int send);
+
+
+/*
+ * Name: ext_yahoo_log
+ * Called to log a message.
+ * Params:
+ * fmt - the printf formatted message
+ * Returns:
+ * 0
+ */
+int YAHOO_CALLBACK_TYPE(ext_yahoo_log)(const char *fmt, ...);
+
+
+/*
+ * Name: ext_yahoo_add_handler
+ * Add a listener for the fd. Must call yahoo_read_ready
+ * when a YAHOO_INPUT_READ fd is ready and yahoo_write_ready
+ * when a YAHOO_INPUT_WRITE fd is ready.
+ * Params:
+ * id - the id that identifies the server connection
+ * fd - the fd on which to listen
+ * cond - the condition on which to call the callback
+ * data - callback data to pass to yahoo_*_ready
+ *
+ * Returns: a tag to be used when removing the handler
+ */
+int YAHOO_CALLBACK_TYPE(ext_yahoo_add_handler)(int id, int fd, yahoo_input_condition cond, void *data);
+
+
+/*
+ * Name: ext_yahoo_remove_handler
+ * Remove the listener for the fd.
+ * Params:
+ * id - the id that identifies the connection
+ * tag - the handler tag to remove
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_remove_handler)(int id, int tag);
+
+
+/*
+ * Name: ext_yahoo_connect
+ * Connect to a host:port
+ * Params:
+ * host - the host to connect to
+ * port - the port to connect on
+ * Returns:
+ * a unix file descriptor to the socket
+ */
+int YAHOO_CALLBACK_TYPE(ext_yahoo_connect)(const char *host, int port, int type);
+
+
+/*
+ * Name: ext_yahoo_connect_async
+ * Connect to a host:port asynchronously. This function should return
+ * immediately returing a tag used to identify the connection handler,
+ * or a pre-connect error (eg: host name lookup failure).
+ * Once the connect completes (successfully or unsuccessfully), callback
+ * should be called (see the signature for yahoo_connect_callback).
+ * The callback may safely be called before this function returns, but
+ * it should not be called twice.
+ * Params:
+ * id - the id that identifies this connection
+ * host - the host to connect to
+ * port - the port to connect on
+ * callback - function to call when connect completes
+ * callback_data - data to pass to the callback function
+ * Returns:
+ * a unix file descriptor to the socket
+ */
+int YAHOO_CALLBACK_TYPE(ext_yahoo_connect_async)(int id, const char *host, int port, int type,
+ yahoo_connect_callback callback, void *callback_data);
+
+#ifdef USE_STRUCT_CALLBACKS
+};
+
+/*
+ * if using a callback structure, call yahoo_register_callbacks
+ * before doing anything else
+ */
+void yahoo_register_callbacks(struct yahoo_callbacks * tyc);
+
+#undef YAHOO_CALLBACK_TYPE
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/miranda-wine/protocols/Yahoo/libyahoo2/yahoo2_types.h b/miranda-wine/protocols/Yahoo/libyahoo2/yahoo2_types.h
new file mode 100644
index 0000000..d0d4dfd
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/libyahoo2/yahoo2_types.h
@@ -0,0 +1,261 @@
+/*
+ * libyahoo2: yahoo2_types.h
+ *
+ * Copyright (C) 2002-2004, Philip S Tellis <philip.tellis AT gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 YAHOO2_TYPES_H
+#define YAHOO2_TYPES_H
+
+#include "yahoo_list.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum yahoo_status {
+ YAHOO_STATUS_DISCONNECTED = -1,
+ YAHOO_STATUS_AVAILABLE = 0,
+ YAHOO_STATUS_BRB,
+ YAHOO_STATUS_BUSY,
+ YAHOO_STATUS_NOTATHOME,
+ YAHOO_STATUS_NOTATDESK,
+ YAHOO_STATUS_NOTINOFFICE,
+ YAHOO_STATUS_ONPHONE,
+ YAHOO_STATUS_ONVACATION,
+ YAHOO_STATUS_OUTTOLUNCH,
+ YAHOO_STATUS_STEPPEDOUT,
+ YAHOO_STATUS_INVISIBLE = 12,
+ YAHOO_STATUS_CUSTOM = 99,
+ YAHOO_STATUS_IDLE = 999,
+ YAHOO_STATUS_WEBLOGIN = 0x5a55aa55,
+ YAHOO_STATUS_OFFLINE = 0x5a55aa56, /* don't ask */
+ YAHOO_STATUS_NOTIFY = 0x16 /* TYPING */
+};
+#define YAHOO_STATUS_GAME 0x2 /* Games don't fit into the regular status model */
+
+enum yahoo_login_status {
+ YAHOO_LOGIN_OK = 0,
+ YAHOO_LOGIN_LOGOFF = 2,
+ YAHOO_LOGIN_UNAME = 3,
+ YAHOO_LOGIN_PASSWD = 13,
+ YAHOO_LOGIN_LOCK = 14,
+ YAHOO_LOGIN_DUPL = 99,
+ YAHOO_LOGIN_SOCK = -1
+};
+
+enum yahoo_error {
+ E_UNKNOWN = -1,
+ E_CONNECTION = -2,
+ E_SYSTEM = -3,
+ E_CUSTOM = 0,
+
+ /* responses from ignore buddy */
+ E_IGNOREDUP = 2,
+ E_IGNORENONE = 3,
+ E_IGNORECONF = 12,
+
+ /* conference */
+ E_CONFNOTAVAIL = 20
+};
+
+enum yahoo_log_level {
+ YAHOO_LOG_NONE = 0,
+ YAHOO_LOG_FATAL,
+ YAHOO_LOG_ERR,
+ YAHOO_LOG_WARNING,
+ YAHOO_LOG_NOTICE,
+ YAHOO_LOG_INFO,
+ YAHOO_LOG_DEBUG
+};
+
+/* Yahoo Protocol versions. Thanks to GAIM devs.*/
+//#define YAHOO_WEBMESSENGER_PROTO_VER 0x0065
+#define YAHOO_WEBMESSENGER_PROTO_VER 0x000D
+//#define YAHOO_PROTO_VER 0x000c
+#define YAHOO_PROTO_VER 0x000d
+
+/* Yahoo style/color directives */
+#define YAHOO_COLOR_BLACK "\033[30m"
+#define YAHOO_COLOR_BLUE "\033[31m"
+#define YAHOO_COLOR_LIGHTBLUE "\033[32m"
+#define YAHOO_COLOR_GRAY "\033[33m"
+#define YAHOO_COLOR_GREEN "\033[34m"
+#define YAHOO_COLOR_PINK "\033[35m"
+#define YAHOO_COLOR_PURPLE "\033[36m"
+#define YAHOO_COLOR_ORANGE "\033[37m"
+#define YAHOO_COLOR_RED "\033[38m"
+#define YAHOO_COLOR_OLIVE "\033[39m"
+#define YAHOO_COLOR_ANY "\033[#"
+#define YAHOO_STYLE_ITALICON "\033[2m"
+#define YAHOO_STYLE_ITALICOFF "\033[x2m"
+#define YAHOO_STYLE_BOLDON "\033[1m"
+#define YAHOO_STYLE_BOLDOFF "\033[x1m"
+#define YAHOO_STYLE_UNDERLINEON "\033[4m"
+#define YAHOO_STYLE_UNDERLINEOFF "\033[x4m"
+#define YAHOO_STYLE_URLON "\033[lm"
+#define YAHOO_STYLE_URLOFF "\033[xlm"
+
+enum yahoo_connection_type {
+ YAHOO_CONNECTION_PAGER=0,
+ YAHOO_CONNECTION_FT,
+ YAHOO_CONNECTION_YAB,
+ YAHOO_CONNECTION_WEBCAM_MASTER,
+ YAHOO_CONNECTION_WEBCAM,
+ YAHOO_CONNECTION_CHATCAT,
+ YAHOO_CONNECTION_SEARCH
+};
+
+enum yahoo_webcam_direction_type {
+ YAHOO_WEBCAM_DOWNLOAD=0,
+ YAHOO_WEBCAM_UPLOAD
+};
+
+enum yahoo_stealth_visibility_type {
+ YAHOO_STEALTH_DEFAULT = 0,
+ YAHOO_STEALTH_ONLINE,
+ YAHOO_STEALTH_PERM_OFFLINE
+};
+
+/* chat member attribs */
+#define YAHOO_CHAT_MALE 0x8000
+#define YAHOO_CHAT_FEMALE 0x10000
+#define YAHOO_CHAT_FEMALE 0x10000
+#define YAHOO_CHAT_DUNNO 0x400
+#define YAHOO_CHAT_WEBCAM 0x10
+
+enum yahoo_webcam_conn_type { Y_WCM_DIALUP, Y_WCM_DSL, Y_WCM_T1 };
+
+struct yahoo_webcam {
+ int direction; /* Uploading or downloading */
+ int conn_type; /* 0=Dialup, 1=DSL/Cable, 2=T1/Lan */
+
+ char *user; /* user we are viewing */
+ char *server; /* webcam server to connect to */
+ int port; /* webcam port to connect on */
+ char *key; /* key to connect to the server with */
+ char *description; /* webcam description */
+ char *my_ip; /* own ip number */
+};
+
+struct yahoo_webcam_data {
+ unsigned int data_size;
+ unsigned int to_read;
+ unsigned int timestamp;
+ unsigned char packet_type;
+};
+
+struct yahoo_data {
+ char *user;
+ char *password;
+
+ char *cookie_y;
+ char *cookie_t;
+ char *cookie_c;
+ char *cookie_b;
+ char *login_cookie;
+
+ YList *buddies;
+ YList *ignore;
+ YList *identities;
+ char *login_id;
+
+ int current_status;
+ int initial_status;
+ int logged_in;
+
+ int session_id;
+
+ int client_id;
+ long session_timestamp;
+
+ char *rawbuddylist;
+ char *rawstealthlist;
+ char *ignorelist;
+
+ void *server_settings;
+};
+
+struct yab {
+ char *id;
+ char *fname;
+ char *lname;
+ char *nname;
+ char *email;
+ char *hphone;
+ char *wphone;
+ char *mphone;
+ int dbid;
+};
+
+struct yahoo_buddy {
+ char *group;
+ char *id;
+ char *real_name;
+ struct yab *yab_entry;
+};
+
+enum yahoo_search_type {
+ YAHOO_SEARCH_KEYWORD = 0,
+ YAHOO_SEARCH_YID,
+ YAHOO_SEARCH_NAME
+};
+
+enum yahoo_search_gender {
+ YAHOO_GENDER_NONE = 0,
+ YAHOO_GENDER_MALE,
+ YAHOO_GENDER_FEMALE
+};
+
+enum yahoo_search_agerange {
+ YAHOO_AGERANGE_NONE = 0
+};
+
+struct yahoo_found_contact {
+ char *id;
+ char *gender;
+ char *location;
+ int age;
+ int online;
+};
+
+/*
+ * Function pointer to be passed to http get/post and send file
+ */
+typedef void (*yahoo_get_fd_callback)(int id, int fd, int error, void *data);
+
+/*
+ * Function pointer to be passed to yahoo_get_url_handle
+ */
+typedef void (*yahoo_get_url_handle_callback)(int id, int fd, int error,
+ const char *filename, unsigned long size, void *data);
+
+
+struct yahoo_chat_member {
+ char *id;
+ int age;
+ int attribs;
+ char *alias;
+ char *location;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_debug.h b/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_debug.h
new file mode 100644
index 0000000..7c80725
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_debug.h
@@ -0,0 +1,55 @@
+/*
+ * libyahoo2: yahoo_debug.h
+ *
+ * Copyright (C) 2002-2004, Philip S Tellis <philip.tellis AT gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+extern int yahoo_log_message(char *fmt, ...);
+
+/*
+#define NOTICE(x) if(yahoo_get_log_level() >= YAHOO_LOG_NOTICE) { yahoo_log_message x; yahoo_log_message("\n"); }
+
+#define LOG(x) if(yahoo_get_log_level() >= YAHOO_LOG_INFO) { yahoo_log_message("%s:%d: ", __FILE__, __LINE__); \
+ yahoo_log_message x; \
+ yahoo_log_message("\n"); }
+
+#define WARNING(x) if(yahoo_get_log_level() >= YAHOO_LOG_WARNING) { yahoo_log_message("%s:%d: warning: ", __FILE__, __LINE__); \
+ yahoo_log_message x; \
+ yahoo_log_message("\n"); }
+
+#define DEBUG_MSG(x) if(yahoo_get_log_level() >= YAHOO_LOG_DEBUG) { yahoo_log_message("%s:%d: debug: ", __FILE__, __LINE__); \
+ yahoo_log_message x; \
+ yahoo_log_message("\n"); }
+*/
+#define NOTICE(x) if(yahoo_get_log_level() >= YAHOO_LOG_NOTICE) { yahoo_log_message x; yahoo_log_message(" "); }
+
+#define LOG(x) if(yahoo_get_log_level() >= YAHOO_LOG_INFO) { yahoo_log_message("%s:%d: ", __FILE__, __LINE__); \
+ yahoo_log_message x; \
+ yahoo_log_message(" "); }
+
+#define WARNING(x) if(yahoo_get_log_level() >= YAHOO_LOG_WARNING) { yahoo_log_message("%s:%d: warning: ", __FILE__, __LINE__); \
+ yahoo_log_message x; \
+ yahoo_log_message(" "); }
+
+#define DEBUG_MSG(x) if(yahoo_get_log_level() >= YAHOO_LOG_DEBUG) { yahoo_log_message("%s:%d: debug: ", __FILE__, __LINE__); \
+ yahoo_log_message x; \
+ yahoo_log_message(" "); }
+
+#define DEBUG_MSG1(x) if(yahoo_get_log_level() >= YAHOO_LOG_DEBUG) { \
+ yahoo_log_message x; \
+ yahoo_log_message(" "); }
diff --git a/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_fn.c b/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_fn.c
new file mode 100644
index 0000000..f2db834
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_fn.c
@@ -0,0 +1,4622 @@
+/*
+ * libyahoo2 - originally from gaim patches by Amatus
+ *
+ * Copyright (C) 2003-2004
+ *
+ * Some code copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
+ * libfaim code copyright 1998, 1999 Adam Fritzler <afritz@auk.cx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "yahoo_fn.h"
+
+unsigned char table_0[256] = {
+ 0x5A, 0x41, 0x11, 0x77, 0x29, 0x9C, 0x31, 0xAD,
+ 0x4A, 0x32, 0x1A, 0x6D, 0x56, 0x9F, 0x39, 0xA6,
+ 0x0C, 0xE8, 0x49, 0x40, 0xA4, 0x21, 0xE9, 0x01,
+ 0x91, 0x86, 0x2F, 0xB9, 0xED, 0x80, 0x51, 0xAB,
+ 0x7F, 0x92, 0xF2, 0x73, 0xCD, 0xD9, 0x75, 0x2A,
+ 0x70, 0x34, 0x35, 0x8D, 0xA8, 0x72, 0x7D, 0x9B,
+ 0x2E, 0xC5, 0x2D, 0x76, 0x1E, 0xBB, 0xE7, 0x37,
+ 0xBA, 0xB7, 0xB2, 0x03, 0x20, 0x17, 0x8A, 0x07,
+ 0xD6, 0x96, 0x13, 0x95, 0xE5, 0xF1, 0x18, 0x3B,
+ 0xA5, 0x62, 0x33, 0xC1, 0x44, 0x3D, 0x6C, 0xA7,
+ 0xBF, 0x1C, 0x60, 0xFF, 0x5B, 0xF5, 0x8E, 0xE6,
+ 0x5C, 0xCC, 0xF7, 0x69, 0x15, 0x0F, 0x0B, 0xBD,
+ 0x12, 0x9D, 0xB3, 0x65, 0x53, 0xB1, 0x14, 0xF4,
+ 0x19, 0x3E, 0xB6, 0x45, 0xCB, 0xA2, 0x7A, 0xD3,
+ 0xF8, 0xD1, 0x61, 0xEE, 0xBC, 0xC6, 0xB0, 0x5D,
+ 0x4B, 0x09, 0x26, 0xE1, 0x1D, 0x6E, 0xC3, 0xFB,
+ 0x68, 0x4C, 0x42, 0x52, 0x5F, 0xDE, 0xFD, 0xEF,
+ 0x81, 0x04, 0x6F, 0xE0, 0xF0, 0x1F, 0x0D, 0x7C,
+ 0x58, 0x4F, 0x1B, 0x30, 0xCF, 0x9A, 0x2B, 0x05,
+ 0xF6, 0x3F, 0x78, 0xAC, 0xD8, 0xEC, 0xE2, 0x25,
+ 0x93, 0xDA, 0x84, 0x8C, 0x4E, 0xD5, 0x38, 0x0A,
+ 0x06, 0x7E, 0xD4, 0x59, 0x98, 0xE3, 0x36, 0xC2,
+ 0xD2, 0xA3, 0x10, 0x79, 0xFA, 0xC9, 0x16, 0x27,
+ 0x66, 0x89, 0xFE, 0x57, 0xF3, 0x83, 0xB8, 0x28,
+ 0x3C, 0xC7, 0xCE, 0x71, 0xC8, 0xDB, 0x22, 0xE4,
+ 0xDD, 0xDF, 0x02, 0x8F, 0x5E, 0xEB, 0x48, 0x2C,
+ 0x08, 0xC4, 0x43, 0xEA, 0x50, 0x55, 0x90, 0x54,
+ 0x87, 0xCA, 0x00, 0x24, 0x6B, 0x85, 0x97, 0xD7,
+ 0xDC, 0x6A, 0x67, 0xD0, 0x88, 0xA1, 0x9E, 0xC0,
+ 0x46, 0xAE, 0x64, 0x74, 0x4D, 0xA0, 0x99, 0xB5,
+ 0x0E, 0x8B, 0xAA, 0x3A, 0xB4, 0xFC, 0xA9, 0x94,
+ 0x7B, 0xBE, 0xF9, 0xAF, 0x82, 0x63, 0x47, 0x23 };
+
+unsigned char table_1[256] = {
+ 0x08, 0xCB, 0x54, 0xCF, 0x97, 0x53, 0x59, 0xF1,
+ 0x66, 0xEC, 0xDB, 0x1B, 0xB1, 0xE2, 0x36, 0xEB,
+ 0xB3, 0x8F, 0x71, 0xA8, 0x90, 0x7D, 0xDA, 0xDC,
+ 0x2C, 0x2F, 0xE8, 0x6A, 0x73, 0x37, 0xAE, 0xCC,
+ 0xA1, 0x16, 0xE6, 0xFC, 0x9C, 0xA9, 0x2A, 0x3F,
+ 0x58, 0xFD, 0x56, 0x4C, 0xA5, 0xF2, 0x33, 0x99,
+ 0x1A, 0xB7, 0xFE, 0xA6, 0x1E, 0x32, 0x9E, 0x48,
+ 0x03, 0x4A, 0x78, 0xEE, 0xCA, 0xC3, 0x88, 0x7A,
+ 0xAC, 0x23, 0xAA, 0xBD, 0xDE, 0xD3, 0x67, 0x43,
+ 0xFF, 0x64, 0x8A, 0xF9, 0x04, 0xD0, 0x7B, 0xC2,
+ 0xBC, 0xF3, 0x89, 0x0E, 0xDD, 0xAB, 0x9D, 0x84,
+ 0x5A, 0x62, 0x7F, 0x6D, 0x82, 0x68, 0xA3, 0xED,
+ 0x2E, 0x07, 0x41, 0xEF, 0x2D, 0x70, 0x4F, 0x69,
+ 0x8E, 0xE7, 0x0F, 0x11, 0x19, 0xAF, 0x31, 0xFB,
+ 0x8D, 0x4B, 0x5F, 0x96, 0x75, 0x42, 0x6C, 0x46,
+ 0xE4, 0x55, 0xD6, 0x3B, 0xE1, 0xD1, 0xB0, 0xB5,
+ 0x45, 0x29, 0xC0, 0x94, 0x9F, 0xD4, 0x15, 0x17,
+ 0x3C, 0x47, 0xC8, 0xD9, 0xC6, 0x76, 0xB9, 0x02,
+ 0xE0, 0xC9, 0xB2, 0x01, 0xC1, 0x5D, 0x4E, 0x14,
+ 0xF4, 0xAD, 0xB6, 0x00, 0x72, 0xF0, 0x49, 0x0D,
+ 0xD8, 0x5E, 0x6F, 0x2B, 0x8C, 0x51, 0x83, 0xC5,
+ 0x0A, 0x85, 0xE5, 0x38, 0x7E, 0x26, 0xEA, 0x22,
+ 0x6B, 0x06, 0xD5, 0x8B, 0xBF, 0xC7, 0x35, 0x1D,
+ 0xF6, 0x24, 0x28, 0xCE, 0x9B, 0x77, 0x20, 0x60,
+ 0xF5, 0x87, 0x3D, 0x65, 0x86, 0x0C, 0xDF, 0xBA,
+ 0x12, 0xA4, 0x3A, 0x34, 0xD7, 0xA0, 0xF8, 0x63,
+ 0x52, 0x27, 0xB8, 0x18, 0xA7, 0x13, 0x91, 0x09,
+ 0x93, 0x5C, 0x10, 0x9A, 0xB4, 0xE9, 0x44, 0xC4,
+ 0x21, 0x57, 0x1C, 0x0B, 0xA2, 0x74, 0x4D, 0xBE,
+ 0xD2, 0x1F, 0xCD, 0xE3, 0x6E, 0x7C, 0x40, 0x50,
+ 0x39, 0x80, 0x98, 0xFA, 0x25, 0x92, 0x30, 0x5B,
+ 0x05, 0x95, 0xBB, 0x79, 0x61, 0x3E, 0x81, 0xF7 };
+
+unsigned char table_2[32] = {
+ 0x19, 0x05, 0x09, 0x1C, 0x0B, 0x1A, 0x12, 0x03,
+ 0x06, 0x04, 0x0D, 0x1D, 0x15, 0x0E, 0x1B, 0x18,
+ 0x00, 0x07, 0x08, 0x02, 0x13, 0x1F, 0x0C, 0x1E,
+ 0x16, 0x0A, 0x10, 0x0F, 0x01, 0x14, 0x11, 0x17 };
+
+unsigned char table_3[256] = {
+ 0xBC, 0x1B, 0xCC, 0x1E, 0x5B, 0x59, 0x4F, 0xA8,
+ 0x62, 0xC6, 0xC1, 0xBB, 0x83, 0x2D, 0xA3, 0xA6,
+ 0x5A, 0xDC, 0xE5, 0x93, 0xFB, 0x5C, 0xD6, 0x2A,
+ 0x97, 0xC7, 0x1C, 0x73, 0x08, 0x45, 0xD2, 0x89,
+ 0x4A, 0xD4, 0xCF, 0x0C, 0x1D, 0xD8, 0xCD, 0x26,
+ 0x8F, 0x11, 0x55, 0x8B, 0xD3, 0x53, 0xCE, 0x00,
+ 0xB5, 0x3B, 0x2E, 0x39, 0x88, 0x7B, 0x85, 0x46,
+ 0x54, 0xA5, 0x31, 0x40, 0x3E, 0x0A, 0x4C, 0x68,
+ 0x70, 0x0F, 0xBA, 0x0E, 0x75, 0x8A, 0xEB, 0x44,
+ 0x60, 0x6C, 0x05, 0xC9, 0xF0, 0xDD, 0x0D, 0x66,
+ 0xAB, 0xA1, 0xAD, 0xF2, 0x12, 0x6A, 0xE6, 0x27,
+ 0xF6, 0x9F, 0xDB, 0xB8, 0xF4, 0x56, 0x5E, 0x2C,
+ 0xDA, 0xFE, 0x34, 0x86, 0xF5, 0xC2, 0xB0, 0xF1,
+ 0xCB, 0xF3, 0x78, 0x9B, 0x7F, 0xB4, 0xD7, 0x58,
+ 0x74, 0x07, 0x72, 0x96, 0x02, 0xCA, 0xAC, 0xE8,
+ 0x5D, 0xA7, 0x32, 0xBD, 0x81, 0x43, 0x18, 0xF8,
+ 0x15, 0x0B, 0xE9, 0x76, 0x30, 0xBF, 0x3A, 0x22,
+ 0x9E, 0xD1, 0x79, 0x37, 0xBE, 0x8C, 0x7A, 0x98,
+ 0x21, 0x95, 0x10, 0x8D, 0xDF, 0xC0, 0x69, 0xC8,
+ 0x03, 0x6E, 0x4B, 0x36, 0xFC, 0x6F, 0xA9, 0x48,
+ 0x63, 0xE1, 0xB9, 0x24, 0x87, 0x13, 0xB2, 0xA4,
+ 0x84, 0x06, 0x14, 0x61, 0x3D, 0x92, 0xB1, 0x41,
+ 0xE2, 0x71, 0xAF, 0x16, 0xDE, 0x25, 0x82, 0xD9,
+ 0x2B, 0x33, 0x51, 0xA2, 0x4E, 0x7D, 0x94, 0xFF,
+ 0xFD, 0x5F, 0x80, 0xED, 0x64, 0xE7, 0x50, 0x6D,
+ 0xD0, 0x3C, 0x6B, 0x65, 0x77, 0x17, 0x1A, 0xEC,
+ 0xD5, 0xAA, 0xF9, 0xC4, 0x9C, 0x35, 0xE3, 0x42,
+ 0xE4, 0x19, 0x52, 0x67, 0xB7, 0x9D, 0x28, 0xC5,
+ 0x47, 0x38, 0x91, 0x57, 0xAE, 0x3F, 0x29, 0x9A,
+ 0x2F, 0xF7, 0x90, 0x04, 0xEE, 0xFA, 0x20, 0xB6,
+ 0xEA, 0x49, 0x23, 0x4D, 0xB3, 0x8E, 0xC3, 0x1F,
+ 0x7C, 0xEF, 0xE0, 0x99, 0x09, 0xA0, 0x01, 0x7E };
+
+unsigned char table_4[32] = {
+ 0x1F, 0x0B, 0x00, 0x1E, 0x03, 0x0E, 0x15, 0x01,
+ 0x1A, 0x17, 0x1D, 0x1B, 0x11, 0x0F, 0x0A, 0x12,
+ 0x13, 0x18, 0x02, 0x04, 0x09, 0x06, 0x0D, 0x07,
+ 0x08, 0x05, 0x10, 0x19, 0x0C, 0x14, 0x16, 0x1C };
+
+unsigned char table_5[256] = {
+ 0x9A, 0xAB, 0x61, 0x28, 0x0A, 0x23, 0xFC, 0xBA,
+ 0x90, 0x22, 0xB7, 0x62, 0xD9, 0x09, 0x91, 0xF4,
+ 0x7B, 0x5D, 0x6B, 0x80, 0xAC, 0x9E, 0x21, 0x72,
+ 0x64, 0x2D, 0xFF, 0x66, 0xEB, 0x5B, 0x05, 0xC8,
+ 0x1B, 0xD1, 0x55, 0xF5, 0x97, 0x08, 0xAE, 0xC7,
+ 0x00, 0xDE, 0xE1, 0x78, 0xD8, 0xB6, 0xF0, 0x17,
+ 0xE4, 0x32, 0xCD, 0x76, 0x07, 0x14, 0x7F, 0x7A,
+ 0xBF, 0xB4, 0x1D, 0x94, 0x48, 0x75, 0xFA, 0xA7,
+ 0x99, 0x7E, 0x65, 0x38, 0x29, 0x51, 0xC3, 0x83,
+ 0x7C, 0x0D, 0xA0, 0xCC, 0xF1, 0xDD, 0xE2, 0x49,
+ 0xF8, 0xD2, 0x25, 0x54, 0x9B, 0x0E, 0xB9, 0xFE,
+ 0x67, 0xC4, 0xCE, 0x13, 0xD4, 0xE7, 0xB8, 0x41,
+ 0x77, 0xDB, 0xA6, 0xB0, 0x11, 0x6A, 0x5E, 0x68,
+ 0x8D, 0xF9, 0x36, 0xD3, 0xC2, 0x3A, 0xAA, 0x59,
+ 0x03, 0xE0, 0xE3, 0xF3, 0x42, 0x2C, 0x04, 0x47,
+ 0xE6, 0x93, 0xCB, 0x6E, 0x20, 0xCA, 0x01, 0xA1,
+ 0x40, 0x2B, 0x2F, 0x5F, 0x87, 0xD0, 0xEC, 0x88,
+ 0x27, 0x58, 0xC6, 0x3E, 0xDF, 0x26, 0x5C, 0xE9,
+ 0x1F, 0x0F, 0x95, 0x1C, 0xFB, 0xA5, 0x12, 0x39,
+ 0x1E, 0x3C, 0x33, 0x43, 0x56, 0xE8, 0x82, 0xF7,
+ 0x7D, 0x89, 0xF2, 0xD7, 0x50, 0x92, 0x60, 0x4C,
+ 0x2A, 0x86, 0x16, 0x6C, 0x37, 0xC0, 0xAD, 0xB3,
+ 0x24, 0x45, 0xB1, 0xA2, 0x71, 0xA4, 0xA3, 0xED,
+ 0xC9, 0x5A, 0x4D, 0x84, 0x0C, 0x3F, 0xC5, 0x9D,
+ 0x63, 0x19, 0x79, 0x57, 0x96, 0x30, 0x74, 0xBB,
+ 0xDA, 0x1A, 0x9F, 0x44, 0xC1, 0x98, 0xE5, 0x81,
+ 0xD6, 0x18, 0x8F, 0xFD, 0x8E, 0x06, 0x6F, 0xF6,
+ 0x2E, 0x3B, 0xB5, 0x85, 0x8A, 0x9C, 0x53, 0x4A,
+ 0xA9, 0x52, 0x3D, 0x4E, 0xBE, 0xAF, 0xBC, 0xA8,
+ 0x4F, 0x6D, 0x15, 0x35, 0x8C, 0xBD, 0x34, 0x8B,
+ 0xDC, 0x0B, 0xCF, 0x31, 0xEA, 0xB2, 0x70, 0x4B,
+ 0x46, 0x73, 0x69, 0xD5, 0x10, 0xEE, 0x02, 0xEF };
+
+unsigned char table_6[32] = {
+ 0x1A, 0x1C, 0x0F, 0x0C, 0x00, 0x02, 0x13, 0x09,
+ 0x11, 0x05, 0x0D, 0x12, 0x18, 0x0B, 0x04, 0x10,
+ 0x14, 0x1B, 0x1E, 0x16, 0x07, 0x08, 0x03, 0x17,
+ 0x19, 0x1F, 0x01, 0x0E, 0x15, 0x06, 0x0A, 0x1D };
+
+unsigned char table_7[256] = {
+ 0x52, 0x11, 0x72, 0xD0, 0x76, 0xD7, 0xAE, 0x03,
+ 0x7F, 0x19, 0xF4, 0xB8, 0xB3, 0x5D, 0xCA, 0x2D,
+ 0x5C, 0x30, 0x53, 0x1A, 0x57, 0xF6, 0xAD, 0x83,
+ 0x29, 0x79, 0xD5, 0xF0, 0x0F, 0xC3, 0x8B, 0xD3,
+ 0x8E, 0x37, 0x01, 0xA6, 0xF1, 0x10, 0x04, 0x71,
+ 0xCC, 0xC6, 0xE7, 0xC2, 0x85, 0x94, 0xBD, 0x6F,
+ 0xCB, 0xEA, 0xFC, 0xA1, 0x38, 0x5E, 0x08, 0x2E,
+ 0x35, 0x42, 0x67, 0xD4, 0x56, 0x6D, 0x7C, 0xE5,
+ 0x0E, 0x7D, 0x12, 0x65, 0xF5, 0x33, 0x82, 0xC4,
+ 0x1D, 0xD2, 0x16, 0x58, 0xEC, 0xCD, 0xA8, 0xBF,
+ 0xAB, 0x07, 0x45, 0x55, 0xB7, 0x6A, 0x70, 0xF2,
+ 0xBE, 0x05, 0x6B, 0x9D, 0xEB, 0x13, 0x0D, 0x9F,
+ 0xE8, 0xA7, 0xC8, 0x31, 0x3C, 0xB6, 0x21, 0xC0,
+ 0x20, 0x60, 0x6C, 0xE2, 0xCE, 0x8C, 0xFD, 0x95,
+ 0xE3, 0x4A, 0xB5, 0xB2, 0x40, 0xB1, 0xF3, 0x17,
+ 0xF9, 0x24, 0x06, 0x22, 0x2F, 0x25, 0x93, 0x8A,
+ 0x2A, 0x7E, 0x28, 0x3D, 0x47, 0xF8, 0x89, 0xA5,
+ 0x7B, 0x9B, 0xC5, 0x84, 0x59, 0x46, 0x90, 0x74,
+ 0x69, 0xC7, 0xAA, 0xEE, 0x6E, 0xD6, 0xB0, 0x18,
+ 0x66, 0xA0, 0x7A, 0x1E, 0xFB, 0xDB, 0x4E, 0x51,
+ 0x92, 0xE4, 0xE0, 0x3E, 0xB4, 0xD8, 0x23, 0x3B,
+ 0xC1, 0x5F, 0xFE, 0x98, 0x99, 0x73, 0x09, 0xA9,
+ 0xA3, 0xDF, 0x14, 0x5A, 0x26, 0x8F, 0x0B, 0xAF,
+ 0x4C, 0x97, 0x54, 0xE1, 0x63, 0x48, 0xED, 0xBA,
+ 0xCF, 0xBB, 0x1F, 0xDC, 0xA4, 0xFA, 0x64, 0x75,
+ 0xDE, 0x81, 0x9A, 0xFF, 0x49, 0x41, 0x27, 0x62,
+ 0x02, 0x15, 0xD9, 0x86, 0xAC, 0x3F, 0x0C, 0x61,
+ 0xD1, 0x77, 0x2B, 0x1B, 0x96, 0xDA, 0x68, 0x1C,
+ 0x44, 0x32, 0xBC, 0xA2, 0x87, 0xF7, 0x91, 0x8D,
+ 0x80, 0xDD, 0x0A, 0x50, 0x34, 0x4B, 0x00, 0xB9,
+ 0x36, 0xE6, 0x78, 0x4F, 0xC9, 0xE9, 0x2C, 0x43,
+ 0x88, 0x9E, 0x9C, 0x5B, 0x4D, 0x3A, 0x39, 0xEF };
+
+unsigned char table_8[32] = {
+ 0x13, 0x08, 0x1E, 0x1D, 0x17, 0x16, 0x07, 0x1F,
+ 0x0E, 0x03, 0x1A, 0x19, 0x01, 0x12, 0x11, 0x10,
+ 0x09, 0x0C, 0x0F, 0x14, 0x0B, 0x05, 0x00, 0x04,
+ 0x1C, 0x18, 0x0A, 0x15, 0x02, 0x1B, 0x06, 0x0D };
+
+unsigned char table_9[256] = {
+ 0x20, 0x2A, 0xDA, 0xFE, 0x76, 0x0D, 0xED, 0x39,
+ 0x51, 0x4C, 0x46, 0x9A, 0xF1, 0xB0, 0x10, 0xC7,
+ 0xD1, 0x6F, 0x18, 0x24, 0xB9, 0x7A, 0x4F, 0x47,
+ 0xE0, 0x4E, 0x88, 0x09, 0x8A, 0xBA, 0x60, 0xBD,
+ 0xC2, 0x27, 0x93, 0x7D, 0x94, 0x40, 0xCB, 0x80,
+ 0xB8, 0x41, 0x84, 0x5D, 0xC1, 0x0F, 0x5E, 0x78,
+ 0x2B, 0x48, 0x28, 0x29, 0xEE, 0x81, 0x90, 0x86,
+ 0x50, 0x9C, 0xF3, 0xB2, 0x35, 0x52, 0x0C, 0x9D,
+ 0xFC, 0x69, 0xD6, 0xA6, 0x06, 0xD7, 0xC6, 0xFF,
+ 0x1C, 0x14, 0x57, 0x33, 0xE2, 0x1F, 0x83, 0xA8,
+ 0xF7, 0x99, 0xC5, 0xDC, 0x70, 0x9E, 0xF4, 0x6B,
+ 0x0A, 0x77, 0x95, 0x4A, 0x2E, 0x53, 0xF2, 0x62,
+ 0x98, 0xF8, 0x96, 0xDB, 0xE6, 0x32, 0x3C, 0x58,
+ 0xD5, 0x6D, 0xE7, 0x4B, 0xCE, 0x91, 0x43, 0xD8,
+ 0xFA, 0xE3, 0x4D, 0xD9, 0x68, 0xDE, 0xEC, 0x01,
+ 0x08, 0xD3, 0x8F, 0x19, 0xC4, 0xA7, 0x6E, 0x3E,
+ 0x63, 0x12, 0x72, 0x42, 0x9F, 0xB4, 0x04, 0x1B,
+ 0x7E, 0x11, 0x17, 0x73, 0xB5, 0x22, 0x56, 0xA1,
+ 0x89, 0xDD, 0xF5, 0x3F, 0x49, 0x26, 0x8D, 0x15,
+ 0x85, 0x75, 0x5F, 0x65, 0x82, 0xB6, 0xF6, 0xD2,
+ 0xA4, 0x55, 0x37, 0xC8, 0xA0, 0xCC, 0x66, 0x5C,
+ 0xC9, 0x25, 0x36, 0x67, 0x7C, 0xE1, 0xA3, 0xCF,
+ 0xA9, 0x59, 0x2F, 0xFB, 0xBB, 0x07, 0x87, 0xA2,
+ 0x44, 0x92, 0x13, 0x00, 0x16, 0x61, 0x38, 0xEB,
+ 0xAE, 0xD4, 0x1E, 0x64, 0x6A, 0xE4, 0xCA, 0x1D,
+ 0x6C, 0xDF, 0xAB, 0x5B, 0x03, 0x7B, 0x9B, 0x8C,
+ 0x5A, 0xFD, 0xC3, 0xB3, 0x0B, 0xAA, 0xAC, 0x8B,
+ 0xBE, 0xBC, 0x3D, 0x97, 0xCD, 0x05, 0x21, 0x8E,
+ 0xAD, 0xEA, 0x54, 0x30, 0xAF, 0x02, 0xB1, 0x34,
+ 0x0E, 0xA5, 0x3B, 0x45, 0x1A, 0x23, 0xE8, 0x7F,
+ 0xEF, 0xB7, 0x31, 0xD0, 0xBF, 0x3A, 0x79, 0xE5,
+ 0xF9, 0xF0, 0x2C, 0x74, 0xE9, 0x71, 0xC0, 0x2D };
+
+unsigned char table_10[32] = {
+ 0x1D, 0x12, 0x11, 0x0D, 0x1E, 0x19, 0x16, 0x1B,
+ 0x18, 0x13, 0x07, 0x17, 0x0C, 0x02, 0x00, 0x15,
+ 0x0E, 0x08, 0x05, 0x01, 0x10, 0x06, 0x04, 0x0F,
+ 0x1F, 0x1A, 0x0B, 0x09, 0x0A, 0x14, 0x1C, 0x03 };
+
+unsigned char table_11[256] = {
+ 0x6B, 0x1D, 0xC6, 0x0A, 0xB7, 0xAC, 0xB2, 0x11,
+ 0x29, 0xD3, 0xA2, 0x4D, 0xCB, 0x03, 0xEF, 0xA6,
+ 0xC1, 0x5D, 0x75, 0x48, 0x35, 0x6C, 0xE2, 0x84,
+ 0xAB, 0xAA, 0xD8, 0x2C, 0x0E, 0x95, 0x25, 0x27,
+ 0x7D, 0x0B, 0xD0, 0xFB, 0x14, 0xE5, 0xF2, 0x4E,
+ 0x7F, 0x2A, 0x63, 0x3C, 0xC9, 0xF6, 0xDC, 0x07,
+ 0x26, 0x55, 0xCF, 0x2B, 0xCD, 0xA7, 0x17, 0xD2,
+ 0x9A, 0x7B, 0x93, 0x78, 0x9E, 0xE6, 0x2F, 0x49,
+ 0x1E, 0xFD, 0xF0, 0xFE, 0x7C, 0x33, 0x92, 0xA3,
+ 0xC8, 0xA0, 0xA9, 0xC4, 0xA1, 0x94, 0x6D, 0x44,
+ 0x0C, 0x90, 0x3A, 0x8C, 0x8E, 0x85, 0xAF, 0x40,
+ 0x36, 0xA4, 0xD1, 0xB9, 0x19, 0x6F, 0xF4, 0xBA,
+ 0x1A, 0x73, 0xD9, 0xB5, 0xB4, 0x7A, 0xF9, 0x83,
+ 0x58, 0xAD, 0xCE, 0x60, 0x98, 0xDB, 0x1C, 0x1B,
+ 0x52, 0xB8, 0xF3, 0x96, 0xED, 0xDE, 0xB3, 0xEE,
+ 0x4F, 0xBD, 0x10, 0xD4, 0x43, 0xEA, 0xE7, 0x37,
+ 0x12, 0x3D, 0xA8, 0x22, 0x65, 0xEC, 0x5B, 0x08,
+ 0x9D, 0x0D, 0x5C, 0xB6, 0x8A, 0x79, 0x3F, 0x04,
+ 0xD6, 0x01, 0xE1, 0xBE, 0xDD, 0x50, 0xFA, 0x41,
+ 0x13, 0x91, 0xF7, 0xDA, 0x18, 0xB0, 0x45, 0x81,
+ 0x4C, 0xF5, 0x32, 0x23, 0x56, 0x5A, 0xEB, 0x97,
+ 0x34, 0x00, 0x77, 0x71, 0x4B, 0x70, 0xD5, 0x31,
+ 0x72, 0x05, 0xDF, 0xE8, 0x15, 0x3B, 0x54, 0x16,
+ 0x89, 0xE4, 0xF1, 0xD7, 0x80, 0x82, 0x4A, 0xE3,
+ 0x39, 0x06, 0x47, 0x28, 0xC2, 0x86, 0x87, 0xB1,
+ 0x62, 0x74, 0x53, 0x21, 0x67, 0x38, 0x42, 0xCA,
+ 0x9B, 0xC3, 0x51, 0x99, 0x8B, 0x1F, 0x24, 0x8D,
+ 0xF8, 0x68, 0x3E, 0x59, 0xBB, 0x61, 0x5F, 0xBC,
+ 0x09, 0x6E, 0x8F, 0x0F, 0x2D, 0xC0, 0xE0, 0x46,
+ 0x66, 0x69, 0xA5, 0xE9, 0x30, 0x9C, 0x5E, 0xAE,
+ 0xBF, 0xC7, 0x20, 0x7E, 0x6A, 0xC5, 0x88, 0xFC,
+ 0x64, 0x76, 0xFF, 0x9F, 0x2E, 0x02, 0xCC, 0x57 };
+
+unsigned char table_12[32] = {
+ 0x14, 0x1B, 0x18, 0x00, 0x1F, 0x15, 0x17, 0x07,
+ 0x11, 0x1A, 0x0E, 0x13, 0x12, 0x06, 0x01, 0x03,
+ 0x1C, 0x0C, 0x0B, 0x1D, 0x10, 0x0F, 0x09, 0x19,
+ 0x0D, 0x1E, 0x04, 0x05, 0x08, 0x16, 0x0A, 0x02 };
+
+unsigned char table_13[256] = {
+ 0x37, 0x8A, 0x1B, 0x91, 0xA5, 0x2B, 0x2D, 0x88,
+ 0x8E, 0xFE, 0x0E, 0xD3, 0xF3, 0xE9, 0x7D, 0xD1,
+ 0x24, 0xEA, 0xB1, 0x8B, 0x5C, 0xA4, 0x44, 0x7E,
+ 0x8C, 0x2C, 0x73, 0xD5, 0x50, 0x3E, 0xD7, 0x18,
+ 0xB9, 0xD6, 0xBA, 0x94, 0x0C, 0xFC, 0xCB, 0xB4,
+ 0x0D, 0x63, 0x4C, 0xDE, 0x77, 0x16, 0xFD, 0x81,
+ 0x3C, 0x11, 0x45, 0x36, 0xF6, 0x67, 0x95, 0x6D,
+ 0x6A, 0x1A, 0xA3, 0xC5, 0x92, 0x10, 0x28, 0x84,
+ 0x48, 0xA6, 0x23, 0xE3, 0x4B, 0xE1, 0xF5, 0x19,
+ 0xE0, 0x2E, 0x00, 0x61, 0x74, 0xCC, 0xF7, 0xB0,
+ 0x68, 0xC8, 0x40, 0x6F, 0x59, 0x52, 0x26, 0x99,
+ 0xC9, 0xF9, 0xC4, 0x53, 0x9B, 0xEC, 0x03, 0x17,
+ 0xE2, 0x06, 0x30, 0x7B, 0xBE, 0xCD, 0x1D, 0x3B,
+ 0xD2, 0x5B, 0x65, 0x21, 0x49, 0xB7, 0x79, 0xCF,
+ 0x82, 0x86, 0xC7, 0x62, 0xEE, 0x8D, 0xFF, 0xD4,
+ 0xC3, 0x85, 0xA7, 0xFA, 0xA9, 0x6B, 0xF2, 0x69,
+ 0x9C, 0x38, 0x78, 0xBD, 0x7F, 0xDD, 0xCE, 0xA1,
+ 0x33, 0xC2, 0x43, 0xEB, 0xD8, 0xE6, 0x2A, 0xE4,
+ 0x76, 0x6C, 0xAA, 0x46, 0x05, 0xE7, 0xA0, 0x0A,
+ 0x71, 0x98, 0x41, 0x5F, 0x0F, 0xEF, 0x51, 0xAD,
+ 0xF0, 0xED, 0x96, 0x5A, 0x42, 0x3F, 0xBF, 0x6E,
+ 0xBC, 0x5D, 0xC1, 0x15, 0x70, 0x54, 0x4D, 0x14,
+ 0xB5, 0xCA, 0x27, 0x80, 0x87, 0x39, 0x60, 0x47,
+ 0x9D, 0x2F, 0x56, 0x1F, 0xBB, 0x31, 0xF1, 0xE8,
+ 0xB3, 0x9E, 0x5E, 0x7C, 0xD0, 0xC6, 0xB2, 0x57,
+ 0x83, 0xAC, 0x09, 0x8F, 0xA2, 0x90, 0x13, 0x25,
+ 0x01, 0x08, 0x64, 0xB6, 0x02, 0xDB, 0x55, 0x32,
+ 0xAF, 0x9A, 0xC0, 0x1C, 0x12, 0x29, 0x0B, 0x72,
+ 0x4F, 0xDA, 0xAB, 0x35, 0xF8, 0x22, 0xD9, 0x4E,
+ 0x3D, 0x1E, 0xDC, 0x58, 0x20, 0x34, 0xAE, 0x66,
+ 0x75, 0x93, 0x9F, 0x3A, 0x07, 0xE5, 0x89, 0xDF,
+ 0x97, 0x4A, 0xB8, 0x7A, 0xF4, 0xFB, 0x04, 0xA8 };
+
+unsigned char table_14[32] = {
+ 0x04, 0x14, 0x13, 0x15, 0x1A, 0x1B, 0x0F, 0x16,
+ 0x02, 0x0D, 0x0C, 0x06, 0x10, 0x17, 0x01, 0x0B,
+ 0x1E, 0x08, 0x1C, 0x18, 0x19, 0x0A, 0x1F, 0x05,
+ 0x11, 0x09, 0x1D, 0x07, 0x0E, 0x12, 0x03, 0x00 };
+
+unsigned char table_15[256] = {
+ 0x61, 0x48, 0x58, 0x41, 0x7F, 0x88, 0x43, 0x42,
+ 0xD9, 0x80, 0x81, 0xFE, 0xC6, 0x49, 0xD7, 0x2C,
+ 0xE6, 0x5B, 0xEE, 0xFF, 0x2A, 0x6F, 0xBF, 0x98,
+ 0xD6, 0x20, 0xB9, 0xB1, 0x5D, 0x95, 0x72, 0x1E,
+ 0x82, 0x96, 0xDE, 0xC1, 0x40, 0xD8, 0x70, 0xA3,
+ 0xD1, 0x1F, 0xF0, 0x9F, 0x2D, 0xDC, 0x3F, 0xF9,
+ 0x5E, 0x0D, 0x15, 0x2F, 0x67, 0x31, 0x9D, 0x84,
+ 0x97, 0x0C, 0xF6, 0x79, 0xC2, 0xA7, 0xC0, 0x32,
+ 0xB3, 0xEB, 0xED, 0x71, 0x30, 0xCC, 0x4B, 0xA0,
+ 0xF5, 0xC4, 0xCD, 0x27, 0xFA, 0x11, 0x25, 0xDB,
+ 0x4F, 0xE2, 0x7E, 0xA6, 0xAF, 0x34, 0x69, 0x63,
+ 0x8F, 0x08, 0x1C, 0x85, 0xF1, 0x57, 0x78, 0xC8,
+ 0xA2, 0x83, 0xB5, 0x68, 0xF7, 0x64, 0x45, 0x26,
+ 0x3B, 0x03, 0xAD, 0x3C, 0x50, 0xD5, 0x77, 0xFC,
+ 0xFB, 0x18, 0xC9, 0xD2, 0x9C, 0xBB, 0xBA, 0x76,
+ 0x23, 0x55, 0xD3, 0x5A, 0x01, 0xE9, 0x87, 0x07,
+ 0x19, 0x09, 0x39, 0x8A, 0x91, 0x93, 0x12, 0xDF,
+ 0x22, 0xA8, 0xCF, 0x4E, 0x4D, 0x65, 0xB0, 0x0F,
+ 0x13, 0x53, 0x21, 0x8C, 0xE5, 0xB7, 0x0B, 0x0E,
+ 0x6C, 0x44, 0xCA, 0x7B, 0xC5, 0x6E, 0xCE, 0xE3,
+ 0x14, 0x29, 0xAC, 0x2E, 0xE7, 0x59, 0xE8, 0x0A,
+ 0xEA, 0x66, 0x7C, 0x94, 0x6D, 0x05, 0x9E, 0x9A,
+ 0x2B, 0x38, 0x6A, 0xCB, 0x51, 0xEF, 0x06, 0xDA,
+ 0xFD, 0x47, 0x92, 0x1D, 0xA5, 0x37, 0x33, 0xEC,
+ 0xB4, 0x52, 0x56, 0xC3, 0xF4, 0xF8, 0x8B, 0xD0,
+ 0xA4, 0x5F, 0x28, 0x89, 0x75, 0xC7, 0x04, 0x00,
+ 0xE4, 0x86, 0x36, 0x3A, 0x99, 0x16, 0x7D, 0xE0,
+ 0x7A, 0x4C, 0x54, 0x46, 0x73, 0xB2, 0xF3, 0xE1,
+ 0x62, 0xBE, 0x90, 0x4A, 0x24, 0x6B, 0x3E, 0xAA,
+ 0x1B, 0xF2, 0x60, 0xD4, 0xA9, 0x9B, 0x1A, 0xB8,
+ 0xA1, 0x35, 0xAE, 0xB6, 0x10, 0x5C, 0x17, 0xBC,
+ 0xAB, 0x8D, 0x02, 0x74, 0xBD, 0x3D, 0x8E, 0xDD };
+
+unsigned char table_16[256] = {
+ 0x3F, 0x9C, 0x17, 0xC1, 0x59, 0xC6, 0x23, 0x93,
+ 0x4B, 0xDF, 0xCB, 0x55, 0x2B, 0xDE, 0xCD, 0xAD,
+ 0xB3, 0xE7, 0x42, 0x2F, 0x02, 0x5A, 0x7B, 0x5C,
+ 0x8F, 0xD1, 0x11, 0xCE, 0xEC, 0xF6, 0xA4, 0xE6,
+ 0x58, 0x98, 0x6A, 0x99, 0xFB, 0x9B, 0x53, 0x21,
+ 0x8A, 0x09, 0x2E, 0x3C, 0x22, 0x38, 0xAC, 0x07,
+ 0x91, 0x46, 0xA9, 0x95, 0xC3, 0x14, 0x84, 0xDB,
+ 0x36, 0x68, 0x1D, 0xDD, 0xF9, 0x12, 0xE0, 0x3D,
+ 0x8D, 0x4D, 0x05, 0x86, 0x69, 0xC0, 0xD3, 0xD5,
+ 0xA5, 0xC9, 0xE5, 0x67, 0x6D, 0xE2, 0x7F, 0xFE,
+ 0xB2, 0x0F, 0x62, 0xCF, 0x37, 0x35, 0xF3, 0x28,
+ 0x16, 0xA6, 0x50, 0x76, 0x80, 0x00, 0x31, 0x97,
+ 0x39, 0x7C, 0x25, 0x0C, 0x64, 0xF2, 0x52, 0x1A,
+ 0x92, 0x4F, 0x2A, 0x56, 0x03, 0x4C, 0xBD, 0x10,
+ 0xB7, 0x2C, 0x8C, 0xAE, 0x73, 0xB9, 0xE9, 0xF7,
+ 0xA7, 0xE1, 0x75, 0xBC, 0xC5, 0x1C, 0x3A, 0x63,
+ 0x7A, 0x4A, 0x29, 0xD2, 0x71, 0xE8, 0x08, 0xA1,
+ 0xD4, 0xFD, 0x13, 0xFA, 0xA0, 0x27, 0x41, 0x72,
+ 0x82, 0x18, 0x51, 0x60, 0x5E, 0x66, 0x0D, 0xAA,
+ 0xD8, 0x1F, 0xAF, 0x45, 0xD0, 0xF1, 0x9F, 0x6B,
+ 0xE4, 0x44, 0x89, 0xEE, 0xC4, 0x0B, 0x6C, 0xCC,
+ 0x83, 0x77, 0xA2, 0x87, 0x0A, 0xA8, 0xED, 0x90,
+ 0x74, 0x6E, 0xF5, 0xAB, 0xA3, 0xB6, 0x5F, 0x0E,
+ 0x04, 0x9A, 0xB4, 0x8E, 0xF0, 0xFF, 0x88, 0xB5,
+ 0xF8, 0xBF, 0x8B, 0x6F, 0x4E, 0x79, 0x40, 0xCA,
+ 0x24, 0x26, 0xDC, 0x33, 0xEB, 0x2D, 0x5B, 0x1B,
+ 0x9D, 0xC7, 0x49, 0x48, 0x54, 0x85, 0xEF, 0xD7,
+ 0xC2, 0xB8, 0xC8, 0x5D, 0xD9, 0x3B, 0x15, 0xBB,
+ 0x65, 0xE3, 0xD6, 0x30, 0x3E, 0x1E, 0x32, 0x9E,
+ 0x57, 0x81, 0x34, 0x06, 0xFC, 0xBA, 0x7D, 0x20,
+ 0x70, 0xDA, 0x7E, 0x47, 0x94, 0x61, 0xB0, 0x78,
+ 0xF4, 0xBE, 0xEA, 0x19, 0x43, 0x01, 0xB1, 0x96 };
+
+unsigned char table_17[256] = {
+ 0x7E, 0xF1, 0xD3, 0x75, 0x87, 0xA6, 0xED, 0x9E,
+ 0xA9, 0xD5, 0xC6, 0xBF, 0xE6, 0x6A, 0xEE, 0x4B,
+ 0x34, 0xDF, 0x4C, 0x7D, 0xDD, 0xFE, 0x3F, 0xAF,
+ 0x66, 0x2D, 0x74, 0x6F, 0xFC, 0x4F, 0x5F, 0x88,
+ 0x29, 0x7B, 0xC7, 0x2A, 0x70, 0xE8, 0x1D, 0xDE,
+ 0xD0, 0x55, 0x71, 0x81, 0xC4, 0x0D, 0x50, 0x4E,
+ 0x58, 0x00, 0x96, 0x97, 0xBB, 0xD7, 0x53, 0x15,
+ 0x6C, 0x40, 0x17, 0xC9, 0xFF, 0x8F, 0x94, 0xFB,
+ 0x19, 0x9A, 0x3E, 0xB5, 0x5A, 0x5E, 0x86, 0x24,
+ 0xB8, 0x77, 0xBA, 0x85, 0x51, 0x18, 0xBE, 0x59,
+ 0x79, 0xF3, 0xD4, 0xC3, 0xAB, 0x28, 0xFD, 0x25,
+ 0x41, 0x91, 0x07, 0x8D, 0xAE, 0x49, 0xF5, 0x80,
+ 0x35, 0xA1, 0x9C, 0x3C, 0xE2, 0x65, 0xB3, 0xE0,
+ 0x16, 0xCB, 0x12, 0x6B, 0xF7, 0xB1, 0x93, 0x8A,
+ 0xCE, 0x54, 0x4D, 0xF8, 0x13, 0xA2, 0x95, 0x46,
+ 0xEA, 0x61, 0x57, 0x9D, 0x27, 0x8B, 0x3D, 0x60,
+ 0x36, 0x68, 0x06, 0x56, 0xB6, 0x1B, 0xD2, 0x89,
+ 0x10, 0xA7, 0xC5, 0x1A, 0x0B, 0x2C, 0xBD, 0x14,
+ 0x0A, 0xDC, 0x23, 0xA8, 0xE1, 0x04, 0x02, 0xC0,
+ 0xB2, 0x9B, 0xE3, 0x2E, 0x33, 0x7C, 0x32, 0xAC,
+ 0x7A, 0x39, 0xB0, 0xF9, 0x98, 0x5B, 0x3A, 0x48,
+ 0x21, 0x90, 0xB9, 0x20, 0xF0, 0xA0, 0x09, 0x1F,
+ 0x2F, 0xEF, 0xEB, 0x22, 0x78, 0x82, 0x37, 0xD6,
+ 0xD1, 0x84, 0x76, 0x01, 0xDB, 0x43, 0xC2, 0xB7,
+ 0x7F, 0xA4, 0xE5, 0xC1, 0x1C, 0x69, 0x05, 0xEC,
+ 0xD8, 0x38, 0x67, 0x42, 0x72, 0xBC, 0x73, 0xAD,
+ 0xA3, 0xE9, 0x4A, 0x8E, 0x47, 0x1E, 0xC8, 0x6E,
+ 0xDA, 0x5D, 0x2B, 0xF6, 0x30, 0x63, 0xCC, 0xF4,
+ 0xCD, 0x8C, 0x0F, 0x3B, 0xE7, 0xD9, 0xCF, 0xB4,
+ 0x03, 0x92, 0x0E, 0x31, 0xE4, 0x08, 0xF2, 0x45,
+ 0xCA, 0x83, 0x26, 0x5C, 0xA5, 0x44, 0x64, 0x6D,
+ 0x9F, 0x99, 0x62, 0xAA, 0xFA, 0x11, 0x0C, 0x52 };
+
+unsigned char table_18[256] = {
+ 0x0F, 0x42, 0x3D, 0x86, 0x3E, 0x66, 0xFE, 0x5C,
+ 0x52, 0xE2, 0xA3, 0xB3, 0xCE, 0x16, 0xCC, 0x95,
+ 0xB0, 0x8B, 0x82, 0x3B, 0x93, 0x7D, 0x62, 0x08,
+ 0x1C, 0x6E, 0xBB, 0xCB, 0x1D, 0x88, 0x69, 0xD4,
+ 0xC9, 0x40, 0x1F, 0xBE, 0x27, 0xBC, 0xDB, 0x38,
+ 0xE5, 0xA1, 0x71, 0xBA, 0x8A, 0x5E, 0xFD, 0x36,
+ 0x8F, 0x26, 0x6B, 0xE4, 0x20, 0x6D, 0xC5, 0xDE,
+ 0xE0, 0x83, 0x7C, 0xD5, 0xD9, 0x4D, 0xDC, 0xE3,
+ 0x0D, 0x32, 0xED, 0x0E, 0x2F, 0x21, 0xA7, 0x79,
+ 0xA0, 0xD3, 0x8C, 0x14, 0x6F, 0xB7, 0xF8, 0x85,
+ 0x5D, 0x37, 0x24, 0xD6, 0x25, 0xD2, 0x8E, 0xA5,
+ 0xB8, 0xCD, 0x5A, 0x9F, 0x05, 0xAD, 0x65, 0x9E,
+ 0x4F, 0x5B, 0x56, 0xF0, 0xAA, 0xC2, 0x28, 0xA8,
+ 0x6A, 0x01, 0x99, 0x2E, 0xA6, 0x77, 0x74, 0x64,
+ 0x76, 0x15, 0x90, 0x75, 0xAF, 0xE8, 0x39, 0x48,
+ 0x09, 0x11, 0xE1, 0x2D, 0xEC, 0xB5, 0x7A, 0xB1,
+ 0x94, 0x13, 0x41, 0x4C, 0x02, 0xA9, 0x97, 0xDF,
+ 0xC3, 0x8D, 0xEA, 0x3A, 0x9C, 0xD1, 0xA2, 0x9A,
+ 0xD7, 0x59, 0xD8, 0x18, 0xDA, 0x47, 0x89, 0x81,
+ 0xC7, 0xF5, 0xFC, 0x98, 0xCA, 0x91, 0x06, 0x68,
+ 0xC8, 0x07, 0x4A, 0x84, 0x0A, 0xE7, 0x33, 0x2C,
+ 0xEB, 0xDD, 0x5F, 0xAC, 0x23, 0x1A, 0x35, 0x70,
+ 0x43, 0x80, 0x61, 0xAE, 0xC1, 0xD0, 0x7B, 0x92,
+ 0x49, 0x51, 0x53, 0xC4, 0x34, 0x30, 0x0C, 0x4B,
+ 0x00, 0x04, 0x10, 0xFF, 0x63, 0x44, 0xB4, 0x0B,
+ 0x57, 0x72, 0xF1, 0x9D, 0x19, 0xF6, 0xB2, 0x87,
+ 0x1B, 0xEE, 0x46, 0x2A, 0xF3, 0xBF, 0x12, 0x96,
+ 0x58, 0x2B, 0xF9, 0xB6, 0xCF, 0x22, 0x3C, 0xAB,
+ 0x1E, 0x6C, 0x31, 0xC6, 0xF7, 0x78, 0x45, 0x17,
+ 0xE9, 0x7E, 0x73, 0xF2, 0x55, 0xFB, 0x3F, 0x9B,
+ 0xF4, 0xBD, 0xA4, 0x29, 0x60, 0x03, 0xB9, 0x50,
+ 0xFA, 0x4E, 0xEF, 0x54, 0xE6, 0x7F, 0xC0, 0x67 };
+
+unsigned char table_19[256] = {
+ 0xEA, 0xE7, 0x13, 0x14, 0xB9, 0xC0, 0xC4, 0x42,
+ 0x49, 0x6E, 0x2A, 0xA6, 0x65, 0x3C, 0x6A, 0x40,
+ 0x07, 0xCD, 0x4F, 0xFE, 0xF2, 0x2D, 0xC8, 0x30,
+ 0x9D, 0xBE, 0x1B, 0x9B, 0x4A, 0x7E, 0x9F, 0xA7,
+ 0x78, 0xAB, 0x4D, 0x1D, 0xF1, 0x96, 0x32, 0x84,
+ 0xFB, 0x80, 0x88, 0xE8, 0x41, 0x97, 0xDC, 0xD0,
+ 0x4E, 0x33, 0xA4, 0x3B, 0xE0, 0xDD, 0x36, 0xC9,
+ 0x72, 0x48, 0x8A, 0x2F, 0x35, 0xF0, 0xDF, 0x21,
+ 0xE1, 0xE5, 0x6C, 0x9A, 0x60, 0x8F, 0xB7, 0x24,
+ 0xE4, 0x9E, 0x8C, 0x0F, 0x3D, 0x28, 0xBB, 0xD6,
+ 0x69, 0xA0, 0x66, 0xC7, 0xE3, 0xD8, 0x11, 0x27,
+ 0xD9, 0x37, 0xF4, 0xF5, 0x8E, 0xD4, 0x76, 0xE2,
+ 0xDB, 0x15, 0xA2, 0x5C, 0x9C, 0xEE, 0x44, 0xED,
+ 0x2B, 0xB3, 0x75, 0x74, 0x71, 0x8B, 0x3A, 0x91,
+ 0x06, 0x19, 0xC1, 0x57, 0x89, 0xCC, 0x82, 0x10,
+ 0x17, 0xB2, 0x08, 0x70, 0x39, 0xCA, 0xBA, 0xB5,
+ 0xAA, 0xBF, 0x02, 0xBD, 0x26, 0x58, 0x04, 0x54,
+ 0x23, 0x4B, 0x90, 0x51, 0x6D, 0x98, 0xD5, 0xB0,
+ 0xAF, 0x22, 0xDA, 0xB4, 0x87, 0xFC, 0x7D, 0x18,
+ 0x6F, 0x64, 0x59, 0x09, 0x0C, 0xA5, 0x5D, 0x03,
+ 0x0A, 0xD3, 0xCE, 0x99, 0x8D, 0xC2, 0xC3, 0x62,
+ 0xD2, 0x83, 0x1A, 0xAC, 0x7C, 0x93, 0xD7, 0xA9,
+ 0x16, 0xF7, 0x77, 0xE6, 0x3E, 0x05, 0x73, 0x55,
+ 0x43, 0x95, 0x7A, 0x6B, 0x38, 0x67, 0x3F, 0xC6,
+ 0xAD, 0x0E, 0x29, 0x46, 0x45, 0xFA, 0xBC, 0xEC,
+ 0x5B, 0x7F, 0x0B, 0x1C, 0x01, 0x12, 0x85, 0x50,
+ 0xF9, 0xEF, 0x25, 0x34, 0x79, 0x2E, 0xEB, 0x00,
+ 0x5F, 0x86, 0xF8, 0x4C, 0xA8, 0x56, 0xB6, 0x5A,
+ 0xF3, 0x31, 0x94, 0x92, 0xB1, 0xB8, 0x52, 0xD1,
+ 0xCF, 0xCB, 0xA1, 0x81, 0x68, 0x47, 0xFF, 0xC5,
+ 0xFD, 0x1F, 0xDE, 0x53, 0xA3, 0x2C, 0x20, 0xF6,
+ 0x1E, 0x0D, 0xAE, 0x7B, 0x5E, 0x61, 0xE9, 0x63 };
+
+unsigned char table_20[32] = {
+ 0x0D, 0x0B, 0x11, 0x02, 0x05, 0x1B, 0x08, 0x1D,
+ 0x04, 0x14, 0x01, 0x09, 0x00, 0x19, 0x1E, 0x15,
+ 0x1F, 0x0A, 0x0F, 0x1C, 0x10, 0x16, 0x0C, 0x07,
+ 0x13, 0x1A, 0x06, 0x17, 0x0E, 0x12, 0x18, 0x03 };
+
+unsigned char table_21[256] = {
+ 0x4C, 0x94, 0xAD, 0x66, 0x9E, 0x69, 0x04, 0xA8,
+ 0x61, 0xE0, 0xE1, 0x3D, 0xFD, 0x9C, 0xFB, 0x19,
+ 0x1E, 0x80, 0x8C, 0xA0, 0xFC, 0x27, 0x26, 0x3B,
+ 0x48, 0x6D, 0x07, 0xE4, 0xEA, 0x17, 0x64, 0x9B,
+ 0xD0, 0xE2, 0xD1, 0x13, 0x39, 0xF5, 0x73, 0xD3,
+ 0x0C, 0x3A, 0x6E, 0x77, 0xFA, 0xE3, 0x2F, 0x44,
+ 0x7E, 0x72, 0x30, 0x43, 0xD4, 0x7F, 0x36, 0xD9,
+ 0xBD, 0x3E, 0x3F, 0x91, 0xBE, 0x54, 0x79, 0xA6,
+ 0x7C, 0x0E, 0xC5, 0x7A, 0x70, 0xC4, 0xD7, 0xCE,
+ 0xDA, 0xAA, 0x68, 0x8F, 0xBC, 0x96, 0x1B, 0x16,
+ 0xA2, 0xC6, 0x67, 0x09, 0x45, 0x9F, 0xCF, 0x41,
+ 0xC8, 0x60, 0x74, 0x99, 0x5D, 0x85, 0x5F, 0x50,
+ 0x33, 0x52, 0x22, 0xA9, 0xB5, 0x2D, 0x98, 0x87,
+ 0x15, 0x9A, 0xAC, 0x2C, 0xDE, 0xC0, 0xB8, 0x37,
+ 0x88, 0x1F, 0xC1, 0x4F, 0x65, 0x0F, 0x3C, 0x84,
+ 0x4B, 0x1A, 0xAB, 0xA4, 0x23, 0xCB, 0xB1, 0xC7,
+ 0xDB, 0xEF, 0x40, 0x0D, 0x46, 0xE8, 0xF4, 0x71,
+ 0x38, 0x01, 0x5C, 0x0B, 0x5E, 0xC9, 0xAF, 0xC3,
+ 0xF6, 0xB6, 0x10, 0x1D, 0xE5, 0x8A, 0x90, 0xA7,
+ 0xA3, 0x05, 0x4E, 0x14, 0x63, 0x25, 0x34, 0xEC,
+ 0x6B, 0x95, 0x21, 0x55, 0xF2, 0xF0, 0x47, 0x9D,
+ 0xF8, 0x8E, 0x02, 0x0A, 0xED, 0x97, 0xAE, 0x00,
+ 0x2A, 0xEB, 0xB2, 0xA5, 0x32, 0x06, 0x2E, 0xFE,
+ 0x8D, 0x7B, 0x7D, 0x35, 0x5A, 0xD2, 0xF1, 0xE9,
+ 0xF9, 0x62, 0xB7, 0xB9, 0x53, 0x75, 0x5B, 0x8B,
+ 0xCC, 0x6C, 0x18, 0x49, 0x89, 0x31, 0xB0, 0x92,
+ 0x6F, 0xDF, 0x03, 0x57, 0xF3, 0x58, 0xCA, 0x2B,
+ 0x93, 0xA1, 0xD6, 0x24, 0x29, 0xCD, 0x59, 0x1C,
+ 0x83, 0xB3, 0x42, 0xBF, 0x82, 0xB4, 0x11, 0x4A,
+ 0x08, 0xEE, 0x76, 0x4D, 0x12, 0xDC, 0xE6, 0xC2,
+ 0x56, 0xBA, 0x86, 0x28, 0x6A, 0x20, 0x51, 0xF7,
+ 0xFF, 0xD8, 0xE7, 0xDD, 0xBB, 0x78, 0xD5, 0x81 };
+
+unsigned char table_22[32] = {
+ 0x0B, 0x15, 0x1C, 0x0C, 0x06, 0x0A, 0x1D, 0x16,
+ 0x12, 0x0E, 0x04, 0x11, 0x1F, 0x0F, 0x07, 0x02,
+ 0x17, 0x13, 0x19, 0x18, 0x0D, 0x10, 0x1A, 0x05,
+ 0x03, 0x00, 0x01, 0x08, 0x09, 0x14, 0x1B, 0x1E };
+
+unsigned char table_23[256] = {
+ 0x36, 0x53, 0x2D, 0xD0, 0x7A, 0xF0, 0xD5, 0x1C,
+ 0x50, 0x61, 0x9A, 0x90, 0x0B, 0x29, 0x20, 0x77,
+ 0xF1, 0x82, 0xFE, 0xC1, 0xA7, 0xB6, 0x78, 0x87,
+ 0x02, 0x05, 0xCB, 0x28, 0xAE, 0xD6, 0x17, 0x1A,
+ 0x91, 0x5D, 0xB9, 0xE2, 0xDE, 0x6A, 0x4E, 0x07,
+ 0xAC, 0x38, 0x13, 0x3B, 0x46, 0xFD, 0xB7, 0xD1,
+ 0x79, 0xFB, 0x58, 0x76, 0x08, 0x47, 0x95, 0xA6,
+ 0x99, 0x9E, 0x12, 0x67, 0xC2, 0xED, 0x9C, 0x1B,
+ 0x89, 0x71, 0xB5, 0x4A, 0xAA, 0x5F, 0x34, 0x85,
+ 0x40, 0x2B, 0x9F, 0x37, 0x7C, 0x0F, 0xD4, 0x75,
+ 0x48, 0x27, 0x2E, 0xC9, 0xEB, 0x06, 0xDF, 0x8C,
+ 0x14, 0xAF, 0xEE, 0xA2, 0x74, 0x45, 0x8D, 0x70,
+ 0x6B, 0xD7, 0x56, 0xCF, 0xBC, 0x7B, 0x01, 0xC8,
+ 0x54, 0xB0, 0x3C, 0x39, 0xFA, 0x81, 0xDC, 0xBB,
+ 0x0D, 0xB2, 0xAD, 0x93, 0xC7, 0x8A, 0x73, 0x6C,
+ 0xC3, 0x04, 0x2F, 0xEF, 0x52, 0x33, 0x9D, 0x1E,
+ 0xC5, 0x65, 0x23, 0xD8, 0xB1, 0xD2, 0xE5, 0x25,
+ 0x2C, 0xE6, 0x92, 0xB4, 0xF7, 0xF4, 0x8F, 0x6E,
+ 0xE8, 0x5A, 0x8E, 0x7D, 0x4C, 0xB3, 0xFF, 0x41,
+ 0x26, 0xE3, 0x30, 0x69, 0xF8, 0x80, 0x57, 0x4F,
+ 0xA0, 0x7F, 0x66, 0x68, 0xE1, 0x7E, 0x0E, 0x31,
+ 0xE7, 0xEA, 0x3E, 0x8B, 0x4B, 0x94, 0xE9, 0xCD,
+ 0x19, 0x35, 0xA3, 0x98, 0xD9, 0x5B, 0x44, 0x2A,
+ 0xE0, 0x6D, 0xF3, 0xE4, 0x72, 0x18, 0x03, 0x59,
+ 0x84, 0x09, 0xA1, 0x9B, 0xBD, 0xDA, 0x4D, 0x63,
+ 0xCC, 0x3A, 0x10, 0xFC, 0x3F, 0x0A, 0x88, 0x24,
+ 0xF5, 0x21, 0xC4, 0x6F, 0x1F, 0x42, 0x62, 0x64,
+ 0x51, 0xDD, 0xCA, 0xF9, 0x22, 0xCE, 0xA8, 0x86,
+ 0xBA, 0xB8, 0x5C, 0xAB, 0x32, 0x00, 0x0C, 0xF2,
+ 0x83, 0xDB, 0xF6, 0x60, 0x3D, 0x16, 0xEC, 0x11,
+ 0xA4, 0xBE, 0x96, 0x5E, 0x97, 0xD3, 0xA5, 0x55,
+ 0x1D, 0x15, 0xC6, 0xBF, 0xA9, 0x43, 0xC0, 0x49 };
+
+unsigned char table_24[256] = {
+ 0xDC, 0x5A, 0xE6, 0x59, 0x64, 0xDA, 0x58, 0x40,
+ 0x95, 0xF8, 0x2A, 0xE0, 0x39, 0x7E, 0x32, 0x89,
+ 0x09, 0x93, 0xED, 0x55, 0xC3, 0x5B, 0x1A, 0xD1,
+ 0xA5, 0x8B, 0x0F, 0x13, 0xC9, 0xE1, 0x34, 0xD0,
+ 0xB6, 0xA2, 0xD9, 0x52, 0x57, 0x83, 0xFD, 0xE9,
+ 0xAC, 0x73, 0x6E, 0x21, 0xF1, 0x0E, 0x25, 0xCC,
+ 0x36, 0xFB, 0xF7, 0x92, 0x15, 0x30, 0x54, 0x91,
+ 0xD6, 0x9E, 0xAA, 0x35, 0x70, 0xB2, 0xC0, 0x27,
+ 0xFE, 0x04, 0xBC, 0xC7, 0x02, 0xFA, 0x7D, 0xE3,
+ 0xBE, 0x62, 0x79, 0x2B, 0x31, 0x6A, 0x8F, 0x7F,
+ 0x56, 0xF0, 0xB4, 0x0C, 0x1F, 0x68, 0xB7, 0xB9,
+ 0x0B, 0x14, 0x3E, 0xA9, 0x4B, 0x03, 0x10, 0xEE,
+ 0x2C, 0xAB, 0x8A, 0x77, 0xB1, 0xE7, 0xCA, 0xD4,
+ 0x98, 0x01, 0xAD, 0x1E, 0x50, 0x26, 0x82, 0x44,
+ 0xF3, 0xBF, 0xD3, 0x6B, 0x33, 0x0A, 0x3C, 0x5D,
+ 0xCE, 0x81, 0xC5, 0x78, 0x9F, 0xB8, 0x23, 0xDB,
+ 0x4E, 0xA1, 0x41, 0x76, 0xAE, 0x51, 0x86, 0x06,
+ 0x7A, 0x66, 0xA0, 0x5E, 0x29, 0x17, 0x84, 0x4A,
+ 0xB0, 0x3B, 0x3D, 0x71, 0x07, 0x7B, 0x0D, 0x9A,
+ 0x6F, 0x9B, 0x5C, 0x88, 0xB3, 0xD7, 0x24, 0xD5,
+ 0x48, 0xF5, 0xE8, 0xE4, 0xCF, 0x16, 0xA4, 0xC8,
+ 0xEF, 0x42, 0x22, 0xEC, 0x47, 0x69, 0x90, 0x63,
+ 0xE2, 0x1B, 0x87, 0x85, 0x3F, 0xDE, 0x8C, 0x60,
+ 0x99, 0xE5, 0x8E, 0x4F, 0xF4, 0xBA, 0xB5, 0x9C,
+ 0x37, 0x67, 0xBD, 0xA6, 0x97, 0xDD, 0xCB, 0x43,
+ 0x45, 0x19, 0x49, 0x1C, 0x75, 0xC1, 0xBB, 0xF2,
+ 0x46, 0xFC, 0x53, 0x9D, 0xD8, 0xA3, 0xDF, 0x2F,
+ 0xEB, 0x72, 0x94, 0xA8, 0x6D, 0xC6, 0x28, 0x4C,
+ 0x00, 0x38, 0xC2, 0x65, 0x05, 0x2E, 0xD2, 0x12,
+ 0xFF, 0x18, 0x61, 0x6C, 0x7C, 0x11, 0xAF, 0x96,
+ 0xCD, 0x20, 0x74, 0x08, 0x1D, 0xC4, 0xF9, 0x4D,
+ 0xEA, 0x8D, 0x2D, 0x5F, 0xF6, 0xA7, 0x80, 0x3A };
+
+unsigned char table_25[32] = {
+ 0x0A, 0x11, 0x17, 0x03, 0x05, 0x0B, 0x18, 0x13,
+ 0x09, 0x02, 0x00, 0x1C, 0x0C, 0x08, 0x1B, 0x14,
+ 0x06, 0x0E, 0x01, 0x0D, 0x16, 0x1E, 0x1D, 0x19,
+ 0x0F, 0x1A, 0x10, 0x04, 0x12, 0x15, 0x07, 0x1F };
+
+unsigned char table_26[32] = {
+ 0x19, 0x13, 0x1B, 0x01, 0x1C, 0x0D, 0x0C, 0x15,
+ 0x0B, 0x00, 0x1A, 0x0F, 0x12, 0x16, 0x08, 0x0A,
+ 0x03, 0x06, 0x14, 0x10, 0x18, 0x04, 0x11, 0x1D,
+ 0x1F, 0x07, 0x17, 0x05, 0x02, 0x0E, 0x1E, 0x09 };
+
+unsigned char table_27[256] = {
+ 0x72, 0xF0, 0x14, 0xCB, 0x61, 0xA5, 0xB2, 0x02,
+ 0x75, 0x22, 0xC3, 0x9D, 0x5A, 0x63, 0xFA, 0x5F,
+ 0xD9, 0x55, 0x58, 0x43, 0x24, 0x7D, 0x77, 0x93,
+ 0xBA, 0x50, 0x1D, 0xF7, 0x49, 0x18, 0xB0, 0x42,
+ 0xBB, 0xEC, 0x52, 0x38, 0xDC, 0xC8, 0x16, 0x54,
+ 0x17, 0x19, 0x89, 0x67, 0x33, 0x3C, 0x0A, 0xAD,
+ 0xC9, 0xDE, 0x81, 0xED, 0xBD, 0x0E, 0x0B, 0x6D,
+ 0x46, 0x30, 0x35, 0x2B, 0x8C, 0xA0, 0x1C, 0x0D,
+ 0xFD, 0xA1, 0x70, 0xC6, 0xD8, 0x41, 0xB3, 0xC0,
+ 0x44, 0xEB, 0x92, 0xBE, 0x6B, 0x98, 0x1A, 0x76,
+ 0x71, 0xC5, 0x51, 0x56, 0x80, 0xFC, 0x01, 0x53,
+ 0x4B, 0xD0, 0x8B, 0xD2, 0x7B, 0xE7, 0x15, 0x5D,
+ 0xE5, 0xA6, 0x8A, 0xD3, 0x9B, 0xF4, 0x69, 0x23,
+ 0xE8, 0xB6, 0xC7, 0xE2, 0x73, 0x9F, 0x88, 0xDF,
+ 0xB4, 0x28, 0xEE, 0xC2, 0x94, 0xB8, 0xF9, 0x7F,
+ 0x4A, 0x57, 0x06, 0xF6, 0xBF, 0xC1, 0xAB, 0xFB,
+ 0xA4, 0x8E, 0xD1, 0xD7, 0xF5, 0x7C, 0xA3, 0x1E,
+ 0x3B, 0x32, 0x03, 0xAA, 0x90, 0x5C, 0x48, 0xE0,
+ 0xE3, 0xCF, 0xD4, 0xEF, 0x59, 0xD5, 0x1B, 0x34,
+ 0x1F, 0x95, 0xCE, 0x7A, 0x20, 0x26, 0x87, 0xB7,
+ 0x78, 0x9C, 0x4F, 0xA2, 0x12, 0x97, 0x27, 0x3F,
+ 0xFF, 0x07, 0x84, 0x96, 0x04, 0xAF, 0xA8, 0xEA,
+ 0x2C, 0x6C, 0xAE, 0x37, 0x91, 0xA9, 0x10, 0xDB,
+ 0xCD, 0xDA, 0x08, 0x99, 0xF1, 0x4D, 0xCC, 0x68,
+ 0x79, 0x2E, 0xB1, 0x39, 0x9E, 0xE9, 0x2F, 0x6A,
+ 0x3D, 0x0F, 0x85, 0x8D, 0xCA, 0x29, 0x86, 0xD6,
+ 0xDD, 0x05, 0x25, 0x3A, 0x40, 0x21, 0x45, 0xAC,
+ 0x11, 0xF3, 0xA7, 0x09, 0x2A, 0x31, 0xE4, 0x0C,
+ 0xF8, 0x6E, 0x3E, 0xB5, 0x82, 0xFE, 0x74, 0x13,
+ 0x65, 0xE1, 0x2D, 0x8F, 0xE6, 0xC4, 0x00, 0x5B,
+ 0x4E, 0xB9, 0x66, 0xF2, 0x62, 0x36, 0x4C, 0x83,
+ 0x5E, 0x6F, 0x47, 0x64, 0xBC, 0x9A, 0x60, 0x7E };
+
+unsigned char table_28[32] = {
+ 0x15, 0x05, 0x08, 0x19, 0x02, 0x18, 0x1E, 0x07,
+ 0x0D, 0x0C, 0x1A, 0x06, 0x17, 0x03, 0x10, 0x09,
+ 0x01, 0x11, 0x1C, 0x04, 0x0F, 0x1F, 0x12, 0x0B,
+ 0x1B, 0x13, 0x0A, 0x16, 0x0E, 0x00, 0x1D, 0x14 };
+
+unsigned char table_29[256] = {
+ 0x34, 0x59, 0x05, 0x13, 0x09, 0x1D, 0xDF, 0x77,
+ 0x11, 0xA5, 0x92, 0x27, 0xCD, 0x7B, 0x5E, 0x80,
+ 0xF9, 0x50, 0x18, 0x24, 0xD4, 0x70, 0x4A, 0x39,
+ 0x66, 0xA4, 0xDB, 0xE9, 0xED, 0x48, 0xD9, 0xE7,
+ 0x32, 0xDA, 0x53, 0x8F, 0x72, 0xE1, 0xF6, 0xFE,
+ 0xD3, 0xAD, 0xA6, 0x1F, 0xB9, 0xD1, 0x0F, 0x4C,
+ 0x23, 0x90, 0x68, 0xBC, 0x4B, 0x9B, 0x3D, 0xAB,
+ 0xF0, 0x94, 0x4F, 0x1C, 0x07, 0x65, 0x7F, 0x01,
+ 0x5C, 0xD7, 0x21, 0x8C, 0xBF, 0x8E, 0xB8, 0x86,
+ 0x6C, 0x33, 0x36, 0xC1, 0x06, 0x74, 0x37, 0x84,
+ 0x41, 0xAE, 0x67, 0x29, 0xB4, 0x85, 0xCE, 0x2A,
+ 0xCB, 0x1E, 0x61, 0x9E, 0x7A, 0x44, 0x3E, 0x89,
+ 0x14, 0x20, 0x19, 0xBB, 0xE0, 0xAA, 0xCF, 0x83,
+ 0xA8, 0x93, 0x43, 0xF2, 0xAC, 0x0E, 0xD2, 0xCC,
+ 0xDD, 0x47, 0x58, 0xC9, 0xCA, 0x1B, 0x54, 0x6E,
+ 0x8A, 0x79, 0xF8, 0xC4, 0xFB, 0xD5, 0x91, 0xDE,
+ 0x12, 0x31, 0x99, 0xFA, 0x6D, 0xC8, 0x57, 0xEC,
+ 0xB7, 0x28, 0x0C, 0x52, 0xF1, 0x0D, 0xB1, 0x9A,
+ 0x26, 0x98, 0x16, 0x7D, 0xD0, 0x2E, 0x8B, 0xD8,
+ 0xE6, 0xE8, 0x30, 0xFD, 0x7C, 0x64, 0x5A, 0xBD,
+ 0x87, 0xE2, 0xA1, 0x3F, 0xC3, 0x38, 0x96, 0xA3,
+ 0x2D, 0xF3, 0x3A, 0xEE, 0xC0, 0x10, 0xEA, 0x6F,
+ 0x8D, 0x03, 0xF4, 0x51, 0x97, 0x7E, 0x56, 0x42,
+ 0x3C, 0x5D, 0x5F, 0xF5, 0x6A, 0xAF, 0xE4, 0xBE,
+ 0xBA, 0x78, 0xA0, 0x5B, 0x49, 0xA7, 0xC7, 0x9C,
+ 0x63, 0x6B, 0x00, 0x17, 0x69, 0x75, 0x3B, 0x40,
+ 0xEF, 0x45, 0xB5, 0x2B, 0x2F, 0x02, 0xC6, 0x22,
+ 0x9F, 0xFC, 0x73, 0x08, 0x81, 0xB2, 0x2C, 0x71,
+ 0x35, 0xA2, 0xE3, 0xB3, 0x9D, 0xC5, 0x0A, 0xC2,
+ 0x25, 0x82, 0xDC, 0x88, 0xA9, 0xE5, 0xF7, 0xEB,
+ 0xD6, 0x60, 0x76, 0x55, 0x0B, 0x4E, 0xFF, 0x1A,
+ 0x46, 0x62, 0xB6, 0xB0, 0x15, 0x04, 0x95, 0x4D };
+
+unsigned char table_30[32] = {
+ 0x00, 0x1C, 0x0E, 0x0C, 0x06, 0x16, 0x09, 0x12,
+ 0x01, 0x13, 0x0B, 0x14, 0x11, 0x08, 0x04, 0x18,
+ 0x10, 0x1B, 0x15, 0x03, 0x02, 0x19, 0x1A, 0x17,
+ 0x1E, 0x1F, 0x0F, 0x07, 0x0D, 0x05, 0x1D, 0x0A };
+
+unsigned char table_31[256] = {
+ 0xDF, 0xD8, 0x3F, 0xBC, 0x5F, 0xC9, 0x8E, 0x4C,
+ 0x0B, 0x3C, 0xE5, 0xBF, 0x39, 0xD5, 0x30, 0xDD,
+ 0x23, 0xC7, 0x72, 0x63, 0x1F, 0xF8, 0x96, 0x31,
+ 0x70, 0xD6, 0x9E, 0xE8, 0x9D, 0xF5, 0xEF, 0x65,
+ 0xC2, 0x50, 0x62, 0x77, 0xD3, 0x6C, 0x1A, 0x91,
+ 0xBB, 0xFF, 0xCD, 0x9B, 0xB6, 0xBA, 0xB8, 0x7A,
+ 0x14, 0xA7, 0x74, 0x89, 0xD4, 0x6E, 0x19, 0x69,
+ 0xAB, 0x01, 0x15, 0x0E, 0x87, 0x55, 0x79, 0x1C,
+ 0x18, 0xBE, 0xA8, 0xDB, 0x52, 0xD2, 0x8F, 0x7E,
+ 0x81, 0xAF, 0xFD, 0x5C, 0x3E, 0x1B, 0xB9, 0xB2,
+ 0xB7, 0x51, 0x57, 0x8C, 0xCF, 0x5B, 0xA4, 0x75,
+ 0xDE, 0x22, 0x8B, 0x10, 0x12, 0xC8, 0x35, 0x2D,
+ 0x45, 0xB5, 0xF0, 0x47, 0x88, 0x16, 0xEB, 0x67,
+ 0xD9, 0x0C, 0xF1, 0xC1, 0x34, 0x33, 0xC6, 0x78,
+ 0xB3, 0x26, 0xE3, 0xBD, 0x5D, 0x4E, 0x66, 0xE4,
+ 0xD7, 0xC4, 0xE6, 0xA1, 0xB0, 0x95, 0x2B, 0x9A,
+ 0x4A, 0x3A, 0xCB, 0x40, 0xE1, 0x60, 0x49, 0xCC,
+ 0x03, 0xAC, 0xF4, 0x97, 0x32, 0x0F, 0x38, 0x17,
+ 0xF9, 0xE0, 0xD1, 0xFB, 0x04, 0x5E, 0x68, 0x06,
+ 0xAE, 0xFA, 0xAA, 0xED, 0x24, 0x0D, 0x00, 0x61,
+ 0x20, 0xA3, 0x7B, 0x6B, 0x76, 0x27, 0xEA, 0xCE,
+ 0x6A, 0x82, 0x9F, 0x6D, 0x9C, 0x64, 0xA2, 0x11,
+ 0x37, 0x2A, 0xCA, 0x84, 0x25, 0x7C, 0x2F, 0x8D,
+ 0x90, 0xE7, 0x09, 0x93, 0xF3, 0x43, 0x71, 0xEC,
+ 0xA9, 0x7D, 0x94, 0xA6, 0x3D, 0x7F, 0x54, 0x44,
+ 0x99, 0x80, 0x41, 0xC0, 0xA0, 0x8A, 0x1E, 0xDC,
+ 0x08, 0xD0, 0x2E, 0x42, 0x05, 0x85, 0x86, 0xFE,
+ 0x3B, 0x59, 0xC3, 0x58, 0x13, 0xB4, 0x36, 0xA5,
+ 0x73, 0x28, 0x29, 0xDA, 0x4F, 0x1D, 0xB1, 0x53,
+ 0x46, 0x2C, 0xF2, 0x4D, 0xAD, 0xFC, 0x83, 0x02,
+ 0x6F, 0x07, 0xE9, 0xEE, 0x21, 0x98, 0x5A, 0xC5,
+ 0x92, 0x48, 0xF7, 0x0A, 0xF6, 0xE2, 0x4B, 0x56 };
+
+unsigned char table_32[256] = {
+ 0x7B, 0x0F, 0x56, 0x2F, 0x1E, 0x2A, 0x7A, 0xD1,
+ 0x02, 0x91, 0x4E, 0x37, 0x6C, 0x10, 0xA7, 0xF2,
+ 0x38, 0xAC, 0x9E, 0x2B, 0x5E, 0x23, 0xE3, 0x19,
+ 0x9B, 0xF6, 0xB0, 0x59, 0x14, 0xB9, 0xA9, 0x46,
+ 0x84, 0x1D, 0xC0, 0x98, 0xF3, 0xE1, 0xE8, 0x94,
+ 0x52, 0x35, 0xBA, 0xD8, 0x07, 0xEF, 0x31, 0xF8,
+ 0x03, 0x76, 0x9C, 0xD7, 0xE4, 0x8B, 0xAF, 0x60,
+ 0xDD, 0x51, 0x00, 0xDF, 0x11, 0x7F, 0x1C, 0xED,
+ 0x49, 0xC9, 0xF4, 0x87, 0x64, 0xFC, 0x5D, 0xAD,
+ 0x88, 0x85, 0xF7, 0x5A, 0x92, 0xDB, 0x72, 0x1A,
+ 0x83, 0x15, 0x30, 0x24, 0x9F, 0xFF, 0x5B, 0xF1,
+ 0xD2, 0xFD, 0xC2, 0xB5, 0x25, 0x22, 0x18, 0x3D,
+ 0xCD, 0x97, 0x8C, 0xCC, 0x78, 0x90, 0xAA, 0x5F,
+ 0x0A, 0x57, 0x05, 0x61, 0xD4, 0xA0, 0x3A, 0xDE,
+ 0x3B, 0xF9, 0x65, 0x68, 0x4F, 0x28, 0xFA, 0xEB,
+ 0x63, 0x2D, 0x8D, 0xD0, 0xA1, 0xFE, 0x12, 0x96,
+ 0x3C, 0x42, 0x29, 0xD6, 0xA4, 0x34, 0xBD, 0x70,
+ 0x89, 0xBE, 0xF5, 0x79, 0xAB, 0x8F, 0x32, 0xB4,
+ 0xEE, 0xE7, 0x2C, 0x04, 0x4B, 0xD5, 0xB1, 0x54,
+ 0xF0, 0xDA, 0x16, 0x77, 0xA6, 0x53, 0xB2, 0xE2,
+ 0x73, 0xBF, 0x17, 0xA8, 0x75, 0x26, 0xE0, 0xBC,
+ 0x0C, 0x71, 0xFB, 0x6D, 0x7E, 0xC5, 0xEA, 0x21,
+ 0x9D, 0x95, 0x8E, 0xA5, 0x48, 0xB8, 0x7D, 0xCB,
+ 0x01, 0x99, 0xE5, 0xBB, 0x82, 0xC4, 0xCA, 0xC1,
+ 0x58, 0x6E, 0x5C, 0x7C, 0xDC, 0x33, 0xB6, 0xC3,
+ 0x09, 0xC7, 0x1F, 0x0D, 0x43, 0x6F, 0xE9, 0x86,
+ 0x27, 0xC8, 0x44, 0xB3, 0xD3, 0xCF, 0x08, 0x66,
+ 0x1B, 0x20, 0x4D, 0xD9, 0xC6, 0x36, 0x40, 0x74,
+ 0x62, 0x6A, 0x55, 0xEC, 0x06, 0x2E, 0xE6, 0x80,
+ 0x13, 0x93, 0x50, 0xCE, 0x69, 0x3E, 0x67, 0x4A,
+ 0x81, 0x4C, 0x0B, 0x3F, 0xB7, 0x0E, 0x39, 0xAE,
+ 0x47, 0x6B, 0x8A, 0xA2, 0x9A, 0xA3, 0x45, 0x41 };
+
+unsigned char table_33[256] = {
+ 0xDE, 0xD3, 0x79, 0x67, 0x13, 0x5C, 0x04, 0xF2,
+ 0xD9, 0x9F, 0x65, 0x56, 0xCC, 0x3B, 0xA4, 0x9A,
+ 0x08, 0xBF, 0x26, 0xB2, 0xA7, 0x5E, 0xAA, 0xCA,
+ 0xBB, 0x2B, 0x38, 0x3F, 0xD8, 0x87, 0xFA, 0x5D,
+ 0x73, 0x8E, 0x1E, 0x93, 0x05, 0xAF, 0x3E, 0x4E,
+ 0x90, 0xDB, 0x0B, 0x33, 0x0D, 0x2F, 0x86, 0x4F,
+ 0xFD, 0xD0, 0x39, 0xB1, 0x8A, 0x1A, 0x20, 0xE6,
+ 0xCF, 0xA2, 0x82, 0xDF, 0x42, 0x9C, 0x30, 0x40,
+ 0xE3, 0xB0, 0x88, 0x5A, 0xEC, 0x25, 0xE2, 0xC4,
+ 0x12, 0x54, 0x50, 0x97, 0x96, 0x21, 0x23, 0x7B,
+ 0x1D, 0x61, 0x52, 0x34, 0x7D, 0x69, 0x16, 0xC3,
+ 0x31, 0xF8, 0x48, 0x19, 0x95, 0x01, 0x29, 0x8C,
+ 0x15, 0xAC, 0x84, 0x74, 0xAB, 0x70, 0xDA, 0x36,
+ 0xD6, 0x8F, 0xFE, 0x35, 0xD7, 0x2E, 0x89, 0x07,
+ 0x62, 0x17, 0xDC, 0x92, 0x45, 0x83, 0xB5, 0xE5,
+ 0x8B, 0xC0, 0x27, 0x85, 0x7C, 0x9D, 0x55, 0x81,
+ 0x71, 0xCD, 0xC9, 0x00, 0x02, 0xC1, 0x0A, 0x37,
+ 0xED, 0xEA, 0xC2, 0x98, 0x49, 0x06, 0x1C, 0x78,
+ 0x64, 0xCE, 0x9E, 0x4C, 0x7A, 0xB4, 0x43, 0x0F,
+ 0xE0, 0x7E, 0xBC, 0x5B, 0x51, 0xE7, 0x18, 0xF9,
+ 0x11, 0xA1, 0xF5, 0xC7, 0xCB, 0x4D, 0x6A, 0x0E,
+ 0x57, 0xF1, 0xFB, 0xB3, 0x99, 0xF0, 0x32, 0xD5,
+ 0xA9, 0x4B, 0x6F, 0x6D, 0xA8, 0xC5, 0xDD, 0x7F,
+ 0xEB, 0xBE, 0xFC, 0x2C, 0x22, 0x58, 0x03, 0x9B,
+ 0x77, 0xF7, 0xBD, 0xBA, 0xD2, 0x6B, 0xAD, 0x5F,
+ 0x10, 0x6E, 0x09, 0xD1, 0x1B, 0x24, 0xEF, 0x72,
+ 0x3D, 0x59, 0x28, 0xE1, 0xB7, 0x44, 0x8D, 0xB8,
+ 0xAE, 0x2D, 0x60, 0xA6, 0xC8, 0x0C, 0xF4, 0x41,
+ 0xA3, 0x68, 0x46, 0x6C, 0x76, 0xA0, 0xB6, 0x66,
+ 0xE4, 0x1F, 0x75, 0x4A, 0xFF, 0x2A, 0x94, 0xD4,
+ 0xF3, 0xE9, 0x91, 0x63, 0xA5, 0xB9, 0xE8, 0x14,
+ 0x80, 0x3C, 0xEE, 0x47, 0xC6, 0x3A, 0x53, 0xF6 };
+
+unsigned char table_34[256] = {
+ 0xF0, 0xE9, 0x3E, 0xD6, 0x89, 0xC8, 0xC7, 0x23,
+ 0x75, 0x26, 0x5F, 0x9C, 0x57, 0xB8, 0x2A, 0x29,
+ 0xE5, 0xB5, 0x68, 0xA4, 0x92, 0x46, 0x40, 0x7F,
+ 0xF2, 0xBC, 0x6A, 0xE0, 0x8F, 0x0F, 0xE4, 0x3A,
+ 0xE1, 0x30, 0x84, 0x6E, 0x82, 0x8E, 0x56, 0xC5,
+ 0x32, 0x85, 0xFB, 0x59, 0x43, 0x41, 0xC2, 0xF6,
+ 0x67, 0x5A, 0x7C, 0x34, 0xA1, 0xD0, 0x4B, 0xAC,
+ 0x61, 0x72, 0x6B, 0xAF, 0xC4, 0x20, 0x9A, 0xD4,
+ 0x74, 0x8D, 0x87, 0x83, 0xE2, 0x62, 0x6D, 0xE6,
+ 0xE7, 0xF9, 0x76, 0xCB, 0x18, 0x90, 0x4F, 0xFF,
+ 0xD3, 0x3C, 0x08, 0x79, 0x93, 0x2D, 0x95, 0xA3,
+ 0xDD, 0x5B, 0xDA, 0x7A, 0x39, 0x4D, 0xC1, 0x2E,
+ 0xCC, 0x53, 0xE8, 0xA2, 0xCF, 0x15, 0x78, 0x1C,
+ 0xEB, 0x9B, 0x7B, 0xAD, 0x31, 0x2F, 0xE3, 0xC9,
+ 0x3B, 0xEC, 0x2C, 0x49, 0x02, 0x52, 0x28, 0xBA,
+ 0x0C, 0x19, 0x24, 0xF7, 0x97, 0x09, 0xA6, 0xA0,
+ 0xDF, 0xD1, 0xD2, 0xDC, 0x51, 0xA5, 0x94, 0xFD,
+ 0x71, 0xF5, 0x50, 0x0A, 0x69, 0x25, 0x88, 0x5C,
+ 0x91, 0xD5, 0x47, 0x0B, 0x27, 0x13, 0x96, 0xD9,
+ 0xF1, 0xA9, 0x70, 0xC3, 0xBE, 0x42, 0x4E, 0x4A,
+ 0xB1, 0x07, 0xA7, 0x54, 0xFE, 0x48, 0x9F, 0x63,
+ 0x17, 0xAE, 0xB9, 0x58, 0x21, 0x35, 0xED, 0x5D,
+ 0x9D, 0x3D, 0xB4, 0xFC, 0xEA, 0x8C, 0x80, 0xA8,
+ 0x1E, 0xB0, 0xDE, 0x0D, 0x11, 0x6F, 0x04, 0x12,
+ 0xF4, 0x10, 0x64, 0x0E, 0xD7, 0x2B, 0xB3, 0x8B,
+ 0xB7, 0x01, 0x86, 0xCA, 0xFA, 0x9E, 0xEE, 0x66,
+ 0x37, 0x65, 0x81, 0x38, 0x1F, 0xAA, 0x73, 0xAB,
+ 0xBD, 0xDB, 0x14, 0xCD, 0x00, 0xBB, 0x98, 0x44,
+ 0x45, 0xB6, 0x99, 0x5E, 0xD8, 0x1D, 0x36, 0xF8,
+ 0x55, 0x6C, 0x16, 0x7E, 0x77, 0x3F, 0x22, 0xEF,
+ 0xF3, 0x7D, 0xC6, 0xCE, 0x8A, 0xB2, 0x33, 0x4C,
+ 0x03, 0x05, 0xBF, 0x06, 0x1B, 0xC0, 0x1A, 0x60 };
+
+unsigned char table_35[256] = {
+ 0xCC, 0x40, 0xEF, 0x1F, 0xDB, 0xE5, 0x71, 0x51,
+ 0x3B, 0x0F, 0x7D, 0x9C, 0x83, 0x17, 0x6F, 0x8F,
+ 0x13, 0xDC, 0x7F, 0xA9, 0xA5, 0xA2, 0x9D, 0xDF,
+ 0xE7, 0x97, 0x2A, 0x30, 0xF2, 0x73, 0xCF, 0x87,
+ 0x29, 0xB3, 0x86, 0x43, 0x09, 0xB0, 0x2E, 0x10,
+ 0x8E, 0xBC, 0x57, 0xBA, 0x68, 0xF5, 0xCB, 0x89,
+ 0x32, 0xC1, 0x6B, 0x1E, 0xAC, 0xB2, 0x2D, 0x6A,
+ 0x50, 0xEB, 0x18, 0x06, 0xD8, 0xC7, 0x36, 0x31,
+ 0xC5, 0xAF, 0x12, 0x15, 0xB7, 0x37, 0x4E, 0x01,
+ 0x14, 0x21, 0x44, 0x5E, 0xF4, 0xB4, 0xE4, 0x65,
+ 0xFE, 0x8A, 0xEA, 0x0D, 0xBB, 0x45, 0x8B, 0x25,
+ 0x80, 0x35, 0x61, 0xA8, 0x4A, 0x47, 0xAB, 0x91,
+ 0x1B, 0x1C, 0x05, 0x4D, 0x5A, 0xD4, 0xF1, 0x9B,
+ 0x0E, 0x98, 0xCA, 0x96, 0x42, 0x7E, 0x03, 0x5F,
+ 0xE2, 0x90, 0xBF, 0x82, 0xC9, 0x3D, 0xE0, 0x5C,
+ 0xFA, 0x3E, 0x41, 0x11, 0x79, 0x58, 0x24, 0x2C,
+ 0xC0, 0x28, 0x5D, 0xA3, 0xDE, 0x67, 0xFF, 0xA4,
+ 0x63, 0xB1, 0x22, 0x04, 0xFD, 0x70, 0x39, 0x46,
+ 0xAA, 0x0A, 0x34, 0x6C, 0xD7, 0x92, 0xA1, 0x3C,
+ 0x19, 0xD5, 0xFC, 0xAD, 0x85, 0x07, 0x00, 0x23,
+ 0xF8, 0x69, 0x56, 0x53, 0x55, 0x7A, 0xB8, 0xC8,
+ 0xDA, 0xCE, 0xF3, 0x5B, 0x49, 0xE1, 0xBE, 0xEC,
+ 0x1A, 0x88, 0x02, 0xBD, 0xF7, 0x1D, 0x64, 0xA0,
+ 0x4F, 0xD9, 0xE3, 0x95, 0xC6, 0x48, 0x2B, 0xED,
+ 0x9A, 0x9E, 0x26, 0x6E, 0xD1, 0x94, 0xB9, 0x93,
+ 0xDD, 0xF6, 0xA6, 0xFB, 0xC2, 0xB6, 0x0C, 0xE9,
+ 0x77, 0xF9, 0xCD, 0x08, 0xEE, 0x3F, 0xE6, 0x75,
+ 0xD6, 0x84, 0x76, 0x8C, 0xF0, 0xAE, 0xD2, 0x78,
+ 0x2F, 0x4B, 0x16, 0x4C, 0x27, 0x81, 0x6D, 0x99,
+ 0x38, 0xD3, 0x54, 0x62, 0x74, 0x20, 0x60, 0xC3,
+ 0x7C, 0x8D, 0x72, 0x0B, 0x52, 0xE8, 0xA7, 0x3A,
+ 0x59, 0xC4, 0x9F, 0xD0, 0x66, 0x7B, 0x33, 0xB5 };
+
+unsigned char table_36[256] = {
+ 0xDB, 0x6F, 0xFE, 0xB3, 0x5C, 0x1F, 0xB8, 0xBF,
+ 0xA3, 0x71, 0x11, 0x56, 0x90, 0xE2, 0x63, 0x18,
+ 0x83, 0x51, 0x21, 0xEB, 0x66, 0x08, 0xA6, 0xA5,
+ 0x1C, 0xF5, 0x14, 0x24, 0x41, 0x33, 0xA7, 0xB5,
+ 0xC7, 0x79, 0x57, 0x50, 0x85, 0xE1, 0x6D, 0xF7,
+ 0x0E, 0xDE, 0x67, 0xAB, 0xA1, 0x0B, 0xD9, 0x4A,
+ 0xCA, 0x36, 0xEA, 0xDA, 0x16, 0xEF, 0x9F, 0x0A,
+ 0x09, 0x9A, 0x1D, 0xC5, 0xD7, 0x5F, 0x19, 0xDC,
+ 0x15, 0x06, 0xE8, 0x94, 0x0C, 0x0D, 0xC9, 0x7C,
+ 0xD6, 0x62, 0xBB, 0x49, 0xF9, 0x61, 0x07, 0x9B,
+ 0x28, 0xC3, 0x9E, 0xF4, 0x38, 0x78, 0x20, 0x03,
+ 0xA2, 0x7F, 0xC2, 0x9D, 0x5E, 0x65, 0x52, 0x17,
+ 0x2E, 0x1B, 0xB0, 0x42, 0xBC, 0xFD, 0xF1, 0xD2,
+ 0xF6, 0x60, 0xD3, 0x29, 0x97, 0x3D, 0x0F, 0xB1,
+ 0x2F, 0x22, 0xDD, 0x80, 0x32, 0xF8, 0xAD, 0x70,
+ 0xB9, 0x8F, 0x37, 0xCE, 0x46, 0x58, 0xB7, 0x30,
+ 0xED, 0x7A, 0xE9, 0xC0, 0x7D, 0x13, 0x64, 0x23,
+ 0x4E, 0xC8, 0xF0, 0xCC, 0x3B, 0x45, 0x68, 0x8D,
+ 0xBE, 0x8B, 0xD8, 0x43, 0x02, 0x27, 0xE4, 0xAA,
+ 0x10, 0xF2, 0x59, 0x72, 0x40, 0x26, 0x69, 0xE5,
+ 0x05, 0x84, 0x4F, 0xE0, 0x6B, 0xC1, 0xAC, 0x4C,
+ 0xFB, 0x31, 0x77, 0x8E, 0xD4, 0x12, 0xA9, 0xB4,
+ 0xEC, 0x00, 0x76, 0x1E, 0x25, 0xAE, 0xE7, 0x3C,
+ 0x35, 0x93, 0x9C, 0xC4, 0xFC, 0x2D, 0x91, 0x04,
+ 0xAF, 0x53, 0x3F, 0xE6, 0xA4, 0xD0, 0x1A, 0xDF,
+ 0x3A, 0x55, 0x99, 0x01, 0xCB, 0x6C, 0x82, 0x3E,
+ 0x5D, 0xA8, 0x88, 0x54, 0x5B, 0x95, 0xCD, 0x8C,
+ 0x81, 0x34, 0xD1, 0x39, 0xFF, 0xEE, 0xFA, 0x8A,
+ 0x6E, 0x86, 0x92, 0x89, 0xF3, 0x6A, 0xBA, 0x2C,
+ 0xD5, 0x44, 0xC6, 0x96, 0xBD, 0xB2, 0x2B, 0x87,
+ 0x74, 0xA0, 0x73, 0x5A, 0x2A, 0x98, 0x75, 0x47,
+ 0x4B, 0xB6, 0x7B, 0x4D, 0xCF, 0x7E, 0x48, 0xE3 };
+
+unsigned char table_37[256] = {
+ 0x1F, 0xD6, 0xB1, 0xB3, 0x40, 0xAD, 0xDE, 0xB7,
+ 0x19, 0xB4, 0xE7, 0x0B, 0x9C, 0x2D, 0xE0, 0xF5,
+ 0xCF, 0x2C, 0x30, 0x65, 0x2F, 0xCD, 0x02, 0x91,
+ 0xCE, 0x2B, 0xBF, 0x78, 0xE6, 0xFA, 0x51, 0x48,
+ 0xFB, 0x4D, 0xBE, 0x71, 0x1A, 0x56, 0xFD, 0x81,
+ 0x33, 0x75, 0x89, 0x96, 0x37, 0x82, 0x9E, 0x93,
+ 0x41, 0x18, 0x5B, 0x2E, 0x22, 0x0F, 0xAF, 0x4B,
+ 0xB9, 0xD5, 0xEE, 0x6C, 0xE4, 0x05, 0xCC, 0x99,
+ 0xE5, 0x3B, 0x62, 0xBD, 0x7B, 0xAA, 0x4A, 0xE2,
+ 0x34, 0x43, 0xF7, 0x39, 0xFE, 0x14, 0x1D, 0xE3,
+ 0xF0, 0xA7, 0x77, 0xDF, 0xA0, 0xD3, 0xAC, 0xD9,
+ 0xEA, 0x76, 0xDD, 0xA4, 0xC5, 0xC9, 0x61, 0xF3,
+ 0xA8, 0xB0, 0x35, 0xE8, 0x68, 0xD4, 0x15, 0xF9,
+ 0x97, 0xED, 0x25, 0x0A, 0x88, 0x8F, 0x06, 0xA3,
+ 0x16, 0x36, 0x32, 0xA2, 0xC6, 0x64, 0xD7, 0x94,
+ 0xD2, 0x6D, 0x74, 0xFC, 0x44, 0x27, 0x5C, 0xFF,
+ 0x60, 0x1E, 0x58, 0x8B, 0x5E, 0xC7, 0x90, 0x17,
+ 0x63, 0xAE, 0xC3, 0x12, 0x13, 0x84, 0xEC, 0x49,
+ 0xA5, 0x9B, 0x31, 0x8D, 0xE1, 0x79, 0xF1, 0x00,
+ 0x28, 0x3D, 0xC2, 0x55, 0x20, 0x52, 0x95, 0x7E,
+ 0x42, 0x1C, 0x66, 0x92, 0x7D, 0xB6, 0xC4, 0xF4,
+ 0x80, 0xB2, 0x72, 0x6E, 0x11, 0xF6, 0x0D, 0x5A,
+ 0xEF, 0x9D, 0x69, 0x9A, 0x45, 0x67, 0x3F, 0xDA,
+ 0x8E, 0x57, 0x09, 0x7C, 0x38, 0xA6, 0x83, 0x87,
+ 0x7A, 0x08, 0x4C, 0x5F, 0x85, 0x7F, 0xD0, 0x04,
+ 0x50, 0xCB, 0xB8, 0x07, 0x24, 0x26, 0x29, 0x46,
+ 0x01, 0x03, 0xC1, 0xD8, 0xDC, 0x0E, 0x3C, 0x4F,
+ 0x53, 0x4E, 0xB5, 0xF8, 0xC0, 0x8A, 0xF2, 0xBB,
+ 0xE9, 0x5D, 0x2A, 0xBA, 0x0C, 0x1B, 0x3A, 0xA9,
+ 0x21, 0x6A, 0x70, 0xBC, 0xEB, 0xA1, 0x54, 0x10,
+ 0x98, 0x9F, 0x23, 0xD1, 0x6B, 0x59, 0x3E, 0xCA,
+ 0x73, 0xC8, 0x86, 0x47, 0xDB, 0xAB, 0x6F, 0x8C };
+
+unsigned char table_38[256] = {
+ 0xAA, 0x8D, 0x37, 0x94, 0x99, 0xDD, 0x70, 0x77,
+ 0x78, 0xC9, 0x0F, 0xFA, 0xE2, 0x05, 0xC2, 0x16,
+ 0x02, 0x4D, 0x44, 0x65, 0xAC, 0xB0, 0x39, 0xF8,
+ 0x06, 0x60, 0xD8, 0xE1, 0x19, 0xB4, 0x36, 0x20,
+ 0x59, 0x1D, 0xAD, 0xE4, 0xE8, 0xFF, 0x9D, 0x0D,
+ 0x51, 0x28, 0xE7, 0x8C, 0x0E, 0x97, 0xE3, 0xAE,
+ 0x6A, 0x27, 0x98, 0xDB, 0x26, 0xF6, 0xEC, 0xC6,
+ 0xC0, 0xBD, 0x68, 0x61, 0x83, 0x86, 0xE0, 0x2C,
+ 0xEE, 0x47, 0xF9, 0x5F, 0x6D, 0xBA, 0xE9, 0x72,
+ 0x8A, 0xBB, 0x08, 0x29, 0xAF, 0x1C, 0xD3, 0x5D,
+ 0xF7, 0x87, 0x6F, 0x9A, 0x2F, 0x11, 0xD9, 0x90,
+ 0x66, 0x8E, 0xEB, 0xB1, 0x2E, 0xEA, 0xA3, 0x55,
+ 0x2B, 0xCC, 0x4C, 0x4B, 0x48, 0x71, 0x3B, 0xFC,
+ 0xA4, 0x45, 0x0A, 0x8F, 0x7A, 0x13, 0x01, 0x22,
+ 0xC1, 0xF1, 0xA2, 0xB8, 0x7C, 0xF4, 0xB3, 0xB7,
+ 0x5B, 0xE5, 0x07, 0x50, 0x7E, 0x18, 0xEF, 0x91,
+ 0x5C, 0x15, 0x69, 0xBE, 0x0C, 0x93, 0x56, 0x35,
+ 0x7B, 0xCF, 0x34, 0x74, 0x3E, 0x5E, 0x31, 0x21,
+ 0x12, 0x63, 0x7F, 0x2A, 0x9B, 0xD4, 0x6B, 0xBC,
+ 0x33, 0x62, 0x30, 0x75, 0x17, 0x23, 0xB2, 0xF0,
+ 0x57, 0x67, 0x95, 0x3D, 0xCD, 0x10, 0xE6, 0xC8,
+ 0x8B, 0xA9, 0x73, 0xC4, 0x43, 0xBF, 0xA7, 0xCA,
+ 0xB5, 0xD5, 0xD6, 0x3F, 0x1A, 0x7D, 0x82, 0xA8,
+ 0x40, 0x64, 0xAB, 0x04, 0xC3, 0x1F, 0xA0, 0x5A,
+ 0x85, 0xF3, 0xDE, 0xFE, 0xDA, 0x1E, 0x81, 0x92,
+ 0x9C, 0x2D, 0x9F, 0x32, 0xB9, 0xA1, 0x96, 0xD0,
+ 0x4F, 0x38, 0x80, 0xCB, 0x6C, 0x14, 0x84, 0x1B,
+ 0xD7, 0xC5, 0xED, 0xD2, 0x3A, 0x0B, 0x88, 0xFD,
+ 0xDC, 0x49, 0x9E, 0xF5, 0xF2, 0x52, 0xA6, 0x24,
+ 0xC7, 0xB6, 0x03, 0x3C, 0xD1, 0x54, 0x41, 0xDF,
+ 0x89, 0x58, 0x79, 0xFB, 0x6E, 0xA5, 0x42, 0x25,
+ 0x09, 0x76, 0x00, 0x46, 0x4E, 0x53, 0xCE, 0x4A };
+
+unsigned char table_39[32] = {
+ 0x12, 0x18, 0x0E, 0x08, 0x16, 0x05, 0x06, 0x00,
+ 0x11, 0x17, 0x15, 0x1B, 0x14, 0x01, 0x1F, 0x19,
+ 0x04, 0x0D, 0x0A, 0x0F, 0x10, 0x07, 0x1D, 0x03,
+ 0x0B, 0x13, 0x0C, 0x09, 0x1E, 0x02, 0x1A, 0x1C };
+
+unsigned char table_40[32] = {
+ 0x16, 0x02, 0x06, 0x0E, 0x0D, 0x1C, 0x08, 0x0A,
+ 0x0F, 0x13, 0x0B, 0x18, 0x07, 0x04, 0x14, 0x01,
+ 0x1B, 0x05, 0x17, 0x1E, 0x11, 0x1A, 0x10, 0x1F,
+ 0x12, 0x19, 0x1D, 0x03, 0x0C, 0x00, 0x09, 0x15 };
+
+unsigned char table_41[32] = {
+ 0x13, 0x18, 0x04, 0x1F, 0x1D, 0x11, 0x03, 0x00,
+ 0x10, 0x12, 0x06, 0x0A, 0x1C, 0x07, 0x15, 0x0E,
+ 0x08, 0x05, 0x0C, 0x09, 0x01, 0x02, 0x16, 0x0B,
+ 0x1A, 0x17, 0x14, 0x1E, 0x0D, 0x0F, 0x19, 0x1B };
+
+unsigned char table_42[32] = {
+ 0x00, 0x08, 0x15, 0x1D, 0x05, 0x18, 0x06, 0x07,
+ 0x1F, 0x01, 0x0B, 0x03, 0x19, 0x13, 0x02, 0x1C,
+ 0x17, 0x11, 0x0E, 0x1E, 0x0C, 0x0F, 0x09, 0x1A,
+ 0x1B, 0x16, 0x10, 0x0D, 0x0A, 0x14, 0x12, 0x04 };
+
+unsigned char table_43[256] = {
+ 0x34, 0xB7, 0x36, 0x85, 0x5F, 0x93, 0x98, 0x70,
+ 0x1E, 0x59, 0x83, 0x60, 0x6F, 0xBF, 0xF9, 0xD0,
+ 0xB3, 0x22, 0x12, 0x38, 0xF5, 0x01, 0xC9, 0x5B,
+ 0xEF, 0x1D, 0x81, 0x64, 0xFA, 0x8F, 0x7F, 0xBC,
+ 0x05, 0x08, 0xE0, 0x8B, 0xE8, 0x86, 0x95, 0xCB,
+ 0xCA, 0x5A, 0xEB, 0x10, 0x92, 0xE2, 0x7E, 0x28,
+ 0xD9, 0xC7, 0x0D, 0x24, 0xA7, 0x02, 0x0B, 0xF1,
+ 0x7B, 0xD3, 0xFE, 0x2B, 0x89, 0x0E, 0xAE, 0xAD,
+ 0xC8, 0x82, 0x79, 0x43, 0x96, 0xDE, 0x0C, 0x9A,
+ 0x57, 0x84, 0xB4, 0x19, 0xF8, 0xF0, 0xAF, 0xBE,
+ 0x99, 0x9F, 0x46, 0xE4, 0x31, 0xDF, 0x30, 0x51,
+ 0xD4, 0xE5, 0xFC, 0x32, 0x04, 0x56, 0x7D, 0x33,
+ 0xF7, 0x18, 0x23, 0x4E, 0xC2, 0x7C, 0x6C, 0xD2,
+ 0xB1, 0x9B, 0x40, 0xA2, 0x88, 0x00, 0xA1, 0xAB,
+ 0xC6, 0x5C, 0x87, 0x3B, 0xD7, 0x27, 0x2E, 0x45,
+ 0xDA, 0x8E, 0x61, 0x5E, 0xFB, 0x09, 0x5D, 0x6B,
+ 0xA3, 0x29, 0x4F, 0xAC, 0xD1, 0x77, 0x4A, 0xA9,
+ 0xC4, 0x7A, 0x15, 0xD8, 0xAA, 0x17, 0xB9, 0x2D,
+ 0xE7, 0xBD, 0x2C, 0x62, 0x2F, 0xB2, 0xED, 0x3F,
+ 0x48, 0x26, 0x1B, 0x35, 0x20, 0x72, 0x4D, 0xFF,
+ 0xBB, 0x78, 0x1F, 0xCC, 0xEC, 0xA8, 0x9D, 0x90,
+ 0x4B, 0x13, 0xE1, 0xBA, 0xF3, 0x3C, 0x42, 0x65,
+ 0x14, 0xDD, 0x75, 0xE3, 0x4C, 0x74, 0x94, 0xCD,
+ 0xF2, 0x66, 0x06, 0xE9, 0x49, 0xB8, 0x71, 0x41,
+ 0xA0, 0x25, 0x55, 0x47, 0x97, 0x9E, 0x11, 0x54,
+ 0x1A, 0xB0, 0x3E, 0x37, 0x39, 0x1C, 0x8D, 0x03,
+ 0x6E, 0xF6, 0x80, 0x6D, 0x8C, 0x9C, 0xB6, 0xCF,
+ 0xC3, 0x91, 0x63, 0xC0, 0x07, 0x67, 0xE6, 0xF4,
+ 0xCE, 0x3D, 0xDB, 0x16, 0xFD, 0xEA, 0xD6, 0x68,
+ 0xD5, 0xA6, 0x0F, 0x58, 0x44, 0x52, 0xB5, 0xDC,
+ 0x0A, 0x69, 0xC5, 0xA5, 0xC1, 0x8A, 0x2A, 0xEE,
+ 0x73, 0x76, 0x3A, 0x21, 0x53, 0xA4, 0x50, 0x6A };
+
+unsigned char table_44[32] = {
+ 0x1A, 0x0E, 0x0A, 0x17, 0x1F, 0x08, 0x10, 0x14,
+ 0x0C, 0x0F, 0x09, 0x1C, 0x06, 0x18, 0x1E, 0x12,
+ 0x15, 0x00, 0x11, 0x13, 0x0D, 0x01, 0x0B, 0x03,
+ 0x16, 0x19, 0x05, 0x1D, 0x02, 0x07, 0x04, 0x1B };
+
+unsigned char table_45[256] = {
+ 0x5E, 0xD6, 0xE2, 0x54, 0x35, 0xC2, 0xAC, 0x9D,
+ 0x92, 0x64, 0x57, 0x65, 0xC8, 0xAE, 0x21, 0xA9,
+ 0x89, 0x48, 0x12, 0x59, 0xEC, 0xEF, 0x9F, 0xF7,
+ 0x19, 0x03, 0x83, 0xC0, 0x79, 0x5D, 0x4A, 0x10,
+ 0x8C, 0xEB, 0xFF, 0xB5, 0x3B, 0x51, 0x2D, 0xD1,
+ 0x6B, 0xC5, 0x24, 0x5C, 0xE6, 0x11, 0x94, 0x3F,
+ 0xD0, 0x2F, 0x0E, 0x95, 0x3C, 0xFE, 0x5B, 0x20,
+ 0x23, 0xE0, 0x91, 0x6F, 0xCA, 0x56, 0x0C, 0x73,
+ 0xDA, 0x67, 0x37, 0xA3, 0xA5, 0x70, 0x93, 0x1C,
+ 0x18, 0xD9, 0x42, 0x5F, 0x44, 0xF0, 0xF2, 0x14,
+ 0x58, 0x8A, 0x1D, 0x40, 0x4E, 0x0B, 0x74, 0x84,
+ 0x52, 0xCB, 0x60, 0xED, 0xAD, 0x66, 0x43, 0x6C,
+ 0x81, 0xA1, 0x27, 0xB9, 0xBA, 0x4D, 0xF5, 0x04,
+ 0xB8, 0x96, 0xA6, 0xA2, 0x7D, 0xD4, 0xEA, 0x45,
+ 0x4F, 0x55, 0xD3, 0x3E, 0x8E, 0x4C, 0xBF, 0x8B,
+ 0x9A, 0x06, 0x7A, 0xF4, 0x02, 0x88, 0x80, 0x22,
+ 0xF3, 0xBD, 0x78, 0xEE, 0xAF, 0xF8, 0x15, 0x09,
+ 0x0F, 0xB0, 0xDD, 0x99, 0x72, 0xE7, 0x90, 0xE1,
+ 0x25, 0x62, 0x8D, 0x9C, 0x13, 0x08, 0xC9, 0x28,
+ 0x2A, 0x47, 0x69, 0xDE, 0x77, 0x87, 0xBB, 0xE9,
+ 0xAA, 0x33, 0x05, 0x29, 0x34, 0x97, 0xFD, 0xA0,
+ 0x1E, 0xFC, 0xBE, 0xB1, 0x71, 0x9B, 0x50, 0xDC,
+ 0xB7, 0x31, 0x63, 0x3A, 0xDF, 0xC3, 0x1B, 0x7C,
+ 0x0A, 0xD7, 0xF6, 0xDB, 0x49, 0x53, 0x7F, 0xD2,
+ 0x30, 0xA4, 0xB3, 0x6E, 0xB2, 0x6D, 0xCD, 0x7E,
+ 0x26, 0xE8, 0x76, 0xCF, 0xE5, 0xCE, 0x16, 0xF1,
+ 0xC6, 0x68, 0x36, 0x46, 0x1F, 0x38, 0x0D, 0x41,
+ 0x17, 0xBC, 0x86, 0x9E, 0x6A, 0x7B, 0xB4, 0x01,
+ 0xCC, 0x2C, 0xE3, 0x5A, 0xB6, 0xFA, 0x00, 0x75,
+ 0x39, 0xA7, 0xC1, 0xD5, 0x98, 0xAB, 0x1A, 0x85,
+ 0xD8, 0xE4, 0xC4, 0xA8, 0x4B, 0x61, 0x2E, 0x3D,
+ 0xF9, 0x2B, 0x32, 0x8F, 0xFB, 0xC7, 0x07, 0x82 };
+
+unsigned char table_46[256] = {
+ 0x85, 0x78, 0xFE, 0x6C, 0x61, 0xA0, 0x71, 0xCC,
+ 0x45, 0x54, 0x7A, 0xE6, 0x82, 0x1D, 0xA6, 0x02,
+ 0x47, 0xD0, 0x23, 0x55, 0x62, 0xFA, 0x76, 0x3E,
+ 0xE3, 0x66, 0x74, 0x10, 0x5D, 0x49, 0x69, 0x0B,
+ 0x75, 0x12, 0x8D, 0x9F, 0xEE, 0x93, 0x50, 0x70,
+ 0x32, 0xBC, 0x1E, 0xD3, 0xEF, 0x7B, 0xB4, 0x92,
+ 0xFD, 0x16, 0xC2, 0xD8, 0xDE, 0x68, 0xD1, 0x64,
+ 0xC3, 0xA3, 0xB3, 0xC9, 0x08, 0xFB, 0x84, 0xC1,
+ 0x28, 0x53, 0xCF, 0xD2, 0x35, 0xD7, 0x4A, 0x01,
+ 0x44, 0xA4, 0x07, 0xAC, 0x98, 0xF1, 0xB2, 0x9A,
+ 0x94, 0x2D, 0xD4, 0x34, 0x27, 0x60, 0x1A, 0xB9,
+ 0xAF, 0x89, 0xEB, 0x8F, 0x6A, 0x13, 0x05, 0xF0,
+ 0x77, 0x5F, 0x4F, 0x58, 0x2C, 0xE7, 0xCE, 0xED,
+ 0xC0, 0x0D, 0x3A, 0xA7, 0xE2, 0x38, 0x5B, 0xE9,
+ 0x3D, 0xF2, 0xDF, 0x86, 0xE0, 0x72, 0xF7, 0x88,
+ 0xAD, 0xB7, 0x11, 0xDB, 0x73, 0x87, 0xC5, 0x22,
+ 0xE1, 0x5C, 0xD6, 0x57, 0x7E, 0x7D, 0xA2, 0xF9,
+ 0xF5, 0x9C, 0x25, 0x6F, 0x26, 0x51, 0xC8, 0x80,
+ 0x2B, 0xA8, 0x19, 0xD9, 0x65, 0xCD, 0x97, 0xEA,
+ 0xFF, 0x5E, 0x24, 0x3B, 0x4D, 0xB1, 0x1C, 0x79,
+ 0x39, 0x6B, 0xA5, 0x2A, 0x09, 0xCA, 0x04, 0xEC,
+ 0xBA, 0x18, 0x31, 0x46, 0x20, 0xBE, 0x1F, 0x3C,
+ 0x6D, 0xAA, 0xF6, 0xDD, 0xF4, 0x96, 0x03, 0x0A,
+ 0x9E, 0x83, 0xA1, 0x9D, 0xD5, 0xB0, 0x17, 0xBF,
+ 0x56, 0xAB, 0xAE, 0x1B, 0x52, 0xC6, 0x81, 0x4B,
+ 0xDC, 0x90, 0x5A, 0x9B, 0xB6, 0x0F, 0xF3, 0x67,
+ 0x30, 0x63, 0x7C, 0x40, 0x0E, 0x7F, 0x95, 0x36,
+ 0xC4, 0x4E, 0x43, 0xCB, 0x15, 0xB8, 0x00, 0x91,
+ 0x8A, 0x4C, 0x8E, 0x14, 0x06, 0x6E, 0xA9, 0x2E,
+ 0x3F, 0x48, 0x2F, 0x0C, 0xB5, 0x21, 0xBB, 0xDA,
+ 0x8B, 0x42, 0x29, 0x8C, 0x33, 0x59, 0xE8, 0xF8,
+ 0xC7, 0xE4, 0x37, 0xE5, 0xFC, 0xBD, 0x99, 0x41 };
+
+unsigned char table_47[32] = {
+ 0x18, 0x1D, 0x16, 0x10, 0x11, 0x04, 0x1E, 0x08,
+ 0x19, 0x0E, 0x0F, 0x02, 0x14, 0x1C, 0x07, 0x17,
+ 0x0D, 0x09, 0x12, 0x1A, 0x05, 0x01, 0x0B, 0x0A,
+ 0x13, 0x15, 0x0C, 0x00, 0x06, 0x1F, 0x03, 0x1B };
+
+unsigned char table_48[32] = {
+ 0x13, 0x08, 0x15, 0x01, 0x17, 0x10, 0x0F, 0x1F,
+ 0x1D, 0x0D, 0x12, 0x03, 0x06, 0x0A, 0x1C, 0x19,
+ 0x1A, 0x04, 0x1B, 0x02, 0x16, 0x1E, 0x11, 0x00,
+ 0x14, 0x09, 0x0C, 0x18, 0x05, 0x07, 0x0E, 0x0B };
+
+unsigned char table_49[32] = {
+ 0x1F, 0x0F, 0x19, 0x07, 0x18, 0x05, 0x1E, 0x1D,
+ 0x15, 0x08, 0x17, 0x10, 0x0A, 0x0E, 0x0C, 0x1B,
+ 0x02, 0x13, 0x03, 0x0D, 0x04, 0x1A, 0x06, 0x09,
+ 0x12, 0x1C, 0x0B, 0x16, 0x14, 0x01, 0x11, 0x00 };
+
+unsigned char table_50[32] = {
+ 0x16, 0x18, 0x1C, 0x0E, 0x12, 0x00, 0x04, 0x1B,
+ 0x1F, 0x13, 0x17, 0x0A, 0x1E, 0x03, 0x0C, 0x01,
+ 0x0F, 0x10, 0x02, 0x08, 0x14, 0x09, 0x19, 0x15,
+ 0x06, 0x0D, 0x0B, 0x1D, 0x05, 0x07, 0x11, 0x1A };
+
+unsigned char table_51[32] = {
+ 0x1C, 0x0D, 0x1B, 0x07, 0x17, 0x0E, 0x06, 0x01,
+ 0x12, 0x19, 0x03, 0x0B, 0x10, 0x08, 0x00, 0x1E,
+ 0x0A, 0x04, 0x1A, 0x1D, 0x0C, 0x18, 0x02, 0x13,
+ 0x0F, 0x11, 0x05, 0x09, 0x15, 0x16, 0x1F, 0x14 };
+
+unsigned char table_52[256] = {
+ 0x34, 0x0B, 0x47, 0xA3, 0x56, 0x30, 0x73, 0xD4,
+ 0x4B, 0xF6, 0xA6, 0x80, 0x22, 0x95, 0xA5, 0xBB,
+ 0xFE, 0xCD, 0x27, 0x88, 0x87, 0x18, 0x86, 0x6E,
+ 0xB9, 0x07, 0x37, 0x52, 0x0A, 0x28, 0x2C, 0xC4,
+ 0x75, 0xA1, 0x29, 0x54, 0x84, 0x08, 0x72, 0x51,
+ 0xDD, 0xF1, 0x4E, 0x1A, 0x90, 0x57, 0x20, 0xAD,
+ 0x68, 0x61, 0xAF, 0x50, 0x6B, 0x1B, 0x71, 0xEB,
+ 0x63, 0xC9, 0xB0, 0x58, 0x26, 0x40, 0xC7, 0xD9,
+ 0x70, 0xA2, 0x9A, 0x09, 0x3F, 0x92, 0x0D, 0x8C,
+ 0xC1, 0x96, 0x9F, 0x77, 0x4D, 0x5A, 0xEA, 0x11,
+ 0xD7, 0xF3, 0x33, 0x93, 0x10, 0xF2, 0x9D, 0x83,
+ 0xFF, 0x7E, 0xD2, 0x41, 0x24, 0xB4, 0x8D, 0x5C,
+ 0xCF, 0xEF, 0xE9, 0x64, 0x76, 0xD1, 0xDE, 0xE4,
+ 0x91, 0x35, 0x89, 0x19, 0x02, 0x0E, 0xF4, 0x2A,
+ 0x0F, 0xE1, 0xA8, 0x2D, 0x21, 0x23, 0xAA, 0x7C,
+ 0x78, 0x45, 0xA9, 0xDC, 0x06, 0xF9, 0xDF, 0xF7,
+ 0x03, 0xAB, 0xB5, 0x1C, 0x36, 0x7B, 0x97, 0xFA,
+ 0xE5, 0x3B, 0x2F, 0x1F, 0x9E, 0xED, 0xA7, 0x55,
+ 0x42, 0x6F, 0x1E, 0xB7, 0xE6, 0xFB, 0x12, 0xD5,
+ 0x99, 0xC6, 0x66, 0x4A, 0xE8, 0x48, 0x60, 0xB1,
+ 0x05, 0x53, 0x8A, 0xB6, 0x25, 0x8F, 0xA4, 0xD8,
+ 0x9C, 0xC0, 0x59, 0x3A, 0xBD, 0xDB, 0x44, 0x5E,
+ 0xE3, 0xDA, 0x1D, 0x32, 0xF5, 0xBA, 0x43, 0x13,
+ 0x82, 0x4C, 0xE7, 0x17, 0x15, 0x3E, 0x69, 0x2E,
+ 0xC3, 0xF0, 0x5F, 0xFD, 0xCE, 0xD3, 0xCA, 0x39,
+ 0xD6, 0x79, 0x3D, 0xC8, 0x67, 0x8B, 0x31, 0x4F,
+ 0xB3, 0xBC, 0x65, 0x00, 0x7A, 0x98, 0xC5, 0x6C,
+ 0x2B, 0x94, 0x6D, 0x74, 0x14, 0xAC, 0xCC, 0xA0,
+ 0x5B, 0xF8, 0xCB, 0x7F, 0xB2, 0xEC, 0xBF, 0x3C,
+ 0xE0, 0xAE, 0xFC, 0x62, 0x04, 0x8E, 0x85, 0x49,
+ 0x9B, 0xC2, 0x38, 0xD0, 0xEE, 0x81, 0x46, 0xE2,
+ 0x01, 0x0C, 0x5D, 0x7D, 0xB8, 0xBE, 0x6A, 0x16 };
+
+unsigned char table_53[256] = {
+ 0xE3, 0xF4, 0x8D, 0x72, 0x45, 0x32, 0x9D, 0xCE,
+ 0x1F, 0x6B, 0xBC, 0xDC, 0xF1, 0xEC, 0x5A, 0x3B,
+ 0xA5, 0xA2, 0x2B, 0xDD, 0x8A, 0xA3, 0x76, 0xE4,
+ 0xAF, 0xE9, 0xE1, 0x21, 0xDB, 0x9F, 0x19, 0xD3,
+ 0x26, 0x80, 0x15, 0xC2, 0x46, 0xB8, 0x17, 0x56,
+ 0x99, 0x81, 0x08, 0xD7, 0xEF, 0x8E, 0x04, 0x05,
+ 0x97, 0x2F, 0x78, 0xAD, 0xA1, 0x52, 0x36, 0x58,
+ 0x53, 0x68, 0x22, 0x70, 0x0B, 0x79, 0xE6, 0xFA,
+ 0xC3, 0x91, 0xE2, 0xF7, 0xF6, 0x75, 0x2D, 0x0A,
+ 0x90, 0xEB, 0xA6, 0x35, 0xA7, 0x10, 0xB5, 0xFB,
+ 0xE7, 0xAA, 0x1E, 0x43, 0xBB, 0x3C, 0x65, 0x25,
+ 0x2C, 0x59, 0x62, 0x2A, 0xF9, 0x4B, 0x95, 0x5E,
+ 0x20, 0x11, 0x42, 0x27, 0x44, 0xE8, 0x14, 0x6F,
+ 0xD1, 0xD8, 0x00, 0x3A, 0x5B, 0x18, 0x89, 0x02,
+ 0x61, 0xD6, 0xC5, 0x98, 0xD0, 0x5F, 0x34, 0x29,
+ 0xFD, 0x31, 0x1A, 0xCD, 0x0F, 0x9E, 0xCA, 0x7B,
+ 0xEA, 0x93, 0x71, 0x5C, 0x0E, 0x57, 0x33, 0xC4,
+ 0x37, 0xF5, 0x83, 0xB0, 0xDF, 0x49, 0x74, 0x54,
+ 0x1D, 0x24, 0xB9, 0x16, 0x1C, 0x28, 0xDE, 0x4A,
+ 0xF0, 0x01, 0x86, 0x82, 0xCC, 0x12, 0x8C, 0x06,
+ 0x30, 0xA8, 0x7A, 0x73, 0x66, 0x7C, 0xC6, 0xB6,
+ 0xF2, 0x13, 0xBF, 0x40, 0x85, 0x77, 0x09, 0x3D,
+ 0x67, 0x63, 0x3F, 0x7F, 0xF3, 0x87, 0x8F, 0xFF,
+ 0x92, 0xC7, 0x4C, 0x23, 0xBA, 0xCB, 0xB1, 0xED,
+ 0x0C, 0x60, 0x47, 0xFE, 0x38, 0x5D, 0xCF, 0x8B,
+ 0x4D, 0xA9, 0x2E, 0xE5, 0xA4, 0x1B, 0x88, 0x3E,
+ 0x7D, 0xF8, 0xC0, 0xD5, 0x6D, 0x6C, 0x48, 0xAC,
+ 0x9B, 0x51, 0x7E, 0x6E, 0x50, 0x0D, 0x9A, 0xB3,
+ 0xEE, 0x07, 0x4F, 0x69, 0x9C, 0x03, 0xD9, 0xD4,
+ 0xB4, 0xD2, 0xAE, 0x4E, 0x55, 0xB7, 0xC9, 0x41,
+ 0x39, 0x6A, 0xC8, 0xA0, 0xB2, 0xC1, 0x84, 0xFC,
+ 0xAB, 0x64, 0xE0, 0xBE, 0xDA, 0xBD, 0x96, 0x94 };
+
+unsigned char table_54[32] = {
+ 0x01, 0x02, 0x1D, 0x10, 0x0E, 0x11, 0x08, 0x14,
+ 0x12, 0x09, 0x15, 0x17, 0x16, 0x04, 0x06, 0x1B,
+ 0x07, 0x1A, 0x18, 0x13, 0x0A, 0x1E, 0x1C, 0x1F,
+ 0x0C, 0x0B, 0x0D, 0x05, 0x0F, 0x00, 0x19, 0x03 };
+
+unsigned char table_55[32] = {
+ 0x01, 0x12, 0x13, 0x09, 0x0B, 0x19, 0x03, 0x0E,
+ 0x02, 0x1F, 0x1D, 0x1B, 0x1E, 0x11, 0x06, 0x05,
+ 0x00, 0x16, 0x07, 0x0C, 0x15, 0x0D, 0x1A, 0x08,
+ 0x18, 0x10, 0x0F, 0x17, 0x1C, 0x0A, 0x04, 0x14 };
+
+unsigned char table_56[256] = {
+ 0xEF, 0x06, 0x5F, 0x11, 0x4B, 0x60, 0x13, 0xBB,
+ 0x79, 0xD7, 0xE4, 0x6D, 0x22, 0xB4, 0x15, 0x50,
+ 0x29, 0x17, 0xD2, 0xE3, 0x37, 0x8C, 0x46, 0x7C,
+ 0xA2, 0xF5, 0x65, 0x16, 0xCB, 0x04, 0x3E, 0xDF,
+ 0x8E, 0xDE, 0x53, 0xF1, 0xF4, 0xD1, 0x3B, 0xEE,
+ 0x9A, 0x09, 0x9B, 0x6C, 0xF6, 0xCC, 0xFB, 0x40,
+ 0xE0, 0xFD, 0x2B, 0x1D, 0x73, 0x18, 0xCD, 0x31,
+ 0x3F, 0x9E, 0xAD, 0xC9, 0x43, 0x4E, 0x99, 0x3A,
+ 0x8F, 0x92, 0x85, 0xFC, 0x12, 0x41, 0x20, 0xE8,
+ 0x2A, 0xC0, 0x1C, 0x38, 0x74, 0x0B, 0xF3, 0x05,
+ 0x0D, 0x1F, 0x94, 0x9C, 0xAC, 0x00, 0x59, 0x0C,
+ 0xB3, 0x8D, 0xA8, 0x75, 0xB7, 0x68, 0x2F, 0x27,
+ 0x6F, 0x69, 0x76, 0xD8, 0xEC, 0xA5, 0xB2, 0x6A,
+ 0x19, 0x72, 0x1A, 0xB6, 0xE5, 0x77, 0xC6, 0x44,
+ 0x9D, 0xCA, 0x82, 0x35, 0x36, 0x5E, 0xA9, 0x25,
+ 0xFA, 0x5C, 0x24, 0x30, 0x39, 0x0E, 0x2C, 0x7D,
+ 0xE6, 0x88, 0xA0, 0x63, 0xB8, 0x6B, 0x01, 0xDD,
+ 0xDA, 0x9F, 0x45, 0x83, 0xE2, 0x7F, 0x1B, 0x56,
+ 0xAF, 0x14, 0xC3, 0x49, 0xBF, 0x78, 0x70, 0x58,
+ 0x23, 0xA3, 0xBD, 0x34, 0x47, 0x2D, 0x0A, 0xD4,
+ 0x33, 0x03, 0x1E, 0xC1, 0x87, 0xAE, 0x3C, 0x95,
+ 0xB0, 0x42, 0x91, 0xB9, 0x5A, 0x61, 0xAA, 0xCF,
+ 0xF2, 0x51, 0xA6, 0xF8, 0xDC, 0x71, 0xAB, 0x48,
+ 0x66, 0x90, 0x97, 0xC4, 0x08, 0xF9, 0xD0, 0x7B,
+ 0xDB, 0xBA, 0x8B, 0xC2, 0xC5, 0x2E, 0xF7, 0x5B,
+ 0xFF, 0x21, 0x81, 0x54, 0xD3, 0x62, 0x57, 0x4C,
+ 0x6E, 0x02, 0x98, 0xFE, 0x7E, 0xE7, 0xBC, 0x07,
+ 0x28, 0x5D, 0x86, 0xCE, 0xEA, 0x84, 0xF0, 0xE1,
+ 0x93, 0x80, 0xE9, 0xC7, 0x4A, 0xED, 0xB1, 0x26,
+ 0x89, 0x3D, 0x4F, 0xA7, 0xA1, 0xD6, 0xB5, 0x4D,
+ 0x67, 0xA4, 0x55, 0x10, 0x0F, 0xD9, 0x52, 0x32,
+ 0x96, 0xD5, 0xEB, 0x64, 0x8A, 0xC8, 0x7A, 0xBE };
+
+unsigned char table_57[256] = {
+ 0xD1, 0x9B, 0x15, 0x06, 0xB4, 0xF6, 0x97, 0xF0,
+ 0xC6, 0x5B, 0x88, 0x12, 0x25, 0xFA, 0x7B, 0x79,
+ 0xD6, 0xAB, 0xDC, 0x47, 0x85, 0x61, 0x67, 0x0B,
+ 0xF3, 0x20, 0x44, 0x53, 0x2A, 0x3B, 0x2D, 0xE8,
+ 0x17, 0x71, 0xC3, 0xB7, 0x7F, 0x35, 0xEB, 0x10,
+ 0x03, 0x0D, 0x60, 0x96, 0x27, 0xBB, 0x39, 0x50,
+ 0x95, 0x55, 0xCC, 0xD4, 0x2F, 0x51, 0xB3, 0x05,
+ 0xA5, 0xAD, 0xBC, 0x18, 0xE2, 0xAE, 0x07, 0x87,
+ 0xC4, 0x8D, 0xBE, 0x77, 0xC2, 0x16, 0xFC, 0x33,
+ 0x4C, 0x4F, 0xE6, 0xA6, 0x57, 0x9F, 0x37, 0x91,
+ 0xED, 0x4A, 0xF7, 0xB5, 0x52, 0x7C, 0xBD, 0x30,
+ 0xA0, 0x2C, 0x8C, 0xB0, 0x0C, 0xDA, 0x6F, 0x9E,
+ 0xEE, 0x43, 0x40, 0x8F, 0x8B, 0x76, 0xA4, 0x68,
+ 0xFF, 0x6D, 0x58, 0xC9, 0xF9, 0x6E, 0x3F, 0x56,
+ 0xCA, 0x49, 0xC8, 0x5D, 0xCD, 0xC7, 0x99, 0xEC,
+ 0x72, 0x38, 0x0A, 0xA9, 0xC5, 0x04, 0x64, 0xBF,
+ 0xB6, 0x29, 0x80, 0x2E, 0x19, 0x0E, 0x82, 0x45,
+ 0xBA, 0xD7, 0x1E, 0x86, 0xA8, 0xD8, 0x24, 0xDB,
+ 0xCF, 0xE1, 0x54, 0xB2, 0x3E, 0x4D, 0x90, 0x42,
+ 0x5F, 0x59, 0x0F, 0xCE, 0x8E, 0xA2, 0xA7, 0x1D,
+ 0x22, 0xFD, 0x81, 0x63, 0xE5, 0x6A, 0xE7, 0x93,
+ 0x41, 0x46, 0x66, 0x89, 0x13, 0xEA, 0x69, 0x1C,
+ 0x83, 0xF2, 0x08, 0xB8, 0x01, 0x23, 0x26, 0xFB,
+ 0x78, 0xAA, 0x31, 0x11, 0x1B, 0x98, 0xDD, 0xAC,
+ 0xB9, 0xFE, 0x94, 0x74, 0xAF, 0x32, 0xD0, 0x5A,
+ 0xA1, 0xF4, 0x6B, 0x8A, 0xE3, 0x65, 0xDE, 0xCB,
+ 0x73, 0x3D, 0xA3, 0x7E, 0xDF, 0xD2, 0x6C, 0x7A,
+ 0x36, 0xD9, 0x62, 0x4B, 0xEF, 0xC1, 0x1F, 0x00,
+ 0x34, 0xB1, 0xF8, 0xE4, 0xD5, 0x09, 0x1A, 0x9A,
+ 0x70, 0x48, 0x9D, 0xF1, 0xE0, 0x9C, 0xD3, 0x5C,
+ 0x75, 0x02, 0x2B, 0x92, 0x21, 0x7D, 0xF5, 0x5E,
+ 0x4E, 0x3C, 0x84, 0x14, 0x28, 0x3A, 0xE9, 0xC0 };
+
+unsigned char table_58[256] = {
+ 0xE9, 0x81, 0x60, 0xA7, 0x18, 0xA0, 0x0F, 0x55,
+ 0x2B, 0x52, 0xE0, 0x8B, 0x9D, 0x85, 0xD2, 0xA3,
+ 0x3F, 0x6E, 0xB1, 0xAF, 0xE3, 0x36, 0xE2, 0x19,
+ 0x56, 0xB0, 0x09, 0xB5, 0x79, 0x43, 0xE1, 0x06,
+ 0x45, 0xB6, 0xC0, 0x22, 0xEE, 0x41, 0xEC, 0x01,
+ 0x66, 0x2D, 0x87, 0x38, 0x16, 0x37, 0xFA, 0x29,
+ 0x96, 0xA4, 0xC3, 0x23, 0x59, 0x7E, 0x92, 0x78,
+ 0x10, 0x2A, 0x4C, 0x0E, 0x9B, 0x4A, 0x35, 0xF4,
+ 0x42, 0x0C, 0xD8, 0xD7, 0x24, 0x2C, 0xDD, 0x8E,
+ 0x5B, 0xF5, 0x33, 0x48, 0xEF, 0xDE, 0x4B, 0xBC,
+ 0x51, 0xAB, 0x7C, 0xE4, 0x63, 0x70, 0x9A, 0xAC,
+ 0x54, 0x1D, 0x25, 0xC5, 0xEA, 0xB3, 0x05, 0xF7,
+ 0xC1, 0x1F, 0xE8, 0x97, 0xBB, 0x32, 0x6D, 0xC7,
+ 0x28, 0x61, 0xDB, 0x4D, 0x77, 0x72, 0x65, 0x8C,
+ 0x80, 0x3A, 0x76, 0x47, 0xA8, 0x03, 0x04, 0x12,
+ 0xCE, 0xA9, 0x75, 0x3C, 0x49, 0xF8, 0x64, 0xDF,
+ 0x57, 0xA2, 0x69, 0x44, 0xAD, 0x3E, 0x4F, 0x0B,
+ 0x74, 0x67, 0xC9, 0x1A, 0x17, 0xAA, 0x02, 0x6F,
+ 0xDA, 0xF2, 0xC6, 0x27, 0x53, 0xD6, 0xFD, 0xCA,
+ 0x8D, 0x93, 0x89, 0xD5, 0x6B, 0x4E, 0x90, 0x82,
+ 0x30, 0xE7, 0xC4, 0xD9, 0x8A, 0x7F, 0xB4, 0xFC,
+ 0xCF, 0xA1, 0xAE, 0x1C, 0x39, 0x1B, 0x7B, 0x5E,
+ 0x88, 0x7D, 0xD3, 0x71, 0x2E, 0x98, 0x13, 0x8F,
+ 0xCC, 0x84, 0x73, 0xCD, 0x21, 0x0D, 0x5C, 0xA5,
+ 0x3D, 0x9E, 0x99, 0xC2, 0xF3, 0x34, 0x14, 0x62,
+ 0x46, 0x0A, 0x07, 0x08, 0xFF, 0xFB, 0xB7, 0xBF,
+ 0x5D, 0x91, 0xB8, 0x83, 0xBE, 0x94, 0xBA, 0xF9,
+ 0xEB, 0xE5, 0xCB, 0x95, 0x40, 0x31, 0xE6, 0x86,
+ 0xD4, 0xFE, 0xD0, 0x7A, 0x26, 0xB9, 0xDC, 0x2F,
+ 0xBD, 0xF0, 0x5F, 0x00, 0x9C, 0x6A, 0x5A, 0x3B,
+ 0xF1, 0xC8, 0x9F, 0xED, 0x50, 0x20, 0x15, 0x11,
+ 0x68, 0x1E, 0xF6, 0xA6, 0x6C, 0xB2, 0xD1, 0x58 };
+
+unsigned char table_59[256] = {
+ 0x4C, 0x85, 0x2B, 0x14, 0xCC, 0x4D, 0x5F, 0xD7,
+ 0xCE, 0x28, 0xC5, 0x0B, 0xA1, 0x99, 0x08, 0xDE,
+ 0x42, 0xD1, 0x82, 0x5C, 0xC9, 0x8F, 0x72, 0x12,
+ 0xCB, 0x0D, 0x04, 0xFA, 0xCD, 0xE5, 0x9A, 0x6F,
+ 0xCF, 0x92, 0xB5, 0x88, 0x87, 0xBF, 0x90, 0x7C,
+ 0xAC, 0xBE, 0x36, 0x21, 0x7D, 0x7F, 0xC7, 0x9F,
+ 0x75, 0xBB, 0x61, 0x16, 0x17, 0x63, 0xAE, 0xC4,
+ 0x23, 0x89, 0xE0, 0x37, 0x91, 0x5E, 0xC8, 0xE4,
+ 0xFD, 0xD5, 0xA2, 0xC6, 0x5A, 0xEF, 0x9B, 0xD6,
+ 0x27, 0xEE, 0x60, 0x1C, 0xDF, 0xDA, 0xF1, 0xD2,
+ 0x1E, 0x01, 0x9D, 0x44, 0x03, 0xD8, 0x11, 0x53,
+ 0x4F, 0x6C, 0x8B, 0xB7, 0x40, 0xF2, 0x79, 0x20,
+ 0x74, 0x97, 0x3E, 0x3D, 0x05, 0xD4, 0x70, 0x30,
+ 0x54, 0x59, 0xE7, 0x15, 0xE1, 0xEB, 0x71, 0x83,
+ 0xFE, 0x66, 0xB1, 0xA6, 0xF7, 0x8E, 0x6A, 0xEA,
+ 0x65, 0x7E, 0xA3, 0xCA, 0x2D, 0x4B, 0xB8, 0x9C,
+ 0x35, 0xC3, 0xB6, 0x49, 0x32, 0x25, 0xB3, 0xB0,
+ 0x76, 0xC0, 0xF5, 0x00, 0x8A, 0xAF, 0x19, 0xDB,
+ 0xDD, 0x47, 0xDC, 0x07, 0xB2, 0x4A, 0x55, 0xE6,
+ 0x69, 0xEC, 0xED, 0x06, 0x94, 0xB9, 0xA7, 0x56,
+ 0x2C, 0xAA, 0xE3, 0x22, 0x3B, 0x98, 0x77, 0x52,
+ 0x3C, 0x64, 0xF8, 0x13, 0x78, 0xFC, 0xFB, 0xF3,
+ 0xD3, 0xF9, 0x29, 0x45, 0x51, 0x8C, 0xA0, 0x38,
+ 0xD9, 0xA5, 0x62, 0x3A, 0x6E, 0xD0, 0xE8, 0x7A,
+ 0x33, 0x1D, 0xB4, 0x73, 0x02, 0xFF, 0x10, 0x80,
+ 0x6B, 0xF0, 0xA4, 0xBA, 0xF6, 0xC2, 0x0E, 0xE2,
+ 0x81, 0x43, 0x84, 0x86, 0x1F, 0x31, 0x2F, 0xA9,
+ 0x1B, 0x2A, 0x4E, 0xF4, 0x95, 0x5B, 0x3F, 0x34,
+ 0x39, 0x7B, 0x0A, 0x26, 0x6D, 0x57, 0x50, 0x09,
+ 0x9E, 0xA8, 0xBC, 0x24, 0x93, 0x67, 0x41, 0x96,
+ 0x0C, 0x46, 0xBD, 0xE9, 0x68, 0x18, 0xAB, 0x2E,
+ 0x5D, 0x1A, 0x8D, 0xC1, 0x58, 0x48, 0xAD, 0x0F };
+
+unsigned char table_60[32] = {
+ 0x1C, 0x06, 0x1E, 0x10, 0x1D, 0x05, 0x00, 0x0E,
+ 0x0C, 0x02, 0x11, 0x19, 0x15, 0x18, 0x16, 0x07,
+ 0x1F, 0x0B, 0x14, 0x01, 0x0F, 0x09, 0x0D, 0x13,
+ 0x03, 0x08, 0x12, 0x04, 0x1B, 0x0A, 0x17, 0x1A };
+
+unsigned char table_61[256] = {
+ 0xC5, 0xA6, 0xF2, 0x6B, 0x4B, 0x58, 0xE0, 0x41,
+ 0xC6, 0x2F, 0x13, 0xFE, 0xC1, 0x34, 0x3F, 0x24,
+ 0x10, 0xBF, 0x8B, 0xC9, 0x26, 0x2E, 0x68, 0xBE,
+ 0x28, 0x54, 0x93, 0x11, 0x21, 0x03, 0xFF, 0x50,
+ 0x31, 0x71, 0x2C, 0x6C, 0x91, 0x8F, 0x3B, 0x40,
+ 0x3E, 0xE5, 0xA5, 0x80, 0xEA, 0x7C, 0x9D, 0x18,
+ 0x84, 0x5A, 0x73, 0x3A, 0x33, 0x43, 0xA1, 0x47,
+ 0xB1, 0xEE, 0xFB, 0x79, 0x5E, 0xAF, 0xB9, 0x48,
+ 0x0F, 0x88, 0x65, 0x67, 0x6F, 0xDB, 0x25, 0xE4,
+ 0xB0, 0x87, 0xD0, 0x46, 0xB5, 0xB7, 0x53, 0xD4,
+ 0x1E, 0x76, 0xB4, 0x90, 0xDD, 0xA3, 0xF7, 0x57,
+ 0xD2, 0xCC, 0x5D, 0xE3, 0xB3, 0xD8, 0x5F, 0x2B,
+ 0x69, 0x4A, 0x9B, 0x39, 0x1A, 0x8D, 0x05, 0x8A,
+ 0x44, 0x15, 0xAE, 0xF3, 0xA8, 0x92, 0x02, 0xAB,
+ 0xB8, 0xDA, 0x0A, 0x0C, 0xED, 0xD7, 0x77, 0x98,
+ 0x3D, 0x19, 0x95, 0x36, 0xE7, 0x7F, 0x66, 0xEF,
+ 0x86, 0xDC, 0xCB, 0x9C, 0x63, 0xE6, 0x1D, 0x14,
+ 0x9A, 0x22, 0xBD, 0xD6, 0x89, 0x2D, 0xD1, 0xF9,
+ 0xA2, 0xDE, 0xF5, 0x5C, 0x8E, 0x2A, 0x29, 0xCA,
+ 0x7A, 0x8C, 0x38, 0x9F, 0xBB, 0xDF, 0xEC, 0x30,
+ 0x00, 0xFC, 0xAC, 0x81, 0xB2, 0xE8, 0xC0, 0xA7,
+ 0x7B, 0x07, 0x52, 0x74, 0x70, 0x0E, 0x51, 0x6A,
+ 0x62, 0x0D, 0x85, 0x1B, 0x4F, 0x96, 0x55, 0x1C,
+ 0x32, 0x6E, 0x01, 0xF6, 0x08, 0xFD, 0x17, 0x35,
+ 0xF0, 0x16, 0xC8, 0x23, 0xE9, 0x59, 0x3C, 0x37,
+ 0x5B, 0x42, 0xD3, 0x49, 0x7D, 0x83, 0x78, 0xAD,
+ 0x94, 0x9E, 0x56, 0xB6, 0xF1, 0xC3, 0x75, 0xF8,
+ 0xFA, 0x09, 0x4C, 0xD9, 0x97, 0xF4, 0x7E, 0x6D,
+ 0xBC, 0x4D, 0x64, 0xCD, 0x12, 0x99, 0x45, 0xCE,
+ 0x61, 0x20, 0x0B, 0xA0, 0x82, 0xD5, 0xE1, 0x72,
+ 0xA9, 0x1F, 0x06, 0x27, 0xC7, 0x04, 0xE2, 0xBA,
+ 0xCF, 0x60, 0xAA, 0xA4, 0xEB, 0xC4, 0x4E, 0xC2 };
+
+unsigned char table_62[256] = {
+ 0x01, 0x59, 0xEC, 0xFC, 0x51, 0xD2, 0xE4, 0x9D,
+ 0xAA, 0x61, 0xD5, 0xCA, 0x63, 0x5D, 0xCE, 0x36,
+ 0xB9, 0x49, 0x76, 0xA9, 0x14, 0x4C, 0x90, 0x28,
+ 0x66, 0x17, 0x4F, 0x1E, 0x1A, 0x47, 0x30, 0xE8,
+ 0xFD, 0x86, 0x2E, 0x7B, 0x7E, 0xCC, 0x34, 0x13,
+ 0x94, 0x45, 0x38, 0x74, 0x29, 0xB0, 0x37, 0xC3,
+ 0x26, 0x6C, 0x39, 0xA3, 0x89, 0xEB, 0xA2, 0x20,
+ 0x00, 0xE0, 0x73, 0xE7, 0xB5, 0xCB, 0xED, 0x3E,
+ 0x79, 0x09, 0xFA, 0x32, 0x54, 0xBA, 0x05, 0x96,
+ 0xDE, 0x23, 0xD0, 0xA1, 0xAB, 0xFE, 0xF2, 0x22,
+ 0xB2, 0x9B, 0x7D, 0x44, 0x12, 0x3D, 0x40, 0x82,
+ 0xA0, 0xA8, 0x33, 0xDC, 0xF7, 0xFB, 0xAC, 0x41,
+ 0x8A, 0x9C, 0x60, 0x11, 0xC8, 0xF0, 0xEA, 0x57,
+ 0x3A, 0x42, 0xCD, 0x1D, 0x3C, 0xC6, 0x97, 0x62,
+ 0x55, 0x9F, 0xF3, 0x93, 0x91, 0xDA, 0x6A, 0xE5,
+ 0x27, 0x8E, 0x4E, 0xFF, 0xA4, 0x80, 0x04, 0xE1,
+ 0x2B, 0x5E, 0xC0, 0x64, 0xC2, 0xD8, 0x46, 0x8C,
+ 0xD4, 0x0F, 0xC4, 0x43, 0xD9, 0x9E, 0x4B, 0x5C,
+ 0x0A, 0x8B, 0xBF, 0xD7, 0x7A, 0x81, 0x3B, 0x4A,
+ 0x58, 0xB6, 0x21, 0x1F, 0xC1, 0xBD, 0xB1, 0x77,
+ 0x72, 0x1C, 0x4D, 0xBC, 0xA5, 0x65, 0xC7, 0xF5,
+ 0xB4, 0x2D, 0x69, 0x71, 0xE6, 0x8F, 0xBB, 0x03,
+ 0xAF, 0xD6, 0x08, 0x75, 0xB7, 0x31, 0xF4, 0x2A,
+ 0x48, 0x70, 0x0C, 0x8D, 0xD1, 0x87, 0x2F, 0x16,
+ 0x5A, 0x5B, 0x98, 0xA6, 0xC5, 0x99, 0x50, 0x07,
+ 0xDD, 0x92, 0x25, 0x68, 0x0D, 0xBE, 0x78, 0x0B,
+ 0xAD, 0x84, 0x6B, 0x19, 0x52, 0x7C, 0xF6, 0xB3,
+ 0x56, 0x83, 0x88, 0xEE, 0x2C, 0x1B, 0x6E, 0x53,
+ 0x67, 0xE2, 0x6F, 0x15, 0x06, 0x10, 0x18, 0x85,
+ 0xF1, 0x6D, 0xF9, 0xC9, 0xAE, 0x3F, 0xB8, 0x95,
+ 0x35, 0xDF, 0xEF, 0xA7, 0x7F, 0x24, 0xF8, 0xE3,
+ 0xCF, 0xE9, 0xDB, 0xD3, 0x02, 0x9A, 0x0E, 0x5F };
+
+unsigned char table_63[256] = {
+ 0x0C, 0x02, 0xEE, 0x94, 0x2D, 0x76, 0x96, 0x75,
+ 0x21, 0xDC, 0x37, 0x03, 0xC0, 0xF7, 0xDF, 0xEF,
+ 0xB1, 0x1D, 0xCF, 0x15, 0x5A, 0xB4, 0xCC, 0x81,
+ 0x89, 0x6B, 0xA5, 0x2E, 0x6D, 0xD4, 0x08, 0x44,
+ 0x2A, 0x60, 0x50, 0xBF, 0x40, 0x7D, 0x5F, 0x64,
+ 0x93, 0x70, 0xA4, 0x7F, 0xC9, 0xEB, 0x0A, 0xF8,
+ 0x9F, 0xA8, 0xBC, 0x25, 0xE5, 0xF3, 0x1B, 0xD7,
+ 0x29, 0x13, 0x0D, 0x69, 0x20, 0x5C, 0x0F, 0x91,
+ 0x4F, 0x62, 0x06, 0x26, 0x41, 0xED, 0xDA, 0x53,
+ 0x65, 0xFF, 0xCD, 0x3F, 0xF6, 0x01, 0xCE, 0xA2,
+ 0x04, 0xDE, 0x27, 0x87, 0xBA, 0x86, 0x24, 0x78,
+ 0xAF, 0xE1, 0x3D, 0xD0, 0xC8, 0x1F, 0x4A, 0x2C,
+ 0x9A, 0xF0, 0xCB, 0xAD, 0x0B, 0x59, 0xC5, 0x58,
+ 0xEA, 0x8A, 0xA1, 0x45, 0xB7, 0x5D, 0xB5, 0x77,
+ 0x2B, 0x47, 0x05, 0x00, 0xAC, 0x61, 0xFA, 0x33,
+ 0x74, 0x31, 0xCA, 0x22, 0x42, 0x8B, 0xFE, 0x09,
+ 0xB2, 0x6E, 0x1A, 0xBE, 0xAA, 0x7B, 0xEC, 0xF4,
+ 0x51, 0x66, 0x28, 0x12, 0xFC, 0x5E, 0x67, 0xF5,
+ 0xB9, 0x82, 0x90, 0x8E, 0x8D, 0x17, 0xE7, 0xE8,
+ 0xB0, 0xC3, 0x16, 0xA0, 0x4B, 0xB6, 0xFB, 0x7E,
+ 0xC4, 0x85, 0x4C, 0x1E, 0xC7, 0x39, 0x4E, 0xA9,
+ 0xE3, 0x4D, 0x32, 0x72, 0x35, 0x80, 0xE0, 0x34,
+ 0xB8, 0x73, 0x98, 0x49, 0x92, 0x30, 0xD5, 0xD2,
+ 0xA3, 0x54, 0x7A, 0x84, 0x8F, 0x6C, 0xFD, 0x43,
+ 0x3A, 0x36, 0x3B, 0xD9, 0x48, 0x6A, 0x14, 0x79,
+ 0xD1, 0x57, 0x88, 0xDB, 0xE4, 0x9B, 0xF9, 0x99,
+ 0x10, 0x71, 0xC1, 0x68, 0x9E, 0x11, 0xAB, 0xBD,
+ 0x7C, 0x3E, 0x3C, 0x18, 0x9D, 0x97, 0xF2, 0xE6,
+ 0xA6, 0xF1, 0x46, 0xC2, 0x19, 0xBB, 0x52, 0xD8,
+ 0x95, 0xD3, 0x23, 0xAE, 0x07, 0x2F, 0xE9, 0x63,
+ 0x1C, 0x55, 0x6F, 0x9C, 0x56, 0x38, 0xC6, 0x5B,
+ 0x8C, 0xE2, 0x83, 0xA7, 0xD6, 0x0E, 0xB3, 0xDD };
+
+unsigned char table_64[32] = {
+ 0x03, 0x05, 0x0D, 0x09, 0x1A, 0x16, 0x08, 0x10,
+ 0x06, 0x1E, 0x1C, 0x15, 0x02, 0x04, 0x17, 0x0C,
+ 0x18, 0x0B, 0x19, 0x11, 0x1B, 0x14, 0x13, 0x0A,
+ 0x0E, 0x00, 0x1D, 0x1F, 0x01, 0x0F, 0x07, 0x12 };
+
+unsigned char table_65[32] = {
+ 0x01, 0x0A, 0x1E, 0x14, 0x10, 0x1D, 0x0D, 0x17,
+ 0x0E, 0x0C, 0x0F, 0x12, 0x04, 0x1A, 0x05, 0x02,
+ 0x08, 0x1C, 0x09, 0x1F, 0x0B, 0x13, 0x19, 0x1B,
+ 0x11, 0x00, 0x16, 0x06, 0x03, 0x18, 0x15, 0x07 };
+
+unsigned char table_66[32] = {
+ 0x1C, 0x18, 0x0C, 0x09, 0x05, 0x03, 0x15, 0x12,
+ 0x0D, 0x02, 0x08, 0x0E, 0x19, 0x07, 0x13, 0x17,
+ 0x1E, 0x1D, 0x1F, 0x11, 0x06, 0x0A, 0x0B, 0x14,
+ 0x0F, 0x10, 0x01, 0x1B, 0x00, 0x04, 0x1A, 0x16 };
+
+unsigned char table_67[256] = {
+ 0x6B, 0x49, 0xC8, 0x86, 0xFF, 0xC0, 0x5D, 0xEF,
+ 0xF7, 0x06, 0xE0, 0x98, 0xA9, 0x72, 0x71, 0xD5,
+ 0xBA, 0x7F, 0x10, 0xD1, 0xBE, 0x41, 0x9C, 0x40,
+ 0x28, 0x8E, 0xE5, 0x74, 0x47, 0x9E, 0x3E, 0x7C,
+ 0xB5, 0xCD, 0x3F, 0x20, 0xF2, 0xA6, 0xDC, 0x97,
+ 0x32, 0x6D, 0x52, 0xF5, 0x16, 0x05, 0xFE, 0x04,
+ 0x3D, 0x53, 0x50, 0x23, 0x39, 0x77, 0x08, 0x60,
+ 0x75, 0x18, 0x4A, 0xC6, 0xBB, 0xE7, 0xF1, 0xAB,
+ 0xEB, 0x88, 0xB6, 0x82, 0x6E, 0x91, 0xF3, 0x34,
+ 0x3A, 0x42, 0x1A, 0xDF, 0xA1, 0xB3, 0x92, 0xBF,
+ 0xB7, 0x00, 0xD4, 0xDE, 0x31, 0xF0, 0x1C, 0xDA,
+ 0x4F, 0x61, 0x67, 0x2C, 0x07, 0xF9, 0x15, 0xA4,
+ 0x7A, 0x26, 0x45, 0x2A, 0x12, 0x9F, 0xF4, 0x14,
+ 0x8C, 0x90, 0xFC, 0xC5, 0x4B, 0x87, 0xE2, 0xC7,
+ 0xD0, 0x8A, 0xE8, 0xDD, 0xEE, 0x3C, 0x2F, 0x22,
+ 0x6A, 0x54, 0x37, 0x9B, 0x84, 0x25, 0x8F, 0xE3,
+ 0xD7, 0xD8, 0x4E, 0xAD, 0x0F, 0x4C, 0x56, 0xA2,
+ 0xD3, 0xB0, 0x73, 0x0B, 0xAE, 0xEA, 0x1D, 0x01,
+ 0x36, 0xB4, 0x2D, 0xC4, 0x19, 0x58, 0x1E, 0x62,
+ 0xE9, 0xB2, 0x5B, 0x5A, 0xBD, 0xD6, 0x65, 0x94,
+ 0x9A, 0x55, 0xCC, 0x99, 0x1B, 0x85, 0x2B, 0xBC,
+ 0x8D, 0x46, 0x81, 0xB8, 0xA3, 0x29, 0x5F, 0x35,
+ 0x5C, 0xB1, 0x1F, 0x13, 0x17, 0xCB, 0x51, 0x02,
+ 0x09, 0x7E, 0xA7, 0x69, 0x6F, 0x95, 0x30, 0x7B,
+ 0xCA, 0x48, 0xAF, 0xAA, 0x0E, 0x44, 0x38, 0xB9,
+ 0x0D, 0x11, 0xA0, 0xD9, 0x0C, 0xDB, 0xF8, 0x68,
+ 0x33, 0x79, 0x59, 0x66, 0x4D, 0x03, 0xE1, 0x89,
+ 0xE4, 0x3B, 0x78, 0xC2, 0x64, 0x6C, 0x27, 0xC9,
+ 0xCF, 0xAC, 0xED, 0xFA, 0x5E, 0x2E, 0x76, 0x57,
+ 0x93, 0xEC, 0x80, 0xA8, 0xE6, 0xCE, 0xC1, 0xA5,
+ 0x9D, 0xD2, 0xC3, 0x0A, 0x7D, 0x70, 0xF6, 0x63,
+ 0x24, 0x43, 0x21, 0x83, 0xFB, 0xFD, 0x8B, 0x96 };
+
+unsigned char table_68[256] = {
+ 0x93, 0xFF, 0x83, 0x70, 0x12, 0x2D, 0x1C, 0xD6,
+ 0xF9, 0xEE, 0xCF, 0x94, 0x7B, 0xB5, 0xA4, 0x84,
+ 0x99, 0xF7, 0x67, 0x32, 0xFC, 0x8A, 0xE3, 0xE4,
+ 0xCE, 0xC6, 0x77, 0x7E, 0xDA, 0x42, 0x85, 0xF0,
+ 0x7D, 0x48, 0x28, 0x79, 0xDE, 0x5B, 0xE2, 0x0F,
+ 0x75, 0xC5, 0x2C, 0x4F, 0xF3, 0xEC, 0x14, 0x10,
+ 0x9C, 0x6E, 0x59, 0x4A, 0x20, 0x34, 0xA3, 0x89,
+ 0xE0, 0x4E, 0x52, 0x88, 0x81, 0x5F, 0x6F, 0x71,
+ 0x17, 0x3B, 0x21, 0xB4, 0xCB, 0x9B, 0x18, 0x13,
+ 0xE8, 0xE1, 0x02, 0x2E, 0xED, 0x00, 0xA7, 0x1B,
+ 0x06, 0xF4, 0x27, 0xDC, 0x35, 0x2F, 0x08, 0x9D,
+ 0x7C, 0xC0, 0x36, 0xA6, 0x6B, 0xDF, 0x4C, 0xBC,
+ 0xFE, 0xDB, 0xA5, 0xA8, 0x8D, 0x73, 0x7F, 0xC7,
+ 0x8E, 0x60, 0x31, 0x61, 0x4B, 0x29, 0xD7, 0xE9,
+ 0xBD, 0xAB, 0xCC, 0xFA, 0xD9, 0xEF, 0xC2, 0xD4,
+ 0x19, 0x11, 0x15, 0xC9, 0xB1, 0xD5, 0x64, 0x97,
+ 0xE7, 0x8F, 0x05, 0x44, 0xF8, 0xF1, 0x58, 0x47,
+ 0x2A, 0x03, 0x1F, 0xAF, 0x0D, 0x04, 0x23, 0xB8,
+ 0x24, 0x51, 0xB2, 0x54, 0x41, 0x53, 0x5C, 0xAE,
+ 0xB7, 0xB3, 0xB6, 0x3D, 0x37, 0x39, 0x55, 0xBF,
+ 0x0B, 0x7A, 0x57, 0x3C, 0x0E, 0x40, 0x6A, 0xF5,
+ 0x72, 0xDD, 0xBB, 0x8B, 0xAA, 0x46, 0xA0, 0x30,
+ 0x56, 0x78, 0x38, 0xBA, 0x9E, 0x92, 0x87, 0xFB,
+ 0x66, 0x90, 0x1E, 0xB9, 0x96, 0x65, 0xA2, 0x50,
+ 0x1D, 0xC3, 0x26, 0x22, 0xD0, 0x0A, 0x43, 0xF2,
+ 0xB0, 0xEB, 0xAC, 0x62, 0x98, 0x3F, 0xD3, 0x69,
+ 0xA1, 0x9F, 0x16, 0x95, 0xE6, 0xF6, 0x2B, 0x25,
+ 0x1A, 0xD2, 0xBE, 0x09, 0x5D, 0x45, 0xC4, 0xFD,
+ 0x5A, 0x07, 0x0C, 0x82, 0x3E, 0x49, 0x74, 0x6C,
+ 0x68, 0x5E, 0xCA, 0xEA, 0xCD, 0x9A, 0xAD, 0xD1,
+ 0x33, 0x86, 0x76, 0x80, 0xE5, 0xC8, 0xD8, 0xA9,
+ 0x8C, 0x6D, 0x91, 0x63, 0x3A, 0x4D, 0xC1, 0x01 };
+
+unsigned char table_69[256] = {
+ 0x21, 0x6B, 0x9B, 0xAE, 0x11, 0x5A, 0x91, 0xC2,
+ 0x47, 0x8E, 0x87, 0x86, 0x4F, 0xFC, 0x8F, 0x66,
+ 0x97, 0x2F, 0x61, 0x9C, 0x5B, 0x4C, 0xB3, 0x14,
+ 0x77, 0x48, 0x62, 0xE1, 0x54, 0x64, 0xDD, 0xCD,
+ 0x30, 0xB7, 0x2D, 0xD2, 0xC3, 0xC0, 0x0B, 0xD8,
+ 0x53, 0x98, 0x16, 0x56, 0x7A, 0x35, 0x50, 0xD9,
+ 0xE8, 0x2C, 0x32, 0x55, 0x17, 0x5D, 0x79, 0xEB,
+ 0xC8, 0x75, 0x67, 0xE2, 0x4B, 0xBA, 0xFE, 0x57,
+ 0x10, 0xF4, 0x70, 0x2A, 0xBB, 0xA6, 0x72, 0x36,
+ 0xAF, 0x8D, 0xAB, 0x90, 0xE3, 0x2B, 0xB2, 0x26,
+ 0x93, 0x01, 0xBD, 0x71, 0xF9, 0x05, 0xC7, 0x80,
+ 0x29, 0xCC, 0x3B, 0x22, 0xF2, 0x12, 0x81, 0x34,
+ 0xF6, 0x1A, 0x8B, 0xDF, 0x28, 0x46, 0x9E, 0x6A,
+ 0x23, 0x85, 0x74, 0xE7, 0xE6, 0x52, 0xA0, 0x49,
+ 0xF0, 0x19, 0x25, 0xAC, 0x78, 0x42, 0xD6, 0xA2,
+ 0x37, 0x65, 0x4D, 0x94, 0x02, 0x6F, 0xB4, 0xC6,
+ 0x99, 0xD3, 0x9A, 0x33, 0xB8, 0x00, 0xCA, 0xE4,
+ 0x45, 0xAD, 0x1B, 0x6C, 0x03, 0xA8, 0x07, 0x8A,
+ 0x60, 0x69, 0xFF, 0xF7, 0xA7, 0x27, 0x95, 0xF5,
+ 0x82, 0xCB, 0xEC, 0xED, 0x4E, 0xFB, 0xA4, 0x59,
+ 0xDA, 0xCF, 0x2E, 0x20, 0xFA, 0x31, 0xD1, 0xEA,
+ 0x4A, 0xE9, 0x5E, 0xA9, 0xA1, 0x08, 0x1C, 0x96,
+ 0x38, 0xB9, 0xEE, 0x7F, 0xAA, 0xF1, 0x7D, 0x3A,
+ 0xA5, 0x43, 0xC5, 0xE0, 0x24, 0x39, 0x0D, 0xDE,
+ 0xB0, 0xF8, 0xBE, 0x58, 0x7E, 0x51, 0xD4, 0x89,
+ 0x15, 0x40, 0x3E, 0xB1, 0x1F, 0x5F, 0x68, 0x63,
+ 0x84, 0x3D, 0x88, 0xBC, 0x41, 0xEF, 0xB5, 0xBF,
+ 0x06, 0x6E, 0x9D, 0x3F, 0x0E, 0x76, 0x5C, 0xDC,
+ 0x13, 0xF3, 0xE5, 0x8C, 0x7C, 0x04, 0x0A, 0xD5,
+ 0x18, 0xC4, 0x44, 0x09, 0xC9, 0x1D, 0x9F, 0xFD,
+ 0xD0, 0x0F, 0x6D, 0xD7, 0x92, 0x7B, 0x0C, 0xA3,
+ 0x73, 0xDB, 0xB6, 0x83, 0xCE, 0x1E, 0xC1, 0x3C };
+
+unsigned char table_70[256] = {
+ 0x54, 0x23, 0xF1, 0x09, 0x9D, 0xEB, 0x26, 0xD9,
+ 0x6C, 0xC1, 0xBC, 0x3D, 0x6E, 0xB0, 0x5F, 0xE2,
+ 0x59, 0x4D, 0x95, 0xFA, 0xD8, 0x29, 0xAA, 0x8E,
+ 0xF5, 0xEF, 0x43, 0x76, 0xFD, 0x0D, 0x4F, 0xAD,
+ 0xB7, 0xFC, 0xA8, 0x9F, 0x62, 0xC2, 0x7B, 0x10,
+ 0x0B, 0xF2, 0x73, 0xA9, 0x46, 0x4C, 0x53, 0xD7,
+ 0x0A, 0x50, 0x89, 0x63, 0x48, 0xD6, 0xA2, 0x44,
+ 0xE6, 0x8D, 0x69, 0x2C, 0xF9, 0xC0, 0x35, 0x06,
+ 0x66, 0x21, 0x9E, 0xD2, 0x98, 0xF7, 0x9B, 0xE7,
+ 0x12, 0xB8, 0xA5, 0xBA, 0xE0, 0x79, 0x71, 0x7E,
+ 0x8C, 0x24, 0xED, 0x7C, 0x60, 0x81, 0xC3, 0x5C,
+ 0x2B, 0xE5, 0xEE, 0xB5, 0xA4, 0x05, 0x03, 0x34,
+ 0x16, 0x2A, 0xA3, 0x2D, 0x3F, 0xDF, 0x07, 0x5B,
+ 0xAE, 0x47, 0x61, 0x08, 0x18, 0xDB, 0x6D, 0x3C,
+ 0x96, 0xD5, 0xAB, 0x78, 0x94, 0x45, 0x20, 0x9A,
+ 0xE4, 0x13, 0x68, 0xDD, 0xDE, 0x31, 0x14, 0x57,
+ 0x02, 0x52, 0x56, 0x1C, 0x1B, 0xE9, 0xD0, 0xA1,
+ 0x22, 0x64, 0xB2, 0x7A, 0xCF, 0x5D, 0x00, 0x0F,
+ 0xF8, 0x5E, 0x36, 0x58, 0x40, 0xAF, 0x19, 0x32,
+ 0x2E, 0xB3, 0x72, 0xBE, 0xB9, 0xD3, 0xCD, 0x7D,
+ 0x4A, 0x1D, 0x33, 0x2F, 0xAC, 0x27, 0x41, 0xE8,
+ 0x55, 0xCB, 0x0E, 0x5A, 0x77, 0xFB, 0x8B, 0x86,
+ 0x75, 0x8A, 0x51, 0xEC, 0xDA, 0xC6, 0xA6, 0xCC,
+ 0x91, 0x4B, 0x11, 0xF6, 0xEA, 0xD1, 0xB6, 0x4E,
+ 0x82, 0x04, 0x92, 0x30, 0xF4, 0x25, 0x88, 0x1E,
+ 0x9C, 0xA0, 0xC8, 0x6A, 0x93, 0x87, 0x1F, 0xB4,
+ 0xB1, 0x8F, 0x65, 0xCA, 0xFE, 0xFF, 0x97, 0x15,
+ 0x99, 0x28, 0x80, 0x42, 0x70, 0x85, 0x0C, 0x3B,
+ 0xBD, 0xE1, 0xA7, 0x17, 0xC9, 0x3A, 0xBB, 0x6B,
+ 0x37, 0xF0, 0xC5, 0x39, 0x6F, 0x01, 0x83, 0x67,
+ 0x74, 0xCE, 0xDC, 0x90, 0x3E, 0xF3, 0x7F, 0xC4,
+ 0x49, 0x84, 0x38, 0xC7, 0xE3, 0xD4, 0x1A, 0xBF };
+
+unsigned char table_71[32] = {
+ 0x17, 0x13, 0x0E, 0x1A, 0x0D, 0x18, 0x19, 0x10,
+ 0x14, 0x11, 0x16, 0x05, 0x04, 0x00, 0x12, 0x0A,
+ 0x02, 0x07, 0x03, 0x0B, 0x09, 0x1F, 0x1C, 0x0F,
+ 0x0C, 0x06, 0x1B, 0x08, 0x1D, 0x01, 0x15, 0x1E };
+
+unsigned char table_72[256] = {
+ 0xC9, 0xA7, 0x1B, 0xEC, 0x2B, 0x8B, 0xB0, 0xEB,
+ 0x7F, 0x39, 0x25, 0xD9, 0x1D, 0xD5, 0x67, 0xA0,
+ 0xB3, 0xAC, 0x3B, 0xC8, 0x82, 0xC0, 0xE3, 0x9E,
+ 0x4C, 0x9B, 0xAF, 0xFD, 0x91, 0x86, 0x5F, 0x92,
+ 0xB4, 0x42, 0x3C, 0x45, 0x12, 0xC4, 0xE2, 0xE1,
+ 0x6C, 0x1F, 0xC6, 0x40, 0x93, 0x2A, 0xC2, 0x72,
+ 0x2E, 0x14, 0x51, 0xA5, 0x70, 0xBD, 0xA2, 0xC7,
+ 0x7D, 0xF1, 0x9F, 0x64, 0xC1, 0xF7, 0x80, 0xFF,
+ 0x50, 0x49, 0x8C, 0x66, 0x13, 0x48, 0x6A, 0x0A,
+ 0x26, 0x94, 0x83, 0x1E, 0x84, 0xBB, 0x57, 0x27,
+ 0x44, 0x5B, 0x62, 0xF6, 0x09, 0x4F, 0x77, 0x76,
+ 0x2D, 0x7E, 0xCD, 0x0B, 0x24, 0xFE, 0x81, 0xB8,
+ 0x21, 0x85, 0xCF, 0xA8, 0x75, 0x56, 0x37, 0x17,
+ 0xAA, 0x23, 0xE5, 0xE8, 0x9A, 0x9D, 0x2F, 0x04,
+ 0x31, 0x4A, 0x7C, 0xFC, 0xD6, 0xE4, 0x29, 0xC3,
+ 0xFB, 0x36, 0x1C, 0x0C, 0xCE, 0xEE, 0x0D, 0xF3,
+ 0x46, 0xF8, 0x41, 0x0E, 0x68, 0xAB, 0x2C, 0x69,
+ 0x96, 0x90, 0x28, 0xED, 0x02, 0x63, 0x07, 0xAD,
+ 0xB2, 0xDC, 0x05, 0xE6, 0x78, 0x03, 0xA4, 0x7A,
+ 0x5C, 0x52, 0x95, 0x5D, 0x88, 0x01, 0xDF, 0x35,
+ 0x5E, 0xB6, 0x06, 0x4D, 0x15, 0x89, 0x59, 0x3F,
+ 0xF0, 0xA1, 0xA3, 0x99, 0x19, 0xEA, 0xDB, 0xE0,
+ 0x6B, 0x71, 0x6E, 0xB7, 0x65, 0x54, 0x9C, 0xBC,
+ 0x98, 0xDD, 0x4B, 0x60, 0x3D, 0xBF, 0xF5, 0xD1,
+ 0xD7, 0xF9, 0x55, 0x61, 0xA9, 0xB1, 0x6D, 0xDE,
+ 0x79, 0xAE, 0x1A, 0x34, 0x3A, 0x4E, 0xCB, 0x38,
+ 0xBA, 0x97, 0x00, 0x74, 0xEF, 0xD8, 0x18, 0x33,
+ 0x7B, 0xFA, 0x22, 0x32, 0x20, 0xCA, 0x8A, 0xBE,
+ 0xA6, 0x43, 0x11, 0x10, 0xD0, 0xD3, 0x87, 0x73,
+ 0x6F, 0xF4, 0x8D, 0xCC, 0x30, 0x0F, 0x16, 0xDA,
+ 0xB5, 0xC5, 0xD4, 0x47, 0x8E, 0xE7, 0x58, 0x8F,
+ 0x08, 0x53, 0xF2, 0xB9, 0x5A, 0x3E, 0xE9, 0xD2 };
+
+unsigned char table_73[256] = {
+ 0x36, 0x37, 0xED, 0xD8, 0xBF, 0xD7, 0x12, 0xB7,
+ 0x40, 0x32, 0x19, 0x4A, 0x44, 0x2A, 0xCE, 0xA5,
+ 0x29, 0x13, 0x43, 0x51, 0x5C, 0xD0, 0x76, 0x6E,
+ 0x41, 0xD6, 0xE2, 0x4F, 0xB8, 0x27, 0x2E, 0xCF,
+ 0xD9, 0xE0, 0x69, 0xC0, 0x59, 0x77, 0x62, 0x6F,
+ 0x53, 0xE7, 0x93, 0xD4, 0xAD, 0xC8, 0x4C, 0xC2,
+ 0x2C, 0xBE, 0xAA, 0xA0, 0x22, 0x78, 0x14, 0xB3,
+ 0xB0, 0xEA, 0xBA, 0x9A, 0x33, 0x1B, 0x31, 0x6C,
+ 0xFC, 0x0A, 0x0B, 0xA1, 0xE4, 0x75, 0x7C, 0xE3,
+ 0x65, 0x21, 0xA9, 0xA4, 0x4E, 0x3C, 0x5F, 0x39,
+ 0x74, 0xA2, 0x9E, 0x03, 0x70, 0xD2, 0xFD, 0x1D,
+ 0x25, 0x72, 0x73, 0x8E, 0x7B, 0xB2, 0x6A, 0x92,
+ 0x81, 0xF3, 0xF0, 0x46, 0x08, 0x85, 0xE6, 0x30,
+ 0x05, 0x7E, 0xEC, 0x0D, 0xDD, 0x42, 0x2F, 0x5B,
+ 0xB9, 0xCB, 0x84, 0x0C, 0x16, 0xC7, 0x24, 0xFA,
+ 0xF9, 0x8F, 0x20, 0xAC, 0x10, 0x55, 0xC3, 0x1A,
+ 0x8B, 0x94, 0x3D, 0xDB, 0xC9, 0x04, 0xB5, 0xCC,
+ 0xC6, 0x98, 0xB6, 0x8D, 0x0F, 0x3A, 0x06, 0x4B,
+ 0xEF, 0x35, 0x68, 0x3F, 0xEE, 0xE5, 0x63, 0xC5,
+ 0x60, 0x88, 0x52, 0x2D, 0x6D, 0xAB, 0xCD, 0xC4,
+ 0x1F, 0xF4, 0xCA, 0x67, 0x7D, 0x1C, 0xDA, 0x34,
+ 0xDE, 0x86, 0xAE, 0xF1, 0x61, 0x09, 0xF5, 0xF6,
+ 0x49, 0xE9, 0xF2, 0x48, 0x1E, 0xD3, 0x56, 0x18,
+ 0x9B, 0xB1, 0x57, 0x9D, 0xBB, 0x5E, 0xAF, 0x87,
+ 0x9F, 0x8A, 0xC1, 0x79, 0xA7, 0xA8, 0xFB, 0xDC,
+ 0x47, 0x3E, 0x97, 0x80, 0x91, 0xA6, 0x7A, 0xA3,
+ 0x9C, 0x11, 0x02, 0x2B, 0x58, 0xD1, 0xF7, 0x00,
+ 0x83, 0x01, 0xE8, 0xFE, 0x50, 0x23, 0x66, 0x4D,
+ 0xD5, 0x82, 0x89, 0x3B, 0xEB, 0xE1, 0xF8, 0x5A,
+ 0x15, 0x7F, 0x8C, 0x17, 0x96, 0x28, 0x5D, 0x64,
+ 0x26, 0x38, 0x71, 0x0E, 0x45, 0xDF, 0xB4, 0x99,
+ 0xFF, 0x90, 0x6B, 0xBC, 0x54, 0x95, 0xBD, 0x07 };
+
+unsigned char table_74[256] = {
+ 0xA7, 0xCF, 0x99, 0x1A, 0x13, 0xC7, 0xE9, 0xC4,
+ 0xB6, 0x0E, 0x15, 0x09, 0xFF, 0xDF, 0xBE, 0x03,
+ 0xAD, 0xF1, 0xB0, 0x3C, 0x4A, 0x9B, 0xF5, 0x12,
+ 0xA1, 0x2C, 0xDB, 0x51, 0x5E, 0x6F, 0xE6, 0x49,
+ 0x27, 0xBB, 0xAE, 0x56, 0xC0, 0x0C, 0x77, 0x60,
+ 0x5B, 0x69, 0xA2, 0xF0, 0x24, 0x8E, 0xE1, 0xA4,
+ 0xBC, 0x9F, 0x50, 0xD4, 0x61, 0x19, 0x67, 0x00,
+ 0x7B, 0xAB, 0xDD, 0x26, 0xCD, 0x6C, 0xE8, 0xA8,
+ 0x7A, 0x93, 0xEF, 0x20, 0x52, 0x1F, 0x1B, 0x46,
+ 0x25, 0x3B, 0x1E, 0x65, 0xC2, 0xF9, 0x10, 0xB2,
+ 0xB3, 0xD9, 0x21, 0xD2, 0x11, 0x94, 0xE2, 0xFC,
+ 0x38, 0x9E, 0x36, 0x87, 0xAA, 0x53, 0x45, 0x68,
+ 0x2B, 0xE7, 0x07, 0xFA, 0xD3, 0x8D, 0x3F, 0x17,
+ 0xC1, 0x06, 0x72, 0x62, 0x8C, 0x55, 0x73, 0x8A,
+ 0xC9, 0x2E, 0x5A, 0x7D, 0x02, 0x6D, 0xF8, 0x4B,
+ 0xE4, 0xBF, 0xEC, 0xB7, 0x31, 0xDC, 0xF4, 0xB8,
+ 0x47, 0x64, 0x0A, 0x33, 0x48, 0xAC, 0xFB, 0x05,
+ 0x3E, 0x34, 0x1C, 0x97, 0x1D, 0x63, 0x37, 0x2D,
+ 0xB1, 0x92, 0xED, 0x9D, 0x4C, 0xD5, 0x4E, 0x9A,
+ 0x0D, 0x79, 0x0F, 0xBD, 0x95, 0xBA, 0x08, 0x2A,
+ 0xC6, 0x7E, 0x88, 0xCB, 0xA6, 0x29, 0x70, 0x35,
+ 0x66, 0xCA, 0x89, 0x75, 0x6A, 0x4F, 0xB5, 0x6B,
+ 0x74, 0xDE, 0x01, 0x04, 0x81, 0x91, 0x90, 0x18,
+ 0x32, 0x0B, 0x7F, 0x44, 0xB4, 0xAF, 0xF2, 0xEB,
+ 0x22, 0xFD, 0x14, 0xA0, 0xFE, 0x8B, 0xB9, 0x16,
+ 0x86, 0xE3, 0xD7, 0xDA, 0xC5, 0x3A, 0x41, 0x83,
+ 0xD1, 0x28, 0x54, 0x30, 0xE0, 0x40, 0xA5, 0x57,
+ 0x8F, 0x84, 0xD6, 0x96, 0x39, 0xE5, 0x42, 0x80,
+ 0xA9, 0x58, 0xCE, 0x5D, 0xEE, 0x5F, 0xA3, 0xD0,
+ 0xC8, 0x59, 0x43, 0x4D, 0x5C, 0xF7, 0xCC, 0x76,
+ 0x6E, 0xF3, 0x23, 0x3D, 0x85, 0x82, 0x78, 0xF6,
+ 0x2F, 0xD8, 0xC3, 0x7C, 0x9C, 0x98, 0xEA, 0x71 };
+
+unsigned char table_75[256] = {
+ 0xE7, 0xA5, 0x30, 0xE1, 0x9D, 0x81, 0xBE, 0x83,
+ 0xB2, 0x1E, 0xE4, 0x69, 0x2F, 0x2B, 0x0D, 0xEB,
+ 0x7C, 0x59, 0x2D, 0xAA, 0x01, 0x0C, 0xDB, 0xED,
+ 0xC4, 0xEE, 0x5D, 0x38, 0x72, 0xD8, 0x70, 0xCE,
+ 0x0B, 0xF6, 0x7F, 0x48, 0x26, 0x9E, 0xA3, 0x44,
+ 0xD6, 0xCF, 0x0F, 0x6B, 0xFD, 0x23, 0x98, 0xAB,
+ 0x11, 0xD4, 0x92, 0x91, 0x5E, 0x08, 0x4D, 0xC6,
+ 0xF0, 0xA8, 0x7E, 0x8A, 0x1D, 0xA1, 0x97, 0x76,
+ 0x3E, 0x64, 0x07, 0x24, 0xDE, 0x75, 0xA4, 0xCC,
+ 0x1A, 0x04, 0x4B, 0x6C, 0xFA, 0xB0, 0xC7, 0x35,
+ 0xE2, 0x56, 0x61, 0xA0, 0xE9, 0x27, 0xDF, 0xC3,
+ 0xE5, 0xF4, 0x8D, 0xB4, 0xD3, 0x52, 0xD7, 0x49,
+ 0xCD, 0x31, 0x6E, 0x3F, 0x4E, 0x6A, 0x5B, 0x65,
+ 0xCA, 0x14, 0x71, 0x53, 0xD9, 0x47, 0x28, 0x7D,
+ 0x17, 0x06, 0x5C, 0xFE, 0xBA, 0xB8, 0xAC, 0x15,
+ 0xE8, 0xE0, 0x9A, 0xDD, 0x1F, 0xBC, 0x95, 0x42,
+ 0xCB, 0x58, 0x00, 0x85, 0xD5, 0x62, 0xC9, 0xB6,
+ 0x05, 0x80, 0x4C, 0x3C, 0x1C, 0xF5, 0x03, 0xF8,
+ 0x96, 0x77, 0x02, 0x19, 0xF2, 0xFB, 0x5F, 0xC2,
+ 0xAE, 0x60, 0x1B, 0xAD, 0x8F, 0xC1, 0x33, 0xA6,
+ 0x20, 0xBF, 0xA7, 0xC8, 0x74, 0x18, 0x90, 0xE3,
+ 0x68, 0x09, 0x7A, 0x79, 0xB5, 0xDA, 0xF3, 0x0E,
+ 0x66, 0x84, 0xB3, 0xBB, 0xE6, 0xF7, 0xB7, 0x7B,
+ 0x39, 0x4A, 0x12, 0x4F, 0xC5, 0x41, 0x54, 0xD0,
+ 0xFF, 0x87, 0x63, 0x40, 0x99, 0x21, 0x29, 0xD2,
+ 0x3D, 0x37, 0x3A, 0x93, 0xFC, 0x25, 0xF1, 0xD1,
+ 0x2C, 0x6D, 0x8C, 0x5A, 0x8E, 0x9B, 0xBD, 0xAF,
+ 0x10, 0x55, 0xF9, 0x9F, 0x43, 0x0A, 0x50, 0x16,
+ 0x57, 0xB1, 0xC0, 0x73, 0x82, 0xEF, 0x88, 0x6F,
+ 0xEA, 0x2A, 0xEC, 0x2E, 0x86, 0x45, 0x51, 0x22,
+ 0xA9, 0x34, 0x94, 0x3B, 0xB9, 0x9C, 0xA2, 0x13,
+ 0x89, 0x46, 0x78, 0xDC, 0x32, 0x8B, 0x67, 0x36 };
+
+unsigned char table_76[256] = {
+ 0x3D, 0x66, 0x40, 0xC5, 0x1D, 0xF5, 0xE7, 0xB7,
+ 0x2C, 0x23, 0x09, 0xC2, 0x68, 0xE6, 0xD3, 0x8D,
+ 0x35, 0x94, 0x93, 0xF0, 0x43, 0x97, 0x2B, 0x4B,
+ 0x1A, 0xEB, 0x00, 0x4C, 0x6F, 0xE4, 0x92, 0xEA,
+ 0xB8, 0xA3, 0xA6, 0xEC, 0x11, 0x5E, 0x61, 0x81,
+ 0xE1, 0x48, 0xC9, 0xCB, 0xDB, 0x2E, 0x3B, 0xED,
+ 0x36, 0x52, 0x3A, 0xD2, 0x4F, 0x4E, 0x22, 0x96,
+ 0x57, 0x2D, 0x62, 0x53, 0xCF, 0xD9, 0x5B, 0x9F,
+ 0x8E, 0x78, 0xC6, 0x07, 0x7D, 0xA1, 0x02, 0xB4,
+ 0xF4, 0xB6, 0x34, 0x98, 0xDA, 0xA9, 0xD4, 0x54,
+ 0x99, 0x82, 0x0A, 0xD8, 0x88, 0x5D, 0x3C, 0xD0,
+ 0xAB, 0x31, 0xFB, 0x03, 0x17, 0x46, 0xE8, 0xE2,
+ 0xA4, 0xFF, 0xB0, 0xAA, 0xAD, 0x7C, 0x55, 0x49,
+ 0x75, 0x6B, 0x10, 0x24, 0xC0, 0x04, 0xB1, 0xBF,
+ 0x6A, 0xF6, 0x15, 0xEF, 0x5C, 0x60, 0x27, 0x3E,
+ 0x38, 0x63, 0xC1, 0x76, 0xFD, 0x84, 0xE0, 0xCD,
+ 0xFE, 0x30, 0xCE, 0xBB, 0xDC, 0x1E, 0x1B, 0xBC,
+ 0xB5, 0xE9, 0x9E, 0x8F, 0x0D, 0x3F, 0x91, 0x19,
+ 0x28, 0x37, 0x26, 0x42, 0x08, 0x9A, 0x0C, 0x83,
+ 0x90, 0x6D, 0x74, 0x65, 0xF2, 0x4A, 0xDE, 0x8B,
+ 0x67, 0x0E, 0x8C, 0x5F, 0xF9, 0x7F, 0x5A, 0x86,
+ 0x69, 0x45, 0x44, 0xD5, 0xF7, 0xE5, 0x8A, 0xA8,
+ 0xC8, 0x7E, 0x05, 0x64, 0xEE, 0x79, 0xBE, 0x7A,
+ 0x14, 0xD6, 0x50, 0x18, 0x25, 0xBD, 0x85, 0xE3,
+ 0xA2, 0x70, 0xCC, 0x59, 0x71, 0x77, 0xFA, 0x47,
+ 0x9B, 0x1F, 0x9D, 0xBA, 0x29, 0x4D, 0xF8, 0xDF,
+ 0xC4, 0x72, 0x2F, 0xAE, 0x06, 0x51, 0x41, 0xAF,
+ 0xF3, 0xDD, 0x87, 0xB2, 0x9C, 0xC7, 0x12, 0x16,
+ 0x20, 0xA7, 0x21, 0x73, 0xF1, 0x58, 0xD7, 0x7B,
+ 0xB9, 0xB3, 0x32, 0x01, 0x80, 0x1C, 0x39, 0x0B,
+ 0x13, 0x56, 0x6C, 0x89, 0x33, 0x6E, 0x2A, 0xA5,
+ 0xD1, 0x95, 0xC3, 0xA0, 0x0F, 0xCA, 0xAC, 0xFC };
+
+unsigned char table_77[32] = {
+ 0x1C, 0x0D, 0x1E, 0x01, 0x06, 0x16, 0x18, 0x17,
+ 0x0B, 0x1F, 0x04, 0x0F, 0x00, 0x19, 0x08, 0x0A,
+ 0x11, 0x03, 0x05, 0x07, 0x09, 0x0C, 0x15, 0x14,
+ 0x1A, 0x12, 0x13, 0x0E, 0x1D, 0x10, 0x02, 0x1B };
+
+unsigned char table_78[32] = {
+ 0x0E, 0x02, 0x17, 0x12, 0x1E, 0x09, 0x15, 0x03,
+ 0x01, 0x0B, 0x0F, 0x11, 0x10, 0x0A, 0x16, 0x06,
+ 0x07, 0x00, 0x1C, 0x1D, 0x1F, 0x0C, 0x18, 0x04,
+ 0x13, 0x0D, 0x1B, 0x08, 0x19, 0x14, 0x05, 0x1A };
+
+unsigned char table_79[32] = {
+ 0x12, 0x0B, 0x11, 0x01, 0x07, 0x0E, 0x1A, 0x0D,
+ 0x1E, 0x18, 0x14, 0x1F, 0x0A, 0x17, 0x19, 0x1B,
+ 0x00, 0x10, 0x0C, 0x08, 0x13, 0x02, 0x0F, 0x1D,
+ 0x09, 0x06, 0x04, 0x16, 0x15, 0x1C, 0x05, 0x03 };
+
+unsigned char table_80[256] = {
+ 0x14, 0xE7, 0x31, 0x0F, 0xD1, 0x5F, 0xED, 0x1E,
+ 0xA6, 0x77, 0x20, 0x57, 0x34, 0x64, 0x33, 0x0B,
+ 0x5A, 0xB4, 0x83, 0x62, 0xFD, 0x8E, 0xE4, 0xF3,
+ 0xBD, 0xA5, 0xC8, 0x6D, 0x3E, 0x4F, 0x01, 0x7A,
+ 0xD3, 0x45, 0x3C, 0xF2, 0x68, 0xFF, 0xE6, 0x84,
+ 0xC2, 0xC1, 0x53, 0x72, 0x8C, 0xA1, 0xC7, 0x00,
+ 0x89, 0x97, 0x69, 0xA4, 0xF8, 0xAA, 0xAD, 0x8F,
+ 0x24, 0xC6, 0x9A, 0xAC, 0xE5, 0xAB, 0x6B, 0x79,
+ 0x99, 0x60, 0x28, 0x2B, 0x3B, 0xAF, 0x1C, 0x80,
+ 0xA3, 0x8A, 0x1A, 0xB5, 0xE1, 0x9F, 0xDA, 0x78,
+ 0xD7, 0xC4, 0x87, 0x5D, 0xE9, 0x27, 0xFB, 0x18,
+ 0x94, 0x3A, 0xCE, 0x3F, 0xF6, 0x12, 0x75, 0x37,
+ 0x6E, 0x9E, 0x29, 0x6C, 0xF7, 0x7D, 0x92, 0x08,
+ 0x42, 0xB2, 0xBF, 0x0C, 0xB6, 0x25, 0xE0, 0x49,
+ 0x43, 0x91, 0x98, 0xBB, 0xDC, 0x63, 0xEA, 0xA8,
+ 0x74, 0x38, 0x35, 0xCD, 0x07, 0x70, 0x81, 0x41,
+ 0xC9, 0x51, 0xBC, 0xA9, 0x59, 0xD4, 0xB8, 0x2C,
+ 0x7C, 0x2D, 0xB3, 0x6F, 0x11, 0x86, 0x9D, 0x46,
+ 0xF0, 0x65, 0x76, 0x04, 0x0E, 0xCA, 0xBE, 0x5C,
+ 0xF9, 0x71, 0x9C, 0x21, 0x4C, 0x02, 0xFE, 0x8D,
+ 0xD5, 0x26, 0x40, 0xC3, 0x32, 0x9B, 0xB0, 0x5E,
+ 0x48, 0xC5, 0x85, 0x4B, 0x0A, 0xCC, 0x58, 0x52,
+ 0x61, 0x13, 0xEF, 0x4A, 0xEE, 0x03, 0xD9, 0xDE,
+ 0xA7, 0x19, 0x09, 0x7F, 0x5B, 0x96, 0xBA, 0x0D,
+ 0xCF, 0xD2, 0x06, 0x1F, 0xD8, 0xDB, 0xEC, 0xA0,
+ 0xDD, 0x66, 0x10, 0xA2, 0xDF, 0x30, 0xF4, 0x88,
+ 0xCB, 0x36, 0x82, 0xE3, 0x73, 0x17, 0x55, 0x15,
+ 0xF5, 0xB7, 0x23, 0xB1, 0xD6, 0xE2, 0x47, 0x7E,
+ 0x67, 0xE8, 0x1D, 0x16, 0x8B, 0xEB, 0xD0, 0x3D,
+ 0x6A, 0x54, 0x2A, 0x4E, 0x93, 0xFA, 0x44, 0x05,
+ 0x2F, 0x50, 0x2E, 0x95, 0xAE, 0x1B, 0x56, 0x7B,
+ 0x39, 0xB9, 0xC0, 0x22, 0xF1, 0x4D, 0x90, 0xFC };
+
+unsigned char table_81[32] = {
+ 0x03, 0x02, 0x1D, 0x0E, 0x09, 0x1A, 0x0C, 0x11,
+ 0x1C, 0x0D, 0x08, 0x12, 0x19, 0x10, 0x04, 0x17,
+ 0x15, 0x05, 0x0A, 0x00, 0x13, 0x16, 0x1B, 0x18,
+ 0x1E, 0x0B, 0x0F, 0x01, 0x07, 0x14, 0x1F, 0x06 };
+
+unsigned char table_82[256] = {
+ 0x53, 0xD3, 0x64, 0x89, 0x7D, 0xA5, 0x66, 0xA4,
+ 0x09, 0x46, 0x17, 0x2C, 0xAF, 0x8C, 0x21, 0x5F,
+ 0x3B, 0x22, 0xE3, 0x05, 0x07, 0x28, 0x2F, 0xAB,
+ 0xF4, 0x8E, 0x51, 0x31, 0x02, 0xC7, 0x48, 0x13,
+ 0x24, 0x12, 0xB8, 0xE5, 0xBD, 0xAE, 0x7E, 0xCC,
+ 0xC9, 0x98, 0x08, 0xEE, 0xDB, 0x1B, 0xE8, 0x3D,
+ 0x8F, 0xF2, 0xFB, 0x36, 0x4D, 0x94, 0x9C, 0x16,
+ 0xF7, 0x42, 0x9B, 0x2B, 0xFD, 0x7B, 0x77, 0x3F,
+ 0xC3, 0xFC, 0x23, 0x93, 0x50, 0x0C, 0x79, 0x18,
+ 0x47, 0xE1, 0xCB, 0xA7, 0xB6, 0x85, 0xE6, 0x61,
+ 0x2D, 0xD8, 0x9F, 0x80, 0xE9, 0x14, 0x0B, 0x1C,
+ 0x40, 0x76, 0x2A, 0x25, 0x0E, 0x99, 0xAC, 0xC4,
+ 0xEB, 0x29, 0x41, 0x8A, 0x73, 0x06, 0x57, 0xC6,
+ 0x8D, 0xFA, 0x5A, 0xCD, 0x67, 0xB2, 0xD9, 0x0A,
+ 0x1E, 0xEF, 0x3E, 0xA0, 0x45, 0x03, 0x27, 0xF1,
+ 0x38, 0x54, 0xC1, 0x7A, 0xFE, 0x52, 0x75, 0xD4,
+ 0x74, 0x7C, 0xD2, 0x68, 0xEA, 0x4C, 0x97, 0xF9,
+ 0xF5, 0x8B, 0x0F, 0x84, 0xA8, 0x6E, 0x9E, 0x11,
+ 0x6B, 0xBC, 0x4B, 0x6C, 0x9A, 0xF0, 0xA3, 0x1F,
+ 0x92, 0x19, 0xA2, 0x3A, 0x15, 0x04, 0xC5, 0x62,
+ 0xD5, 0x96, 0x90, 0x32, 0xAA, 0xD6, 0xCF, 0x35,
+ 0xB4, 0x81, 0x2E, 0x01, 0x10, 0x49, 0x70, 0xDE,
+ 0xDD, 0x88, 0xB9, 0x6D, 0x60, 0xBB, 0x44, 0xF8,
+ 0x3C, 0xEC, 0x34, 0x82, 0x95, 0x72, 0x58, 0x4E,
+ 0xE4, 0x0D, 0xBE, 0xDA, 0x83, 0x4A, 0x00, 0xBF,
+ 0xD0, 0xC8, 0x26, 0xB3, 0x65, 0x1A, 0x69, 0xCA,
+ 0xF3, 0xD7, 0x6F, 0x55, 0xE2, 0xFF, 0x5D, 0xDC,
+ 0x20, 0xF6, 0x63, 0xED, 0xE0, 0x59, 0x9D, 0xB1,
+ 0x1D, 0xAD, 0x91, 0xA1, 0xB7, 0xA9, 0xDF, 0xC0,
+ 0x39, 0xD1, 0x43, 0xCE, 0x4F, 0x5C, 0xE7, 0x37,
+ 0x5E, 0x33, 0x5B, 0xA6, 0xC2, 0xB0, 0xBA, 0x30,
+ 0x6A, 0x78, 0xB5, 0x71, 0x56, 0x87, 0x7F, 0x86 };
+
+unsigned char table_83[32] = {
+ 0x1B, 0x0A, 0x1F, 0x01, 0x10, 0x08, 0x0E, 0x18,
+ 0x06, 0x04, 0x00, 0x1C, 0x0C, 0x19, 0x0D, 0x16,
+ 0x02, 0x03, 0x09, 0x07, 0x13, 0x0F, 0x05, 0x12,
+ 0x17, 0x1E, 0x1A, 0x1D, 0x0B, 0x11, 0x14, 0x15 };
+
+unsigned char table_84[32] = {
+ 0x02, 0x1A, 0x0D, 0x15, 0x01, 0x16, 0x1E, 0x00,
+ 0x08, 0x1B, 0x04, 0x10, 0x1C, 0x18, 0x19, 0x14,
+ 0x0C, 0x11, 0x0B, 0x0E, 0x03, 0x0A, 0x07, 0x12,
+ 0x1D, 0x17, 0x13, 0x06, 0x0F, 0x05, 0x09, 0x1F };
+
+unsigned char table_85[256] = {
+ 0xC6, 0x7C, 0xCE, 0xBD, 0x84, 0x3E, 0x0B, 0xD8,
+ 0xFE, 0xCC, 0x46, 0x50, 0xD1, 0xFB, 0xA0, 0x6D,
+ 0xEA, 0xE2, 0x40, 0x51, 0x13, 0xB0, 0xD6, 0xB1,
+ 0xA8, 0xDF, 0x61, 0xA4, 0x80, 0x21, 0xB3, 0x33,
+ 0x06, 0x6B, 0xE3, 0x8C, 0xA1, 0x18, 0xBA, 0x03,
+ 0xD7, 0x8D, 0x54, 0x12, 0x4C, 0xEE, 0x9E, 0xCF,
+ 0x04, 0x2A, 0x08, 0xBB, 0xC2, 0xD4, 0xC3, 0x4A,
+ 0xD5, 0xFA, 0x36, 0x2F, 0x14, 0x3F, 0xED, 0x05,
+ 0x17, 0x28, 0x75, 0xFC, 0xA2, 0x1F, 0x4B, 0x6F,
+ 0x91, 0x7E, 0x4E, 0x96, 0x3B, 0xF3, 0x1D, 0x78,
+ 0xEB, 0x68, 0xF1, 0xA7, 0x9F, 0xC7, 0x59, 0x6C,
+ 0x92, 0xE6, 0x66, 0x07, 0x8A, 0x25, 0x26, 0x72,
+ 0x30, 0x5A, 0x81, 0x2C, 0x58, 0x32, 0xCB, 0xE0,
+ 0xF9, 0x48, 0x83, 0x9B, 0xA5, 0xE1, 0xA6, 0x64,
+ 0xFF, 0xC9, 0x8F, 0x53, 0x3D, 0x24, 0xC8, 0xDE,
+ 0x02, 0x7D, 0x09, 0xB4, 0x0A, 0x95, 0x0F, 0xE4,
+ 0xDB, 0xB7, 0x71, 0x4D, 0x1C, 0xAC, 0x35, 0xCD,
+ 0x29, 0xDD, 0xC1, 0xF2, 0xF4, 0xC0, 0x5C, 0x74,
+ 0xDC, 0x87, 0xFD, 0x4F, 0x11, 0x0E, 0x5D, 0x3C,
+ 0x01, 0x73, 0xE9, 0xD9, 0x10, 0x9A, 0x5B, 0xC5,
+ 0x98, 0x34, 0x15, 0xAE, 0xF7, 0xAA, 0x67, 0x23,
+ 0xBC, 0x8B, 0x7B, 0x65, 0xA9, 0xB6, 0x77, 0x00,
+ 0x19, 0x0C, 0x5E, 0x99, 0xF0, 0x55, 0x86, 0x97,
+ 0x69, 0xDA, 0x38, 0x9C, 0x16, 0xE8, 0x27, 0xAF,
+ 0x2E, 0x47, 0x6A, 0xD0, 0x79, 0x44, 0x45, 0x2B,
+ 0x5F, 0x85, 0xF5, 0x62, 0x70, 0x22, 0x7F, 0xF6,
+ 0x88, 0x93, 0x60, 0x42, 0x3A, 0x39, 0x49, 0x6E,
+ 0x89, 0x52, 0x20, 0xF8, 0xCA, 0xD2, 0x76, 0xB9,
+ 0xAB, 0x7A, 0x9D, 0xD3, 0xBE, 0x1A, 0xAD, 0x41,
+ 0x56, 0x31, 0x90, 0xB5, 0xB2, 0xEC, 0xA3, 0xE5,
+ 0x8E, 0x1B, 0xEF, 0xBF, 0x94, 0xC4, 0x0D, 0xB8,
+ 0x2D, 0x57, 0xE7, 0x82, 0x1E, 0x37, 0x63, 0x43 };
+
+unsigned char table_86[32] = {
+ 0x11, 0x07, 0x0F, 0x0A, 0x19, 0x1D, 0x0B, 0x09,
+ 0x1C, 0x1E, 0x14, 0x06, 0x0C, 0x16, 0x13, 0x04,
+ 0x15, 0x18, 0x00, 0x0D, 0x12, 0x05, 0x08, 0x02,
+ 0x10, 0x1A, 0x1F, 0x01, 0x17, 0x0E, 0x03, 0x1B };
+
+unsigned char table_87[32] = {
+ 0x17, 0x0E, 0x1D, 0x13, 0x0B, 0x19, 0x03, 0x06,
+ 0x09, 0x01, 0x0D, 0x15, 0x1C, 0x16, 0x18, 0x1B,
+ 0x11, 0x10, 0x00, 0x1E, 0x1F, 0x08, 0x12, 0x0F,
+ 0x02, 0x04, 0x07, 0x1A, 0x14, 0x0A, 0x0C, 0x05 };
+
+unsigned char table_88[32] = {
+ 0x09, 0x08, 0x17, 0x10, 0x0A, 0x07, 0x1C, 0x1F,
+ 0x04, 0x0E, 0x01, 0x0C, 0x0D, 0x1B, 0x03, 0x15,
+ 0x02, 0x1E, 0x18, 0x19, 0x0F, 0x06, 0x1A, 0x0B,
+ 0x05, 0x11, 0x14, 0x00, 0x16, 0x1D, 0x12, 0x13 };
+
+unsigned char table_89[32] = {
+ 0x15, 0x1C, 0x1D, 0x14, 0x0F, 0x1A, 0x05, 0x02,
+ 0x07, 0x09, 0x06, 0x08, 0x1F, 0x00, 0x10, 0x13,
+ 0x0D, 0x03, 0x0C, 0x18, 0x0E, 0x16, 0x1B, 0x1E,
+ 0x12, 0x04, 0x11, 0x0A, 0x01, 0x0B, 0x17, 0x19 };
+
+unsigned char table_90[256] = {
+ 0x62, 0x36, 0x64, 0x0E, 0x4C, 0x6C, 0xBE, 0xCF,
+ 0x25, 0x5A, 0x3D, 0x12, 0x54, 0x9F, 0xE7, 0xA5,
+ 0xDE, 0xD7, 0xB2, 0x60, 0x18, 0x8D, 0x89, 0x70,
+ 0x48, 0x66, 0x1C, 0xA6, 0x17, 0x9B, 0xDF, 0x9A,
+ 0x82, 0xB9, 0x2E, 0xFA, 0x83, 0x5B, 0x7A, 0x61,
+ 0xFC, 0x6B, 0x8B, 0x4E, 0x0F, 0xAD, 0x78, 0xE1,
+ 0xE8, 0x15, 0x1A, 0xF7, 0xA3, 0x3A, 0x04, 0xE3,
+ 0x30, 0x8C, 0x06, 0xC4, 0x05, 0x32, 0x1F, 0x6A,
+ 0xB8, 0x37, 0x58, 0xF5, 0x74, 0x63, 0xD4, 0xAC,
+ 0xA4, 0xF3, 0xEC, 0xBB, 0x8E, 0x65, 0xA0, 0xEE,
+ 0x6D, 0x11, 0xDD, 0xEA, 0x68, 0x2B, 0xDA, 0x0B,
+ 0xEF, 0xC3, 0x8F, 0x03, 0x77, 0x1B, 0xFB, 0x1E,
+ 0x5C, 0xD9, 0xCB, 0x33, 0x55, 0xF1, 0xA1, 0xF9,
+ 0x7C, 0x38, 0x95, 0x00, 0x6E, 0x85, 0xC2, 0x7F,
+ 0xBF, 0x84, 0x2A, 0x13, 0x72, 0x81, 0xE9, 0x59,
+ 0x41, 0x69, 0x3B, 0x0C, 0x90, 0xB4, 0x51, 0x2F,
+ 0xA2, 0xFE, 0xF8, 0x49, 0x57, 0xE5, 0x96, 0xFF,
+ 0xCD, 0xD5, 0xCE, 0xAA, 0x40, 0xB0, 0x4D, 0xBA,
+ 0xDB, 0xC7, 0x46, 0x86, 0xD1, 0xCA, 0xC0, 0x67,
+ 0x9C, 0x21, 0xAE, 0xB3, 0x7B, 0x87, 0xE2, 0x71,
+ 0xE6, 0x39, 0xA8, 0x22, 0x07, 0x2C, 0x44, 0x52,
+ 0xA7, 0xF0, 0x4A, 0x92, 0x56, 0x28, 0x43, 0x8A,
+ 0x5E, 0x53, 0x93, 0x47, 0x97, 0x88, 0x76, 0x79,
+ 0x91, 0x26, 0xC1, 0x3F, 0xB7, 0xF6, 0x3E, 0x80,
+ 0xA9, 0xC6, 0x01, 0xD2, 0xEB, 0x9E, 0x4B, 0xBC,
+ 0xC8, 0xB5, 0x02, 0x5F, 0x98, 0x9D, 0x5D, 0x35,
+ 0xD0, 0x16, 0xB1, 0x23, 0x7D, 0xAF, 0x10, 0x3C,
+ 0xAB, 0x14, 0x09, 0x2D, 0x0D, 0xC5, 0x1D, 0xD6,
+ 0x42, 0xF2, 0x34, 0x73, 0xF4, 0xFD, 0xE0, 0x24,
+ 0x6F, 0xD3, 0x75, 0xD8, 0xCC, 0xB6, 0x99, 0x4F,
+ 0x29, 0x0A, 0x08, 0xE4, 0x27, 0x19, 0x31, 0xC9,
+ 0x20, 0x94, 0x45, 0xED, 0xDC, 0xBD, 0x7E, 0x50 };
+
+unsigned char table_91[32] = {
+ 0x03, 0x04, 0x0C, 0x18, 0x10, 0x0D, 0x13, 0x1B,
+ 0x1F, 0x07, 0x11, 0x17, 0x1C, 0x1D, 0x05, 0x06,
+ 0x0A, 0x12, 0x02, 0x1A, 0x0B, 0x01, 0x0E, 0x08,
+ 0x14, 0x16, 0x00, 0x15, 0x19, 0x09, 0x0F, 0x1E };
+
+unsigned char table_92[32] = {
+ 0x1E, 0x10, 0x01, 0x07, 0x11, 0x16, 0x15, 0x17,
+ 0x1F, 0x14, 0x0C, 0x1C, 0x06, 0x03, 0x00, 0x18,
+ 0x08, 0x0E, 0x02, 0x1B, 0x09, 0x0D, 0x19, 0x05,
+ 0x0F, 0x12, 0x0B, 0x13, 0x0A, 0x04, 0x1D, 0x1A };
+
+unsigned char table_93[256] = {
+ 0x76, 0x78, 0xA2, 0x94, 0x0E, 0x7F, 0xDF, 0xC1,
+ 0xB9, 0xE1, 0x3D, 0x59, 0x6F, 0x1E, 0x53, 0x99,
+ 0x80, 0xE3, 0x21, 0xF8, 0x65, 0xB8, 0x08, 0xBC,
+ 0x29, 0x17, 0xFD, 0x33, 0x35, 0xF2, 0x70, 0xC7,
+ 0x25, 0xD0, 0xCD, 0x7A, 0xB7, 0x9B, 0xA5, 0xC3,
+ 0x00, 0x90, 0xDC, 0xB1, 0x0C, 0x20, 0x67, 0x8D,
+ 0x43, 0x49, 0xF3, 0x96, 0x14, 0x1A, 0xC8, 0x19,
+ 0x72, 0xD7, 0x8A, 0x38, 0x66, 0xDA, 0xDD, 0x2E,
+ 0xBE, 0xD5, 0x91, 0x7C, 0x3A, 0x92, 0x8E, 0xE7,
+ 0x51, 0xB5, 0xA8, 0xD9, 0x0B, 0x2A, 0xBA, 0x81,
+ 0x41, 0x0F, 0xBD, 0x4E, 0x31, 0x23, 0x9C, 0x8B,
+ 0x2B, 0x1D, 0x04, 0x3E, 0x8C, 0xF0, 0x45, 0xA0,
+ 0x1C, 0x44, 0x55, 0x5E, 0xF1, 0x98, 0x54, 0x5D,
+ 0x9D, 0x84, 0xAE, 0x09, 0xA9, 0xC5, 0x83, 0x60,
+ 0x86, 0x95, 0xB4, 0xFA, 0x6B, 0xA7, 0x9A, 0xCA,
+ 0x8F, 0x4F, 0x0A, 0x7B, 0xB0, 0x02, 0xEA, 0xA4,
+ 0x18, 0xDB, 0xD3, 0x64, 0xEB, 0xFC, 0xC4, 0xC9,
+ 0xF5, 0xD6, 0xCC, 0x75, 0x0D, 0x5C, 0x93, 0x4A,
+ 0x6D, 0xC0, 0x1F, 0x50, 0xE6, 0x16, 0xEE, 0x07,
+ 0xFB, 0x74, 0x56, 0x58, 0x52, 0x89, 0x79, 0x68,
+ 0xB6, 0xFE, 0x01, 0xD4, 0x7E, 0x06, 0xBF, 0xCB,
+ 0x5B, 0xC2, 0xC6, 0x32, 0xAC, 0x26, 0x22, 0xD2,
+ 0x82, 0x46, 0x69, 0x15, 0x2C, 0xF7, 0xAD, 0x13,
+ 0x4D, 0xA3, 0xF6, 0x2D, 0x48, 0x71, 0x57, 0x11,
+ 0x63, 0x05, 0x5F, 0x9E, 0x4B, 0xAB, 0xA6, 0x61,
+ 0xBB, 0xA1, 0x3C, 0x97, 0xF9, 0x03, 0x40, 0x12,
+ 0xCF, 0x37, 0xE4, 0x10, 0x6A, 0xED, 0xFF, 0x62,
+ 0x42, 0x4C, 0xAF, 0x9F, 0xE5, 0xE8, 0xD8, 0xD1,
+ 0x28, 0x3F, 0x1B, 0xE9, 0xCE, 0x6C, 0x27, 0x88,
+ 0xEF, 0x2F, 0xE0, 0x30, 0x87, 0x5A, 0x73, 0xB3,
+ 0x6E, 0x3B, 0x7D, 0x77, 0x36, 0xAA, 0x39, 0xDE,
+ 0x24, 0x34, 0xE2, 0xEC, 0x85, 0x47, 0xF4, 0xB2 };
+
+unsigned char table_94[32] = {
+ 0x1C, 0x07, 0x05, 0x1A, 0x10, 0x1D, 0x14, 0x12,
+ 0x08, 0x0F, 0x0C, 0x01, 0x04, 0x1B, 0x16, 0x0A,
+ 0x11, 0x02, 0x1F, 0x13, 0x0D, 0x1E, 0x17, 0x06,
+ 0x0E, 0x09, 0x15, 0x19, 0x03, 0x18, 0x00, 0x0B };
+
+unsigned char table_95[32] = {
+ 0x12, 0x10, 0x11, 0x15, 0x03, 0x0A, 0x14, 0x05,
+ 0x1D, 0x07, 0x17, 0x0D, 0x09, 0x08, 0x1B, 0x1F,
+ 0x0B, 0x06, 0x19, 0x0E, 0x18, 0x04, 0x00, 0x02,
+ 0x1E, 0x1C, 0x01, 0x0C, 0x1A, 0x0F, 0x13, 0x16 };
+
+unsigned char table_96[256] = {
+ 0x1C, 0x6E, 0xCD, 0xB4, 0xB3, 0x93, 0xA8, 0x2E,
+ 0x4F, 0x09, 0xE3, 0x72, 0x64, 0x13, 0x21, 0xF5,
+ 0x89, 0xB2, 0xD2, 0x22, 0x5D, 0x63, 0x90, 0xC4,
+ 0x42, 0x9B, 0x07, 0xCA, 0x16, 0x19, 0x5C, 0x2B,
+ 0x3D, 0xA0, 0x69, 0x5F, 0x52, 0x41, 0x66, 0xC0,
+ 0x55, 0xDA, 0x82, 0x40, 0x25, 0x02, 0x3C, 0xDD,
+ 0xAE, 0xD7, 0xD6, 0xDB, 0x04, 0x78, 0x05, 0x4A,
+ 0x4C, 0x81, 0x00, 0xBE, 0x45, 0xC5, 0x30, 0xB0,
+ 0x65, 0x5A, 0xA9, 0x38, 0x75, 0x26, 0x85, 0x4E,
+ 0xF0, 0xA2, 0x91, 0x8A, 0x54, 0xD0, 0x3E, 0x0D,
+ 0xFE, 0xF2, 0x0A, 0x23, 0x24, 0x37, 0x32, 0x0B,
+ 0xCB, 0xB5, 0x28, 0x6A, 0x95, 0x49, 0x53, 0x9A,
+ 0xEE, 0x2C, 0x9D, 0xD4, 0x1D, 0x46, 0xC9, 0x79,
+ 0xCC, 0xDF, 0x17, 0xE8, 0x6D, 0x29, 0x0E, 0x80,
+ 0xE0, 0x62, 0xA1, 0xFA, 0x10, 0xF6, 0x03, 0xC1,
+ 0x15, 0x14, 0x1F, 0x99, 0x97, 0xD5, 0x9E, 0x3F,
+ 0x7B, 0x2F, 0xEF, 0x2A, 0x68, 0x83, 0xE2, 0x1B,
+ 0xC8, 0x87, 0x12, 0x70, 0xC7, 0x36, 0xD3, 0x73,
+ 0x8B, 0x7D, 0x47, 0x9F, 0xD9, 0xFB, 0x6C, 0x5B,
+ 0xFC, 0xAA, 0xB9, 0xB1, 0x0C, 0x31, 0x8E, 0xF3,
+ 0x92, 0xA3, 0x4B, 0xF1, 0xC2, 0x3A, 0x67, 0xEA,
+ 0x77, 0x11, 0xB6, 0xE4, 0x1A, 0x33, 0xD1, 0xBA,
+ 0xF9, 0xAC, 0x43, 0xE5, 0xC3, 0xC6, 0xFD, 0xF4,
+ 0x44, 0x6F, 0xB7, 0x88, 0xA7, 0xF8, 0x34, 0x94,
+ 0x6B, 0x27, 0xDE, 0x1E, 0xDC, 0x01, 0x61, 0x50,
+ 0xAD, 0x74, 0x4D, 0x86, 0xF7, 0x8D, 0x9C, 0x0F,
+ 0x5E, 0xBD, 0x08, 0x84, 0x18, 0xED, 0xA5, 0x39,
+ 0xAB, 0x98, 0x48, 0xE6, 0x2D, 0x96, 0xCF, 0x7F,
+ 0xFF, 0xBB, 0x8F, 0xEC, 0xBF, 0xE7, 0x56, 0xA4,
+ 0x35, 0x76, 0xA6, 0xAF, 0xBC, 0x71, 0xE9, 0xB8,
+ 0x7E, 0x7C, 0x06, 0x3B, 0xEB, 0x60, 0x7A, 0x8C,
+ 0x59, 0xCE, 0xE1, 0x57, 0x20, 0x58, 0x51, 0xD8 };
+
+unsigned char table_97[256] = {
+ 0x15, 0x2D, 0xAF, 0x36, 0xCF, 0xD3, 0xD0, 0xED,
+ 0xB2, 0x1B, 0xFE, 0x92, 0xBD, 0xAD, 0x58, 0x0F,
+ 0x76, 0x3C, 0x47, 0x03, 0x2E, 0x4C, 0x40, 0xF7,
+ 0x39, 0xA7, 0x72, 0x22, 0x95, 0xF3, 0x8C, 0xE0,
+ 0x79, 0xB6, 0x75, 0x82, 0x94, 0x8F, 0x44, 0xFC,
+ 0xB0, 0x05, 0xE9, 0x10, 0x68, 0xE7, 0xF1, 0xA5,
+ 0xA8, 0xE2, 0x6F, 0xBE, 0xE5, 0x54, 0xA2, 0xC6,
+ 0xDB, 0x1C, 0x9E, 0x6D, 0x14, 0xA1, 0x26, 0x34,
+ 0x1E, 0x1A, 0x06, 0x53, 0xEE, 0x67, 0xA9, 0x73,
+ 0xD5, 0x59, 0x2F, 0x61, 0xE6, 0x74, 0xD6, 0x97,
+ 0xC0, 0x0C, 0xB1, 0x6E, 0x6C, 0x33, 0xC8, 0x77,
+ 0x8B, 0x49, 0x43, 0xE3, 0xB5, 0xDE, 0x6A, 0xA0,
+ 0x78, 0x2A, 0xC9, 0xF9, 0x9A, 0xDC, 0x90, 0x55,
+ 0xF4, 0x16, 0x5E, 0x3F, 0xC5, 0x7C, 0xFA, 0x09,
+ 0x8E, 0x87, 0xF2, 0x9D, 0x70, 0x27, 0x9B, 0xC4,
+ 0xCD, 0x91, 0x4B, 0xB4, 0x18, 0xE1, 0x3D, 0x5D,
+ 0x7A, 0xEA, 0xF0, 0x65, 0xB9, 0xF6, 0xC3, 0x66,
+ 0x21, 0x96, 0xD1, 0xB8, 0x56, 0x62, 0x48, 0x28,
+ 0x3A, 0x86, 0x63, 0xD4, 0xD7, 0x41, 0x8D, 0x20,
+ 0xC2, 0x98, 0x37, 0xD8, 0x85, 0x42, 0x0D, 0x31,
+ 0x84, 0x4E, 0x11, 0x46, 0x2B, 0x19, 0xCC, 0xB7,
+ 0x69, 0x13, 0x6B, 0x29, 0x38, 0x7E, 0x0E, 0xD2,
+ 0x3B, 0x60, 0x89, 0x7F, 0xEF, 0x07, 0x08, 0xCA,
+ 0xBF, 0x3E, 0xA3, 0xAA, 0x52, 0x4A, 0x45, 0x00,
+ 0xC7, 0xF8, 0x57, 0xEB, 0x93, 0x9C, 0x4D, 0x7B,
+ 0x2C, 0xBB, 0xFB, 0xFF, 0x35, 0x4F, 0x32, 0xA6,
+ 0x23, 0x8A, 0xDD, 0x12, 0xA4, 0x81, 0x17, 0x1D,
+ 0x1F, 0xCB, 0x0A, 0x71, 0x02, 0xAC, 0xDF, 0x24,
+ 0xAB, 0x7D, 0x30, 0x5C, 0x01, 0x5A, 0xBA, 0xEC,
+ 0x51, 0xF5, 0x0B, 0x64, 0xCE, 0xAE, 0x5B, 0x50,
+ 0x80, 0x88, 0xE8, 0x5F, 0x04, 0xDA, 0xE4, 0xBC,
+ 0x83, 0x25, 0x9F, 0xD9, 0x99, 0xC1, 0xFD, 0xB3 };
+
+unsigned char table_98[256] = {
+ 0xC8, 0xE6, 0x38, 0x93, 0xE5, 0x03, 0x18, 0x1F,
+ 0xE9, 0x5A, 0xB6, 0xAF, 0xC3, 0x95, 0x00, 0x51,
+ 0xC0, 0xFD, 0x32, 0xE8, 0x96, 0x57, 0xF0, 0xAA,
+ 0xDC, 0x71, 0xF8, 0x01, 0x40, 0x0A, 0x4F, 0xB0,
+ 0x1B, 0x9D, 0x16, 0x92, 0xF3, 0x5E, 0xA9, 0x3C,
+ 0xBE, 0x6A, 0xA7, 0xE3, 0x35, 0x0D, 0xAD, 0xDB,
+ 0x48, 0xE0, 0x7E, 0xC6, 0xB4, 0x6D, 0x17, 0x41,
+ 0x3E, 0xE2, 0x87, 0x12, 0xE1, 0x53, 0xD9, 0x8A,
+ 0xAC, 0xA6, 0xD8, 0xFA, 0x36, 0x0B, 0x06, 0xDF,
+ 0x6C, 0x4E, 0xA4, 0xBC, 0xC9, 0xEE, 0x44, 0x26,
+ 0xF2, 0xE4, 0x9E, 0x34, 0xEF, 0x05, 0x0F, 0x7F,
+ 0xD1, 0xCD, 0x67, 0x28, 0xC1, 0x8E, 0x7D, 0x90,
+ 0x8F, 0x60, 0x1E, 0x19, 0xBD, 0x77, 0xB8, 0xD5,
+ 0x3D, 0x8C, 0x31, 0x99, 0x08, 0xDD, 0x04, 0x30,
+ 0x61, 0xFB, 0xEB, 0x98, 0x15, 0xFC, 0x10, 0xDE,
+ 0x20, 0xBA, 0xA1, 0xB3, 0xD4, 0x91, 0x6F, 0x9F,
+ 0x94, 0x5B, 0x42, 0xCB, 0x75, 0x1C, 0xBB, 0x5C,
+ 0x5D, 0xD6, 0x66, 0x50, 0xB9, 0xF1, 0x82, 0x7B,
+ 0x33, 0x23, 0x4A, 0xA5, 0x55, 0x97, 0xEA, 0x37,
+ 0xF4, 0x64, 0x6E, 0xBF, 0x8B, 0xB1, 0x07, 0x9A,
+ 0x43, 0x11, 0x65, 0xC2, 0x02, 0xDA, 0x9B, 0x25,
+ 0xCA, 0x3B, 0x7A, 0xCE, 0xA8, 0xCF, 0xF7, 0x56,
+ 0x6B, 0xF9, 0x47, 0x2A, 0x2E, 0x1D, 0x2D, 0xE7,
+ 0x46, 0xD0, 0x62, 0x4C, 0x80, 0x4B, 0x2B, 0xF5,
+ 0x69, 0x9C, 0x45, 0xED, 0x83, 0xAB, 0x74, 0x39,
+ 0xA3, 0x85, 0xD7, 0x5F, 0xB2, 0x86, 0x22, 0x29,
+ 0x89, 0x49, 0x1A, 0xC4, 0x52, 0xEC, 0x8D, 0x73,
+ 0xD3, 0x7C, 0x79, 0xD2, 0x14, 0x4D, 0x84, 0xA2,
+ 0x0E, 0x70, 0x78, 0x72, 0xB7, 0xA0, 0xC5, 0x81,
+ 0x58, 0x0C, 0x68, 0x27, 0xFF, 0xF6, 0xAE, 0xCC,
+ 0x88, 0xFE, 0x24, 0x2F, 0x76, 0x3F, 0x59, 0x21,
+ 0x54, 0x3A, 0x13, 0x09, 0x2C, 0xB5, 0xC7, 0x63 };
+
+unsigned char table_99[32] = {
+ 0x19, 0x00, 0x10, 0x18, 0x09, 0x11, 0x13, 0x1D,
+ 0x08, 0x1A, 0x02, 0x05, 0x03, 0x17, 0x12, 0x01,
+ 0x1F, 0x14, 0x06, 0x07, 0x15, 0x0D, 0x0F, 0x0B,
+ 0x0E, 0x16, 0x1E, 0x04, 0x1B, 0x0A, 0x0C, 0x1C };
+
+unsigned char table_100[256] = {
+ 0x9B, 0x3A, 0xAE, 0x60, 0x27, 0x67, 0x1E, 0x4E,
+ 0x91, 0xDA, 0x85, 0x43, 0x5C, 0xCC, 0x89, 0x55,
+ 0x75, 0x56, 0xF2, 0x86, 0xEB, 0xC4, 0x0D, 0xE6,
+ 0x63, 0x88, 0x38, 0x59, 0x68, 0xD0, 0x18, 0xF0,
+ 0xBA, 0x28, 0xF5, 0x80, 0x02, 0x5B, 0xE1, 0xA4,
+ 0x7A, 0x4B, 0x8E, 0xF7, 0x9E, 0x99, 0x70, 0xEF,
+ 0x66, 0x50, 0xB1, 0xCD, 0x9A, 0xAF, 0x5F, 0x21,
+ 0xE5, 0x5D, 0x14, 0xD4, 0x34, 0x22, 0xC3, 0x0F,
+ 0x44, 0xB6, 0x92, 0xCE, 0xB4, 0x6E, 0xB0, 0x00,
+ 0xF9, 0xB5, 0x10, 0xEA, 0x45, 0x2F, 0x2B, 0xF4,
+ 0xF6, 0xFE, 0xCB, 0x0A, 0x42, 0xF8, 0xE7, 0xFD,
+ 0xC8, 0xC2, 0x6C, 0x9C, 0x57, 0xA1, 0x46, 0x04,
+ 0xE9, 0x97, 0x40, 0x32, 0x19, 0xFA, 0x51, 0xD1,
+ 0x6D, 0x4C, 0x2A, 0xD9, 0x95, 0x26, 0x72, 0x1B,
+ 0x83, 0x93, 0x5A, 0x15, 0x33, 0xC5, 0x77, 0x13,
+ 0xE0, 0x36, 0x37, 0xDB, 0xA7, 0xC7, 0x81, 0x62,
+ 0xC1, 0x47, 0x64, 0x74, 0x1D, 0x84, 0x29, 0x39,
+ 0x41, 0x35, 0x09, 0x90, 0x20, 0x9F, 0x8C, 0x7D,
+ 0x3E, 0x07, 0xB9, 0x76, 0x06, 0xA3, 0x31, 0x7F,
+ 0x49, 0x6F, 0x3D, 0xD5, 0x25, 0xAC, 0xDF, 0x0B,
+ 0x3C, 0x79, 0x01, 0x8F, 0x82, 0x2E, 0xFC, 0x98,
+ 0xA5, 0x58, 0xA0, 0x4A, 0x7C, 0x24, 0xDD, 0x05,
+ 0x4D, 0x12, 0xBC, 0xAA, 0xE2, 0xAB, 0xD3, 0xBF,
+ 0x94, 0x2D, 0x54, 0xBB, 0xAD, 0xB7, 0x6A, 0xE3,
+ 0xBD, 0x5E, 0x8D, 0x08, 0x3B, 0xB8, 0x73, 0x8A,
+ 0x16, 0xD2, 0x69, 0xE8, 0xEE, 0x53, 0xD8, 0xDC,
+ 0x48, 0xCF, 0xC6, 0xA9, 0x1A, 0xCA, 0x17, 0x11,
+ 0xED, 0xC0, 0xA6, 0x1F, 0x96, 0x8B, 0xFF, 0x78,
+ 0x03, 0x61, 0x1C, 0xA8, 0x3F, 0x9D, 0x0E, 0xC9,
+ 0xE4, 0xA2, 0x52, 0xEC, 0x4F, 0xD6, 0xF3, 0x6B,
+ 0x87, 0xB3, 0x7E, 0xDE, 0xD7, 0x71, 0x65, 0xF1,
+ 0x30, 0x0C, 0xB2, 0x7B, 0xBE, 0xFB, 0x23, 0x2C };
+
+unsigned char table_101[32] = {
+ 0x18, 0x08, 0x14, 0x17, 0x03, 0x10, 0x19, 0x04,
+ 0x0D, 0x1C, 0x06, 0x1D, 0x1E, 0x12, 0x11, 0x0B,
+ 0x0F, 0x02, 0x0E, 0x1B, 0x13, 0x05, 0x07, 0x16,
+ 0x15, 0x0A, 0x0C, 0x1A, 0x00, 0x01, 0x1F, 0x09 };
+
+unsigned char table_102[32] = {
+ 0x17, 0x1F, 0x0E, 0x05, 0x13, 0x0C, 0x14, 0x1A,
+ 0x0F, 0x01, 0x12, 0x1C, 0x00, 0x07, 0x0D, 0x02,
+ 0x10, 0x16, 0x04, 0x11, 0x1D, 0x03, 0x1E, 0x18,
+ 0x06, 0x15, 0x0A, 0x19, 0x09, 0x08, 0x1B, 0x0B };
+
+unsigned char table_103[32] = {
+ 0x0F, 0x09, 0x1E, 0x11, 0x0D, 0x08, 0x10, 0x00,
+ 0x01, 0x1F, 0x1D, 0x1C, 0x12, 0x04, 0x07, 0x05,
+ 0x19, 0x14, 0x1B, 0x02, 0x1A, 0x15, 0x17, 0x16,
+ 0x18, 0x0B, 0x0A, 0x13, 0x0C, 0x0E, 0x03, 0x06 };
+
+unsigned char table_104[256] = {
+ 0xA4, 0x9F, 0x78, 0x39, 0x3D, 0x81, 0x51, 0x24,
+ 0x46, 0x2A, 0x56, 0xE8, 0xDF, 0x73, 0xA8, 0xA2,
+ 0x0D, 0xDC, 0xA5, 0x4F, 0xF0, 0x93, 0xC0, 0x76,
+ 0x38, 0x70, 0xB0, 0x30, 0x98, 0x13, 0x8B, 0x14,
+ 0x26, 0x45, 0x0F, 0x7D, 0x34, 0x72, 0x6B, 0x89,
+ 0x43, 0xE2, 0x96, 0x5B, 0xEF, 0x2B, 0xF9, 0xDE,
+ 0x82, 0xB5, 0x61, 0x4A, 0x17, 0xC2, 0x5A, 0xCB,
+ 0xB2, 0x8D, 0xE4, 0xEC, 0xD9, 0x80, 0xBC, 0x62,
+ 0x67, 0x11, 0xA9, 0x3A, 0xE1, 0xC4, 0xEA, 0xD2,
+ 0x71, 0xD0, 0xDB, 0xE5, 0x7B, 0x08, 0x77, 0xD6,
+ 0x10, 0x19, 0x48, 0xEB, 0xAA, 0x2C, 0x0C, 0x59,
+ 0xBE, 0xF6, 0x28, 0x50, 0x90, 0x87, 0xCD, 0x04,
+ 0x1F, 0x79, 0x99, 0x5C, 0x49, 0x06, 0x8A, 0x3E,
+ 0x5F, 0x5E, 0x15, 0x23, 0x2D, 0xB6, 0xA6, 0x7A,
+ 0x03, 0x20, 0xDA, 0xFB, 0x35, 0x75, 0xC7, 0x47,
+ 0xB9, 0x7C, 0xA1, 0xCE, 0xC5, 0xDD, 0xFD, 0x6C,
+ 0x05, 0xAC, 0x09, 0xB4, 0x95, 0xD1, 0xB1, 0x63,
+ 0xFF, 0xAE, 0xD5, 0x25, 0x1E, 0x6E, 0x57, 0x18,
+ 0x74, 0xE6, 0x2F, 0x9A, 0xE7, 0x42, 0x65, 0xF5,
+ 0x58, 0x27, 0x33, 0x9C, 0xCF, 0xB7, 0xC3, 0xF1,
+ 0x12, 0x1D, 0xB8, 0xF4, 0x64, 0x4D, 0xD4, 0xBD,
+ 0xE3, 0xAB, 0x44, 0x60, 0xAF, 0xCC, 0x0A, 0xFC,
+ 0xD3, 0x21, 0x0B, 0x1A, 0x6D, 0x83, 0xA7, 0x8E,
+ 0x3C, 0xC1, 0xED, 0xF3, 0x2E, 0x86, 0xC9, 0x41,
+ 0x02, 0xF7, 0xC8, 0x40, 0x1B, 0xF8, 0xF2, 0x07,
+ 0x5D, 0x4E, 0xC6, 0x29, 0xD7, 0x4B, 0x7E, 0x31,
+ 0x94, 0x32, 0x01, 0x92, 0xE9, 0x36, 0x0E, 0x7F,
+ 0x85, 0x16, 0xFA, 0x00, 0x88, 0x3F, 0x68, 0x4C,
+ 0x22, 0x55, 0xBF, 0x9D, 0xE0, 0x6A, 0xAD, 0xBA,
+ 0x91, 0xCA, 0xA3, 0x1C, 0xEE, 0xD8, 0x3B, 0x66,
+ 0x69, 0x9B, 0x84, 0xA0, 0xB3, 0x6F, 0xFE, 0x52,
+ 0x97, 0xBB, 0x37, 0x8C, 0x54, 0x53, 0x9E, 0x8F };
+
+unsigned char table_105[256] = {
+ 0x7B, 0x35, 0x11, 0x79, 0x07, 0x2F, 0xF6, 0x82,
+ 0x8E, 0xB4, 0x6E, 0xD2, 0x6D, 0xC5, 0x8C, 0x1C,
+ 0xE0, 0xD6, 0x34, 0xF0, 0x4F, 0x25, 0x59, 0xE8,
+ 0xDF, 0x1D, 0xEB, 0x32, 0x86, 0x51, 0xA4, 0xF2,
+ 0x5C, 0xD1, 0xC8, 0x41, 0xEC, 0x9D, 0x62, 0xAC,
+ 0xDD, 0x3E, 0xB8, 0x65, 0x75, 0x89, 0x12, 0x6C,
+ 0x40, 0x4E, 0xC7, 0x27, 0xE1, 0x37, 0xCF, 0x09,
+ 0x16, 0x78, 0xAA, 0x58, 0x0D, 0xE6, 0x54, 0xFE,
+ 0x8F, 0xFD, 0xF9, 0x61, 0x26, 0x3F, 0x2E, 0xCD,
+ 0x2C, 0x04, 0xB2, 0x80, 0x0F, 0x14, 0x6F, 0xC6,
+ 0xAB, 0xFB, 0x13, 0xDB, 0x9A, 0x21, 0xB3, 0xC0,
+ 0xA9, 0x19, 0x70, 0xF3, 0x2B, 0xAE, 0x9B, 0x49,
+ 0xB7, 0xA8, 0x24, 0x1B, 0x48, 0xEA, 0xED, 0xD9,
+ 0x47, 0x9E, 0x9C, 0x69, 0x3C, 0x66, 0xBB, 0x06,
+ 0x46, 0x38, 0x17, 0xB5, 0xCB, 0x05, 0x4A, 0x5E,
+ 0x15, 0x20, 0xB9, 0xB6, 0x33, 0x4C, 0x7D, 0xA3,
+ 0xD7, 0xB1, 0x23, 0x72, 0xC3, 0x4B, 0x63, 0xBE,
+ 0xF7, 0x5B, 0x74, 0x64, 0x77, 0xCC, 0xD3, 0x85,
+ 0xDE, 0x1A, 0x31, 0x97, 0xA2, 0x8B, 0xFC, 0x10,
+ 0x5F, 0xDC, 0xD5, 0xB0, 0xBD, 0x55, 0xC1, 0xE7,
+ 0x0C, 0x50, 0x43, 0x39, 0x71, 0x52, 0xE5, 0xAF,
+ 0x8A, 0x60, 0x92, 0x2D, 0xD8, 0x03, 0xF5, 0x28,
+ 0xCA, 0xEF, 0xD0, 0xC2, 0x53, 0x91, 0xA6, 0x73,
+ 0x56, 0xA5, 0xF1, 0x57, 0x42, 0xF4, 0xD4, 0x36,
+ 0x8D, 0xBC, 0xE9, 0x7E, 0x02, 0x76, 0x18, 0x0B,
+ 0x84, 0x5A, 0xE2, 0xBF, 0x68, 0x95, 0x29, 0x98,
+ 0xAD, 0x88, 0x1F, 0x81, 0x67, 0xA1, 0x3A, 0xA7,
+ 0x22, 0xF8, 0x01, 0xA0, 0xCE, 0x7A, 0xDA, 0x30,
+ 0xC4, 0xE4, 0xEE, 0x7C, 0x3B, 0x4D, 0x3D, 0xE3,
+ 0xFA, 0x6A, 0x7F, 0x99, 0x00, 0x93, 0x0E, 0xFF,
+ 0x90, 0x0A, 0x2A, 0x5D, 0x96, 0x08, 0x6B, 0x83,
+ 0xBA, 0x1E, 0x44, 0x87, 0x45, 0x9F, 0xC9, 0x94 };
+
+unsigned char table_106[32] = {
+ 0x03, 0x11, 0x07, 0x1B, 0x0F, 0x14, 0x0C, 0x01,
+ 0x04, 0x02, 0x09, 0x0A, 0x05, 0x12, 0x06, 0x1F,
+ 0x1C, 0x0E, 0x0D, 0x15, 0x18, 0x08, 0x00, 0x10,
+ 0x1E, 0x1D, 0x17, 0x19, 0x13, 0x16, 0x0B, 0x1A };
+
+unsigned char table_107[32] = {
+ 0x13, 0x1B, 0x06, 0x11, 0x1C, 0x07, 0x08, 0x0E,
+ 0x10, 0x05, 0x09, 0x18, 0x04, 0x15, 0x1E, 0x0F,
+ 0x1F, 0x12, 0x02, 0x00, 0x17, 0x19, 0x1A, 0x0D,
+ 0x03, 0x0C, 0x0A, 0x1D, 0x14, 0x01, 0x16, 0x0B };
+
+unsigned char table_108[256] = {
+ 0x99, 0xA3, 0x48, 0xE8, 0x5A, 0x7D, 0x97, 0xCA,
+ 0x7F, 0x06, 0x9B, 0x04, 0xE0, 0xF3, 0x18, 0xAE,
+ 0x59, 0xA0, 0x2B, 0x15, 0x85, 0x3E, 0x12, 0x93,
+ 0x3D, 0x28, 0x32, 0xF5, 0x20, 0x5D, 0x86, 0x00,
+ 0x1B, 0x2E, 0x36, 0x10, 0x5E, 0x6C, 0xD8, 0x29,
+ 0xB6, 0x3F, 0x05, 0x1C, 0xCE, 0xC2, 0x34, 0x5F,
+ 0x5C, 0x79, 0xD1, 0x1F, 0xA2, 0xEE, 0x8A, 0x69,
+ 0xB5, 0x87, 0x96, 0x6D, 0x4D, 0xC1, 0x61, 0x2C,
+ 0x11, 0xE7, 0x8E, 0xBF, 0x1E, 0x53, 0xD0, 0x58,
+ 0x76, 0xA4, 0x60, 0xA9, 0xB0, 0xF9, 0xEA, 0x3C,
+ 0x52, 0x9A, 0x24, 0xF1, 0x9F, 0xD3, 0x40, 0x0A,
+ 0x63, 0x78, 0x6A, 0x8B, 0x08, 0x22, 0x16, 0x83,
+ 0x6B, 0xD2, 0x49, 0x19, 0xBD, 0xFD, 0x62, 0x72,
+ 0xA8, 0x55, 0xAB, 0x0C, 0xB9, 0x13, 0xD5, 0xF0,
+ 0xF2, 0x84, 0xAF, 0x2F, 0x7B, 0x2A, 0x21, 0x0F,
+ 0xDA, 0x30, 0x71, 0xD6, 0x81, 0xE6, 0xEC, 0x41,
+ 0x90, 0x50, 0x66, 0x0E, 0xA7, 0xB8, 0xF7, 0x3A,
+ 0xB2, 0xCF, 0x3B, 0xFC, 0x56, 0x6F, 0xC3, 0xA6,
+ 0xC9, 0xA1, 0x8D, 0xBB, 0x9D, 0x75, 0xF6, 0xAA,
+ 0x7E, 0xF8, 0x33, 0xEF, 0xBC, 0x7C, 0x23, 0x1A,
+ 0x92, 0x6E, 0x2D, 0x8F, 0xED, 0xB7, 0xB1, 0x1D,
+ 0x67, 0x39, 0xAC, 0x0D, 0x74, 0xDB, 0x7A, 0x94,
+ 0x07, 0x09, 0xC0, 0xD7, 0xAD, 0xFE, 0x54, 0x91,
+ 0xDE, 0x45, 0xA5, 0x77, 0xCB, 0x37, 0xC6, 0x38,
+ 0x89, 0x88, 0x17, 0xD9, 0x4F, 0xDF, 0x25, 0xFB,
+ 0xFA, 0x4C, 0x80, 0x35, 0x82, 0xF4, 0x95, 0xC8,
+ 0xFF, 0xE9, 0x31, 0x01, 0x14, 0xB3, 0x02, 0x9E,
+ 0x4E, 0x43, 0x46, 0xC7, 0xEB, 0x51, 0xE5, 0x47,
+ 0xB4, 0xE3, 0xDC, 0x57, 0xC4, 0x98, 0x03, 0xE1,
+ 0xBA, 0x68, 0xCD, 0x27, 0xC5, 0x0B, 0xD4, 0x64,
+ 0x4B, 0x9C, 0x70, 0x65, 0x4A, 0xE4, 0x42, 0xDD,
+ 0xCC, 0xE2, 0x44, 0x73, 0xBE, 0x26, 0x8C, 0x5B };
+
+unsigned char table_109[256] = {
+ 0xE3, 0x95, 0xDB, 0x09, 0x82, 0x0A, 0x8F, 0x9E,
+ 0xC9, 0xDC, 0x28, 0x35, 0x0F, 0x8B, 0xA8, 0xA5,
+ 0x7F, 0x3D, 0x8C, 0xD1, 0x93, 0x57, 0x04, 0xAA,
+ 0x6A, 0x98, 0x81, 0xDD, 0x16, 0x67, 0x2E, 0xDF,
+ 0xED, 0xF7, 0xB2, 0xBD, 0x14, 0xB6, 0x76, 0xC8,
+ 0x75, 0x9F, 0x48, 0xAE, 0xBB, 0xB0, 0xF3, 0xE2,
+ 0xD4, 0x59, 0xD8, 0x9C, 0x64, 0xC1, 0x73, 0x21,
+ 0x6D, 0x96, 0x7B, 0x62, 0x56, 0x55, 0xCC, 0xFD,
+ 0xCE, 0x41, 0xA3, 0x43, 0x33, 0xAF, 0x23, 0x9D,
+ 0x6F, 0x65, 0x19, 0x52, 0xAD, 0xC6, 0xD3, 0x3F,
+ 0x66, 0xFF, 0xD0, 0x30, 0x6C, 0xC0, 0xEB, 0xCF,
+ 0x51, 0x88, 0x38, 0x72, 0x69, 0x77, 0x3B, 0xFA,
+ 0xBA, 0xB7, 0xA1, 0x91, 0xE0, 0x89, 0xAB, 0x44,
+ 0x1B, 0x05, 0x5B, 0xB9, 0x71, 0x47, 0x7E, 0xFB,
+ 0x02, 0xC7, 0x99, 0x6E, 0x42, 0x20, 0x90, 0x1F,
+ 0x4A, 0x85, 0x1A, 0xEA, 0x0C, 0x0D, 0xB3, 0xDA,
+ 0xE7, 0x13, 0xE6, 0xD7, 0x6B, 0x12, 0x46, 0x53,
+ 0xB5, 0xF8, 0x1D, 0x83, 0x54, 0x49, 0x8A, 0x26,
+ 0x4D, 0xDE, 0xF6, 0x03, 0xA2, 0x7D, 0x0E, 0xA0,
+ 0x68, 0x79, 0xCA, 0x0B, 0x5D, 0x40, 0x4F, 0x80,
+ 0xC2, 0xD6, 0x87, 0x70, 0xF0, 0xD2, 0x92, 0xEE,
+ 0xBE, 0x74, 0x5F, 0xBC, 0xA4, 0x4B, 0xFE, 0x37,
+ 0x60, 0xA9, 0x06, 0xA7, 0xE1, 0xF5, 0x2B, 0x10,
+ 0xEF, 0x2C, 0x07, 0x86, 0x7A, 0x27, 0xE9, 0xC5,
+ 0xAC, 0x32, 0x22, 0xF2, 0xE5, 0x8D, 0x31, 0x01,
+ 0x34, 0xA6, 0xB8, 0xC3, 0x3C, 0xE4, 0x08, 0x94,
+ 0x15, 0x4E, 0xB4, 0x39, 0x58, 0x00, 0x3E, 0x29,
+ 0x45, 0x3A, 0x84, 0x36, 0xF1, 0x2A, 0x50, 0x11,
+ 0xC4, 0x5A, 0xFC, 0xBF, 0xD9, 0xF9, 0x17, 0x9B,
+ 0x8E, 0x18, 0x63, 0x4C, 0x2F, 0x78, 0x2D, 0x5E,
+ 0x9A, 0xCD, 0x24, 0xEC, 0x7C, 0x97, 0x61, 0xCB,
+ 0x1E, 0xF4, 0xD5, 0xB1, 0x5C, 0x25, 0xE8, 0x1C };
+
+unsigned char table_110[256] = {
+ 0xC3, 0x06, 0x3C, 0xCB, 0xD2, 0x44, 0x9D, 0x48,
+ 0x28, 0xAA, 0xA9, 0xD0, 0x64, 0x25, 0x56, 0xCA,
+ 0xC2, 0xF8, 0x5C, 0xAE, 0x4E, 0x63, 0xB2, 0xE9,
+ 0x35, 0x11, 0xA8, 0x1A, 0x76, 0x15, 0xE0, 0x26,
+ 0x97, 0x99, 0xD4, 0x43, 0x80, 0xEE, 0xC1, 0x69,
+ 0xA6, 0x1E, 0x7A, 0x42, 0x55, 0x38, 0xBF, 0x75,
+ 0x0E, 0x29, 0xF5, 0xF3, 0x36, 0x7D, 0x51, 0xE8,
+ 0xE5, 0xEB, 0x68, 0x60, 0x0C, 0x70, 0xFD, 0xCC,
+ 0xE3, 0x23, 0x09, 0x6D, 0x2D, 0x6C, 0x5E, 0xB6,
+ 0x98, 0x8B, 0x1F, 0x50, 0x34, 0x8D, 0x10, 0x92,
+ 0x82, 0x85, 0xD5, 0x79, 0x02, 0xA4, 0x0A, 0xBC,
+ 0x40, 0xC6, 0xA3, 0x72, 0x8F, 0xC4, 0xA5, 0xE4,
+ 0x49, 0xD6, 0xCE, 0xA1, 0x12, 0x4F, 0x30, 0x31,
+ 0xDE, 0x2A, 0xF7, 0x95, 0xB5, 0x96, 0x14, 0x08,
+ 0xE6, 0x3D, 0x86, 0xF2, 0x47, 0x74, 0xB8, 0x5D,
+ 0x1D, 0x2B, 0x3A, 0x93, 0x7C, 0x6A, 0x01, 0xA0,
+ 0x9A, 0x4D, 0xB7, 0x71, 0xA7, 0x41, 0xC5, 0x65,
+ 0xC8, 0x89, 0xD1, 0x3E, 0x0D, 0xD8, 0xFF, 0x6F,
+ 0x7F, 0xA2, 0xFE, 0xD9, 0xF0, 0x4A, 0x07, 0x1C,
+ 0x0F, 0x6E, 0x03, 0x81, 0x1B, 0x05, 0xDF, 0x52,
+ 0xF1, 0x8A, 0xF9, 0xDD, 0x91, 0x3B, 0xD7, 0xE1,
+ 0x54, 0xAD, 0x90, 0x5A, 0x7B, 0xC7, 0x32, 0x62,
+ 0x16, 0x27, 0xB9, 0x66, 0x21, 0x88, 0xBD, 0x18,
+ 0x77, 0x8E, 0x94, 0x8C, 0x9B, 0x46, 0x9C, 0xB1,
+ 0xD3, 0x53, 0xB0, 0xBE, 0xAC, 0xAF, 0x73, 0x24,
+ 0xDA, 0x58, 0xE2, 0xFC, 0x78, 0xEA, 0xCD, 0xFA,
+ 0x37, 0xED, 0x13, 0x19, 0xC0, 0x59, 0x83, 0xBA,
+ 0x3F, 0x57, 0x00, 0x7E, 0xC9, 0x2E, 0x17, 0x5B,
+ 0x84, 0xF6, 0xE7, 0x22, 0xFB, 0x5F, 0x4C, 0x2C,
+ 0x61, 0x9F, 0x45, 0x39, 0xB3, 0xEC, 0x04, 0x87,
+ 0x67, 0xDC, 0x0B, 0xF4, 0x20, 0xAB, 0x6B, 0x9E,
+ 0x4B, 0xCF, 0xB4, 0x2F, 0xBB, 0xEF, 0xDB, 0x33 };
+
+unsigned char table_111[32] = {
+ 0x09, 0x0F, 0x00, 0x15, 0x12, 0x17, 0x1A, 0x0D,
+ 0x1C, 0x0B, 0x01, 0x0A, 0x05, 0x1E, 0x1D, 0x0C,
+ 0x1B, 0x08, 0x19, 0x18, 0x14, 0x07, 0x0E, 0x03,
+ 0x10, 0x16, 0x11, 0x1F, 0x04, 0x06, 0x02, 0x13 };
+
+unsigned char table_112[256] = {
+ 0xF9, 0x7D, 0xBE, 0xD5, 0x9F, 0xB8, 0x95, 0x43,
+ 0xDB, 0xAE, 0x7E, 0xEC, 0x5B, 0x58, 0x18, 0x49,
+ 0x4B, 0x9D, 0x1C, 0x3E, 0x61, 0xD1, 0xF6, 0x2F,
+ 0x41, 0x82, 0x51, 0x37, 0x72, 0x79, 0x05, 0x2A,
+ 0xC2, 0xB0, 0xE2, 0xE7, 0xB2, 0xF3, 0x1B, 0x92,
+ 0x86, 0xBB, 0xDC, 0x90, 0x1A, 0x19, 0xD7, 0xBA,
+ 0x2C, 0x7B, 0xEF, 0xC7, 0x8A, 0x81, 0xEB, 0xDE,
+ 0x73, 0x4E, 0xB7, 0x97, 0xCA, 0x29, 0x85, 0xC1,
+ 0xA5, 0x7F, 0xFE, 0x56, 0xE9, 0x9E, 0x21, 0x76,
+ 0x3A, 0x88, 0x70, 0xC6, 0xD3, 0x8C, 0x47, 0xC8,
+ 0x83, 0x48, 0xC3, 0x6A, 0x9C, 0x80, 0x53, 0xBD,
+ 0xFD, 0x54, 0x09, 0x91, 0x94, 0xAA, 0x7A, 0x59,
+ 0x71, 0xDD, 0xA8, 0x07, 0xCB, 0x0F, 0xE0, 0x9A,
+ 0x36, 0x4C, 0x4D, 0x0D, 0xA4, 0x96, 0x6F, 0x14,
+ 0x22, 0x38, 0xAD, 0x02, 0xF4, 0x0B, 0xEA, 0x93,
+ 0x20, 0x04, 0xBC, 0xE8, 0x6C, 0xFB, 0x10, 0x6B,
+ 0x40, 0xB6, 0x24, 0x17, 0x06, 0x31, 0xD9, 0x33,
+ 0xF5, 0x99, 0x57, 0xCD, 0xAB, 0x67, 0x5C, 0x30,
+ 0x1E, 0x34, 0xB4, 0x3F, 0x16, 0x42, 0xA2, 0x68,
+ 0x27, 0xB3, 0x1D, 0xED, 0x5F, 0x52, 0xF7, 0x3C,
+ 0x65, 0x5D, 0xE5, 0x23, 0x0C, 0x6D, 0x84, 0x6E,
+ 0xDA, 0x77, 0xF8, 0x15, 0xFA, 0x69, 0xD0, 0xA7,
+ 0x11, 0xAC, 0xA6, 0xA3, 0x1F, 0x2E, 0xBF, 0x4A,
+ 0x8F, 0xFC, 0xEE, 0xC9, 0x26, 0x12, 0xC0, 0xB1,
+ 0x45, 0x0E, 0x3D, 0x7C, 0xCE, 0x13, 0x8E, 0x98,
+ 0x46, 0x2B, 0xC5, 0x66, 0x28, 0x32, 0xD2, 0x03,
+ 0xE3, 0xC4, 0x9B, 0x89, 0x5E, 0xF0, 0xCF, 0x3B,
+ 0x2D, 0x50, 0xB5, 0x00, 0x0A, 0xD6, 0x55, 0xE1,
+ 0x62, 0x63, 0x64, 0x87, 0xAF, 0x78, 0xB9, 0xF2,
+ 0x25, 0x44, 0xFF, 0x39, 0xF1, 0x08, 0x4F, 0x74,
+ 0xA9, 0x8B, 0x75, 0x01, 0xA0, 0xE4, 0x35, 0x8D,
+ 0xA1, 0xCC, 0xDF, 0x60, 0xD8, 0x5A, 0xE6, 0xD4 };
+
+unsigned char table_113[256] = {
+ 0x46, 0x9D, 0x39, 0xB2, 0x8D, 0x3B, 0x59, 0x5A,
+ 0xD0, 0x9C, 0xE4, 0x04, 0x01, 0xE2, 0xB3, 0xD2,
+ 0xD7, 0x18, 0x40, 0xD8, 0xF1, 0xEF, 0x3A, 0x1D,
+ 0x8E, 0xE5, 0xD9, 0xD3, 0xCB, 0x49, 0x4C, 0xCF,
+ 0xC0, 0xD6, 0xB5, 0x73, 0x77, 0x82, 0x54, 0xA2,
+ 0xB1, 0xB0, 0x84, 0x5D, 0xC7, 0xDE, 0x31, 0x2F,
+ 0x50, 0x78, 0xBE, 0x94, 0x64, 0x44, 0x60, 0x7A,
+ 0x1A, 0x6E, 0x09, 0x6F, 0xBF, 0x76, 0x81, 0x38,
+ 0x22, 0xC3, 0xEE, 0x8F, 0xFB, 0x32, 0xED, 0x92,
+ 0xAE, 0xE6, 0x5F, 0xAA, 0xAC, 0x0D, 0xA3, 0x47,
+ 0x1F, 0x11, 0xC1, 0x29, 0xAF, 0xFD, 0x1C, 0xDB,
+ 0x00, 0x23, 0xB9, 0xB8, 0x91, 0x41, 0x27, 0x37,
+ 0x43, 0x02, 0x26, 0xF6, 0x7D, 0x0A, 0x85, 0x93,
+ 0x97, 0x2E, 0x20, 0x55, 0x13, 0x4B, 0x6C, 0xE7,
+ 0xFC, 0x25, 0xFA, 0x9E, 0x5B, 0xA1, 0xDF, 0x2C,
+ 0x3E, 0xBC, 0xEA, 0x42, 0x7C, 0x36, 0x30, 0xEB,
+ 0xBD, 0x8B, 0x87, 0x16, 0x3D, 0x5C, 0x07, 0xBA,
+ 0xB4, 0x1B, 0xC2, 0xE3, 0x71, 0x9A, 0x5E, 0x4D,
+ 0xF2, 0xCC, 0x0E, 0xE1, 0x34, 0x75, 0x58, 0x89,
+ 0x17, 0xD4, 0x68, 0x80, 0x2B, 0x74, 0x70, 0x8A,
+ 0x63, 0xE8, 0x56, 0x24, 0xD1, 0x57, 0x35, 0x6D,
+ 0x3C, 0xA6, 0xC8, 0x7E, 0xA8, 0x4E, 0xC4, 0x33,
+ 0xA9, 0x62, 0x61, 0x7F, 0x21, 0x98, 0x2A, 0xAD,
+ 0xB6, 0xA7, 0xF5, 0x3F, 0x15, 0x45, 0xF8, 0xA4,
+ 0x95, 0x88, 0xDC, 0x96, 0x90, 0x08, 0x9B, 0xF9,
+ 0x06, 0x14, 0x05, 0xF0, 0xF7, 0xA0, 0xE0, 0x65,
+ 0xCA, 0xA5, 0x9F, 0x79, 0xCD, 0x4F, 0x72, 0xB7,
+ 0x4A, 0x0F, 0x66, 0xC5, 0x0C, 0x52, 0xF3, 0x69,
+ 0x83, 0x03, 0x99, 0x1E, 0x2D, 0xDA, 0x8C, 0x53,
+ 0x28, 0xDD, 0xE9, 0x0B, 0xC9, 0xF4, 0x48, 0x12,
+ 0x6A, 0x19, 0xCE, 0xAB, 0x51, 0xD5, 0x6B, 0xBB,
+ 0xFE, 0x7B, 0x67, 0xFF, 0x10, 0xEC, 0xC6, 0x86 };
+
+unsigned char table_114[32] = {
+ 0x11, 0x10, 0x04, 0x1D, 0x08, 0x15, 0x1A, 0x1B,
+ 0x14, 0x18, 0x0F, 0x17, 0x16, 0x07, 0x1E, 0x0E,
+ 0x12, 0x0A, 0x13, 0x0B, 0x0C, 0x00, 0x06, 0x02,
+ 0x1F, 0x19, 0x09, 0x1C, 0x01, 0x0D, 0x03, 0x05 };
+
+unsigned char table_115[256] = {
+ 0xB7, 0xBB, 0x63, 0x0D, 0xF0, 0x33, 0x5A, 0x05,
+ 0xF2, 0x7F, 0x64, 0xDB, 0x51, 0xC9, 0x2C, 0x85,
+ 0x4F, 0x41, 0xA4, 0x42, 0xCF, 0xA6, 0x52, 0x2F,
+ 0x26, 0xEF, 0xFB, 0x29, 0x40, 0x16, 0xF7, 0xED,
+ 0x23, 0x69, 0x8A, 0xDF, 0x77, 0x28, 0x93, 0x14,
+ 0x82, 0x0C, 0xBE, 0x3D, 0x20, 0xB4, 0x79, 0x94,
+ 0x54, 0xF8, 0x07, 0xB1, 0xE1, 0x66, 0x73, 0xD3,
+ 0x19, 0x15, 0xFF, 0x03, 0x6A, 0x9A, 0xDC, 0x1C,
+ 0xB3, 0x5D, 0x76, 0x68, 0x47, 0x6C, 0xF9, 0xFD,
+ 0xE9, 0xDD, 0x01, 0x65, 0xBD, 0x80, 0x0E, 0x7A,
+ 0x8D, 0x99, 0x13, 0x7C, 0xA5, 0xA7, 0x1A, 0xCC,
+ 0xB8, 0xE6, 0x2B, 0xB2, 0xB6, 0xD0, 0x62, 0x2D,
+ 0x4D, 0xD2, 0xB9, 0x04, 0x46, 0xAE, 0xAA, 0x44,
+ 0xDA, 0x92, 0x4B, 0x4E, 0xC4, 0xE2, 0xFE, 0xA2,
+ 0x75, 0x7B, 0xC3, 0xFA, 0x9F, 0x37, 0x9D, 0x1E,
+ 0x72, 0xD4, 0x1F, 0x4A, 0x9B, 0xE5, 0x6D, 0xEC,
+ 0x5C, 0x7D, 0x98, 0xE8, 0xEE, 0x86, 0xD1, 0xC8,
+ 0xEA, 0x55, 0xBF, 0xAF, 0xDE, 0x32, 0x09, 0x3A,
+ 0x8F, 0x57, 0x83, 0x43, 0x61, 0xC6, 0x8E, 0x96,
+ 0x22, 0xA3, 0x97, 0x91, 0x5F, 0x11, 0x3B, 0x5B,
+ 0x1B, 0x34, 0x49, 0x95, 0xF1, 0x6F, 0x89, 0xA8,
+ 0xC0, 0x36, 0x0A, 0x3F, 0x60, 0x50, 0xE7, 0x08,
+ 0xCE, 0x25, 0xC1, 0x71, 0xF6, 0x59, 0x58, 0x56,
+ 0x4C, 0xAB, 0x27, 0xAC, 0x06, 0xCB, 0x00, 0x30,
+ 0x84, 0x3E, 0xC2, 0x1D, 0x02, 0xE0, 0xC5, 0xD6,
+ 0x18, 0x70, 0xA9, 0x88, 0xD9, 0x39, 0x8B, 0x6E,
+ 0xF4, 0x24, 0xA0, 0x48, 0x45, 0x21, 0x87, 0x78,
+ 0x38, 0x90, 0xE3, 0xCA, 0xF5, 0xD7, 0x2A, 0x53,
+ 0x9C, 0xCD, 0x31, 0x35, 0xAD, 0x74, 0xD8, 0x12,
+ 0xBC, 0x9E, 0x6B, 0x67, 0xB0, 0xBA, 0xE4, 0x10,
+ 0x5E, 0xFC, 0xC7, 0x0F, 0x2E, 0x81, 0x7E, 0xA1,
+ 0x8C, 0x17, 0xB5, 0xEB, 0xD5, 0xF3, 0x0B, 0x3C };
+
+unsigned char table_116[32] = {
+ 0x00, 0x05, 0x10, 0x1C, 0x0C, 0x1A, 0x04, 0x1B,
+ 0x0A, 0x0D, 0x14, 0x0B, 0x07, 0x03, 0x12, 0x1E,
+ 0x06, 0x11, 0x01, 0x08, 0x15, 0x09, 0x1F, 0x0F,
+ 0x19, 0x18, 0x16, 0x02, 0x13, 0x0E, 0x17, 0x1D };
+
+unsigned char table_117[256] = {
+ 0xD0, 0x9A, 0xAB, 0xA8, 0xA7, 0xDF, 0x28, 0xCE,
+ 0x3E, 0x51, 0xBF, 0x76, 0x03, 0xA0, 0x53, 0x3F,
+ 0x90, 0x93, 0x87, 0x67, 0x98, 0x3D, 0xEA, 0x8B,
+ 0x55, 0xCF, 0x10, 0xF3, 0x25, 0xFC, 0x9F, 0x41,
+ 0x6B, 0x54, 0x6E, 0x0B, 0x83, 0x35, 0x69, 0x7D,
+ 0xE0, 0x88, 0x4B, 0xE9, 0x1E, 0x96, 0x91, 0x57,
+ 0xBD, 0x72, 0x21, 0x3C, 0xA6, 0x99, 0x6C, 0xF6,
+ 0x13, 0xFA, 0x29, 0xED, 0xDB, 0x16, 0x4D, 0x07,
+ 0x45, 0xA5, 0xE3, 0x0E, 0x31, 0xBC, 0x56, 0x5C,
+ 0xB2, 0x23, 0xDA, 0x74, 0xFF, 0x02, 0x8F, 0xF4,
+ 0x2A, 0xC9, 0x89, 0xAA, 0x05, 0xB1, 0xD1, 0x1F,
+ 0x4F, 0xB0, 0x7A, 0x2C, 0x14, 0xD9, 0xE7, 0x66,
+ 0x62, 0x1A, 0x4C, 0xC0, 0xC6, 0x63, 0x7F, 0xB4,
+ 0xF1, 0x43, 0xFE, 0x61, 0xA3, 0xCC, 0xE8, 0x6D,
+ 0xBA, 0x65, 0x42, 0x2B, 0xCA, 0xD5, 0x52, 0x3A,
+ 0xCD, 0x1D, 0x24, 0xD7, 0x47, 0xDE, 0x9E, 0x95,
+ 0x85, 0x48, 0x86, 0xE1, 0xC5, 0xD2, 0x34, 0xAF,
+ 0x40, 0xFB, 0xE6, 0x4E, 0xC8, 0xF5, 0x7B, 0x5A,
+ 0xCB, 0xD4, 0x97, 0x6F, 0x0C, 0x79, 0x9C, 0x20,
+ 0x59, 0x19, 0x68, 0x2E, 0x09, 0x64, 0x73, 0x50,
+ 0xC2, 0x2F, 0x0D, 0xEF, 0x9D, 0x94, 0x00, 0x81,
+ 0xE2, 0x46, 0x5F, 0xB8, 0x0A, 0x12, 0x75, 0x1C,
+ 0x8C, 0xB6, 0x71, 0xAC, 0x04, 0x60, 0xA9, 0x5B,
+ 0xF8, 0x30, 0x49, 0x44, 0x4A, 0xBE, 0x6A, 0xEB,
+ 0xD3, 0xD8, 0x36, 0xB3, 0x3B, 0x17, 0x80, 0xA4,
+ 0xEC, 0x26, 0x82, 0xB5, 0x37, 0x5D, 0x1B, 0x2D,
+ 0xE5, 0xA2, 0x0F, 0xB7, 0xC4, 0xF2, 0x70, 0x39,
+ 0xF9, 0xC7, 0xBB, 0x8A, 0x32, 0x78, 0xC3, 0x5E,
+ 0xD6, 0xE4, 0x22, 0x9B, 0x18, 0x8E, 0xEE, 0x27,
+ 0x8D, 0x33, 0x11, 0x77, 0x01, 0x06, 0x38, 0xF0,
+ 0x7E, 0x08, 0x15, 0xB9, 0x7C, 0xAD, 0x84, 0xDD,
+ 0xC1, 0xFD, 0x92, 0xA1, 0xF7, 0xAE, 0xDC, 0x58 };
+
+unsigned char table_118[256] = {
+ 0x38, 0xA0, 0xA6, 0xFC, 0x7C, 0x5A, 0x97, 0x1D,
+ 0xFD, 0x00, 0x20, 0xA2, 0x72, 0x10, 0x1F, 0x48,
+ 0x98, 0x7E, 0xDF, 0x2D, 0x80, 0x0A, 0x27, 0xDC,
+ 0xCF, 0xBF, 0x92, 0x94, 0x53, 0xCC, 0x0E, 0x74,
+ 0xA7, 0x60, 0x08, 0x15, 0x87, 0x6F, 0xB3, 0xA3,
+ 0xED, 0x59, 0x09, 0x4F, 0x9E, 0x9A, 0xEE, 0x83,
+ 0x56, 0x32, 0x34, 0xC7, 0x24, 0xE7, 0x96, 0x4D,
+ 0xAE, 0xE3, 0xBD, 0xE2, 0x36, 0x4A, 0xB6, 0x8B,
+ 0xF2, 0xC1, 0xD7, 0x40, 0x31, 0x4B, 0xDA, 0xF1,
+ 0xB1, 0x70, 0xA8, 0xC3, 0xC6, 0x8A, 0xE6, 0x77,
+ 0x21, 0x7D, 0xD5, 0x0C, 0x43, 0xC4, 0xF0, 0x1B,
+ 0x18, 0xA1, 0x85, 0xE1, 0xFF, 0x8D, 0xE5, 0x6E,
+ 0x9B, 0x51, 0x1C, 0xA4, 0x5C, 0x8E, 0x69, 0x49,
+ 0x23, 0xCD, 0x52, 0xF8, 0x3E, 0x91, 0x5E, 0x1E,
+ 0x25, 0xB4, 0x93, 0xCB, 0xE0, 0x47, 0xBC, 0x4E,
+ 0x33, 0xB7, 0x75, 0x1A, 0x11, 0x9C, 0x3F, 0xEC,
+ 0xD1, 0x46, 0xDD, 0xAA, 0xB8, 0x99, 0x86, 0x67,
+ 0x58, 0xF9, 0x16, 0x17, 0x6D, 0x5F, 0x2B, 0xA5,
+ 0xD3, 0x8F, 0x55, 0x71, 0xD2, 0xBA, 0x5B, 0x3C,
+ 0x82, 0xB5, 0x41, 0xE4, 0x90, 0x45, 0x6C, 0xF6,
+ 0xDE, 0xA9, 0x84, 0x62, 0x19, 0x3B, 0xB9, 0xC8,
+ 0x2C, 0xB0, 0x76, 0x57, 0xD8, 0x26, 0x9D, 0x89,
+ 0xC9, 0x54, 0xFB, 0x07, 0xCE, 0x22, 0x5D, 0x64,
+ 0x65, 0xAD, 0x01, 0xDB, 0x14, 0x4C, 0x37, 0x03,
+ 0x6B, 0xAF, 0xD0, 0x7F, 0x9F, 0xBB, 0xEB, 0xC0,
+ 0x50, 0x66, 0x68, 0x0B, 0x42, 0x2A, 0xD4, 0xF5,
+ 0x61, 0x63, 0xF3, 0x39, 0xBE, 0xC5, 0xEF, 0x28,
+ 0x3A, 0xAB, 0x79, 0x05, 0xE9, 0x12, 0x73, 0x3D,
+ 0xB2, 0x8C, 0xCA, 0x29, 0x0F, 0xF4, 0x7B, 0x13,
+ 0x88, 0x44, 0xC2, 0x2E, 0xFA, 0xFE, 0x04, 0x35,
+ 0xE8, 0x06, 0x7A, 0x78, 0x0D, 0x81, 0xF7, 0xEA,
+ 0xD9, 0x2F, 0x02, 0xAC, 0x30, 0x6A, 0xD6, 0x95 };
+
+unsigned char table_119[32] = {
+ 0x14, 0x0A, 0x1C, 0x00, 0x0C, 0x1F, 0x1E, 0x0B,
+ 0x12, 0x1D, 0x17, 0x08, 0x07, 0x04, 0x09, 0x10,
+ 0x03, 0x1B, 0x0E, 0x1A, 0x05, 0x0D, 0x11, 0x15,
+ 0x18, 0x02, 0x06, 0x01, 0x19, 0x16, 0x13, 0x0F };
+
+unsigned char table_120[256] = {
+ 0xCE, 0x89, 0xB2, 0x72, 0x04, 0x77, 0x64, 0xAE,
+ 0x80, 0x99, 0xB5, 0x00, 0x7B, 0x50, 0x9D, 0xE3,
+ 0x87, 0x37, 0x6D, 0x3D, 0x32, 0xBA, 0x20, 0xF0,
+ 0xDC, 0xBD, 0x61, 0x26, 0xD4, 0xA6, 0x70, 0x54,
+ 0xC1, 0x7D, 0x82, 0xFF, 0x81, 0x83, 0x2F, 0xF5,
+ 0x3B, 0x42, 0x08, 0x5C, 0x30, 0x59, 0xBB, 0xC2,
+ 0x33, 0x5D, 0xEE, 0xB7, 0xF7, 0x2B, 0x76, 0xD0,
+ 0x43, 0x1C, 0x48, 0xFC, 0x01, 0xCD, 0x27, 0x1D,
+ 0x5A, 0x96, 0x95, 0x03, 0xC6, 0x1F, 0x09, 0xCB,
+ 0xF6, 0x47, 0xA9, 0x93, 0xA7, 0xD2, 0xDB, 0x51,
+ 0xB0, 0x7A, 0xE6, 0x62, 0x0F, 0x12, 0x57, 0xF4,
+ 0x35, 0xFE, 0xA4, 0xDF, 0x5B, 0xF3, 0x67, 0x85,
+ 0x98, 0xE4, 0xAB, 0x75, 0x4C, 0xE2, 0x25, 0x74,
+ 0x3A, 0x45, 0xDE, 0xEF, 0x4A, 0x97, 0x86, 0x24,
+ 0xE9, 0x8F, 0xD8, 0xD7, 0x60, 0xAD, 0x36, 0x8E,
+ 0x1E, 0xB9, 0x4F, 0x6B, 0x8C, 0x06, 0x23, 0x94,
+ 0x0E, 0xD3, 0x49, 0x14, 0x90, 0xAF, 0x65, 0xEC,
+ 0xF9, 0x0D, 0xED, 0x6C, 0xBE, 0x7F, 0xA5, 0xC5,
+ 0xEA, 0x78, 0x2E, 0xBC, 0xD5, 0xDA, 0x18, 0xE1,
+ 0x10, 0x2D, 0xB4, 0x16, 0x4B, 0xE8, 0xC4, 0x8D,
+ 0x19, 0x1B, 0x02, 0x66, 0xB6, 0xE7, 0x9C, 0x7C,
+ 0xC9, 0xA0, 0x2A, 0x53, 0x13, 0xDD, 0xF8, 0xA8,
+ 0x0A, 0x6E, 0xCF, 0x6F, 0x7E, 0xE0, 0x3E, 0xE5,
+ 0x07, 0xCC, 0x38, 0xD1, 0xF2, 0x2C, 0x9A, 0xAC,
+ 0x88, 0x79, 0xB8, 0xC8, 0xBF, 0x63, 0x71, 0x69,
+ 0x52, 0x39, 0x9F, 0x22, 0x3F, 0x9E, 0x44, 0xFA,
+ 0x73, 0x6A, 0x8B, 0xA2, 0xD6, 0x1A, 0x9B, 0xB1,
+ 0x8A, 0x4D, 0x58, 0xA1, 0x46, 0x5F, 0x55, 0x56,
+ 0x21, 0x05, 0x15, 0x92, 0xAA, 0xEB, 0x31, 0x68,
+ 0xFB, 0x41, 0xC3, 0x4E, 0xB3, 0x40, 0x34, 0x17,
+ 0xD9, 0x29, 0x3C, 0x0C, 0xF1, 0x0B, 0x28, 0x84,
+ 0x5E, 0xCA, 0xFD, 0x11, 0xA3, 0xC7, 0xC0, 0x91 };
+
+unsigned char table_121[32] = {
+ 0x1E, 0x12, 0x06, 0x1D, 0x15, 0x1F, 0x13, 0x0B,
+ 0x10, 0x0D, 0x1C, 0x01, 0x0A, 0x0E, 0x02, 0x19,
+ 0x04, 0x1A, 0x03, 0x11, 0x00, 0x16, 0x0C, 0x17,
+ 0x14, 0x08, 0x18, 0x05, 0x09, 0x0F, 0x1B, 0x07 };
+
+unsigned char table_122[256] = {
+ 0x85, 0xDF, 0x7F, 0x7C, 0x56, 0xF0, 0x0C, 0x7D,
+ 0x76, 0xA8, 0x58, 0x31, 0x25, 0x8A, 0x0D, 0x23,
+ 0x05, 0x0F, 0x12, 0x64, 0x8E, 0x5D, 0xF4, 0x2C,
+ 0x18, 0xFA, 0x4B, 0xFE, 0x91, 0xBF, 0x95, 0x0B,
+ 0xF1, 0x88, 0x10, 0xD8, 0x3E, 0x53, 0x96, 0xB5,
+ 0x75, 0x24, 0x8F, 0xD6, 0x68, 0x5C, 0x93, 0x1F,
+ 0x6B, 0xC2, 0xAB, 0xED, 0x1E, 0xC0, 0xBC, 0x47,
+ 0xE9, 0xD1, 0xDE, 0xCA, 0xF6, 0x62, 0x43, 0xEB,
+ 0xA2, 0xB4, 0x08, 0xE6, 0x74, 0x0E, 0xA1, 0x72,
+ 0x66, 0x61, 0x21, 0x2E, 0x32, 0x63, 0x29, 0xD7,
+ 0x1C, 0x22, 0xAC, 0xE7, 0x54, 0xF3, 0x65, 0x17,
+ 0x9F, 0x78, 0x79, 0x4C, 0xDD, 0x27, 0x90, 0x36,
+ 0x19, 0x44, 0x03, 0xD9, 0x4A, 0x5A, 0x34, 0xF9,
+ 0x97, 0xA6, 0x70, 0x39, 0x28, 0x77, 0x6E, 0xB7,
+ 0x8C, 0x02, 0x5E, 0x9B, 0x8D, 0x59, 0x6F, 0xA5,
+ 0x07, 0xE2, 0x41, 0x51, 0xC9, 0x3C, 0xE8, 0xE1,
+ 0xB3, 0x16, 0x50, 0x04, 0xE3, 0x1D, 0x3B, 0xD2,
+ 0x4D, 0x35, 0x71, 0xDA, 0x9E, 0xA7, 0xE4, 0xE0,
+ 0xB6, 0x2B, 0xEA, 0x84, 0x55, 0xF8, 0x57, 0x3D,
+ 0x73, 0x42, 0xC6, 0x0A, 0x92, 0x6A, 0xAE, 0xF5,
+ 0xFC, 0xD5, 0x15, 0x52, 0x7E, 0x14, 0x81, 0x13,
+ 0xE5, 0x49, 0x38, 0x2A, 0x94, 0x5B, 0xA3, 0x11,
+ 0x8B, 0x80, 0xBB, 0x01, 0x9C, 0xA4, 0xDB, 0xF7,
+ 0xA9, 0x20, 0xF2, 0x1A, 0xDC, 0x33, 0x3A, 0xEF,
+ 0xD3, 0xFD, 0x30, 0xB0, 0x1B, 0xC4, 0x06, 0xD4,
+ 0x6D, 0x87, 0x2F, 0x60, 0x5F, 0xC5, 0x09, 0x37,
+ 0xAF, 0x00, 0xCB, 0x9D, 0xA0, 0xB9, 0x45, 0x86,
+ 0x4F, 0x6C, 0x67, 0xFB, 0x40, 0x3F, 0xCC, 0xB8,
+ 0xC8, 0x82, 0x98, 0x99, 0x7B, 0xB1, 0xCD, 0xD0,
+ 0xBD, 0x48, 0xAD, 0x26, 0x7A, 0x9A, 0x46, 0xFF,
+ 0x89, 0xC7, 0xC1, 0xCF, 0xBE, 0xAA, 0xEC, 0xBA,
+ 0xCE, 0x2D, 0x4E, 0x83, 0xC3, 0x69, 0xEE, 0xB2 };
+
+unsigned char table_123[256] = {
+ 0x9D, 0xFB, 0x3C, 0x81, 0xAA, 0x05, 0xB2, 0xBE,
+ 0xD1, 0x5F, 0x4C, 0xE0, 0xA3, 0xF4, 0xDE, 0x35,
+ 0xFE, 0x1B, 0x37, 0x99, 0x94, 0x7A, 0x10, 0xAB,
+ 0xC0, 0xA4, 0xB5, 0xFF, 0x8F, 0x3B, 0xB4, 0x51,
+ 0x04, 0xE9, 0xB9, 0xC1, 0x98, 0xC5, 0x82, 0x38,
+ 0x4D, 0x71, 0xFC, 0x33, 0xC4, 0x50, 0x5D, 0x88,
+ 0xB8, 0x5C, 0x32, 0xE2, 0xBB, 0xCD, 0x60, 0x2C,
+ 0xD4, 0x7E, 0x27, 0x59, 0x2B, 0x1F, 0x53, 0xF6,
+ 0x25, 0x86, 0xAE, 0x21, 0xFA, 0x31, 0xD7, 0x0F,
+ 0x17, 0xDA, 0x7F, 0xC9, 0x46, 0x19, 0x08, 0xA8,
+ 0xCF, 0x13, 0xCC, 0x03, 0x3F, 0x22, 0x6E, 0xEB,
+ 0x4A, 0x63, 0x73, 0xBD, 0x36, 0xED, 0x30, 0x57,
+ 0x65, 0xF8, 0x41, 0x61, 0x1E, 0xA0, 0xC6, 0x45,
+ 0x3E, 0x75, 0x28, 0x87, 0xCB, 0xD6, 0x16, 0xD8,
+ 0xDF, 0xEF, 0xEA, 0xA7, 0x58, 0xB0, 0x1D, 0xE6,
+ 0x47, 0x76, 0xD9, 0x96, 0xE7, 0xDC, 0x00, 0x80,
+ 0xDD, 0xB7, 0x9A, 0xE1, 0xF5, 0x9C, 0x4B, 0xE3,
+ 0xBC, 0x8D, 0xF2, 0x2F, 0x9F, 0x6C, 0x93, 0xAF,
+ 0xA9, 0xC2, 0x5E, 0x24, 0x15, 0xD2, 0x09, 0x0D,
+ 0xDB, 0x4F, 0x91, 0x0E, 0x64, 0x34, 0x4E, 0xAD,
+ 0x62, 0x44, 0x23, 0x85, 0xB6, 0xAC, 0xC7, 0xCA,
+ 0x84, 0xF9, 0x8C, 0xBF, 0x14, 0x7C, 0x8E, 0x92,
+ 0xF0, 0x0B, 0xCE, 0x90, 0x7D, 0x70, 0x9E, 0x54,
+ 0x39, 0x5B, 0x6D, 0x52, 0xEE, 0xA2, 0x6F, 0x78,
+ 0x2D, 0x95, 0x8B, 0x02, 0x3D, 0x7B, 0x69, 0xC3,
+ 0x49, 0xA5, 0x1A, 0x26, 0xD5, 0x6B, 0xE8, 0xFD,
+ 0xB3, 0xD3, 0x20, 0x55, 0x18, 0x06, 0xF3, 0xB1,
+ 0x0C, 0xC8, 0x07, 0x12, 0xF7, 0x01, 0x2E, 0x72,
+ 0x97, 0xA6, 0x11, 0x89, 0x56, 0x5A, 0x29, 0xBA,
+ 0x67, 0x42, 0x83, 0x6A, 0x2A, 0xF1, 0xA1, 0x9B,
+ 0xE5, 0xE4, 0x74, 0x66, 0x1C, 0x68, 0xEC, 0x40,
+ 0x48, 0x77, 0xD0, 0x0A, 0x8A, 0x3A, 0x43, 0x79 };
+
+unsigned char table_124[256] = {
+ 0x6C, 0xC3, 0x28, 0x2F, 0x42, 0x4B, 0x7C, 0x3C,
+ 0xCE, 0x24, 0xC8, 0x51, 0x25, 0x3F, 0x49, 0x8D,
+ 0x1E, 0x5C, 0x89, 0x3A, 0x98, 0x47, 0x0B, 0x12,
+ 0xA9, 0xB1, 0xD7, 0xB6, 0x5D, 0xF9, 0x5A, 0xBC,
+ 0xFA, 0x06, 0x7D, 0x08, 0xFC, 0x37, 0x54, 0x4F,
+ 0xD4, 0xCD, 0xA7, 0x5E, 0xE0, 0x92, 0x82, 0x56,
+ 0xF1, 0x2B, 0xC4, 0xE2, 0x29, 0xEA, 0x35, 0x57,
+ 0x33, 0x4E, 0x1A, 0x17, 0x8B, 0x85, 0xBF, 0xD5,
+ 0x18, 0xB3, 0x0D, 0x71, 0x45, 0x81, 0xB4, 0x27,
+ 0xD1, 0xE1, 0xFF, 0x44, 0x9E, 0xA4, 0x15, 0x9A,
+ 0x90, 0xC7, 0x79, 0xE3, 0x4C, 0xE9, 0x3D, 0x6B,
+ 0xF5, 0xF4, 0xEE, 0xAA, 0xDB, 0x07, 0x09, 0xCF,
+ 0x7B, 0x95, 0xA0, 0x53, 0x8F, 0xA1, 0x9D, 0xBE,
+ 0x6F, 0xAE, 0x96, 0x46, 0x59, 0x01, 0x84, 0xCC,
+ 0x3B, 0x8E, 0xF7, 0x4D, 0x6E, 0xDC, 0xE8, 0x36,
+ 0x7A, 0xE5, 0xBD, 0xE7, 0x9F, 0x2C, 0x52, 0xAB,
+ 0x55, 0x13, 0x1D, 0xFB, 0x58, 0x9C, 0xDF, 0xC0,
+ 0x30, 0x73, 0x67, 0x39, 0x74, 0xD3, 0x11, 0xD2,
+ 0x0E, 0x20, 0xB7, 0x02, 0xB9, 0x1C, 0x86, 0x76,
+ 0x10, 0x68, 0x9B, 0x63, 0x48, 0x8A, 0xB2, 0xB8,
+ 0xAF, 0x26, 0x99, 0x04, 0xB0, 0xE4, 0xEF, 0xEB,
+ 0xEC, 0x6D, 0x61, 0xC1, 0xD0, 0x38, 0xC9, 0x19,
+ 0x60, 0xA8, 0xA6, 0xF8, 0x80, 0xC5, 0x03, 0x0F,
+ 0x22, 0x2D, 0x88, 0x32, 0x77, 0x70, 0xFE, 0x0C,
+ 0x31, 0x40, 0x5F, 0xED, 0xA5, 0x93, 0x43, 0xF0,
+ 0x8C, 0xE6, 0x34, 0x21, 0xD9, 0xC2, 0xD8, 0xC6,
+ 0x6A, 0xD6, 0xCB, 0xAC, 0x75, 0xB5, 0x78, 0x0A,
+ 0xA3, 0x69, 0x16, 0xBA, 0x50, 0x2A, 0x41, 0x83,
+ 0xF6, 0x64, 0x00, 0x65, 0x7E, 0xDD, 0x5B, 0xDA,
+ 0x14, 0xFD, 0x3E, 0x7F, 0xCA, 0x66, 0x4A, 0x1F,
+ 0xA2, 0xAD, 0xF2, 0x23, 0xBB, 0x72, 0xF3, 0x94,
+ 0x62, 0x1B, 0xDE, 0x91, 0x87, 0x97, 0x05, 0x2E };
+
+unsigned char table_125[32] = {
+ 0x1A, 0x18, 0x12, 0x15, 0x00, 0x1C, 0x01, 0x0B,
+ 0x19, 0x1B, 0x1F, 0x11, 0x07, 0x10, 0x1E, 0x06,
+ 0x17, 0x04, 0x0A, 0x0E, 0x0D, 0x0C, 0x16, 0x08,
+ 0x02, 0x03, 0x13, 0x14, 0x09, 0x1D, 0x05, 0x0F };
+
+unsigned char table_126[32] = {
+ 0x1C, 0x1D, 0x07, 0x12, 0x18, 0x1A, 0x19, 0x09,
+ 0x0F, 0x14, 0x1F, 0x0B, 0x13, 0x04, 0x0E, 0x1E,
+ 0x0C, 0x0D, 0x01, 0x17, 0x1B, 0x16, 0x0A, 0x05,
+ 0x15, 0x10, 0x11, 0x08, 0x00, 0x03, 0x06, 0x02 };
+
+unsigned char table_127[256] = {
+ 0xA0, 0x66, 0xD8, 0x08, 0xEA, 0x39, 0x78, 0xAB,
+ 0x61, 0x4E, 0xC7, 0xD1, 0xA3, 0x1C, 0x9F, 0xCB,
+ 0x19, 0x51, 0x15, 0x92, 0x23, 0xFD, 0x7D, 0x1D,
+ 0x95, 0xAE, 0x0E, 0x8B, 0xE6, 0x7F, 0x86, 0x6D,
+ 0x06, 0xBD, 0x20, 0x1F, 0x3A, 0xE4, 0x54, 0x91,
+ 0x69, 0xD3, 0xE3, 0x3D, 0x4D, 0x31, 0x49, 0xA4,
+ 0x41, 0xF3, 0xE0, 0x11, 0x14, 0x9B, 0x96, 0x5A,
+ 0xC4, 0x8E, 0x34, 0xDB, 0xBA, 0x83, 0xD9, 0x81,
+ 0xAF, 0x58, 0x8A, 0x79, 0x13, 0xBC, 0x85, 0x37,
+ 0x9E, 0x6C, 0x57, 0x71, 0x8D, 0x97, 0x5F, 0x6F,
+ 0x1E, 0x74, 0x27, 0xFC, 0x5C, 0x7A, 0x64, 0x87,
+ 0xF5, 0xC6, 0xF2, 0x4F, 0xDE, 0x80, 0xAA, 0x84,
+ 0x2E, 0xDC, 0xE7, 0x40, 0x75, 0xC5, 0xB3, 0xC8,
+ 0xCE, 0x21, 0x02, 0x67, 0xB7, 0x10, 0x47, 0x6A,
+ 0xEE, 0x53, 0x2C, 0x16, 0x05, 0xC0, 0x63, 0x4C,
+ 0x0D, 0xBB, 0xC3, 0x38, 0x46, 0x68, 0x7E, 0xF9,
+ 0xB8, 0xB4, 0x3E, 0x36, 0xD5, 0xEC, 0x0B, 0xF6,
+ 0x33, 0x0A, 0x0F, 0x5B, 0xFB, 0x45, 0xEB, 0xA9,
+ 0x6E, 0x6B, 0xCF, 0x55, 0x99, 0xAC, 0x22, 0xBE,
+ 0xB1, 0xA2, 0x3F, 0x25, 0x77, 0x8F, 0x7C, 0xF1,
+ 0xD4, 0x59, 0xA8, 0xE5, 0xD7, 0xCA, 0xA1, 0x93,
+ 0xE9, 0xAD, 0xF7, 0x94, 0xEF, 0xED, 0x3C, 0x2A,
+ 0x88, 0xB5, 0x35, 0x9D, 0x9C, 0x32, 0x5E, 0xB6,
+ 0x48, 0x9A, 0x7B, 0x26, 0x50, 0x90, 0x04, 0xA7,
+ 0xDD, 0x09, 0xB9, 0x98, 0xB2, 0xFE, 0xDF, 0x44,
+ 0x89, 0x29, 0x5D, 0xE2, 0x72, 0xC9, 0x28, 0x03,
+ 0x43, 0x8C, 0x52, 0x18, 0xC1, 0x56, 0x1B, 0x1A,
+ 0x01, 0x65, 0xDA, 0xBF, 0x07, 0xFF, 0x76, 0xE8,
+ 0x30, 0xA5, 0x4A, 0xA6, 0x12, 0x62, 0x24, 0x60,
+ 0x4B, 0x73, 0x0C, 0xF0, 0xFA, 0x42, 0xF4, 0x00,
+ 0xD2, 0xD0, 0xD6, 0x3B, 0xC2, 0x2F, 0xE1, 0x2B,
+ 0x70, 0xF8, 0x17, 0xCD, 0xB0, 0xCC, 0x82, 0x2D };
+
+unsigned char table_128[32] = {
+ 0x1A, 0x1C, 0x09, 0x17, 0x1B, 0x0B, 0x16, 0x1E,
+ 0x14, 0x0C, 0x12, 0x0E, 0x05, 0x03, 0x1F, 0x15,
+ 0x19, 0x0D, 0x10, 0x13, 0x0A, 0x01, 0x00, 0x11,
+ 0x02, 0x08, 0x0F, 0x18, 0x07, 0x04, 0x1D, 0x06 };
+
+unsigned char table_129[256] = {
+ 0x9D, 0x5F, 0xE8, 0x99, 0x57, 0x07, 0x16, 0xA6,
+ 0x9F, 0xB6, 0xDE, 0xED, 0x2D, 0xB3, 0xC0, 0x8E,
+ 0xCC, 0x49, 0xCE, 0xB0, 0x1B, 0xB1, 0x7A, 0xE0,
+ 0xEB, 0x28, 0xDB, 0x7D, 0x88, 0xC8, 0x06, 0x6C,
+ 0x02, 0xD0, 0x85, 0x7E, 0xDF, 0xF5, 0x78, 0xE5,
+ 0xA9, 0x71, 0xD9, 0xDD, 0xDC, 0xEE, 0x8C, 0x54,
+ 0xA0, 0x86, 0xFE, 0x0E, 0x55, 0xF7, 0x41, 0x47,
+ 0x1D, 0x15, 0xD6, 0xA4, 0xFF, 0x1F, 0x25, 0xF8,
+ 0x12, 0xE9, 0x74, 0x7B, 0x04, 0xE6, 0x4C, 0x31,
+ 0xA2, 0xBE, 0x0C, 0xB9, 0x17, 0xBD, 0x3D, 0xF0,
+ 0x9E, 0x4D, 0x4E, 0xB2, 0xE7, 0x40, 0xC9, 0x8A,
+ 0x67, 0x5E, 0x19, 0x0F, 0xB7, 0x22, 0x8D, 0xBA,
+ 0xFC, 0x93, 0x14, 0xEA, 0xFD, 0x0D, 0xD5, 0x38,
+ 0xA1, 0x84, 0x1C, 0x35, 0x60, 0x37, 0x43, 0x9C,
+ 0xCF, 0xEF, 0x3A, 0x72, 0xF2, 0x61, 0x75, 0x6A,
+ 0x42, 0xAC, 0xD3, 0x48, 0x77, 0xC5, 0x29, 0xF6,
+ 0x58, 0x79, 0xFA, 0x5D, 0xC7, 0x70, 0x53, 0x9A,
+ 0x6F, 0xC1, 0x0A, 0x90, 0x8F, 0x3E, 0x3B, 0x8B,
+ 0xEC, 0xBC, 0x20, 0x27, 0xC3, 0x66, 0x3F, 0x33,
+ 0xA5, 0x44, 0x2E, 0x32, 0x65, 0x18, 0xFB, 0x59,
+ 0x52, 0x50, 0xE2, 0x63, 0x2B, 0xCD, 0x64, 0xCB,
+ 0xD2, 0x68, 0x10, 0xA7, 0xAE, 0x11, 0xA8, 0x96,
+ 0x69, 0xAF, 0xC2, 0x34, 0x5C, 0x56, 0xE3, 0xF9,
+ 0xDA, 0x51, 0x81, 0x4A, 0x05, 0x00, 0xB8, 0x7C,
+ 0x30, 0x2F, 0x46, 0xB4, 0xC6, 0x87, 0x4B, 0x94,
+ 0x80, 0xF4, 0x7F, 0x3C, 0x26, 0xF1, 0x5B, 0xAB,
+ 0x91, 0x6E, 0x08, 0x76, 0x98, 0xD1, 0xE1, 0x36,
+ 0x21, 0xCA, 0xD8, 0x24, 0x9B, 0x39, 0xBB, 0xAD,
+ 0x13, 0x62, 0x97, 0x1A, 0x6D, 0x2C, 0x5A, 0xC4,
+ 0xD4, 0xA3, 0x03, 0xBF, 0x1E, 0xE4, 0xF3, 0x95,
+ 0x23, 0x73, 0x92, 0xB5, 0x01, 0x83, 0x82, 0xAA,
+ 0x09, 0x45, 0x6B, 0xD7, 0x0B, 0x89, 0x4F, 0x2A };
+
+unsigned char table_130[32] = {
+ 0x07, 0x03, 0x15, 0x0B, 0x02, 0x11, 0x17, 0x14,
+ 0x05, 0x10, 0x0A, 0x0F, 0x01, 0x1C, 0x1D, 0x0E,
+ 0x12, 0x06, 0x18, 0x16, 0x1A, 0x09, 0x13, 0x19,
+ 0x1B, 0x00, 0x08, 0x0D, 0x0C, 0x1E, 0x04, 0x1F };
+
+unsigned char table_131[32] = {
+ 0x1D, 0x13, 0x1B, 0x10, 0x07, 0x03, 0x0A, 0x02,
+ 0x00, 0x0C, 0x0E, 0x0B, 0x0D, 0x18, 0x12, 0x1F,
+ 0x1A, 0x04, 0x15, 0x11, 0x1E, 0x08, 0x1C, 0x14,
+ 0x19, 0x05, 0x0F, 0x17, 0x06, 0x01, 0x09, 0x16 };
+
+unsigned char table_132[256] = {
+ 0x33, 0x8D, 0x45, 0x6F, 0xFF, 0xF5, 0xB6, 0x53,
+ 0x3B, 0xF3, 0x07, 0xA4, 0x97, 0xEB, 0x6B, 0xA5,
+ 0xD3, 0xDC, 0x7B, 0x79, 0x93, 0xE7, 0xF7, 0x67,
+ 0x9C, 0x4F, 0x88, 0xF9, 0x3A, 0x2B, 0x27, 0x48,
+ 0x47, 0x18, 0xF4, 0xAD, 0xB4, 0x8F, 0x2A, 0x76,
+ 0x17, 0xE9, 0x1F, 0x40, 0x0C, 0x59, 0xD1, 0x4C,
+ 0x20, 0x31, 0x73, 0x54, 0xCD, 0x68, 0x08, 0x52,
+ 0x10, 0x62, 0x3D, 0xD2, 0x77, 0xF2, 0xD7, 0x30,
+ 0xCA, 0x16, 0x01, 0x50, 0x9F, 0x3F, 0x75, 0xED,
+ 0x90, 0x6A, 0x34, 0xCE, 0x05, 0x78, 0x5E, 0xD6,
+ 0x85, 0xCC, 0x29, 0xB8, 0xC1, 0x0D, 0xCB, 0x80,
+ 0x2E, 0x04, 0x00, 0x44, 0x32, 0x95, 0xBF, 0xFE,
+ 0x6E, 0x7C, 0xFD, 0xA7, 0x3C, 0x5C, 0xF0, 0xEC,
+ 0xAC, 0xF8, 0xB9, 0xC0, 0x1B, 0x3E, 0xE8, 0x66,
+ 0x5D, 0xDE, 0x49, 0x71, 0xAA, 0xAF, 0x21, 0x64,
+ 0x28, 0x8A, 0x4E, 0x98, 0x58, 0xA2, 0x23, 0xCF,
+ 0x9E, 0x63, 0x61, 0x91, 0x12, 0xC6, 0x8C, 0x19,
+ 0xA8, 0xD4, 0xC7, 0xDD, 0xFC, 0xBD, 0x38, 0xDF,
+ 0xEA, 0x2D, 0x7E, 0x7D, 0xE3, 0xE0, 0xC3, 0xD9,
+ 0x8B, 0x11, 0xF1, 0x4D, 0xC8, 0xB5, 0x55, 0xAE,
+ 0xE1, 0x89, 0xE5, 0xB3, 0xBC, 0x69, 0x9D, 0xA6,
+ 0x09, 0x9A, 0x74, 0x35, 0x1A, 0xFB, 0x24, 0xB7,
+ 0x13, 0x14, 0x94, 0x0A, 0x86, 0x0F, 0x60, 0x51,
+ 0xB0, 0x84, 0x22, 0x5B, 0x87, 0x43, 0x57, 0x0B,
+ 0x2F, 0x5F, 0x02, 0xD0, 0xBB, 0xA3, 0xC9, 0x7A,
+ 0xBE, 0xC2, 0x26, 0x46, 0xDB, 0x1E, 0x1D, 0x92,
+ 0xE2, 0xB2, 0x37, 0x6D, 0xD5, 0x4A, 0x0E, 0x4B,
+ 0x8E, 0xC5, 0x42, 0x99, 0xEE, 0xE4, 0xB1, 0x06,
+ 0xAB, 0x5A, 0x56, 0x41, 0x65, 0xBA, 0xFA, 0x83,
+ 0x15, 0xDA, 0x72, 0xA1, 0x81, 0x1C, 0xA9, 0x36,
+ 0x25, 0x96, 0x6C, 0x39, 0x82, 0xE6, 0x2C, 0x9B,
+ 0xC4, 0x7F, 0xA0, 0xD8, 0xEF, 0x03, 0x70, 0xF6 };
+
+unsigned char table_133[256] = {
+ 0x02, 0xF0, 0xED, 0xC4, 0xE4, 0x67, 0x60, 0x8B,
+ 0xF3, 0x77, 0x92, 0xE0, 0x85, 0x93, 0x1E, 0x8E,
+ 0x9A, 0x38, 0x61, 0x20, 0xB7, 0x68, 0xE1, 0x5E,
+ 0xD5, 0x63, 0xA9, 0xA5, 0xBE, 0x36, 0x12, 0x4D,
+ 0x86, 0x16, 0xD6, 0xB1, 0x23, 0x64, 0x4F, 0x62,
+ 0xFC, 0xA3, 0xD3, 0x04, 0x7D, 0x8C, 0xE2, 0xFF,
+ 0x5D, 0x30, 0xF5, 0x95, 0x1B, 0x5F, 0x73, 0xAA,
+ 0xE8, 0x07, 0x87, 0xDC, 0x54, 0x7C, 0xEE, 0x00,
+ 0xB8, 0xDE, 0x55, 0xBA, 0xD0, 0x50, 0xBB, 0x89,
+ 0x1C, 0xCC, 0x0E, 0xC0, 0x42, 0x11, 0xD8, 0xA2,
+ 0x2E, 0x33, 0xFE, 0x26, 0xD4, 0x10, 0xDA, 0xC5,
+ 0xFB, 0xAF, 0x98, 0x78, 0xB5, 0xBD, 0xC8, 0x8D,
+ 0x46, 0xA0, 0xD1, 0x7B, 0xBC, 0x75, 0xAB, 0x25,
+ 0xB2, 0x43, 0x57, 0xB6, 0xEC, 0xF4, 0x66, 0x05,
+ 0x9C, 0x08, 0x53, 0x80, 0xEA, 0x21, 0x2C, 0x6C,
+ 0x17, 0x71, 0xD2, 0x70, 0x76, 0x9E, 0x6B, 0x7A,
+ 0x58, 0xA7, 0xBF, 0x29, 0x03, 0x1F, 0x06, 0xC1,
+ 0xDD, 0x2F, 0x5C, 0x0B, 0x0D, 0x8A, 0x0A, 0xCB,
+ 0xCA, 0x6F, 0x19, 0x6A, 0xFA, 0xF7, 0xA8, 0xA1,
+ 0xEB, 0x88, 0x44, 0xAC, 0x01, 0x4E, 0x59, 0x94,
+ 0x72, 0x2B, 0xE9, 0x0F, 0x22, 0x9B, 0x27, 0x37,
+ 0x41, 0xF9, 0xF2, 0xE3, 0xEF, 0xB3, 0xD9, 0x2A,
+ 0x31, 0xC2, 0x0C, 0x15, 0x90, 0x14, 0xF6, 0x83,
+ 0xFD, 0x96, 0x9D, 0x7F, 0xA4, 0x39, 0xE7, 0x3F,
+ 0xE6, 0xC7, 0xCD, 0x1A, 0xCF, 0x48, 0x3C, 0x51,
+ 0x6D, 0x5B, 0x74, 0xC3, 0xC9, 0x09, 0x3D, 0x9F,
+ 0xDB, 0x32, 0x40, 0x18, 0xD7, 0xCE, 0x69, 0x49,
+ 0x3A, 0xF1, 0xB9, 0x56, 0x91, 0x99, 0x84, 0x24,
+ 0x7E, 0x34, 0x4B, 0xA6, 0x47, 0xB4, 0x6E, 0xDF,
+ 0x65, 0x3B, 0xAD, 0x45, 0x13, 0xC6, 0x81, 0xF8,
+ 0x4A, 0x2D, 0x8F, 0x4C, 0x97, 0x28, 0x3E, 0xE5,
+ 0x5A, 0x35, 0xB0, 0xAE, 0x82, 0x79, 0x1D, 0x52 };
+
+unsigned char table_134[32] = {
+ 0x09, 0x0F, 0x10, 0x0C, 0x03, 0x15, 0x07, 0x17,
+ 0x0E, 0x0B, 0x1D, 0x08, 0x19, 0x11, 0x00, 0x0A,
+ 0x01, 0x06, 0x18, 0x16, 0x0D, 0x13, 0x14, 0x12,
+ 0x02, 0x1B, 0x1A, 0x04, 0x05, 0x1F, 0x1C, 0x1E };
+
+unsigned char table_135[256] = {
+ 0x14, 0x34, 0xEA, 0x02, 0x2B, 0x5A, 0x10, 0x51,
+ 0xF3, 0x8F, 0x28, 0xB2, 0x50, 0x8B, 0x01, 0xCC,
+ 0x80, 0x15, 0x29, 0x42, 0xF4, 0x1D, 0xFB, 0xBB,
+ 0x1F, 0x43, 0x8C, 0x17, 0x1E, 0x81, 0x04, 0x98,
+ 0x46, 0xD8, 0xD5, 0x65, 0x4C, 0x1C, 0xDB, 0x40,
+ 0x5F, 0x1A, 0x31, 0x74, 0xF1, 0x64, 0x19, 0x05,
+ 0xFC, 0xF0, 0x73, 0xB6, 0x23, 0x77, 0x9C, 0xCE,
+ 0x70, 0xEF, 0xDA, 0xE0, 0xA2, 0x78, 0x84, 0xEB,
+ 0x9E, 0xC5, 0x95, 0xA3, 0xF6, 0xCA, 0xAD, 0x52,
+ 0xD0, 0x3F, 0x54, 0xA7, 0x33, 0xA9, 0x09, 0x6A,
+ 0x89, 0x7E, 0x75, 0xA8, 0xD6, 0x79, 0x9F, 0xAB,
+ 0x8E, 0x11, 0x0E, 0x3B, 0xAA, 0xE6, 0x85, 0x53,
+ 0x0A, 0x59, 0xEC, 0x94, 0xD7, 0x41, 0x86, 0x7D,
+ 0x2F, 0xC7, 0xDE, 0x06, 0xCB, 0x13, 0xBA, 0x58,
+ 0xC8, 0xC9, 0x07, 0x67, 0x7F, 0xA5, 0xB4, 0x2C,
+ 0x48, 0x6C, 0xB8, 0xD1, 0x30, 0xD3, 0x35, 0x4F,
+ 0x88, 0x26, 0x93, 0x32, 0x71, 0x3E, 0x3D, 0xF7,
+ 0x6D, 0x03, 0xED, 0x8A, 0x36, 0x55, 0x9B, 0x66,
+ 0x8D, 0x27, 0x7C, 0xF9, 0xA6, 0xC3, 0x20, 0x69,
+ 0x4A, 0xE3, 0x99, 0x5C, 0xBC, 0x45, 0x16, 0x6B,
+ 0xB9, 0x49, 0x82, 0xFF, 0xBD, 0xDD, 0xE9, 0x0C,
+ 0xD4, 0x44, 0xFD, 0x22, 0xE5, 0xAC, 0x61, 0xC4,
+ 0x90, 0x47, 0x37, 0x72, 0xA4, 0x7A, 0x24, 0x4D,
+ 0x5B, 0x12, 0x38, 0x92, 0x87, 0x1B, 0xE1, 0xA0,
+ 0x91, 0x3C, 0xEE, 0x6F, 0xC1, 0x0F, 0x56, 0xC2,
+ 0x9A, 0xF8, 0x18, 0xE8, 0xD2, 0xDC, 0x4B, 0xCF,
+ 0x39, 0xF5, 0xFE, 0x2A, 0x2D, 0x9D, 0xA1, 0xFA,
+ 0xE7, 0xBF, 0x6E, 0xE4, 0x2E, 0xB3, 0xCD, 0xE2,
+ 0xAF, 0x7B, 0xC0, 0x68, 0x97, 0xB5, 0x5D, 0xB7,
+ 0x21, 0x57, 0x83, 0x76, 0xB1, 0xAE, 0x5E, 0x0D,
+ 0x96, 0x4E, 0x08, 0xC6, 0x0B, 0xDF, 0x3A, 0xB0,
+ 0x00, 0x63, 0xD9, 0xBE, 0xF2, 0x60, 0x25, 0x62 };
+
+unsigned char table_136[256] = {
+ 0xD3, 0x1A, 0x00, 0xED, 0x59, 0x24, 0xA3, 0xF2,
+ 0xBA, 0x58, 0x4C, 0x5C, 0x75, 0x48, 0x98, 0xB0,
+ 0xCF, 0xC3, 0xF7, 0x88, 0x70, 0xB3, 0x3D, 0x3E,
+ 0x03, 0xF9, 0xC9, 0xFD, 0x80, 0x44, 0x7F, 0x3B,
+ 0x95, 0x5F, 0x31, 0x47, 0x15, 0x07, 0xB8, 0x08,
+ 0xCE, 0xDA, 0x71, 0x9F, 0x83, 0xB1, 0x55, 0x16,
+ 0xE6, 0xB2, 0xC7, 0xBE, 0x54, 0xE7, 0x2E, 0x8D,
+ 0x12, 0x21, 0x41, 0x69, 0xFE, 0x28, 0x11, 0x56,
+ 0x5A, 0xDD, 0xB6, 0x87, 0x78, 0x82, 0x4D, 0x7B,
+ 0x50, 0x9A, 0x9E, 0x62, 0xF8, 0x0A, 0x64, 0xF1,
+ 0x4E, 0x33, 0xAD, 0xBB, 0x79, 0x76, 0xD8, 0xCD,
+ 0x86, 0x34, 0x29, 0xD5, 0x7D, 0x72, 0xC5, 0xC1,
+ 0xDF, 0x09, 0x4A, 0xB4, 0xD2, 0x7A, 0xF0, 0xCC,
+ 0x0F, 0xA7, 0xD6, 0x2B, 0x20, 0x26, 0xEF, 0xAB,
+ 0x74, 0x1E, 0xE3, 0x77, 0xCB, 0x7C, 0x73, 0x5E,
+ 0x6B, 0x0D, 0x65, 0xA6, 0x30, 0xFB, 0xD0, 0xB7,
+ 0xAA, 0x94, 0x9D, 0x85, 0x13, 0x18, 0xA8, 0xF3,
+ 0xE0, 0xBC, 0x45, 0xCA, 0xC8, 0xDC, 0xE2, 0x3C,
+ 0x23, 0xE5, 0xB9, 0x90, 0x49, 0xA5, 0xE4, 0x36,
+ 0xFC, 0x53, 0xF6, 0xE8, 0xC6, 0x2C, 0x02, 0x25,
+ 0xC0, 0x8F, 0x61, 0xA4, 0x39, 0x8C, 0x5D, 0xAE,
+ 0x22, 0x1C, 0x2F, 0xD4, 0x6C, 0xD1, 0x51, 0xEA,
+ 0x4F, 0x7E, 0xA0, 0xF5, 0x6A, 0x32, 0xA2, 0x01,
+ 0xB5, 0x10, 0x2A, 0xAC, 0xA9, 0x06, 0xC4, 0x91,
+ 0x68, 0xE1, 0xBD, 0x14, 0x38, 0xFA, 0x6E, 0x3F,
+ 0x37, 0x66, 0xDB, 0x57, 0x43, 0x1B, 0x67, 0xAF,
+ 0x1F, 0x0B, 0x6D, 0x2D, 0x89, 0x04, 0x4B, 0x52,
+ 0xC2, 0xBF, 0xA1, 0x92, 0x99, 0x6F, 0x63, 0x81,
+ 0x27, 0x05, 0x96, 0x3A, 0xEC, 0x0E, 0x97, 0xD9,
+ 0xDE, 0x46, 0x35, 0x8B, 0x8E, 0x8A, 0xF4, 0xFF,
+ 0x60, 0xD7, 0xE9, 0x17, 0xEB, 0x9C, 0x84, 0x0C,
+ 0x93, 0x1D, 0x9B, 0x5B, 0x40, 0xEE, 0x42, 0x19 };
+
+unsigned char table_137[32] = {
+ 0x0F, 0x09, 0x02, 0x06, 0x18, 0x0B, 0x1E, 0x05,
+ 0x11, 0x1D, 0x16, 0x01, 0x13, 0x10, 0x0E, 0x1A,
+ 0x1B, 0x00, 0x0D, 0x08, 0x15, 0x14, 0x19, 0x17,
+ 0x03, 0x1F, 0x0A, 0x12, 0x0C, 0x07, 0x04, 0x1C };
+
+unsigned char table_138[32] = {
+ 0x0D, 0x1C, 0x1F, 0x15, 0x0F, 0x14, 0x1B, 0x12,
+ 0x09, 0x0B, 0x19, 0x07, 0x11, 0x16, 0x0C, 0x04,
+ 0x13, 0x05, 0x1D, 0x03, 0x0E, 0x0A, 0x08, 0x1E,
+ 0x01, 0x06, 0x18, 0x17, 0x10, 0x1A, 0x02, 0x00 };
+
+unsigned char table_139[32] = {
+ 0x05, 0x15, 0x1D, 0x02, 0x0F, 0x03, 0x17, 0x1A,
+ 0x0A, 0x00, 0x1F, 0x12, 0x0E, 0x11, 0x1B, 0x13,
+ 0x0B, 0x0D, 0x09, 0x18, 0x1E, 0x08, 0x14, 0x07,
+ 0x0C, 0x04, 0x16, 0x19, 0x1C, 0x06, 0x10, 0x01 };
+
+unsigned char table_140[32] = {
+ 0x06, 0x1E, 0x0C, 0x11, 0x13, 0x08, 0x15, 0x01,
+ 0x1D, 0x03, 0x0F, 0x19, 0x18, 0x04, 0x00, 0x14,
+ 0x12, 0x1A, 0x0B, 0x0E, 0x02, 0x1B, 0x07, 0x05,
+ 0x1F, 0x17, 0x09, 0x0A, 0x0D, 0x16, 0x10, 0x1C };
+
+unsigned char table_141[256] = {
+ 0xE1, 0x0A, 0x28, 0xCD, 0x8A, 0x1E, 0x26, 0x10,
+ 0xC0, 0x6F, 0x06, 0x2C, 0xF8, 0x51, 0x6C, 0x8F,
+ 0xA8, 0x8C, 0x41, 0xF4, 0xED, 0x36, 0xAC, 0x89,
+ 0xBD, 0x9D, 0x42, 0x50, 0x95, 0x07, 0x2A, 0x9B,
+ 0x7E, 0xA3, 0x6B, 0x30, 0x72, 0x4E, 0xBE, 0xD8,
+ 0x8B, 0x5B, 0x1A, 0x56, 0x05, 0xEF, 0xEE, 0x64,
+ 0xFF, 0xFD, 0x93, 0xB5, 0xD6, 0x04, 0x57, 0xAE,
+ 0x4D, 0x6D, 0x2F, 0xBA, 0x40, 0xE0, 0xDB, 0xF2,
+ 0xCC, 0x08, 0x35, 0x02, 0xC4, 0x65, 0x66, 0x76,
+ 0xA1, 0x97, 0x9F, 0x6A, 0x90, 0xA7, 0x34, 0x1B,
+ 0x18, 0xB9, 0xA2, 0xDE, 0x23, 0x1F, 0xCB, 0xE6,
+ 0xAB, 0xCF, 0xAD, 0x4A, 0xF7, 0x24, 0xD0, 0xE8,
+ 0x8D, 0x49, 0xEA, 0x0F, 0x94, 0x22, 0xD3, 0x74,
+ 0x71, 0x0D, 0x21, 0x14, 0x39, 0x4B, 0x16, 0x25,
+ 0x5A, 0xB7, 0x17, 0x67, 0x59, 0x47, 0x27, 0x4F,
+ 0x32, 0x3B, 0x63, 0x0C, 0xF0, 0xF3, 0x7B, 0xC7,
+ 0xCA, 0x3A, 0x9A, 0xE2, 0xD5, 0xFA, 0x91, 0xFC,
+ 0x86, 0x81, 0x99, 0xB4, 0xBC, 0x7C, 0xC5, 0xBF,
+ 0xC1, 0xF5, 0x77, 0xA4, 0x79, 0x11, 0x8E, 0x75,
+ 0x55, 0x3D, 0x78, 0x20, 0x37, 0x3E, 0x85, 0xE4,
+ 0x2E, 0x82, 0xA9, 0x7A, 0x31, 0xC9, 0xB3, 0xFE,
+ 0x4C, 0x7D, 0xC3, 0xA0, 0x0E, 0x96, 0x5C, 0xC6,
+ 0x1C, 0x5F, 0xD7, 0xDD, 0x83, 0xC8, 0x9E, 0xEC,
+ 0x3F, 0xAF, 0x38, 0x9C, 0xD9, 0xB6, 0xDA, 0xD4,
+ 0x61, 0x44, 0x43, 0xAA, 0xB1, 0xCE, 0xE7, 0x84,
+ 0x00, 0x0B, 0xFB, 0x68, 0xC2, 0x3C, 0x58, 0xB2,
+ 0x69, 0x7F, 0x33, 0x2B, 0x80, 0x03, 0xE9, 0x88,
+ 0x29, 0x12, 0x01, 0x6E, 0x62, 0xF1, 0xA6, 0xF9,
+ 0x5D, 0xD2, 0xE3, 0x53, 0x09, 0x2D, 0xBB, 0x15,
+ 0xEB, 0x13, 0xA5, 0xF6, 0x73, 0x19, 0x60, 0xB0,
+ 0xD1, 0x48, 0x92, 0x1D, 0x52, 0x5E, 0x45, 0x70,
+ 0x98, 0x54, 0xB8, 0xDC, 0x46, 0xDF, 0x87, 0xE5 };
+
+unsigned char table_142[256] = {
+ 0x90, 0x94, 0xBE, 0x14, 0x99, 0xEB, 0x45, 0x0F,
+ 0x34, 0x4A, 0xE3, 0x79, 0xD2, 0x64, 0x4D, 0x69,
+ 0x91, 0xDE, 0xB9, 0x1C, 0x59, 0x20, 0x6C, 0x0B,
+ 0x16, 0xC7, 0x1D, 0x18, 0x02, 0x7D, 0x13, 0xB2,
+ 0x7B, 0x81, 0xCF, 0x61, 0xA3, 0x33, 0x00, 0x73,
+ 0x5A, 0x8A, 0xA1, 0xA8, 0x31, 0xAC, 0xF0, 0x67,
+ 0xAE, 0xA5, 0x2A, 0x96, 0x58, 0xF4, 0xB7, 0x0E,
+ 0xE1, 0x54, 0x27, 0x83, 0x09, 0x85, 0xF8, 0x84,
+ 0xEA, 0xAD, 0x06, 0xED, 0x43, 0xFF, 0xA2, 0x6E,
+ 0x68, 0x46, 0x74, 0x47, 0x3C, 0xAA, 0xBC, 0x55,
+ 0xA7, 0xC3, 0x82, 0xDC, 0xBF, 0x38, 0x80, 0x15,
+ 0xF6, 0xB3, 0x92, 0x7C, 0x93, 0x3F, 0xE9, 0x4C,
+ 0x35, 0x30, 0x32, 0xF3, 0x88, 0xC0, 0x49, 0x6D,
+ 0xCE, 0x42, 0xDF, 0xFD, 0x78, 0x6A, 0x24, 0xCA,
+ 0xB8, 0xFC, 0xA6, 0x5F, 0x29, 0xFE, 0x0C, 0x5C,
+ 0x0D, 0x23, 0x8B, 0x9D, 0xD4, 0x03, 0x2C, 0x9C,
+ 0x77, 0xD8, 0x39, 0x8C, 0x57, 0xD5, 0xE0, 0x8F,
+ 0xC6, 0xB0, 0xCD, 0x48, 0xC9, 0xA0, 0xDA, 0xC8,
+ 0xD1, 0x5B, 0xAB, 0x37, 0x5D, 0x63, 0xAF, 0xF9,
+ 0x17, 0x1B, 0xE5, 0xF1, 0x36, 0xC1, 0x04, 0x26,
+ 0x6F, 0x9E, 0xD9, 0x2F, 0x7F, 0xB5, 0x3A, 0xD6,
+ 0xE6, 0x40, 0x07, 0xCB, 0x7E, 0x3E, 0xC5, 0x22,
+ 0xEC, 0xE2, 0xD3, 0x4E, 0x65, 0x2D, 0x70, 0xE7,
+ 0x10, 0x19, 0xD0, 0xEF, 0xBD, 0xC2, 0x44, 0xB4,
+ 0xF7, 0xA4, 0x53, 0x9F, 0x86, 0xFA, 0xE8, 0x4B,
+ 0x28, 0x3D, 0x9B, 0x56, 0x89, 0x6B, 0x25, 0x71,
+ 0x60, 0x11, 0x9A, 0x5E, 0x1A, 0x52, 0x08, 0x4F,
+ 0xB1, 0xDD, 0xBB, 0x98, 0xFB, 0x12, 0x3B, 0x0A,
+ 0x2E, 0xDB, 0x62, 0x8D, 0xC4, 0x75, 0xA9, 0x2B,
+ 0xE4, 0x97, 0x72, 0xF5, 0xEE, 0xF2, 0xB6, 0x21,
+ 0xBA, 0x7A, 0x76, 0x41, 0x50, 0x66, 0x05, 0x8E,
+ 0xCC, 0x1E, 0x87, 0xD7, 0x01, 0x1F, 0x51, 0x95 };
+
+unsigned char table_143[32] = {
+ 0x0E, 0x16, 0x18, 0x11, 0x0C, 0x01, 0x12, 0x1F,
+ 0x08, 0x15, 0x0A, 0x06, 0x1C, 0x1E, 0x02, 0x1A,
+ 0x17, 0x03, 0x07, 0x13, 0x05, 0x19, 0x10, 0x0F,
+ 0x0D, 0x14, 0x09, 0x0B, 0x1B, 0x00, 0x1D, 0x04 };
+
+unsigned char table_144[32] = {
+ 0x00, 0x1B, 0x17, 0x19, 0x1D, 0x11, 0x0D, 0x1A,
+ 0x13, 0x03, 0x1E, 0x09, 0x10, 0x0E, 0x15, 0x05,
+ 0x0B, 0x1C, 0x1F, 0x08, 0x0A, 0x06, 0x01, 0x0F,
+ 0x16, 0x14, 0x02, 0x04, 0x07, 0x18, 0x12, 0x0C };
+
+unsigned char table_145[256] = {
+ 0xF9, 0x2C, 0x38, 0x74, 0xDA, 0x65, 0x85, 0x0E,
+ 0xBA, 0x64, 0xDB, 0xE3, 0xB6, 0x8B, 0x0B, 0x5E,
+ 0x01, 0x0F, 0x12, 0x8C, 0xD4, 0xCC, 0xB1, 0x7B,
+ 0xE7, 0xBC, 0x2E, 0x87, 0x84, 0x3B, 0xF8, 0x4C,
+ 0x8E, 0x59, 0x2D, 0xAA, 0xCE, 0x28, 0x1B, 0xEE,
+ 0x7F, 0x5C, 0xFB, 0x62, 0x05, 0xD9, 0xDD, 0x9D,
+ 0x49, 0x66, 0x82, 0x71, 0xD2, 0xC7, 0xEB, 0xCF,
+ 0x5B, 0x41, 0x25, 0xC8, 0x6C, 0xFF, 0x78, 0x97,
+ 0x0C, 0xA2, 0x50, 0x7A, 0xAF, 0x2F, 0xB0, 0x7E,
+ 0xBB, 0x73, 0xA0, 0x9B, 0x09, 0xDE, 0x35, 0xE9,
+ 0x5A, 0x70, 0x56, 0xC5, 0x81, 0x19, 0x55, 0xAB,
+ 0xC1, 0xB4, 0x2A, 0x30, 0x54, 0x6F, 0x3E, 0x46,
+ 0x5D, 0x37, 0xF5, 0x57, 0x6B, 0x7C, 0x43, 0xE1,
+ 0x4A, 0x3F, 0xB2, 0x4B, 0x77, 0xB5, 0x44, 0xD6,
+ 0x91, 0x11, 0x72, 0xE8, 0xBE, 0xA5, 0xA8, 0xD3,
+ 0x9A, 0x17, 0x86, 0x88, 0x16, 0x3C, 0x36, 0xD8,
+ 0x6E, 0x07, 0x8D, 0x5F, 0xFA, 0xF1, 0x24, 0x7D,
+ 0x20, 0x60, 0x0D, 0x89, 0xC9, 0x29, 0xA7, 0x2B,
+ 0x4E, 0x10, 0x9F, 0xE5, 0x61, 0x32, 0x3A, 0xBF,
+ 0x93, 0xE6, 0xF3, 0x52, 0x80, 0xC4, 0x02, 0x22,
+ 0xA4, 0xBD, 0xF0, 0x48, 0x51, 0xF2, 0xD7, 0x33,
+ 0x00, 0x53, 0x98, 0xEC, 0x47, 0x39, 0xB9, 0x90,
+ 0x76, 0x4F, 0x68, 0x3D, 0x9C, 0x92, 0xD5, 0xB8,
+ 0xAE, 0xD0, 0xF4, 0x67, 0x58, 0xC0, 0x06, 0x08,
+ 0x14, 0x31, 0xDC, 0xA1, 0x15, 0xDF, 0xCA, 0xE2,
+ 0x23, 0xFE, 0xE4, 0x8F, 0x0A, 0xFC, 0x8A, 0xA3,
+ 0xC6, 0xCD, 0x6A, 0x75, 0xFD, 0x42, 0xB7, 0x79,
+ 0x96, 0x1D, 0x63, 0x18, 0xA9, 0x1C, 0x83, 0x6D,
+ 0xE0, 0x34, 0x04, 0xA6, 0x13, 0xAC, 0xD1, 0xF7,
+ 0x26, 0xC3, 0x1F, 0x27, 0x45, 0x95, 0xCB, 0x21,
+ 0xED, 0x1A, 0x9E, 0x99, 0xEA, 0x40, 0x94, 0x4D,
+ 0x69, 0xF6, 0xEF, 0xC2, 0xAD, 0x03, 0xB3, 0x1E };
+
+unsigned char table_146[256] = {
+ 0x1C, 0xF5, 0x16, 0xD2, 0xCC, 0xDC, 0x1E, 0x29,
+ 0xE3, 0x17, 0x3B, 0x66, 0x6A, 0xF7, 0x03, 0xB2,
+ 0x92, 0x45, 0x4D, 0xD6, 0x0C, 0x5E, 0xE6, 0x01,
+ 0xDE, 0xCE, 0x83, 0xFA, 0x35, 0x02, 0x85, 0xC4,
+ 0x2E, 0x89, 0x8D, 0xE7, 0x30, 0x93, 0xDD, 0x70,
+ 0x80, 0xD9, 0x6D, 0x81, 0x07, 0x8E, 0xA9, 0xA6,
+ 0x5F, 0xC9, 0xF3, 0x9D, 0x65, 0xE8, 0x88, 0x0B,
+ 0x49, 0xAA, 0xB7, 0x6C, 0x11, 0xFC, 0x6F, 0xA3,
+ 0xF8, 0x52, 0x0E, 0xD4, 0x08, 0x25, 0x27, 0x33,
+ 0x2F, 0xF0, 0x2B, 0x47, 0xDA, 0x4C, 0x39, 0x54,
+ 0xB9, 0xC1, 0xEA, 0x7C, 0x44, 0xEB, 0x06, 0xE1,
+ 0x8C, 0x9B, 0x74, 0x42, 0x4F, 0x0A, 0x69, 0x2A,
+ 0x2D, 0xA1, 0x19, 0xD5, 0xC3, 0x87, 0x68, 0xFF,
+ 0xEC, 0xE4, 0x86, 0xCF, 0xF6, 0x79, 0x34, 0xA8,
+ 0x72, 0xF4, 0x8B, 0xAF, 0xA5, 0x00, 0xBA, 0x5C,
+ 0x23, 0xB8, 0xC8, 0x59, 0xBF, 0x6E, 0xCB, 0x20,
+ 0x1F, 0x53, 0x97, 0x4B, 0xD0, 0x55, 0x5B, 0xDF,
+ 0x8A, 0xED, 0x9A, 0x62, 0xC5, 0xD7, 0x18, 0x82,
+ 0xC7, 0x12, 0x15, 0x1B, 0xC0, 0x38, 0xCA, 0x26,
+ 0xDB, 0xAE, 0xF9, 0x90, 0x1A, 0xF2, 0x56, 0x32,
+ 0x21, 0x3C, 0x43, 0xEE, 0xA4, 0x13, 0x94, 0xA2,
+ 0x46, 0x77, 0xBC, 0xB6, 0x9C, 0x0D, 0xCD, 0x37,
+ 0x63, 0x60, 0x6B, 0x3A, 0x3E, 0xA7, 0xD8, 0xFE,
+ 0xFB, 0xEF, 0x67, 0xFD, 0xAD, 0xF1, 0x09, 0x1D,
+ 0xE9, 0x51, 0xB4, 0x95, 0x75, 0x0F, 0xB3, 0xD3,
+ 0xAB, 0x22, 0xBB, 0x61, 0x7F, 0x5A, 0x58, 0x7B,
+ 0x73, 0xC2, 0x05, 0xE0, 0x14, 0xE2, 0xAC, 0x91,
+ 0xBE, 0x4E, 0xC6, 0x7A, 0x84, 0x50, 0x28, 0x3F,
+ 0xB0, 0x04, 0x7E, 0xD1, 0x40, 0xBD, 0xE5, 0x71,
+ 0xB1, 0x78, 0x41, 0x9E, 0x57, 0x64, 0x8F, 0x24,
+ 0x4A, 0x9F, 0x3D, 0x31, 0x36, 0x5D, 0xA0, 0x2C,
+ 0x7D, 0x96, 0x76, 0x99, 0xB5, 0x48, 0x98, 0x10 };
+
+unsigned char table_147[32] = {
+ 0x17, 0x07, 0x0D, 0x16, 0x00, 0x1B, 0x1F, 0x09,
+ 0x10, 0x11, 0x14, 0x0A, 0x02, 0x06, 0x13, 0x0C,
+ 0x08, 0x1E, 0x0F, 0x12, 0x05, 0x15, 0x19, 0x01,
+ 0x1C, 0x1A, 0x03, 0x18, 0x04, 0x0B, 0x1D, 0x0E };
+
+unsigned char table_148[256] = {
+ 0xFB, 0x23, 0xBC, 0x5A, 0x8C, 0x02, 0x42, 0x3B,
+ 0x95, 0x0C, 0x21, 0x0E, 0x14, 0xDF, 0x11, 0xC0,
+ 0xDB, 0x5E, 0xD3, 0xEA, 0xCE, 0xB4, 0x32, 0x12,
+ 0x70, 0x68, 0xA3, 0x25, 0x5B, 0x4B, 0x47, 0xA5,
+ 0x84, 0x9B, 0xFA, 0xD1, 0xE1, 0x3C, 0x20, 0x93,
+ 0x41, 0x26, 0x81, 0x39, 0x17, 0xA4, 0xCF, 0xB9,
+ 0xC5, 0x5F, 0x1C, 0xB3, 0x88, 0xC2, 0x92, 0x30,
+ 0x0A, 0xB8, 0xA0, 0xE2, 0x50, 0x2B, 0x48, 0x1E,
+ 0xD5, 0x13, 0xC7, 0x46, 0x9E, 0x2A, 0xF7, 0x7E,
+ 0xE8, 0x82, 0x60, 0x7A, 0x36, 0x97, 0x0F, 0x8F,
+ 0x8B, 0x80, 0xE0, 0xEB, 0xB1, 0xC6, 0x6E, 0xAE,
+ 0x90, 0x76, 0xA7, 0x31, 0xBE, 0x9C, 0x18, 0x6D,
+ 0xAB, 0x6C, 0x7B, 0xFE, 0x62, 0x05, 0xE9, 0x66,
+ 0x2E, 0x38, 0xB5, 0xB2, 0xFD, 0xFC, 0x7F, 0xE3,
+ 0xA1, 0xF1, 0x99, 0x4D, 0x79, 0x22, 0xD2, 0x37,
+ 0x29, 0x01, 0x54, 0x00, 0xBD, 0x51, 0x1B, 0x07,
+ 0x0B, 0x4A, 0xEE, 0x57, 0xDA, 0x1A, 0x06, 0xCA,
+ 0xCB, 0x9A, 0xC9, 0x7D, 0xE4, 0xDC, 0xE5, 0x8D,
+ 0x75, 0x4F, 0xF6, 0xA2, 0x65, 0x7C, 0xD9, 0x9D,
+ 0x03, 0x27, 0x2D, 0x4C, 0x49, 0xD4, 0x5D, 0x3E,
+ 0xBA, 0x1D, 0xD8, 0x91, 0x74, 0x10, 0xF8, 0xDE,
+ 0xEF, 0xF0, 0x6A, 0x04, 0x72, 0x08, 0x78, 0x3A,
+ 0x53, 0xC4, 0x34, 0xF2, 0x64, 0xAF, 0x86, 0xC3,
+ 0xF3, 0x73, 0x67, 0xCC, 0x58, 0xF4, 0x96, 0xAC,
+ 0x3D, 0xE7, 0x15, 0x8E, 0x19, 0x61, 0xF9, 0xB6,
+ 0xCD, 0x87, 0xAA, 0xB0, 0x1F, 0x6F, 0xAD, 0x28,
+ 0xC8, 0x69, 0x56, 0xC1, 0x71, 0xED, 0xE6, 0x98,
+ 0x6B, 0x59, 0xB7, 0xF5, 0x2C, 0xEC, 0xA8, 0x94,
+ 0x89, 0xBB, 0xA9, 0xD7, 0x2F, 0x8A, 0x4E, 0xD6,
+ 0x33, 0x16, 0x0D, 0x83, 0x5C, 0x52, 0x85, 0xA6,
+ 0x40, 0x45, 0x9F, 0x44, 0x63, 0x35, 0x77, 0xFF,
+ 0x09, 0x43, 0xBF, 0xD0, 0x55, 0xDD, 0x3F, 0x24 };
+
+unsigned char table_149[32] = {
+ 0x1B, 0x0B, 0x0C, 0x06, 0x1F, 0x17, 0x04, 0x1A,
+ 0x1E, 0x02, 0x0F, 0x16, 0x0E, 0x09, 0x10, 0x01,
+ 0x13, 0x19, 0x11, 0x00, 0x0A, 0x05, 0x03, 0x1C,
+ 0x18, 0x1D, 0x14, 0x0D, 0x07, 0x08, 0x15, 0x12 };
+
+unsigned char table_150[256] = {
+ 0x57, 0xBC, 0x9D, 0x46, 0x14, 0xD0, 0x94, 0x95,
+ 0x1B, 0x12, 0xB8, 0xD4, 0x53, 0x73, 0x83, 0xE6,
+ 0x75, 0xE1, 0xD1, 0x0D, 0xDF, 0x23, 0x13, 0x40,
+ 0xF1, 0x0C, 0xA0, 0xC1, 0x22, 0xDA, 0xE8, 0xFB,
+ 0xE5, 0xC4, 0x16, 0x9C, 0x3F, 0xC3, 0x78, 0x3A,
+ 0x06, 0xC7, 0xA8, 0x79, 0xA4, 0xB3, 0x55, 0x88,
+ 0xA9, 0x82, 0xE3, 0x68, 0xFC, 0x3B, 0x26, 0x81,
+ 0xB4, 0x0A, 0x7D, 0x96, 0xDB, 0x2C, 0xE2, 0xCD,
+ 0x92, 0x5C, 0xED, 0x0E, 0x42, 0x98, 0xBE, 0xB7,
+ 0x63, 0x25, 0x7B, 0xD9, 0xEF, 0x11, 0xB9, 0xA3,
+ 0xFA, 0x00, 0x2A, 0x91, 0x71, 0xBF, 0xB2, 0x3D,
+ 0x20, 0x4C, 0xB0, 0x8C, 0x3C, 0x27, 0xAF, 0x09,
+ 0x10, 0x5D, 0x2B, 0x1D, 0xBD, 0x4B, 0x54, 0xD3,
+ 0xAB, 0x1A, 0xE7, 0xF8, 0x56, 0x65, 0xA5, 0xAD,
+ 0xEC, 0x17, 0x45, 0x28, 0xCA, 0xEA, 0x01, 0xF5,
+ 0x34, 0x84, 0x43, 0x8B, 0x03, 0x02, 0x90, 0x6B,
+ 0x60, 0xCE, 0x19, 0x86, 0x4F, 0x08, 0x35, 0x9A,
+ 0xAE, 0x07, 0xE0, 0xB6, 0xD6, 0x2D, 0xD2, 0x89,
+ 0x5F, 0xA6, 0x72, 0x05, 0x36, 0xB5, 0xC0, 0x5A,
+ 0x4D, 0xD7, 0x30, 0x37, 0x87, 0x50, 0xA2, 0x48,
+ 0x29, 0xAC, 0xDE, 0x93, 0x24, 0x6E, 0x1E, 0xF7,
+ 0x52, 0x5E, 0x41, 0xC8, 0xEB, 0x31, 0x7E, 0xE9,
+ 0x67, 0x7A, 0x47, 0x85, 0x8D, 0x74, 0x9E, 0x64,
+ 0x38, 0x9B, 0xBA, 0xCC, 0x9F, 0x8E, 0xEE, 0x0F,
+ 0xB1, 0x7C, 0x6A, 0xBB, 0x2E, 0x58, 0x70, 0x7F,
+ 0x4E, 0x4A, 0x1C, 0x5B, 0xF0, 0xA1, 0x61, 0xF6,
+ 0x15, 0x33, 0xE4, 0xF9, 0x2F, 0x62, 0x1F, 0x76,
+ 0x32, 0xCB, 0x49, 0xFE, 0x8F, 0xD5, 0xDC, 0x66,
+ 0x0B, 0x3E, 0xC5, 0x21, 0xC6, 0x6C, 0x18, 0xC2,
+ 0x6D, 0xFF, 0x51, 0x99, 0xCF, 0xFD, 0x59, 0xA7,
+ 0xAA, 0x8A, 0xF2, 0x69, 0x39, 0x6F, 0x77, 0xDD,
+ 0x97, 0xC9, 0xF3, 0x04, 0xD8, 0xF4, 0x80, 0x44 };
+
+unsigned char table_151[256] = {
+ 0x78, 0x6C, 0xC5, 0x0C, 0x2D, 0xA7, 0x97, 0x9C,
+ 0x22, 0x76, 0x3E, 0x81, 0x51, 0x47, 0x59, 0x71,
+ 0xB1, 0xA2, 0x4A, 0x3C, 0xB5, 0x16, 0x06, 0x95,
+ 0xB9, 0x01, 0xE6, 0x91, 0x96, 0x1C, 0x1B, 0xAD,
+ 0x61, 0x64, 0xB2, 0xE7, 0x29, 0x19, 0x52, 0x3B,
+ 0xFA, 0xAF, 0x30, 0xDB, 0xD4, 0x0B, 0xFE, 0x75,
+ 0x1F, 0xBE, 0xCB, 0xF6, 0xEA, 0x31, 0xF8, 0xD8,
+ 0xA3, 0x82, 0x73, 0x1D, 0x99, 0xF0, 0xCC, 0xB6,
+ 0x46, 0x26, 0xAA, 0x8C, 0x87, 0x90, 0x24, 0x8F,
+ 0x7A, 0x13, 0xEE, 0xD1, 0xA9, 0x05, 0xB3, 0xF7,
+ 0x02, 0x7C, 0x4C, 0x1E, 0xFF, 0xE5, 0x77, 0xAB,
+ 0xD6, 0x98, 0x20, 0x4D, 0xC4, 0x23, 0xF4, 0xA4,
+ 0x85, 0x9A, 0x8E, 0x1A, 0x0E, 0xF5, 0x15, 0x60,
+ 0x38, 0x72, 0xE9, 0xF1, 0xC3, 0x68, 0xF2, 0x93,
+ 0xD3, 0x2A, 0x48, 0x74, 0xC2, 0x57, 0xA1, 0x7D,
+ 0x94, 0x37, 0x92, 0x5C, 0xE1, 0x41, 0x83, 0xD5,
+ 0x65, 0x14, 0xA6, 0xDC, 0x44, 0x27, 0xEF, 0xD7,
+ 0x25, 0x10, 0x2C, 0x7F, 0x40, 0xA5, 0x55, 0xBD,
+ 0x2B, 0x0D, 0xD0, 0xFC, 0xDF, 0xA0, 0x04, 0x00,
+ 0x62, 0xB4, 0x5A, 0xEB, 0x6B, 0x84, 0x7E, 0x6A,
+ 0xDE, 0xED, 0x66, 0x03, 0xFB, 0x2E, 0x4F, 0x4E,
+ 0xBB, 0x36, 0x5B, 0x18, 0xE3, 0x69, 0x3F, 0xEC,
+ 0xE4, 0xD2, 0x0A, 0x34, 0x63, 0xCF, 0xA8, 0xF9,
+ 0x9B, 0x7B, 0x6F, 0xE8, 0x49, 0xC1, 0x09, 0x54,
+ 0xF3, 0x50, 0x67, 0x79, 0xC0, 0x9F, 0x8D, 0x5F,
+ 0x17, 0x70, 0x11, 0xC8, 0xBC, 0xC6, 0xE0, 0x35,
+ 0x39, 0xC7, 0x6E, 0x21, 0xBF, 0xDA, 0x6D, 0x28,
+ 0x0F, 0xDD, 0x33, 0xAC, 0x8A, 0x12, 0xC9, 0xCD,
+ 0xB8, 0x45, 0xAE, 0x32, 0xCE, 0xE2, 0x56, 0xFD,
+ 0x42, 0x89, 0x86, 0xCA, 0x4B, 0x3D, 0x5E, 0xBA,
+ 0x8B, 0x5D, 0xB0, 0xB7, 0xD9, 0x58, 0x2F, 0x08,
+ 0x43, 0x3A, 0x53, 0x9E, 0x80, 0x88, 0x07, 0x9D };
+
+unsigned char table_152[32] = {
+ 0x02, 0x1A, 0x17, 0x1D, 0x01, 0x03, 0x13, 0x1E,
+ 0x05, 0x18, 0x06, 0x0A, 0x0C, 0x04, 0x1B, 0x00,
+ 0x1C, 0x09, 0x1F, 0x16, 0x07, 0x0F, 0x0B, 0x0E,
+ 0x14, 0x12, 0x0D, 0x10, 0x19, 0x11, 0x08, 0x15 };
+
+unsigned char table_153[32] = {
+ 0x0E, 0x14, 0x12, 0x1E, 0x1C, 0x02, 0x06, 0x16,
+ 0x18, 0x0D, 0x17, 0x0C, 0x1D, 0x11, 0x08, 0x19,
+ 0x07, 0x0F, 0x13, 0x04, 0x03, 0x1B, 0x0B, 0x1F,
+ 0x1A, 0x0A, 0x05, 0x10, 0x00, 0x01, 0x15, 0x09 };
+
+unsigned char table_154[256] = {
+ 0x27, 0x5A, 0x08, 0x5B, 0xF4, 0x39, 0x13, 0x6F,
+ 0x67, 0xEA, 0x22, 0xCA, 0x5C, 0xCF, 0x18, 0x7C,
+ 0x05, 0x87, 0x60, 0xCC, 0x40, 0xC6, 0xE8, 0x6D,
+ 0xF5, 0x2A, 0x2D, 0xA2, 0x8C, 0x82, 0xE9, 0xDC,
+ 0xD6, 0x65, 0x74, 0x8E, 0x42, 0x4F, 0x3E, 0x55,
+ 0xFF, 0xC7, 0x9D, 0x0F, 0x81, 0xE2, 0x4C, 0xE6,
+ 0xEB, 0x4D, 0x70, 0xD1, 0x49, 0x43, 0x3D, 0x69,
+ 0x0C, 0x45, 0x28, 0x00, 0x99, 0xAE, 0xEC, 0xB8,
+ 0xC3, 0x17, 0x93, 0x8D, 0x36, 0x3C, 0x46, 0x2B,
+ 0x29, 0xC5, 0xB4, 0xB1, 0xD0, 0x0D, 0xAD, 0xFE,
+ 0xE5, 0xA8, 0x3B, 0x1A, 0x2C, 0xDF, 0x07, 0x86,
+ 0xB0, 0xD3, 0x7A, 0x59, 0x79, 0x8B, 0xC1, 0x9A,
+ 0x30, 0xDB, 0x24, 0xF3, 0xD8, 0x04, 0x25, 0xC2,
+ 0xA3, 0x98, 0x96, 0x7B, 0x71, 0x4E, 0x5E, 0x58,
+ 0xA5, 0x51, 0x88, 0xDA, 0xF8, 0xC0, 0x7D, 0xF6,
+ 0x31, 0x5F, 0x09, 0x16, 0x21, 0x62, 0x01, 0x64,
+ 0x9B, 0x3A, 0x2F, 0x61, 0x19, 0xA1, 0xB7, 0xE0,
+ 0xB9, 0x12, 0xA0, 0xBA, 0x6E, 0x8A, 0xFB, 0xD9,
+ 0x38, 0x1B, 0xD5, 0xB3, 0x10, 0xED, 0xE4, 0x6A,
+ 0x32, 0xBD, 0x75, 0xD4, 0x1C, 0xFD, 0x73, 0x77,
+ 0x54, 0xC8, 0x97, 0x47, 0x35, 0x94, 0xE3, 0xCD,
+ 0x6B, 0xBB, 0xF9, 0xAC, 0x11, 0x14, 0xAF, 0x78,
+ 0x3F, 0xCE, 0x26, 0x44, 0xEE, 0xFC, 0x15, 0x66,
+ 0x4B, 0xA6, 0x20, 0x23, 0xBE, 0x84, 0x1D, 0x7E,
+ 0x0B, 0x56, 0x92, 0x0A, 0xFA, 0xF7, 0x48, 0x33,
+ 0x9E, 0x8F, 0xAB, 0x5D, 0x41, 0x50, 0xA4, 0x7F,
+ 0x80, 0x4A, 0x68, 0x06, 0x2E, 0x6C, 0xC4, 0x02,
+ 0x0E, 0x63, 0xF0, 0xC9, 0x91, 0xB2, 0xD2, 0x03,
+ 0x37, 0xEF, 0x9C, 0x90, 0x83, 0x76, 0x1E, 0xA9,
+ 0x85, 0xB6, 0x57, 0xD7, 0xF2, 0xF1, 0xE7, 0xDE,
+ 0xCB, 0xAA, 0xBF, 0x89, 0x1F, 0xA7, 0xBC, 0x9F,
+ 0x53, 0xE1, 0xDD, 0x72, 0x95, 0x52, 0x34, 0xB5 };
+
+unsigned char table_155[256] = {
+ 0x75, 0x58, 0xC5, 0xA5, 0x83, 0x16, 0xF3, 0x7F,
+ 0x94, 0xDE, 0xA0, 0xF6, 0xFD, 0x89, 0xA8, 0x06,
+ 0x98, 0x01, 0xD9, 0x69, 0xB7, 0x0F, 0xEA, 0x73,
+ 0x32, 0xF0, 0x49, 0xBF, 0x02, 0xE7, 0x22, 0x3F,
+ 0xDB, 0x30, 0x5F, 0x20, 0x6A, 0x93, 0x07, 0xBC,
+ 0x09, 0x0D, 0x37, 0x24, 0x90, 0x15, 0x80, 0xAF,
+ 0x8F, 0x59, 0x28, 0xFF, 0x6D, 0x1E, 0x52, 0x62,
+ 0xE2, 0xDD, 0x85, 0x48, 0xB5, 0xAB, 0x68, 0xAC,
+ 0x7E, 0x26, 0x2C, 0xF9, 0x2A, 0xBE, 0x5B, 0xCE,
+ 0x87, 0x1D, 0x96, 0xBD, 0xEF, 0x29, 0xA9, 0xC3,
+ 0x9D, 0x57, 0x79, 0x6B, 0x7A, 0x82, 0x78, 0x0A,
+ 0x91, 0xF2, 0x7C, 0xC2, 0x25, 0x88, 0xE3, 0x47,
+ 0x64, 0x46, 0x8D, 0x19, 0xF4, 0xE6, 0xF1, 0x53,
+ 0x9C, 0x54, 0x23, 0xAD, 0xA3, 0x86, 0x3A, 0x04,
+ 0x67, 0x1C, 0xF5, 0x43, 0x05, 0x42, 0xD6, 0x4B,
+ 0xFB, 0xD4, 0x2B, 0x08, 0x45, 0xD8, 0xCD, 0xEB,
+ 0x31, 0x4A, 0x5A, 0x34, 0x9B, 0xEC, 0x4D, 0xB4,
+ 0xC6, 0xFE, 0xD5, 0x5E, 0xC1, 0x39, 0x81, 0xCF,
+ 0x03, 0x6E, 0x95, 0x50, 0xA1, 0x3B, 0xB3, 0xE5,
+ 0x3D, 0xB1, 0xB2, 0x41, 0x17, 0x2F, 0x2E, 0xE4,
+ 0x1F, 0xDC, 0xB0, 0xB6, 0x18, 0x6F, 0x44, 0x12,
+ 0x0B, 0xCC, 0x4E, 0xC0, 0x51, 0x14, 0x76, 0x3C,
+ 0xB9, 0x9F, 0xA4, 0xD3, 0xA7, 0xE8, 0x13, 0x55,
+ 0xC8, 0x8C, 0xD2, 0xEE, 0x65, 0xB8, 0xAA, 0x6C,
+ 0x2D, 0x4F, 0x56, 0xFA, 0x61, 0x4C, 0xE0, 0x5C,
+ 0xA6, 0x1A, 0xD1, 0x38, 0xD7, 0x72, 0x60, 0x74,
+ 0xE1, 0xBA, 0x84, 0x3E, 0x40, 0xF8, 0xC7, 0x36,
+ 0x27, 0x0C, 0x70, 0x97, 0x9A, 0x7D, 0x35, 0x71,
+ 0xCA, 0x1B, 0x99, 0x8E, 0xAE, 0x66, 0x63, 0xE9,
+ 0xC9, 0x11, 0x8A, 0x21, 0x92, 0x5D, 0x77, 0x10,
+ 0xD0, 0xC4, 0xF7, 0x7B, 0x9E, 0xCB, 0xED, 0x0E,
+ 0x8B, 0x33, 0xFC, 0xBB, 0x00, 0xA2, 0xDF, 0xDA };
+
+unsigned char table_156[256] = {
+ 0x31, 0x25, 0xB1, 0xD3, 0xAF, 0xAE, 0x84, 0x2C,
+ 0x71, 0x5E, 0xD8, 0x80, 0x6F, 0x3E, 0x48, 0x86,
+ 0xED, 0x54, 0x6A, 0xC3, 0xBC, 0xBF, 0x0E, 0xEA,
+ 0x10, 0xA2, 0x9D, 0x91, 0x32, 0xE2, 0x7E, 0x1B,
+ 0x49, 0x27, 0xFF, 0xDD, 0x8A, 0x2F, 0x8D, 0x38,
+ 0xFA, 0x3C, 0x03, 0x14, 0x0F, 0x89, 0xCC, 0x07,
+ 0x1A, 0xA0, 0x97, 0x37, 0xA6, 0xD6, 0x63, 0x87,
+ 0xA1, 0xC2, 0x4B, 0x39, 0xCB, 0xCF, 0x69, 0x4E,
+ 0xC9, 0x28, 0x1C, 0xBB, 0x42, 0x2B, 0xA9, 0x78,
+ 0x5B, 0xF6, 0xE0, 0xD0, 0x5F, 0x46, 0x98, 0xCE,
+ 0x1F, 0x7A, 0x34, 0x8B, 0xFD, 0x9B, 0xEF, 0x74,
+ 0x05, 0xF2, 0x02, 0xC6, 0xDF, 0x73, 0x5C, 0x8E,
+ 0xDE, 0x88, 0x57, 0x3B, 0x85, 0xBD, 0xC0, 0x3A,
+ 0x45, 0x4D, 0x2D, 0x72, 0x0C, 0x60, 0xCA, 0x5D,
+ 0x06, 0x04, 0x3D, 0x51, 0x15, 0xAD, 0xE8, 0x67,
+ 0xBA, 0x43, 0x7D, 0xF8, 0xB2, 0xE6, 0xAB, 0xF4,
+ 0x23, 0x6E, 0xF0, 0x6B, 0x0B, 0x2E, 0xC8, 0xC4,
+ 0x4F, 0xA8, 0x6D, 0x26, 0xE9, 0x9C, 0x22, 0xB7,
+ 0x00, 0xB3, 0x0A, 0x7C, 0x44, 0x55, 0x75, 0xD5,
+ 0xAA, 0x66, 0x56, 0x24, 0x83, 0x90, 0xA4, 0xF5,
+ 0xCD, 0xEC, 0x18, 0xDC, 0xFE, 0x96, 0xA3, 0xF7,
+ 0xD2, 0xFB, 0xD1, 0x65, 0xC5, 0x08, 0x7B, 0x70,
+ 0x16, 0x9A, 0x20, 0x09, 0x29, 0xDA, 0x52, 0x5A,
+ 0x59, 0xB4, 0x77, 0x62, 0x9E, 0x19, 0x7F, 0x82,
+ 0x4C, 0xB6, 0x0D, 0x58, 0xEE, 0x1D, 0xB9, 0x93,
+ 0x50, 0xD9, 0x30, 0xE4, 0x13, 0x01, 0x36, 0x8F,
+ 0x53, 0x3F, 0x64, 0xA5, 0xB5, 0xD7, 0x81, 0x41,
+ 0x17, 0xE5, 0x94, 0xE3, 0xF9, 0x61, 0x76, 0xE1,
+ 0x9F, 0xFC, 0x1E, 0x12, 0xDB, 0x21, 0x79, 0x2A,
+ 0xAC, 0xF3, 0x6C, 0xC1, 0x95, 0x92, 0xEB, 0xA7,
+ 0x11, 0xC7, 0xB8, 0x4A, 0x33, 0xB0, 0x99, 0xE7,
+ 0xF1, 0x68, 0xBE, 0x35, 0x40, 0x8C, 0xD4, 0x47 };
+
+unsigned char table_157[32] = {
+ 0x00, 0x0D, 0x03, 0x02, 0x11, 0x04, 0x18, 0x0B,
+ 0x14, 0x1D, 0x1C, 0x13, 0x1B, 0x17, 0x10, 0x15,
+ 0x01, 0x19, 0x07, 0x09, 0x1A, 0x16, 0x12, 0x1E,
+ 0x08, 0x06, 0x0C, 0x0E, 0x1F, 0x0F, 0x0A, 0x05 };
+
+unsigned char table_158[256] = {
+ 0x68, 0x26, 0x80, 0x0B, 0xB8, 0xD5, 0x8C, 0xB7,
+ 0x65, 0xEF, 0xBC, 0x94, 0x28, 0xB9, 0xB2, 0xD2,
+ 0x92, 0xA4, 0x55, 0x27, 0xE0, 0x40, 0x6C, 0x41,
+ 0x25, 0xBD, 0xAF, 0xEA, 0xB1, 0x19, 0xA5, 0xC9,
+ 0x0E, 0xED, 0xB4, 0xF9, 0x8B, 0x6A, 0xAE, 0xD8,
+ 0x64, 0x83, 0xC1, 0xD3, 0x04, 0xF4, 0xFA, 0xC3,
+ 0x46, 0x2C, 0xA8, 0xBB, 0x3A, 0x47, 0x33, 0x8F,
+ 0x52, 0x86, 0x08, 0x9D, 0x1D, 0x59, 0x8E, 0x91,
+ 0x32, 0xCF, 0x6B, 0x75, 0xB0, 0x7F, 0xC7, 0x24,
+ 0x05, 0x6F, 0x00, 0x1C, 0x2D, 0xAC, 0xDA, 0x45,
+ 0x73, 0xB3, 0x3E, 0xD6, 0x54, 0x61, 0x03, 0x77,
+ 0xF8, 0xD9, 0xE2, 0x4B, 0xFF, 0xF2, 0x0C, 0x4F,
+ 0x93, 0x71, 0xA7, 0x3D, 0x66, 0x88, 0x98, 0xF1,
+ 0xB6, 0x7A, 0x2B, 0xCD, 0x44, 0x3C, 0x37, 0x5A,
+ 0x96, 0x23, 0x9F, 0xBF, 0x7D, 0x5E, 0x2A, 0x35,
+ 0x72, 0x79, 0xE1, 0xA3, 0x84, 0x99, 0x38, 0x49,
+ 0xC8, 0xDB, 0x30, 0xDC, 0xAD, 0x3F, 0xF6, 0x09,
+ 0x69, 0x95, 0xE5, 0x67, 0xA1, 0xFD, 0xF7, 0x1B,
+ 0xEC, 0x17, 0xD4, 0xEB, 0x29, 0x36, 0x3B, 0x15,
+ 0xDE, 0x2E, 0xC5, 0x70, 0x6D, 0x53, 0x56, 0xAB,
+ 0xC0, 0x43, 0xC2, 0xE7, 0x31, 0xE6, 0xA6, 0x78,
+ 0x5C, 0x7C, 0x48, 0x10, 0x87, 0xCC, 0x9E, 0x7E,
+ 0x5F, 0xE9, 0x07, 0x5B, 0xF5, 0xEE, 0xB5, 0xCA,
+ 0x62, 0x18, 0xBE, 0x20, 0x16, 0xDF, 0x13, 0x4E,
+ 0x7B, 0x02, 0x11, 0x4C, 0x51, 0x85, 0x0D, 0x22,
+ 0xF3, 0x14, 0x63, 0x76, 0xD0, 0x0F, 0xE4, 0xCB,
+ 0xCE, 0xA0, 0x82, 0xE3, 0x01, 0xAA, 0x5D, 0x4A,
+ 0x4D, 0xFB, 0x39, 0x8A, 0x2F, 0xDD, 0xE8, 0x06,
+ 0x1A, 0x90, 0x81, 0x50, 0x8D, 0x89, 0x97, 0x1E,
+ 0xFC, 0x60, 0x12, 0x42, 0x9C, 0xF0, 0x34, 0xD7,
+ 0xD1, 0x1F, 0x0A, 0x21, 0xA9, 0x6E, 0xC4, 0xBA,
+ 0x9A, 0x57, 0xA2, 0x74, 0xC6, 0xFE, 0x9B, 0x58 };
+
+unsigned char table_159[256] = {
+ 0xE5, 0xBF, 0x84, 0x56, 0xD6, 0x43, 0x3E, 0xA5,
+ 0x64, 0x87, 0x44, 0x63, 0x4A, 0x4C, 0x8D, 0x24,
+ 0x1C, 0xDA, 0x89, 0x52, 0x80, 0x4F, 0xE4, 0xBC,
+ 0xC5, 0xF4, 0x27, 0x75, 0x9C, 0xF0, 0xE1, 0x06,
+ 0x99, 0x48, 0xF2, 0x57, 0x34, 0x9A, 0xA8, 0x62,
+ 0xC9, 0xD5, 0x16, 0x6D, 0x55, 0xFA, 0x37, 0x5A,
+ 0x2A, 0xC6, 0x45, 0xDD, 0x1B, 0x76, 0x50, 0xE2,
+ 0x69, 0x41, 0x6C, 0xC4, 0x3C, 0x47, 0xA9, 0x92,
+ 0x00, 0x3D, 0x6F, 0xE7, 0x7A, 0x3A, 0x33, 0x53,
+ 0xF7, 0x03, 0xA7, 0xB1, 0x15, 0x78, 0x0B, 0x67,
+ 0x2E, 0x21, 0xF1, 0xD4, 0xB3, 0x98, 0x60, 0x58,
+ 0xBB, 0x82, 0x1E, 0x70, 0x0A, 0xA2, 0x02, 0x17,
+ 0xFF, 0x9F, 0xD2, 0xAF, 0xC7, 0xDC, 0x68, 0x83,
+ 0x42, 0xCA, 0x08, 0x39, 0x20, 0xEC, 0x77, 0x96,
+ 0x5B, 0xAD, 0x09, 0x6B, 0x40, 0xC2, 0x91, 0x51,
+ 0x10, 0xD9, 0xF9, 0xC1, 0xB5, 0xDF, 0xDB, 0xC0,
+ 0x7D, 0xAB, 0xAE, 0x54, 0x35, 0xF3, 0xA1, 0xE6,
+ 0xEA, 0x14, 0xBA, 0xFC, 0xE8, 0xEB, 0xF6, 0xBD,
+ 0x8C, 0x72, 0x1F, 0xE9, 0xFB, 0x7C, 0xCF, 0x49,
+ 0xE3, 0xA3, 0x22, 0x9D, 0x46, 0x71, 0x94, 0x31,
+ 0x2D, 0x65, 0x2B, 0x32, 0x18, 0xB6, 0x90, 0xF8,
+ 0x11, 0x5F, 0xA0, 0xEF, 0xED, 0x1A, 0x25, 0x2C,
+ 0x3B, 0xFD, 0x2F, 0x73, 0xB9, 0x7E, 0xDE, 0xB4,
+ 0x97, 0x0F, 0x7F, 0x86, 0x93, 0x07, 0x19, 0xCE,
+ 0xE0, 0xB7, 0xEE, 0x26, 0xD1, 0x01, 0x59, 0x5C,
+ 0xC3, 0x79, 0x8B, 0xD3, 0x4B, 0x04, 0xD0, 0x29,
+ 0x0D, 0x3F, 0xB2, 0x30, 0xCC, 0x36, 0xFE, 0xB0,
+ 0xF5, 0x8E, 0xA6, 0x8A, 0xC8, 0xD8, 0x05, 0xB8,
+ 0x12, 0xBE, 0x81, 0x4D, 0x38, 0xAC, 0x1D, 0x9E,
+ 0x66, 0x5E, 0x7B, 0x6E, 0x0C, 0xCD, 0x6A, 0x88,
+ 0xAA, 0x0E, 0x61, 0x5D, 0x95, 0x4E, 0xD7, 0x74,
+ 0xCB, 0x9B, 0x13, 0x8F, 0xA4, 0x28, 0x23, 0x85 };
+
+unsigned char table_160[256] = {
+ 0x35, 0x44, 0x0E, 0x92, 0x75, 0x83, 0x9D, 0x53,
+ 0xA5, 0x90, 0xF8, 0xF7, 0x54, 0x74, 0xDF, 0x3D,
+ 0x5A, 0xAA, 0xC6, 0x26, 0x7A, 0xFC, 0x79, 0x6C,
+ 0x56, 0xB3, 0x32, 0xE3, 0x1C, 0xF9, 0xDC, 0xE6,
+ 0xA2, 0x93, 0x71, 0xFF, 0x1D, 0xEB, 0xB2, 0x04,
+ 0x96, 0x46, 0x0C, 0x2B, 0x17, 0xEE, 0x28, 0x25,
+ 0xD9, 0xAE, 0x11, 0xA7, 0x40, 0x45, 0xFB, 0x80,
+ 0x18, 0xF1, 0xCB, 0x2E, 0x24, 0xF3, 0xEC, 0x4F,
+ 0xAB, 0xD7, 0xD4, 0xC4, 0xFD, 0x4B, 0xAD, 0xC9,
+ 0x4C, 0x08, 0xAC, 0xF4, 0xCD, 0xB7, 0xF2, 0x15,
+ 0x02, 0x2F, 0x16, 0x34, 0x65, 0x8A, 0x87, 0xCC,
+ 0x50, 0x0F, 0x9B, 0xC2, 0xC8, 0x7B, 0xEA, 0x8E,
+ 0xE4, 0xD6, 0x97, 0x30, 0xA8, 0xA0, 0x94, 0xC5,
+ 0xE8, 0x12, 0x27, 0xCE, 0x84, 0xDD, 0xB1, 0x47,
+ 0x7E, 0xE7, 0xE1, 0x3A, 0x37, 0x21, 0x2D, 0x3B,
+ 0x20, 0x60, 0x1E, 0x1B, 0x82, 0xBE, 0xA3, 0x70,
+ 0x98, 0xBF, 0xA6, 0x4D, 0x76, 0x86, 0x42, 0x9F,
+ 0xCF, 0xE0, 0x14, 0x4A, 0x0B, 0xB4, 0x36, 0xF5,
+ 0x85, 0xB8, 0xC0, 0x6A, 0xE9, 0x7D, 0xBD, 0x4E,
+ 0x8F, 0x51, 0x0D, 0x5B, 0x6B, 0x58, 0x5F, 0x03,
+ 0x6F, 0xBC, 0x5D, 0x1F, 0x7F, 0xDB, 0x00, 0xC1,
+ 0x13, 0xF0, 0xD1, 0xFA, 0xDA, 0x05, 0x39, 0xD3,
+ 0x38, 0xD2, 0x89, 0xE2, 0x88, 0x5E, 0x5C, 0x6D,
+ 0xCA, 0xB0, 0x01, 0x63, 0x8B, 0x59, 0xA4, 0xD0,
+ 0x78, 0x19, 0xB5, 0x62, 0x1A, 0x69, 0x8D, 0x9C,
+ 0x22, 0x3F, 0x9E, 0x33, 0x72, 0x2A, 0x41, 0x29,
+ 0xFE, 0xF6, 0x64, 0x7C, 0x66, 0xB6, 0xAF, 0x23,
+ 0x8C, 0x68, 0x6E, 0x49, 0x07, 0x99, 0x77, 0x3E,
+ 0x9A, 0x73, 0xD8, 0x55, 0x0A, 0x3C, 0xBA, 0xA9,
+ 0x52, 0xED, 0x91, 0x09, 0x95, 0xC7, 0x43, 0xD5,
+ 0x57, 0x61, 0x81, 0xEF, 0x06, 0xDE, 0x48, 0x31,
+ 0xBB, 0x2C, 0xE5, 0xC3, 0x67, 0xA1, 0x10, 0xB9 };
+
+unsigned char table_161[256] = {
+ 0x8F, 0x1A, 0x81, 0xA2, 0x2C, 0x56, 0x6D, 0xCD,
+ 0x4A, 0x33, 0x50, 0xE9, 0xE0, 0x12, 0x5A, 0x43,
+ 0x2D, 0x4F, 0xEA, 0x95, 0xFD, 0x49, 0xAB, 0xA3,
+ 0x79, 0x42, 0x0B, 0xB8, 0x89, 0x40, 0x71, 0x14,
+ 0x80, 0x55, 0xAF, 0xCF, 0x3E, 0x64, 0x8B, 0x74,
+ 0xBF, 0x9C, 0x24, 0x97, 0xD1, 0xBA, 0x48, 0xD2,
+ 0x08, 0x1F, 0xDD, 0xA7, 0xDC, 0x92, 0x30, 0x75,
+ 0x31, 0x37, 0x67, 0x06, 0x68, 0x72, 0x6F, 0x05,
+ 0x8A, 0x7C, 0x4C, 0x3C, 0x19, 0x28, 0x86, 0x3D,
+ 0x93, 0xDA, 0xF4, 0xC7, 0x17, 0x85, 0xAC, 0x02,
+ 0x78, 0x04, 0xAD, 0x03, 0x8D, 0x11, 0xC5, 0x9D,
+ 0x3A, 0x73, 0x82, 0x59, 0x51, 0x9F, 0x27, 0x47,
+ 0xE7, 0xED, 0x1E, 0xFF, 0x34, 0x01, 0x5B, 0x4B,
+ 0xCA, 0x6C, 0x69, 0xBB, 0x3B, 0xC4, 0x5F, 0xDF,
+ 0x09, 0x6B, 0x7D, 0xC9, 0x88, 0x45, 0x57, 0xD3,
+ 0x2A, 0x4E, 0xF1, 0xC2, 0xA9, 0xB6, 0x18, 0xD4,
+ 0xA0, 0x1C, 0x4D, 0x0E, 0xE5, 0xE1, 0xD7, 0xB2,
+ 0x0C, 0x3F, 0x00, 0x61, 0x16, 0x0D, 0x32, 0x62,
+ 0x58, 0x63, 0xEE, 0xEF, 0x2F, 0x5D, 0xB0, 0x20,
+ 0x7A, 0x10, 0xE6, 0xA1, 0xF9, 0xD8, 0x6E, 0xCB,
+ 0xF0, 0x9B, 0x84, 0x8E, 0xF2, 0xFE, 0xC8, 0x7F,
+ 0xBD, 0xF8, 0x07, 0xC6, 0x39, 0xBC, 0xCC, 0x22,
+ 0x54, 0x15, 0x9A, 0xA4, 0xC1, 0x2B, 0x1B, 0x25,
+ 0xDE, 0x6A, 0xDB, 0x90, 0xEB, 0xB7, 0xD0, 0x44,
+ 0xA6, 0xB9, 0xB1, 0x23, 0x9E, 0x65, 0x83, 0xFA,
+ 0x96, 0xB5, 0x0F, 0xF6, 0xD6, 0xE8, 0x53, 0x13,
+ 0x76, 0xD5, 0x35, 0x87, 0xE3, 0x38, 0xF5, 0xAE,
+ 0xB3, 0xCE, 0xE2, 0x70, 0xD9, 0x66, 0x5C, 0x26,
+ 0xC3, 0xFC, 0xF7, 0x94, 0xF3, 0xEC, 0xFB, 0x99,
+ 0x91, 0x77, 0xB4, 0x46, 0xA5, 0x98, 0x7B, 0x1D,
+ 0x52, 0x2E, 0xA8, 0x60, 0x5E, 0x29, 0x21, 0x7E,
+ 0xBE, 0x0A, 0x36, 0x41, 0xC0, 0x8C, 0xE4, 0xAA };
+
+unsigned char table_162[256] = {
+ 0xF7, 0x1B, 0xC0, 0x31, 0x5A, 0x23, 0xEA, 0xE9,
+ 0xFB, 0x14, 0x6A, 0xE8, 0x04, 0x65, 0x5B, 0x2C,
+ 0x41, 0xD9, 0xEB, 0xE4, 0x8D, 0x1D, 0xCA, 0x8F,
+ 0x5E, 0x43, 0xAF, 0x46, 0x0A, 0x01, 0x0C, 0xB4,
+ 0x95, 0x52, 0x92, 0xE0, 0x10, 0x57, 0x0F, 0x71,
+ 0xB1, 0x26, 0xD8, 0x05, 0x69, 0x3C, 0x54, 0xDF,
+ 0xFF, 0x9D, 0x51, 0xA0, 0xA1, 0x0B, 0xC1, 0x20,
+ 0x6D, 0xFA, 0x47, 0x15, 0x09, 0xD3, 0xE1, 0xA9,
+ 0x66, 0x12, 0x5C, 0x49, 0x1E, 0x3B, 0xD0, 0x8B,
+ 0x62, 0xBD, 0x06, 0xE5, 0x00, 0x98, 0x4E, 0x32,
+ 0xB0, 0x2D, 0x2A, 0x7F, 0x03, 0xD5, 0x99, 0x7E,
+ 0xAB, 0x22, 0xC6, 0xC3, 0x2F, 0x4C, 0x33, 0x45,
+ 0xE3, 0x3F, 0xF9, 0xB2, 0xFE, 0x36, 0xE7, 0xF8,
+ 0x55, 0x0D, 0x56, 0x1F, 0x4B, 0xE6, 0x50, 0x81,
+ 0xCE, 0x80, 0xCD, 0x67, 0x6B, 0xCF, 0x2E, 0x9B,
+ 0xBC, 0xBE, 0x11, 0x75, 0x4D, 0xAC, 0x59, 0x40,
+ 0x85, 0x0E, 0xC9, 0x17, 0xA3, 0x60, 0xED, 0x16,
+ 0xA4, 0xDD, 0xEE, 0x96, 0x77, 0x83, 0x34, 0xD2,
+ 0xCB, 0xFC, 0x6C, 0x08, 0xEC, 0x35, 0xF2, 0x6F,
+ 0x3A, 0x7B, 0x21, 0x4A, 0x70, 0xEF, 0xAD, 0xDE,
+ 0x90, 0x9E, 0x7D, 0x64, 0x2B, 0x79, 0xF5, 0xF3,
+ 0x13, 0x1C, 0x7A, 0x07, 0x4F, 0x78, 0x89, 0xB6,
+ 0x97, 0xF1, 0xD7, 0x7C, 0x48, 0xAE, 0x39, 0xA8,
+ 0xA6, 0x86, 0x3E, 0x27, 0x87, 0x73, 0x82, 0x24,
+ 0x30, 0x74, 0x5F, 0xD1, 0x9F, 0x9C, 0x1A, 0x8C,
+ 0x42, 0x6E, 0x28, 0xB9, 0xF0, 0xC4, 0x68, 0x25,
+ 0xC5, 0xDC, 0xB8, 0x29, 0xD6, 0x84, 0x3D, 0xBB,
+ 0x88, 0x76, 0xFD, 0x61, 0x94, 0x91, 0xDA, 0xB7,
+ 0x72, 0xBA, 0xC2, 0xDB, 0xB5, 0xA5, 0xE2, 0x18,
+ 0xF6, 0xAA, 0x8A, 0x19, 0x63, 0x9A, 0xA7, 0xC8,
+ 0xD4, 0x02, 0x8E, 0x37, 0xF4, 0xB3, 0xA2, 0x53,
+ 0x38, 0xCC, 0x58, 0x44, 0xBF, 0x93, 0x5D, 0xC7 };
+
+unsigned char table_163[32] = {
+ 0x1B, 0x14, 0x12, 0x15, 0x11, 0x1D, 0x17, 0x19,
+ 0x10, 0x09, 0x08, 0x06, 0x1A, 0x16, 0x07, 0x13,
+ 0x1F, 0x0B, 0x1C, 0x05, 0x0E, 0x00, 0x18, 0x0A,
+ 0x04, 0x01, 0x03, 0x0C, 0x0D, 0x1E, 0x02, 0x0F };
+
+unsigned char table_164[32] = {
+ 0x15, 0x00, 0x10, 0x0B, 0x1D, 0x0A, 0x06, 0x1C,
+ 0x0D, 0x1F, 0x17, 0x0F, 0x03, 0x14, 0x13, 0x12,
+ 0x1B, 0x18, 0x08, 0x1E, 0x16, 0x09, 0x1A, 0x04,
+ 0x02, 0x0C, 0x0E, 0x01, 0x07, 0x19, 0x11, 0x05 };
+
+unsigned char table_165[256] = {
+ 0x98, 0xF5, 0x1D, 0xFB, 0x13, 0x20, 0x41, 0xA3,
+ 0xE3, 0x76, 0x49, 0x7E, 0x60, 0xD8, 0x68, 0x30,
+ 0x88, 0x45, 0xD5, 0x77, 0x00, 0xC3, 0x09, 0x31,
+ 0x44, 0x18, 0xD4, 0x14, 0xC8, 0x1B, 0x8B, 0x38,
+ 0x08, 0x52, 0xD1, 0xF3, 0x69, 0x9F, 0xDA, 0x61,
+ 0x16, 0x1C, 0xE4, 0x7D, 0xEE, 0xD9, 0x5E, 0x4C,
+ 0xA7, 0xAA, 0xA6, 0xF6, 0xCF, 0xA0, 0xBA, 0x10,
+ 0xE2, 0xDE, 0x0F, 0xEA, 0xBC, 0x32, 0x63, 0xC0,
+ 0x54, 0xC5, 0xBE, 0x71, 0x80, 0x56, 0x5C, 0xA4,
+ 0xAD, 0x15, 0x9D, 0x11, 0x43, 0x67, 0x95, 0xAE,
+ 0xC6, 0xC4, 0x91, 0x9C, 0xE5, 0x37, 0xE1, 0x7A,
+ 0xDB, 0xEF, 0x03, 0x65, 0x86, 0x66, 0x2A, 0xB5,
+ 0xBF, 0xB4, 0x0D, 0xB3, 0xD7, 0x2D, 0x01, 0xEB,
+ 0x8C, 0xF2, 0x5A, 0x2E, 0x64, 0x25, 0x02, 0xCB,
+ 0x4A, 0xB0, 0xCE, 0x35, 0xA8, 0x47, 0x85, 0x33,
+ 0x34, 0x24, 0x23, 0x7B, 0xB6, 0x48, 0x83, 0x40,
+ 0x87, 0x57, 0x3C, 0xD6, 0xCD, 0x2C, 0x6D, 0xE7,
+ 0xBB, 0xED, 0x81, 0x5D, 0x55, 0x46, 0xDD, 0xD3,
+ 0x70, 0xBD, 0xB8, 0x75, 0x53, 0x6E, 0xD0, 0x99,
+ 0xCA, 0x58, 0xC7, 0x4B, 0x3D, 0xA5, 0x50, 0x7C,
+ 0x93, 0x51, 0xB7, 0xFD, 0x05, 0x3A, 0xE8, 0x8F,
+ 0x28, 0x74, 0x39, 0xF0, 0x7F, 0x4F, 0x06, 0x36,
+ 0xB2, 0x19, 0x2F, 0x1F, 0x8D, 0x0C, 0xB9, 0xFC,
+ 0x89, 0x21, 0x12, 0xF7, 0x3F, 0x94, 0x6F, 0xDC,
+ 0x3E, 0x4E, 0x3B, 0xC9, 0x07, 0x9B, 0x17, 0x9A,
+ 0x73, 0x6A, 0x5B, 0xA1, 0x1E, 0x8A, 0x04, 0x72,
+ 0x6C, 0xA2, 0xEC, 0x96, 0xFE, 0xF8, 0x84, 0xC1,
+ 0x79, 0x0E, 0x62, 0x90, 0x8E, 0xF4, 0x42, 0x29,
+ 0x92, 0x9E, 0xAC, 0x82, 0x4D, 0xAF, 0x2B, 0x6B,
+ 0xA9, 0xFF, 0x0A, 0xAB, 0x22, 0x5F, 0xDF, 0xD2,
+ 0x0B, 0x78, 0xF1, 0xE6, 0x59, 0x27, 0xC2, 0xE0,
+ 0x1A, 0x26, 0xCC, 0xB1, 0xF9, 0xFA, 0x97, 0xE9 };
+
+unsigned char table_166[256] = {
+ 0xCB, 0xEA, 0x2A, 0x36, 0x6D, 0x93, 0x4E, 0xD5,
+ 0xBC, 0x6A, 0xD4, 0x68, 0xF7, 0x18, 0xAB, 0x8B,
+ 0x66, 0x95, 0x94, 0x64, 0xB7, 0x00, 0x4D, 0x97,
+ 0x38, 0xB3, 0xFC, 0xE1, 0xBB, 0x63, 0xF3, 0x1F,
+ 0x6B, 0x2C, 0x2F, 0x5E, 0xA4, 0x7E, 0xFB, 0xF4,
+ 0xA8, 0x8A, 0x65, 0x53, 0x90, 0x58, 0x40, 0x60,
+ 0x28, 0x8E, 0x35, 0x49, 0xED, 0xBD, 0x1B, 0x0B,
+ 0xBA, 0xB8, 0x61, 0x50, 0xE9, 0x39, 0xEF, 0xC3,
+ 0x74, 0xB6, 0x46, 0x8D, 0xD9, 0x32, 0x92, 0x9A,
+ 0x30, 0x01, 0xF2, 0x41, 0xB9, 0xE7, 0x3A, 0xB0,
+ 0x80, 0x15, 0xDE, 0x7D, 0x7F, 0x09, 0xC2, 0x76,
+ 0xF8, 0x12, 0x59, 0xDD, 0x1D, 0xE6, 0x75, 0xBE,
+ 0xA3, 0x04, 0xCA, 0x78, 0x7B, 0xAC, 0xD8, 0x70,
+ 0xD3, 0xC1, 0x25, 0x6F, 0x03, 0x6C, 0x14, 0x45,
+ 0xE5, 0x2B, 0x87, 0x83, 0xAA, 0x77, 0x5F, 0x4A,
+ 0x9C, 0x27, 0x0C, 0x10, 0xAE, 0x56, 0x85, 0x0D,
+ 0xE3, 0xFA, 0x71, 0xEE, 0x9F, 0x21, 0xC0, 0xCD,
+ 0xFD, 0xDC, 0x5B, 0x11, 0x02, 0x0F, 0x96, 0x3D,
+ 0x3C, 0x26, 0xEB, 0x08, 0x7A, 0x82, 0xA7, 0x19,
+ 0xD7, 0xC5, 0xF6, 0x52, 0x57, 0x88, 0xFF, 0x47,
+ 0x8F, 0xC6, 0x33, 0xB5, 0x2E, 0x8C, 0x81, 0x91,
+ 0x44, 0xA6, 0x17, 0xF0, 0x4B, 0x9D, 0x34, 0x73,
+ 0x72, 0x67, 0xD2, 0x0E, 0xA0, 0x99, 0xA5, 0xAF,
+ 0xFE, 0x9E, 0x6E, 0xDA, 0x3B, 0xE2, 0x23, 0xD6,
+ 0xD0, 0x13, 0x89, 0x5A, 0x42, 0x98, 0x5C, 0xD1,
+ 0x86, 0x24, 0xDF, 0x37, 0xF9, 0xCC, 0xF5, 0xA9,
+ 0x2D, 0xBF, 0x5D, 0xF1, 0x69, 0xE8, 0xA2, 0x06,
+ 0x48, 0xC7, 0xDB, 0x29, 0xE4, 0xAD, 0x3E, 0xA1,
+ 0xC9, 0x4C, 0x1A, 0xCE, 0x62, 0x4F, 0x7C, 0xC8,
+ 0x05, 0xC4, 0xB1, 0x1E, 0x79, 0x55, 0x84, 0xB2,
+ 0x20, 0x31, 0x9B, 0xEC, 0xB4, 0xCF, 0x54, 0x22,
+ 0x1C, 0xE0, 0x51, 0x16, 0x43, 0x07, 0x0A, 0x3F };
+
+unsigned char table_167[256] = {
+ 0x91, 0xEA, 0x4F, 0x6A, 0x6E, 0x2D, 0x27, 0x22,
+ 0x44, 0xA5, 0x6D, 0xE3, 0x45, 0x06, 0xE2, 0x87,
+ 0x9A, 0xC9, 0x2C, 0x4A, 0x93, 0x6F, 0x00, 0xEB,
+ 0x7C, 0x7F, 0xA2, 0xFE, 0x40, 0x3C, 0x3F, 0xC0,
+ 0xC7, 0xFB, 0x8B, 0xDF, 0xA3, 0x28, 0x78, 0x48,
+ 0x46, 0xD5, 0x70, 0x5C, 0x35, 0x4E, 0xD7, 0x3A,
+ 0x42, 0x47, 0x5B, 0x26, 0x8E, 0xE0, 0x21, 0xB1,
+ 0x77, 0x1E, 0x53, 0x4B, 0xCC, 0xE5, 0x65, 0xF6,
+ 0x66, 0x2A, 0xA0, 0x5E, 0x3E, 0xAD, 0xA8, 0x95,
+ 0x1B, 0x0D, 0x8A, 0x05, 0x68, 0x59, 0x0C, 0x38,
+ 0x18, 0xC3, 0x81, 0xA4, 0xFD, 0x13, 0x50, 0xCA,
+ 0xE8, 0xDD, 0xD9, 0x76, 0x8C, 0xC5, 0xF4, 0x17,
+ 0xB4, 0x3D, 0xEC, 0x0B, 0x67, 0xC6, 0x8D, 0xE1,
+ 0xBB, 0x7E, 0xCB, 0x10, 0x99, 0xE9, 0x39, 0xF3,
+ 0x75, 0xFA, 0xAC, 0x16, 0x54, 0x51, 0xBC, 0x24,
+ 0x58, 0x08, 0xA7, 0x0F, 0x5D, 0xBF, 0xBA, 0xE7,
+ 0x9D, 0x2B, 0xB5, 0x29, 0xE4, 0xCD, 0x37, 0x30,
+ 0x55, 0xAE, 0x1D, 0x4D, 0x94, 0x34, 0x92, 0x1C,
+ 0x6B, 0xBE, 0x52, 0x7B, 0x33, 0xB0, 0x0A, 0x5A,
+ 0x03, 0x23, 0x41, 0x49, 0x61, 0x64, 0x73, 0x97,
+ 0xC2, 0x9F, 0x5F, 0x07, 0x04, 0xF8, 0xC1, 0xFC,
+ 0x74, 0x02, 0x0E, 0x60, 0x9E, 0xD4, 0x85, 0x88,
+ 0xC4, 0xF5, 0x90, 0x31, 0xF7, 0xEE, 0x9B, 0xB9,
+ 0x20, 0xE6, 0xA6, 0x63, 0x79, 0x56, 0x62, 0xF0,
+ 0x2F, 0xD8, 0x4C, 0x83, 0xF9, 0x36, 0x3B, 0x84,
+ 0xDE, 0x57, 0xB8, 0xB7, 0x11, 0xF2, 0xC8, 0xD3,
+ 0xD1, 0x96, 0x19, 0x2E, 0x72, 0x9C, 0xDB, 0xB3,
+ 0xA1, 0xAA, 0xCE, 0x09, 0x98, 0xED, 0xA9, 0xDA,
+ 0xAF, 0x86, 0xD0, 0x12, 0xFF, 0xDC, 0x1F, 0xD6,
+ 0x01, 0xF1, 0xD2, 0x80, 0x43, 0x7A, 0x71, 0x82,
+ 0xB6, 0xAB, 0x89, 0xBD, 0x8F, 0xEF, 0x7D, 0xB2,
+ 0x14, 0x15, 0x25, 0x32, 0x6C, 0x69, 0x1A, 0xCF };
+
+unsigned char table_168[256] = {
+ 0x28, 0xEE, 0xB1, 0xFD, 0xB3, 0xEF, 0x36, 0x8E,
+ 0x85, 0x5D, 0x1C, 0x53, 0x1E, 0xDA, 0xBA, 0x3C,
+ 0xA8, 0x90, 0x99, 0x49, 0x45, 0xE0, 0x27, 0x8D,
+ 0x22, 0xE4, 0x51, 0x3E, 0xAB, 0xE8, 0x70, 0xF5,
+ 0x81, 0xE6, 0x34, 0x29, 0xF3, 0x11, 0x46, 0x5F,
+ 0x5C, 0xA0, 0xD1, 0xE3, 0x15, 0x68, 0x3A, 0x01,
+ 0xE9, 0xD7, 0x24, 0x5A, 0x18, 0x16, 0x88, 0x3B,
+ 0x64, 0xA1, 0xDB, 0xBF, 0xAA, 0x43, 0xEA, 0x19,
+ 0xA2, 0xD5, 0x7B, 0xBD, 0x2A, 0x0E, 0x4F, 0xB5,
+ 0x4B, 0xB7, 0x5B, 0x73, 0xC9, 0xAC, 0x1B, 0x67,
+ 0xC7, 0xB4, 0x69, 0x00, 0xBC, 0x6D, 0xC1, 0x04,
+ 0xF4, 0x74, 0xD6, 0xD0, 0x60, 0xAE, 0x17, 0xFE,
+ 0x63, 0xB6, 0x89, 0x41, 0x7C, 0x44, 0x8B, 0xDC,
+ 0x50, 0xE5, 0x79, 0x77, 0x47, 0x9F, 0xA6, 0x3D,
+ 0x09, 0x8A, 0x2F, 0xC0, 0x0F, 0xCD, 0x2B, 0x4D,
+ 0x0D, 0xC2, 0x5E, 0xB0, 0x57, 0x62, 0xAF, 0x1A,
+ 0x21, 0x82, 0x48, 0x9E, 0x38, 0xB9, 0xB8, 0xF2,
+ 0x37, 0x07, 0xCA, 0xC5, 0x84, 0xDF, 0xF9, 0xEC,
+ 0x42, 0x6B, 0x8F, 0x6C, 0x3F, 0xC4, 0x94, 0xED,
+ 0x7A, 0x2D, 0xA3, 0x83, 0xD9, 0x55, 0x02, 0x9A,
+ 0xA9, 0x75, 0x10, 0x2C, 0xCB, 0x95, 0xBB, 0x6E,
+ 0x23, 0x65, 0x35, 0x97, 0x56, 0xAD, 0xCE, 0xF8,
+ 0xF0, 0x0C, 0xE2, 0x52, 0x05, 0x91, 0xCC, 0xC8,
+ 0x78, 0x06, 0x96, 0x4E, 0x03, 0xD3, 0x98, 0xA7,
+ 0x13, 0x58, 0x93, 0xD4, 0xDD, 0xC6, 0xFC, 0x25,
+ 0x9C, 0x86, 0x1F, 0xCF, 0x76, 0xA4, 0x6A, 0xFA,
+ 0x0B, 0x4A, 0x54, 0x40, 0x59, 0xD8, 0x61, 0xFF,
+ 0x7F, 0x80, 0x6F, 0x7D, 0xF1, 0x8C, 0x92, 0xDE,
+ 0x9D, 0xC3, 0xB2, 0xE7, 0xFB, 0x20, 0x31, 0x72,
+ 0x12, 0xBE, 0x1D, 0xF6, 0x9B, 0x14, 0x26, 0x0A,
+ 0xEB, 0xF7, 0x71, 0x39, 0x30, 0xA5, 0x87, 0xD2,
+ 0x66, 0x2E, 0x08, 0x32, 0x4C, 0x33, 0x7E, 0xE1 };
+
+unsigned char table_169[256] = {
+ 0xA4, 0x31, 0xA9, 0x3F, 0x13, 0x4D, 0x1B, 0x29,
+ 0x73, 0x43, 0xF1, 0xE7, 0x9C, 0xC2, 0xF6, 0xCD,
+ 0xA1, 0x94, 0x0D, 0x27, 0xFE, 0x7B, 0x9B, 0x0B,
+ 0x89, 0xBA, 0x23, 0xEC, 0x76, 0xC3, 0x6C, 0xD8,
+ 0x8D, 0xF8, 0xF9, 0x7D, 0x68, 0x5B, 0x61, 0x87,
+ 0x28, 0x14, 0x55, 0x0C, 0xFC, 0xD9, 0x07, 0xE8,
+ 0x36, 0x88, 0x67, 0x4C, 0xEA, 0xBD, 0xF5, 0x9D,
+ 0xB6, 0xC6, 0x24, 0x32, 0x93, 0x03, 0x79, 0x8C,
+ 0x12, 0x84, 0xFF, 0x7E, 0x42, 0xE4, 0x3C, 0xF2,
+ 0x50, 0xEB, 0x1F, 0x47, 0xB0, 0xA5, 0xB1, 0x71,
+ 0x30, 0x5F, 0x5C, 0x53, 0xF7, 0x10, 0xC5, 0x6E,
+ 0xE0, 0xDE, 0xC8, 0x58, 0xB7, 0x90, 0xA6, 0x95,
+ 0x70, 0x8F, 0xFD, 0xC1, 0x48, 0xB5, 0x19, 0x92,
+ 0xBC, 0x15, 0x4E, 0xE6, 0x11, 0xDD, 0x81, 0x0E,
+ 0xBB, 0x75, 0x5D, 0x4A, 0xAB, 0x2D, 0x02, 0x54,
+ 0x4B, 0x66, 0xD6, 0x2B, 0x2A, 0xE5, 0x26, 0xE1,
+ 0xEE, 0xE9, 0x8B, 0x6A, 0x7A, 0xF4, 0x51, 0x39,
+ 0x1C, 0xC9, 0xCF, 0x77, 0x00, 0xF3, 0x25, 0xCC,
+ 0x08, 0xFB, 0x0F, 0x3E, 0xCE, 0xED, 0x3D, 0x56,
+ 0xEF, 0x1D, 0x85, 0x96, 0x52, 0xA8, 0xD3, 0xCB,
+ 0xE3, 0x33, 0x06, 0x7C, 0xAE, 0x72, 0x09, 0x04,
+ 0x91, 0xC4, 0x5A, 0x69, 0x98, 0xB4, 0x40, 0xDF,
+ 0x7F, 0x9F, 0xAA, 0x83, 0xE2, 0x78, 0x74, 0x20,
+ 0xAD, 0x6D, 0xDC, 0xD4, 0xCA, 0x60, 0xF0, 0x35,
+ 0x37, 0xD0, 0x18, 0x1A, 0x64, 0x3A, 0x99, 0xDB,
+ 0x62, 0x44, 0x2C, 0x82, 0x8E, 0xD7, 0xD1, 0xFA,
+ 0x16, 0xD5, 0x46, 0xBF, 0xA7, 0xC0, 0x2E, 0x3B,
+ 0x01, 0x63, 0xB2, 0x1E, 0x05, 0x21, 0xB8, 0x17,
+ 0x22, 0x97, 0xAF, 0x4F, 0x86, 0x34, 0xDA, 0xC7,
+ 0xA3, 0xA0, 0xB3, 0x2F, 0xAC, 0x49, 0xD2, 0x57,
+ 0x6F, 0x9A, 0x65, 0xB9, 0x41, 0xBE, 0x8A, 0xA2,
+ 0x6B, 0x0A, 0x59, 0x9E, 0x5E, 0x38, 0x45, 0x80 };
+
+unsigned char table_170[256] = {
+ 0xE3, 0x00, 0x99, 0x03, 0xF6, 0xDD, 0xD1, 0x41,
+ 0x58, 0x7E, 0xD9, 0x46, 0x04, 0xAF, 0x5C, 0x43,
+ 0xDE, 0x5E, 0xFC, 0x97, 0x3D, 0x68, 0xC8, 0x37,
+ 0x3C, 0xFB, 0x0F, 0x5A, 0xBE, 0xFA, 0x4C, 0x82,
+ 0x0C, 0xA0, 0x0A, 0xD4, 0x9D, 0xCE, 0x78, 0xA8,
+ 0x55, 0x56, 0x60, 0xAA, 0xC9, 0x96, 0x62, 0xEA,
+ 0x0D, 0xB8, 0xE2, 0x84, 0x17, 0xAE, 0x2B, 0x2C,
+ 0x91, 0x57, 0x38, 0x01, 0xA9, 0xCD, 0x34, 0xBA,
+ 0x8D, 0xC0, 0xD6, 0xFF, 0xF2, 0xD3, 0x5F, 0x26,
+ 0xCA, 0x9B, 0x21, 0x75, 0x4E, 0x49, 0x20, 0x59,
+ 0x39, 0xBF, 0x90, 0x6C, 0xFE, 0x8F, 0x2F, 0x18,
+ 0x36, 0xD7, 0xB4, 0xAC, 0xBD, 0xF3, 0x1D, 0x4F,
+ 0xA3, 0x74, 0x5B, 0x44, 0x05, 0x9C, 0x6D, 0x6B,
+ 0x1E, 0xE8, 0x25, 0x16, 0x80, 0xCC, 0x29, 0xC7,
+ 0x94, 0x4A, 0xF5, 0xF4, 0x27, 0x85, 0xBB, 0x24,
+ 0xDA, 0xB5, 0x76, 0x69, 0xA5, 0x54, 0x23, 0x31,
+ 0x11, 0xA4, 0x09, 0xE4, 0x64, 0x10, 0xC5, 0xC1,
+ 0x7D, 0xE7, 0x92, 0xF8, 0x9E, 0x6A, 0x15, 0x8B,
+ 0x98, 0x42, 0x52, 0x66, 0x0B, 0xA1, 0x35, 0x1A,
+ 0x14, 0x7C, 0xE1, 0x9F, 0x28, 0xF1, 0x1B, 0xA6,
+ 0x71, 0x73, 0x81, 0xAB, 0xE6, 0x95, 0x06, 0x1F,
+ 0xC6, 0xB0, 0x51, 0x0E, 0xEE, 0x77, 0xF0, 0xD8,
+ 0xC2, 0x89, 0x7B, 0x07, 0xA2, 0xB7, 0x19, 0x67,
+ 0x2E, 0x8E, 0x47, 0xA7, 0xEF, 0x32, 0xD2, 0x93,
+ 0xDC, 0x9A, 0xB2, 0xED, 0x45, 0xC4, 0x50, 0x3F,
+ 0xE5, 0xCF, 0x88, 0x1C, 0x7A, 0x79, 0xEB, 0x70,
+ 0x2A, 0x7F, 0xBC, 0xDB, 0xD0, 0xB1, 0xCB, 0x08,
+ 0x86, 0x5D, 0x53, 0x72, 0xB6, 0x4B, 0xB3, 0x22,
+ 0xC3, 0x6F, 0xB9, 0xD5, 0x3B, 0x13, 0x2D, 0xAD,
+ 0x33, 0xFD, 0x02, 0x40, 0x8A, 0x3A, 0xF7, 0xE0,
+ 0x8C, 0x3E, 0x61, 0x6E, 0xE9, 0x63, 0xF9, 0xEC,
+ 0x48, 0x30, 0x87, 0x83, 0x12, 0x4D, 0x65, 0xDF };
+
+unsigned char table_171[32] = {
+ 0x07, 0x06, 0x11, 0x08, 0x0C, 0x1F, 0x19, 0x02,
+ 0x14, 0x04, 0x0D, 0x18, 0x1A, 0x05, 0x17, 0x13,
+ 0x1C, 0x1B, 0x15, 0x03, 0x01, 0x0F, 0x16, 0x1E,
+ 0x1D, 0x10, 0x00, 0x12, 0x0B, 0x0E, 0x09, 0x0A };
+
+unsigned char table_172[32] = {
+ 0x11, 0x01, 0x1F, 0x06, 0x1A, 0x04, 0x02, 0x09,
+ 0x05, 0x0D, 0x0B, 0x18, 0x0E, 0x12, 0x1B, 0x17,
+ 0x07, 0x08, 0x1D, 0x1E, 0x14, 0x19, 0x16, 0x15,
+ 0x03, 0x0C, 0x00, 0x10, 0x0A, 0x1C, 0x0F, 0x13 };
+
+unsigned char table_173[32] = {
+ 0x1F, 0x0B, 0x13, 0x00, 0x16, 0x15, 0x14, 0x0A,
+ 0x1D, 0x05, 0x1E, 0x1A, 0x0F, 0x04, 0x0E, 0x01,
+ 0x19, 0x07, 0x02, 0x12, 0x0C, 0x17, 0x08, 0x09,
+ 0x03, 0x11, 0x18, 0x10, 0x1C, 0x1B, 0x06, 0x0D };
+
+unsigned char table_174[32] = {
+ 0x02, 0x1B, 0x0C, 0x17, 0x1F, 0x05, 0x15, 0x1E,
+ 0x16, 0x09, 0x1A, 0x12, 0x0F, 0x1C, 0x18, 0x0A,
+ 0x19, 0x10, 0x0D, 0x13, 0x04, 0x11, 0x08, 0x14,
+ 0x1D, 0x0E, 0x06, 0x00, 0x01, 0x07, 0x0B, 0x03 };
+
+unsigned char table_175[32] = {
+ 0x00, 0x06, 0x0B, 0x08, 0x0C, 0x04, 0x1A, 0x1C,
+ 0x05, 0x1E, 0x14, 0x03, 0x0A, 0x18, 0x12, 0x1D,
+ 0x16, 0x1F, 0x07, 0x09, 0x0F, 0x0E, 0x17, 0x13,
+ 0x11, 0x19, 0x10, 0x0D, 0x1B, 0x02, 0x01, 0x15 };
+
+unsigned char table_176[32] = {
+ 0x12, 0x03, 0x1A, 0x15, 0x04, 0x19, 0x0B, 0x1B,
+ 0x17, 0x1E, 0x0D, 0x05, 0x11, 0x14, 0x1C, 0x00,
+ 0x18, 0x10, 0x0A, 0x06, 0x0E, 0x08, 0x02, 0x07,
+ 0x13, 0x09, 0x16, 0x1D, 0x0F, 0x0C, 0x01, 0x1F };
+
+unsigned char table_177[256] = {
+ 0x5E, 0x4D, 0x76, 0xFE, 0xB5, 0x50, 0x83, 0x23,
+ 0x72, 0xDD, 0x93, 0x08, 0x69, 0xAD, 0xEC, 0x3B,
+ 0x0B, 0x9A, 0x36, 0xC9, 0xCA, 0xBE, 0xF7, 0x30,
+ 0x19, 0x39, 0x2C, 0xAB, 0xE3, 0x7B, 0xBC, 0x32,
+ 0xA0, 0xE4, 0xA6, 0xB6, 0xCB, 0xC8, 0x37, 0x07,
+ 0xD2, 0xA1, 0xD9, 0xF6, 0xBF, 0xF5, 0x88, 0x01,
+ 0x95, 0x0F, 0x03, 0xFD, 0xE6, 0x68, 0x90, 0x61,
+ 0x21, 0x6D, 0x3C, 0x62, 0x34, 0x2B, 0x71, 0x4B,
+ 0x44, 0x64, 0x75, 0xA2, 0x6A, 0xFF, 0x29, 0xBD,
+ 0x35, 0x15, 0xF9, 0xC1, 0x09, 0x45, 0xB2, 0xF2,
+ 0x3F, 0xCE, 0xB0, 0xC0, 0xB8, 0x00, 0x05, 0xD7,
+ 0x11, 0xC6, 0x78, 0x53, 0x9E, 0xB3, 0xED, 0x56,
+ 0x22, 0x5C, 0x9D, 0x6C, 0x99, 0x43, 0x2F, 0xAE,
+ 0xEB, 0x40, 0x8C, 0x1F, 0xC2, 0xDF, 0x92, 0x65,
+ 0x6F, 0x79, 0x5D, 0x5B, 0xAA, 0xDB, 0xF1, 0x96,
+ 0xD4, 0xF4, 0x8B, 0x51, 0xD5, 0xE2, 0xBB, 0x80,
+ 0x17, 0x7C, 0x2A, 0x6E, 0xDE, 0xEA, 0x94, 0x31,
+ 0xA4, 0x2D, 0xC3, 0x8D, 0x55, 0x14, 0x9B, 0x0E,
+ 0x7D, 0xC4, 0x06, 0x33, 0x73, 0xE9, 0x7A, 0x38,
+ 0x5F, 0x89, 0x84, 0xD6, 0xA8, 0x13, 0xE8, 0xCF,
+ 0x46, 0xD0, 0x7F, 0x24, 0x8F, 0xF8, 0x87, 0x1B,
+ 0x47, 0x02, 0x0C, 0x97, 0x52, 0xFB, 0x8E, 0x20,
+ 0x70, 0x3E, 0x7E, 0xD1, 0xE5, 0xEE, 0xCC, 0x91,
+ 0x74, 0xCD, 0x42, 0x04, 0x8A, 0xEF, 0xE1, 0x10,
+ 0x4F, 0x1C, 0x28, 0x9F, 0xD8, 0x0A, 0x18, 0x49,
+ 0x9C, 0x16, 0xF3, 0x82, 0x57, 0x1D, 0x26, 0x66,
+ 0x27, 0x86, 0xE7, 0x59, 0xFA, 0x25, 0x54, 0x0D,
+ 0x98, 0xDC, 0xF0, 0x3D, 0x63, 0x1E, 0x77, 0x3A,
+ 0xDA, 0xB7, 0x6B, 0x2E, 0x48, 0x4C, 0xBA, 0xC7,
+ 0x60, 0xAC, 0x1A, 0xB9, 0xFC, 0xA3, 0xA7, 0xA5,
+ 0xB4, 0x67, 0xA9, 0x81, 0xB1, 0x12, 0xD3, 0x85,
+ 0x5A, 0xC5, 0xE0, 0x58, 0x41, 0x4E, 0x4A, 0xAF };
+
+unsigned char table_178[256] = {
+ 0x33, 0xBA, 0x98, 0xDA, 0x07, 0x2C, 0x22, 0x9B,
+ 0xE0, 0xED, 0xB7, 0xA1, 0x93, 0xEB, 0xDC, 0x49,
+ 0xDF, 0xE1, 0x6C, 0xC2, 0x64, 0x52, 0xD0, 0x8F,
+ 0xA2, 0x48, 0x26, 0x21, 0x6E, 0x5E, 0x0B, 0x7C,
+ 0x0D, 0x90, 0xA4, 0xCE, 0xF5, 0x5F, 0xF9, 0x1D,
+ 0x55, 0x83, 0x8D, 0xFB, 0x38, 0xB3, 0xF2, 0x67,
+ 0xDE, 0x0A, 0xBE, 0xEC, 0x5B, 0x35, 0x08, 0x50,
+ 0xE7, 0x56, 0x4A, 0x02, 0xBC, 0x5A, 0xBD, 0x43,
+ 0x6F, 0x79, 0xB2, 0xF7, 0x60, 0xE9, 0xA0, 0x1B,
+ 0xC8, 0xDD, 0x9D, 0xA3, 0x5C, 0x61, 0x77, 0x72,
+ 0x9C, 0x31, 0x0E, 0x05, 0x1E, 0x12, 0xF1, 0xC9,
+ 0x78, 0x4E, 0x15, 0x7D, 0x54, 0xCB, 0x73, 0xEA,
+ 0xC5, 0x2B, 0x0F, 0x7E, 0x42, 0x96, 0xC6, 0x74,
+ 0x09, 0x65, 0x34, 0xE6, 0x63, 0xA6, 0x70, 0xD3,
+ 0x27, 0x87, 0x3A, 0x16, 0x7B, 0x13, 0x06, 0x40,
+ 0x46, 0x69, 0xAD, 0x88, 0x81, 0xC0, 0x37, 0x58,
+ 0xD1, 0x8A, 0x8E, 0x9A, 0x5D, 0x6D, 0xC7, 0xC3,
+ 0xD2, 0xF4, 0x3F, 0x57, 0x3C, 0x4F, 0xA9, 0x6A,
+ 0x92, 0xA5, 0x97, 0x0C, 0x2A, 0x36, 0x47, 0xDB,
+ 0x8C, 0xEE, 0x03, 0x89, 0x7F, 0x91, 0x24, 0x80,
+ 0x2F, 0x62, 0xE4, 0xAF, 0x17, 0x99, 0xD6, 0xCD,
+ 0xFE, 0x76, 0x1C, 0xD4, 0x3E, 0xFF, 0xD8, 0xC4,
+ 0x39, 0x32, 0xCF, 0xE2, 0xE3, 0x53, 0xD7, 0xCC,
+ 0xD9, 0x11, 0xAA, 0x1F, 0x01, 0x3B, 0x51, 0xB5,
+ 0x94, 0x4B, 0x28, 0xF0, 0xAC, 0x44, 0x14, 0x4C,
+ 0xB9, 0xA7, 0xB8, 0x1A, 0xD5, 0xCA, 0xE8, 0x82,
+ 0x9F, 0x2D, 0xAB, 0x2E, 0x29, 0xFD, 0x68, 0xB1,
+ 0x66, 0xC1, 0x7A, 0xFA, 0x71, 0x04, 0xA8, 0xB0,
+ 0x59, 0x18, 0xAE, 0x25, 0x3D, 0xE5, 0xF6, 0x41,
+ 0x86, 0x75, 0x6B, 0xBB, 0xFC, 0x84, 0x8B, 0x85,
+ 0x10, 0x23, 0xB6, 0xF3, 0x19, 0x30, 0x20, 0x4D,
+ 0x95, 0x9E, 0xBF, 0xEF, 0xF8, 0x45, 0x00, 0xB4 };
+
+unsigned char table_179[256] = {
+ 0x50, 0x3D, 0x41, 0x42, 0x06, 0x5B, 0xD6, 0x34,
+ 0x9D, 0x3C, 0x7B, 0x14, 0xE2, 0x9B, 0x80, 0x15,
+ 0x51, 0x01, 0x6A, 0x30, 0xD7, 0xFC, 0x61, 0x4B,
+ 0x8A, 0xEC, 0x38, 0x71, 0x70, 0x2E, 0x1C, 0x72,
+ 0x79, 0x26, 0x4C, 0x48, 0xED, 0xAD, 0x25, 0x53,
+ 0x03, 0xD9, 0xB5, 0x0D, 0x8E, 0x19, 0xCC, 0xBE,
+ 0xE1, 0x91, 0x64, 0xA6, 0x21, 0xCE, 0x76, 0xAB,
+ 0x9F, 0xD1, 0xB6, 0x23, 0x6D, 0xB0, 0x90, 0xBD,
+ 0x09, 0x3A, 0x5E, 0xD0, 0x73, 0x10, 0x44, 0x08,
+ 0xFF, 0xB8, 0x24, 0x58, 0xDB, 0x65, 0x95, 0xAA,
+ 0xE9, 0xC4, 0x32, 0x2B, 0x84, 0xC9, 0xC7, 0xB1,
+ 0x4F, 0x0C, 0xCB, 0x11, 0x4E, 0x22, 0x4A, 0x16,
+ 0xDE, 0xBC, 0xEE, 0x68, 0x13, 0xFA, 0xC3, 0x98,
+ 0xEB, 0x29, 0x43, 0x9A, 0xA1, 0xE0, 0xF0, 0x3F,
+ 0x2F, 0x1B, 0xC2, 0x66, 0x35, 0xF5, 0xC8, 0xD8,
+ 0x5A, 0xE5, 0x87, 0x47, 0xD3, 0x7A, 0xE6, 0x39,
+ 0x77, 0x81, 0xF2, 0x0E, 0x83, 0x7E, 0x17, 0x6C,
+ 0xB3, 0x5C, 0xE8, 0xD2, 0xC0, 0xA4, 0xF9, 0x86,
+ 0xCD, 0xFB, 0x54, 0x7C, 0xBF, 0x2D, 0x82, 0xDA,
+ 0x96, 0x74, 0x97, 0xC5, 0x7D, 0x27, 0x57, 0x56,
+ 0xDC, 0xBA, 0x69, 0x8C, 0x9C, 0x88, 0xB4, 0x8D,
+ 0x37, 0xEA, 0x3B, 0x33, 0x2C, 0xB2, 0x45, 0xF7,
+ 0xC1, 0x1E, 0x46, 0x02, 0x6B, 0x3E, 0xA7, 0xD5,
+ 0x05, 0x0A, 0xA9, 0x1D, 0xA3, 0x4D, 0xAE, 0x6F,
+ 0x49, 0xDD, 0x8F, 0xEF, 0xBB, 0x67, 0x0B, 0x40,
+ 0x9E, 0xF1, 0x78, 0x28, 0xDF, 0x52, 0xF4, 0x92,
+ 0x94, 0x0F, 0xB9, 0x93, 0xF6, 0x1F, 0xAF, 0xA8,
+ 0xCA, 0xE4, 0x59, 0x7F, 0x85, 0x75, 0xC6, 0xFD,
+ 0x00, 0xB7, 0x55, 0xFE, 0x8B, 0x62, 0x5F, 0x12,
+ 0xF8, 0xD4, 0x89, 0xA0, 0x20, 0xE7, 0xCF, 0x60,
+ 0x5D, 0xAC, 0x1A, 0x36, 0x63, 0x99, 0x31, 0xF3,
+ 0x2A, 0x04, 0x18, 0xA5, 0xA2, 0x6E, 0x07, 0xE3 };
+
+unsigned char table_180[256] = {
+ 0xDA, 0xCC, 0x72, 0xA6, 0xE7, 0x07, 0xFD, 0x25,
+ 0x92, 0x39, 0x49, 0x02, 0xD6, 0x09, 0xA8, 0x65,
+ 0x2E, 0x6C, 0xA1, 0x19, 0xBF, 0x21, 0x11, 0xC7,
+ 0x3F, 0x9F, 0xF4, 0x51, 0xAF, 0x8C, 0xFE, 0xCD,
+ 0x7A, 0xEB, 0x5A, 0xF7, 0x18, 0x69, 0xB9, 0xED,
+ 0x37, 0x45, 0x13, 0xB4, 0xAA, 0x75, 0x47, 0x42,
+ 0xA3, 0x81, 0x88, 0x70, 0xC1, 0x36, 0x73, 0x1D,
+ 0x3B, 0x22, 0xB6, 0x35, 0xE9, 0x31, 0x56, 0x23,
+ 0xE1, 0xF5, 0xAD, 0x46, 0x99, 0x32, 0xE4, 0x40,
+ 0x00, 0x0F, 0x05, 0xC6, 0x33, 0x84, 0x7B, 0x4D,
+ 0x4B, 0x7D, 0x91, 0x3D, 0xCE, 0x64, 0x77, 0x55,
+ 0xD7, 0x2B, 0x2F, 0x2C, 0xB8, 0xD3, 0x85, 0xD1,
+ 0xB5, 0x6A, 0xF9, 0x41, 0x08, 0xBB, 0x87, 0xEC,
+ 0x78, 0xE0, 0xEE, 0x8D, 0x01, 0x58, 0x15, 0x8F,
+ 0x06, 0xF0, 0x8B, 0x27, 0x0D, 0x0B, 0x6D, 0xBD,
+ 0xCA, 0x2A, 0xA2, 0xE6, 0xDD, 0xBC, 0x4E, 0x5D,
+ 0x74, 0x04, 0x3A, 0x96, 0x66, 0x12, 0x1E, 0xF2,
+ 0xF6, 0xC4, 0xAE, 0x3C, 0x0C, 0x90, 0x68, 0xD8,
+ 0x24, 0x5E, 0x79, 0x10, 0xAC, 0xDF, 0x9B, 0xC5,
+ 0x44, 0xC3, 0x50, 0x5C, 0xA5, 0x89, 0x60, 0x5F,
+ 0x48, 0x17, 0x34, 0xA7, 0xE2, 0xF3, 0xD9, 0x3E,
+ 0x9C, 0xB7, 0x7C, 0x1F, 0xA9, 0xD4, 0xA4, 0x0E,
+ 0x8E, 0x4C, 0xDC, 0xF8, 0xF1, 0x98, 0xDE, 0x2D,
+ 0x61, 0xCB, 0xD5, 0x43, 0x86, 0x26, 0xB0, 0x7F,
+ 0x7E, 0xFF, 0xAB, 0x83, 0x14, 0x9A, 0x80, 0x16,
+ 0x30, 0xA0, 0x53, 0x97, 0x52, 0x9E, 0xB1, 0x1B,
+ 0xD0, 0x1A, 0xC8, 0x57, 0xBA, 0x6E, 0xFA, 0x94,
+ 0xE8, 0x63, 0x5B, 0x29, 0xEF, 0x71, 0x8A, 0x03,
+ 0xB3, 0x76, 0xC9, 0xD2, 0xBE, 0xE5, 0x82, 0x1C,
+ 0x95, 0x9D, 0x4A, 0x28, 0xEA, 0x0A, 0xC0, 0xE3,
+ 0x6F, 0x20, 0x54, 0xFB, 0x93, 0xFC, 0x6B, 0x38,
+ 0x62, 0x4F, 0xCF, 0xB2, 0xC2, 0x59, 0xDB, 0x67 };
+
+unsigned char table_181[256] = {
+ 0x2B, 0xED, 0x14, 0x05, 0x80, 0xCC, 0x5A, 0xF8,
+ 0x43, 0xB7, 0x86, 0xC6, 0xEE, 0xA6, 0xD7, 0xD6,
+ 0xA0, 0xC4, 0x21, 0x34, 0xB1, 0x8C, 0xF9, 0xF4,
+ 0x7C, 0x53, 0x06, 0xD4, 0x6B, 0x3F, 0xE1, 0x12,
+ 0x6A, 0xCE, 0xCF, 0xBF, 0x74, 0x3E, 0xD5, 0xCB,
+ 0x97, 0x01, 0xA2, 0x2D, 0xAE, 0xF7, 0x17, 0x29,
+ 0x47, 0x03, 0x0E, 0xE9, 0x82, 0x46, 0x94, 0xAF,
+ 0x2A, 0x90, 0xFE, 0x4A, 0x7E, 0x0C, 0x71, 0xB6,
+ 0xA5, 0xF2, 0x67, 0x41, 0xBA, 0xC2, 0x8A, 0x9D,
+ 0x36, 0xFF, 0x50, 0x2E, 0xC3, 0x91, 0x9C, 0x37,
+ 0x66, 0xAD, 0xB2, 0x1F, 0xE4, 0xE3, 0x9F, 0xDD,
+ 0x87, 0xC0, 0xE6, 0xEF, 0x13, 0x70, 0x5B, 0xDE,
+ 0x5C, 0x75, 0x7F, 0x4F, 0x44, 0xCA, 0x55, 0x57,
+ 0xF0, 0x26, 0xA7, 0xC7, 0x10, 0x51, 0x00, 0xB3,
+ 0x5D, 0x99, 0x81, 0x3B, 0xB9, 0x1C, 0x64, 0x7B,
+ 0xFB, 0xD9, 0x8D, 0x4E, 0xAC, 0x25, 0xBB, 0x69,
+ 0xDF, 0x02, 0x9E, 0x2C, 0xAB, 0xF3, 0x65, 0x09,
+ 0xA3, 0x6C, 0xC1, 0x76, 0x52, 0x30, 0xD8, 0x3A,
+ 0x40, 0x18, 0x59, 0xD0, 0xE5, 0xB4, 0x5F, 0x33,
+ 0x68, 0x92, 0x2F, 0xB8, 0x93, 0xD1, 0xEB, 0xA4,
+ 0xFC, 0x77, 0x19, 0x62, 0xC9, 0x49, 0x84, 0x1A,
+ 0x9A, 0xE7, 0x31, 0xE8, 0xE2, 0x58, 0xF1, 0x4B,
+ 0x1E, 0x0B, 0x39, 0xFD, 0x42, 0x7A, 0x89, 0x38,
+ 0x11, 0x98, 0x63, 0x08, 0xE0, 0xEA, 0xBE, 0xB0,
+ 0x45, 0x1B, 0x4C, 0x54, 0xC8, 0x27, 0x3D, 0x73,
+ 0x04, 0x8F, 0x79, 0xBC, 0x6F, 0x0D, 0x0F, 0xA1,
+ 0x60, 0xDC, 0xC5, 0xFA, 0x8E, 0xDA, 0x15, 0x96,
+ 0xD3, 0x07, 0xF5, 0x3C, 0x88, 0x72, 0x1D, 0x4D,
+ 0x8B, 0x61, 0x0A, 0xDB, 0xAA, 0x20, 0x23, 0xEC,
+ 0x6E, 0x22, 0x48, 0x28, 0xBD, 0xA9, 0x56, 0x5E,
+ 0x85, 0xA8, 0x95, 0x6D, 0x16, 0x78, 0xB5, 0xF6,
+ 0x32, 0x24, 0x7D, 0x9B, 0xD2, 0x83, 0x35, 0xCD };
+
+unsigned char table_182[256] = {
+ 0x06, 0x7F, 0x66, 0xB5, 0xBA, 0x1E, 0xFD, 0x51,
+ 0x81, 0x8D, 0x28, 0xA3, 0x15, 0x37, 0xDC, 0x58,
+ 0xE6, 0x3D, 0xB4, 0xB9, 0x2E, 0xA0, 0x2F, 0xC4,
+ 0xCB, 0xB1, 0x25, 0xBF, 0xC1, 0x4E, 0x5A, 0xE4,
+ 0x0F, 0x10, 0x7C, 0x52, 0xA7, 0x29, 0x76, 0x55,
+ 0xAA, 0x70, 0x62, 0x54, 0x43, 0x93, 0x3A, 0x7D,
+ 0x5B, 0x56, 0x33, 0x64, 0x74, 0x2A, 0xD9, 0x9B,
+ 0x88, 0xC0, 0x3C, 0x63, 0xDE, 0xF4, 0x73, 0xDF,
+ 0x9E, 0xB2, 0xA8, 0x4F, 0x04, 0x57, 0x47, 0x87,
+ 0x14, 0xFC, 0x27, 0x53, 0x83, 0xDB, 0xD7, 0x20,
+ 0x96, 0x31, 0xD0, 0xCF, 0x30, 0x19, 0x69, 0x1A,
+ 0xAE, 0x3B, 0x11, 0x0C, 0xA6, 0x95, 0x8A, 0xF2,
+ 0x1B, 0xCC, 0x78, 0xEF, 0xB3, 0x71, 0x84, 0xA2,
+ 0xF1, 0x7A, 0x92, 0x61, 0xCA, 0x90, 0x94, 0x89,
+ 0x68, 0xEE, 0x97, 0x38, 0x0D, 0xF9, 0x1F, 0x8E,
+ 0xE9, 0x26, 0xBD, 0xC9, 0xFF, 0x4C, 0x44, 0x1D,
+ 0x98, 0xE5, 0x86, 0xF3, 0x18, 0xB6, 0x09, 0xD2,
+ 0x7E, 0xC5, 0xE7, 0x2B, 0x8C, 0x8B, 0x60, 0x3F,
+ 0x2C, 0x6A, 0x08, 0x0E, 0x50, 0x32, 0x9F, 0xF0,
+ 0x9A, 0xC2, 0x39, 0xBE, 0xEA, 0x12, 0x16, 0xBB,
+ 0x5E, 0x67, 0xE3, 0xB8, 0x79, 0x46, 0xDA, 0x00,
+ 0xD3, 0xBC, 0xCE, 0x1C, 0x80, 0xFA, 0xAB, 0x65,
+ 0x4A, 0xF8, 0xAC, 0x72, 0x01, 0xC6, 0x35, 0x85,
+ 0x3E, 0x5C, 0xA1, 0x05, 0xA5, 0xA9, 0xE1, 0x40,
+ 0xEB, 0xE8, 0x5F, 0xF5, 0xC3, 0xD1, 0x34, 0xFB,
+ 0xEC, 0xF7, 0x9C, 0xC7, 0xDD, 0x6C, 0x36, 0x9D,
+ 0x42, 0x59, 0x99, 0x5D, 0xD8, 0x82, 0x07, 0x24,
+ 0x6D, 0xAD, 0x13, 0x48, 0x6B, 0x6E, 0x75, 0x4D,
+ 0xD5, 0x02, 0xED, 0xFE, 0x91, 0xCD, 0x77, 0xB0,
+ 0xF6, 0xC8, 0x6F, 0x23, 0xAF, 0xB7, 0x2D, 0xD6,
+ 0xA4, 0xE2, 0x45, 0x8F, 0x21, 0xE0, 0x49, 0x22,
+ 0x7B, 0x17, 0x0B, 0x0A, 0x41, 0x03, 0xD4, 0x4B };
+
+unsigned char table_183[32] = {
+ 0x1E, 0x1B, 0x11, 0x07, 0x08, 0x06, 0x18, 0x17,
+ 0x0D, 0x0F, 0x12, 0x03, 0x1D, 0x04, 0x0A, 0x1A,
+ 0x0C, 0x13, 0x14, 0x1F, 0x0B, 0x19, 0x10, 0x01,
+ 0x16, 0x05, 0x1C, 0x0E, 0x02, 0x00, 0x09, 0x15 };
+
+unsigned char table_184[32] = {
+ 0x0F, 0x1D, 0x17, 0x16, 0x0D, 0x05, 0x13, 0x1F,
+ 0x1B, 0x09, 0x1C, 0x1E, 0x15, 0x01, 0x06, 0x08,
+ 0x0C, 0x10, 0x0B, 0x02, 0x04, 0x0A, 0x07, 0x1A,
+ 0x18, 0x0E, 0x03, 0x11, 0x12, 0x14, 0x19, 0x00 };
+
+unsigned char table_185[256] = {
+ 0xA5, 0xEE, 0x2E, 0x28, 0xA7, 0xAC, 0xD9, 0xB2,
+ 0x6E, 0x04, 0xB4, 0x03, 0xE8, 0x92, 0x5F, 0x4D,
+ 0x73, 0x20, 0x71, 0xE0, 0x43, 0x53, 0x3F, 0xF8,
+ 0x96, 0xA1, 0x24, 0x97, 0xAD, 0x7B, 0xE5, 0xE6,
+ 0xF2, 0xCE, 0xE3, 0x76, 0x2F, 0xA2, 0x48, 0x0E,
+ 0x4B, 0x4A, 0x8B, 0x5A, 0x81, 0x2C, 0xBF, 0xD7,
+ 0xFB, 0x7D, 0x4C, 0x16, 0xF4, 0x00, 0xF5, 0x40,
+ 0x64, 0x74, 0xA9, 0x37, 0x86, 0xD3, 0x1B, 0xCD,
+ 0xF1, 0x1A, 0x90, 0x9F, 0x54, 0x79, 0x29, 0xC3,
+ 0x77, 0x85, 0x02, 0xB1, 0x70, 0xFE, 0x5B, 0xDA,
+ 0x6B, 0x01, 0x0C, 0x07, 0xB8, 0x58, 0x47, 0x42,
+ 0x09, 0xE4, 0x27, 0xDD, 0xF3, 0x1E, 0x10, 0x9E,
+ 0x49, 0x30, 0x05, 0xBE, 0x59, 0xEB, 0xD2, 0xAA,
+ 0xC8, 0x9D, 0x8C, 0x5E, 0x14, 0x56, 0x8E, 0xF7,
+ 0x38, 0x55, 0x87, 0xA3, 0x5D, 0x41, 0x4F, 0x1F,
+ 0xF6, 0x0F, 0x57, 0x91, 0xAE, 0xBA, 0xB3, 0x95,
+ 0x9B, 0x69, 0xC1, 0x11, 0xD0, 0x25, 0x7F, 0x3B,
+ 0x62, 0xCF, 0xC0, 0xA0, 0xFC, 0xB6, 0x12, 0x6C,
+ 0xF0, 0x13, 0x93, 0xAB, 0xC6, 0x78, 0x6D, 0x88,
+ 0x22, 0x08, 0x2A, 0xE2, 0xB7, 0x65, 0x31, 0x3A,
+ 0xA6, 0x7C, 0xF9, 0xDC, 0xE7, 0xA4, 0xC9, 0x63,
+ 0xA8, 0x0B, 0xED, 0x50, 0x36, 0xD8, 0x3E, 0xB0,
+ 0x6A, 0x5C, 0x45, 0x4E, 0x23, 0x84, 0x34, 0x9A,
+ 0xCC, 0x3D, 0xB5, 0xEA, 0xDE, 0x75, 0xD6, 0xFF,
+ 0x6F, 0xC2, 0xDB, 0x8D, 0x7A, 0x1C, 0xE9, 0x61,
+ 0x0A, 0x1D, 0x32, 0x52, 0x3C, 0x19, 0xFA, 0xD1,
+ 0xD4, 0x68, 0xC7, 0x0D, 0x99, 0x83, 0xEF, 0x80,
+ 0x82, 0xBD, 0xD5, 0x7E, 0x39, 0x72, 0x51, 0xAF,
+ 0x8A, 0x2D, 0xB9, 0x89, 0xC4, 0x67, 0x35, 0xE1,
+ 0x44, 0x06, 0xEC, 0xCB, 0x8F, 0x17, 0xDF, 0x94,
+ 0x60, 0xCA, 0x26, 0xFD, 0x33, 0x46, 0x21, 0xBB,
+ 0x2B, 0xC5, 0x98, 0x18, 0x66, 0x15, 0x9C, 0xBC };
+
+unsigned char table_186[256] = {
+ 0xB7, 0xFA, 0x03, 0x7C, 0x76, 0x43, 0xA7, 0x15,
+ 0x4B, 0x4F, 0x04, 0xAA, 0x4E, 0xD2, 0x52, 0xC8,
+ 0x79, 0x16, 0xF6, 0x61, 0x01, 0x5D, 0xD6, 0x47,
+ 0xDE, 0xC5, 0x4D, 0x2F, 0xF5, 0x29, 0x21, 0xE6,
+ 0x97, 0x35, 0xDC, 0x0E, 0x8B, 0xF4, 0x0F, 0xBE,
+ 0x30, 0x07, 0x1D, 0x46, 0x75, 0xCE, 0x56, 0x42,
+ 0x28, 0x93, 0x84, 0x20, 0xA5, 0xC2, 0x87, 0x45,
+ 0x1C, 0x6B, 0x55, 0x06, 0xEB, 0xB0, 0xF9, 0x14,
+ 0x23, 0xF1, 0xFC, 0xD7, 0x98, 0xD1, 0xA4, 0xED,
+ 0x5B, 0xB1, 0x12, 0x7A, 0xD5, 0x5F, 0x53, 0x88,
+ 0x95, 0x71, 0xE7, 0x5C, 0xF8, 0x83, 0xC7, 0x49,
+ 0xDD, 0xDA, 0x0B, 0xC1, 0x70, 0xEC, 0x67, 0xE2,
+ 0xEA, 0x72, 0x4C, 0x92, 0xA6, 0xE5, 0x59, 0xA9,
+ 0x3C, 0xFE, 0x0A, 0x65, 0x6E, 0xF3, 0xA3, 0x22,
+ 0x24, 0x81, 0xF2, 0xCC, 0xD3, 0xA0, 0xDF, 0xDB,
+ 0xAB, 0x09, 0x13, 0x96, 0x36, 0x9C, 0xEE, 0xD4,
+ 0x33, 0x5E, 0x26, 0xAE, 0x48, 0x38, 0xFF, 0x08,
+ 0x1F, 0x6D, 0x02, 0xEF, 0x7E, 0x57, 0x2A, 0x8A,
+ 0xBA, 0x90, 0xAF, 0xA8, 0x37, 0x8E, 0x9B, 0xC0,
+ 0x69, 0x32, 0x86, 0xBD, 0x73, 0x6C, 0xB9, 0x31,
+ 0x66, 0xBF, 0x1B, 0x44, 0x9E, 0xB2, 0xD0, 0xE0,
+ 0xF0, 0x2C, 0x3F, 0xE1, 0x91, 0x18, 0x19, 0x50,
+ 0xCA, 0x8F, 0x54, 0xB5, 0x8D, 0x0C, 0x17, 0x39,
+ 0x8C, 0x00, 0x7F, 0x41, 0xE3, 0x2E, 0x1A, 0x9D,
+ 0x27, 0xA1, 0x10, 0x34, 0x1E, 0x3A, 0x60, 0x77,
+ 0xBB, 0xB6, 0x0D, 0x4A, 0x3E, 0x6A, 0xB4, 0xA2,
+ 0xB3, 0xFD, 0xCD, 0x80, 0x51, 0xAD, 0xCF, 0xBC,
+ 0x40, 0x74, 0x6F, 0x68, 0x2B, 0xC3, 0xF7, 0x63,
+ 0xB8, 0x25, 0xC4, 0x62, 0xE9, 0xFB, 0x58, 0x85,
+ 0x78, 0xCB, 0x9A, 0x3D, 0xE4, 0xC9, 0x89, 0x2D,
+ 0x64, 0x82, 0xC6, 0x05, 0xD8, 0xAC, 0x99, 0x9F,
+ 0x11, 0x3B, 0x94, 0xE8, 0x7D, 0x7B, 0xD9, 0x5A };
+
+unsigned char table_187[32] = {
+ 0x0F, 0x04, 0x1D, 0x1B, 0x15, 0x10, 0x01, 0x0B,
+ 0x00, 0x17, 0x13, 0x07, 0x1E, 0x1F, 0x08, 0x0A,
+ 0x19, 0x09, 0x05, 0x06, 0x0C, 0x1A, 0x14, 0x16,
+ 0x0E, 0x18, 0x03, 0x1C, 0x12, 0x11, 0x0D, 0x02 };
+
+struct yahoo_fn yahoo_fntable[5][96] =
+ {{{ IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 },
+ { IDENT, 0, 0 }},
+ {{ MULADD, 0x36056CD7, 0x4387 },
+ { LOOKUP, (long)table_0, 0 },
+ { LOOKUP, (long)table_1, 0 },
+ { BITFLD, (long)table_2, 0 },
+ { LOOKUP, (long)table_3, 0 },
+ { BITFLD, (long)table_4, 0 },
+ { MULADD, 0x4ABB534D, 0x3769 },
+ { XOR, 0x1D242DA5, 0 },
+ { MULADD, 0x3C23132D, 0x339B },
+ { XOR, 0x0191265C, 0 },
+ { XOR, 0x3DB979DB, 0 },
+ { LOOKUP, (long)table_5, 0 },
+ { XOR, 0x1A550E1E, 0 },
+ { XOR, 0x2F140A2D, 0 },
+ { MULADD, 0x7C466A4B, 0x29BF },
+ { XOR, 0x2D3F30D3, 0 },
+ { MULADD, 0x7E823B21, 0x6BB3 },
+ { BITFLD, (long)table_6, 0 },
+ { LOOKUP, (long)table_7, 0 },
+ { BITFLD, (long)table_8, 0 },
+ { LOOKUP, (long)table_9, 0 },
+ { BITFLD, (long)table_10, 0 },
+ { LOOKUP, (long)table_11, 0 },
+ { BITFLD, (long)table_12, 0 },
+ { LOOKUP, (long)table_13, 0 },
+ { BITFLD, (long)table_14, 0 },
+ { MULADD, 0x5B756AB9, 0x7E9B },
+ { LOOKUP, (long)table_15, 0 },
+ { XOR, 0x1D1C4911, 0 },
+ { LOOKUP, (long)table_16, 0 },
+ { LOOKUP, (long)table_17, 0 },
+ { XOR, 0x46BD7771, 0 },
+ { XOR, 0x51AE2B42, 0 },
+ { MULADD, 0x2417591B, 0x177B },
+ { MULADD, 0x57F27C5F, 0x2433 },
+ { LOOKUP, (long)table_18, 0 },
+ { LOOKUP, (long)table_19, 0 },
+ { XOR, 0x71422261, 0 },
+ { BITFLD, (long)table_20, 0 },
+ { MULADD, 0x58E937F9, 0x1075 },
+ { LOOKUP, (long)table_21, 0 },
+ { BITFLD, (long)table_22, 0 },
+ { LOOKUP, (long)table_23, 0 },
+ { LOOKUP, (long)table_24, 0 },
+ { MULADD, 0x0B4C3D13, 0x1597 },
+ { BITFLD, (long)table_25, 0 },
+ { XOR, 0x0FE07D38, 0 },
+ { MULADD, 0x689B4017, 0x3CFB },
+ { BITFLD, (long)table_26, 0 },
+ { LOOKUP, (long)table_27, 0 },
+ { XOR, 0x35413DF3, 0 },
+ { MULADD, 0x05B611AB, 0x570B },
+ { MULADD, 0x0DA5334F, 0x3AC7 },
+ { XOR, 0x47706008, 0 },
+ { BITFLD, (long)table_28, 0 },
+ { LOOKUP, (long)table_29, 0 },
+ { BITFLD, (long)table_30, 0 },
+ { XOR, 0x57611B36, 0 },
+ { MULADD, 0x314C2CD1, 0x2B5B },
+ { XOR, 0x1EF33946, 0 },
+ { MULADD, 0x28EA041F, 0x638F },
+ { LOOKUP, (long)table_31, 0 },
+ { LOOKUP, (long)table_32, 0 },
+ { LOOKUP, (long)table_33, 0 },
+ { MULADD, 0x511537CB, 0x7135 },
+ { MULADD, 0x1CF71007, 0x5E17 },
+ { XOR, 0x583D4BCF, 0 },
+ { LOOKUP, (long)table_34, 0 },
+ { XOR, 0x373E6856, 0 },
+ { MULADD, 0x4D595519, 0x1A7D },
+ { LOOKUP, (long)table_35, 0 },
+ { LOOKUP, (long)table_36, 0 },
+ { XOR, 0x0E2A36A7, 0 },
+ { LOOKUP, (long)table_37, 0 },
+ { LOOKUP, (long)table_38, 0 },
+ { BITFLD, (long)table_39, 0 },
+ { BITFLD, (long)table_40, 0 },
+ { XOR, 0x53F3604F, 0 },
+ { BITFLD, (long)table_41, 0 },
+ { BITFLD, (long)table_42, 0 },
+ { MULADD, 0x1EDC0BA3, 0x7531 },
+ { LOOKUP, (long)table_43, 0 },
+ { XOR, 0x10DF1038, 0 },
+ { BITFLD, (long)table_44, 0 },
+ { LOOKUP, (long)table_45, 0 },
+ { XOR, 0x4EDE0CAC, 0 },
+ { MULADD, 0x2F076EEB, 0x5BCF },
+ { XOR, 0x6D86030F, 0 },
+ { XOR, 0x3F331713, 0 },
+ { LOOKUP, (long)table_46, 0 },
+ { MULADD, 0x41CD726F, 0x3F79 },
+ { BITFLD, (long)table_47, 0 },
+ { XOR, 0x0ECE0054, 0 },
+ { MULADD, 0x19B32B03, 0x4AD1 },
+ { BITFLD, (long)table_48, 0 },
+ { BITFLD, (long)table_49, 0 }},
+ {{ MULADD, 0x39731111, 0x419B },
+ { XOR, 0x54F7757A, 0 },
+ { BITFLD, (long)table_50, 0 },
+ { BITFLD, (long)table_51, 0 },
+ { LOOKUP, (long)table_52, 0 },
+ { LOOKUP, (long)table_53, 0 },
+ { MULADD, 0x3CC0256B, 0x7CE7 },
+ { XOR, 0x79991847, 0 },
+ { MULADD, 0x228F7FB5, 0x472D },
+ { MULADD, 0x32DA290B, 0x7745 },
+ { XOR, 0x7A28180D, 0 },
+ { BITFLD, (long)table_54, 0 },
+ { BITFLD, (long)table_55, 0 },
+ { MULADD, 0x5C814F8B, 0x227F },
+ { LOOKUP, (long)table_56, 0 },
+ { MULADD, 0x0B496F6D, 0x412D },
+ { XOR, 0x6F4B62DA, 0 },
+ { LOOKUP, (long)table_57, 0 },
+ { XOR, 0x64973977, 0 },
+ { LOOKUP, (long)table_58, 0 },
+ { LOOKUP, (long)table_59, 0 },
+ { BITFLD, (long)table_60, 0 },
+ { LOOKUP, (long)table_61, 0 },
+ { LOOKUP, (long)table_62, 0 },
+ { XOR, 0x6DD14C92, 0 },
+ { LOOKUP, (long)table_63, 0 },
+ { BITFLD, (long)table_64, 0 },
+ { BITFLD, (long)table_65, 0 },
+ { BITFLD, (long)table_66, 0 },
+ { LOOKUP, (long)table_67, 0 },
+ { XOR, 0x5E6324D8, 0 },
+ { LOOKUP, (long)table_68, 0 },
+ { LOOKUP, (long)table_69, 0 },
+ { LOOKUP, (long)table_70, 0 },
+ { BITFLD, (long)table_71, 0 },
+ { XOR, 0x62745ED0, 0 },
+ { MULADD, 0x102C215B, 0x0581 },
+ { LOOKUP, (long)table_72, 0 },
+ { LOOKUP, (long)table_73, 0 },
+ { LOOKUP, (long)table_74, 0 },
+ { MULADD, 0x19511111, 0x12C1 },
+ { LOOKUP, (long)table_75, 0 },
+ { MULADD, 0x2A6E2953, 0x6977 },
+ { LOOKUP, (long)table_76, 0 },
+ { XOR, 0x55CD5445, 0 },
+ { BITFLD, (long)table_77, 0 },
+ { BITFLD, (long)table_78, 0 },
+ { MULADD, 0x646C21EB, 0x43E5 },
+ { XOR, 0x71DC4898, 0 },
+ { XOR, 0x167519CB, 0 },
+ { XOR, 0x6D3158F8, 0 },
+ { XOR, 0x7EA95BEA, 0 },
+ { BITFLD, (long)table_79, 0 },
+ { XOR, 0x47377587, 0 },
+ { XOR, 0x2D8B6E8F, 0 },
+ { MULADD, 0x5E6105DB, 0x1605 },
+ { XOR, 0x65B543C8, 0 },
+ { LOOKUP, (long)table_80, 0 },
+ { BITFLD, (long)table_81, 0 },
+ { MULADD, 0x48AF73CB, 0x0A67 },
+ { XOR, 0x4FB96154, 0 },
+ { LOOKUP, (long)table_82, 0 },
+ { BITFLD, (long)table_83, 0 },
+ { XOR, 0x622C4954, 0 },
+ { BITFLD, (long)table_84, 0 },
+ { XOR, 0x20D220F3, 0 },
+ { XOR, 0x361D4F0D, 0 },
+ { XOR, 0x2B2000D1, 0 },
+ { XOR, 0x6FB8593E, 0 },
+ { LOOKUP, (long)table_85, 0 },
+ { BITFLD, (long)table_86, 0 },
+ { XOR, 0x2B7F7DFC, 0 },
+ { MULADD, 0x5FC41A57, 0x0693 },
+ { MULADD, 0x17154387, 0x2489 },
+ { BITFLD, (long)table_87, 0 },
+ { BITFLD, (long)table_88, 0 },
+ { BITFLD, (long)table_89, 0 },
+ { LOOKUP, (long)table_90, 0 },
+ { XOR, 0x7E221470, 0 },
+ { XOR, 0x7A600061, 0 },
+ { BITFLD, (long)table_91, 0 },
+ { BITFLD, (long)table_92, 0 },
+ { LOOKUP, (long)table_93, 0 },
+ { BITFLD, (long)table_94, 0 },
+ { MULADD, 0x00E813A5, 0x2CE5 },
+ { MULADD, 0x3D707E25, 0x3827 },
+ { MULADD, 0x77A53E07, 0x6A5F },
+ { BITFLD, (long)table_95, 0 },
+ { LOOKUP, (long)table_96, 0 },
+ { LOOKUP, (long)table_97, 0 },
+ { XOR, 0x43A73788, 0 },
+ { LOOKUP, (long)table_98, 0 },
+ { BITFLD, (long)table_99, 0 },
+ { LOOKUP, (long)table_100, 0 },
+ { XOR, 0x55F4606B, 0 },
+ { BITFLD, (long)table_101, 0 }},
+ {{ BITFLD, (long)table_102, 0 },
+ { MULADD, 0x32CA58E3, 0x04F9 },
+ { XOR, 0x11756B30, 0 },
+ { MULADD, 0x218B2569, 0x5DB1 },
+ { XOR, 0x77D64B90, 0 },
+ { BITFLD, (long)table_103, 0 },
+ { LOOKUP, (long)table_104, 0 },
+ { MULADD, 0x7D1428CB, 0x3D },
+ { XOR, 0x6F872C49, 0 },
+ { XOR, 0x2E484655, 0 },
+ { MULADD, 0x1E3349F7, 0x41F5 },
+ { LOOKUP, (long)table_105, 0 },
+ { BITFLD, (long)table_106, 0 },
+ { XOR, 0x61640311, 0 },
+ { BITFLD, (long)table_107, 0 },
+ { LOOKUP, (long)table_108, 0 },
+ { LOOKUP, (long)table_109, 0 },
+ { LOOKUP, (long)table_110, 0 },
+ { XOR, 0x007044D3, 0 },
+ { BITFLD, (long)table_111, 0 },
+ { MULADD, 0x5C221625, 0x576F },
+ { LOOKUP, (long)table_112, 0 },
+ { LOOKUP, (long)table_113, 0 },
+ { XOR, 0x2D406BB1, 0 },
+ { MULADD, 0x680B1F17, 0x12CD },
+ { BITFLD, (long)table_114, 0 },
+ { MULADD, 0x12564D55, 0x32B9 },
+ { MULADD, 0x21A67897, 0x6BAB },
+ { LOOKUP, (long)table_115, 0 },
+ { MULADD, 0x06405119, 0x7143 },
+ { XOR, 0x351D01ED, 0 },
+ { MULADD, 0x46356F6B, 0x0A49 },
+ { MULADD, 0x32C77969, 0x72F3 },
+ { BITFLD, (long)table_116, 0 },
+ { LOOKUP, (long)table_117, 0 },
+ { LOOKUP, (long)table_118, 0 },
+ { BITFLD, (long)table_119, 0 },
+ { LOOKUP, (long)table_120, 0 },
+ { BITFLD, (long)table_121, 0 },
+ { MULADD, 0x74D52C55, 0x5F43 },
+ { XOR, 0x26201CA8, 0 },
+ { XOR, 0x7AEB3255, 0 },
+ { LOOKUP, (long)table_122, 0 },
+ { MULADD, 0x578F1047, 0x640B },
+ { LOOKUP, (long)table_123, 0 },
+ { LOOKUP, (long)table_124, 0 },
+ { BITFLD, (long)table_125, 0 },
+ { BITFLD, (long)table_126, 0 },
+ { XOR, 0x4A1352CF, 0 },
+ { MULADD, 0x4BFB6EF3, 0x704F },
+ { MULADD, 0x1B4C7FE7, 0x5637 },
+ { MULADD, 0x04091A3B, 0x4917 },
+ { XOR, 0x270C2F52, 0 },
+ { LOOKUP, (long)table_127, 0 },
+ { BITFLD, (long)table_128, 0 },
+ { LOOKUP, (long)table_129, 0 },
+ { BITFLD, (long)table_130, 0 },
+ { MULADD, 0x127549D5, 0x579B },
+ { MULADD, 0x0AB54121, 0x7A47 },
+ { BITFLD, (long)table_131, 0 },
+ { XOR, 0x751E6E49, 0 },
+ { LOOKUP, (long)table_132, 0 },
+ { LOOKUP, (long)table_133, 0 },
+ { XOR, 0x670C3F74, 0 },
+ { MULADD, 0x6B080851, 0x7E8B },
+ { XOR, 0x71CD789E, 0 },
+ { XOR, 0x3EB20B7B, 0 },
+ { BITFLD, (long)table_134, 0 },
+ { LOOKUP, (long)table_135, 0 },
+ { MULADD, 0x58A67753, 0x272B },
+ { MULADD, 0x1AB54AD7, 0x4D33 },
+ { MULADD, 0x07D30A45, 0x0569 },
+ { MULADD, 0x737616BF, 0x70C7 },
+ { LOOKUP, (long)table_136, 0 },
+ { MULADD, 0x45C4485D, 0x2063 },
+ { BITFLD, (long)table_137, 0 },
+ { XOR, 0x2598043D, 0 },
+ { MULADD, 0x223A4FE3, 0x49A7 },
+ { XOR, 0x1EED619F, 0 },
+ { BITFLD, (long)table_138, 0 },
+ { XOR, 0x6F477561, 0 },
+ { BITFLD, (long)table_139, 0 },
+ { BITFLD, (long)table_140, 0 },
+ { LOOKUP, (long)table_141, 0 },
+ { MULADD, 0x4BC13C4F, 0x45C1 },
+ { XOR, 0x3B547BFB, 0 },
+ { LOOKUP, (long)table_142, 0 },
+ { MULADD, 0x71406AB3, 0x7A5F },
+ { XOR, 0x2F1467E9, 0 },
+ { MULADD, 0x009366D1, 0x22D1 },
+ { MULADD, 0x587D1B75, 0x2CA5 },
+ { MULADD, 0x213A4BE7, 0x4499 },
+ { MULADD, 0x62653E89, 0x2D5D },
+ { BITFLD, (long)table_143, 0 },
+ { MULADD, 0x4F5F3257, 0x444F },
+ { MULADD, 0x4C0E2B2B, 0x19D3 }},
+ {{ MULADD, 0x3F867B35, 0x7B3B },
+ { MULADD, 0x32D25CB1, 0x3D6D },
+ { BITFLD, (long)table_144, 0 },
+ { MULADD, 0x50FA1C51, 0x5F4F },
+ { LOOKUP, (long)table_145, 0 },
+ { XOR, 0x05FE7AF1, 0 },
+ { MULADD, 0x14067C29, 0x10C5 },
+ { LOOKUP, (long)table_146, 0 },
+ { MULADD, 0x4A5558C5, 0x271F },
+ { XOR, 0x3C0861B1, 0 },
+ { BITFLD, (long)table_147, 0 },
+ { LOOKUP, (long)table_148, 0 },
+ { MULADD, 0x18837C9D, 0x6335 },
+ { BITFLD, (long)table_149, 0 },
+ { XOR, 0x7DAB5033, 0 },
+ { LOOKUP, (long)table_150, 0 },
+ { MULADD, 0x03B87321, 0x7225 },
+ { XOR, 0x7F906745, 0 },
+ { LOOKUP, (long)table_151, 0 },
+ { BITFLD, (long)table_152, 0 },
+ { XOR, 0x21C46C2C, 0 },
+ { MULADD, 0x2B36757D, 0x028D },
+ { BITFLD, (long)table_153, 0 },
+ { LOOKUP, (long)table_154, 0 },
+ { XOR, 0x106B4A85, 0 },
+ { XOR, 0x17640F11, 0 },
+ { LOOKUP, (long)table_155, 0 },
+ { XOR, 0x69E60486, 0 },
+ { LOOKUP, (long)table_156, 0 },
+ { MULADD, 0x3782017D, 0x05BF },
+ { BITFLD, (long)table_157, 0 },
+ { LOOKUP, (long)table_158, 0 },
+ { XOR, 0x6BCA53B0, 0 },
+ { LOOKUP, (long)table_159, 0 },
+ { LOOKUP, (long)table_160, 0 },
+ { LOOKUP, (long)table_161, 0 },
+ { LOOKUP, (long)table_162, 0 },
+ { XOR, 0x0B8236E3, 0 },
+ { BITFLD, (long)table_163, 0 },
+ { MULADD, 0x5EE51C43, 0x4553 },
+ { BITFLD, (long)table_164, 0 },
+ { LOOKUP, (long)table_165, 0 },
+ { LOOKUP, (long)table_166, 0 },
+ { LOOKUP, (long)table_167, 0 },
+ { MULADD, 0x42B14C6F, 0x5531 },
+ { XOR, 0x4A2548E8, 0 },
+ { MULADD, 0x5C071D85, 0x2437 },
+ { LOOKUP, (long)table_168, 0 },
+ { MULADD, 0x29195861, 0x108B },
+ { XOR, 0x24012258, 0 },
+ { LOOKUP, (long)table_169, 0 },
+ { XOR, 0x63CC2377, 0 },
+ { XOR, 0x08D04B59, 0 },
+ { MULADD, 0x3FD30CF5, 0x7027 },
+ { XOR, 0x7C3E0478, 0 },
+ { MULADD, 0x457776B7, 0x24B3 },
+ { XOR, 0x086652BC, 0 },
+ { MULADD, 0x302F5B13, 0x371D },
+ { LOOKUP, (long)table_170, 0 },
+ { MULADD, 0x58692D47, 0x0671 },
+ { XOR, 0x6601178E, 0 },
+ { MULADD, 0x0F195B9B, 0x1369 },
+ { XOR, 0x07BA21D8, 0 },
+ { BITFLD, (long)table_171, 0 },
+ { BITFLD, (long)table_172, 0 },
+ { XOR, 0x13AC3D21, 0 },
+ { MULADD, 0x5BCF3275, 0x6E1B },
+ { MULADD, 0x62725C5B, 0x16B9 },
+ { MULADD, 0x5B950FDF, 0x2D35 },
+ { BITFLD, (long)table_173, 0 },
+ { BITFLD, (long)table_174, 0 },
+ { MULADD, 0x73BA5335, 0x1C13 },
+ { BITFLD, (long)table_175, 0 },
+ { BITFLD, (long)table_176, 0 },
+ { XOR, 0x3E144154, 0 },
+ { MULADD, 0x4EED7B27, 0x38AB },
+ { LOOKUP, (long)table_177, 0 },
+ { MULADD, 0x627C7E0F, 0x7F01 },
+ { MULADD, 0x5D7E1F73, 0x2C0F },
+ { LOOKUP, (long)table_178, 0 },
+ { MULADD, 0x55C9525F, 0x4659 },
+ { XOR, 0x3765334C, 0 },
+ { MULADD, 0x5DF66DDF, 0x7C25 },
+ { LOOKUP, (long)table_179, 0 },
+ { LOOKUP, (long)table_180, 0 },
+ { XOR, 0x16AE5776, 0 },
+ { LOOKUP, (long)table_181, 0 },
+ { LOOKUP, (long)table_182, 0 },
+ { BITFLD, (long)table_183, 0 },
+ { BITFLD, (long)table_184, 0 },
+ { LOOKUP, (long)table_185, 0 },
+ { MULADD, 0x4392327B, 0x7E0D },
+ { LOOKUP, (long)table_186, 0 },
+ { MULADD, 0x3D8B0CB5, 0x640D },
+ { MULADD, 0x32865601, 0x4D43 },
+ { BITFLD, (long)table_187, 0 }}};
+
+#define A( x ) (( x ) & 0xFF )
+#define B( x ) (( x ) >> 8 & 0xFF )
+#define C( x ) (( x ) >> 16 & 0xFF )
+#define D( x ) (( x ) >> 24 & 0xFF )
+
+int yahoo_xfrm( int table, int depth, int seed )
+{
+ struct yahoo_fn *xfrm;
+ int i, j, z;
+ unsigned int n = seed;
+ unsigned char *arg;
+
+ for( i = 0; i < depth; i++ )
+ {
+ xfrm = &yahoo_fntable[table][n % 96];
+ switch( xfrm->type )
+ {
+ case IDENT:
+ return seed;
+ case XOR:
+ seed ^= xfrm->arg1;
+ break;
+ case MULADD:
+ seed = seed * xfrm->arg1 + xfrm->arg2;
+ break;
+ case LOOKUP:
+ arg = (unsigned char *)xfrm->arg1;
+ seed = arg[A( seed )] | arg[B( seed )] << 8 | arg[C( seed )] << 16
+ | arg[D( seed )] << 24;
+ break;
+ case BITFLD:
+ arg = (unsigned char *)xfrm->arg1;
+ for( j = 0, z = 0; j < 32; j++ )
+ z = ((( seed >> j ) & 1 ) << arg[j] ) | ( ~( 1 << arg[j] ) & z );
+ seed = z;
+ break;
+ }
+ if( depth - i == 1 )
+ return seed;
+ z = (((((( A( seed ) * 0x9E3779B1 ) ^ B( seed )) * 0x9E3779B1 )
+ ^ C( seed )) * 0x9E3779B1 ) ^ D( seed )) * 0x9E3779B1;
+ n = (((( z ^ ( z >> 8 )) >> 16 ) ^ z ) ^ ( z >> 8 )) & 0xFF;
+ seed *= 0x00010DCD;
+ }
+ return seed;
+}
diff --git a/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_fn.h b/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_fn.h
new file mode 100644
index 0000000..ac1c569
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_fn.h
@@ -0,0 +1,33 @@
+/*
+ * libyahoo2 - originally from gaim patches by Amatus
+ *
+ * Copyright (C) 2003-2004
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define IDENT 1 /* identify function */
+#define XOR 2 /* xor with arg1 */
+#define MULADD 3 /* multipy by arg1 then add arg2 */
+#define LOOKUP 4 /* lookup each byte in the table pointed to by arg1 */
+#define BITFLD 5 /* reorder bits according to table pointed to by arg1 */
+
+struct yahoo_fn
+{
+ int type; /* type of transform */
+ int arg1, arg2; /* arguments */
+};
+
+int yahoo_xfrm( int table, int depth, int seed );
diff --git a/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_httplib.c b/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_httplib.c
new file mode 100644
index 0000000..60325c6
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_httplib.c
@@ -0,0 +1,451 @@
+/*
+ * libyahoo2: yahoo_httplib.c
+ *
+ * Copyright (C) 2002-2004, Philip S Tellis <philip.tellis AT gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if STDC_HEADERS
+# include <string.h>
+#else
+# if !HAVE_STRCHR
+# define strchr index
+# define strrchr rindex
+# endif
+char *strchr (), *strrchr ();
+# if !HAVE_MEMCPY
+# define memcpy(d, s, n) bcopy ((s), (d), (n))
+# define memmove(d, s, n) bcopy ((s), (d), (n))
+# endif
+#endif
+
+
+#include <errno.h>
+
+/* special check for MSVC compiler */
+#ifndef _MSC_VER
+#ifndef __GNUC__
+ #include <unistd.h>
+#endif
+#endif
+
+#include <ctype.h>
+#include "yahoo2.h"
+#include "yahoo2_callbacks.h"
+#include "yahoo_httplib.h"
+#include "yahoo_util.h"
+
+#include "yahoo_debug.h"
+
+#ifdef USE_STRUCT_CALLBACKS
+extern struct yahoo_callbacks *yc;
+#define YAHOO_CALLBACK(x) yc->x
+#else
+#define YAHOO_CALLBACK(x) x
+#endif
+
+extern enum yahoo_log_level log_level;
+
+int yahoo_tcp_readline(char *ptr, int maxlen, int fd)
+{
+ int n, rc;
+ char c;
+
+ for (n = 1; n < maxlen; n++) {
+
+ do {
+ rc = read(fd, &c, 1);
+ } while(rc == -1 && (errno == EINTR || errno == EAGAIN)); /* this is bad - it should be done asynchronously */
+
+ if (rc == 1) {
+ if(c == '\r') /* get rid of \r */
+ continue;
+ *ptr = c;
+ if (c == '\n')
+ break;
+ ptr++;
+ } else if (rc == 0) {
+ if (n == 1)
+ return (0); /* EOF, no data */
+ else
+ break; /* EOF, w/ data */
+ } else {
+ return -1;
+ }
+ }
+
+ *ptr = 0;
+ return (n);
+}
+
+static int url_to_host_port_path(const char *url,
+ char *host, int *port, char *path)
+{
+ char *urlcopy=NULL;
+ char *slash=NULL;
+ char *colon=NULL;
+
+ /*
+ * http://hostname
+ * http://hostname/
+ * http://hostname/path
+ * http://hostname/path:foo
+ * http://hostname:port
+ * http://hostname:port/
+ * http://hostname:port/path
+ * http://hostname:port/path:foo
+ */
+
+ if(strstr(url, "http://") == url) {
+ urlcopy = strdup(url+7);
+ } else {
+ WARNING(("Weird url - unknown protocol: %s", url));
+ return 0;
+ }
+
+ slash = strchr(urlcopy, '/');
+ colon = strchr(urlcopy, ':');
+
+ if(!colon || (slash && slash < colon)) {
+ *port = 80;
+ } else {
+ *colon = 0;
+ *port = atoi(colon+1);
+ }
+
+ if(!slash) {
+ strcpy(path, "/");
+ } else {
+ strcpy(path, slash);
+ *slash = 0;
+ }
+
+ strcpy(host, urlcopy);
+
+ FREE(urlcopy);
+
+ return 1;
+}
+
+static int isurlchar(unsigned char c)
+{
+ return (isalnum(c) || '-' == c || '_' == c);
+}
+
+char *yahoo_urlencode(const char *instr)
+{
+ int ipos=0, bpos=0;
+ char *str = NULL;
+ int len = strlen(instr);
+
+ if(!(str = y_new(char, 3*len + 1) ))
+ return "";
+
+ while(instr[ipos]) {
+ while(isurlchar(instr[ipos]))
+ str[bpos++] = instr[ipos++];
+ if(!instr[ipos])
+ break;
+
+ snprintf(&str[bpos], 4, "%%%.2x", instr[ipos]);
+ bpos+=3;
+ ipos++;
+ }
+ str[bpos]='\0';
+
+ /* free extra alloc'ed mem. */
+ len = strlen(str);
+ str = y_renew(char, str, len+1);
+
+ return (str);
+}
+
+char *yahoo_urldecode(const char *instr)
+{
+ int ipos=0, bpos=0;
+ char *str = NULL;
+ char entity[3]={0,0,0};
+ unsigned dec;
+ int len = strlen(instr);
+
+ if(!(str = y_new(char, len+1) ))
+ return "";
+
+ while(instr[ipos]) {
+ while(instr[ipos] && instr[ipos]!='%')
+ if(instr[ipos]=='+') {
+ str[bpos++]=' ';
+ ipos++;
+ } else
+ str[bpos++] = instr[ipos++];
+ if(!instr[ipos])
+ break;
+
+ if(instr[ipos+1] && instr[ipos+2]) {
+ ipos++;
+ entity[0]=instr[ipos++];
+ entity[1]=instr[ipos++];
+ sscanf(entity, "%2x", &dec);
+ str[bpos++] = (char)dec;
+ } else {
+ str[bpos++] = instr[ipos++];
+ }
+ }
+ str[bpos]='\0';
+
+ /* free extra alloc'ed mem. */
+ len = strlen(str);
+ str = y_renew(char, str, len+1);
+
+ return (str);
+}
+
+char *yahoo_xmldecode(const char *instr)
+{
+ int ipos=0, bpos=0, epos=0;
+ char *str = NULL;
+ char entity[4]={0,0,0,0};
+ char *entitymap[5][2]={
+ {"amp;", "&"},
+ {"quot;", "\""},
+ {"lt;", "<"},
+ {"gt;", "<"},
+ {"nbsp;", " "}
+ };
+ unsigned dec;
+ int len = strlen(instr);
+
+ if(!(str = y_new(char, len+1) ))
+ return "";
+
+ while(instr[ipos]) {
+ while(instr[ipos] && instr[ipos]!='&')
+ if(instr[ipos]=='+') {
+ str[bpos++]=' ';
+ ipos++;
+ } else
+ str[bpos++] = instr[ipos++];
+ if(!instr[ipos] || !instr[ipos+1])
+ break;
+ ipos++;
+
+ if(instr[ipos] == '#') {
+ ipos++;
+ epos=0;
+ while(instr[ipos] != ';')
+ entity[epos++]=instr[ipos++];
+ sscanf(entity, "%u", &dec);
+ str[bpos++] = (char)dec;
+ ipos++;
+ } else {
+ int i;
+ for (i=0; i<5; i++)
+ if(!strncmp(instr+ipos, entitymap[i][0],
+ strlen(entitymap[i][0]))) {
+ str[bpos++] = entitymap[i][1][0];
+ ipos += strlen(entitymap[i][0]);
+ break;
+ }
+ }
+ }
+ str[bpos]='\0';
+
+ /* free extra alloc'ed mem. */
+ len = strlen(str);
+ str = y_renew(char, str, len+1);
+
+ return (str);
+}
+
+typedef void (*http_connected)(int id, int fd, int error);
+
+struct callback_data {
+ int id;
+ yahoo_get_fd_callback callback;
+ char *request;
+ void *user_data;
+};
+
+static void connect_complete(int fd, int error, void *data)
+{
+ struct callback_data *ccd = data;
+ if(error == 0 && fd > 0)
+ write(fd, ccd->request, strlen(ccd->request));
+ FREE(ccd->request);
+ ccd->callback(ccd->id, fd, error, ccd->user_data);
+ FREE(ccd);
+}
+
+static void yahoo_send_http_request(int id, char *host, int port, char *request,
+ yahoo_get_fd_callback callback, void *data)
+{
+ struct callback_data *ccd=y_new0(struct callback_data, 1);
+ ccd->callback = callback;
+ ccd->id = id;
+ ccd->request = strdup(request);
+ ccd->user_data = data;
+
+ YAHOO_CALLBACK(ext_yahoo_connect_async)(id, host, port, YAHOO_CONNECTION_FT, connect_complete, ccd);
+}
+
+void yahoo_http_post(int id, const char *url, const char *cookies, long content_length,
+ yahoo_get_fd_callback callback, void *data)
+{
+ char host[255];
+ int port = 80;
+ char path[255];
+ char ck[2048];
+ char buff[4096];
+
+ if(!url_to_host_port_path(url, host, &port, path))
+ return;
+
+ if (cookies == NULL)
+ ck[0] = '\0';
+ else
+ snprintf(ck, sizeof(ck), "Cookie: %s\r\n", cookies);
+
+ snprintf(buff, sizeof(buff),
+ "POST %s HTTP/1.0\r\n"
+ "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\n"
+ "Pragma: no-cache\r\n"
+ "Host: %s:%d\r\n"
+ "Content-Length: %ld\r\n"
+ "%s"
+ "\r\n",
+ path,
+ host, port,content_length,
+ ck);
+
+ yahoo_send_http_request(id, host, port, buff, callback, data);
+}
+
+void yahoo_http_get(int id, const char *url, const char *cookies,
+ yahoo_get_fd_callback callback, void *data)
+{
+ char host[255];
+ int port = 80;
+ char path[255];
+ char ck[2048];
+ char buff[4096];
+
+ if(!url_to_host_port_path(url, host, &port, path))
+ return;
+
+ if (cookies == NULL)
+ ck[0] = '\0';
+ else
+ snprintf(ck, sizeof(ck), "Cookie: %s\r\n", cookies);
+
+ snprintf(buff, sizeof(buff),
+ "GET %s HTTP/1.0\r\n"
+ "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\n"
+ "Pragma: no-cache\r\n"
+ "Host: %s\r\n"
+ "%s"
+ "\r\n",
+ path, host, ck);
+
+ yahoo_send_http_request(id, host, port, buff, callback, data);
+}
+
+struct url_data {
+ yahoo_get_url_handle_callback callback;
+ void *user_data;
+};
+
+static void yahoo_got_url_fd(int id, int fd, int error, void *data)
+{
+ char *tmp=NULL;
+ char buff[1024];
+ unsigned long filesize=0;
+ char *filename=NULL;
+ int n;
+
+ struct url_data *ud = data;
+
+ if(error || fd < 0) {
+ ud->callback(id, fd, error, filename, filesize, ud->user_data);
+ FREE(ud);
+ return;
+ }
+
+ while((n=yahoo_tcp_readline(buff, sizeof(buff), fd)) > 0) {
+ LOG(("Read:%s:\n", buff));
+ if(!strcmp(buff, ""))
+ break;
+
+ if( !strncasecmp(buff, "Content-length:",
+ strlen("Content-length:")) ) {
+ tmp = strrchr(buff, ' ');
+ if(tmp)
+ filesize = atol(tmp);
+ }
+
+ if( !strncasecmp(buff, "Content-disposition:",
+ strlen("Content-disposition:")) ) {
+ tmp = strstr(buff, "name=");
+ if(tmp) {
+ tmp+=strlen("name=");
+ if(tmp[0] == '"') {
+ char *tmp2;
+ tmp++;
+ tmp2 = strchr(tmp, '"');
+ if(tmp2)
+ *tmp2 = '\0';
+ } else {
+ char *tmp2;
+ tmp2 = strchr(tmp, ';');
+ if(!tmp2)
+ tmp2 = strchr(tmp, '\r');
+ if(!tmp2)
+ tmp2 = strchr(tmp, '\n');
+ if(tmp2)
+ *tmp2 = '\0';
+ }
+
+ filename = strdup(tmp);
+ }
+ }
+ }
+
+ LOG(("n == %d\n", n));
+ LOG(("Calling callback, filename:%s, size: %ld\n", filename, filesize));
+ ud->callback(id, fd, error, filename, filesize, ud->user_data);
+ FREE(ud);
+ FREE(filename);
+}
+
+void yahoo_get_url_fd(int id, const char *url, const struct yahoo_data *yd,
+ yahoo_get_url_handle_callback callback, void *data)
+{
+ char buff[1024];
+ struct url_data *ud = y_new0(struct url_data, 1);
+ //snprintf(buff, sizeof(buff), "Y=%s; T=%s", yd->cookie_y, yd->cookie_t);
+ buff[0]='\0'; /*don't send them our cookies!! */
+ ud->callback = callback;
+ ud->user_data = data;
+ yahoo_http_get(id, url, buff, yahoo_got_url_fd, ud);
+}
+
diff --git a/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_httplib.h b/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_httplib.h
new file mode 100644
index 0000000..5a6c247
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_httplib.h
@@ -0,0 +1,48 @@
+/*
+ * libyahoo2: yahoo_httplib.h
+ *
+ * Copyright (C) 2002-2004, Philip S Tellis <philip.tellis AT gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 YAHOO_HTTPLIB_H
+#define YAHOO_HTTPLIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "yahoo2_types.h"
+
+char *yahoo_urlencode(const char *instr);
+char *yahoo_urldecode(const char *instr);
+char *yahoo_xmldecode(const char *instr);
+
+int yahoo_tcp_readline(char *ptr, int maxlen, int fd);
+void yahoo_http_post(int id, const char *url, const char *cookies, long size,
+ yahoo_get_fd_callback callback, void *data);
+void yahoo_http_get(int id, const char *url, const char *cookies,
+ yahoo_get_fd_callback callback, void *data);
+void yahoo_get_url_fd(int id, const char *url, const struct yahoo_data *yd,
+ yahoo_get_url_handle_callback callback, void *data);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_list.c b/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_list.c
new file mode 100644
index 0000000..193a78f
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_list.c
@@ -0,0 +1,236 @@
+/*
+ * yahoo_list.c: linked list routines
+ *
+ * Some code copyright (C) 2002-2004, Philip S Tellis <philip.tellis AT gmx.net>
+ * Other code copyright Meredydd Luff <meredydd AT everybuddy.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Some of this code was borrowed from elist.c in the eb-lite sources
+ *
+ */
+
+#include <stdlib.h>
+
+#include "yahoo_list.h"
+
+YList *y_list_append(YList * list, void *data)
+{
+ YList *n;
+ YList *new_list = malloc(sizeof(YList));
+ YList *attach_to = NULL;
+
+ new_list->next = NULL;
+ new_list->data = data;
+
+ for (n = list; n != NULL; n = n->next) {
+ attach_to = n;
+ }
+
+ if (attach_to == NULL) {
+ new_list->prev = NULL;
+ return new_list;
+ } else {
+ new_list->prev = attach_to;
+ attach_to->next = new_list;
+ return list;
+ }
+}
+
+YList *y_list_prepend(YList * list, void *data)
+{
+ YList *n = malloc(sizeof(YList));
+
+ n->next = list;
+ n->prev = NULL;
+ n->data = data;
+ if (list)
+ list->prev = n;
+
+ return n;
+}
+
+YList *y_list_concat(YList * list, YList * add)
+{
+ YList *l;
+
+ if(!list)
+ return add;
+
+ if(!add)
+ return list;
+
+ for (l = list; l->next; l = l->next)
+ ;
+
+ l->next = add;
+ add->prev = l;
+
+ return list;
+}
+
+YList *y_list_remove(YList * list, void *data)
+{
+ YList *n;
+
+ for (n = list; n != NULL; n = n->next) {
+ if (n->data == data) {
+ list=y_list_remove_link(list, n);
+ y_list_free_1(n);
+ break;
+ }
+ }
+
+ return list;
+}
+
+/* Warning */
+/* link MUST be part of list */
+/* caller must free link using y_list_free_1 */
+YList *y_list_remove_link(YList * list, const YList * link)
+{
+ if (!link)
+ return list;
+
+ if (link->next)
+ link->next->prev = link->prev;
+ if (link->prev)
+ link->prev->next = link->next;
+
+ if (link == list)
+ list = link->next;
+
+ return list;
+}
+
+int y_list_length(const YList * list)
+{
+ int retval = 0;
+ const YList *n = list;
+
+ for (n = list; n != NULL; n = n->next) {
+ retval++;
+ }
+
+ return retval;
+}
+
+/* well, you could just check for list == NULL, but that would be
+ * implementation dependent
+ */
+int y_list_empty(const YList * list)
+{
+ if(!list)
+ return 1;
+ else
+ return 0;
+}
+
+int y_list_singleton(const YList * list)
+{
+ if(!list || list->next)
+ return 0;
+ return 1;
+}
+
+YList *y_list_copy(YList * list)
+{
+ YList *n;
+ YList *copy = NULL;
+
+ for (n = list; n != NULL; n = n->next) {
+ copy = y_list_append(copy, n->data);
+ }
+
+ return copy;
+}
+
+void y_list_free_1(YList * list)
+{
+ free(list);
+}
+
+void y_list_free(YList * list)
+{
+ YList *n = list;
+
+ while (n != NULL) {
+ YList *next = n->next;
+ free(n);
+ n = next;
+ }
+}
+
+YList *y_list_find(YList * list, const void *data)
+{
+ YList *l;
+ for (l = list; l && l->data != data; l = l->next)
+ ;
+
+ return l;
+}
+
+void y_list_foreach(YList * list, YListFunc fn, void * user_data)
+{
+ for (; list; list = list->next)
+ fn(list->data, user_data);
+}
+
+YList *y_list_find_custom(YList * list, const void *data, YListCompFunc comp)
+{
+ YList *l;
+ for (l = list; l; l = l->next)
+ if (comp(l->data, data) == 0)
+ return l;
+
+ return NULL;
+}
+
+YList *y_list_nth(YList * list, int n)
+{
+ int i=n;
+ for ( ; list && i; list = list->next, i--)
+ ;
+
+ return list;
+}
+
+YList *y_list_insert_sorted(YList * list, void *data, YListCompFunc comp)
+{
+ YList *l, *n, *prev = NULL;
+ if (!list)
+ return y_list_append(list, data);
+
+ n = malloc(sizeof(YList));
+ n->data = data;
+ for (l = list; l && comp(l->data, n->data) <= 0; l = l->next)
+ prev = l;
+
+ if (l) {
+ n->prev = l->prev;
+ l->prev = n;
+ } else
+ n->prev = prev;
+
+ n->next = l;
+
+ if(n->prev) {
+ n->prev->next = n;
+ return list;
+ } else {
+ return n;
+ }
+
+}
diff --git a/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_list.h b/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_list.h
new file mode 100644
index 0000000..abb2c64
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_list.h
@@ -0,0 +1,74 @@
+/*
+ * yahoo_list.h: linked list routines
+ *
+ * Some code copyright (C) 2002-2004, Philip S Tellis <philip.tellis AT gmx.net>
+ * Other code copyright Meredydd Luff <meredydd AT everybuddy.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 is a replacement for the GList. It only provides functions that
+ * we use in Ayttm. Thanks to Meredyyd from everybuddy dev for doing
+ * most of it.
+ */
+
+#ifndef __YLIST_H__
+#define __YLIST_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _YList {
+ struct _YList *next;
+ struct _YList *prev;
+ void *data;
+} YList;
+
+typedef int (*YListCompFunc) (const void *, const void *);
+typedef void (*YListFunc) (void *, void *);
+
+YList *y_list_append(YList * list, void *data);
+YList *y_list_prepend(YList * list, void *data);
+YList *y_list_remove_link(YList * list, const YList * link);
+YList *y_list_remove(YList * list, void *data);
+
+YList *y_list_insert_sorted(YList * list, void * data, YListCompFunc comp);
+
+YList *y_list_copy(YList * list);
+
+YList *y_list_concat(YList * list, YList * add);
+
+YList *y_list_find(YList * list, const void *data);
+YList *y_list_find_custom(YList * list, const void *data, YListCompFunc comp);
+
+YList *y_list_nth(YList * list, int n);
+
+void y_list_foreach(YList * list, YListFunc fn, void *user_data);
+
+void y_list_free_1(YList * list);
+void y_list_free(YList * list);
+int y_list_length(const YList * list);
+int y_list_empty(const YList * list);
+int y_list_singleton(const YList * list);
+
+#define y_list_next(list) list->next
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_util.c b/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_util.c
new file mode 100644
index 0000000..f166501
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_util.c
@@ -0,0 +1,161 @@
+/*
+ * libyahoo2: yahoo_util.c
+ *
+ * Copyright (C) 2002-2004, Philip S Tellis <philip.tellis AT gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#if STDC_HEADERS
+# include <string.h>
+#else
+# if !HAVE_STRCHR
+# define strchr index
+# define strrchr rindex
+# endif
+char *strchr (), *strrchr ();
+# if !HAVE_MEMCPY
+# define memcpy(d, s, n) bcopy ((s), (d), (n))
+# define memmove(d, s, n) bcopy ((s), (d), (n))
+# endif
+#endif
+
+#include "yahoo_util.h"
+
+char * y_string_append(char * string, char * append)
+{
+ int size = strlen(string) + strlen(append) + 1;
+ char * new_string = y_renew(char, string, size);
+
+ if(new_string == NULL) {
+ new_string = y_new(char, size);
+ strcpy(new_string, string);
+ FREE(string);
+ }
+
+ strcat(new_string, append);
+
+ return new_string;
+}
+
+/*char * y_str_to_utf8(const char *in)
+{
+ unsigned int n, i = 0;
+ char *result = NULL;
+
+ if(in == NULL || *in == '\0')
+ return "";
+
+ result = y_new(char, strlen(in) * 2 + 1);
+
+ // convert a string to UTF-8 Format
+ for (n = 0; n < strlen(in); n++) {
+ unsigned char c = (unsigned char)in[n];
+
+ if (c < 128) {
+ result[i++] = (char) c;
+ } else {
+ result[i++] = (char) ((c >> 6) | 192);
+ result[i++] = (char) ((c & 63) | 128);
+ }
+ }
+ result[i] = '\0';
+ return result;
+}
+
+char * y_utf8_to_str(const char *in)
+{
+ int i = 0;
+ unsigned int n;
+ char *result = NULL;
+
+ if(in == NULL || *in == '\0')
+ return "";
+
+ result = y_new(char, strlen(in) + 1);
+
+ // convert a string from UTF-8 Format
+ for (n = 0; n < strlen(in); n++) {
+ unsigned char c = in[n];
+
+ if (c < 128) {
+ result[i++] = (char) c;
+ } else {
+ result[i++] = (c << 6) | (in[++n] & 63);
+ }
+ }
+ result[i] = '\0';
+ return result;
+} */
+
+#if !HAVE_GLIB
+
+void y_strfreev(char ** vector)
+{
+ char **v;
+ for(v = vector; *v; v++) {
+ FREE(*v);
+ }
+ FREE(vector);
+}
+
+char ** y_strsplit(char * str, char * sep, int nelem)
+{
+ char ** vector;
+ char *s, *p;
+ int i=0;
+ int l = strlen(sep);
+ if(nelem <= 0) {
+ char * s;
+ nelem=0;
+ if (*str) {
+ for(s=strstr(str, sep); s; s=strstr(s+l, sep),nelem++)
+ ;
+ if(strcmp(str+strlen(str)-l, sep))
+ nelem++;
+ }
+ }
+
+ vector = y_new(char *, nelem + 1);
+
+ for(p=str, s=strstr(p,sep); i<nelem && s; p=s+l, s=strstr(p,sep), i++) {
+ int len = s-p;
+ vector[i] = y_new(char, len+1);
+ strncpy(vector[i], p, len);
+ vector[i][len] = '\0';
+ }
+
+ if(i<nelem && *str) /* str didn't end with sep, and str isn't empty */
+ vector[i++] = strdup(p);
+
+ vector[i] = NULL;
+
+ return vector;
+}
+
+void * y_memdup(const void * addr, int n)
+{
+ void * new_chunk = malloc(n);
+ if(new_chunk)
+ memcpy(new_chunk, addr, n);
+ return new_chunk;
+}
+
+#endif
diff --git a/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_util.h b/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_util.h
new file mode 100644
index 0000000..396ce14
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/libyahoo2/yahoo_util.h
@@ -0,0 +1,104 @@
+/*
+ * libyahoo2: yahoo_util.h
+ *
+ * Copyright (C) 2002-2004, Philip S Tellis <philip.tellis AT gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 __YAHOO_UTIL_H__
+#define __YAHOO_UTIL_H__
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#if HAVE_GLIB
+# include <glib.h>
+
+# define FREE(x) if(x) {g_free(x); x=NULL;}
+
+# define y_new g_new
+# define y_new0 g_new0
+# define y_renew g_renew
+
+# define y_memdup g_memdup
+# define y_strsplit g_strsplit
+# define y_strfreev g_strfreev
+# ifndef strdup
+# define strdup g_strdup
+# endif
+# ifndef strncasecmp
+# define strncasecmp g_strncasecmp
+# define strcasecmp g_strcasecmp
+# endif
+
+# define snprintf g_snprintf
+# define vsnprintf g_vsnprintf
+
+#else
+
+# include <stdlib.h>
+# include <stdarg.h>
+
+# define FREE(x) if(x) {free(x); x=NULL;}
+
+# define y_new(type, n) (type *)malloc(sizeof(type) * (n))
+# define y_new0(type, n) (type *)calloc((n), sizeof(type))
+# define y_renew(type, mem, n) (type *)realloc(mem, n)
+
+void * y_memdup(const void * addr, int n);
+char ** y_strsplit(char * str, char * sep, int nelem);
+void y_strfreev(char ** vector);
+
+/*
+int strncasecmp(const char * s1, const char * s2, size_t n);
+int strcasecmp(const char * s1, const char * s2);
+
+char * strdup(const char *s);
+
+int snprintf(char *str, size_t size, const char *format, ...);
+int vsnprintf(char *str, size_t size, const char *format, va_list ap);
+*/
+
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef MIN
+#define MIN(x,y) ((x)<(y)?(x):(y))
+#endif
+
+#ifndef MAX
+#define MAX(x,y) ((x)>(y)?(x):(y))
+#endif
+
+/*
+ * The following three functions return newly allocated memory.
+ * You must free it yourself
+ */
+char * y_string_append(char * str, char * append);
+/*char * y_str_to_utf8(const char * in);
+char * y_utf8_to_str(const char * in);*/
+
+#endif
+
diff --git a/miranda-wine/protocols/Yahoo/main.c b/miranda-wine/protocols/Yahoo/main.c
new file mode 100644
index 0000000..7700b56
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/main.c
@@ -0,0 +1,302 @@
+/*
+ * $Id: main.c 3717 2006-09-06 17:49:35Z gena01 $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+#include <windows.h>
+#include "yahoo.h"
+#include "http_gateway.h"
+#include "version.h"
+#include "resource.h"
+
+#include <m_system.h>
+#include <m_langpack.h>
+#include <m_options.h>
+#include <m_skin.h>
+#include <m_message.h>
+#include <m_idle.h>
+#include <m_userinfo.h>
+
+#include "options.h"
+
+//#define HTTP_GATEWAY
+extern char *szStartMsg;
+
+/*
+ * Global Variables
+ */
+HINSTANCE hinstance;
+PLUGINLINK *pluginLink;
+char yahooProtocolName[MAX_PATH];
+
+HANDLE hNetlibUser = NULL;
+HANDLE YahooMenuItems[ MENU_ITEMS_COUNT ];
+static HANDLE hHookOptsInit;
+static HANDLE hHookModulesLoaded;
+static HANDLE hHookSettingChanged;
+static HANDLE hHookUserTyping;
+static HANDLE hHookUserInfoInit;
+HANDLE hHookContactDeleted;
+HANDLE hHookIdle;
+HANDLE hYahooNudge = NULL;
+
+pthread_mutex_t connectionHandleMutex;
+
+PLUGININFO pluginInfo={
+ sizeof(PLUGININFO),
+#ifdef YAHOO_CVSBUILD
+ "Yahoo Protocol Beta/Nightly",
+#else
+ "Yahoo Protocol",
+#endif
+ __VERSION_DWORD,
+ "Yahoo Protocol support via libyahoo2 library. [Built: "__DATE__" "__TIME__"]",
+ "Gennady Feldman, Laurent Marechal",
+ "gena01@miranda-im.org",
+ "© 2003-2006 G.Feldman",
+ "http://www.miranda-im.org/download/details.php?action=viewfile&id=1248",
+ 0, //not transient
+ 0 //DEFMOD_PROTOCOLYAHOO - no core yahoo protocol
+};
+
+int yahooStatus = ID_STATUS_OFFLINE;
+BOOL yahooLoggedIn = FALSE;
+
+/*
+ * WINAPI DllMain - main entry point into a DLL
+ * Parameters:
+ * HINSTANCE hinst,
+ * DWORD fdwReason,
+ * LPVOID lpvReserved
+ * Returns :
+ * BOOL
+ *
+ */
+BOOL WINAPI DllMain(HINSTANCE hinst,DWORD fdwReason,LPVOID lpvReserved)
+{
+ hinstance=hinst;
+ return TRUE;
+}
+
+
+/*
+ * MainInit - Called at very beginning of plugin
+ * Parameters: wparam , lparam
+ * Returns : int
+ */
+/*int MainInit(WPARAM wparam,LPARAM lparam)
+{
+ return 0;
+}*/
+
+/*
+ * MirandaPluginInfo - Sets plugin info
+ * Parameters: (DWORD mirandaVersion)
+ */
+__declspec(dllexport) PLUGININFO* MirandaPluginInfo(DWORD mirandaVersion)
+{
+ //
+ // We require Miranda 0.6
+ // This requires the latest trunk... experimental API used here
+ //
+ if (mirandaVersion < PLUGIN_MAKE_VERSION(0, 6, 0, 0)) {
+ MessageBox( NULL,
+ "Yahoo plugin cannot be loaded. It requires Miranda IM 0.6 or later.",
+ "Yahoo",
+ MB_OK|MB_ICONWARNING|MB_SETFOREGROUND|MB_TOPMOST );
+
+ return NULL;
+ }
+
+ return &pluginInfo;
+}
+
+/*
+ * Unload - Unloads plugin
+ * Parameters: void
+ */
+
+int __declspec(dllexport) Unload(void)
+{
+ YAHOO_DebugLog("Unload");
+
+ //stop_timer();
+
+ if (yahooLoggedIn)
+ yahoo_logout();
+
+ YAHOO_DebugLog("Logged out");
+ pthread_mutex_destroy(&connectionHandleMutex);
+
+ LocalEventUnhook(hHookContactDeleted);
+ LocalEventUnhook(hHookIdle);
+ LocalEventUnhook(hHookModulesLoaded);
+ LocalEventUnhook(hHookOptsInit);
+ LocalEventUnhook(hHookSettingChanged);
+ LocalEventUnhook(hHookUserTyping);
+
+ if (szStartMsg)
+ free(szStartMsg);
+
+ YAHOO_DebugLog("Before Netlib_CloseHandle");
+ Netlib_CloseHandle( hNetlibUser );
+
+ return 0;
+}
+
+int YahooIdleEvent(WPARAM wParam, LPARAM lParam);
+int OnDetailsInit(WPARAM wParam, LPARAM lParam);
+
+
+/*
+ * Load - loads plugin into memory
+ */
+
+static int OnModulesLoaded( WPARAM wParam, LPARAM lParam )
+{
+ char tModule[ 100 ], tModuleDescr[ 100 ];
+ NETLIBUSER nlu = {0};
+
+ if ( !ServiceExists( MS_DB_CONTACT_GETSETTING_STR )) {
+ MessageBox( NULL,
+ Translate("Yahoo plugin requires db3x plugin version 0.5.1.0 or later" ),
+ Translate("Yahoo"),
+ MB_OK );
+ return 1;
+ }
+
+ CharUpper( lstrcpy( tModule, yahooProtocolName ));
+ wsprintf(tModuleDescr, "%s plugin connections", yahooProtocolName);
+
+ nlu.cbSize = sizeof(nlu);
+
+#ifdef HTTP_GATEWAY
+ nlu.flags = NUF_OUTGOING | NUF_HTTPGATEWAY| NUF_HTTPCONNS;
+#else
+ nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS;
+#endif
+
+ nlu.szSettingsModule = tModule;
+ nlu.szDescriptiveName = Translate( tModuleDescr );
+
+#ifdef HTTP_GATEWAY
+ // Here comes the Gateway Code!
+ nlu.szHttpGatewayHello = NULL;
+ nlu.szHttpGatewayUserAgent = "User-Agent: Mozilla/4.01 [en] (Win95; I)";
+ nlu.pfnHttpGatewayInit = YAHOO_httpGatewayInit;
+ nlu.pfnHttpGatewayBegin = NULL;
+ nlu.pfnHttpGatewayWrapSend = YAHOO_httpGatewayWrapSend;
+ nlu.pfnHttpGatewayUnwrapRecv = YAHOO_httpGatewayUnwrapRecv;
+#endif
+
+ hNetlibUser = ( HANDLE )YAHOO_CallService( MS_NETLIB_REGISTERUSER, 0, ( LPARAM )&nlu );
+
+ hHookOptsInit = HookEvent( ME_OPT_INITIALISE, YahooOptInit );
+ hHookSettingChanged = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, YAHOO_util_dbsettingchanged);
+ hHookIdle = HookEvent(ME_IDLE_CHANGED, YahooIdleEvent);
+ hHookUserInfoInit = HookEvent(ME_USERINFO_INITIALISE, OnDetailsInit);
+
+ // Add support for Plugin Uninstaller
+ //DBWriteContactSettingString(NULL, "Uninstall", "Yahoo", yahooProtocolName);
+
+ //add as a known module in DB Editor ++
+ CallService("DBEditorpp/RegisterSingleModule",(WPARAM)yahooProtocolName, 0);
+
+ //start_timer();
+ return 0;
+}
+
+//=====================================================
+// Name : Load
+// Parameters: PLUGINLINK *link
+// Returns : int
+// Description : Called when plugin is loaded into Miranda
+//=====================================================
+
+int __declspec(dllexport)Load(PLUGINLINK *link)
+{
+ PROTOCOLDESCRIPTOR pd;
+ char path[MAX_PATH], tNudge[250];
+ char* protocolname;
+
+ pluginLink=link;
+ //
+ // Need to disable threading since we got our own routines.
+ //
+ DisableThreadLibraryCalls(hinstance);
+
+ GetModuleFileName( hinstance, path, sizeof( path ));
+
+ protocolname = strrchr(path,'\\');
+
+ if (protocolname != NULL) {
+ char* fend;
+
+ protocolname++;
+ fend = strrchr(path,'.');
+
+ if (fend != NULL)
+ *fend = '\0';
+
+ CharUpper( protocolname );
+ lstrcpyn(yahooProtocolName, protocolname, MAX_PATH);
+ } else
+ lstrcpy(yahooProtocolName, "YAHOO");
+
+ mir_snprintf( path, sizeof( path ), "%s/Status", yahooProtocolName );
+ CallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )path );
+
+ mir_snprintf( path, sizeof( path ), "%s/YStatus", yahooProtocolName );
+ CallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )path );
+
+ mir_snprintf( path, sizeof( path ), "%s/YAway", yahooProtocolName );
+ CallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )path );
+
+ mir_snprintf( path, sizeof( path ), "%s/Mobile", yahooProtocolName );
+ CallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )path );
+
+ mir_snprintf( path, sizeof( path ), "%s/YGMsg", yahooProtocolName );
+ CallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )path );
+
+ mir_snprintf( path, sizeof( path ), "%s/IdleTS", yahooProtocolName );
+ CallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )path );
+
+ mir_snprintf( path, sizeof( path ), "%s/PictLastCheck", yahooProtocolName );
+ CallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )path );
+
+ mir_snprintf( path, sizeof( path ), "%s/PictLoading", yahooProtocolName );
+ CallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )path );
+
+ // 1.
+ hHookModulesLoaded = HookEvent( ME_SYSTEM_MODULESLOADED, OnModulesLoaded );
+ // Create nudge event
+ lstrcpyn(tNudge, yahooProtocolName , sizeof( tNudge ) - 7);
+ lstrcat(tNudge, "/Nudge");
+ hYahooNudge = CreateHookableEvent(tNudge);
+
+ // 2.
+ ZeroMemory(&pd,sizeof(pd));
+ pd.cbSize=sizeof(pd);
+ pd.szName=yahooProtocolName;
+ pd.type=PROTOTYPE_PROTOCOL;
+ CallService(MS_PROTO_REGISTERMODULE,0,(LPARAM)&pd);
+
+ register_callbacks();
+ // 3.
+ yahoo_logoff_buddies();
+
+ SkinAddNewSoundEx(Translate( "mail" ), yahooProtocolName, "New E-mail available in Inbox" );
+
+ LoadYahooServices();
+
+ pthread_mutex_init(&connectionHandleMutex);
+ return 0;
+}
+
diff --git a/miranda-wine/protocols/Yahoo/options.c b/miranda-wine/protocols/Yahoo/options.c
new file mode 100644
index 0000000..32d7b06
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/options.c
@@ -0,0 +1,256 @@
+/*
+ * $Id: options.c 3640 2006-08-29 17:54:56Z gena01 $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+#include <windows.h>
+#include <shlwapi.h>
+
+#include "yahoo.h"
+#include "resource.h"
+
+#include <m_langpack.h>
+#include <m_utils.h>
+#include <m_options.h>
+#include <m_popup.h>
+
+#include "options.h"
+
+/*
+ * YahooOptInit - initialize/register our Options w/ Miranda.
+ */
+int YahooOptInit(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp;
+
+ ZeroMemory(&odp, sizeof( odp ));
+ odp.cbSize = sizeof(odp);
+ odp.position = -790000000;
+ odp.hInstance = hinstance;
+ odp.pszTemplate = MAKEINTRESOURCE(IDD_OPT_YAHOO);
+ odp.pszTitle = Translate( yahooProtocolName );
+ odp.pszGroup = Translate("Network");
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.nIDBottomSimpleControl = IDC_STYAHOOGROUP;
+ odp.pfnDlgProc = DlgProcYahooOpts;
+ YAHOO_CallService( MS_OPT_ADDPAGE, wParam,( LPARAM )&odp );
+
+ return 0;
+}
+
+/*
+ * DlgProcYahooOpts - Connection Options Dialog
+ */
+BOOL CALLBACK DlgProcYahooOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ DBVARIANT dbv;
+ YList *l;
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+
+ if ( !DBGetContactSetting( NULL, yahooProtocolName, YAHOO_LOGINID, &dbv )) {
+ SetDlgItemText(hwndDlg,IDC_HANDLE,dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+
+ if ( !DBGetContactSetting( NULL, yahooProtocolName, "Nick", &dbv )) {
+ SetDlgItemText(hwndDlg,IDC_NICK,dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+
+ if ( !DBGetContactSetting( NULL, yahooProtocolName, YAHOO_PASSWORD, &dbv )) {
+ //bit of a security hole here, since it's easy to extract a password from an edit box
+ YAHOO_CallService( MS_DB_CRYPT_DECODESTRING, strlen( dbv.pszVal )+1, ( LPARAM )dbv.pszVal );
+ SetDlgItemText( hwndDlg, IDC_PASSWORD, dbv.pszVal );
+ DBFreeVariant( &dbv );
+ }
+
+ if ( !DBGetContactSetting( NULL, yahooProtocolName, YAHOO_LOGINSERVER, &dbv )){
+ SetDlgItemText( hwndDlg, IDC_LOGINSERVER, dbv. pszVal );
+ DBFreeVariant( &dbv );
+ }
+ else SetDlgItemText( hwndDlg, IDC_LOGINSERVER, YAHOO_DEFAULT_LOGIN_SERVER );
+
+ SetDlgItemInt( hwndDlg, IDC_YAHOOPORT, YAHOO_GetWord( NULL, YAHOO_LOGINPORT, 5050 ), FALSE );
+
+ SetButtonCheck( hwndDlg, IDC_YAHOO_JAPAN, YAHOO_GetByte( "YahooJapan", 0 ) );
+ SetButtonCheck( hwndDlg, IDC_DISMAINMENU, YAHOO_GetByte( "DisableMainMenu", 0 ) );
+ SetButtonCheck( hwndDlg, IDC_USE_YAB, YAHOO_GetByte( "UseYAB", 1 ));
+ SetButtonCheck( hwndDlg, IDC_SHOW_AVATARS, YAHOO_GetByte( "ShowAvatars", 0 ));
+ SetButtonCheck( hwndDlg, IDC_MAIL_AUTOLOGIN, YAHOO_GetByte( "MailAutoLogin", 0 ));
+ SetButtonCheck( hwndDlg, IDC_DISABLEYAHOOMAIL, !YAHOO_GetByte( "DisableYahoomail", 0 ));
+ SetButtonCheck( hwndDlg, IDC_SHOW_ERRORS, YAHOO_GetByte( "ShowErrors", 1 ));
+
+ /* show our current ignore list */
+ l = (YList *)YAHOO_GetIgnoreList();
+ while (l != NULL) {
+ struct yahoo_buddy *b = (struct yahoo_buddy *) l->data;
+
+ //MessageBox(NULL, b->id, "ID", MB_OK);
+ SendMessage(GetDlgItem(hwndDlg,IDC_YIGN_LIST), LB_ADDSTRING, 0, (LPARAM)b->id);
+ l = l->next;
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_NEWYAHOOACCOUNTLINK:
+ YAHOO_CallService( MS_UTILS_OPENURL, 1,
+ YAHOO_GetByte( "YahooJapan", 0 )
+ ?(LPARAM)"http://edit.yahoo.co.jp/config/eval_register"
+ :(LPARAM)"http://edit.yahoo.com/config/eval_register" );
+ return TRUE;
+
+ case IDC_RESETSERVER:
+ SetDlgItemText( hwndDlg, IDC_LOGINSERVER, YAHOO_DEFAULT_LOGIN_SERVER );
+ SetDlgItemInt( hwndDlg, IDC_YAHOOPORT, 5050, FALSE );
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_IGN_ADD:
+ {
+ char id[128];
+ int i;
+
+ if (!yahooLoggedIn) {
+ MessageBox(hwndDlg, Translate("You need to be connected to Yahoo to add to Ignore List."), Translate("Yahoo Ignore"), MB_OK| MB_ICONINFORMATION);
+ break;
+ }
+
+
+ i = GetDlgItemText( hwndDlg, IDC_YIGN_EDIT, id, sizeof( id ));
+
+ if (i < 3) {
+ MessageBox(hwndDlg, Translate("Please enter a valid buddy name to ignore."), Translate("Yahoo Ignore"), MB_OK| MB_ICONINFORMATION);
+ break;
+ }
+
+ i = SendMessage(GetDlgItem(hwndDlg,IDC_YIGN_LIST), LB_FINDSTRINGEXACT,(WPARAM) -1, (LPARAM)id);
+ if (i != LB_ERR ) {
+ MessageBox(hwndDlg, Translate("The buddy is already on your ignore list. "), Translate("Yahoo Ignore"), MB_OK | MB_ICONINFORMATION);
+ break;
+ }
+ YAHOO_IgnoreBuddy(id, 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_YIGN_LIST), LB_ADDSTRING, 0, (LPARAM)id);
+ SetDlgItemText( hwndDlg, IDC_YIGN_EDIT, "" );
+ }
+ break;
+
+ case IDC_IGN_REMOVE:
+ {
+ int i;
+ char id[128];
+
+ if (!yahooLoggedIn) {
+ MessageBox(hwndDlg, Translate("You need to be connected to Yahoo to remove from the Ignore List."), Translate("Yahoo Ignore"), MB_OK| MB_ICONINFORMATION);
+ break;
+ }
+
+ i = SendMessage(GetDlgItem(hwndDlg,IDC_YIGN_LIST), LB_GETCURSEL, 0, 0);
+ if (i == LB_ERR) {
+ MessageBox(hwndDlg, Translate("Please select a buddy on the ignore list to remove."), Translate("Yahoo Ignore"), MB_OK| MB_ICONINFORMATION);
+ break;
+ }
+
+ SendMessage(GetDlgItem(hwndDlg,IDC_YIGN_LIST), LB_GETTEXT, i, (LPARAM)id);
+
+ YAHOO_IgnoreBuddy(id, 1);
+ SendMessage(GetDlgItem(hwndDlg,IDC_YIGN_LIST), LB_DELETESTRING, i, 0);
+ }
+
+ break;
+ case IDC_YAHOO_JAPAN:
+ SetDlgItemText( hwndDlg, IDC_LOGINSERVER,
+ (IsDlgButtonChecked(hwndDlg,IDC_YAHOO_JAPAN)==BST_CHECKED)
+ ?YAHOO_DEFAULT_JAPAN_LOGIN_SERVER
+ :YAHOO_DEFAULT_LOGIN_SERVER );
+ // fall through and enable apply button
+
+ case IDC_DISMAINMENU:
+ case IDC_USE_YAB:
+ case IDC_SHOW_AVATARS:
+ case IDC_MAIL_AUTOLOGIN:
+ case IDC_SHOW_ERRORS:
+ case IDC_DISABLEYAHOOMAIL:
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+
+ if ( HIWORD( wParam ) == EN_CHANGE && ( HWND )lParam == GetFocus())
+ switch( LOWORD( wParam )) {
+ case IDC_HANDLE:
+ case IDC_PASSWORD:
+ case IDC_LOGINSERVER:
+ case IDC_YAHOOPORT:
+ case IDC_NICK:
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+
+ break;
+
+
+
+ case WM_NOTIFY:
+ if (((LPNMHDR)lParam)->code == PSN_APPLY )
+ {
+ BOOL reconnectRequired = FALSE, restartRequired = FALSE;
+ char str[128];
+ char id[128];
+ DBVARIANT dbv;
+
+ GetDlgItemText( hwndDlg, IDC_HANDLE, id, sizeof( id ));
+ dbv.pszVal = NULL;
+
+ if ( DBGetContactSetting( NULL, yahooProtocolName, YAHOO_LOGINID, &dbv ) ||
+ lstrcmp( id, dbv.pszVal ))
+ reconnectRequired = TRUE;
+
+ if ( dbv.pszVal != NULL ) DBFreeVariant( &dbv );
+
+ YAHOO_SetString( NULL, YAHOO_LOGINID, id );
+
+ GetDlgItemText( hwndDlg, IDC_PASSWORD, str, sizeof( str ));
+ YAHOO_CallService( MS_DB_CRYPT_ENCODESTRING, sizeof( str ),( LPARAM )str );
+ dbv.pszVal = NULL;
+ if ( DBGetContactSetting( NULL, yahooProtocolName, YAHOO_PASSWORD, &dbv ) ||
+ lstrcmp( str, dbv.pszVal ))
+ reconnectRequired = TRUE;
+ if ( dbv.pszVal != NULL ) DBFreeVariant( &dbv );
+
+ YAHOO_SetString( NULL, YAHOO_PASSWORD, str );
+ GetDlgItemText( hwndDlg, IDC_NICK, str, sizeof( str ));
+ YAHOO_SetString( NULL, "Nick", str );
+
+ GetDlgItemText( hwndDlg, IDC_LOGINSERVER, str, sizeof( str ));
+ YAHOO_SetString( NULL, YAHOO_LOGINSERVER, str );
+
+ YAHOO_SetWord( NULL, YAHOO_LOGINPORT, GetDlgItemInt( hwndDlg, IDC_YAHOOPORT, NULL, FALSE ));
+
+ YAHOO_SetByte("YahooJapan", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_YAHOO_JAPAN ));
+ YAHOO_SetByte("DisableMainMenu", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_DISMAINMENU ));
+ YAHOO_SetByte("UseYAB", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_USE_YAB ));
+ YAHOO_SetByte("ShowAvatars", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_SHOW_AVATARS ));
+ YAHOO_SetByte("MailAutoLogin", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_MAIL_AUTOLOGIN ));
+ YAHOO_SetByte("DisableYahoomail", ( BYTE )!IsDlgButtonChecked( hwndDlg, IDC_DISABLEYAHOOMAIL ));
+ YAHOO_SetByte("ShowErrors", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_SHOW_ERRORS ));
+
+ if ( restartRequired )
+ MessageBox( hwndDlg, Translate( "The changes you have made require you to restart Miranda IM before they take effect"), Translate("YAHOO Options"), MB_OK );
+ else if ( reconnectRequired && yahooLoggedIn )
+ MessageBox( hwndDlg, Translate( "The changes you have made require you to reconnect to the Yahoo network before they take effect"), Translate("YAHOO Options"), MB_OK );
+
+ return TRUE;
+ }
+ break;
+ }
+ return FALSE;
+}
diff --git a/miranda-wine/protocols/Yahoo/options.h b/miranda-wine/protocols/Yahoo/options.h
new file mode 100644
index 0000000..345d0e2
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/options.h
@@ -0,0 +1,20 @@
+/*
+ * $Id: options.h 3640 2006-08-29 17:54:56Z gena01 $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+#ifndef _YAHOO_SEARCH_H_
+#define _YAHOO_SEARCH_H_
+
+BOOL CALLBACK DlgProcYahooOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+//BOOL CALLBACK DlgProcYahooPopUpOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+int YahooOptInit(WPARAM wParam,LPARAM lParam);
+
+#endif
diff --git a/miranda-wine/protocols/Yahoo/pthread.c b/miranda-wine/protocols/Yahoo/pthread.c
new file mode 100644
index 0000000..f979b0e
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/pthread.c
@@ -0,0 +1,75 @@
+/*
+ * $Id: pthread.c 2874 2006-05-16 21:38:00Z ghazan $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * Code borrowed for myYahoo plugin. Fixed to compile on Mingw by G.Feldman
+ * Original Copyright (c) 2003 Robert Rainwater
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+#include "yahoo.h"
+#include <process.h>
+#include <m_system.h>
+
+/* Gena01 - added some defined to fix compilation with mingw gcc */
+/* __try/__finally taken from abiword patch found on the web */
+#ifdef __GNUC__
+
+#if 0
+ #include <crtdbg.h>
+#else
+#define __try
+#define __except(x) if (0) /* don't execute handler */
+#define __finally
+
+#define _try __try
+#define _except __except
+#define _finally __finally
+#endif
+
+#endif
+
+#include <excpt.h>
+
+struct pthread_arg
+{
+ HANDLE hEvent;
+ void (*threadcode) (void *);
+ void *arg;
+};
+
+void pthread_r(struct pthread_arg *fa)
+{
+ void (*callercode) (void *) = fa->threadcode;
+ void *arg = fa->arg;
+ CallService(MS_SYSTEM_THREAD_PUSH, 0, 0);
+ SetEvent(fa->hEvent);
+ __try {
+ callercode(arg);
+ }
+ __finally {
+ CallService(MS_SYSTEM_THREAD_POP, 0, 0);
+ }
+}
+
+unsigned long pthread_create(void (*threadcode) (void *), void *arg)
+{
+ unsigned long rc;
+ struct pthread_arg fa;
+ fa.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ fa.threadcode = threadcode;
+ fa.arg = arg;
+ rc = _beginthread((void *) (void *) pthread_r, 0, &fa);
+ if ((unsigned long) -1L != rc) {
+ WaitForSingleObject(fa.hEvent, INFINITE);
+ }
+ CloseHandle(fa.hEvent);
+ return rc;
+}
+
diff --git a/miranda-wine/protocols/Yahoo/pthread.h b/miranda-wine/protocols/Yahoo/pthread.h
new file mode 100644
index 0000000..e3a769a
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/pthread.h
@@ -0,0 +1,26 @@
+/*
+ * $Id: pthread.h 2874 2006-05-16 21:38:00Z ghazan $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * Code borrowed for myYahoo plugin. Fixed to compile on Mingw by G.Feldman
+ * Original Copyright (c) 2003 Robert Rainwater
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+#ifndef PTHREAD_H
+#define PTHREAD_H
+
+unsigned long pthread_create(void (*threadcode) (void *), void *arg);
+typedef CRITICAL_SECTION pthread_mutex_t;
+#define pthread_mutex_init(pmutex) InitializeCriticalSection(pmutex)
+#define pthread_mutex_destroy(pmutex) DeleteCriticalSection(pmutex)
+#define pthread_mutex_lock(pmutex) EnterCriticalSection(pmutex)
+#define pthread_mutex_unlock(pmutex) LeaveCriticalSection(pmutex)
+
+#endif
diff --git a/miranda-wine/protocols/Yahoo/resource.h b/miranda-wine/protocols/Yahoo/resource.h
new file mode 100644
index 0000000..4c4451b
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/resource.h
@@ -0,0 +1,70 @@
+/*
+ * $Id: resource.h 3465 2006-08-06 01:26:35Z gena01 $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+
+//#define IDI_ICON1 101
+#define IDI_MAIN 101
+#define IDI_YAHOO 102
+#define IDI_INBOX 103
+#define IDI_PROFILE 104
+#define IDI_REFRESH 105
+#define IDI_YAB 106
+#define IDI_SET_STATUS 107
+#define IDI_CALENDAR 108
+
+#define IDD_OPT_YAHOO 185
+#define IDD_SETCUSTSTAT 186
+#define IDD_OPT_YAHOO_POPUP 187
+#define IDC_CUSTSTATBUSY 1000
+#define IDC_CUSTSTAT 1001
+#define IDC_STYAHOOGROUP 1002
+#define IDC_EDIT1 1003
+#define IDC_STIGNGROUP 1004
+#define IDC_USEWINCOLORS 1008
+#define IDC_YCHECKMAIL 1011
+#define IDC_YTNOTIF 1012
+#define IDC_PASSWORD 1020
+#define IDC_NICK 1021
+#define IDC_HANDLE 1022
+#define IDC_BGCOLOUR 1026
+#define IDC_TEXTCOLOUR 1028
+#define IDC_PREVIEW 1030
+#define IDC_DEBUG 1050
+#define IDC_POPUP_TIMEOUT 1051
+#define IDC_LOGINSERVER 1171
+#define IDC_YAHOOPORT 1174
+#define IDC_DISABLEYAHOOMAIL 1301
+#define IDC_NEWYAHOOACCOUNTLINK 1438
+#define IDC_RESETSERVER 1472
+#define IDC_DISMAINMENU 1475
+#define IDC_USE_YAB 1477
+#define IDC_SHOW_ERRORS 1478
+#define IDC_SHOW_AVATARS 1479
+#define IDC_MAIL_AUTOLOGIN 1480
+#define IDC_YAHOO_JAPAN 1481
+
+#define IDD_OPT_YAHOO_IGNORE 201
+#define IDC_YIGN_EDIT 202
+#define IDC_YIGN_LIST 203
+#define IDC_IGN_ADD 204
+#define IDC_IGN_REMOVE 205
+
+#define IDD_INFO_AVATAR 300
+#define IDC_AVATAR 301
+#define IDC_SETAVATAR 302
+#define IDC_DELETEAVATAR 303
+#define IDC_SHARE_AVATAR 304
+
+/*
+ *
+ */
+#define IDC_STATIC -1
diff --git a/miranda-wine/protocols/Yahoo/search.c b/miranda-wine/protocols/Yahoo/search.c
new file mode 100644
index 0000000..7a06df8
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/search.c
@@ -0,0 +1,121 @@
+/*
+ * $Id: search.c 3659 2006-08-30 19:43:41Z gena01 $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+#include "yahoo.h"
+#include <m_protosvc.h>
+#include <m_langpack.h>
+#include <m_message.h>
+
+extern yahoo_local_account * ylad;
+
+//=======================================================
+//Search for user
+//=======================================================
+static void __cdecl yahoo_search_simplethread(void *snsearch)
+{
+ PROTOSEARCHRESULT psr;
+
+/* if (aim_util_isme(sn)) {
+ ProtoBroadcastAck(AIM_PROTO, NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE) 1, 0);
+ return;
+ }
+ */
+ ZeroMemory(&psr, sizeof(psr));
+ psr.cbSize = sizeof(psr);
+ psr.nick = (char *)snsearch;
+ //psr.email = (char *)snsearch;
+
+ //void yahoo_search(int id, enum yahoo_search_type t, const char *text, enum yahoo_search_gender g, enum yahoo_search_agerange ar,
+ // int photo, int yahoo_only)
+
+ YAHOO_SendBroadcast(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE) 1, (LPARAM) & psr);
+ //YAHOO_SendBroadcast(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE) 1, 0);
+}
+
+static void yahoo_search_simple(const char *nick)
+{
+ static char m[255];
+ char *c;
+
+ c = strchr(nick, '@');
+
+ if (c != NULL){
+ int l = c - nick;
+
+ strncpy(m, nick, l);
+ m[l] = '\0';
+ }else
+ strcpy(m, nick);
+
+ //YAHOO_basicsearch(nick);
+ yahoo_search(ylad->id, YAHOO_SEARCH_YID, nick, YAHOO_GENDER_NONE, YAHOO_AGERANGE_NONE, 0, 1);
+
+ pthread_create(yahoo_search_simplethread, (void *) m);
+}
+
+int YahooBasicSearch(WPARAM wParam,LPARAM lParam)
+{
+ if ( !yahooLoggedIn )
+ return 0;
+
+ yahoo_search_simple((char *) lParam);
+ return 1;
+}
+
+void ext_yahoo_got_search_result(int id, int found, int start, int total, YList *contacts)
+{
+ PROTOSEARCHRESULT psr;
+ struct yahoo_found_contact *yct=NULL;
+ char *c;
+ int i=start;
+ YList *en=contacts;
+
+ LOG(("got search result: "));
+
+ LOG(("ID: %d", id));
+ LOG(("Found: %d", found));
+ LOG(("Start: %d", start));
+ LOG(("Total: %d", total));
+
+ ZeroMemory(&psr, sizeof(psr));
+ psr.cbSize = sizeof(psr);
+
+ while (en) {
+ yct = en->data;
+
+ if (yct == NULL) {
+ LOG(("[%d] Empty record?",i++));
+ } else {
+ LOG(("[%d] id: '%s', online: %d, age: %d, sex: '%s', location: '%s'", i++, yct->id, yct->online, yct->age, yct->gender, yct->location));
+ psr.nick = (char *)yct->id;
+ c = (char *)malloc(10);
+
+ if (yct->gender[0] != 5)
+ psr.firstName = yct->gender;
+
+ if (yct->age > 0) {
+ itoa(yct->age, c,10);
+ psr.lastName = (char *)c;
+ }
+
+ if (yct->location[0] != 5)
+ psr.email = (char *)yct->location;
+
+ //void yahoo_search(int id, enum yahoo_search_type t, const char *text, enum yahoo_search_gender g, enum yahoo_search_agerange ar,
+ // int photo, int yahoo_only)
+
+ YAHOO_SendBroadcast(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE) 1, (LPARAM) & psr);
+ }
+ en = y_list_next(en);
+ }
+ YAHOO_SendBroadcast(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE) 1, 0);
+}
diff --git a/miranda-wine/protocols/Yahoo/search.h b/miranda-wine/protocols/Yahoo/search.h
new file mode 100644
index 0000000..ba347a2
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/search.h
@@ -0,0 +1,19 @@
+/*
+ * $Id: search.h 3640 2006-08-29 17:54:56Z gena01 $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+#ifndef _YAHOO_SEARCH_H_
+#define _YAHOO_SEARCH_H_
+
+int YahooBasicSearch(WPARAM wParam,LPARAM lParam);
+void ext_yahoo_got_search_result(int id, int found, int start, int total, YList *contacts);
+
+#endif
diff --git a/miranda-wine/protocols/Yahoo/server.c b/miranda-wine/protocols/Yahoo/server.c
new file mode 100644
index 0000000..83d67e4
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/server.c
@@ -0,0 +1,221 @@
+/*
+ * $Id: server.c 3699 2006-09-04 18:01:00Z gena01 $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+#include <windows.h>
+#include "yahoo.h"
+#include <m_system.h>
+#include <time.h>
+
+int poll_loop = 1;
+long lLastSend;
+extern YList *connections;
+
+int PASCAL send(SOCKET s, const char FAR *buf, int len, int flags)
+{
+ int rlen;
+ //LOG(("send socket: %d, %d bytes", s, len));
+
+ if (yahooStatus == ID_STATUS_OFFLINE) {
+ LOG(("WARNING: WE OFFLINE ALREADY!!"));
+ //return 0;
+ }
+
+ rlen = Netlib_Send((HANDLE)s, buf, len, 0);
+
+#ifdef HTTP_GATEWAY
+ if (iHTTPGateway)
+ lLastSend = time(NULL);
+#endif
+
+ if (rlen == SOCKET_ERROR) {
+ LOG(("SEND Error."));
+ return -1;
+ }
+
+ return len;
+}
+
+int PASCAL recv(SOCKET s, char FAR *buf, int len, int flags)
+{
+ int RecvResult;
+ //LOG(("Recv socket: %d", s));
+ if (yahooStatus == ID_STATUS_OFFLINE)
+ LOG(("WARNING:WE ARE OFFLINE!!"));
+
+ RecvResult = Netlib_Recv((HANDLE)s, buf, len, (len == 1) ? MSG_NODUMP : 0);
+
+ //LOG(("Got bytes: %d, len: %d", RecvResult, len));
+ if (RecvResult == SOCKET_ERROR) {
+ LOG(("Receive error on socket: %d", s));
+ return -1;
+ }
+
+ return RecvResult;
+}
+
+extern yahoo_local_account * ylad;
+
+void __cdecl yahoo_server_main(void *empty)
+{
+ int status = (int) empty;
+ long lLastPing;
+ YList *l;
+ NETLIBSELECTEX nls = {0};
+
+ if (hNetlibUser == 0) {
+ /* wait for the stupid netlib to load!!!! */
+ int i;
+
+ for (i = 0; (i < 3) && (hNetlibUser == 0); i++)
+ SleepEx(30, TRUE);
+
+ }
+
+ YAHOO_DebugLog("Server Thread Starting status: %d", status);
+
+ do_yahoo_debug=YAHOO_LOG_DEBUG;
+ yahoo_set_log_level(do_yahoo_debug);
+
+ //YAHOO_DebugLog("Before Yahoo Login Need Status: %d", status);
+ poll_loop = 1; /* set this so we start looping */
+
+ ext_yahoo_login(status);
+
+ lLastPing = time(NULL);
+ {
+ int recvResult, ridx = 0, widx = 0, i;
+
+ while (poll_loop) {
+ nls.cbSize = sizeof(nls);
+ nls.dwTimeout = 1000; // 1000 millis = 1 sec
+
+ FD_ZERO(&nls.hReadStatus);
+ FD_ZERO(&nls.hWriteStatus);
+ FD_ZERO(&nls.hExceptStatus);
+ nls.hExceptConns[0] = NULL;
+ ridx = 0; widx = 0;
+
+ for(l=connections; l; ) {
+ struct _conn *c = l->data;
+ //LOG(("Connection tag:%d id:%d fd:%d remove:%d", c->tag, c->id, c->fd, c->remove));
+ if(c->remove) {
+ YList *n = y_list_next(l);
+ //LOG(("Removing id:%d fd:%d tag:%d", c->id, c->fd, c->tag));
+ connections = y_list_remove_link(connections, l);
+ y_list_free_1(l);
+ FREE(c);
+ l=n;
+ } else {
+ if(c->cond & YAHOO_INPUT_READ)
+ nls.hReadConns[ridx++] = (HANDLE)c->fd;
+
+ if(c->cond & YAHOO_INPUT_WRITE)
+ nls.hWriteConns[widx++] =(HANDLE) c->fd;
+
+ l = y_list_next(l);
+ }
+ }
+
+ //YAHOO_DebugLog("[Yahoo_Server] ridx:%d widx:%d", ridx, widx);
+
+ nls.hReadConns[ridx] = NULL;
+ nls.hWriteConns[widx] = NULL;
+
+ if (connections == NULL){
+ YAHOO_DebugLog("Last connection closed.");
+ break;
+ }
+ recvResult = CallService(MS_NETLIB_SELECTEX, (WPARAM) 0, (LPARAM)&nls);
+
+ /* Check for Miranda Exit Status */
+ if (Miranda_Terminated()) {
+ YAHOO_DebugLog("Miranda Exiting... stopping the loop.");
+ break;
+ }
+
+ /* do the timer check */
+ if (ylad != NULL) {
+#ifdef HTTP_GATEWAY
+ //YAHOO_DebugLog("HTTPGateway: %d", iHTTPGateway);
+ if (!iHTTPGateway) {
+#endif
+ if (yahooLoggedIn && time(NULL) - lLastPing > 60) {
+ LOG(("[TIMER] Sending a keep alive message"));
+ yahoo_keepalive(ylad->id);
+
+ lLastPing = time(NULL);
+ }
+#ifdef HTTP_GATEWAY
+ } else {
+ YAHOO_DebugLog("[SERVER] Got packets: %d", ylad->rpkts);
+
+ if ( yahooLoggedIn && ( (ylad->rpkts > 0 && (time(NULL) - lLastSend) >=3) ||
+ ( (time(NULL) - lLastSend) >= 13) ) ) {
+
+ LOG(("[TIMER] Sending an idle message..."));
+ yahoo_send_idle_packet(ylad->id);
+ }
+
+ //
+ // need to sleep, cause netlibselectex is too fast?
+ //
+ SleepEx(500, TRUE);
+ }
+#endif
+ }
+ /* do the timer check ends */
+
+ for(l = connections; l; l = y_list_next(l)) {
+ struct _conn *c = l->data;
+
+ if (c->remove)
+ continue;
+
+ for (i = 0; i < ridx; i++) {
+ if ((HANDLE)c->fd == nls.hReadConns[i]) {
+ if (nls.hReadStatus[i])
+ yahoo_callback(c, YAHOO_INPUT_READ);
+ }//if c->fd=
+ }//for i = 0
+
+ for (i = 0; i < widx; i++) {
+ if ((HANDLE)c->fd == nls.hWriteConns[i]) {
+ if (nls.hWriteStatus[i])
+ yahoo_callback(c, YAHOO_INPUT_WRITE);
+ } // if c->fd == nls
+ }// for i = 0
+ }// for l=connections
+
+ }
+ YAHOO_DebugLog("Exited loop");
+ }
+
+ /* need to logout first */
+ yahoo_logout();
+
+ /* cleanup the data stuff and close our connection handles */
+ while(connections) {
+ YList *tmp = connections;
+ struct _conn * c = connections->data;
+ Netlib_CloseHandle((HANDLE)c->fd);
+ FREE(c);
+ connections = y_list_remove_link(connections, connections);
+ y_list_free_1(tmp);
+ }
+
+ /* now set ourselves to offline */
+ yahoo_util_broadcaststatus(ID_STATUS_OFFLINE);
+ yahoo_logoff_buddies();
+
+ YAHOO_DebugLog("Server thread ending");
+}
+
diff --git a/miranda-wine/protocols/Yahoo/services.c b/miranda-wine/protocols/Yahoo/services.c
new file mode 100644
index 0000000..df39017
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/services.c
@@ -0,0 +1,1134 @@
+/*
+ * $Id: services.c 3707 2006-09-05 20:47:58Z gena01 $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+#include <malloc.h>
+#include <time.h>
+
+#include "yahoo.h"
+
+#include <m_system.h>
+#include <m_protomod.h>
+#include <m_protosvc.h>
+#include <m_langpack.h>
+#include <m_skin.h>
+#include <m_utils.h>
+#include <m_options.h>
+#include <m_popup.h>
+#include <m_idle.h>
+
+#include "avatar.h"
+#include "resource.h"
+#include "file_transfer.h"
+#include "im.h"
+#include "search.h"
+
+void yahoo_logoff_buddies()
+{
+ //set all contacts to 'offline'
+ HANDLE hContact = ( HANDLE )YAHOO_CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL )
+ {
+ if ( !lstrcmp( yahooProtocolName, ( char* )YAHOO_CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact,0 ))) {
+ YAHOO_SetWord( hContact, "Status", ID_STATUS_OFFLINE );
+ DBWriteContactSettingDword(hContact, yahooProtocolName, "IdleTS", 0);
+ DBWriteContactSettingDword(hContact, yahooProtocolName, "PictLastCheck", 0);
+ DBWriteContactSettingDword(hContact, yahooProtocolName, "PictLoading", 0);
+ DBDeleteContactSetting(hContact, "CList", "StatusMsg" );
+ DBDeleteContactSetting(hContact, yahooProtocolName, "YMsg" );
+ DBDeleteContactSetting(hContact, yahooProtocolName, "YGMsg" );
+ //DBDeleteContactSetting(hContact, yahooProtocolName, "MirVer" );
+ }
+
+ hContact = ( HANDLE )YAHOO_CallService( MS_DB_CONTACT_FINDNEXT,( WPARAM )hContact, 0 );
+ }
+}
+
+
+//=======================================================
+//GetCaps
+//=======================================================
+int GetCaps(WPARAM wParam,LPARAM lParam)
+{
+ int ret = 0;
+ switch (wParam) {
+ case PFLAGNUM_1:
+ ret = PF1_IM | PF1_ADDED | PF1_AUTHREQ | PF1_MODEMSGRECV | PF1_MODEMSGSEND | PF1_BASICSEARCH
+ | PF1_FILESEND | PF1_FILERECV| PF1_VISLIST;
+// | PF1_SERVERCLIST ;
+ break;
+
+ case PFLAGNUM_2:
+ ret = PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_ONTHEPHONE |
+ PF2_OUTTOLUNCH | PF2_INVISIBLE | PF2_LIGHTDND | PF2_HEAVYDND;
+ break;
+
+ case PFLAGNUM_3:
+ ret = PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_ONTHEPHONE |
+ PF2_OUTTOLUNCH | /*PF2_INVISIBLE |*/ PF2_LIGHTDND | PF2_HEAVYDND;
+ break;
+
+ case PFLAGNUM_4:
+ ret = PF4_FORCEAUTH|PF4_FORCEADDED|PF4_SUPPORTTYPING|PF4_SUPPORTIDLE| PF4_AVATARS;
+ break;
+ case PFLAG_UNIQUEIDTEXT:
+ ret = (int) Translate("ID");
+ break;
+ case PFLAG_UNIQUEIDSETTING:
+ ret = (int) YAHOO_LOGINID;
+ break;
+ case PFLAG_MAXLENOFMESSAGE:
+ ret = 800; /* STUPID YAHOO!!! */
+ break;
+
+ }
+ return ret;
+
+}
+
+//=======================================================
+//GetName
+//=======================================================
+int GetName(WPARAM wParam,LPARAM lParam)
+{
+ lstrcpyn((char*)lParam, yahooProtocolName, wParam);
+ return 0;
+}
+
+//=======================================================
+//YahooLoadIcon
+//=======================================================
+int YahooLoadIcon(WPARAM wParam,LPARAM lParam)
+{
+ UINT id;
+
+ switch(wParam&0xFFFF) {
+ case PLI_PROTOCOL: id=IDI_MAIN; break; // IDI_MAIN is the main icon for the protocol
+ default: return (int)(HICON)NULL;
+ }
+ return (int)LoadImage(hinstance,MAKEINTRESOURCE(id),IMAGE_ICON,GetSystemMetrics(wParam&PLIF_SMALL?SM_CXSMICON:SM_CXICON),GetSystemMetrics(wParam&PLIF_SMALL?SM_CYSMICON:SM_CYICON),0);
+}
+
+//=======================================================
+//GetStatus
+//=======================================================
+int GetStatus(WPARAM wParam,LPARAM lParam)
+{
+ return yahooStatus;
+}
+
+extern yahoo_local_account *ylad;
+
+int gStartStatus = ID_STATUS_ONLINE;
+char *szStartMsg = NULL;
+
+//=======================================================
+//SetStatus
+//=======================================================
+int SetStatus(WPARAM wParam,LPARAM lParam)
+{
+ int status = (int) wParam;
+
+ //if (yahooStatus == status)
+ // return 0;
+
+ YAHOO_DebugLog("[SetStatus] New status %s", (char *) CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, status, 0));
+ if (status == ID_STATUS_OFFLINE) {
+ yahoo_logout();
+
+ yahoo_util_broadcaststatus(ID_STATUS_OFFLINE);
+ yahoo_logoff_buddies();
+ }
+ else if (!yahooLoggedIn) {
+ DBVARIANT dbv;
+ int err = 0;
+ char errmsg[80];
+
+ if (yahooStatus == ID_STATUS_CONNECTING)
+ return 0;
+
+ YAHOO_utils_logversion();
+
+ ylad = y_new0(yahoo_local_account, 1);
+
+ /*
+ * Load Yahoo ID form the database.
+ */
+ if (!DBGetContactSetting(NULL, yahooProtocolName, YAHOO_LOGINID, &dbv)) {
+ if (lstrlen(dbv.pszVal) > 0) {
+ lstrcpyn(ylad->yahoo_id, dbv.pszVal, 255);
+ } else
+ err++;
+ DBFreeVariant(&dbv);
+ } else
+ err++;
+
+ if (err) {
+ lstrcpyn(errmsg, Translate("Please enter your yahoo id in Options/Network/Yahoo"), 80);
+ } else {
+ if (!DBGetContactSetting(NULL, yahooProtocolName, YAHOO_PASSWORD, &dbv)) {
+ CallService(MS_DB_CRYPT_DECODESTRING, lstrlen(dbv.pszVal) + 1, (LPARAM) dbv.pszVal);
+ if (lstrlen(dbv.pszVal) > 0) {
+ lstrcpyn(ylad->password, dbv.pszVal, 255);
+ } else
+ err++;
+
+ DBFreeVariant(&dbv);
+ } else
+ err++;
+
+ if (err) {
+ lstrcpyn(errmsg, Translate("Please enter your yahoo password in Options/Network/Yahoo"), 80);
+ }
+ }
+
+ if (err != 0){
+ FREE(ylad);
+ ylad = NULL;
+ yahoo_util_broadcaststatus(ID_STATUS_OFFLINE);
+
+ YAHOO_ShowError(Translate("Yahoo Login Error"), errmsg);
+ return 0;
+ }
+
+ if (status == ID_STATUS_OFFLINE)
+ status = ID_STATUS_ONLINE;
+
+ //DBWriteContactSettingWord(NULL, yahooProtocolName, "StartupStatus", status);
+ gStartStatus = status;
+
+ yahoo_util_broadcaststatus(ID_STATUS_CONNECTING);
+
+ status = (status == ID_STATUS_INVISIBLE) ? YAHOO_STATUS_INVISIBLE: YAHOO_STATUS_AVAILABLE;
+ pthread_create(yahoo_server_main, (void *) status );
+
+ //start_timer();
+ } else if (status == ID_STATUS_INVISIBLE){ /* other normal away statuses are set via setaway */
+ yahoo_util_broadcaststatus(status);
+ yahoo_set_status(yahooStatus,NULL,(yahooStatus != ID_STATUS_ONLINE) ? 1 : 0);
+ } else {
+ /* clear out our message just in case, STUPID AA! */
+ if (szStartMsg) free(szStartMsg);
+
+ szStartMsg = NULL;
+
+ /* now tell miranda that we are Online, don't tell Yahoo server yet though! */
+ yahoo_util_broadcaststatus(status);
+ }
+ return 0;
+}
+
+//=======================================================
+//Broadcast the user status
+//=======================================================
+void yahoo_util_broadcaststatus(int s)
+{
+ int oldStatus = yahooStatus;
+ if (oldStatus == s)
+ return;
+
+ yahooStatus = s;
+
+ YAHOO_DebugLog("[yahoo_util_broadcaststatus] Old Status: %s (%d), New Status: %s (%d)",
+ NEWSTR_ALLOCA((char *) CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, oldStatus, 0)), oldStatus,
+ NEWSTR_ALLOCA((char *) CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, yahooStatus, 0)), yahooStatus);
+ ProtoBroadcastAck(yahooProtocolName, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE) oldStatus, (LPARAM)yahooStatus);
+}
+
+static int YahooContactDeleted( WPARAM wParam, LPARAM lParam )
+{
+ char* szProto;
+ DBVARIANT dbv;
+
+ YAHOO_DebugLog("[YahooContactDeleted]");
+
+ if ( !yahooLoggedIn ) {//should never happen for Yahoo contacts
+ YAHOO_DebugLog("[YahooContactDeleted] We are not Logged On!!!");
+ return 0;
+ }
+
+ szProto = ( char* )YAHOO_CallService( MS_PROTO_GETCONTACTBASEPROTO, wParam, 0 );
+ if ( szProto == NULL || lstrcmp( szProto, yahooProtocolName )) {
+ YAHOO_DebugLog("[YahooContactDeleted] Not a Yahoo Contact!!!");
+ return 0;
+ }
+
+ // he is not a permanent contact!
+ if (DBGetContactSettingByte(( HANDLE )wParam, "CList", "NotOnList", 0) != 0) {
+ YAHOO_DebugLog("[YahooContactDeleted] Not a permanent buddy!!!");
+ return 0;
+ }
+
+ if ( !DBGetContactSetting(( HANDLE )wParam, yahooProtocolName, YAHOO_LOGINID, &dbv )){
+ YAHOO_DebugLog("[YahooContactDeleted] Removing %s", dbv.pszVal);
+ YAHOO_remove_buddy(dbv.pszVal);
+
+ DBFreeVariant( &dbv );
+ } else {
+ YAHOO_DebugLog("[YahooContactDeleted] Can't retrieve contact Yahoo ID");
+ }
+ return 0;
+}
+
+int YahooSendAuthRequest(WPARAM wParam,LPARAM lParam)
+{
+ YAHOO_DebugLog("[YahooSendAuthRequest]");
+
+ if (lParam && yahooLoggedIn){
+
+ CCSDATA *ccs = (CCSDATA *)lParam;
+
+ if (ccs->hContact){
+
+ DBVARIANT dbv;
+
+ if (!DBGetContactSetting(ccs->hContact, yahooProtocolName, YAHOO_LOGINID, &dbv )) {
+ char *c = NULL;
+
+ if ( ccs->lParam )
+ c = (char *)ccs->lParam;
+
+ YAHOO_DebugLog("Adding buddy:%s Auth:%s", dbv.pszVal, c);
+ YAHOO_add_buddy(dbv.pszVal, "miranda", c);
+ YAHOO_SetString(ccs->hContact, "YGroup", "miranda");
+ DBFreeVariant( &dbv );
+
+ return 0; // Success
+
+ }
+
+ }
+
+ }
+
+ return 1; // Failure
+}
+
+int YahooAddToList(WPARAM wParam,LPARAM lParam)
+{
+ PROTOSEARCHRESULT *psr=(PROTOSEARCHRESULT*)lParam;
+ HANDLE hContact;
+
+ YAHOO_DebugLog("[YahooAddToList]");
+
+ if (!yahooLoggedIn){
+ YAHOO_DebugLog("[YahooAddToList] WARNING: WE ARE OFFLINE!");
+ return 0;
+ }
+
+ if (psr == NULL || psr->cbSize != sizeof( PROTOSEARCHRESULT )) {
+ YAHOO_DebugLog("[YahooAddToList] Empty data passed?");
+ return 0;
+ }
+
+
+
+ hContact = getbuddyH(psr->nick);
+ if (hContact != NULL) {
+ if (DBGetContactSettingByte(hContact, "CList", "NotOnList", 0)) {
+ YAHOO_DebugLog("[YahooAddToList] Temporary Buddy:%s already on our buddy list", psr->nick);
+ //return 0;
+ } else {
+ YAHOO_DebugLog("[YahooAddToList] Buddy:%s already on our buddy list", psr->nick);
+ return 0;
+ }
+ } else if (wParam & PALF_TEMPORARY ) { /* not on our list */
+ YAHOO_DebugLog("[YahooAddToList] Adding Temporary Buddy:%s ", psr->nick);
+ }
+
+ YAHOO_DebugLog("Adding buddy:%s", psr->nick);
+ return (int)add_buddy(psr->nick, psr->nick, wParam);
+}
+
+int YahooAddToListByEvent(WPARAM wParam,LPARAM lParam)
+{
+ DBEVENTINFO dbei;
+ char* nick;
+ HANDLE hContact;
+
+ YAHOO_DebugLog("[YahooAddToListByEvent]");
+ if ( !yahooLoggedIn )
+ return 0;
+
+
+ memset( &dbei, 0, sizeof( dbei ));
+ dbei.cbSize = sizeof( dbei );
+
+ if (( dbei.cbBlob = YAHOO_CallService( MS_DB_EVENT_GETBLOBSIZE, lParam, 0 )) == -1 ) {
+ YAHOO_DebugLog("[YahooAddToListByEvent] ERROR: Can't get blob size.");
+ return 0;
+ }
+
+ YAHOO_DebugLog("[YahooAddToListByEvent] Got blob size: %lu", dbei.cbBlob);
+ dbei.pBlob = ( PBYTE )_alloca( dbei.cbBlob );
+ if ( YAHOO_CallService( MS_DB_EVENT_GET, lParam, ( LPARAM )&dbei )) {
+ YAHOO_DebugLog("[YahooAddToListByEvent] ERROR: Can't get event.");
+ return 0;
+ }
+
+ if ( dbei.eventType != EVENTTYPE_AUTHREQUEST ) {
+ YAHOO_DebugLog("[YahooAddToListByEvent] ERROR: Not authorization.");
+ return 0;
+ }
+
+ if ( strcmp( dbei.szModule, yahooProtocolName )) {
+ YAHOO_DebugLog("[YahooAddToListByEvent] ERROR: Not Yahoo protocol.");
+ return 0;
+ }
+
+ //Adds a contact to the contact list given an auth, added or contacts event
+//wParam=MAKEWPARAM(flags,iContact)
+//lParam=(LPARAM)(HANDLE)hDbEvent
+//Returns a HANDLE to the new contact, or NULL on failure
+//hDbEvent must be either EVENTTYPE_AUTHREQ or EVENTTYPE_ADDED
+//flags are the same as for PS_ADDTOLIST.
+//iContact is only used for contacts events. It is the 0-based index of the
+//contact in the event to add. There is no way to add two or more contacts at
+//once, you should just do lots of calls.
+
+ /* TYPE ADDED
+ blob is: uin(DWORD), hcontact(HANDLE), nick(ASCIIZ), first(ASCIIZ),
+ last(ASCIIZ), email(ASCIIZ)
+
+ TYPE AUTH REQ
+ blob is: uin(DWORD), hcontact(HANDLE), nick(ASCIIZ), first(ASCIIZ),
+ last(ASCIIZ), email(ASCIIZ), reason(ASCIIZ)
+ */
+ //hContact = (HANDLE) ( dbei.pBlob + sizeof( DWORD ));
+
+ nick = ( char* )( dbei.pBlob + sizeof( DWORD )*2 );
+ {
+ char* firstName = nick + lstrlen(nick) + 1;
+ char* lastName = firstName + lstrlen(firstName) + 1;
+ char* email = lastName + lstrlen(lastName) + 1;
+ char* reason = email + lstrlen(email) + 1;
+
+ YAHOO_DebugLog("buddy:%s first:%s last:%s e-mail:%s", nick,
+ firstName, lastName, email);
+ YAHOO_DebugLog("reason:%s ", reason);
+ }
+
+ /* we need to send out a packet to request an add */
+ //YAHOO_add_buddy(nick, "miranda", reason);
+ //return 0;
+ hContact = getbuddyH(nick);
+ if (hContact != NULL) {
+ YAHOO_DebugLog("Temp Buddy found at: %p ", hContact);
+ }
+ return (int)hContact;
+}
+
+int YahooAuthAllow(WPARAM wParam,LPARAM lParam)
+{
+ DBEVENTINFO dbei;
+ char* nick;
+
+ YAHOO_DebugLog("[YahooAuthAllow]");
+ if ( !yahooLoggedIn ) {
+ YAHOO_DebugLog("[YahooAuthAllow] Not Logged In!");
+ return 1;
+ }
+
+
+ memset( &dbei, 0, sizeof( dbei ));
+ dbei.cbSize = sizeof( dbei );
+
+ if (( dbei.cbBlob = YAHOO_CallService( MS_DB_EVENT_GETBLOBSIZE, wParam, 0 )) == -1 )
+ return 1;
+
+ dbei.pBlob = ( PBYTE )_alloca( dbei.cbBlob );
+ if ( YAHOO_CallService( MS_DB_EVENT_GET, wParam, ( LPARAM )&dbei ))
+ return 1;
+
+ if ( dbei.eventType != EVENTTYPE_AUTHREQUEST )
+ return 1;
+
+ if ( strcmp( dbei.szModule, yahooProtocolName ))
+ return 1;
+
+ nick = ( char* )( dbei.pBlob + sizeof( DWORD )*2 );
+
+ YAHOO_DebugLog("Accepting buddy:%s ", nick);
+ //YAHOO_add_buddy(nick, "miranda", NULL);
+ YAHOO_accept(nick);
+
+ return 0;
+}
+
+int YahooAuthDeny(WPARAM wParam,LPARAM lParam)
+{
+ DBEVENTINFO dbei;
+ char* nick;
+ char *handle;
+ char* reason;
+ HANDLE hContact;
+
+ YAHOO_DebugLog("[YahooAuthDeny]");
+ if ( !yahooLoggedIn )
+ return 1;
+
+ memset( &dbei, 0, sizeof( dbei ));
+ dbei.cbSize = sizeof( dbei );
+
+ if (( dbei.cbBlob = YAHOO_CallService( MS_DB_EVENT_GETBLOBSIZE, wParam, 0 )) == -1 ){
+ YAHOO_DebugLog("[YahooAuthDeny] ERROR: Can't get blob size");
+ return 1;
+ }
+
+ dbei.pBlob = ( PBYTE )alloca( dbei.cbBlob );
+ if ( YAHOO_CallService( MS_DB_EVENT_GET, wParam, ( LPARAM )&dbei )){
+ YAHOO_DebugLog("YahooAuthDeny - Can't get db event!");
+ return 1;
+ }
+
+ if ( dbei.eventType != EVENTTYPE_AUTHREQUEST ){
+ YAHOO_DebugLog("YahooAuthDeny - not Authorization event");
+ return 1;
+ }
+
+ if ( strcmp( dbei.szModule, yahooProtocolName )){
+ YAHOO_DebugLog("YahooAuthDeny - wrong module?");
+ return 1;
+ }
+
+ nick = ( char* )( dbei.pBlob + sizeof( DWORD )*2 );
+ handle = ( char* )( dbei.pBlob + sizeof( DWORD ) );
+ reason = (char*)lParam;
+
+ memcpy(&hContact,handle, sizeof(HANDLE));
+
+ /* Need to remove the buddy from our Miranda Lists */
+ YAHOO_DebugLog("Rejecting buddy:%s msg: %s", nick, reason);
+ YAHOO_reject(nick,reason);
+
+ YAHOO_CallService( MS_DB_CONTACT_DELETE, (WPARAM) hContact, 0);
+ return 0;
+}
+
+int YahooRecvAuth(WPARAM wParam,LPARAM lParam)
+{
+ DBEVENTINFO dbei;
+ CCSDATA *ccs=(CCSDATA*)lParam;
+ PROTORECVEVENT *pre=(PROTORECVEVENT*)ccs->lParam;
+
+ YAHOO_DebugLog("[YahooRecvAuth] ");
+ DBDeleteContactSetting(ccs->hContact,"CList","Hidden");
+
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.szModule=yahooProtocolName;
+ dbei.timestamp=pre->timestamp;
+ dbei.flags=pre->flags & (PREF_CREATEREAD?DBEF_READ:0);
+ dbei.eventType=EVENTTYPE_AUTHREQUEST;
+
+ /* Just copy the Blob from PSR_AUTH event. */
+ dbei.cbBlob=pre->lParam;
+ dbei.pBlob=(PBYTE)pre->szMessage;
+ CallService(MS_DB_EVENT_ADD,(WPARAM)NULL,(LPARAM)&dbei);
+
+ return 0;
+}
+
+static void __cdecl yahoo_get_statusthread(HANDLE hContact)
+{
+ CCSDATA ccs1;
+ PROTORECVEVENT pre;
+ int status, l;
+ DBVARIANT dbv;
+ char *gm = NULL, *sm = NULL, *fm;
+ status = DBGetContactSettingWord(hContact, yahooProtocolName, "Status", ID_STATUS_OFFLINE);
+
+ if (status == ID_STATUS_OFFLINE)
+ return;
+
+ /* Check Yahoo Games Message */
+ if (! DBGetContactSetting(( HANDLE )hContact, yahooProtocolName, "YGMsg", &dbv )) {
+ gm = strdup(dbv.pszVal);
+
+ DBFreeVariant( &dbv );
+ }
+
+ //if ( DBGetContactSetting(( HANDLE )hContact, yahooProtocolName, "YMsg", &dbv )) {
+ if ( DBGetContactSetting(( HANDLE )hContact, "CList", "StatusMsg", &dbv )) {
+ sm = yahoo_status_code(DBGetContactSettingWord(hContact, yahooProtocolName, "YStatus", YAHOO_STATUS_OFFLINE));
+ } else {
+ if (lstrlen(dbv.pszVal) < 1)
+ sm = yahoo_status_code(DBGetContactSettingWord(hContact, yahooProtocolName, "YStatus", YAHOO_STATUS_OFFLINE));
+ else
+ sm = strdup(dbv.pszVal);
+
+ DBFreeVariant( &dbv );
+ }
+
+ l = 0;
+ if (gm)
+ l += lstrlen(gm) + 3;
+
+ l += lstrlen(sm) + 1;
+ fm = (char *) malloc(l);
+
+ fm[0] ='\0';
+ if (gm && lstrlen(gm) > 0) {
+ /* BAH YAHOO SUCKS! WHAT A PAIN!
+ find first carriage return add status message then add the rest */
+ char *c = strchr(gm, '\r');
+
+ if (c != NULL) {
+ lstrcpyn(fm,gm, c - gm + 1);
+ fm[c - gm + 1] = '\0';
+ } else
+ lstrcpy(fm, gm);
+
+ lstrcat(fm, ": ");
+ lstrcat(fm, sm);
+
+ if (c != NULL)
+ lstrcat(fm, c);
+ } else {
+ lstrcat(fm, sm);
+ }
+ ccs1.szProtoService = PSR_AWAYMSG;
+ ccs1.hContact = hContact;
+ ccs1.wParam = status;
+ ccs1.lParam = (LPARAM)&pre;
+ pre.flags = 0;
+ pre.timestamp = time(NULL);
+ pre.lParam = 1;
+ pre.szMessage = fm;
+
+ CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs1);
+}
+
+//=======================================================
+//Handle away message
+//=======================================================
+int YahooGetAwayMessage(WPARAM wParam,LPARAM lParam)
+{
+ YAHOO_DebugLog("YahooGetAwayMessage");
+ if (lParam && yahooLoggedIn) {
+ CCSDATA *ccs = (CCSDATA *) lParam;
+ DBVARIANT dbv;
+ int status;
+
+ status = DBGetContactSettingWord(( HANDLE )ccs->hContact, yahooProtocolName, "Status", ID_STATUS_OFFLINE);
+
+ if (status == ID_STATUS_OFFLINE)
+ return 0; /* user offline, what Status message? */
+
+ if ( DBGetContactSetting(( HANDLE )ccs->hContact, yahooProtocolName, YAHOO_LOGINID, &dbv )) {
+ YAHOO_DebugLog("YAHOOGetAwayMessage Can't retrieve buddy id.");
+ return 0;
+ }
+ YAHOO_DebugLog("Buddy %s ", dbv.pszVal);
+
+ DBFreeVariant( &dbv );
+
+ pthread_create(yahoo_get_statusthread, ccs->hContact);
+ return 1; //Success
+
+ }
+
+ return 0; // Failure
+}
+
+int YahooRecvAwayMessage(WPARAM wParam,LPARAM lParam)
+{
+ CCSDATA *ccs;
+ PROTORECVEVENT *pre;
+
+ YAHOO_DebugLog("YahooRecvAwayMessage");
+
+ ccs=(CCSDATA*)lParam;
+ pre=(PROTORECVEVENT*)ccs->lParam;
+
+ YAHOO_DebugLog("Got Msg: %s", pre->szMessage);
+ ProtoBroadcastAck(yahooProtocolName,ccs->hContact,ACKTYPE_AWAYMSG,ACKRESULT_SUCCESS,(HANDLE)pre->lParam,(LPARAM)pre->szMessage);
+ return 0;
+}
+
+//=======================================================
+//SetStatusMessage
+//=======================================================
+int YahooSetAwayMessage(WPARAM wParam, LPARAM lParam)
+{
+ char *c;
+
+ c = (char *) lParam;
+ if (c != NULL)
+ if (*c == '\0')
+ c = NULL;
+
+ YAHOO_DebugLog("[YahooSetAwayMessage] Status: %s, Msg: %s",(char *) CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, wParam, 0), (char*) c);
+
+ if(!yahooLoggedIn){
+ if (yahooStatus == ID_STATUS_OFFLINE) {
+ YAHOO_DebugLog("[YahooSetAwayMessage] WARNING: WE ARE OFFLINE!");
+ return 1;
+ } else {
+ if (szStartMsg) free(szStartMsg);
+
+ if (c != NULL)
+ szStartMsg = _strdup(c);
+ else
+ szStartMsg = NULL;
+
+ return 0;
+ }
+ }
+
+ /* need to tell ALL plugins that we are changing status */
+ yahoo_util_broadcaststatus(wParam);
+
+ if (szStartMsg) free(szStartMsg);
+
+ /* now decide what we tell the server */
+ if (c != 0) {
+ szStartMsg = _strdup(c);
+ if(wParam == ID_STATUS_ONLINE) {
+ yahoo_set_status(YAHOO_CUSTOM_STATUS, c, 0);
+ } else if(wParam != ID_STATUS_INVISIBLE){
+ yahoo_set_status(YAHOO_CUSTOM_STATUS, c, 1);
+ }
+ } else {
+ yahoo_set_status(wParam, NULL, 0);
+ szStartMsg = NULL;
+ }
+
+
+ return 0;
+}
+
+static void __cdecl yahoo_get_infothread(HANDLE hContact)
+{
+ SleepEx(500, TRUE);
+ ProtoBroadcastAck(yahooProtocolName, hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE) 1, 0);
+}
+
+int YahooGetInfo(WPARAM wParam,LPARAM lParam)
+{
+ CCSDATA *ccs = (CCSDATA *) lParam;
+ pthread_create(yahoo_get_infothread, ccs->hContact);
+ return 0;
+}
+
+//=======================================================
+//Custom status message windows handling
+//=======================================================
+static BOOL CALLBACK DlgProcSetCustStat(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+// char str[ 4096 ];
+ DBVARIANT dbv;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault( hwndDlg );
+ SendMessage( hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon( hinstance, MAKEINTRESOURCE( IDI_YAHOO )));
+
+ if ( !DBGetContactSetting( NULL, yahooProtocolName, YAHOO_CUSTSTATDB, &dbv ))
+ {
+ SetDlgItemText( hwndDlg, IDC_CUSTSTAT, dbv. pszVal );
+
+ EnableWindow( GetDlgItem( hwndDlg, IDOK ), lstrlen(dbv.pszVal) > 0 );
+ DBFreeVariant( &dbv );
+ }
+ else {
+ SetDlgItemText( hwndDlg, IDC_CUSTSTAT, "" );
+ EnableWindow( GetDlgItem( hwndDlg, IDOK ), FALSE );
+ }
+
+
+ CheckDlgButton( hwndDlg, IDC_CUSTSTATBUSY, YAHOO_GetByte( "BusyCustStat", 0 ));
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch(wParam)
+ {
+ case IDOK:
+ {
+ char str[ 255 + 1 ];
+
+ /* Get String from dialog */
+ GetDlgItemText( hwndDlg, IDC_CUSTSTAT, str, sizeof( str ));
+
+ /* Save it for later use */
+ YAHOO_SetString( NULL, YAHOO_CUSTSTATDB, str );
+ YAHOO_SetByte("BusyCustStat", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_CUSTSTATBUSY ));
+
+ /* set for Idle/AA */
+ if (szStartMsg) free(szStartMsg);
+ szStartMsg = _strdup(str);
+
+ /* notify Server about status change */
+ yahoo_set_status(YAHOO_CUSTOM_STATUS, str, ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_CUSTSTATBUSY ));
+
+ /* change local/miranda status */
+ yahoo_util_broadcaststatus(( BYTE )IsDlgButtonChecked( hwndDlg, IDC_CUSTSTATBUSY ) ?
+ ID_STATUS_AWAY : ID_STATUS_ONLINE);
+ }
+ case IDCANCEL:
+ DestroyWindow( hwndDlg );
+ break;
+ }
+
+ if ( HIWORD( wParam ) == EN_CHANGE && ( HWND )lParam == GetFocus()) {
+ if (LOWORD( wParam ) == IDC_CUSTSTAT) {
+ char str[ 255 + 1 ];
+
+ BOOL toSet;
+
+ toSet = GetDlgItemText( hwndDlg, IDC_CUSTSTAT, str, sizeof( str )) != 0;
+
+ EnableWindow( GetDlgItem( hwndDlg, IDOK ), toSet );
+ }
+ }
+ break; /* case WM_COMMAND */
+
+ case WM_CLOSE:
+ DestroyWindow( hwndDlg );
+ break;
+ }
+ return FALSE;
+}
+
+//=======================================================
+//Show custom status windows
+//=======================================================
+static int SetCustomStatCommand( WPARAM wParam, LPARAM lParam )
+{
+ HWND hwndSetCustomStatus;
+
+ if ( !yahooLoggedIn ) {
+ YAHOO_shownotification(Translate("Yahoo Error"), Translate("You need to be connected to set the custom message"), NIIF_ERROR);
+ return 0;
+ }
+
+ hwndSetCustomStatus = CreateDialog(hinstance, MAKEINTRESOURCE( IDD_SETCUSTSTAT ), NULL, DlgProcSetCustStat );
+
+ SetForegroundWindow( hwndSetCustomStatus );
+ SetFocus( hwndSetCustomStatus );
+ ShowWindow( hwndSetCustomStatus, SW_SHOW );
+ return 0;
+}
+
+//=======================================================
+//Open URL
+//=======================================================
+void YahooOpenURL(const char *url, int autoLogin)
+{
+ char tUrl[ 4096 ];
+
+ if (autoLogin && YAHOO_GetByte( "MailAutoLogin", 0 ) && yahooLoggedIn) {
+ int id = 1;
+ char *y, *t, *u;
+
+ y = yahoo_urlencode(yahoo_get_cookie(id, "y"));
+ t = yahoo_urlencode(yahoo_get_cookie(id, "t"));
+ u = yahoo_urlencode(url);
+ _snprintf( tUrl, sizeof( tUrl ),
+ "http://msg.edit.yahoo.com/config/reset_cookies?&.y=Y=%s&.t=T=%s&.ver=2&.done=http%%3a//us.rd.yahoo.com/messenger/client/%%3f%s",
+ y, t, u);
+
+ FREE(y);
+ FREE(t);
+ FREE(u);
+ } else {
+ _snprintf( tUrl, sizeof( tUrl ), url );
+ }
+
+ YAHOO_DebugLog("[YahooOpenURL] url: %s Final URL: %s", url, tUrl);
+
+ CallService( MS_UTILS_OPENURL, TRUE, ( LPARAM )tUrl );
+}
+
+//=======================================================
+//Show buddy profile
+//=======================================================
+static int YahooShowProfileCommand( WPARAM wParam, LPARAM lParam )
+{
+ char tUrl[ 4096 ];
+ DBVARIANT dbv;
+
+ if ( DBGetContactSetting(( HANDLE )wParam, yahooProtocolName, "yahoo_id", &dbv ))
+ return 0;
+
+ _snprintf( tUrl, sizeof( tUrl ), "http://profiles.yahoo.com/%s", dbv.pszVal );
+ DBFreeVariant( &dbv );
+
+ YahooOpenURL(tUrl, 0);
+ return 0;
+}
+
+//=======================================================
+//Show My profile
+//=======================================================
+static int YahooShowMyProfileCommand( WPARAM wParam, LPARAM lParam )
+{
+ char tUrl[ 4096 ];
+ DBVARIANT dbv;
+
+ DBGetContactSetting( NULL, yahooProtocolName, YAHOO_LOGINID, &dbv );
+
+ _snprintf( tUrl, sizeof( tUrl ), "http://profiles.yahoo.com/%s", dbv.pszVal );
+ DBFreeVariant( &dbv );
+
+ YahooOpenURL(tUrl, 0);
+
+ return 0;
+}
+
+//=======================================================
+//Show Goto mailbox
+//=======================================================
+int YahooGotoMailboxCommand( WPARAM wParam, LPARAM lParam )
+{
+ YahooOpenURL("http://mail.yahoo.com/", 1);
+
+ return 0;
+}
+
+static int YahooABCommand( WPARAM wParam, LPARAM lParam )
+{
+ YahooOpenURL("http://address.yahoo.com/yab/", 1);
+
+ return 0;
+}
+
+static int YahooCalendarCommand( WPARAM wParam, LPARAM lParam )
+{
+ YahooOpenURL("http://calendar.yahoo.com/", 1);
+
+ return 0;
+}
+
+//=======================================================
+//Refresh Yahoo
+//=======================================================
+static int YahooRefreshCommand( WPARAM wParam, LPARAM lParam )
+{
+ if ( !yahooLoggedIn ){
+ YAHOO_shownotification(Translate("Yahoo Error"), Translate("You need to be connected to refresh your buddy list"), NIIF_ERROR);
+ return 0;
+ }
+
+ YAHOO_refresh();
+ return 0;
+}
+
+int YAHOOSendTyping(WPARAM wParam, LPARAM lParam)
+{
+ DBVARIANT dbv;
+ char *szProto;
+ HANDLE hContact = (HANDLE)wParam;
+ int state = (int)lParam;
+
+ if (!yahooLoggedIn)
+ return 0;
+
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (szProto==NULL || strcmp(szProto, yahooProtocolName)) return 0;
+ if (!DBGetContactSetting(hContact, yahooProtocolName, YAHOO_LOGINID, &dbv)) {
+ if (state==PROTOTYPE_SELFTYPING_OFF || state==PROTOTYPE_SELFTYPING_ON) {
+ YAHOO_sendtyping(dbv.pszVal, state == PROTOTYPE_SELFTYPING_ON?1:0);
+ }
+ DBFreeVariant(&dbv);
+ }
+ return 0;
+}
+
+int YahooIdleEvent(WPARAM wParam, LPARAM lParam)
+{
+ BOOL bIdle = (lParam & IDF_ISIDLE);
+
+ YAHOO_DebugLog("[YAHOO_IDLE_EVENT] Idle: %s", bIdle ?"Yes":"No");
+
+ if ( lParam & IDF_PRIVACY )
+ return 0; /* we support Privacy settings */
+
+ if (yahooLoggedIn) {
+ /* set me to idle or back */
+ if (yahooStatus == ID_STATUS_INVISIBLE)
+ YAHOO_DebugLog("[YAHOO_IDLE_EVENT] WARNING: INVISIBLE! Don't change my status!");
+ else
+ yahoo_set_status(yahooStatus,szStartMsg,(bIdle) ? 2 : (yahooStatus == ID_STATUS_ONLINE) ? 0 : 1);
+ } else {
+ YAHOO_DebugLog("[YAHOO_IDLE_EVENT] WARNING: NOT LOGGED IN???");
+ }
+
+ return 0;
+}
+
+int YahooSetApparentMode(WPARAM wParam, LPARAM lParam)
+{
+ int oldMode;
+ CCSDATA *ccs = (CCSDATA *) lParam;
+
+ if (ccs->wParam && ccs->wParam != ID_STATUS_OFFLINE)
+ return 1;
+
+ oldMode = DBGetContactSettingWord(ccs->hContact, yahooProtocolName, "ApparentMode", 0);
+
+ if ((int) ccs->wParam == oldMode)
+ return 1;
+
+ DBWriteContactSettingWord(ccs->hContact, yahooProtocolName, "ApparentMode", (WORD) ccs->wParam);
+ return 1;
+}
+
+extern HANDLE hHookContactDeleted;
+extern HANDLE hHookIdle;
+
+//=======================================================
+//Load the yahoo service/plugin
+//=======================================================
+int LoadYahooServices( void )
+{
+ if (!YAHOO_GetByte( "DisableMainMenu", 0 ))
+ {
+ char servicefunction[ 100 ];
+ char* tDest;
+ CLISTMENUITEM mi;
+
+ lstrcpy( servicefunction, yahooProtocolName );
+ tDest = servicefunction + lstrlen( servicefunction );
+
+ // Show custom status menu
+ lstrcpy( tDest, YAHOO_SET_CUST_STAT );
+ CreateServiceFunction( servicefunction, SetCustomStatCommand );
+ memset( &mi, 0, sizeof( mi ));
+ mi.pszPopupName = yahooProtocolName;
+ mi.cbSize = sizeof( mi );
+ mi.popupPosition = 500090000;
+ mi.position = 500090000;
+ mi.hIcon = LoadIcon( hinstance, MAKEINTRESOURCE( IDI_SET_STATUS ));
+ mi.pszName = Translate( "Set &Custom Status" );
+ mi.pszService = servicefunction;
+ YahooMenuItems [ 0 ] = ( HANDLE )CallService( MS_CLIST_ADDMAINMENUITEM, 0, (LPARAM)&mi );
+
+ // Show My profile menu
+ lstrcpy( tDest, YAHOO_SHOW_MY_PROFILE );
+ CreateServiceFunction( servicefunction, YahooShowMyProfileCommand );
+ mi.position = 500090005;
+ mi.hIcon = LoadIcon( hinstance, MAKEINTRESOURCE( IDI_PROFILE ));
+ mi.pszName = Translate( "&My Profile" );
+ mi.pszService = servicefunction;
+ YahooMenuItems [ 1 ] = ( HANDLE )CallService( MS_CLIST_ADDMAINMENUITEM, 0, ( LPARAM )&mi );
+
+ // Show Yahoo mail menu
+ strcpy( tDest, YAHOO_YAHOO_MAIL );
+ CreateServiceFunction( servicefunction, YahooGotoMailboxCommand );
+ mi.position = 500090010;
+ mi.hIcon = LoadIcon( hinstance, MAKEINTRESOURCE( IDI_INBOX ));
+ mi.pszName = Translate( "&Yahoo Mail" );
+ mi.pszService = servicefunction;
+ YahooMenuItems [ 2 ] = ( HANDLE )CallService( MS_CLIST_ADDMAINMENUITEM, 0, ( LPARAM )&mi );
+
+ // Show refresh menu
+ strcpy( tDest, YAHOO_AB );
+ CreateServiceFunction( servicefunction, YahooABCommand );
+ mi.position = 500090015;
+ mi.hIcon = LoadIcon( hinstance, MAKEINTRESOURCE( IDI_YAB ));
+ mi.pszName = Translate( "&Address Book" );
+ mi.pszService = servicefunction;
+ YahooMenuItems [ 3 ] = ( HANDLE )CallService( MS_CLIST_ADDMAINMENUITEM, 0, ( LPARAM )&mi );
+
+ // Show refresh menu
+ strcpy( tDest, YAHOO_CALENDAR );
+ CreateServiceFunction( servicefunction, YahooCalendarCommand );
+ mi.position = 500090015;
+ mi.hIcon = LoadIcon( hinstance, MAKEINTRESOURCE( IDI_CALENDAR ));
+ mi.pszName = Translate( "&Calendar" );
+ mi.pszService = servicefunction;
+ YahooMenuItems [ 4 ] = ( HANDLE )CallService( MS_CLIST_ADDMAINMENUITEM, 0, ( LPARAM )&mi );
+
+ // Show refresh menu
+ strcpy( tDest, YAHOO_REFRESH );
+ CreateServiceFunction( servicefunction, YahooRefreshCommand );
+ mi.position = 500090015;
+ mi.hIcon = LoadIcon( hinstance, MAKEINTRESOURCE( IDI_REFRESH ));
+ mi.pszName = Translate( "&Refresh" );
+ mi.pszService = servicefunction;
+ YahooMenuItems [ 5 ] = ( HANDLE )CallService( MS_CLIST_ADDMAINMENUITEM, 0, ( LPARAM )&mi );
+
+ // Show show profile menu
+ strcpy( tDest, YAHOO_SHOW_PROFILE );
+ CreateServiceFunction( servicefunction, YahooShowProfileCommand );
+ mi.position = -2000006000;
+ mi.hIcon = LoadIcon( hinstance, MAKEINTRESOURCE( IDI_PROFILE ));
+ mi.pszName = Translate( "&Show Profile" );
+ mi.pszService = servicefunction;
+ mi.pszContactOwner = yahooProtocolName;
+ YahooMenuItems [ 6 ] = ( HANDLE )CallService( MS_CLIST_ADDCONTACTMENUITEM, 0, ( LPARAM )&mi );
+
+ }
+
+ //----| Service creation |------------------------------------------------------------
+ hHookContactDeleted = HookEvent( ME_DB_CONTACT_DELETED, YahooContactDeleted );
+
+ // Send Nudge
+ YAHOO_CreateProtoServiceFunction( YAHOO_SEND_NUDGE, YahooSendNudge );
+
+ YAHOO_CreateProtoServiceFunction( PS_GETCAPS, GetCaps );
+ YAHOO_CreateProtoServiceFunction( PS_GETNAME, GetName );
+ YAHOO_CreateProtoServiceFunction( PS_LOADICON, YahooLoadIcon );
+ YAHOO_CreateProtoServiceFunction( PS_SETSTATUS, SetStatus );
+ YAHOO_CreateProtoServiceFunction( PS_GETSTATUS, GetStatus );
+
+ YAHOO_CreateProtoServiceFunction( PS_BASICSEARCH, YahooBasicSearch );
+ YAHOO_CreateProtoServiceFunction( PS_ADDTOLIST, YahooAddToList );
+
+ YAHOO_CreateProtoServiceFunction( PS_AUTHALLOW, YahooAuthAllow );
+ YAHOO_CreateProtoServiceFunction( PS_AUTHDENY, YahooAuthDeny );
+ YAHOO_CreateProtoServiceFunction( PS_ADDTOLISTBYEVENT, YahooAddToListByEvent );
+
+ YAHOO_CreateProtoServiceFunction( PS_FILERESUME, YahooFileResume );
+
+
+ YAHOO_CreateProtoServiceFunction( PSR_AUTH, YahooRecvAuth );
+ YAHOO_CreateProtoServiceFunction( PSS_AUTHREQUEST, YahooSendAuthRequest);
+ ///
+ YAHOO_CreateProtoServiceFunction( PSS_MESSAGE, YahooSendMessage );
+ YAHOO_CreateProtoServiceFunction( PSS_MESSAGE"W", YahooSendMessageW );
+
+ YAHOO_CreateProtoServiceFunction( PSR_MESSAGE, YahooRecvMessage );
+
+ YAHOO_CreateProtoServiceFunction( PSS_GETAWAYMSG, YahooGetAwayMessage );
+ YAHOO_CreateProtoServiceFunction( PSR_AWAYMSG, YahooRecvAwayMessage );
+
+ YAHOO_CreateProtoServiceFunction( PS_SETAWAYMSG, YahooSetAwayMessage );
+
+ YAHOO_CreateProtoServiceFunction( PSS_GETINFO, YahooGetInfo );
+
+ YAHOO_CreateProtoServiceFunction( PSS_USERISTYPING, YAHOOSendTyping );
+
+ //Allows a file transfer to begin
+ YAHOO_CreateProtoServiceFunction( PSS_FILEALLOW, YahooFileAllow );
+ //Refuses a file transfer request
+ YAHOO_CreateProtoServiceFunction( PSS_FILEDENY, YahooFileDeny );
+
+ //Cancel an in-progress file transfer
+ YAHOO_CreateProtoServiceFunction( PSS_FILECANCEL, YahooFileCancel );
+ //Initiate a file send
+ YAHOO_CreateProtoServiceFunction( PSS_FILE, YahooSendFile );
+ //File(s) have been received
+ YAHOO_CreateProtoServiceFunction( PSR_FILE, YahooRecvFile );
+
+ YAHOO_CreateProtoServiceFunction( PSS_SETAPPARENTMODE, YahooSetApparentMode);
+
+ YAHOO_CreateProtoServiceFunction( PS_GETAVATARINFO, YahooGetAvatarInfo);
+ YAHOO_CreateProtoServiceFunction( PS_GETMYAVATARMAXSIZE, YahooGetAvatarSize);
+ YAHOO_CreateProtoServiceFunction( PS_GETMYAVATAR, YahooGetMyAvatar);
+ YAHOO_CreateProtoServiceFunction( PS_SETMYAVATAR, YahooSetMyAvatar);
+ YAHOO_CreateProtoServiceFunction( PS_ISAVATARFORMATSUPPORTED, YahooAvatarFormatSupported);
+ return 0;
+}
+
diff --git a/miranda-wine/protocols/Yahoo/util.c b/miranda-wine/protocols/Yahoo/util.c
new file mode 100644
index 0000000..43fc2f2
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/util.c
@@ -0,0 +1,386 @@
+/*
+ * $Id: util.c 3676 2006-09-01 18:02:28Z gena01 $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+#include <windows.h>
+#include <windowsx.h>
+#include <stdio.h>
+#include <shlwapi.h>
+#include <malloc.h>
+
+#include "yahoo.h"
+#include <m_popup.h>
+#include <m_system.h>
+#include <m_protomod.h>
+#include <m_protosvc.h>
+#include <m_langpack.h>
+#include <m_skin.h>
+#include <m_utils.h>
+#include <m_options.h>
+
+#include "resource.h"
+
+HANDLE __stdcall YAHOO_CreateProtoServiceFunction(
+ const char* szService,
+ MIRANDASERVICE serviceProc )
+{
+ char str[ MAXMODULELABELLENGTH ];
+
+ strcpy( str, yahooProtocolName );
+ strcat( str, szService );
+
+ return CreateServiceFunction( str, serviceProc );
+}
+
+int __stdcall YAHOO_CallService( const char* szSvcName, WPARAM wParam, LPARAM lParam )
+{
+ return CallService( szSvcName, wParam, lParam );
+}
+
+
+int YAHOO_DebugLog( const char *fmt, ... )
+{
+ char str[ 4096 ];
+ va_list vararg;
+ int tBytes;
+
+ va_start( vararg, fmt );
+
+ tBytes = _vsnprintf( str, sizeof( str ), fmt, vararg );
+ if ( tBytes > 0 )
+ str[ tBytes ] = 0;
+
+ va_end( vararg );
+
+ return CallService( MS_NETLIB_LOG, ( WPARAM )hNetlibUser, ( LPARAM )str );
+}
+
+DWORD __stdcall YAHOO_GetByte( const char* valueName, int parDefltValue )
+{
+ return DBGetContactSettingByte( NULL, yahooProtocolName, valueName, parDefltValue );
+}
+
+DWORD __stdcall YAHOO_SetByte( const char* valueName, int parValue )
+{
+ return DBWriteContactSettingByte( NULL, yahooProtocolName, valueName, parValue );
+}
+
+DWORD __stdcall YAHOO_GetDword( const char* valueName, DWORD parDefltValue )
+{
+ return DBGetContactSettingDword( NULL, yahooProtocolName, valueName, parDefltValue );
+}
+
+DWORD __stdcall YAHOO_SetDword( const char* valueName, DWORD parValue )
+{
+ return DBWriteContactSettingDword(NULL, yahooProtocolName, valueName, parValue);
+}
+
+DWORD __stdcall YAHOO_SetWord( HANDLE hContact, const char* valueName, int parValue )
+{
+ return DBWriteContactSettingWord( hContact, yahooProtocolName, valueName, parValue );
+}
+
+WORD __stdcall YAHOO_GetWord( HANDLE hContact, const char* valueName, int parDefltValue )
+{
+ return DBGetContactSettingWord( hContact, yahooProtocolName, valueName, parDefltValue );
+}
+
+int __stdcall YAHOO_SendBroadcast( HANDLE hContact, int type, int result, HANDLE hProcess, LPARAM lParam )
+{
+ ACKDATA ack;
+
+ ZeroMemory(&ack, sizeof(ack) );
+
+ ack.cbSize = sizeof( ACKDATA );
+ ack.szModule = yahooProtocolName;
+ ack.hContact = hContact;
+ ack.type = type;
+ ack.result = result;
+ ack.hProcess = hProcess;
+ ack.lParam = lParam;
+ return YAHOO_CallService( MS_PROTO_BROADCASTACK, 0, ( LPARAM )&ack );
+}
+
+DWORD __stdcall YAHOO_SetString( HANDLE hContact, const char* valueName, const char* parValue )
+{
+ return DBWriteContactSettingString( hContact, yahooProtocolName, valueName, parValue );
+}
+
+DWORD __stdcall YAHOO_SetStringUtf( HANDLE hContact, const char* valueName, const char* parValue )
+{
+ return DBWriteContactSettingStringUtf( hContact, yahooProtocolName, valueName, parValue );
+}
+
+LRESULT CALLBACK PopupWindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
+{
+ switch( message ) {
+ case WM_COMMAND:
+ YAHOO_DebugLog("[MS_POPUP_ADDPOPUPEX] WM_COMMAND");
+ if ( HIWORD( wParam ) == STN_CLICKED) {
+ char *szURL = (char *)PUGetPluginData( hWnd );
+ if ( szURL != NULL ) {
+ YahooOpenURL(szURL, 1);
+ FREE(szURL);
+ }
+
+ PUDeletePopUp( hWnd );
+ return 0;
+ }
+ break;
+
+ case WM_CONTEXTMENU:
+ YAHOO_DebugLog("[MS_POPUP_ADDPOPUPEX] WM_CONTEXTMENU");
+ PUDeletePopUp( hWnd );
+ break;
+
+ }
+
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+
+int __stdcall YAHOO_ShowPopup( const char* nickname, const char* msg, const char *szURL )
+{
+ POPUPDATAEX ppd;
+
+ if ( !ServiceExists( MS_POPUP_ADDPOPUPEX ))
+ return 0;
+
+ ZeroMemory(&ppd, sizeof(ppd) );
+ lstrcpy( ppd.lpzContactName, nickname );
+ lstrcpy( ppd.lpzText, msg );
+
+ ppd.PluginWindowProc = ( WNDPROC )PopupWindowProc;
+
+ if (szURL != NULL) {
+ if (lstrcmpi(szURL, "http://mail.yahoo.com") == 0) {
+ ppd.lchIcon = LoadIcon( hinstance, MAKEINTRESOURCE( IDI_INBOX ));
+ } else {
+ ppd.lchIcon = LoadIcon( hinstance, MAKEINTRESOURCE( IDI_CALENDAR ));
+ }
+
+ ppd.PluginData = (void *)strdup( szURL );
+ } else {
+ ppd.lchIcon = LoadIcon( hinstance, MAKEINTRESOURCE( IDI_MAIN ));
+ }
+ YAHOO_DebugLog("[MS_POPUP_ADDPOPUPEX] Generating a popup for %s", nickname);
+ YAHOO_CallService( MS_POPUP_ADDPOPUPEX, (WPARAM)&ppd, 0 );
+
+ return 1;
+}
+
+int YAHOO_shownotification(const char *title, const char *info, DWORD flags)
+{
+ if (ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) {
+ MIRANDASYSTRAYNOTIFY err;
+ int ret;
+
+ err.szProto = yahooProtocolName;
+ err.cbSize = sizeof(err);
+ err.szInfoTitle = (char *)title;
+ err.szInfo = (char *)info;
+ err.dwInfoFlags = flags;
+ err.uTimeout = 1000 * 3;
+ ret = CallService(MS_CLIST_SYSTRAY_NOTIFY, 0, (LPARAM) & err);
+
+ if (ret == 0)
+ return 1;
+ }
+
+ MessageBox(NULL, info, title, MB_OK | MB_ICONINFORMATION);
+
+ return 0;
+}
+
+void YAHOO_ShowError(const char *title, const char *buff)
+{
+ if (YAHOO_GetByte( "ShowErrors", 1 ))
+ if (!YAHOO_ShowPopup(title, buff, NULL))
+ YAHOO_shownotification(title, buff, NIIF_ERROR);
+}
+
+int YAHOO_util_dbsettingchanged(WPARAM wParam, LPARAM lParam)
+{
+ DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *) lParam;
+
+ if ((HANDLE) wParam == NULL)
+ return 0;
+ if (!yahooLoggedIn)
+ return 0;
+
+ if (!strcmp(cws->szModule, "CList") && !strcmp(cws->szModule, yahooProtocolName)) {
+ // A temporary contact has been added permanently
+ if (!strcmp(cws->szSetting, "NotOnList")) {
+ if (DBGetContactSettingByte((HANDLE) wParam, "CList", "Hidden", 0))
+ return 0;
+ if (cws->value.type == DBVT_DELETED || (cws->value.type == DBVT_BYTE && cws->value.bVal == 0)) {
+ char *szProto;
+ DBVARIANT dbv;
+
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (szProto==NULL || strcmp(szProto, yahooProtocolName)) return 0;
+
+ if ( !DBGetContactSetting( (HANDLE) wParam, yahooProtocolName, YAHOO_LOGINID, &dbv )){
+ YAHOO_DebugLog("Adding Permanently %s to list.", dbv.pszVal);
+ YAHOO_add_buddy(dbv.pszVal, "miranda", NULL);
+ DBFreeVariant(&dbv);
+ }
+
+ }
+ }
+ }else if (!strcmp(cws->szModule, yahooProtocolName) && !strcmp(cws->szSetting, "ApparentMode")) {
+ DBVARIANT dbv;
+
+ YAHOO_DebugLog("DB Setting changed. YAHOO user's visible setting changed.");
+
+ if ( !DBGetContactSetting( (HANDLE) wParam, yahooProtocolName, YAHOO_LOGINID, &dbv )){
+ int iAdd;
+
+
+ iAdd = (ID_STATUS_OFFLINE == DBGetContactSettingWord((HANDLE) wParam, yahooProtocolName, "ApparentMode", 0));
+ yahoo_stealth(dbv.pszVal, iAdd);
+ DBFreeVariant(&dbv);
+ }
+
+ }
+ return 0;
+}
+
+char* YAHOO_GetContactName( HANDLE hContact )
+{
+ return ( char* )YAHOO_CallService( MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) hContact, 0 );
+}
+
+extern PLUGININFO pluginInfo;
+
+/*
+ * Thanks Robert for the following function. Copied from AIM plugin.
+ */
+void YAHOO_utils_logversion()
+{
+ char str[256];
+
+#ifdef YAHOO_CVSBUILD
+ _snprintf(str, sizeof(str), "Yahoo v%d.%d.%d.%da (%s %s)", (pluginInfo.version >> 24) & 0xFF, (pluginInfo.version >> 16) & 0xFF,
+ (pluginInfo.version >> 8) & 0xFF, pluginInfo.version & 0xFF, __DATE__, __TIME__);
+#else
+ _snprintf(str, sizeof(str), "Yahoo v%d.%d.%d.%d", (pluginInfo.version >> 24) & 0xFF, (pluginInfo.version >> 16) & 0xFF,
+ (pluginInfo.version >> 8) & 0xFF, pluginInfo.version & 0xFF);
+#endif
+ YAHOO_DebugLog(str);
+#ifdef YAHOO_CVSBUILD
+ YAHOO_DebugLog("You are using a development version of Yahoo. Please make sure you are using the latest version before posting bug reports.");
+#endif
+}
+
+//=======================================================================================
+// Utf8Decode - converts UTF8-encoded string to the UCS2/MBCS format
+//=======================================================================================
+
+void __stdcall Utf8Decode( char* str, int maxSize, wchar_t** ucs2 )
+{
+ wchar_t* tempBuf;
+
+ int len = strlen( str );
+ if ( len < 2 ) {
+ if ( ucs2 != NULL ) {
+ *ucs2 = ( wchar_t* )malloc(( len+1 )*sizeof( wchar_t ));
+ MultiByteToWideChar( CP_ACP, 0, str, len, *ucs2, len );
+ ( *ucs2 )[ len ] = 0;
+ }
+ return;
+ }
+
+ tempBuf = ( wchar_t* )alloca(( len+1 )*sizeof( wchar_t ));
+ {
+ wchar_t* d = tempBuf;
+ BYTE* s = ( BYTE* )str;
+
+ while( *s )
+ {
+ if (( *s & 0x80 ) == 0 ) {
+ *d++ = *s++;
+ continue;
+ }
+
+ if (( s[0] & 0xE0 ) == 0xE0 && ( s[1] & 0xC0 ) == 0x80 && ( s[2] & 0xC0 ) == 0x80 ) {
+ *d++ = (( WORD )( s[0] & 0x0F) << 12 ) + ( WORD )(( s[1] & 0x3F ) << 6 ) + ( WORD )( s[2] & 0x3F );
+ s += 3;
+ continue;
+ }
+
+ if (( s[0] & 0xE0 ) == 0xC0 && ( s[1] & 0xC0 ) == 0x80 ) {
+ *d++ = ( WORD )(( s[0] & 0x1F ) << 6 ) + ( WORD )( s[1] & 0x3F );
+ s += 2;
+ continue;
+ }
+
+ *d++ = *s++;
+ }
+
+ *d = 0;
+ }
+
+ if ( ucs2 != NULL ) {
+ int fullLen = ( len+1 )*sizeof( wchar_t );
+ *ucs2 = ( wchar_t* )malloc( fullLen );
+ memcpy( *ucs2, tempBuf, fullLen );
+ }
+
+ if ( maxSize == 0 )
+ maxSize = len;
+
+ WideCharToMultiByte( CP_ACP, 0, tempBuf, -1, str, maxSize, NULL, NULL );
+}
+
+//=======================================================================================
+// Utf8Encode - converts UCS2 string to the UTF8-encoded format
+//=======================================================================================
+
+char* __stdcall Utf8EncodeUcs2( const wchar_t* src )
+{
+ int len = wcslen( src );
+ char* result = ( char* )malloc( len*3 + 1 );
+ if ( result == NULL )
+ return NULL;
+
+ { const wchar_t* s = src;
+ BYTE* d = ( BYTE* )result;
+
+ while( *s ) {
+ int U = *s++;
+
+ if ( U < 0x80 ) {
+ *d++ = ( BYTE )U;
+ }
+ else if ( U < 0x800 ) {
+ *d++ = 0xC0 + (( U >> 6 ) & 0x3F );
+ *d++ = 0x80 + ( U & 0x003F );
+ }
+ else {
+ *d++ = 0xE0 + ( U >> 12 );
+ *d++ = 0x80 + (( U >> 6 ) & 0x3F );
+ *d++ = 0x80 + ( U & 0x3F );
+ } }
+
+ *d = 0;
+ }
+
+ return result;
+}
+
+void SetButtonCheck(HWND hwndDlg, int CtrlID, BOOL bCheck)
+{
+ HWND hwndCtrl = GetDlgItem(hwndDlg, CtrlID);
+
+ Button_SetCheck(hwndCtrl, (bCheck)?BST_CHECKED:BST_UNCHECKED);
+}
+
diff --git a/miranda-wine/protocols/Yahoo/version.h b/miranda-wine/protocols/Yahoo/version.h
new file mode 100644
index 0000000..77d0c4c
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/version.h
@@ -0,0 +1,3 @@
+#define __FILEVERSION_STRING 0,4,0,1
+#define __VERSION_STRING "0.4.0.1"
+#define __VERSION_DWORD 0x00040001
diff --git a/miranda-wine/protocols/Yahoo/version.rc b/miranda-wine/protocols/Yahoo/version.rc
new file mode 100644
index 0000000..88ea147
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/version.rc
@@ -0,0 +1,36 @@
+
+#include <windows.h>
+#include "version.h"
+
+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 "CompanyName", "Gennady Feldman"
+ VALUE "FileDescription", "Miranda Yahoo plugin"
+ VALUE "FileVersion", __VERSION_STRING
+ VALUE "InternalName", "yahoo"
+ VALUE "LegalCopyright", "Copyright (C) 2003-2006 Gennady Feldman"
+ VALUE "OriginalFilename", "yahoo.dll"
+ VALUE "ProductName", "Miranda"
+ VALUE "ProductVersion", __VERSION_STRING
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0, 1200
+ END
+END
diff --git a/miranda-wine/protocols/Yahoo/webcam.c b/miranda-wine/protocols/Yahoo/webcam.c
new file mode 100644
index 0000000..126a8d8
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/webcam.c
@@ -0,0 +1,64 @@
+/*
+ * $Id: webcam.c 3659 2006-08-30 19:43:41Z gena01 $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+#include <time.h>
+#include <sys/stat.h>
+#include <malloc.h>
+#include <io.h>
+
+/*
+ * Miranda headers
+ */
+#include "yahoo.h"
+#include <m_protosvc.h>
+#include <m_langpack.h>
+#include <m_message.h>
+
+extern yahoo_local_account * ylad;
+
+void ext_yahoo_got_im(int id, const char *me, const char *who, const char *msg, long tm, int stat, int utf8, int buddy_icon);
+
+/* WEBCAM callbacks */
+void ext_yahoo_got_webcam_image(int id, const char *who,
+ const unsigned char *image, unsigned int image_size, unsigned int real_size,
+ unsigned int timestamp)
+{
+ LOG(("ext_yahoo_got_webcam_image"));
+}
+
+void ext_yahoo_webcam_viewer(int id, const char *who, int connect)
+{
+ LOG(("ext_yahoo_webcam_viewer"));
+}
+
+void ext_yahoo_webcam_closed(int id, const char *who, int reason)
+{
+ LOG(("ext_yahoo_webcam_closed"));
+}
+
+void ext_yahoo_webcam_data_request(int id, int send)
+{
+ LOG(("ext_yahoo_webcam_data_request"));
+}
+
+void ext_yahoo_webcam_invite(int id, const char *me, const char *from)
+{
+ LOG(("ext_yahoo_webcam_invite"));
+
+ ext_yahoo_got_im(id, me, from, Translate("[miranda] Got webcam invite. (not currently supported)"), 0, 0, 0, -1);
+}
+
+void ext_yahoo_webcam_invite_reply(int id, const char *me, const char *from, int accept)
+{
+ LOG(("ext_yahoo_webcam_invite_reply"));
+}
+
diff --git a/miranda-wine/protocols/Yahoo/webcam.h b/miranda-wine/protocols/Yahoo/webcam.h
new file mode 100644
index 0000000..c33b7c5
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/webcam.h
@@ -0,0 +1,31 @@
+/*
+ * $Id: webcam.h 3627 2006-08-28 16:11:15Z gena01 $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+#ifndef _YAHOO_WEBCAM_H_
+#define _YAHOO_WEBCAM_H_
+
+/* WEBCAM callbacks */
+void ext_yahoo_got_webcam_image(int id, const char *who,
+ const unsigned char *image, unsigned int image_size, unsigned int real_size,
+ unsigned int timestamp);
+
+void ext_yahoo_webcam_viewer(int id, const char *who, int connect);
+
+void ext_yahoo_webcam_closed(int id, const char *who, int reason);
+
+void ext_yahoo_webcam_data_request(int id, int send);
+
+void ext_yahoo_webcam_invite(int id, const char *me, const char *from);
+
+void ext_yahoo_webcam_invite_reply(int id, const char *me, const char *from, int accept);
+
+#endif
diff --git a/miranda-wine/protocols/Yahoo/yahoo.c b/miranda-wine/protocols/Yahoo/yahoo.c
new file mode 100644
index 0000000..07aeb1d
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/yahoo.c
@@ -0,0 +1,1463 @@
+/*
+ * $Id: yahoo.c 3676 2006-09-01 18:02:28Z gena01 $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+#include <time.h>
+#include <malloc.h>
+#include <io.h>
+
+/*
+ * Miranda headers
+ */
+#include "yahoo.h"
+#include <m_protosvc.h>
+#include <m_langpack.h>
+#include <m_skin.h>
+#include <m_popup.h>
+#include <m_message.h>
+
+#include "avatar.h"
+#include "chat.h"
+#include "webcam.h"
+#include "file_transfer.h"
+#include "im.h"
+#include "search.h"
+
+typedef struct {
+ int id;
+ char *label;
+} yahoo_idlabel;
+
+typedef struct {
+ int id;
+ char *who;
+} yahoo_authorize_data;
+
+yahoo_idlabel yahoo_status_codes[] = {
+ {YAHOO_STATUS_AVAILABLE, "Available"},
+ {YAHOO_STATUS_BRB, "BRB"},
+ {YAHOO_STATUS_BUSY, "Busy"},
+ {YAHOO_STATUS_NOTATHOME, "Not At Home"},
+ {YAHOO_STATUS_NOTATDESK, "Not At my Desk"},
+ {YAHOO_STATUS_NOTINOFFICE, "Not In The Office"},
+ {YAHOO_STATUS_ONPHONE, "On The Phone"},
+ {YAHOO_STATUS_ONVACATION, "On Vacation"},
+ {YAHOO_STATUS_OUTTOLUNCH, "Out To Lunch"},
+ {YAHOO_STATUS_STEPPEDOUT, "Stepped Out"},
+ {YAHOO_STATUS_INVISIBLE, "Invisible"},
+ {YAHOO_STATUS_IDLE, "Idle"},
+ {YAHOO_STATUS_OFFLINE, "Offline"},
+ {YAHOO_STATUS_CUSTOM, "[Custom]"},
+ {YAHOO_STATUS_NOTIFY, "Notify"},
+ {0, NULL}
+};
+
+#define MAX_PREF_LEN 255
+
+yahoo_local_account * ylad = NULL;
+
+int do_yahoo_debug = 0;
+#ifdef HTTP_GATEWAY
+int iHTTPGateway = 0;
+#endif
+extern int poll_loop;
+extern int gStartStatus;
+extern char *szStartMsg;
+
+char * yahoo_status_code(enum yahoo_status s)
+{
+ int i;
+ for(i=0; yahoo_status_codes[i].label; i++)
+ if(yahoo_status_codes[i].id == s)
+ return yahoo_status_codes[i].label;
+ return "Unknown";
+}
+
+int miranda_to_yahoo(int myyahooStatus)
+{
+ int ret = YAHOO_STATUS_OFFLINE;
+ switch (myyahooStatus) {
+ case ID_STATUS_ONLINE:
+ ret = YAHOO_STATUS_AVAILABLE;
+ break;
+ case ID_STATUS_NA:
+ ret = YAHOO_STATUS_BRB;
+ break;
+ case ID_STATUS_OCCUPIED:
+ ret = YAHOO_STATUS_BUSY;
+ break;
+ case ID_STATUS_AWAY:
+ ret = YAHOO_STATUS_NOTATDESK;
+ break;
+ case ID_STATUS_ONTHEPHONE:
+ ret = YAHOO_STATUS_ONPHONE;
+ break;
+ case ID_STATUS_OUTTOLUNCH:
+ ret = YAHOO_STATUS_OUTTOLUNCH;
+ break;
+ case ID_STATUS_INVISIBLE:
+ ret = YAHOO_STATUS_INVISIBLE;
+ break;
+ case ID_STATUS_DND:
+ ret = YAHOO_STATUS_STEPPEDOUT;
+ break;
+ }
+
+ return ret;
+}
+
+void yahoo_set_status(int myyahooStatus, char *msg, int away)
+{
+ //LOG(("yahoo_set_status myyahooStatus: %s (%d), msg: %s, away: %d", (char *) CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, myyahooStatus, 0), myyahooStatus, msg, away));
+ LOG(("yahoo_set_status myyahooStatus: %d, msg: %s, away: %d", myyahooStatus, msg, away));
+
+ /* Safety check, don't dereference Invalid pointers */
+ if ((ylad != NULL) && (ylad->id > 0) ) {
+
+ if (YAHOO_CUSTOM_STATUS != myyahooStatus)
+ yahoo_set_away(ylad->id, miranda_to_yahoo(myyahooStatus), msg, away);
+ else
+ yahoo_set_away(ylad->id, YAHOO_CUSTOM_STATUS, msg, away);
+ }
+}
+
+void yahoo_stealth(const char *buddy, int add)
+{
+ LOG(("yahoo_stealth buddy: %s, add: %d", buddy, add));
+
+ /* Safety check, don't dereference Invalid pointers */
+ if ((ylad != NULL) && (ylad->id > 0) ) {
+ yahoo_set_stealth(ylad->id, buddy, add);
+ }
+}
+
+
+int yahoo_to_miranda_status(int yahooStatus, int away)
+{
+ int ret = ID_STATUS_OFFLINE;
+ switch (yahooStatus) {
+ case YAHOO_STATUS_AVAILABLE:
+ ret = ID_STATUS_ONLINE;
+ break;
+ case YAHOO_STATUS_BRB:
+ ret = ID_STATUS_NA;
+ break;
+ case YAHOO_STATUS_BUSY:
+ ret = ID_STATUS_OCCUPIED;
+ break;
+ case YAHOO_STATUS_ONPHONE:
+ ret = ID_STATUS_ONTHEPHONE;
+ break;
+ case YAHOO_STATUS_OUTTOLUNCH:
+ ret = ID_STATUS_OUTTOLUNCH;
+ break;
+ case YAHOO_STATUS_INVISIBLE:
+ ret = ID_STATUS_INVISIBLE;
+ break;
+ case YAHOO_STATUS_NOTATHOME:
+ ret = ID_STATUS_AWAY;
+ break;
+ case YAHOO_STATUS_NOTATDESK:
+ ret = ID_STATUS_AWAY;
+ break;
+ case YAHOO_STATUS_NOTINOFFICE:
+ ret = ID_STATUS_AWAY;
+ break;
+ case YAHOO_STATUS_ONVACATION:
+ ret = ID_STATUS_AWAY;
+ break;
+ case YAHOO_STATUS_STEPPEDOUT:
+ ret = ID_STATUS_DND;
+ break;
+ case YAHOO_STATUS_IDLE:
+ ret = ID_STATUS_AWAY;
+ break;
+ case YAHOO_STATUS_CUSTOM:
+ ret = (away ? ID_STATUS_AWAY:ID_STATUS_ONLINE);
+ break;
+ }
+ return ret;
+}
+
+
+const YList* YAHOO_GetIgnoreList(void)
+{
+ if (!ylad)
+ return NULL;
+
+ return yahoo_get_ignorelist(ylad->id);
+}
+
+void YAHOO_IgnoreBuddy(const char *buddy, int ignore)
+{
+ if (!ylad)
+ return;
+
+ yahoo_ignore_buddy(ylad->id, buddy, ignore);
+ //yahoo_get_list(ylad->id);
+}
+
+void YAHOO_remove_buddy(const char *who)
+{
+ HANDLE hContact;
+ DBVARIANT dbv;
+
+ LOG(("YAHOO_remove_buddy '%s'", who));
+
+ hContact = getbuddyH(who);
+
+ //if ( DBGetContactSetting( hContact, "Clist", "Group", &dbv ))
+ // return;
+ if ( DBGetContactSetting( hContact, yahooProtocolName, "YGroup", &dbv )) {
+ LOG(("WARNING NO DATABASE GROUP using 'miranda'!"));
+ yahoo_remove_buddy(ylad->id, who, "miranda");
+ return;
+ }
+
+ yahoo_remove_buddy(ylad->id, who, dbv.pszVal);
+ DBFreeVariant( &dbv );
+}
+
+void YAHOO_sendtyping(const char *who, int stat)
+{
+ LOG(("[Yahoo_sendtyping] Sending Typing Notification to '%s', state: %d", who, stat));
+ yahoo_send_typing(ylad->id, NULL, who, stat);
+}
+
+void YAHOO_accept(const char *who)
+{
+ yahoo_accept_buddy(ylad->id, who);
+}
+
+void YAHOO_reject(const char *who, const char *msg)
+{
+ yahoo_reject_buddy(ylad->id, who, msg);
+ //YAHOO_remove_buddy(who);
+ //yahoo_refresh(ylad->id);
+}
+
+void yahoo_logout()
+{
+ //poll_loop = 0; <- don't kill us before we do full cleanup!!!
+
+ if (ylad == NULL)
+ return;
+
+ if (ylad->id <= 0) {
+ return;
+ }
+
+ if (yahooLoggedIn) {
+ yahoo_logoff(ylad->id);
+ } else {
+ poll_loop = 0; /* we need to trigger server stop */
+ }
+
+ if (ylad)
+ yahoo_close(ylad->id);
+
+ yahooLoggedIn = FALSE;
+
+ FREE(ylad);
+ ylad = NULL;
+
+ //pthread_mutex_lock(&connectionHandleMutex);
+
+
+ //pthread_mutex_unlock(&connectionHandleMutex);
+}
+
+HANDLE getbuddyH(const char *yahoo_id)
+{
+ char *szProto;
+ HANDLE hContact;
+
+ for ( hContact = ( HANDLE )YAHOO_CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ hContact != NULL;
+ hContact = ( HANDLE )YAHOO_CallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM )hContact, 0 ))
+ {
+ szProto = ( char* )YAHOO_CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact, 0 );
+ if ( szProto != NULL && !lstrcmp( szProto, yahooProtocolName ))
+ {
+ DBVARIANT dbv;
+ if ( DBGetContactSetting( hContact, yahooProtocolName, YAHOO_LOGINID, &dbv ))
+ continue;
+
+ {
+ int tCompareResult = lstrcmpi( dbv.pszVal, yahoo_id );
+ DBFreeVariant( &dbv );
+ if ( tCompareResult )
+ continue;
+ }
+
+ return hContact;
+ }
+ }
+
+ return NULL;
+}
+
+HANDLE add_buddy( const char *yahoo_id, const char *yahoo_name, DWORD flags )
+{
+ //char *szProto;
+ HANDLE hContact;
+ //DBVARIANT dbv;
+
+ hContact = getbuddyH(yahoo_id);
+ if (hContact != NULL) {
+ LOG(("[add_buddy] Found buddy id: %s, handle: %lu", yahoo_id, (DWORD)hContact));
+ if ( !( flags & PALF_TEMPORARY ) && DBGetContactSettingByte( hContact, "CList", "NotOnList", 1 ))
+ {
+ LOG(("[add_buddy] Making Perm id: %s, flags: %lu", yahoo_id, flags));
+ DBDeleteContactSetting( hContact, "CList", "NotOnList" );
+ DBDeleteContactSetting( hContact, "CList", "Hidden" );
+
+ }
+ return hContact;
+ }
+
+ //not already there: add
+ LOG(("[add_buddy] Adding buddy id: %s, flags: %lu", yahoo_id, flags));
+ hContact = ( HANDLE )YAHOO_CallService( MS_DB_CONTACT_ADD, 0, 0 );
+ YAHOO_CallService( MS_PROTO_ADDTOCONTACT, ( WPARAM )hContact,( LPARAM )yahooProtocolName );
+ YAHOO_SetString( hContact, YAHOO_LOGINID, yahoo_id );
+ if (lstrlen(yahoo_name) > 0)
+ YAHOO_SetStringUtf( hContact, "Nick", yahoo_name );
+ else
+ YAHOO_SetStringUtf( hContact, "Nick", yahoo_id );
+
+ //DBWriteContactSettingWord(hContact, yahooProtocolName, "Status", ID_STATUS_OFFLINE);
+
+ if (flags & PALF_TEMPORARY ) {
+ DBWriteContactSettingByte( hContact, "CList", "NotOnList", 1 );
+ DBWriteContactSettingByte( hContact, "CList", "Hidden", 1 );
+ }
+ return hContact;
+}
+
+const char *find_buddy( const char *yahoo_id)
+{
+ //char *szProto;
+ static char nick[128];
+ HANDLE hContact;
+ DBVARIANT dbv;
+
+ hContact = getbuddyH(yahoo_id);
+ if (hContact != NULL) {
+ if ( DBGetContactSetting( hContact, yahooProtocolName, "Nick", &dbv ))
+ return NULL;
+
+ strncpy(nick, dbv.pszVal, 128);
+ DBFreeVariant( &dbv );
+ return nick;
+
+ }
+
+ return NULL;
+}
+
+/* Required handlers bellow */
+
+/* Other handlers */
+void ext_yahoo_status_changed(int id, const char *who, int stat, const char *msg, int away, int idle, int mobile)
+{
+ HANDLE hContact = 0;
+ time_t idlets = 0;
+
+ YAHOO_DebugLog("ext_yahoo_status_changed for %s with msg %s (stat: %d, away: %d, idle: %d seconds)", who, msg, stat, away, idle);
+
+ hContact = getbuddyH(who);
+ if (hContact == NULL) {
+ YAHOO_DebugLog("Buddy Not Found. Adding...");
+ hContact = add_buddy(who, who, 0);
+ } else {
+ YAHOO_DebugLog("Buddy Found On My List! Buddy %p", hContact);
+ }
+
+ if (!mobile)
+ YAHOO_SetWord(hContact, "Status", yahoo_to_miranda_status(stat,away));
+ else
+ YAHOO_SetWord(hContact, "Status", ID_STATUS_ONTHEPHONE);
+
+ YAHOO_SetWord(hContact, "YStatus", stat);
+ YAHOO_SetWord(hContact, "YAway", away);
+ YAHOO_SetWord(hContact, "Mobile", mobile);
+
+ if(msg) {
+ LOG(("%s custom message '%s'", who, msg));
+ //YAHOO_SetString(hContact, "YMsg", msg);
+ //DBWriteContactSettingString( hContact, "CList", "StatusMsg", msg);
+ DBWriteContactSettingStringUtf( hContact, "CList", "StatusMsg", msg);
+ } else {
+ //YAHOO_SetString(hContact, "YMsg", "");
+ DBDeleteContactSetting(hContact, "CList", "StatusMsg" );
+ }
+
+ /*if (stat == YAHOO_STATUS_OFFLINE)
+ DBDeleteContactSetting(hContact, yahooProtocolName, "MirVer" );*/
+
+ if ( (away == 2) || (stat == YAHOO_STATUS_IDLE) || (idle > 0)) {
+ if (stat > 0) {
+ LOG(("%s idle for %d:%02d:%02d", who, idle/3600, (idle/60)%60, idle%60));
+
+ time(&idlets);
+ idlets -= idle;
+ }
+ }
+
+ DBWriteContactSettingDword(hContact, yahooProtocolName, "IdleTS", idlets);
+
+ LOG(("[ext_yahoo_status_changed] exiting"));
+}
+
+void ext_yahoo_status_logon(int id, const char *who, int stat, const char *msg, int away, int idle, int mobile, int cksum, int buddy_icon, long client_version)
+{
+ HANDLE hContact = 0;
+ char *s = NULL;
+
+ LOG(("[ext_yahoo_status_logon] %s with msg %s (stat: %d, away: %d, idle: %d seconds, checksum: %d buddy_icon: %d client_version: %ld)", who, msg, stat, away, idle, cksum, buddy_icon, client_version));
+
+ ext_yahoo_status_changed(id, who, stat, msg, away, idle, mobile);
+ hContact = getbuddyH(who);
+ if (hContact == NULL) {
+ YAHOO_DebugLog("[ext_yahoo_status_logon] Can't find handle for %s??? PANIC!!!", who);
+ return;
+ }
+
+ switch (client_version) {
+ case 262651: s = "libyahoo2"; break;
+ case 262655: s = "< Yahoo 6.x (Yahoo 5.x?)"; break;
+ case 278527: s = "Yahoo 6.x"; break;
+ case 524223: s = "Yahoo 7.x"; break;
+ }
+
+ if (s != NULL)
+ DBWriteContactSettingString( hContact, yahooProtocolName, "MirVer", s);
+
+ /* Last thing check the checksum and request new one if we need to */
+ if (buddy_icon == -1) {
+ LOG(("[ext_yahoo_status_logon] No avatar information in this packet? Not touching stuff!"));
+ } else {
+ // we got some avatartype info
+ DBWriteContactSettingByte(hContact, yahooProtocolName, "AvatarType", buddy_icon);
+
+ if (cksum == 0 || cksum == -1){
+ // no avatar
+ DBWriteContactSettingDword(hContact, yahooProtocolName, "PictCK", 0);
+ } else if (DBGetContactSettingDword(hContact, yahooProtocolName,"PictCK", 0) != cksum) {
+ char szFile[MAX_PATH];
+
+ // Save new Checksum
+ DBWriteContactSettingDword(hContact, yahooProtocolName, "PictCK", cksum);
+
+ // Need to delete the Avatar File!!
+ GetAvatarFileName(hContact, szFile, sizeof szFile, 0);
+ DeleteFile(szFile);
+ }
+
+ // Cleanup the type? and reset things...
+ yahoo_reset_avatar(hContact);
+ }
+ LOG(("[ext_yahoo_status_logon] exiting"));
+}
+
+void ext_yahoo_got_audible(int id, const char *me, const char *who, const char *aud, const char *msg, const char *aud_hash)
+{
+ HANDLE hContact = 0;
+ char z[1024];
+
+ /* aud = file class name
+ GAIM: the audible, in foo.bar.baz format
+
+ Actually this is the filename.
+ Full URL:
+
+ http://us.dl1.yimg.com/download.yahoo.com/dl/aud/us/aud.swf
+
+ where aud in foo.bar.baz format
+ */
+
+ LOG(("ext_yahoo_got_audible for %s aud: %s msg:'%s' hash: %s", who, aud, msg, aud_hash));
+
+ hContact = getbuddyH(who);
+ if (hContact == NULL) {
+ LOG(("Buddy Not Found. Skipping avatar update"));
+ return;
+ }
+
+ _snprintf(z, sizeof(z), "[miranda-audible] %s", msg ?msg:"");
+ ext_yahoo_got_im(id, (char*)me, (char*)who, z, 0, 0, 1, -1);
+}
+
+void ext_yahoo_got_calendar(int id, const char *url, int type, const char *msg, int svc)
+{
+ LOG(("[ext_yahoo_got_calendar] URL:%s type: %d msg: %s svc: %d", url, type, msg, svc));
+
+ if (!YAHOO_ShowPopup( Translate("Calendar Reminder"), msg, url))
+ YAHOO_shownotification(Translate("Calendar Reminder"), msg, NIIF_INFO);
+}
+
+void ext_yahoo_got_picture_upload(int id, const char *me, const char *url,unsigned int ts)
+{
+ int cksum = 0;
+ DBVARIANT dbv;
+
+ LOG(("[ext_yahoo_got_picture_upload] url: %s timestamp: %d", url, ts));
+
+ if (!url) {
+ LOG(("[ext_yahoo_got_picture_upload] Problem with upload?"));
+ return;
+ }
+
+ cksum = YAHOO_GetDword("TMPAvatarHash", 0);
+ if (cksum != 0) {
+ LOG(("[ext_yahoo_got_picture_upload] Updating Checksum to: %d", cksum));
+ YAHOO_SetDword("AvatarHash", cksum);
+ DBDeleteContactSetting(NULL, yahooProtocolName, "TMPAvatarHash");
+
+ // This is only meant for message sessions, but we don't got those in miranda yet
+ YAHOO_bcast_picture_checksum(cksum);
+ // need to tell the stupid Yahoo that our icon updated
+ YAHOO_bcast_picture_update(2);
+ }
+
+ YAHOO_SetString(NULL, "AvatarURL", url);
+
+ if (!DBGetContactSetting(NULL, yahooProtocolName, "AvatarInv", &dbv) ){
+ LOG(("[ext_yahoo_got_picture_upload] Buddy: %s told us this is bad??", dbv.pszVal));
+
+ LOG(("[ext_yahoo_got_picture] Sending url: %s checksum: %d to '%s'!", url, cksum, dbv.pszVal));
+ //void yahoo_send_picture_info(int id, const char *me, const char *who, const char *pic_url, int cksum)
+ yahoo_send_picture_info(id, dbv.pszVal, 2, url, cksum);
+
+ DBDeleteContactSetting(NULL, yahooProtocolName, "AvatarInv");
+ DBFreeVariant(&dbv);
+ }
+}
+
+void ext_yahoo_got_avatar_share(int id, int buddy_icon)
+{
+ LOG(("[ext_yahoo_got_avatar_share] buddy icon: %d", buddy_icon));
+
+ YAHOO_SetByte( "ShareAvatar", buddy_icon );
+}
+
+void ext_yahoo_got_stealth(int id, char *stealthlist)
+{
+ char **s;
+ int found = 0;
+ char **stealth = NULL;
+ char *szProto;
+ HANDLE hContact;
+
+ LOG(("[ext_yahoo_got_stealth] list: %s", stealthlist));
+
+ if (stealthlist)
+ stealth = y_strsplit(stealthlist, ",", -1);
+
+
+ for ( hContact = ( HANDLE )YAHOO_CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ hContact != NULL;
+ hContact = ( HANDLE )YAHOO_CallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM )hContact, 0 ))
+ {
+ szProto = ( char* )YAHOO_CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact, 0 );
+ if ( szProto != NULL && !lstrcmp( szProto, yahooProtocolName )) {
+ DBVARIANT dbv;
+ if ( DBGetContactSetting( hContact, yahooProtocolName, YAHOO_LOGINID, &dbv ))
+ continue;
+
+ found = 0;
+
+ for(s = stealth; s && *s; s++) {
+
+ if (lstrcmpi(*s, dbv.pszVal) == 0) {
+ YAHOO_DebugLog("GOT id = %s", dbv.pszVal);
+ found = 1;
+ break;
+ }
+ }
+
+ /* Check the stealth list */
+ if (found) { /* we have him on our Stealth List */
+ YAHOO_DebugLog("Setting STEALTH for id = %s", dbv.pszVal);
+ /* need to set the ApparentMode thingy */
+ if (ID_STATUS_OFFLINE != DBGetContactSettingWord(hContact, yahooProtocolName, "ApparentMode", 0))
+ DBWriteContactSettingWord(hContact, yahooProtocolName, "ApparentMode", (WORD) ID_STATUS_OFFLINE);
+
+ } else { /* he is not on the Stealth List */
+ //LOG(("Resetting STEALTH for id = %s", dbv.pszVal));
+ /* need to delete the ApparentMode thingy */
+ if (DBGetContactSettingWord(hContact, yahooProtocolName, "ApparentMode", 0))
+ DBDeleteContactSetting(hContact, yahooProtocolName, "ApparentMode");
+ }
+
+ DBFreeVariant( &dbv );
+ }
+ }
+}
+
+
+void ext_yahoo_got_buddies(int id, YList * buds)
+{
+ LOG(("ext_yahoo_got_buddies"));
+
+ if (buds == NULL) {
+ LOG(("No Buddies to work on!"));
+ return;
+ }
+
+ LOG(("Walking buddy list..."));
+ for(; buds; buds = buds->next) {
+ HANDLE hContact;
+
+ struct yahoo_buddy *bud = buds->data;
+ if (bud == NULL) {
+ LOG(("EMPTY BUDDY LIST??"));
+ continue;
+ }
+
+ if (bud->real_name)
+ YAHOO_DebugLog("id = %s name = %s", bud->id, bud->real_name);
+
+ hContact = getbuddyH(bud->id);
+ if (hContact == NULL)
+ hContact = add_buddy(bud->id, (bud->real_name != NULL) ? bud->real_name : bud->id, 0);
+
+ if (bud->group)
+ YAHOO_SetString( hContact, "YGroup", bud->group);
+
+ if (bud->yab_entry) {
+ //LOG(("YAB_ENTRY"));
+
+ if (bud->yab_entry->fname)
+ YAHOO_SetStringUtf( hContact, "FirstName", bud->yab_entry->fname);
+
+
+ if (bud->yab_entry->lname)
+ YAHOO_SetStringUtf( hContact, "LastName", bud->yab_entry->lname);
+
+
+ if (bud->yab_entry->nname)
+ YAHOO_SetStringUtf( hContact, "Nick", bud->yab_entry->nname);
+
+
+ if (bud->yab_entry->email)
+ YAHOO_SetString( hContact, "e-mail", bud->yab_entry->email);
+
+ if (bud->yab_entry->mphone)
+ YAHOO_SetString( hContact, "Cellular", bud->yab_entry->mphone);
+
+ if (bud->yab_entry->hphone)
+ YAHOO_SetString( hContact, "Phone", bud->yab_entry->hphone);
+
+ if (bud->yab_entry->wphone)
+ YAHOO_SetString( hContact, "CompanyPhone", bud->yab_entry->wphone);
+
+ YAHOO_SetWord( hContact, "YabID", bud->yab_entry->dbid);
+
+ }
+
+
+ }
+
+}
+
+void ext_yahoo_got_ignore(int id, YList * igns)
+{
+ LOG(("ext_yahoo_got_ignore"));
+}
+
+void ext_yahoo_rejected(int id, const char *who, const char *msg)
+{
+ char buff[1024]={0};
+ HANDLE hContact;
+ LOG(("[ext_yahoo_rejected] who: %s msg: %s", who, msg));
+ snprintf(buff, sizeof(buff), Translate("%s has rejected your request and sent the following message:"), who);
+
+ hContact = getbuddyH(who);
+
+ if (hContact != NULL) {
+ /*
+ * Make sure the contact is temporary so we could delete it w/o extra traffic
+ */
+ DBWriteContactSettingByte( hContact, "CList", "NotOnList", 1 );
+ YAHOO_CallService( MS_DB_CONTACT_DELETE, (WPARAM) hContact, 0);
+ } else {
+ LOG(("[ext_yahoo_rejected] Buddy not on our buddy list"));
+ }
+
+ MessageBox( NULL, msg, buff, MB_OK | MB_ICONINFORMATION );
+
+}
+
+void YAHOO_add_buddy(const char *who, const char *group, const char *msg)
+{
+ /* We adding a buddy to our list.
+ 2 Stages.
+ 1. We send add buddy packet.
+ 2. We get a packet back from the server confirming add.
+
+ No refresh needed. */
+ yahoo_add_buddy(ylad->id, who, group, msg);
+}
+
+void ext_yahoo_buddy_added(int id, char *myid, char *who, char *group, int status, int auth)
+{
+ LOG(("[ext_yahoo_buddy_added] %s authorized you as %s group: %s status: %d auth: %d", who, myid, group, status, auth));
+
+}
+
+void ext_yahoo_buddy_group_changed(int id, char *myid, char *who, char *old_group, char *new_group)
+{
+LOG(("[ext_yahoo_buddy_group_changed] %s has been moved from group: %s to: %s", who, old_group, new_group));
+}
+
+void ext_yahoo_contact_added(int id, char *myid, char *who, char *fname, char *lname, char *msg)
+{
+ char *szBlob,*pCurBlob;
+ char m[1024];
+ HANDLE hContact=NULL;
+ CCSDATA ccs;
+ PROTORECVEVENT pre;
+
+ /* NOTE: Msg is actually in UTF8 unless stated otherwise!! */
+ LOG(("[ext_yahoo_contact_added] %s added you as %s w/ msg '%s'", who, myid, msg));
+
+ hContact = add_buddy(who, who, PALF_TEMPORARY);
+
+ ccs.szProtoService= PSR_AUTH;
+ ccs.hContact=hContact;
+ ccs.wParam=0;
+ ccs.lParam=(LPARAM)&pre;
+ pre.flags=0;
+ pre.timestamp=time(NULL);
+
+ pre.lParam=sizeof(DWORD)*2+lstrlen(who)+lstrlen(who)+5;
+
+ if (fname != NULL)
+ pre.lParam += lstrlen(fname);
+
+ if (lname != NULL)
+ pre.lParam += lstrlen(lname);
+
+ if (msg != NULL)
+ pre.lParam += lstrlen(msg);
+
+ pCurBlob=szBlob=(char *)malloc(pre.lParam);
+ /*
+ Auth blob is: uin(DWORD),hcontact(HANDLE),nick(ASCIIZ),first(ASCIIZ),
+ last(ASCIIZ),email(ASCIIZ),reason(ASCIIZ)
+
+ blob is: 0(DWORD), nick(ASCIIZ), fname (ASCIIZ), lname (ASCIIZ), email(ASCIIZ), msg(ASCIIZ)
+
+ */
+
+ // UIN
+ *( PDWORD )pCurBlob = 0;
+ pCurBlob+=sizeof(DWORD);
+
+ // hContact
+ *( PDWORD )pCurBlob = ( DWORD )hContact;
+ pCurBlob+=sizeof(DWORD);
+
+ // NICK
+ lstrcpy((char *)pCurBlob,who);
+ pCurBlob+=lstrlen((char *)pCurBlob)+1;
+
+ // FIRST
+ if (fname != NULL)
+ lstrcpyn(m, fname, sizeof(m));
+ else
+ m[0] = '\0';
+
+ lstrcpy((char *)pCurBlob,m);
+ pCurBlob+=lstrlen((char *)pCurBlob)+1;
+
+ // LAST
+ if (lname != NULL)
+ lstrcpyn(m, lname, sizeof(m));
+ else
+ m[0] = '\0';
+
+ lstrcpy((char *)pCurBlob,m);
+ pCurBlob+=lstrlen((char *)pCurBlob)+1;
+
+ // E-mail
+ lstrcpy((char *)pCurBlob,who);
+ pCurBlob+=lstrlen((char *)pCurBlob)+1;
+
+ // Reason
+ if (msg != NULL)
+ lstrcpyn(m, msg, sizeof(m));
+ else
+ m[0] = '\0';
+
+ lstrcpy((char *)pCurBlob, m);
+
+ pre.szMessage=(char *)szBlob;
+ CallService(MS_PROTO_CHAINRECV,0,(LPARAM)&ccs);
+}
+
+void ext_yahoo_typing_notify(int id, const char *me, const char *who, int stat)
+{
+ const char *c;
+ HANDLE hContact;
+
+ LOG(("[ext_yahoo_typing_notify] me: '%s' who: '%s' stat: %d ", me, who, stat));
+
+ hContact = getbuddyH(who);
+ if (!hContact) return;
+
+ c = YAHOO_GetContactName(hContact);
+
+ CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hContact, (LPARAM)stat?10:0);
+}
+
+void ext_yahoo_game_notify(int id, const char *me, const char *who, int stat, const char *msg)
+{
+ HANDLE hContact;
+
+ /* There's also game invite packet:
+ [17:36:44 YAHOO] libyahoo2/libyahoo2.c:3093: debug:
+[17:36:44 YAHOO] Yahoo Service: (null) (0xb7) Status: YAHOO_STATUS_BRB (1)
+[17:36:44 YAHOO]
+[17:36:44 YAHOO] libyahoo2/libyahoo2.c:863: debug:
+[17:36:44 YAHOO] [Reading packet] len: 88
+[17:36:44 YAHOO]
+[17:36:44 YAHOO] Key: From (4) Value: 'xxxxx'
+[17:36:44 YAHOO]
+[17:36:44 YAHOO] Key: To (5) Value: 'zxzxxx'
+[17:36:44 YAHOO]
+[17:36:44 YAHOO] Key: (null) (180) Value: 'pl'
+[17:36:44 YAHOO]
+[17:36:44 YAHOO] Key: (null) (183) Value: ''
+[17:36:44 YAHOO]
+[17:36:44 YAHOO] Key: (null) (181) Value: ''
+[17:36:44 YAHOO]
+[17:36:44 YAHOO] Key: session (11) Value: 'o8114ik_lixyxtdfrxbogw--'
+[17:36:44 YAHOO]
+[17:36:44 YAHOO] Key: stat/location (13) Value: '1'
+[17:36:44 YAHOO]
+[17:36:44 YAHOO] libyahoo2/libyahoo2.c:908: debug:
+[17:36:44 YAHOO] [Reading packet done]
+
+ */
+ LOG(("[ext_yahoo_game_notify] id: %d, me: %s, who: %s, stat: %d, msg: %s", id, me, who, stat, msg));
+ /* FIXME - Not Implemented - this informs you someone else is playing on Yahoo! Games */
+ /* Also Stubbed in Sample Client */
+ hContact = getbuddyH(who);
+ if (!hContact) return;
+
+ if (stat == 2)
+ YAHOO_SetString(hContact, "YGMsg", "");
+ else if (msg) {
+ char z[1024];
+ char *c;
+ const char *l = msg, *u = NULL;
+ int i = 0;
+
+ /* Parse and Set a custom Message
+ *
+ * Format: 1 [09] ygamesp [09] 1 [09] 0 [09] ante?room=yahoo_1078798506&follow=rrrrrrr
+ * [09] Yahoo! Poker\nRoom: Intermediate Lounge 2
+ *
+ * Sign-in:
+ * [17:13:42 YAHOO] [ext_yahoo_game_notify] id: 1, me: xxxxx, who: rrrrrrr,
+ * stat: 1, msg: 1 ygamesa 1 0 ante?room=yahoo_1043183792&follow=lotesdelere
+ * Yahoo! Backgammon Room: Social Lounge 12
+ *
+ * Sign-out:
+ * [17:18:38 YAHOO] [ext_yahoo_game_notify] id: 1, me: xxxxx, who: rrrrr,
+ * stat: 2, msg: 1 ygamesa 2
+ */
+ z[0]='\0';
+ do{
+ c = strchr(l, 0x09);
+ i++;
+ if (c != NULL) {
+ l = c;
+ l++;
+ if (i == 4)
+ u = l;
+ }
+ } while (c != NULL && i < 5);
+
+ if (c != NULL) {
+ // insert \r before \n
+ do{
+ c = strchr(l, '\n');
+
+ if (c != NULL) {
+ (*c) = '\0';
+ lstrcat(z, l);
+ lstrcat(z, "\r\n");
+ l = c + 1;
+ } else {
+ lstrcat(z, l);
+ }
+ } while (c != NULL);
+
+ lstrcat(z, "\r\n\r\nhttp://games.yahoo.com/games/");
+ lstrcat(z, u);
+ c = strchr(z, 0x09);
+ (*c) = '\0';
+ }
+
+ YAHOO_SetString(hContact, "YGMsg", z);
+
+ } else {
+ /* ? no information / reset custom message */
+ YAHOO_SetString(hContact, "YGMsg", "");
+ }
+}
+
+void ext_yahoo_mail_notify(int id, const char *from, const char *subj, int cnt)
+{
+ LOG(("[ext_yahoo_mail_notify] from: %s subject: %s count: %d", from, subj, cnt));
+
+ if (cnt > 0) {
+ SkinPlaySound( Translate( "mail" ) );
+
+ if (!YAHOO_GetByte( "DisableYahoomail", 0)) {
+ char z[MAX_SECONDLINE], title[MAX_CONTACTNAME];
+
+ LOG(("ext_yahoo_mail_notify"));
+
+ if (from == NULL) {
+ lstrcpyn(title, Translate("New Mail"), sizeof(title));
+ snprintf(z, sizeof(z), Translate("You Have %i unread msgs"), cnt);
+ } else {
+ snprintf(title, sizeof(title), Translate("New Mail (%i msgs)"), cnt);
+ snprintf(z, sizeof(z), Translate("From: %s\nSubject: %s"), from, subj);
+ }
+
+ if(!YAHOO_ShowPopup( title, z, "http://mail.yahoo.com" ))
+ YAHOO_shownotification(title, z, NIIF_INFO);
+ }
+ }
+}
+
+void ext_yahoo_system_message(int id, const char *me, const char *who, const char *msg)
+{
+ LOG(("Yahoo System Message to: %s from: %s msg: %s", me, who, msg));
+
+ if (strncmp(msg, "A user on Windows Live", lstrlen("A user on Windows Live")) != 0)
+ YAHOO_ShowPopup( (who != NULL) ? who : "Yahoo System Message", msg, NULL);
+}
+
+void ext_yahoo_got_identities(int id, YList * ids)
+{
+ LOG(("ext_yahoo_got_identities"));
+ /* FIXME - Not implemented - Got list of Yahoo! identities */
+ /* We currently only use the default identity */
+ /* Also Stubbed in Sample Client */
+
+}
+
+void __cdecl yahoo_get_yab_thread(void *psf)
+{
+ int id = (int)psf;
+
+ yahoo_get_yab(id);
+}
+
+char * getcookie(char *rawcookie);
+
+void check_for_update(void)
+{
+ NETLIBHTTPREQUEST nlhr={0},*nlhrReply;
+ NETLIBHTTPHEADER httpHeaders[3];
+
+ nlhr.cbSize=sizeof(nlhr);
+ nlhr.requestType=REQUEST_GET;
+ nlhr.flags=NLHRF_DUMPASTEXT|NLHRF_GENERATEHOST|NLHRF_SMARTAUTHHEADER|NLHRF_HTTP11;
+ nlhr.szUrl="http://update.messenger.yahoo.com/msgrcli7.html";//url.sz;
+ nlhr.headers = httpHeaders;
+ nlhr.headersCount= 3;
+
+ httpHeaders[0].szName="Accept";
+ httpHeaders[0].szValue="*/*";
+ httpHeaders[1].szName="User-Agent";
+ httpHeaders[1].szValue="Mozilla Compatible/2.0 (WinNT; I; NCC/2.0)";
+ httpHeaders[2].szName="Pragma";
+ httpHeaders[2].szValue="no-cache";
+
+ nlhrReply=(NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION,(WPARAM)hNetlibUser,(LPARAM)&nlhr);
+
+ if(nlhrReply) {
+ int i;
+
+ if (nlhrReply->resultCode != 200) {
+ LOG(("Update server returned '%d' instead of 200. It also sent the following: %s", nlhrReply->resultCode, nlhrReply->szResultDescr));
+ return;
+ }
+
+ LOG(("Got %d headers!", nlhrReply->headersCount));
+
+ for (i=0; i < nlhrReply->headersCount; i++) {
+ LOG(("%s: %s", nlhrReply->headers[i].szName, nlhrReply->headers[i].szValue));
+
+ if (lstrcmpi(nlhrReply->headers[i].szName, "Set-Cookie") == 0) {
+ LOG(("Found Cookie... Yum yum..."));
+
+ if (nlhrReply->headers[i].szValue[0] == 'B' && nlhrReply->headers[i].szValue[1] == '=') {
+ char *b;
+
+ b = getcookie(nlhrReply->headers[i].szValue);
+
+ LOG(("Got B Cookie: %s", b));
+ }
+ }
+ }
+ CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT,0,(LPARAM)nlhrReply);
+ }
+}
+void ext_yahoo_got_cookies(int id)
+{
+// char z[1024];
+
+ LOG(("ext_yahoo_got_cookies "));
+/* LOG(("Y Cookie: '%s'", yahoo_get_cookie(id, "y")));
+ LOG(("T Cookie: '%s'", yahoo_get_cookie(id, "t")));
+ LOG(("C Cookie: '%s'", yahoo_get_cookie(id, "c")));
+ LOG(("Login Cookie: '%s'", yahoo_get_cookie(id, "login")));
+
+ //wsprintf(z, "Cookie: %s; C=%s; Y=%s; T=%s", Bcookie, yahoo_get_cookie(id, "c"), yahoo_get_cookie(id, "y"), yahoo_get_cookie(id, "t"));
+ //wsprintf(z, "Cookie: %s; Y=%s", Bcookie, yahoo_get_cookie(id, "y"), yahoo_get_cookie(id, "t"));
+ wsprintf(z, "Cookie: Y=%s; T=%s", yahoo_get_cookie(id, "y"), yahoo_get_cookie(id, "t"));
+ LOG(("Our Cookie: '%s'", z));
+ YAHOO_CallService(MS_NETLIB_SETSTICKYHEADERS, (WPARAM)hnuMain, (LPARAM)z);*/
+
+#ifdef HTTP_GATEWAY
+ if (iHTTPGateway) {
+ char z[1024];
+
+ // need to add Cookie header to our requests or we get booted w/ "Bad Cookie" message.
+ mir_snprintf(z, sizeof(z), "Cookie: Y=%s; T=%s; C=%s", yahoo_get_cookie(id, "y"),
+ yahoo_get_cookie(id, "t"), yahoo_get_cookie(id, "c"));
+ LOG(("Our Cookie: '%s'", z));
+ YAHOO_CallService(MS_NETLIB_SETSTICKYHEADERS, (WPARAM)hNetlibUser, (LPARAM)z);
+ }
+#endif
+
+ /*if (YAHOO_GetByte( "UseYAB", 1 )) {
+ LOG(("GET YAB [Before final check] "));
+ if (yahooStatus != ID_STATUS_OFFLINE)
+ //yahoo_get_yab(id);
+ check_for_update();
+ pthread_create(yahoo_get_yab_thread, (void *)id);
+ }*/
+}
+
+void ext_yahoo_got_ping(int id, const char *errormsg)
+{
+ LOG(("[ext_yahoo_got_ping]"));
+
+ if (errormsg) {
+ LOG(("[ext_yahoo_got_ping] Error msg: %s", errormsg));
+ YAHOO_ShowError(Translate("Yahoo Ping Error"), errormsg);
+ return;
+ }
+
+ LOG(("[ext_yahoo_got_ping] Status Check current: %d, CONNECTING: %d ", yahooStatus, ID_STATUS_CONNECTING));
+
+ if (yahooStatus == ID_STATUS_CONNECTING) {
+ LOG(("[ext_yahoo_got_ping] We are connecting. Checking for different status. Start: %d, Current: %d", gStartStatus, yahooStatus));
+ if (gStartStatus != yahooStatus) {
+ LOG(("[COOKIES] Updating Status to %d ", gStartStatus));
+
+ if (gStartStatus != ID_STATUS_INVISIBLE) {// don't generate a bogus packet for Invisible state
+ if (szStartMsg != NULL) {
+ yahoo_set_status(YAHOO_STATUS_CUSTOM, szStartMsg, (gStartStatus != ID_STATUS_ONLINE) ? 1 : 0);
+ } else
+ yahoo_set_status(gStartStatus, NULL, (gStartStatus != ID_STATUS_ONLINE) ? 1 : 0);
+ }
+
+ yahoo_util_broadcaststatus(gStartStatus);
+ yahooLoggedIn=TRUE;
+ }
+ }
+}
+
+void ext_yahoo_login_response(int id, int succ, const char *url)
+{
+ char buff[1024];
+
+ LOG(("ext_yahoo_login_response"));
+
+ if(succ == YAHOO_LOGIN_OK) {
+ ylad->status = yahoo_current_status(id);
+ LOG(("logged in status-> %d", ylad->status));
+
+ if (YAHOO_GetByte( "UseYAB", 1 )) {
+ LOG(("GET YAB [Before final check] "));
+ if (yahooStatus != ID_STATUS_OFFLINE)
+ pthread_create(yahoo_get_yab_thread, (void *)id);
+ }
+
+ return;
+ } else if(succ == YAHOO_LOGIN_UNAME) {
+
+ snprintf(buff, sizeof(buff), Translate("Could not log into Yahoo service - username not recognised. Please verify that your username is correctly typed."));
+ } else if(succ == YAHOO_LOGIN_PASSWD) {
+
+ snprintf(buff, sizeof(buff), Translate("Could not log into Yahoo service - password incorrect. Please verify that your username and password are correctly typed."));
+
+ } else if(succ == YAHOO_LOGIN_LOCK) {
+
+ snprintf(buff, sizeof(buff), Translate("Could not log into Yahoo service. Your account has been locked.\nVisit %s to reactivate it."), url);
+
+ } else if(succ == YAHOO_LOGIN_DUPL) {
+ snprintf(buff, sizeof(buff), Translate("You have been logged out of the yahoo service, possibly due to a duplicate login."));
+ ProtoBroadcastAck(yahooProtocolName, NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_OTHERLOCATION);
+ }else if(succ == YAHOO_LOGIN_LOGOFF) {
+ snprintf(buff, sizeof(buff), Translate("You have been logged out of the yahoo service."));
+ //ProtoBroadcastAck(yahooProtocolName, NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_OTHERLOCATION);
+ }else if(succ == -1) {
+ /// Can't Connect or got disconnected.
+ if (yahooStatus == ID_STATUS_CONNECTING)
+ snprintf(buff, sizeof(buff), Translate("Could not connect to the Yahoo service. Check your server/port and proxy settings."));
+ else
+ return;
+ } else {
+ snprintf(buff, sizeof(buff),Translate("Could not log in, unknown reason: %d."), succ);
+ }
+
+ YAHOO_DebugLog("ERROR: %s", buff);
+
+ /*
+ * Show Error Message
+ */
+ YAHOO_ShowError(Translate("Yahoo Login Error"), buff);
+
+ yahooLoggedIn = FALSE; /* don't send logout message */
+ yahoo_logout();
+}
+
+void ext_yahoo_error(int id, const char *err, int fatal, int num)
+{
+ char buff[1024];
+
+ LOG(("Yahoo Error: id: %d, fatal: %d, num: %d, %s", id, fatal, num, err));
+
+ switch(num) {
+ case E_UNKNOWN:
+ snprintf(buff, sizeof(buff), Translate("Unknown error %s"), err);
+ break;
+ case E_CUSTOM:
+ snprintf(buff, sizeof(buff), Translate("Custom error %s"), err);
+ break;
+ case E_CONFNOTAVAIL:
+ snprintf(buff, sizeof(buff), Translate("%s is not available for the conference"), err);
+ break;
+ case E_IGNOREDUP:
+ snprintf(buff, sizeof(buff), Translate("%s is already ignored"), err);
+ break;
+ case E_IGNORENONE:
+ snprintf(buff, sizeof(buff), Translate("%s is not in the ignore list"), err);
+ break;
+ case E_IGNORECONF:
+ snprintf(buff, sizeof(buff), Translate("%s is in buddy list - cannot ignore "), err);
+ break;
+ case E_SYSTEM:
+ snprintf(buff, sizeof(buff), Translate("System Error: %s"), err);
+ break;
+ case E_CONNECTION:
+ snprintf(buff, sizeof(buff), Translate("Server Connection Error: %s"), err);
+ break;
+ }
+
+ YAHOO_DebugLog("Error: %s", buff);
+
+ /*
+ * Show Error Message
+ */
+ if (yahooStatus != ID_STATUS_OFFLINE) {
+ // Show error only if we are not offline. [manual status changed]
+ YAHOO_ShowError(Translate("Yahoo Error"), buff);
+ }
+
+}
+
+int ext_yahoo_connect(const char *h, int p, int type)
+{
+ NETLIBOPENCONNECTION ncon = {0};
+ HANDLE con;
+
+ LOG(("ext_yahoo_connect %s:%d", h, p));
+
+ ncon.cbSize = sizeof(ncon);
+ ncon.szHost = h;
+ ncon.wPort = p;
+
+ if (type != YAHOO_CONNECTION_PAGER)
+ ncon.flags = NLOCF_HTTP;
+
+
+ con = (HANDLE) CallService(MS_NETLIB_OPENCONNECTION, (WPARAM) hNetlibUser, (LPARAM) & ncon);
+ if (con == NULL) {
+ LOG(("ERROR: Connect Failed!"));
+ return -1;
+ }
+
+ return (int)con;
+}
+
+/*************************************
+ * Callback handling code starts here
+ */
+YList *connections = NULL;
+static int connection_tags=0;
+
+int ext_yahoo_add_handler(int id, int fd, yahoo_input_condition cond, void *data)
+{
+ struct _conn *c = y_new0(struct _conn, 1);
+ c->tag = ++connection_tags;
+ c->id = id;
+ c->fd = fd;
+ c->cond = cond;
+ c->data = data;
+
+ LOG(("Add %d for %d, tag %d", fd, id, c->tag));
+
+ connections = y_list_prepend(connections, c);
+
+ return c->tag;
+}
+
+void ext_yahoo_remove_handler(int id, int tag)
+{
+ YList *l;
+ LOG(("ext_yahoo_remove_handler id:%d tag:%d ", id, tag));
+
+ for(l = connections; l; l = y_list_next(l)) {
+ struct _conn *c = l->data;
+ if(c->tag == tag) {
+ /* don't actually remove it, just mark it for removal */
+ /* we'll remove when we start the next poll cycle */
+ LOG(("Marking id:%d fd:%d tag:%d for removal", c->id, c->fd, c->tag));
+ c->remove = 1;
+ return;
+ }
+ }
+}
+
+struct connect_callback_data {
+ yahoo_connect_callback callback;
+ void * callback_data;
+ int id;
+ int tag;
+};
+
+static void connect_complete(void *data, int source, yahoo_input_condition condition)
+{
+ struct connect_callback_data *ccd = data;
+ int error = 0;//, err_size = sizeof(error);
+ NETLIBSELECT tSelect = {0};
+
+ ext_yahoo_remove_handler(0, ccd->tag);
+
+ // We Need to read the Socket error
+ //getsockopt(source, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&err_size);
+
+ tSelect.cbSize = sizeof( tSelect );
+ //tSelect.dwTimeout = T->mGatewayTimeout * 1000;
+ tSelect.dwTimeout = 1;
+ tSelect.hReadConns[ 0 ] = ( HANDLE )source;
+ error = YAHOO_CallService( MS_NETLIB_SELECT, 0, ( LPARAM )&tSelect );
+
+ if(error) {
+ //close(source);
+ Netlib_CloseHandle((HANDLE)source);
+ source = -1;
+ }
+
+ LOG(("Connected fd: %d, error: %d", source, error));
+
+ ccd->callback(source, error, ccd->callback_data);
+ FREE(ccd);
+}
+
+void yahoo_callback(struct _conn *c, yahoo_input_condition cond)
+{
+ int ret=1;
+
+ LOG(("[yahoo_callback] id: %d, fd: %d tag: %d", c->id, c->fd, c->tag));
+ if(c->id < 0) {
+ connect_complete(c->data, c->fd, cond);
+ } else if (c->fd > 0) {
+
+ if(cond & YAHOO_INPUT_READ)
+ ret = yahoo_read_ready(c->id, c->fd, c->data);
+ if(ret>0 && cond & YAHOO_INPUT_WRITE)
+ ret = yahoo_write_ready(c->id, c->fd, c->data);
+
+ if (ret == -1) {
+ LOG(("Yahoo read error (%d): %s", errno, strerror(errno)));
+ } else if(ret == 0)
+ LOG(("Yahoo read error: Server closed socket"));
+ }
+
+ LOG(("[yahoo_callback] id: %d exiting...", c->id));
+}
+
+int ext_yahoo_connect_async(int id, const char *host, int port, int type,
+ yahoo_connect_callback callback, void *data)
+{
+ int res;
+
+ LOG(("ext_yahoo_connect_async %s:%d type: %d", host, port, type));
+
+ res = ext_yahoo_connect(host, port, type);
+
+ /*
+ * need to call the callback so we could handle the failure condition!!!
+ * fd = -1 in case of an error
+ */
+ callback(res, 0, data);
+
+ /*
+ * Return proper thing: 0 - ok, -1 - failed, >0 - pending connect
+ */
+ return (res <= 0) ? -1 : 0;
+}
+/*
+ * Callback handling code ends here
+ ***********************************/
+
+void register_callbacks()
+{
+ static struct yahoo_callbacks yc;
+
+ yc.ext_yahoo_login_response = ext_yahoo_login_response;
+ yc.ext_yahoo_got_buddies = ext_yahoo_got_buddies;
+ yc.ext_yahoo_got_ignore = ext_yahoo_got_ignore;
+ yc.ext_yahoo_got_identities = ext_yahoo_got_identities;
+ yc.ext_yahoo_got_cookies = ext_yahoo_got_cookies;
+ yc.ext_yahoo_status_changed = ext_yahoo_status_changed;
+ yc.ext_yahoo_status_logon = ext_yahoo_status_logon;
+ yc.ext_yahoo_got_im = ext_yahoo_got_im;
+ yc.ext_yahoo_got_conf_invite = ext_yahoo_got_conf_invite;
+ yc.ext_yahoo_conf_userdecline = ext_yahoo_conf_userdecline;
+ yc.ext_yahoo_conf_userjoin = ext_yahoo_conf_userjoin;
+ yc.ext_yahoo_conf_userleave = ext_yahoo_conf_userleave;
+ yc.ext_yahoo_conf_message = ext_yahoo_conf_message;
+ yc.ext_yahoo_chat_cat_xml = ext_yahoo_chat_cat_xml;
+ yc.ext_yahoo_chat_join = ext_yahoo_chat_join;
+ yc.ext_yahoo_chat_userjoin = ext_yahoo_chat_userjoin;
+ yc.ext_yahoo_chat_userleave = ext_yahoo_chat_userleave;
+ yc.ext_yahoo_chat_message = ext_yahoo_chat_message;
+ yc.ext_yahoo_chat_yahoologout = ext_yahoo_chat_yahoologout;
+ yc.ext_yahoo_chat_yahooerror = ext_yahoo_chat_yahooerror;
+ yc.ext_yahoo_got_webcam_image = ext_yahoo_got_webcam_image;
+ yc.ext_yahoo_webcam_invite = ext_yahoo_webcam_invite;
+ yc.ext_yahoo_webcam_invite_reply = ext_yahoo_webcam_invite_reply;
+ yc.ext_yahoo_webcam_closed = ext_yahoo_webcam_closed;
+ yc.ext_yahoo_webcam_viewer = ext_yahoo_webcam_viewer;
+ yc.ext_yahoo_webcam_data_request = ext_yahoo_webcam_data_request;
+ yc.ext_yahoo_got_file = ext_yahoo_got_file;
+ yc.ext_yahoo_contact_added = ext_yahoo_contact_added;
+ yc.ext_yahoo_rejected = ext_yahoo_rejected;
+ yc.ext_yahoo_typing_notify = ext_yahoo_typing_notify;
+ yc.ext_yahoo_game_notify = ext_yahoo_game_notify;
+ yc.ext_yahoo_mail_notify = ext_yahoo_mail_notify;
+ yc.ext_yahoo_got_search_result = ext_yahoo_got_search_result;
+ yc.ext_yahoo_system_message = ext_yahoo_system_message;
+ yc.ext_yahoo_error = ext_yahoo_error;
+ yc.ext_yahoo_log = YAHOO_DebugLog;
+ yc.ext_yahoo_add_handler = ext_yahoo_add_handler;
+ yc.ext_yahoo_remove_handler = ext_yahoo_remove_handler;
+ yc.ext_yahoo_connect = ext_yahoo_connect;
+ yc.ext_yahoo_connect_async = ext_yahoo_connect_async;
+
+ yc.ext_yahoo_got_stealthlist = ext_yahoo_got_stealth;
+ yc.ext_yahoo_got_ping = ext_yahoo_got_ping;
+ yc.ext_yahoo_got_picture = ext_yahoo_got_picture;
+ yc.ext_yahoo_got_picture_checksum = ext_yahoo_got_picture_checksum;
+ yc.ext_yahoo_got_picture_update = ext_yahoo_got_picture_update;
+ yc.ext_yahoo_got_avatar_share = ext_yahoo_got_avatar_share;
+
+ yc.ext_yahoo_buddy_added = ext_yahoo_buddy_added;
+ yc.ext_yahoo_got_picture_upload = ext_yahoo_got_picture_upload;
+ yc.ext_yahoo_got_avatar_update = ext_yahoo_got_avatar_update;
+ yc.ext_yahoo_got_audible = ext_yahoo_got_audible;
+ yc.ext_yahoo_got_calendar = ext_yahoo_got_calendar;
+ yc.ext_yahoo_buddy_group_changed = ext_yahoo_buddy_group_changed;
+
+ yahoo_register_callbacks(&yc);
+
+}
+
+void ext_yahoo_login(int login_mode)
+{
+ char host[128], fthost[128];
+ int port=0;
+ DBVARIANT dbv;
+#ifdef HTTP_GATEWAY
+ NETLIBUSERSETTINGS nlus = { 0 };
+#endif
+
+ LOG(("ext_yahoo_login"));
+
+ if (!DBGetContactSetting(NULL, yahooProtocolName, YAHOO_LOGINSERVER, &dbv)) {
+ mir_snprintf(host, sizeof(host), "%s", dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ else {
+ //_snprintf(host, sizeof(host), "%s", pager_host);
+ YAHOO_ShowError(Translate("Yahoo Login Error"), Translate("Please enter Yahoo server to Connect to in Options."));
+
+ return;
+ }
+
+ lstrcpyn(fthost,YAHOO_GetByte("YahooJapan",0)?"filetransfer.msg.yahoo.co.jp":"filetransfer.msg.yahoo.com" , sizeof(fthost));
+ port = DBGetContactSettingWord(NULL, yahooProtocolName, YAHOO_LOGINPORT, 5050);
+
+#ifdef HTTP_GATEWAY
+ nlus.cbSize = sizeof( nlus );
+ if (CallService(MS_NETLIB_GETUSERSETTINGS, (WPARAM) hNetlibUser, (LPARAM) &nlus) == 0) {
+ LOG(("ERROR: Problem retrieving miranda network settings!!!"));
+ }
+
+ iHTTPGateway = (nlus.useProxy && nlus.proxyType == PROXYTYPE_HTTP) ? 1:0;
+ LOG(("Proxy Type: %d HTTP Gateway: %d", nlus.proxyType, iHTTPGateway));
+#endif
+
+ //ylad->id = yahoo_init(ylad->yahoo_id, ylad->password);
+ ylad->id = yahoo_init_with_attributes(ylad->yahoo_id, ylad->password,
+ "pager_host", host,
+ "pager_port", port,
+ "filetransfer_host", fthost,
+ "picture_checksum", YAHOO_GetDword("AvatarHash", -1),
+#ifdef HTTP_GATEWAY
+ "web_messenger", iHTTPGateway,
+#endif
+ NULL);
+
+ ylad->status = YAHOO_STATUS_OFFLINE;
+ yahoo_login(ylad->id, login_mode);
+
+ if (ylad == NULL || ylad->id <= 0) {
+ LOG(("Could not connect to Yahoo server. Please verify that you are connected to the net and the pager host and port are correctly entered."));
+ YAHOO_ShowError(Translate("Yahoo Login Error"), Translate("Could not connect to Yahoo server. Please verify that you are connected to the net and the pager host and port are correctly entered."));
+ return;
+ }
+
+ //rearm(&pingTimer, 600);
+}
+
+void YAHOO_refresh()
+{
+ yahoo_refresh(ylad->id);
+}
+
+
+
diff --git a/miranda-wine/protocols/Yahoo/yahoo.h b/miranda-wine/protocols/Yahoo/yahoo.h
new file mode 100644
index 0000000..15e7c59
--- /dev/null
+++ b/miranda-wine/protocols/Yahoo/yahoo.h
@@ -0,0 +1,208 @@
+/*
+ * $Id: yahoo.h 3676 2006-09-01 18:02:28Z gena01 $
+ *
+ * myYahoo Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+#ifndef _YAHOO_YAHOO_H_
+#define _YAHOO_YAHOO_H_
+
+#include <windows.h>
+
+/*
+ * Yahoo Services
+ */
+#include "pthread.h"
+
+//#include "libyahoo2/config.h"
+#define USE_STRUCT_CALLBACKS
+
+#include "libyahoo2/yahoo2.h"
+#include "libyahoo2/yahoo2_callbacks.h"
+#include "libyahoo2/yahoo_util.h"
+
+#include <newpluginapi.h>
+#include <m_database.h>
+#include <m_protomod.h>
+#include <m_netlib.h>
+#include <m_clist.h>
+
+//=======================================================
+// Definitions
+//=======================================================
+// Build is a cvs build
+//
+// If defined, the build will add cvs info to the plugin info
+#define YAHOO_CVSBUILD
+
+//#define modname "myYahoo"
+#define YAHOO_LOGINSERVER "LoginServer"
+#define YAHOO_LOGINPORT "LoginPort"
+#define YAHOO_LOGINID "yahoo_id"
+#define YAHOO_PASSWORD "Password"
+#define YAHOO_CHECKMAIL "CheckMail"
+#define YAHOO_TNOTIF "TypeNotif"
+#define YAHOO_CUSTSTATDB "CustomStat"
+#define YAHOO_ALLOW_MSGBOX 1
+#define YAHOO_ALLOW_ENTER 2
+#define YAHOO_MAIL_POPUP 4
+#define YAHOO_NOTIFY_POPUP 8
+#define YAHOO_DEFAULT_PORT 5050
+#define YAHOO_DEFAULT_LOGIN_SERVER "scs.msg.yahoo.com"
+#define YAHOO_DEFAULT_JAPAN_LOGIN_SERVER "cs.yahoo.co.jp"
+#define YAHOO_CUSTOM_STATUS 99
+
+#define YAHOO_DEBUGLOG YAHOO_DebugLog
+
+extern int do_yahoo_debug;
+
+#define LOG(x) if(do_yahoo_debug) { YAHOO_DEBUGLOG("%s:%d: ", __FILE__, __LINE__); \
+ YAHOO_DEBUGLOG x; \
+ YAHOO_DEBUGLOG(" ");}
+
+#define YAHOO_SET_CUST_STAT "/SetCustomStatCommand"
+#define YAHOO_SHOW_PROFILE "/YahooShowProfileCommand"
+#define YAHOO_SHOW_MY_PROFILE "/YahooShowMyProfileCommand"
+#define YAHOO_YAHOO_MAIL "/YahooGotoMailboxCommand"
+#define YAHOO_REFRESH "/YahooRefreshCommand"
+#define YAHOO_AB "/YahooAddressBook"
+#define YAHOO_CALENDAR "/YahooCalendar"
+#define YAHOO_SEND_NUDGE "/SendNudge"
+
+#define STYLE_DEFAULTBGCOLOUR RGB(173,206,247)
+
+#define MENU_ITEMS_COUNT 7
+extern HANDLE YahooMenuItems[ MENU_ITEMS_COUNT ];
+
+#define LocalEventUnhook(hook) if(hook) UnhookEvent(hook)
+#define NEWSTR_ALLOCA(A) (A==NULL)?NULL:strcpy((char*)alloca(strlen(A)+1),A)
+
+struct _conn {
+ int tag;
+ int id;
+ int fd;
+ yahoo_input_condition cond;
+ void *data;
+ int remove;
+};
+
+//=======================================================
+// Defines
+//=======================================================
+//General
+extern HANDLE hNetlibUser;
+extern HINSTANCE hinstance;
+extern int yahooStatus;
+extern char yahooProtocolName[MAX_PATH];
+extern BOOL yahooLoggedIn;
+
+extern HANDLE YahooMenuItems[ MENU_ITEMS_COUNT ];
+extern pthread_mutex_t connectionHandleMutex;
+
+#ifdef HTTP_GATEWAY
+extern int iHTTPGateway;
+#endif
+
+//int ext_yahoo_log(char *fmt,...);
+
+HANDLE __stdcall YAHOO_CreateProtoServiceFunction(
+ const char* szService,
+ MIRANDASERVICE serviceProc );
+
+int __stdcall YAHOO_CallService( const char* szSvcName, WPARAM wParam, LPARAM lParam );
+
+#ifdef __GNUC__
+int YAHOO_DebugLog( const char *fmt, ... ) __attribute__ ((format (printf, 1, 2)));
+#else
+int YAHOO_DebugLog( const char *fmt, ... );
+#endif
+
+DWORD __stdcall YAHOO_GetByte( const char* valueName, int parDefltValue );
+DWORD __stdcall YAHOO_SetByte( const char* valueName, int parValue );
+
+DWORD __stdcall YAHOO_GetDword( const char* valueName, DWORD parDefltValue );
+DWORD __stdcall YAHOO_SetDword( const char* valueName, DWORD parValue );
+
+WORD __stdcall YAHOO_GetWord( HANDLE hContact, const char* valueName, int parDefltValue );
+DWORD __stdcall YAHOO_SetWord( HANDLE hContact, const char* valueName, int parValue );
+
+int __stdcall YAHOO_SendBroadcast( HANDLE hContact, int type, int result, HANDLE hProcess, LPARAM lParam );
+
+DWORD __stdcall YAHOO_SetString( HANDLE hContact, const char* valueName, const char* parValue );
+DWORD __stdcall YAHOO_SetStringUtf( HANDLE hContact, const char* valueName, const char* parValue );
+
+int __stdcall YAHOO_ShowPopup( const char* nickname, const char* msg, const char *szURL );
+
+#define YAHOO_hasnotification() ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)
+
+int YAHOO_shownotification(const char *title, const char *info, DWORD flags);
+int YAHOO_util_dbsettingchanged(WPARAM wParam, LPARAM lParam);
+void YAHOO_utils_logversion();
+void YAHOO_ShowError(const char *title, const char *buff);
+
+//Services.c
+int GetCaps(WPARAM wParam,LPARAM lParam);
+int GetName(WPARAM wParam,LPARAM lParam);
+int SetStatus(WPARAM wParam,LPARAM lParam);
+int GetStatus(WPARAM wParam,LPARAM lParam);
+void yahoo_util_broadcaststatus(int s);
+void __cdecl yahoo_server_main(void *empty);
+const char *find_buddy( const char *yahoo_id);
+HANDLE getbuddyH(const char *yahoo_id);
+
+void yahoo_logoff_buddies();
+void yahoo_set_status(int myyahooStatus, char *msg, int away);
+int miranda_to_yahoo(int myyahooStatus);
+void yahoo_stealth(const char *buddy, int add);
+const YList* YAHOO_GetIgnoreList(void);
+void YAHOO_IgnoreBuddy(const char *buddy, int ignore);
+
+void register_callbacks();
+char* YAHOO_GetContactName(HANDLE hContact);
+
+void YAHOO_remove_buddy(const char *who);
+void YAHOO_reject(const char *who, const char *msg);
+void YAHOO_accept(const char *who);
+void YAHOO_add_buddy(const char *who, const char *group, const char *msg);
+HANDLE add_buddy( const char *yahoo_id, const char *yahoo_name, DWORD flags );
+void YAHOO_sendtyping(const char *who, int stat);
+
+typedef struct {
+ char yahoo_id[255];
+ char name[255];
+ int status;
+ int away;
+ char *msg;
+ char group[255];
+} yahoo_account;
+
+typedef struct {
+ char yahoo_id[255];
+ char password[255];
+ int id;
+ int fd;
+ int status;
+ char *msg;
+ int rpkts;
+} yahoo_local_account;
+
+void SetButtonCheck(HWND hwndDlg, int CtrlID, BOOL bCheck);
+void YahooOpenURL(const char *url, int autoLogin);
+
+char * yahoo_status_code(enum yahoo_status s);
+void YAHOO_refresh();
+int LoadYahooServices(void);
+void yahoo_logout();
+void yahoo_callback(struct _conn *c, yahoo_input_condition cond);
+void ext_yahoo_login(int login_mode);
+void __stdcall Utf8Decode( char* str, int maxSize, wchar_t** ucs2 );
+char* __stdcall Utf8EncodeUcs2( const wchar_t* src );
+int YahooGotoMailboxCommand( WPARAM wParam, LPARAM lParam );
+
+#endif