summaryrefslogtreecommitdiff
path: root/miranda-wine
diff options
context:
space:
mode:
Diffstat (limited to 'miranda-wine')
-rw-r--r--miranda-wine/Makefile450
-rw-r--r--miranda-wine/docs/credits.txt36
-rw-r--r--miranda-wine/include/m_addcontact.h65
-rw-r--r--miranda-wine/include/m_awaymsg.h41
-rw-r--r--miranda-wine/include/m_button.h59
-rw-r--r--miranda-wine/include/m_chat.h631
-rw-r--r--miranda-wine/include/m_clc.h265
-rw-r--r--miranda-wine/include/m_clist.h550
-rw-r--r--miranda-wine/include/m_clistint.h328
-rw-r--r--miranda-wine/include/m_clui.h166
-rw-r--r--miranda-wine/include/m_contactdir.h162
-rw-r--r--miranda-wine/include/m_contacts.h106
-rw-r--r--miranda-wine/include/m_database.h1054
-rw-r--r--miranda-wine/include/m_email.h36
-rw-r--r--miranda-wine/include/m_file.h62
-rw-r--r--miranda-wine/include/m_findadd.h35
-rw-r--r--miranda-wine/include/m_fuse.h32
-rw-r--r--miranda-wine/include/m_history.h34
-rw-r--r--miranda-wine/include/m_icq.h298
-rw-r--r--miranda-wine/include/m_idle.h72
-rw-r--r--miranda-wine/include/m_ignore.h63
-rw-r--r--miranda-wine/include/m_langpack.h101
-rw-r--r--miranda-wine/include/m_message.h100
-rw-r--r--miranda-wine/include/m_netlib.h748
-rw-r--r--miranda-wine/include/m_options.h108
-rw-r--r--miranda-wine/include/m_plugins.h82
-rw-r--r--miranda-wine/include/m_png.h64
-rw-r--r--miranda-wine/include/m_popup.h317
-rw-r--r--miranda-wine/include/m_protocols.h288
-rw-r--r--miranda-wine/include/m_protomod.h134
-rw-r--r--miranda-wine/include/m_protosvc.h635
-rw-r--r--miranda-wine/include/m_sessions.h343
-rw-r--r--miranda-wine/include/m_skin.h145
-rw-r--r--miranda-wine/include/m_system.h366
-rw-r--r--miranda-wine/include/m_url.h35
-rw-r--r--miranda-wine/include/m_userinfo.h75
-rw-r--r--miranda-wine/include/m_utils.h325
-rw-r--r--miranda-wine/include/newpluginapi.h169
-rw-r--r--miranda-wine/include/statusmodes.h48
-rw-r--r--miranda-wine/include/win2k.h295
-rw-r--r--miranda-wine/plugins/clist/clc.h83
-rw-r--r--miranda-wine/plugins/clist/clcopts.c923
-rw-r--r--miranda-wine/plugins/clist/clcpaint.c590
-rw-r--r--miranda-wine/plugins/clist/clist.h30
-rw-r--r--miranda-wine/plugins/clist/clistmenus.c947
-rw-r--r--miranda-wine/plugins/clist/clistopts.c353
-rw-r--r--miranda-wine/plugins/clist/cluiopts.c346
-rw-r--r--miranda-wine/plugins/clist/commonheaders.c1
-rw-r--r--miranda-wine/plugins/clist/commonheaders.h96
-rw-r--r--miranda-wine/plugins/clist/forkthread.c94
-rw-r--r--miranda-wine/plugins/clist/forkthread.h63
-rw-r--r--miranda-wine/plugins/clist/init.c175
-rw-r--r--miranda-wine/plugins/clist/res/blank.icobin0 -> 318 bytes
-rw-r--r--miranda-wine/plugins/clist/res/delete.icobin0 -> 1406 bytes
-rw-r--r--miranda-wine/plugins/clist/res/dragcopy.curbin0 -> 326 bytes
-rw-r--r--miranda-wine/plugins/clist/res/dropuser.curbin0 -> 1086 bytes
-rw-r--r--miranda-wine/plugins/clist/res/hyperlin.curbin0 -> 326 bytes
-rw-r--r--miranda-wine/plugins/clist/res/rename.icobin0 -> 1406 bytes
-rw-r--r--miranda-wine/plugins/clist/resource.h554
-rw-r--r--miranda-wine/plugins/clist/resource.rc706
-rw-r--r--miranda-wine/plugins/db3x/Makefile53
-rw-r--r--miranda-wine/plugins/db3x/commonheaders.c1
-rw-r--r--miranda-wine/plugins/db3x/commonheaders.h66
-rw-r--r--miranda-wine/plugins/db3x/database.c186
-rw-r--r--miranda-wine/plugins/db3x/database.h218
-rw-r--r--miranda-wine/plugins/db3x/dbcache.c229
-rw-r--r--miranda-wine/plugins/db3x/dbcontacts.c270
-rw-r--r--miranda-wine/plugins/db3x/dbevents.c436
-rw-r--r--miranda-wine/plugins/db3x/dbheaders.c78
-rw-r--r--miranda-wine/plugins/db3x/dbmodulechain.c132
-rw-r--r--miranda-wine/plugins/db3x/dbsettings.c957
-rw-r--r--miranda-wine/plugins/db3x/dbtime.c163
-rw-r--r--miranda-wine/plugins/db3x/encrypt.c67
-rw-r--r--miranda-wine/plugins/db3x/encryption.h23
-rw-r--r--miranda-wine/plugins/db3x/init.c193
-rw-r--r--miranda-wine/plugins/db3x/resource.h30
-rw-r--r--miranda-wine/plugins/db3x/resource.rc169
-rw-r--r--miranda-wine/plugins/db3x/utf.c166
-rw-r--r--miranda-wine/plugins/png2dib/m_png.h64
-rw-r--r--miranda-wine/plugins/png2dib/png2dib.c411
-rw-r--r--miranda-wine/plugins/png2dib/version.h3
-rw-r--r--miranda-wine/plugins/png2dib/version.rc36
-rw-r--r--miranda-wine/plugins/srmm/cmdlist.c124
-rw-r--r--miranda-wine/plugins/srmm/cmdlist.h48
-rw-r--r--miranda-wine/plugins/srmm/commonheaders.h57
-rw-r--r--miranda-wine/plugins/srmm/globals.c107
-rw-r--r--miranda-wine/plugins/srmm/globals.h59
-rw-r--r--miranda-wine/plugins/srmm/msgdialog.c1859
-rw-r--r--miranda-wine/plugins/srmm/msglog.c549
-rw-r--r--miranda-wine/plugins/srmm/msgoptions.c723
-rw-r--r--miranda-wine/plugins/srmm/msgs.c587
-rw-r--r--miranda-wine/plugins/srmm/msgs.h211
-rw-r--r--miranda-wine/plugins/srmm/msgtimedout.c71
-rw-r--r--miranda-wine/plugins/srmm/res/add.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/plugins/srmm/res/clock.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/plugins/srmm/res/details.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/plugins/srmm/res/downarrow.icobin0 -> 1406 bytes
-rw-r--r--miranda-wine/plugins/srmm/res/history.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/plugins/srmm/res/incoming.icobin0 -> 1246 bytes
-rw-r--r--miranda-wine/plugins/srmm/res/notice.icobin0 -> 1246 bytes
-rw-r--r--miranda-wine/plugins/srmm/res/outgoing.icobin0 -> 1246 bytes
-rw-r--r--miranda-wine/plugins/srmm/res/typing.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/plugins/srmm/resource.h93
-rw-r--r--miranda-wine/plugins/srmm/resource.rc356
-rw-r--r--miranda-wine/plugins/srmm/richutil.c234
-rw-r--r--miranda-wine/plugins/srmm/richutil.h55
-rw-r--r--miranda-wine/plugins/srmm/srmm.c71
-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
-rw-r--r--miranda-wine/src/core/commonheaders.c2
-rw-r--r--miranda-wine/src/core/commonheaders.h84
-rw-r--r--miranda-wine/src/core/forkthread.h64
-rw-r--r--miranda-wine/src/core/memory.c167
-rw-r--r--miranda-wine/src/core/miranda.c565
-rw-r--r--miranda-wine/src/core/miranda.h48
-rw-r--r--miranda-wine/src/core/modules.c656
-rw-r--r--miranda-wine/src/core/modules.h184
-rw-r--r--miranda-wine/src/modules/addcontact/addcontact.c235
-rw-r--r--miranda-wine/src/modules/autoaway/autoaway.c82
-rw-r--r--miranda-wine/src/modules/button/button.c540
-rw-r--r--miranda-wine/src/modules/clist/Docking.c293
-rw-r--r--miranda-wine/src/modules/clist/clc.c1321
-rw-r--r--miranda-wine/src/modules/clist/clc.h154
-rw-r--r--miranda-wine/src/modules/clist/clcfiledrop.c295
-rw-r--r--miranda-wine/src/modules/clist/clcidents.c201
-rw-r--r--miranda-wine/src/modules/clist/clcitems.c721
-rw-r--r--miranda-wine/src/modules/clist/clcmsgs.c462
-rw-r--r--miranda-wine/src/modules/clist/clcutils.c865
-rw-r--r--miranda-wine/src/modules/clist/clistcore.c315
-rw-r--r--miranda-wine/src/modules/clist/clistevents.c308
-rw-r--r--miranda-wine/src/modules/clist/clistmod.c526
-rw-r--r--miranda-wine/src/modules/clist/clistsettings.c380
-rw-r--r--miranda-wine/src/modules/clist/clisttray.c632
-rw-r--r--miranda-wine/src/modules/clist/clui.c1042
-rw-r--r--miranda-wine/src/modules/clist/cluiservices.c239
-rw-r--r--miranda-wine/src/modules/clist/contact.c185
-rw-r--r--miranda-wine/src/modules/clist/groups.c514
-rw-r--r--miranda-wine/src/modules/clist/keyboard.c135
-rw-r--r--miranda-wine/src/modules/contacts/contacts.c478
-rw-r--r--miranda-wine/src/modules/database/database.c377
-rw-r--r--miranda-wine/src/modules/database/dbini.c495
-rw-r--r--miranda-wine/src/modules/database/dblists.c149
-rw-r--r--miranda-wine/src/modules/database/dblists.h36
-rw-r--r--miranda-wine/src/modules/database/dbtime.c239
-rw-r--r--miranda-wine/src/modules/database/profilemanager.c696
-rw-r--r--miranda-wine/src/modules/database/profilemanager.h37
-rw-r--r--miranda-wine/src/modules/findadd/findadd.c902
-rw-r--r--miranda-wine/src/modules/findadd/findadd.h57
-rw-r--r--miranda-wine/src/modules/findadd/searchresults.c424
-rw-r--r--miranda-wine/src/modules/help/about.c143
-rw-r--r--miranda-wine/src/modules/help/help.c104
-rw-r--r--miranda-wine/src/modules/history/history.c434
-rw-r--r--miranda-wine/src/modules/idle/idle.c415
-rw-r--r--miranda-wine/src/modules/ignore/ignore.c449
-rw-r--r--miranda-wine/src/modules/langpack/langpack.c362
-rw-r--r--miranda-wine/src/modules/langpack/lpservices.c128
-rw-r--r--miranda-wine/src/modules/netlib/netlib.c503
-rw-r--r--miranda-wine/src/modules/netlib/netlib.h157
-rw-r--r--miranda-wine/src/modules/netlib/netlibbind.c247
-rw-r--r--miranda-wine/src/modules/netlib/netlibhttp.c729
-rw-r--r--miranda-wine/src/modules/netlib/netlibhttpproxy.c610
-rw-r--r--miranda-wine/src/modules/netlib/netliblog.c440
-rw-r--r--miranda-wine/src/modules/netlib/netlibopenconn.c569
-rw-r--r--miranda-wine/src/modules/netlib/netlibopts.c516
-rw-r--r--miranda-wine/src/modules/netlib/netlibpktrecver.c85
-rw-r--r--miranda-wine/src/modules/netlib/netlibsock.c166
-rw-r--r--miranda-wine/src/modules/netlib/netlibupnp.c495
-rw-r--r--miranda-wine/src/modules/options/options.c664
-rw-r--r--miranda-wine/src/modules/plugins/newplugins.c815
-rw-r--r--miranda-wine/src/modules/protocols/protochains.c225
-rw-r--r--miranda-wine/src/modules/protocols/protocols.c134
-rw-r--r--miranda-wine/src/modules/protocols/protodir.c248
-rw-r--r--miranda-wine/src/modules/skin/skin.c77
-rw-r--r--miranda-wine/src/modules/skin/skinicons.c1044
-rw-r--r--miranda-wine/src/modules/skin/sounds.c403
-rw-r--r--miranda-wine/src/modules/srauth/auth.c97
-rw-r--r--miranda-wine/src/modules/srauth/authdialogs.c269
-rw-r--r--miranda-wine/src/modules/srawaymsg/awaymsg.c161
-rw-r--r--miranda-wine/src/modules/srawaymsg/sendmsg.c414
-rw-r--r--miranda-wine/src/modules/sremail/email.c92
-rw-r--r--miranda-wine/src/modules/srfile/file.c287
-rw-r--r--miranda-wine/src/modules/srfile/file.h88
-rw-r--r--miranda-wine/src/modules/srfile/fileexistsdlg.c331
-rw-r--r--miranda-wine/src/modules/srfile/fileopts.c227
-rw-r--r--miranda-wine/src/modules/srfile/filerecvdlg.c431
-rw-r--r--miranda-wine/src/modules/srfile/filesenddlg.c380
-rw-r--r--miranda-wine/src/modules/srfile/filexferdlg.c562
-rw-r--r--miranda-wine/src/modules/srurl/url.c203
-rw-r--r--miranda-wine/src/modules/srurl/url.h43
-rw-r--r--miranda-wine/src/modules/srurl/urldialogs.c737
-rw-r--r--miranda-wine/src/modules/userinfo/contactinfo.c503
-rw-r--r--miranda-wine/src/modules/userinfo/stdinfo.c541
-rw-r--r--miranda-wine/src/modules/userinfo/userinfo.c500
-rw-r--r--miranda-wine/src/modules/useronline/useronline.c96
-rw-r--r--miranda-wine/src/modules/utils/bmpfilter.c180
-rw-r--r--miranda-wine/src/modules/utils/colourpicker.c107
-rw-r--r--miranda-wine/src/modules/utils/hyperlink.c183
-rw-r--r--miranda-wine/src/modules/utils/openurl.c228
-rw-r--r--miranda-wine/src/modules/utils/path.c83
-rw-r--r--miranda-wine/src/modules/utils/resizer.c152
-rw-r--r--miranda-wine/src/modules/utils/utf.c165
-rw-r--r--miranda-wine/src/modules/utils/utils.c364
-rw-r--r--miranda-wine/src/modules/utils/windowlist.c107
-rw-r--r--miranda-wine/src/modules/visibility/visibility.c297
-rw-r--r--miranda-wine/src/res/addcontact.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/away.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/blank.icobin0 -> 318 bytes
-rw-r--r--miranda-wine/src/res/changefont.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/delete.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/detailsl.icobin0 -> 6518 bytes
-rw-r--r--miranda-wine/src/res/dnd.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/downarrow.icobin0 -> 1406 bytes
-rw-r--r--miranda-wine/src/res/dragcopy.curbin0 -> 326 bytes
-rw-r--r--miranda-wine/src/res/dropuser.curbin0 -> 1086 bytes
-rw-r--r--miranda-wine/src/res/emptyblo.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/file.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/filledbl.icobin0 -> 1406 bytes
-rw-r--r--miranda-wine/src/res/finduser.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/freechat.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/groupope.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/groupshu.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/help.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/history.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/hyperlin.curbin0 -> 326 bytes
-rw-r--r--miranda-wine/src/res/invisible.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/message.icobin0 -> 1406 bytes
-rw-r--r--miranda-wine/src/res/miranda.icobin0 -> 22486 bytes
-rw-r--r--miranda-wine/src/res/mirandaw.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/multisend.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/na2.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/notick.icobin0 -> 1406 bytes
-rw-r--r--miranda-wine/src/res/notick1.icobin0 -> 1406 bytes
-rw-r--r--miranda-wine/src/res/occupied.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/offline2.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/online2.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/onthepho.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/options.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/outtolun.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/rename.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/reply.icobin0 -> 1406 bytes
-rw-r--r--miranda-wine/src/res/searchal.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/sendmail.icobin0 -> 1406 bytes
-rw-r--r--miranda-wine/src/res/smalldot.icobin0 -> 318 bytes
-rw-r--r--miranda-wine/src/res/sms.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/sortcold.bmpbin0 -> 150 bytes
-rw-r--r--miranda-wine/src/res/sortcolu.bmpbin0 -> 150 bytes
-rw-r--r--miranda-wine/src/res/timestamp.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/url.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/useronli.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/res/viewdetails.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/src/resource.h392
-rw-r--r--miranda-wine/src/resource.rc1765
-rw-r--r--miranda-wine/src/version.rc45
562 files changed, 153849 insertions, 0 deletions
diff --git a/miranda-wine/Makefile b/miranda-wine/Makefile
new file mode 100644
index 0000000..83edd0d
--- /dev/null
+++ b/miranda-wine/Makefile
@@ -0,0 +1,450 @@
+CC = winegcc
+CPP = wineg++
+WRC = wrc
+
+CPPFLAGS = -I/usr/local/include/wine/windows \
+ -I/usr/local/include/wine/msvcrt \
+ -I./include \
+ -I./src/core
+
+LNK_COMMON = -L/usr/local/lib/wine -L/usr/local/lib \
+ -lwine \
+ -lmsvcrt \
+ -lgdi32 \
+ -lshell32 \
+ -lole32 \
+ -lcomctl32 \
+ -lcomdlg32
+
+LNK_MAINLIBS = -lversion \
+ -lws2_32 \
+ -lwinmm \
+ -loleaut32 \
+ -luuid
+
+MAINOBJS = ./src/core/commonheaders.o \
+ ./src/core/memory.o \
+ ./src/core/miranda.o \
+ ./src/core/modules.o \
+ ./src/modules/addcontact/addcontact.o \
+ ./src/modules/autoaway/autoaway.o \
+ ./src/modules/button/button.o \
+ ./src/modules/contacts/contacts.o \
+ ./src/modules/database/database.o \
+ ./src/modules/database/dblists.o \
+ ./src/modules/database/dbtime.o \
+ ./src/modules/database/profilemanager.o \
+ ./src/modules/findadd/findadd.o \
+ ./src/modules/findadd/searchresults.o \
+ ./src/modules/help/about.o \
+ ./src/modules/help/help.o \
+ ./src/modules/history/history.o \
+ ./src/modules/idle/idle.o \
+ ./src/modules/ignore/ignore.o \
+ ./src/modules/langpack/langpack.o \
+ ./src/modules/langpack/lpservices.o \
+ ./src/modules/netlib/netlib.o \
+ ./src/modules/netlib/netlibbind.o \
+ ./src/modules/netlib/netlibhttp.o \
+ ./src/modules/netlib/netlibhttpproxy.o \
+ ./src/modules/netlib/netliblog.o \
+ ./src/modules/netlib/netlibopenconn.o \
+ ./src/modules/netlib/netlibopts.o \
+ ./src/modules/netlib/netlibpktrecver.o \
+ ./src/modules/netlib/netlibsock.o \
+ ./src/modules/netlib/netlibupnp.o \
+ ./src/modules/options/options.o \
+ ./src/modules/plugins/newplugins.o \
+ ./src/modules/protocols/protochains.o \
+ ./src/modules/protocols/protocols.o \
+ ./src/modules/protocols/protodir.o \
+ ./src/modules/skin/skin.o \
+ ./src/modules/skin/skinicons.o \
+ ./src/modules/skin/sounds.o \
+ ./src/modules/srauth/auth.o \
+ ./src/modules/srauth/authdialogs.o \
+ ./src/modules/srawaymsg/awaymsg.o \
+ ./src/modules/srawaymsg/sendmsg.o \
+ ./src/modules/sremail/email.o \
+ ./src/modules/srfile/file.o \
+ ./src/modules/srfile/fileexistsdlg.o \
+ ./src/modules/srfile/fileopts.o \
+ ./src/modules/srfile/filerecvdlg.o \
+ ./src/modules/srfile/filesenddlg.o \
+ ./src/modules/srfile/filexferdlg.o \
+ ./src/modules/srurl/url.o \
+ ./src/modules/srurl/urldialogs.o \
+ ./src/modules/userinfo/contactinfo.o \
+ ./src/modules/userinfo/stdinfo.o \
+ ./src/modules/userinfo/userinfo.o \
+ ./src/modules/useronline/useronline.o \
+ ./src/modules/utils/bmpfilter.o \
+ ./src/modules/utils/colourpicker.o \
+ ./src/modules/utils/hyperlink.o \
+ ./src/modules/utils/openurl.o \
+ ./src/modules/utils/path.o \
+ ./src/modules/utils/resizer.o \
+ ./src/modules/utils/utf.o \
+ ./src/modules/utils/utils.o \
+ ./src/modules/utils/windowlist.o \
+ ./src/modules/visibility/visibility.o \
+ ./src/modules/clist/keyboard.o \
+ ./src/modules/clist/clc.o \
+ ./src/modules/clist/clcfiledrop.o \
+ ./src/modules/clist/clcidents.o \
+ ./src/modules/clist/clcitems.o \
+ ./src/modules/clist/clcmsgs.o \
+ ./src/modules/clist/clcutils.o \
+ ./src/modules/clist/clistcore.o \
+ ./src/modules/clist/clistevents.o \
+ ./src/modules/clist/clistmod.o \
+ ./src/modules/clist/clistsettings.o \
+ ./src/modules/clist/clisttray.o \
+ ./src/modules/clist/clui.o \
+ ./src/modules/clist/cluiservices.o \
+ ./src/modules/clist/contact.o \
+ ./src/modules/clist/Docking.o \
+ ./src/modules/clist/groups.o \
+ ./src/resource.res
+
+DB3XOBJS = ./plugins/db3x/commonheaders.o \
+ ./plugins/db3x/database.o \
+ ./plugins/db3x/dbcache.o \
+ ./plugins/db3x/dbcontacts.o \
+ ./plugins/db3x/dbevents.o \
+ ./plugins/db3x/dbheaders.o \
+ ./plugins/db3x/dbmodulechain.o \
+ ./plugins/db3x/dbsettings.o \
+ ./plugins/db3x/encrypt.o \
+ ./plugins/db3x/init.o \
+ ./plugins/db3x/utf.o \
+ ./plugins/db3x/resource.res
+
+CLISTOBJS= ./plugins/clist/clcopts.o \
+ ./plugins/clist/clcpaint.o \
+ ./plugins/clist/clistmenus.o \
+ ./plugins/clist/clistopts.o \
+ ./plugins/clist/cluiopts.o \
+ ./plugins/clist/commonheaders.o \
+ ./plugins/clist/forkthread.o \
+ ./plugins/clist/init.o \
+ ./plugins/clist/resource.res
+
+SRMMOBJS = ./plugins/srmm/cmdlist.o \
+ ./plugins/srmm/globals.o \
+ ./plugins/srmm/msgdialog.o \
+ ./plugins/srmm/msglog.o \
+ ./plugins/srmm/msgoptions.o \
+ ./plugins/srmm/msgs.o \
+ ./plugins/srmm/msgtimedout.o \
+ ./plugins/srmm/richutil.o\
+ ./plugins/srmm/srmm.o \
+ ./plugins/srmm/resource.res
+
+ICQOBJS = ./protocols/IcqOscarJ/chan_01login.o \
+ ./protocols/IcqOscarJ/chan_02data.o \
+ ./protocols/IcqOscarJ/chan_03error.o \
+ ./protocols/IcqOscarJ/chan_04close.o \
+ ./protocols/IcqOscarJ/chan_05ping.o \
+ ./protocols/IcqOscarJ/cookies.o \
+ ./protocols/IcqOscarJ/fam_01service.o \
+ ./protocols/IcqOscarJ/fam_02location.o \
+ ./protocols/IcqOscarJ/fam_03buddy.o \
+ ./protocols/IcqOscarJ/fam_04message.o \
+ ./protocols/IcqOscarJ/fam_09bos.o \
+ ./protocols/IcqOscarJ/fam_0alookup.o \
+ ./protocols/IcqOscarJ/fam_0bstatus.o \
+ ./protocols/IcqOscarJ/fam_13servclist.o \
+ ./protocols/IcqOscarJ/fam_15icqserver.o \
+ ./protocols/IcqOscarJ/fam_17signon.o \
+ ./protocols/IcqOscarJ/directpackets.o \
+ ./protocols/IcqOscarJ/iconlib.o \
+ ./protocols/IcqOscarJ/icq_direct.o \
+ ./protocols/IcqOscarJ/icq_directmsg.o \
+ ./protocols/IcqOscarJ/icq_filerequests.o \
+ ./protocols/IcqOscarJ/icq_filetransfer.o \
+ ./protocols/IcqOscarJ/icq_advsearch.o \
+ ./protocols/IcqOscarJ/icq_db.o \
+ ./protocols/IcqOscarJ/icqosc_svcs.o \
+ ./protocols/IcqOscarJ/init.o \
+ ./protocols/IcqOscarJ/log.o \
+ ./protocols/IcqOscarJ/UI/askauthentication.o \
+ ./protocols/IcqOscarJ/icq_firstrun.o \
+ ./protocols/IcqOscarJ/icq_opts.o \
+ ./protocols/IcqOscarJ/icq_popups.o \
+ ./protocols/IcqOscarJ/icq_rates.o \
+ ./protocols/IcqOscarJ/icq_uploadui.o \
+ ./protocols/IcqOscarJ/UI/loginpassword.o \
+ ./protocols/IcqOscarJ/UI/userinfotab.o \
+ ./protocols/IcqOscarJ/changeinfo/constants.o \
+ ./protocols/IcqOscarJ/changeinfo/db.o \
+ ./protocols/IcqOscarJ/changeinfo/dlgproc.o \
+ ./protocols/IcqOscarJ/changeinfo/editlist.o \
+ ./protocols/IcqOscarJ/changeinfo/editstring.o \
+ ./protocols/IcqOscarJ/changeinfo/main.o \
+ ./protocols/IcqOscarJ/changeinfo/upload.o \
+ ./protocols/IcqOscarJ/capabilities.o \
+ ./protocols/IcqOscarJ/forkthread.o \
+ ./protocols/IcqOscarJ/i18n.o \
+ ./protocols/IcqOscarJ/icq_avatar.o \
+ ./protocols/IcqOscarJ/icq_clients.o \
+ ./protocols/IcqOscarJ/icq_fieldnames.o \
+ ./protocols/IcqOscarJ/icq_http.o \
+ ./protocols/IcqOscarJ/icq_infoupdate.o \
+ ./protocols/IcqOscarJ/icq_packet.o \
+ ./protocols/IcqOscarJ/icq_server.o \
+ ./protocols/IcqOscarJ/icq_servlist.o \
+ ./protocols/IcqOscarJ/icq_xstatus.o \
+ ./protocols/IcqOscarJ/icq_xtraz.o \
+ ./protocols/IcqOscarJ/icqoscar.o \
+ ./protocols/IcqOscarJ/md5.o \
+ ./protocols/IcqOscarJ/oscar_filetransfer.o \
+ ./protocols/IcqOscarJ/stdpackets.o \
+ ./protocols/IcqOscarJ/tlv.o \
+ ./protocols/IcqOscarJ/utilities.o \
+ ./protocols/IcqOscarJ/resources.res
+
+WEATHEROBJS = ./protocols/weather/forkthread.o \
+ ./protocols/weather/weather_addstn.o \
+ ./protocols/weather/weather.o \
+ ./protocols/weather/weather_contacts.o \
+ ./protocols/weather/weather_conv.o \
+ ./protocols/weather/weather_data.o \
+ ./protocols/weather/weather_http.o \
+ ./protocols/weather/weather_info.o \
+ ./protocols/weather/weather_ini.o \
+ ./protocols/weather/weather_opt.o \
+ ./protocols/weather/weather_popup.o \
+ ./protocols/weather/weather_svcs.o \
+ ./protocols/weather/weather_update.o \
+ ./protocols/weather/weather_userinfo.o \
+ ./protocols/weather/resource.res
+
+YAHOOOBJS = ./protocols/Yahoo/avatar.o \
+ ./protocols/Yahoo/chat.o \
+ ./protocols/Yahoo/file_transfer.o \
+ ./protocols/Yahoo/http_gateway.o \
+ ./protocols/Yahoo/im.o \
+ ./protocols/Yahoo/main.o \
+ ./protocols/Yahoo/options.o \
+ ./protocols/Yahoo/search.o \
+ ./protocols/Yahoo/server.o \
+ ./protocols/Yahoo/services.o \
+ ./protocols/Yahoo/util.o \
+ ./protocols/Yahoo/webcam.o \
+ ./protocols/Yahoo/yahoo.o \
+ ./protocols/Yahoo/libyahoo2/crypt.o \
+ ./protocols/Yahoo/libyahoo2/libyahoo2.o \
+ ./protocols/Yahoo/libyahoo2/md5.o \
+ ./protocols/Yahoo/libyahoo2/sha.o \
+ ./protocols/Yahoo/libyahoo2/yahoo_fn.o \
+ ./protocols/Yahoo/libyahoo2/yahoo_httplib.o \
+ ./protocols/Yahoo/libyahoo2/yahoo_list.o \
+ ./protocols/Yahoo/libyahoo2/yahoo_util.o \
+ ./protocols/Yahoo/Yahoo.res
+
+JABBEROBJS = ./protocols/JabberG/jabber.o \
+ ./protocols/JabberG/jabber_agent.o \
+ ./protocols/JabberG/jabber_bitmap.o \
+ ./protocols/JabberG/jabber_byte.o \
+ ./protocols/JabberG/jabber_chat.o \
+ ./protocols/JabberG/jabber_file.o \
+ ./protocols/JabberG/jabber_form.o \
+ ./protocols/JabberG/jabber_ft.o \
+ ./protocols/JabberG/jabber_groupchat.o \
+ ./protocols/JabberG/jabber_iq.o \
+ ./protocols/JabberG/jabber_iqid.o \
+ ./protocols/JabberG/jabber_iqid_muc.o \
+ ./protocols/JabberG/jabber_libstr.o \
+ ./protocols/JabberG/jabber_list.o \
+ ./protocols/JabberG/jabber_menu.o \
+ ./protocols/JabberG/jabber_misc.o \
+ ./protocols/JabberG/jabber_opt.o \
+ ./protocols/JabberG/jabber_password.o \
+ ./protocols/JabberG/jabber_proxy.o \
+ ./protocols/JabberG/jabber_ssl.o \
+ ./protocols/JabberG/jabber_std.o \
+ ./protocols/JabberG/jabber_svc.o \
+ ./protocols/JabberG/jabber_thread.o \
+ ./protocols/JabberG/jabber_userinfo.o \
+ ./protocols/JabberG/jabber_util.o \
+ ./protocols/JabberG/jabber_vcard.o \
+ ./protocols/JabberG/jabber_ws.o \
+ ./protocols/JabberG/jabber_xml.o \
+ ./protocols/JabberG/jabber_xmlns.o \
+ ./protocols/JabberG/sha1.o \
+ ./protocols/JabberG/msvc6.res
+
+MSNOBJS = ./protocols/MSN/mmdecsjis.o \
+ ./protocols/MSN/msn.o \
+ ./protocols/MSN/msn_bitmap.o \
+ ./protocols/MSN/msn_chat.o \
+ ./protocols/MSN/msn_commands.o \
+ ./protocols/MSN/msn_contact.o \
+ ./protocols/MSN/msn_errors.o \
+ ./protocols/MSN/msn_ftold.o \
+ ./protocols/MSN/msn_http.o \
+ ./protocols/MSN/msn_libstr.o \
+ ./protocols/MSN/msn_lists.o \
+ ./protocols/MSN/msn_md5c.o \
+ ./protocols/MSN/msn_mime.o \
+ ./protocols/MSN/msn_misc.o \
+ ./protocols/MSN/msn_msgqueue.o \
+ ./protocols/MSN/msn_opts.o \
+ ./protocols/MSN/msn_p2p.o \
+ ./protocols/MSN/msn_p2ps.o \
+ ./protocols/MSN/msn_srv.o \
+ ./protocols/MSN/msn_ssl.o \
+ ./protocols/MSN/msn_std.o \
+ ./protocols/MSN/msn_svcs.o \
+ ./protocols/MSN/msn_switchboard.o \
+ ./protocols/MSN/msn_threads.o \
+ ./protocols/MSN/msn_useropts.o \
+ ./protocols/MSN/msn_ws.o \
+ ./protocols/MSN/sha1.o \
+ ./protocols/MSN/resource.res
+
+PNG2DIBOBJS = ./plugins/png2dib/png2dib.o \
+ ./plugins/png2dib/version.res
+
+POPUPOBJS = ./plugins/popup/buffer.o \
+ ./plugins/popup/list.o \
+ ./plugins/popup/main.o \
+ ./plugins/popup/resource.res
+
+NSNOBJS = ./plugins/popup/buffer.o \
+ ./plugins/popup/indiv_sounds.o \
+ ./plugins/popup/main.o \
+ ./plugins/popup/statuschange.o \
+ ./plugins/newstatusnotify/resource.res
+
+SAWAYOBJS = ./plugins/simpleaway/awaymsg.o \
+ ./plugins/simpleaway/main.o \
+ ./plugins/simpleaway/msgbox.o \
+ ./plugins/simpleaway/options.o \
+ ./plugins/simpleaway/random.o \
+ ./plugins/simpleaway/resource.res
+
+SEENOBJS = ./plugins/seenplugin/file.o \
+ ./plugins/seenplugin/history.o \
+ ./plugins/seenplugin/main.o \
+ ./plugins/seenplugin/menu.o \
+ ./plugins/seenplugin/missed.o \
+ ./plugins/seenplugin/options.o \
+ ./plugins/seenplugin/userinfo.o \
+ ./plugins/seenplugin/utils.o \
+ ./plugins/seenplugin/resource.res
+
+AVSOBJS = ./plugins/avatarservice/commonheaders.o \
+ ./plugins/avatarservice/main.o \
+ ./plugins/avatarservice/options.o \
+ ./plugins/avatarservice/avatars.res
+
+TABSRMMOBJS = ./plugins/tabsrmm/container.o \
+ ./plugins/tabsrmm/containeroptions.o \
+ ./plugins/tabsrmm/eventpopups.o \
+ ./plugins/tabsrmm/formatting.o \
+ ./plugins/tabsrmm/hotkeyhandler.o \
+ ./plugins/tabsrmm/ImageDataObject.o \
+ ./plugins/tabsrmm/msgdialog.o \
+ ./plugins/tabsrmm/msgdlgutils.o \
+ ./plugins/tabsrmm/msglog.o \
+ ./plugins/tabsrmm/msgoptions.o \
+ ./plugins/tabsrmm/msgs.o \
+ ./plugins/tabsrmm/selectcontainer.o \
+ ./plugins/tabsrmm/sendqueue.o \
+ ./plugins/tabsrmm/srmm.o \
+ ./plugins/tabsrmm/tabctrl.o \
+ ./plugins/tabsrmm/templates.o \
+ ./plugins/tabsrmm/themes.o \
+ ./plugins/tabsrmm/trayicon.o \
+ ./plugins/tabsrmm/TSButton.o \
+ ./plugins/tabsrmm/URLCtrl.o \
+ ./plugins/tabsrmm/userprefs.o \
+ ./plugins/tabsrmm/tabsrmm_private.res
+
+CHATOBJS = ./plugins/chat/chat.res \
+ ./plugins/chat/clist.o \
+ ./plugins/chat/colorchooser.o \
+ ./plugins/chat/log.o \
+ ./plugins/chat/main.o \
+ ./plugins/chat/manager.o \
+ ./plugins/chat/message.o \
+ ./plugins/chat/options.o \
+ ./plugins/chat/richutil.o \
+ ./plugins/chat/services.o \
+ ./plugins/chat/tools.o \
+ ./plugins/chat/window.o
+
+#all: miranda-core plugin-db3x plugin-clist plugin-srmm protocol-icq protocol-weather protocol-yahoo protocol-jabber protocol-msn plugin-png2dib plugin-popup plugin-nsn plugin-simpleaway plugin-lastseen plugin-loadavatars
+#all: miranda-core plugin-db3x plugin-clist plugin-srmm plugin-png2dib protocol-icq protocol-yahoo protocol-jabber protocol-msn
+ all: miranda-core plugin-db3x plugin-clist plugin-srmm plugin-png2dib protocol-icq protocol-jabber protocol-msn
+#all: protocol-yahoo
+
+miranda-core: $(MAINOBJS)
+ $(CC) $(MAINOBJS) $(LNK_COMMON) $(LNK_MAINLIBS) -o miranda32.exe
+
+plugin-db3x: $(DB3XOBJS)
+ $(CC) -shared ./plugins/db3x/dbx_3x.spec $(DB3XOBJS) $(LNK_COMMON) -o dbx_3x.dll
+
+plugin-clist: $(CLISTOBJS)
+ $(CC) -shared ./plugins/clist/clist_classic.spec $(CLISTOBJS) $(LNK_COMMON) -luuid -o clist_classic.dll
+
+plugin-srmm: $(SRMMOBJS)
+ $(CC) -shared ./plugins/srmm/srmm.spec $(SRMMOBJS) $(LNK_COMMON) -luuid -o srmm.dll
+
+protocol-icq: $(ICQOBJS)
+ $(CC) -shared ./protocols/IcqOscarJ/icq.spec $(ICQOBJS) $(LNK_COMMON) -o icq.dll
+
+protocol-weather: $(WEATHEROBJS)
+ $(CC) -shared ./protocols/weather/weather.spec $(WEATHEROBJS) $(LNK_COMMON) -lws2_32 -o weather.dll
+
+protocol-yahoo: $(YAHOOOBJS)
+ $(CC) -shared ./protocols/Yahoo/yahoo.spec $(YAHOOOBJS) $(LNK_COMMON) -lpthread -o yahoo.dll
+
+protocol-jabber: $(JABBEROBJS)
+ $(CPP) -shared ./protocols/JabberG/jabber.spec $(JABBEROBJS) $(LNK_COMMON) -luuid -lversion -lwsock32 -o jabber.dll
+
+protocol-msn: $(MSNOBJS)
+ $(CPP) -shared ./protocols/MSN/msn.spec $(MSNOBJS) $(LNK_COMMON) -lrpcrt4 -luuid -lwsock32 -lws2_32 -o msn.dll
+
+plugin-png2dib: $(PNG2DIBOBJS)
+ $(CC) -shared ./plugins/png2dib/png2dib.spec $(PNG2DIBOBJS) $(LNK_COMMON) -lpng -o png2dib.dll
+
+plugin-chat: $(CHATOBJS)
+ $(CC) -shared ./plugins/chat/chat.spec $(CHATOBJS) $(LNK_COMMON) -lshlwapi -luuid -lversion -o chat.dll
+
+plugin-popup: $(POPUPOBJS)
+ $(CC) -shared ./plugins/popup/popup.spec $(POPUPOBJS) $(LNK_COMMON) -o popup.dll
+
+plugin-nsn: $(NSNOBJS)
+ $(CC) -shared ./plugins/newstatusnotify/newstatusnotify.spec $(NSNOBJS) $(LNK_COMMON) -o newstatusnotify.dll
+
+plugin-simpleaway: $(SAWAYOBJS)
+ $(CC) -shared ./plugins/simpleaway/simpleaway.spec $(SAWAYOBJS) $(LNK_COMMON) -o simpleaway.dll
+
+plugin-lastseen: $(SEENOBJS)
+ $(CC) -shared ./plugins/seenplugin/seenplugin.spec $(SEENOBJS) $(LNK_COMMON) -o seenplugin.dll
+
+plugin-loadavatars: $(AVSOBJS)
+ $(CC) -shared ./plugins/avatarservice/loadavatars.spec $(AVSOBJS) $(LNK_COMMON) -lmsimg32 -o loadavatars.dll
+
+plugin-tabsrmm: $(TABSRMMOBJS)
+ $(CC) -shared ./plugins/tabsrmm/tabsrmm.spec $(TABSRMMOBJS) $(LNK_COMMON) -o tabsrmm.dll
+
+.c.o:
+ $(CC) -c $(CPPFLAGS) -DNDEBUG -o $@ $<
+
+.cpp.o:
+ $(CPP) -c $(CPPFLAGS) -DNDEBUG -o $@ $<
+
+%.res: %.rc
+ $(WRC) -I. -I./include $< -o $@
+
+clean:
+ rm -f miranda32 *.so *~
+ find . -regex '.*\.\(o\|res\|orig\|rej\)' -exec rm -f {} \;
+ find . -name *~ -exec rm -f {} \;
+
+
+
diff --git a/miranda-wine/docs/credits.txt b/miranda-wine/docs/credits.txt
new file mode 100644
index 0000000..ce78e49
--- /dev/null
+++ b/miranda-wine/docs/credits.txt
@@ -0,0 +1,36 @@
+Miranda IM is brought to you by:
+Martin Öberg
+George Hazan
+Robert Rainwater
+Lyon Lim
+Gennady Feldman
+Joe Kucera
+Adam Strzelecki
+Piotr Piastucki
+Alex Sanda
+Aaron Myles Landwehr
+
+Retired Members:
+Richard Hughes
+Emostar
+Esnow
+Figbug
+Tristan_VdV
+Crypt0gl
+Lowspirit
+Glutnix
+Santithorn Bunchua
+Sam K
+Jörgen Persson
+
+All the plugin developers, who are too multitudinous to name individually, but you can find out who they are when you download their work from the website.
+
+The translators, who have done great things for increasing Miranda IM's user base, and who will be infuriated that I won't let them change this text.
+
+The media developers, who made the icons, sounds and skins you see on the website. A special thanks to a0x, Faith Healer, Quadrone, and Valkyre for their work on the application icons. Be sure to check out their other creations as well.
+
+The bug reporters, who give Miranda IM its quality. Extra special mention to those who helped with the really difficult ones and went a long way out of their way to help me fix them.
+
+The web forum residents, who discover new and exciting ways to break Miranda IM daily and who are the gestalt that shapes how Miranda IM works.
+
+The users, who...er...use it. \ No newline at end of file
diff --git a/miranda-wine/include/m_addcontact.h b/miranda-wine/include/m_addcontact.h
new file mode 100644
index 0000000..b5a7495
--- /dev/null
+++ b/miranda-wine/include/m_addcontact.h
@@ -0,0 +1,65 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_ADDCONTACT_H__
+#define M_ADDCONTACT_H__ 1
+
+typedef struct{
+ int handleType; //one of the HANDLE_ constants
+ HANDLE handle; //hDbEvent if acs.handleType==HANDLE_EVENT, hContact if acs.handleType==HANDLE_CONTACT, ignored if acs.handleType==HANDLE_SEARCHRESULT
+ const char *szProto; //ignored if acs.handleType!=HANDLE_SEARCHRESULT
+ PROTOSEARCHRESULT *psr; //ignored if acs.handleType!=HANDLE_SEARCHRESULT
+}ADDCONTACTSTRUCT;
+
+/*
+ Description: Open the add contact dialog, see notes
+
+ wParam=[ (WPARAM)hWndParent ]
+ lParam=(LPARAM)(ADDCONTACTSTRUCT*)&acs
+
+ Notes:
+
+ During 0.3.0.0 development (circa 2003/06/08)
+
+ An entire copy of the ADDCONTACTSTRUCT structure is made,
+ the PROTOSEARCHRESULT is also copied at psr->cbSize, all default
+ strings are copied (even if they're not needed/used)
+ if you pass a structure that is bigger than PROTOSEARCHRESULT
+ then do not use pointers in the newly defined area because
+ they will not be copied.
+
+ passing wParam==NULL will result in a dialog that is created modeless
+
+ Before the circa, a modal dialog was *always* created and
+ strings within PROTOSEARCHRESULT were not copied.
+
+*/
+
+#define HANDLE_SEARCHRESULT 0
+#define HANDLE_EVENT 1
+#define HANDLE_CONTACT 2
+#define MS_ADDCONTACT_SHOW "AddContact/Show"
+
+#endif // M_ADDCONTACT_H__
+
+
diff --git a/miranda-wine/include/m_awaymsg.h b/miranda-wine/include/m_awaymsg.h
new file mode 100644
index 0000000..05dd295
--- /dev/null
+++ b/miranda-wine/include/m_awaymsg.h
@@ -0,0 +1,41 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_AWAYMSG_H__
+#define M_AWAYMSG_H__ 1
+
+//show the away/na/etc message for a contact v0.1.0.1+
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=0
+//returns 0 on success or nonzero on failure
+//returns immediately, without waiting for the message to retrieve
+#define MS_AWAYMSG_SHOWAWAYMSG "SRAway/GetMessage"
+
+//returns the default status message for a status
+//wParam=(int)status
+//lParam=0
+//returns status msg. Remember to free the return value
+#define MS_AWAYMSG_GETSTATUSMSG "SRAway/GetStatusMessage"
+
+#endif // M_AWAYMSG_H__
+
diff --git a/miranda-wine/include/m_button.h b/miranda-wine/include/m_button.h
new file mode 100644
index 0000000..304f1bd
--- /dev/null
+++ b/miranda-wine/include/m_button.h
@@ -0,0 +1,59 @@
+/*
+Miranda IM
+Copyright (C) 2002 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.
+*/
+// Added in 0.3.0.0+
+
+#ifndef M_BUTTON_H__
+#define M_BUTTON_H__ 1
+
+#define MIRANDABUTTONCLASS _T( "MButtonClass" ) // Class of the control
+
+
+// Sets whether a dropdown arrow is used
+// wParam = TRUE/FALSE turns arrow on or off
+// lParam = not used
+// Usage: SendMessage(hwndbutton,BUTTONSETARROW,1,0);
+// Only works on MButtonClass buttons
+#define BUTTONSETARROW (WM_USER+1)
+
+// Sets whether the button is a default button
+// wParam = TRUE/FALSE default on/off
+// lParam = not used
+// Usage: SendMessage(hwndbutton,BUTTONSETDEFAULT,1,0);
+// Only works on MButtonClass buttons
+#define BUTTONSETDEFAULT (WM_USER+2)
+
+// Sets the button as a push button
+// wParam = lParam = not used
+// Usage: SendMessage(hwndbutton,BUTTONSETASPUSHBTN,0,0);
+// Only works on MButtonClass buttons
+#define BUTTONSETASPUSHBTN (WM_USER+3)
+
+// Sets the button type as a flat button without borders v0.3.3+
+// Usage: SendMessage(hwndbutton,BUTTONSETASFLATBTN,0,0);
+// Only works on MButtonClass buttons
+#define BUTTONSETASFLATBTN (WM_USER+4)
+
+// Sets a tooltip for the button v0.3.3+
+// wParam = (WPARAM)(char *)szTip
+// lParam = not used
+// Usage: SendMessage(hwndButton,BUTTONADDTOOLTIP,(WPARAM)"My Tip",0);
+#define BUTTONADDTOOLTIP (WM_USER+5)
+
+#endif // M_BUTTON_H__
+
diff --git a/miranda-wine/include/m_chat.h b/miranda-wine/include/m_chat.h
new file mode 100644
index 0000000..8003795
--- /dev/null
+++ b/miranda-wine/include/m_chat.h
@@ -0,0 +1,631 @@
+/*
+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.
+*/
+
+
+
+/*
+ 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 hContacts 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.
+
+ NOTE. Chat keeps its own copies of strings passed.
+
+
+
+
+ * * Example of implementing this rule * *:
+ * * This is a code snippet that is common in protocols * *:
+
+
+
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact)
+ {
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ if (szProto != NULL && !lstrcmpi(szProto, PROTONAME))
+ {
+ ... do something with the hContact here;
+ }
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ }
+
+
+
+ * * You should do this instead * *:
+
+
+
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact)
+ {
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ if (szProto != NULL && !lstrcmpi(szProto, PROTONAME))
+ {
+ if(DBGetContactSettingByte(hContact, PROTONAME, "ChatRoom", 0) == 0)
+ {
+ ... do something with the hContact here;
+ }
+ }
+ hContact = (HANDLE) 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 anything other than 0,
+
+
+
+
+
+
+ OK, enough of the precautions, HOW DO YOU USE CHAT? In short you need to do FOUR things:
+
+ 1. REGISTER your protocol with Chat
+ Only registered protocols can use Chat
+
+ 2. CREATE SESSIONS when your protocol are joining a group chat room. (One per room joined)
+ These sessions will be put on the contact-list and are managed totally by chat.
+ This is the reason you must obey to the "precautions" I mentioned above.
+ Do not tamper directly with Chat's hContacts. Use Services provided by Chat instead.
+
+ 3. SEND EVENTS to the sessions created in #3.
+ These events reflect users joining/leaving/speaking etc.
+
+ 4. DESTROY SESSIONS when the user leaves the room (ie the session is not needed anymore).
+
+ These four points are implemented in three services: MS_GC_REGISTER, MS_GC_NEWSESSION
+ and MS_GC_EVENT.
+*/
+
+
+//------------------------- SERVICES ------------------------
+/*
+ Step 1. -- REGISTER with Chat --
+
+ The first thing that a protocol need to do is register with Chat. This is best done
+ when ALL modules has loaded (ME_SYSTEM_MODULESLOADED). The registration is
+ needed to make sure that the protocol obey rule 1 mentioned above, but also to
+ set protocol specific preferences.
+
+ * Use MS_GC_REGISTER like this: CallService(MS_GC_REGISTER, 0, (LPARAM)(GCREGISTER *) &gcr;
+
+ * returns 0 on success or error code on failure.
+*/
+
+// Flags
+#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 acknowlege messages sent
+#define GC_TYPNOTIF 0x0040 //NOT SUPPORTED YET! Enable typing notifications.
+#define GC_CHANMGR 0x0080 //enable the 'channel settings' button
+#define GC_UNICODE 0x0100 //NOT SUPPORTED YET! Enable unicode (if chat supports it),
+ //Pass UNICODE instead of ASCII. Note that
+ //registration will fail if the unicode version of chat is not installed //isn't installed. Check what MS_GC_REGISTER returns.
+// Error messages
+#define GC_REGISTER_WRONGVER 1 //You appear to be using the wrong version of this API. Registration failed.
+#define GC_REGISTER_ERROR 2 //An internal error occurred. Registration failed.
+#define GC_REGISTER_NOUNICODE 3 //MS_GC_REGISTER returns this error if the Unicode version of chat
+ //is not installed and GC_UNICODE is set. Registration failed
+
+// GCREGISTER struct
+typedef struct {
+ int cbSize; //Set to sizeof(GCREGISTER);
+ DWORD dwFlags; //Use GC_* flags above to indicate features supported
+ const char* pszModule; //This MUST be the protocol name as registered with Miranda IM
+ const char* pszModuleDispName; //This is the protocol's real name as it will be displayed to the user
+ int iMaxText; //Max message length the protocol supports. Will limit the typing area input. 0 = no limit
+ int nColors; //Number of colors in the colorchooser menu for the color buttons. Max = 100
+ COLORREF* pColors; //pointer to the first item in a static COLORREF array containing the colors
+ //that should be showed in the colorchooser menu.
+ //ie: COLORREF crCols[nColors];
+ // pColors = &crCols[0];
+ } GCREGISTER;
+
+#define MS_GC_REGISTER "GChat/Register"
+
+
+
+
+
+
+
+/*
+ Step 2. -- CREATE a new SESSION --
+
+ Create a new session (chat room) and set various settings related to it.
+ The chat room will not be shown to the user until the 'set up' phase is
+ completed and SESSION_INITDONE is sent. See the MS_GC_EVENT for that.
+
+ * Use MS_GC_NEWSESSION like this: CallService(MS_GC_NEWSESSION, 0, (LPARAM)(GCSESSION *) &gcr;
+
+ * returns 0 on success or error code on failure
+*/
+
+
+// Session type
+#define GCW_CHATROOM 1 // the session is a dedicated multi user chat room. ex "IRC channels".
+ // A hContact will be added for the session
+#define GCW_SERVER 2 // the session is used as a network console. ex "IRC server window"
+ // A hContact will be added for the session, but it will default to being hidden (on the CList)
+#define GCW_PRIVMESS 3 // NOT SUPPORTED YET! the session is a 1 to 1 session, but with additional
+ // support for adding more users etc. ex "MSN session".
+
+
+
+// Error messages
+#define GC_NEWSESSION_WRONGVER 1 //You appear to be using the wrong version of this API.
+#define GC_NEWSESSION_ERROR 2 //An internal error occurred.
+
+
+// GCREGISTER structure
+typedef struct {
+ int cbSize; //Set to sizeof(GCSESSION);
+ int iType; //Use one of the GCW_* flags above to set the type of session
+ const char *pszModule; //The name of the protocol owning the session (the same as pszModule when you register)
+ const char *pszName; //The name of the session as it will be displayed to the user
+ const char *pszID; //The unique identifier for the session.
+ const char *pszStatusbarText; //Optional text to set in the statusbar of the chat room window, or NULL.
+ BOOL bDisableNickList; //SUPPORT REMOVED in Chat 0.3+ but still included to not break existing implementations.
+ DWORD dwItemData; //Set user defined data for this session. Retrieve it by using the GC_EVENT_GETITEMDATA event
+ } GCSESSION;
+#define MS_GC_NEWSESSION "GChat/NewChat"
+
+
+
+
+
+
+/*
+ Step 3 -- SEND an EVENT --
+
+ Events is what drives Chat! After having created the session in Step 2
+ it is time to make it work for real. Follow these guidelines:
+
+ 1. Start off by telling Chat what possible statuses a user can have (in the nicklist)
+ by sending GC_EVENT_ADDGROUP as many times as needed. Also supply an icon
+ to go with this status. Ex "Voice status" on IRC
+
+ 2.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. As long as
+ SESSION_INITDONE has not been sent these events will not show up in the log.
+
+ 3.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 GC_EVENT_CONTROL event
+ with wParam = SESSION_INITDONE.
+
+ 4.You will also want to send a GC_EVENT_CONTROL with wParam = SESSION_ONLINE to
+ make the statusbar and the CList item go to "online" status
+
+ You have now set up the session and made it active. A CList hContact has been added
+ to the contact list and a chat room window is associated to the session. Send EVENTS to
+ Chat users speaking, users joining and so on. See below for full
+ list of what events are possible.
+
+ IMPORTANT: For sending events you'll use the GCEVENT and GCDEST structures. A GCDEST
+ structure pointer is passed inside GCEVENT and it tells Chat what event type it is
+ and what session it is related to. The GCDEST structure and its members are ALWAYS
+ used (but the members can be NULL in some occasions). Depending on what type of event
+ you are sending, the members of GCEVENT have different usage. Each event and how to
+ use the members are discussed below. The "bAddToLog" and "time" members are always valid
+ and always mean the same. bAddToLog = TRUE means that the event is added to the disk log
+ (at least when this makes sense). This can be used by Jabber for instance, when
+ it needs to add channel history to the window, but without logging to disk.
+ The "time" member is the timestamp of the event.(Tip. use the function time(NULL)
+ to set the current time)
+
+ NOTE. It is possible to send formatted text (bold, italics, underlined, foreground color
+ and background color) to Chat by using the following identifiers in the text (pszText):
+
+ %cXX - set the foreground color ( XX is the zero based decimal index of the color registered in MS_GC_REGISTER.. Always use two digits )
+ %C - reset foreground color to default
+ %fXX - set the background color ( XX is the zero based decimal index of the color registered in MS_GC_REGISTER.. Always use two digits )
+ %F - reset 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 %
+
+ IMPORTANT. If you have specified GC_COLOR or GC_BKGCOLOR when you registered you can expect to
+ get these identifiers in the text you receive from Chat as well. Make sure % is ALWAYS
+ translated to %% in text you send to Chat to avoid accidental formatting.
+ NOTE. You will not get %cRRRGGGBBB back, instead you will get the index of the colour as
+ registered with GC_REGISTER. Eg %c3 (the fourth colour of your index)
+
+ * Use MS_GC_EVENT like this: CallService(MS_GC_EVENT, 0, (LPARAM)(GCEVENT *) &gce;
+
+ * returns 0 on success or error code on failure
+
+*/
+
+// * List of possible events to send to Chat. Unlisted members are not valid *
+// * for the event. Listed members are mandatory unless otherwise specified *
+
+
+// GC_EVENT_JOIN - "<pszNick> has joined" (A user is joining the session)
+// pszNick - Display name
+// pszUID - Unique identifier of the user
+// pszStatus - Which status does the user have. Should be a status previously
+// registered with GC_EVENT_ADDGROUP. Ex "Voice" in IRC
+// bIsMe - Set to TRUE if it is the Miranda user
+// Chat needs to know which user in the userlist that is "self"
+// It cannot highlight a message containing the "own" nick without this info
+// NOTE. if time == NULL, then the event will not be shown in the message log
+#define GC_EVENT_JOIN 0x0001
+
+// GC_EVENT_PART - "<pszNick> has left: <pszText>" (A user left the session)
+// pszNick - Display name
+// pszUID - Unique identifier
+// pszText - Optional part message, can be NULL
+#define GC_EVENT_PART 0x0002
+
+// GC_EVENT_QUIT - "<pszNick> disconnected: pszText" (A user disconnected from the network)
+// pszID(in GCDEST) - Should be NULL as a disconnect event is global.
+// pszNick - Display name
+// pszUID - Unique identifier
+// pszText - Optional disconnect message, can be NULL
+#define GC_EVENT_QUIT 0x0004
+
+// GC_EVENT_KICK - "<pszStatus> kicked <pszNick>: <pszText>" (A user is kicking another user from the room)
+// pszNick - Display name of the one being being kicked
+// pszUID - Unique identifier of the one being kicked
+// pszStatus - Name of user who is doing the kicking
+// pszText - Optional kick message, can be NULL
+#define GC_EVENT_KICK 0x0008
+
+// GC_EVENT_NICK - "<pszNick> is now known as <pszText>" (A user changed his name)
+// NOTE, see GC_EVENT_CHUID also
+// pszID(in GCDEST) - Should be NULL as a nick change event is global.
+// pszNick - Old display name
+// pszUID - Unique identifier
+// pszText - New display name of the user. Color codes are not valid
+#define GC_EVENT_NICK 0x0010
+
+// GC_EVENT_NOTICE - "Notice from <pszNick>: <pszText>" (An IRC type notice)
+// pszID(in GCDEST) - Should be NULL to send to the active window
+// pszNick - Display name
+// pszUID - Unique identifier
+// pszText - Notice text
+#define GC_EVENT_NOTICE 0x0020
+
+// GC_EVENT_MESSAGE - "<pszNick>: <pszText> (A user is speaking)
+// pszNick - Display name
+// pszUID - Unique identifier
+// bIsMe - Set to TRUE if it is the Miranda user
+// pszText - Message text.
+#define GC_EVENT_MESSAGE 0x0040
+
+// GC_EVENT_TOPIC - "Topic is <pszText> (Set by: <pszNick>" (The room topic was changed/set)
+// pszNick - Optional display name of who set the topic, can be NULL
+// pszUID - Optional unique identifier of who set the topic, can be NULL
+// pszText - Topic text
+#define GC_EVENT_TOPIC 0x0080
+
+// GC_EVENT_INFORMATION (Informational text) Ex a server response to a /WHO command in IRC
+// pszID(in GCDEST) - NULL to send to the active window
+// pszText - Information text
+#define GC_EVENT_INFORMATION 0x0100
+
+// GC_EVENT_ACTION - "<pszNick> <pszText>" (An IRC Style action event)
+// pszNick - Display name
+// pszUID - Unique identifier
+// bIsMe - Set to TRUE if it is the Miranda user
+// pszText - Message text.
+#define GC_EVENT_ACTION 0x0200
+
+// GC_EVENT_ADDSTATUS - "<pszText> enables '<pszStatus>' for <pszNick>" (A status change has occured for a user)
+// NOTE. Status changes are cumulative. The user will show in the nicklist with the highest status received.
+// Ex, IRC users can have "Op" and "Voice" statuses simultaneously but s/he will be displayed as "Op"
+// pszNick - Display name of the one who receives a new status
+// pszUID - Unique identifier of the one who receives a new status
+// pszText - The display name of the one who is setting the status. Color codes are not valid
+// pszStatus - The status. Should be a status previously
+// registered with GC_EVENT_ADDGROUP. Ex "Voice" in IRC
+#define GC_EVENT_ADDSTATUS 0x0400
+
+// GC_EVENT_REMOVESTATUS - "<pszText> disables '<pszStatus>' for <pszNick>" (A status change has occured for a user)
+// NOTE. Status changes are cumulative. The user will show in the nicklist with the highest status received.
+// Ex, IRC users can have "Op" and "Voice" statuses simultaneously but s/he will be displayed as "Op"
+// pszNick - Display name of the one who got a status mode disabled
+// pszUID - Unique identifier of the one who got a status mode disabled
+// pszText - The display name of the one disabling the status. Color codes are not valid
+// pszStatus - The status. Should be a status previously
+// registered with GC_EVENT_ADDGROUP. Ex "Voice" in IRC
+#define GC_EVENT_REMOVESTATUS 0x0800
+
+// GC_EVENT_CHUID - not shown in the log (Change the unique identifier of a contact)
+// pszID(in GCDEST) - Should be NULL as a unique id's are global.
+// pszUID - The current unique identifier
+// pszText - The new unique identifier. Color codes are not valid
+#define GC_EVENT_CHUID 0x1000
+
+// GC_EVENT_CHANGESESSIONAME - not shown in the log (Change the display name of a session)
+// pszText - The new name. Color codes are not valid
+#define GC_EVENT_CHANGESESSIONAME 0x1001
+
+// GC_EVENT_ADDGROUP - not shown in the log (Add a possible status mode to the nicklist, ex IRC uses "Op", "Voice", "Normal" etc )
+// NOTE. When adding several statuses, start with the highest status
+// pszStatus - The new group name
+// dwItemData - Optional HICON handle to a 10x10 icon. Set to NULL to use the built in icons.
+#define GC_EVENT_ADDGROUP 0x1002
+
+// GC_EVENT_SETITEMDATA & GC_EVENT_SETITEMDATA - not shown in the log (Get/Set the user defined data of a session)
+// dwItemData - The itemdata to set or get
+#define GC_EVENT_SETITEMDATA 0x1003
+#define GC_EVENT_GETITEMDATA 0x1004
+
+// GC_EVENT_SETSBTEXT - not shown in the log (Set the text of the statusbar for a chat room window)
+// pszText - Statusbar text. Color codes are not valid
+#define GC_EVENT_SETSBTEXT 0x1006
+
+// GC_EVENT_ACK - not shown in the log (Acknowledge a outgoing message, when GC_ACKMSG is set
+#define GC_EVENT_ACK 0x1007
+
+// GC_EVENT_SENDMESSAGE - not shown in the log ("Fake" a message from a chat room as if the user had typed it). Used by IRC to broadcast /AME and /AMSG messages
+// pszText - The text
+#define GC_EVENT_SENDMESSAGE 0x1008
+
+// GC_EVENT_SETSTATUSEX - not shown in the log (Space separated list of pszUID's to indicate as away).
+// Used by IRC to mark users as away in the nicklist. Remember that UID's cannot contain spaces.
+// Let me know if you need some other support for your protocol.
+// pszText - The space separated list of pszUID's
+#define GC_EVENT_SETSTATUSEX 0x1009
+
+// GC_EVENT_CONTROL - not shown in the log (Control window associated to a session and the session itself)
+// NOTE 1: No members of GCEVENT are used, send one of the below flags in wParam instead,
+// Ex CallService(GC_EVENT_CONTROL, SESSION_INITDONE, (LPARAM)&gce);
+// NOTE 2: The first four control events are the only ones you should use most likely!
+// The ones below them are used by IRC to join channels hidden or maximized and show the server window from the system menu.
+// The SESSION_VISIBLE, SESSION_HIDDEN, SESSION_MAXIMIZE and SESSION_MINIMIZE events CAN replace SESSION_INITDONE but I urge you not to
+// do that as it will override any settings the user has made in the Chat options
+// NOTE 3: If pszID (of GCDEST) = NULL then this message will be broadcasted to all sessions, which can be usefule for terminating
+// all sessions when the protocol was disconnected
+#define SESSION_INITDONE 1 //send this when the session is fully set up (all users have ben added to the nicklist)
+#define SESSION_TERMINATE 7 //send to terminate a session and close the window associated with it
+#define SESSION_OFFLINE 8 //send to set the session as "online" (hContact is set to Online etc)
+#define SESSION_ONLINE 9 //send to set the session as "offline" (hContact is set to Offline etc)
+//------------
+#define WINDOW_VISIBLE 2 //make the room window visible
+#define WINDOW_HIDDEN 3 //close the room window. Session is not terminated.
+#define WINDOW_MAXIMIZE 4 //make the room window maximized
+#define WINDOW_MINIMIZE 5 //make the room window minimized
+#define WINDOW_CLEARLOG 6 //clear the log of the room window
+
+#define GC_EVENT_CONTROL 0x1005
+
+
+
+// Error messages
+#define GC_EVENT_WRONGVER 1 //You appear to be using the wrong version of this API.
+#define GC_EVENT_ERROR 2 //An internal error occurred.
+
+
+
+// The GCDEST structure. It is passed to Chat inside GCEVENT.
+typedef struct {
+ char *pszModule; //Name of the protocol (same as you registered with)
+ char *pszID; //Unique identifier of the session, or NULL to broadcast to all sessions as specified above
+ int iType; //Use GC_EVENT_* as defined above. Only one event per service call.
+} GCDEST;
+
+
+// The GCEVENT structure
+typedef struct {
+ int cbSize; // Set to sizeof(GCEVENT);
+ GCDEST* pDest; // pointer to a GCDEST structure which specifies the session to receive the event
+ const char *pszText; // usage depends on type of event, max 2048 characters
+ const char *pszNick; // usage depends on type of event
+ const char *pszUID; // usage depends on type of event, Do NOT use spaces for unique user identifiers.
+ const char *pszStatus; // usage depends on type of event
+ const char *pszUserInfo; // Additional user information that is displayed after the nickname.
+ // IRC use it to display a hostmask for JOIN, PART (and more) events.
+ BOOL bIsMe; // Is this event from the Miranda user?
+ BOOL bAddToLog; // Display in the message log? There is no need to set this to
+ // FALSE any other time than when initializing the window (before sending SESSION_INITDONE)
+ DWORD dwItemData; // User specified data.
+ time_t time; // Timestamp of the event
+ } GCEVENT;
+
+#define MS_GC_EVENT "GChat/NewEvent"
+
+
+
+
+// OK! That was about everything that you need to know about for operating Chat in a basic way.
+// There are however some more things you will need to know about. Some you may use and some you may not need,
+
+
+
+/*
+ -- GETTING info about a SESSION or session data --
+
+ Use this service to get information on different aspects of the sessions that are registered with Chat.
+
+ * Use MS_GC_GETINFO like this: CallService(MS_GC_GETSESSIONCOUNT, 0, (LPARAM)(char *) pszModule);
+
+ * returns -1 on failure and the sessioncount on success
+*/
+#define MS_GC_GETSESSIONCOUNT "GChat/GetCount"
+
+
+
+
+/*
+ -- GETTING info about a SESSION or session data --
+
+ Use this service to get information on different aspects of the sessions that are registered with Chat.
+
+ * Use MS_GC_GETINFO like this: CallService(MS_GC_GETINFO, 0, (LPARAM)(GC_INFO *) &gci;
+
+ * returns 0 on success or error code on failure
+*/
+
+// Flags
+#define BYINDEX 0x0001 // iItem is valid and should contain the index of the session to get
+#define BYID 0x0002 // pszID is valid and should contain the ID of the session to get. This is the default if no
+#define HCONTACT 0x0004 // hContact is valid
+#define DATA 0x0008 // wItemData is valid
+#define ID 0x0010 // pszID is valid.
+#define NAME 0x0020 // pszName is valid
+#define TYPE 0x0040 // iType is valid
+#define COUNT 0x0080 // iCount is valid
+#define USERS 0x0100 // pszUsers is valid
+
+
+// The GC_INFO structure
+typedef struct {
+ DWORD Flags; // use a combination of the above flags
+ int iItem; // session type (GCW_*)
+ int iType; // session type (GCW_*)
+ char * pszModule; // the module name as registered in MS_GC_REGISTER
+ char * pszID; // unique ID of the session
+ char * pszName; // display name of the session
+ DWORD dwItemData; // user specified data.
+ int iCount; // count of users in the nicklist
+ char * pszUsers; // space separated string containing the UID's of the users in the user list.
+ // NOTE. Use Mirandas mmi_free() on the returned string.
+ HANDLE hContact; // hContact for the session (can be NULL)
+ } GC_INFO;
+#define MS_GC_GETINFO "GChat/GetInfo"
+
+
+
+
+
+//------------------------- HOOKS ------------------------
+/*
+ -- user interaction --
+ Hook this to receive notifications about when user take actions in a chat room window.
+ Check for the below flags to find out what type of user interaction it is. See the
+ to find out which members of GCHOOK that are valid.
+
+ * wParam=0
+ * lParam=(LPARAM)(GCEVENT *)pgch
+
+ * Returning nonzero from your hook will stop other hooks from being called.
+*/
+#define GC_USER_MESSAGE 1 // user sent a message, with \n delimiting lines, pszText contains the text.
+#define GC_USER_CHANMGR 2 // user clicked the settings button in a chat room
+#define GC_USER_LOGMENU 3 // user has selected a message log menu item, dwData is valid. See ME_GC_BUILDMENU
+#define GC_USER_NICKLISTMENU 4 // user has selected a userlist menu item, valid members: dwData. See ME_GC_BUILDMENU
+#define GC_USER_TYPNOTIFY 5 // NOT IMPLEMENTED YET! user is typing
+#define GC_USER_PRIVMESS 6 // user requests to send a private message to a user. pszUID is valid
+#define GC_USER_LEAVE 8 // user requests to leave the session
+#define GC_USER_CLOSEWND 9 // user closed the window (this is usually not an indication that the protocol
+ // should take action, but MSN may want to terminate the session here)
+#define GC_SESSION_TERMINATE 7 // the session is about to be terminated, the "user defined data" is passed in dwData, which can be good free'ing any allocated memory.
+#define ME_GC_EVENT "GChat/OutgoingEvent"
+
+typedef struct {
+ GCDEST* pDest; // pointer to a GCDEST structure which specifies from which session the hook was triggered
+ char * pszText; // usage depends on type of event
+ char * pszUID; // unique identifier, usage depends on type of event
+ DWORD dwData; // user defined data, usage depends on type of event
+ } GCHOOK;
+
+
+/*
+ -- Build the pop up menus --
+ The user wants to show a right click (popup) menu and your protocol should tell what
+ items should be added to the menu. You should create a static array of struct gc_item's.
+ When you get this notification you should set "nItems" to the number of gc_item's
+ you want to show on the user's popup menu and then set the "Item" member to point to that array.
+
+ * wParam=0
+ * lParam=(LPARAM)(GCMENUITEM *)gcmi
+
+ Returning nonzero from your hook will stop other hooks from being called.
+
+*/
+
+// type of item to add to the popup menu
+#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
+
+// type of menu that is being requested
+#define MENU_ON_LOG 1 // pop up menu on the message log
+#define MENU_ON_NICKLIST 2 // pop up menu on the user list
+
+// contains info on a menuitem to be added
+struct gc_item {
+ char * pszDesc; // Textual description of the menu item to add
+ DWORD dwID; // when/if the user selects this menu item this
+ // value will be returned via the above hook, GC_USER_LOGMENU
+ // or GC_USER_NICKLISTMENU. Must not be 0 and must be unique.
+ int uType; // What kind of menu item is it? Use MENU_* flags above
+ BOOL bDisabled; // should the menu item be shown as disabled
+ };
+
+typedef struct {
+ char * pszModule; // Contains the protocol name, do NOT change.
+ char * pszID; // The unique identifier of the session that triggered the hook, do NOT change.
+ char * pszUID; // Contains the unique identifier if Type = MENU_ON_NICKLIST. do NOT change.
+ int Type; // Type of menu. MENU_ON_* flags used. do NOT change.
+ int nItems; // Set this to the number of menu items you want to add
+ struct gc_item* Item; // pointer to the first in the array of gc_item's
+ } GCMENUITEMS;
+#define ME_GC_BUILDMENU "GChat/BuildMenu"
+
+/*
+ * Example of how to add 2 items to the popup menu for the userlist *
+
+ GCMENUITEMS *gcmi= (GCMENUITEMS*) lParam;
+ if(gcmi->Type == MENU_ON_NICKLIST)
+ {
+ static struct gc_item Item[] = {
+ {Translate("User &details"), 1, MENU_ITEM, FALSE},
+ {Translate("&Op"), 2, MENU_POPUPITEM, FALSE},
+ };
+
+ gcmi->nItems = sizeof(Item)/sizeof(Item[0]);
+ gcmi->Item = &Item[0];
+ gcmi->Item[gcmi->nItems-1].bDisabled = bFlag;
+
+ return 0;
+ }
+*/
diff --git a/miranda-wine/include/m_clc.h b/miranda-wine/include/m_clc.h
new file mode 100644
index 0000000..9f098bf
--- /dev/null
+++ b/miranda-wine/include/m_clc.h
@@ -0,0 +1,265 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_CLC_H__
+#define M_CLC_H__ 1
+
+//This module is new in 0.1.2.1
+
+#define CLISTCONTROL_CLASS _T("CListControl")
+
+//styles
+#define CLS_MANUALUPDATE 0x0001 //todo
+#define CLS_SHOWHIDDEN 0x0002
+#define CLS_HIDEOFFLINE 0x0004 //hides all offline users
+#define CLS_CHECKBOXES 0x0008
+#define CLS_MULTICOLUMN 0x0010 //not true multi-column, just for ignore/vis options
+#define CLS_HIDEEMPTYGROUPS 0x0020 //note: this flag will be spontaneously removed if the 'new subgroup' menu item is clicked, for obvious reasons
+#define CLS_USEGROUPS 0x0040
+#define CLS_NOHIDEOFFLINE 0x0080 //overrides CLS_HIDEOFFLINE and the per-group hideoffline setting
+#define CLS_GREYALTERNATE 0x0100 //make every other line slightly grey
+#define CLS_GROUPCHECKBOXES 0x0200 //put checkboxes on groups too (managed by CLC)
+#define CLS_CONTACTLIST 0x0400 //this control will be the main contact list (v. 0.3.4.3+ 2004/11/02)
+
+#define CLS_EX_DISABLEDRAGDROP 0x00000001
+#define CLS_EX_EDITLABELS 0x00000002
+#define CLS_EX_SHOWSELALWAYS 0x00000004
+#define CLS_EX_TRACKSELECT 0x00000008
+#define CLS_EX_SHOWGROUPCOUNTS 0x00000010
+#define CLS_EX_DIVIDERONOFF 0x00000020
+#define CLS_EX_HIDECOUNTSWHENEMPTY 0x00000040
+#define CLS_EX_NOTRANSLUCENTSEL 0x00000080
+#define CLS_EX_LINEWITHGROUPS 0x00000100
+#define CLS_EX_QUICKSEARCHVISONLY 0x00000200
+#define CLS_EX_SORTGROUPSALPHA 0x00000400
+#define CLS_EX_NOSMOOTHSCROLLING 0x00000800
+
+#define CLM_FIRST 0x1000 //this is the same as LVM_FIRST
+#define CLM_LAST 0x1100
+
+//messages, compare with equivalent TVM_s in the MSDN
+#define CLM_ADDCONTACT (CLM_FIRST+0) //wParam=hContact
+#define CLM_ADDGROUP (CLM_FIRST+1) //wParam=hGroup
+#define CLM_AUTOREBUILD (CLM_FIRST+2)
+#define CLM_DELETEITEM (CLM_FIRST+3) //wParam=hItem
+#define CLM_EDITLABEL (CLM_FIRST+4) //wParam=hItem
+#define CLM_ENDEDITLABELNOW (CLM_FIRST+5) //wParam=cancel, 0 to save
+#define CLM_ENSUREVISIBLE (CLM_FIRST+6) //wParam=hItem, lParam=partialOk
+#define CLE_TOGGLE -1
+#define CLE_COLLAPSE 0
+#define CLE_EXPAND 1
+#define CLE_INVALID 0xFFFF
+#define CLM_EXPAND (CLM_FIRST+7) //wParam=hItem, lParam=CLE_
+#define CLM_FINDCONTACT (CLM_FIRST+8) //wParam=hContact, returns an hItem
+#define CLM_FINDGROUP (CLM_FIRST+9) //wParam=hGroup, returns an hItem
+#define CLM_GETBKCOLOR (CLM_FIRST+10) //returns a COLORREF
+#define CLM_GETCHECKMARK (CLM_FIRST+11) //wParam=hItem, returns 1 or 0
+#define CLM_GETCOUNT (CLM_FIRST+12) //returns the total number of items
+#define CLM_GETEDITCONTROL (CLM_FIRST+13) //returns the HWND, or NULL
+#define CLM_GETEXPAND (CLM_FIRST+14) //wParam=hItem, returns a CLE_, CLE_INVALID if not a group
+#define CLM_GETEXTRACOLUMNS (CLM_FIRST+15) //returns number of extra columns
+#define CLM_GETEXTRAIMAGE (CLM_FIRST+16) //wParam=hItem, lParam=MAKELPARAM(iColumn (0 based),0), returns iImage or 0xFF
+#define CLM_GETEXTRAIMAGELIST (CLM_FIRST+17) //returns HIMAGELIST
+#define CLM_GETFONT (CLM_FIRST+18) //wParam=fontId, see clm_setfont. returns hFont.
+#define CLM_GETINDENT (CLM_FIRST+19) //wParam=new group indent
+#define CLM_GETISEARCHSTRING (CLM_FIRST+20) //lParam=(char*)pszStr, max 120 bytes, returns number of chars in string
+#define CLM_GETITEMTEXT (CLM_FIRST+21) //wParam=hItem, lParam=(char*)pszStr, max 120 bytes
+#define CLM_GETSCROLLTIME (CLM_FIRST+22) //returns time in ms
+#define CLM_GETSELECTION (CLM_FIRST+23) //returns hItem
+#define CLCHT_ABOVE 0x0001 //above client area
+#define CLCHT_BELOW 0x0002 //below client area
+#define CLCHT_TOLEFT 0x0004 //left of client area
+#define CLCHT_TORIGHT 0x0008 //right of client area
+#define CLCHT_NOWHERE 0x0010 //in client area, not on an item
+#define CLCHT_ONITEMICON 0x0020
+#define CLCHT_ONITEMCHECK 0x0040
+#define CLCHT_ONITEMLABEL 0x0080
+#define CLCHT_ONITEMINDENT 0x0100 //to the left of an item icon
+#define CLCHT_ONITEMEXTRA 0x0200 //on an extra icon, HIBYTE(HIWORD()) says which
+#define CLCHT_ONITEM 0x03E0
+#define CLCHT_INLEFTMARGIN 0x0400
+#define CLCHT_BELOWITEMS 0x0800 //in client area but below last item
+#define CLM_HITTEST (CLM_FIRST+25) //lParam=MAKELPARAM(x,y) (relative to control), wParam=(PDWORD)&hitTest (see encoding of HitTest() in clc.h, can be NULL) returns hItem or NULL
+#define CLM_SELECTITEM (CLM_FIRST+26) //wParam=hItem
+#define CLB_TOPLEFT 0
+#define CLB_STRETCHV 1
+#define CLB_STRETCHH 2 //and tile vertically
+#define CLB_STRETCH 3
+#define CLBM_TYPE 0x00FF
+#define CLBF_TILEH 0x1000
+#define CLBF_TILEV 0x2000
+#define CLBF_PROPORTIONAL 0x4000
+#define CLBF_SCROLL 0x8000
+#define CLM_SETBKBITMAP (CLM_FIRST+27) //wParam=mode, lParam=hBitmap (don't delete it), NULL for none
+#define CLM_SETBKCOLOR (CLM_FIRST+28) //wParam=a COLORREF, default is GetSysColor(COLOR_3DFACE)
+#define CLM_SETCHECKMARK (CLM_FIRST+29) //wParam=hItem, lParam=1 or 0
+#define CLM_SETEXTRACOLUMNS (CLM_FIRST+30) //wParam=number of extra columns (zero to MAXEXTRACOLUMNS from clc.h, currently 16)
+#define CLM_SETEXTRAIMAGE (CLM_FIRST+31) //wParam=hItem, lParam=MAKELPARAM(iColumn (0 based),iImage). iImage=0xFF is a blank
+#define CLM_SETEXTRAIMAGELIST (CLM_FIRST+32) //lParam=HIMAGELIST
+
+#define FONTID_CONTACTS 0
+#define FONTID_INVIS 1
+#define FONTID_OFFLINE 2
+#define FONTID_NOTONLIST 3
+#define FONTID_GROUPS 4
+#define FONTID_GROUPCOUNTS 5
+#define FONTID_DIVIDERS 6
+#define FONTID_OFFINVIS 7
+#define FONTID_STATUSMSG 8
+#define FONTID_GROUPSCLOSED 9
+#define FONTID_CONTACTSHOVER 10
+#define FONTID_MAX 18
+
+#define CLM_SETFONT (CLM_FIRST+33) //wParam=hFont, lParam=MAKELPARAM(fRedraw,fontId)
+#define CLM_SETINDENT (CLM_FIRST+34) //wParam=new indent, default is 3 pixels
+#define CLM_SETITEMTEXT (CLM_FIRST+35) //wParam=hItem, lParam=(char*)pszNewText
+#define CLM_SETSCROLLTIME (CLM_FIRST+36) //wParam=time in ms, default 200
+
+#define CLM_SETHIDEEMPTYGROUPS (CLM_FIRST+38) //wParam=TRUE/FALSE
+#define GREYF_UNFOCUS 0x80000000
+#define MODEF_OFFLINE 0x40000000
+//and use the PF2_ #defines from m_protosvc.h
+#define CLM_SETGREYOUTFLAGS (CLM_FIRST+39) //wParam=new flags
+#define CLM_GETHIDEOFFLINEROOT (CLM_FIRST+40) //returns TRUE/FALSE
+#define CLM_SETHIDEOFFLINEROOT (CLM_FIRST+41) //wParam=TRUE/FALSE
+#define CLM_SETUSEGROUPS (CLM_FIRST+42) //wParam=TRUE/FALSE
+#define CLM_SETOFFLINEMODES (CLM_FIRST+43) //for 'hide offline', wParam=PF2_ flags and MODEF_OFFLINE
+#define CLM_GETEXSTYLE (CLM_FIRST+44) //returns CLS_EX_ flags
+#define CLM_SETEXSTYLE (CLM_FIRST+45) //wParam=CLS_EX_ flags
+#define CLM_GETLEFTMARGIN (CLM_FIRST+46) //returns count of pixels
+#define CLM_SETLEFTMARGIN (CLM_FIRST+47) //wParam=pixels
+typedef struct {
+ int cbSize;
+ const TCHAR *pszText;
+ HANDLE hParentGroup;
+ DWORD flags;
+ HICON hIcon; //todo
+} CLCINFOITEM;
+#define CLCIIF_BELOWGROUPS 1 //put it between groups and contacts, default is at top
+#define CLCIIF_BELOWCONTACTS 2 //put it at the bottom
+#define CLCIIF_CHECKBOX 0x40 //give this item a check box
+#define CLCIIF_GROUPFONT 0x80 //draw the item using FONTID_GROUPS
+
+#define CLM_ADDINFOITEMA (CLM_FIRST+48) //lParam=&cii, returns hItem
+#define CLM_ADDINFOITEMW (CLM_FIRST+53) //lParam=&cii, returns hItem
+#if defined( _UNICODE )
+ #define CLM_ADDINFOITEM CLM_ADDINFOITEMW
+#else
+ #define CLM_ADDINFOITEM CLM_ADDINFOITEMA
+#endif
+
+ //the order of info items is never changed, so make sure you add them in the
+ // order you want them to remain
+#define CLCIT_INVALID -1
+#define CLCIT_GROUP 0
+#define CLCIT_CONTACT 1
+#define CLCIT_DIVIDER 2
+#define CLCIT_INFO 3
+#define CLM_GETITEMTYPE (CLM_FIRST+49) //wParam=hItem, returns a CLCIT_
+#define CLGN_ROOT 0
+#define CLGN_CHILD 1
+#define CLGN_PARENT 2
+#define CLGN_NEXT 3
+#define CLGN_PREVIOUS 4
+#define CLGN_NEXTCONTACT 5
+#define CLGN_PREVIOUSCONTACT 6
+#define CLGN_NEXTGROUP 7
+#define CLGN_PREVIOUSGROUP 8
+#define CLM_GETNEXTITEM (CLM_FIRST+50) //wParam=flag, lParam=hItem, returns an hItem
+#define CLM_GETTEXTCOLOR (CLM_FIRST+51) //wParam=FONTID_, returns COLORREF
+#define CLM_SETTEXTCOLOR (CLM_FIRST+52) //wParam=FONTID_, lParam=COLORREF
+
+//notifications (most are omitted because the control processes everything)
+#define CLNF_ISGROUP 1
+#define CLNF_ISINFO 2
+typedef struct {
+ NMHDR hdr;
+ HANDLE hItem;
+ int action;
+ int iColumn; //-1 if not on an extra column
+ DWORD flags;
+ POINT pt;
+} NMCLISTCONTROL;
+#define CLN_FIRST (0U-100U)
+#define CLN_EXPANDED (CLN_FIRST-0) //hItem=hGroup, action=CLE_*
+#define CLN_LISTREBUILT (CLN_FIRST-1)
+#define CLN_ITEMCHECKED (CLN_FIRST-2) //todo //hItem,action,flags valid
+#define CLN_DRAGGING (CLN_FIRST-3) //hItem,pt,flags valid. only sent when cursor outside window, return nonzero if processed
+#define CLN_DROPPED (CLN_FIRST-4) //hItem,pt,flags valid. only sent when cursor outside window, return nonzero if processed
+#define CLN_LISTSIZECHANGE (CLN_FIRST-5) //pt.y valid. the vertical height of the visible items in the list has changed.
+#define CLN_OPTIONSCHANGED (CLN_FIRST-6) //nothing valid. If you set some extended options they have been overwritten and should be re-set
+#define CLN_DRAGSTOP (CLN_FIRST-7) //hItem,flags valid. sent when cursor goes back in to the window having been outside, return nonzero if processed
+#define CLN_NEWCONTACT (CLN_FIRST-8) //hItem,flags valid. sent when a new contact is added without a full list rebuild
+#define CLN_CONTACTMOVED (CLN_FIRST-9) //hItem,flags valid. sent when contact is moved without a full list rebuild
+#define CLN_CHECKCHANGED (CLN_FIRST-10) //hItem,flags valid. sent when any check mark is changed, but only for one change if there are many
+//NM_CLICK //hItem,iColumn,pt,flags valid
+//NM_KEYDOWN //NMKEY structure, only sent when key is not already processed, return nonzero to prevent further processing
+
+//an infotip for an item should be shown now
+//wParam=0
+//lParam=(LPARAM)(CLCINFOTIP*)&it
+//Return nonzero if you process this, because it makes no sense for more than
+//one plugin to grab it.
+//It is up to the plugin to decide the best place to put the infotip. Normally
+//it's a few pixels below and to the right of the cursor
+//This event is called after the mouse has been stationary over a contact for
+//(by default) 200ms, but see below.
+//Everything is in screen coordinates.
+typedef struct {
+ int cbSize;
+ int isTreeFocused; //so the plugin can provide an option
+ int isGroup; //0 if it's a contact, 1 if it's a group
+ HANDLE hItem; //handle to group or contact
+ POINT ptCursor;
+ RECT rcItem;
+} CLCINFOTIP;
+#define ME_CLC_SHOWINFOTIP "CLC/ShowInfoTip"
+
+//it's time to destroy an infotip
+//wParam=0
+//lParam=(LPARAM)(CLCINFOTIP*)&it
+//Only cbSize, isGroup and hItem are set
+//Return nonzero if you process this.
+//This is sent when the mouse moves off a contact when clc/showinfotip has
+//previously been called.
+//If you don't want this behaviour, you should have grabbed the mouse capture
+//yourself and made your own arrangements.
+#define ME_CLC_HIDEINFOTIP "CLC/HideInfoTip"
+
+//set the hover time before the infotip hooks are called
+//wParam=newTime
+//lParam=0
+//Returns 0 on success or nonzero on failure
+//The value of this setting is applied to all current CLC windows, and saved
+//to be applied to all future windows, including after restarts.
+//newTime is in ms.
+//The default is 750ms.
+#define MS_CLC_SETINFOTIPHOVERTIME "CLC/SetInfoTipHoverTime"
+
+//get the hover time before the infotip hooks are called
+//wParam=lParam=0
+//Returns the time in ms
+#define MS_CLC_GETINFOTIPHOVERTIME "CLC/GetInfoTipHoverTime"
+
+#endif // M_CLC_H__
+
diff --git a/miranda-wine/include/m_clist.h b/miranda-wine/include/m_clist.h
new file mode 100644
index 0000000..e215992
--- /dev/null
+++ b/miranda-wine/include/m_clist.h
@@ -0,0 +1,550 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_CLIST_H__
+#define M_CLIST_H__ 1
+
+#include "statusmodes.h"
+
+//sent when the user asks to change their status
+//wParam=new status, from statusmodes.h
+//lParam=protocol name, NULL if for all protocols (added in v0.3.1alpha)
+//also sent due to a ms_clist_setstatusmode call
+#define ME_CLIST_STATUSMODECHANGE "CList/StatusModeChange"
+
+//force a change of status mode
+//wParam=new status, from statusmodes.h
+#define MS_CLIST_SETSTATUSMODE "CList/SetStatusMode"
+
+//get the current status mode
+//wParam=lParam=0
+//returns the current status
+//This is the status *as set by the user*, not any protocol-specific status
+//All protocol modules will attempt to conform to this setting at all times
+#define MS_CLIST_GETSTATUSMODE "CList/GetStatusMode"
+
+//gets a textual description of the given status mode (v0.1.0.1+)
+//wParam=status mode, from statusmodes.h
+//lParam=flags, below
+//returns a static buffer of the description of the given status mode
+//returns NULL if the status mode was unknown
+#define GSMDF_PREFIXONLINE 1 //prefix "Online: " to all status modes that
+ //imply online, eg "Online: Away"
+#define GCMDF_UNICODE 2 //will return TCHAR* instead of char*
+#if defined( _UNICODE )
+ #define GCMDF_TCHAR GCMDF_UNICODE //will return TCHAR* instead of char*
+#else
+ #define GCMDF_TCHAR 0 //will return char*, as usual
+#endif
+#define MS_CLIST_GETSTATUSMODEDESCRIPTION "CList/GetStatusModeDescription"
+
+//add a new item to the main menu
+//wParam=0
+//lParam=(LPARAM)(CLISTMENUITEM*)&mi
+//returns a handle to the new item, or NULL on failure
+//the service that is called when the item is clicked is called with
+//wParam=0, lParam=hwndContactList
+//dividers are inserted every 100000 positions
+//pszContactOwner is ignored for this service.
+//there is a #define PUTPOSITIONSINMENU in clistmenus.c which, when set, will
+//cause the position numbers to be placed in brackets after the menu items
+typedef struct {
+ int cbSize; //size in bytes of this structure
+ union {
+ char* pszName; //text of the menu item
+ TCHAR* ptszName; //Unicode text of the menu item
+ };
+ DWORD flags; //flags
+ int position; //approx position on the menu. lower numbers go nearer the top
+ HICON hIcon; //icon to put by the item. If this was not loaded from
+ //a resource, you can delete it straight after the call
+ char* pszService; //name of service to call when the item gets selected
+ union {
+ char* pszPopupName; //name of the popup menu that this item is on. If this
+ //is NULL the item is on the root of the menu
+ TCHAR* ptszPopupName;
+ };
+
+ int popupPosition; //position of the popup menu on the root menu. Ignored
+ //if pszPopupName is NULL or the popup menu already
+ //existed
+ DWORD hotKey; //keyboard accelerator, same as lParam of WM_HOTKEY
+ //0 for none
+ char *pszContactOwner; //contact menus only. The protocol module that owns
+ //the contacts to which this menu item applies. NULL if it
+ //applies to all contacts. If it applies to multiple but not all
+ //protocols, add multiple menu items or use ME_CLIST_PREBUILDCONTACTMENU
+} CLISTMENUITEM;
+#define CMIF_GRAYED 1
+#define CMIF_CHECKED 2
+#define CMIF_HIDDEN 4 //only works on contact menus
+#define CMIF_NOTOFFLINE 8 //item won't appear for contacts that are offline
+#define CMIF_NOTONLINE 16 // " online
+#define CMIF_NOTONLIST 32 //item won't appear on standard contacts
+#define CMIF_NOTOFFLIST 64 //item won't appear on contacts that have the 'NotOnList' setting
+#define MS_CLIST_ADDMAINMENUITEM "CList/AddMainMenuItem"
+
+//add a new item to the user contact menus
+//identical to clist/addmainmenuitem except when item is selected the service
+//gets called with wParam=(WPARAM)(HANDLE)hContact
+//pszContactOwner is obeyed.
+//popup menus are not supported. pszPopupName and popupPosition are ignored.
+//If ctrl is held down when right clicking, the menu position numbers will be
+//displayed in brackets after the menu item text. This only works in debug
+//builds.
+#define MS_CLIST_ADDCONTACTMENUITEM "CList/AddContactMenuItem"
+
+//modify an existing menu item v0.1.0.1+
+//wParam=(WPARAM)(HANDLE)hMenuItem
+//lParam=(LPARAM)(CLISTMENUITEM*)&clmi
+//returns 0 on success, nonzero on failure
+//hMenuItem will have been returned by clist/add*menuItem
+//clmi.flags should contain cmim_ constants below specifying which fields to
+//update. Fields without a mask flag cannot be changed and will be ignored
+#define CMIM_NAME 0x80000000
+#define CMIM_FLAGS 0x40000000
+#define CMIM_ICON 0x20000000
+#define CMIM_HOTKEY 0x10000000
+#define CMIM_ALL 0xF0000000
+#define MS_CLIST_MODIFYMENUITEM "CList/ModifyMenuItem"
+
+//the context menu for a contact is about to be built v0.1.0.1+
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=0
+//modules should use this to change menu items that are specific to the
+//contact that has them
+#define ME_CLIST_PREBUILDCONTACTMENU "CList/PreBuildContactMenu"
+
+//sets the service to call when a contact is double-clicked
+//wParam=0
+//lParam=(LPARAM)(CLISTDOUBLECLICKACTION*)&dca
+//contactType is one or more of the constants below
+//pszService is called with wParam=hContact, lParam=0
+//pszService will only be called if there is no outstanding event on the
+//selected contact
+//returns 0 on success, nonzero on failure
+//in case of conflicts, the first module to have registered will get the
+//double click, no others will. This service will return success even for
+//duplicates.
+/*
+ Note: During development of 0.3.0.0 (2003/02/15) this service was completely dropped
+ by default it always returns 1 to mark failure, see ME_CLIST_DOUBLECLICKED for
+ a better implementation as a hook.
+*/
+typedef struct {
+ int cbSize;
+ char *pszContactOwner; //name of protocol owning contact, or NULL for all
+ DWORD flags; //any of the CMIF_NOT... flags above
+ char *pszService; //service to call on double click
+} CLISTDOUBLECLICKACTION;
+#define MS_CLIST_SETDOUBLECLICKACTION "CList/SetDoubleClickAction"
+
+/*
+wParam=(WPARAM)hContact
+lParam=0
+
+Event is fired when there is a double click on a CList contact,
+it is upto the caller to check for the protocol & status
+of the HCONTACT, it's not done for you anymore since it didn't make
+sense to store all this information in memory, etc.
+
+*/
+#define ME_CLIST_DOUBLECLICKED "CList/DoubleClicked"
+//gets the string that the contact list will use to represent a contact
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=flags
+//returns a pointer to the name, will always succeed, even if it needs to
+//return "(Unknown Contact)"
+//this pointer is to a statically allocated buffer which will be overwritten
+//on every call to this service. Callers should make sure that they copy the
+//information before they call this service again.
+#define GCDNF_NOMYHANDLE 1 //will never return the user's custom name
+#define GCDNF_UNICODE 2 //will return TCHAR* instead of char*
+#define GCDNF_NOCACHE 4 //will not use the cache
+
+#if defined( _UNICODE )
+ #define GCDNF_TCHAR GCDNF_UNICODE //will return TCHAR* instead of char*
+#else
+ #define GCDNF_TCHAR 0 //will return char*, as usual
+#endif
+
+ //even if it's the one that should be displayed. v0.1.2.0+
+ //v0.3.0.0+ if using GCDNF_NOMYHANDLE you must free your string
+#define MS_CLIST_GETCONTACTDISPLAYNAME "CList/GetContactDisplayName"
+
+// Invalidates the display name cache
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=not used
+#define MS_CLIST_INVALIDATEDISPLAYNAME "CList/InvalidateDiplayName"
+
+//adds an event to the contact list's queue
+//wParam=0
+//lParam=(LPARAM)(CLISTEVENT*)cle
+//The contact list will flash hIcon next to the contact hContact (use NULL for
+//a system message). szServiceName will be called when the user double clicks
+//the icon, at which point the event will be removed from the contact list's
+//queue automatically
+//pszService is called with wParam=(WPARAM)(HWND)hwndContactList,
+//lParam=(LPARAM)(CLISTEVENT*)cle. Its return value is ignored. cle is
+//invalidated when your service returns, so take copies of any important
+//information in it.
+//hDbEvent should be unique since it and hContact are the identifiers used by
+//clist/removeevent if, for example, your module implements a 'read next' that
+//bypasses the double-click.
+typedef struct {
+ int cbSize; //size in bytes of this structure
+ HANDLE hContact; //handle to the contact to put the icon by
+ HICON hIcon; //icon to flash
+ DWORD flags; //...of course
+ HANDLE hDbEvent; //caller defined but should be unique for hContact
+ LPARAM lParam; //caller defined
+ char *pszService; //name of the service to call on activation
+ union {
+ char *pszTooltip; //short description of the event to display as a
+ TCHAR *ptszTooltip; //tooltip on the system tray
+ };
+} CLISTEVENT;
+#define CLEF_URGENT 1 //flashes the icon even if the user is occupied,
+ //and puts the event at the top of the queue
+#define CLEF_ONLYAFEW 2 //the icon will not flash for ever, only a few
+ //times. This is for eg online alert
+#define CLEF_UNICODE 4 //set pszTooltip as unicode
+
+#if defined( _UNICODE )
+ #define CLEF_TCHAR CLEF_UNICODE //will use TCHAR* instead of char*
+#else
+ #define CLEF_TCHAR 0 //will return char*, as usual
+#endif
+
+#define MS_CLIST_ADDEVENT "CList/AddEvent"
+
+//removes an event from the contact list's queue
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=(LPARAM)(HANDLE)hDbEvent
+//returns 0 if the event was successfully removed, or nonzero if the event
+//was not found
+#define MS_CLIST_REMOVEEVENT "Clist/RemoveEvent"
+
+//gets the details of an event in the queue v0.1.2.1+
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=iEvent
+//returns a CLISTEVENT* on success, NULL on failure
+//Returns the iEvent-th event from the queue for hContact, so iEvent=0 will
+//get the event that will be got when the user clicks on that contact.
+//Use hContact=INVALID_HANDLE_VALUE to search over all contacts, so iEvent=0
+//will get the event that will be got if the user clicks the systray icon.
+#define MS_CLIST_GETEVENT "CList/GetEvent"
+
+//process a WM_MEASUREITEM message for user context menus v0.1.1.0+
+//wParam, lParam, return value as for WM_MEASUREITEM
+//This is for displaying the icons by the menu items. If you don't call this
+//and clist/menudrawitem whne drawing a menu returned by one of the three menu
+//services below then it'll work but you won't get any icons
+#define MS_CLIST_MENUMEASUREITEM "CList/MenuMeasureItem"
+
+//process a WM_DRAWITEM message for user context menus v0.1.1.0+
+//wParam, lParam, return value as for WM_MEASUREITEM
+//See comments for clist/menumeasureitem
+#define MS_CLIST_MENUDRAWITEM "CList/MenuDrawItem"
+
+//builds the context menu for a specific contact v0.1.1.0+
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=0
+//returns a HMENU identifying the menu. This should be DestroyMenu()ed when
+//finished with.
+#define MS_CLIST_MENUBUILDCONTACT "CList/MenuBuildContact"
+
+//gets the image list with all the useful icons in it v0.1.1.0+
+//wParam=lParam=0
+//returns a HIMAGELIST
+//the members of this image list are opaque, and you should trust what you
+//are given
+#define MS_CLIST_GETICONSIMAGELIST "CList/GetIconsImageList"
+#define IMAGE_GROUPOPEN 11
+#define IMAGE_GROUPSHUT 12
+
+//get the icon that should be associated with a contact v0.1.2.0+
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=0
+//returns an index into the contact list imagelist. See clist/geticonsimagelist
+//If the contact is flashing an icon, this function will not return that
+//flashing icon. Use me_clist_contacticonchanged to get info about that.
+#define MS_CLIST_GETCONTACTICON "CList/GetContactIcon"
+
+//The icon of a contact in the contact list has changed v0.1.2.0+
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=iconId
+//iconId is an offset into the clist's imagelist. See clist/geticonsimagelist
+#define ME_CLIST_CONTACTICONCHANGED "CList/ContactIconChanged"
+
+/******************************* CLUI only *********************************/
+
+// Stuff below here is ideally for the use of a CList UI module only.
+
+//get a handle to the main Miranda menu v0.1.1.0+
+//wParam=lParam=0
+//returns a HMENU. This need not be freed since it's owned by clist
+#define MS_CLIST_MENUGETMAIN "CList/MenuGetMain"
+
+//get a handle to the Miranda status menu v0.1.1.0+
+//wParam=lParam=0
+//returns a HMENU. This need not be freed since it's owned by clist
+#define MS_CLIST_MENUGETSTATUS "CList/MenuGetStatus"
+
+//processes a menu selection from a menu v0.1.1.0+
+//wParam=MAKEWPARAM(LOWORD(wParam from WM_COMMAND),flags)
+//lParam=(LPARAM)(HANDLE)hContact
+//returns TRUE if it processed the command, FALSE otherwise
+//hContact is the currently selected contact. It it not used if this is a main
+//menu command. If this is NULL and the command is a contact menu one, the
+//command is ignored
+#define MPCF_CONTACTMENU 1 //test commands from a contact menu
+#define MPCF_MAINMENU 2 //test commands from the main menu
+#define MS_CLIST_MENUPROCESSCOMMAND "CList/MenuProcessCommand"
+
+//processes a menu hotkey v0.1.1.0+
+//wParam=virtual key code
+//lParam=MPCF_ flags
+//returns TRUE if it processed the command, FALSE otherwise
+//this should be called in WM_KEYDOWN
+#define MS_CLIST_MENUPROCESSHOTKEY "CList/MenuProcessHotkey"
+
+//process all the messages required for docking v0.1.1.0+
+//wParam=(WPARAM)(MSG*)&msg
+//lParam=(LPARAM)(LRESULT*)&lResult
+//returns TRUE if the message should not be processed further, FALSE otherwise
+//only msg.hwnd, msg.message, msg.wParam and msg.lParam are used
+//your wndproc should return lResult if and only if TRUE is returned
+#define MS_CLIST_DOCKINGPROCESSMESSAGE "CList/DockingProcessMessage"
+
+//determines whether the contact list is docked v0.1.1.0+
+//wParam=lParam=0
+//returns nonzero if the contact list is docked, of 0 if it is not
+#define MS_CLIST_DOCKINGISDOCKED "CList/DockingIsDocked"
+
+//process all the messages required for the tray icon v0.1.1.0+
+//wParam=(WPARAM)(MSG*)&msg
+//lParam=(LPARAM)(LRESULT*)&lResult
+//returns TRUE if the message should not be processed further, FALSE otherwise
+//only msg.hwnd, msg.message, msg.wParam and msg.lParam are used
+//your wndproc should return lResult if and only if TRUE is returned
+#define MS_CLIST_TRAYICONPROCESSMESSAGE "CList/TrayIconProcessMessage"
+
+//process all the messages required for hotkeys v0.1.1.0+
+//wParam=(WPARAM)(MSG*)&msg
+//lParam=(LPARAM)(LRESULT*)&lResult
+//returns TRUE if the message should not be processed further, FALSE otherwise
+//only msg.hwnd, msg.message, msg.wParam and msg.lParam are used
+//your wndproc should return lResult if and only if TRUE is returned
+#define MS_CLIST_HOTKEYSPROCESSMESSAGE "CList/HotkeysProcessMessage"
+
+//toggles the show/hide status of the contact list v0.1.1.0+
+//wParam=lParam=0
+//returns 0 on success, nonzero on failure
+#define MS_CLIST_SHOWHIDE "CList/ShowHide"
+
+//temporarily disable the autohide feature v0.1.2.1+
+//wParam=lParam=0
+//returns 0 on success, nonzero on failure
+//This service will restart the autohide timer, so if you need to keep the
+//window visible you'll have to be getting user input regularly and calling
+//this function each time
+#define MS_CLIST_PAUSEAUTOHIDE "CList/PauseAutoHide"
+
+//creates a new group and calls CLUI to display it v0.1.1.0+
+//wParam=hParentGroup
+//lParam=0
+//returns a handle to the new group
+//hParentGroup is NULL to create the new group at the root, or can be the
+//handle of the group of which the new group should be a subgroup.
+#define MS_CLIST_GROUPCREATE "CList/GroupCreate"
+
+//deletes a group and calls CLUI to display the change v0.1.1.0+
+//wParam=(WPARAM)(HANDLE)hGroup
+//lParam=0
+//returns 0 on success, nonzero on failure
+#define MS_CLIST_GROUPDELETE "CList/GroupDelete"
+
+//change the expanded state flag for a group internally v0.1.1.0+
+//wParam=(WPARAM)(HANDLE)hGroup
+//lParam=newState
+//returns 0 on success, nonzero on failure
+//newState is nonzero if the group is expanded, 0 if it's collapsed
+//CLUI is not called when this change is made
+#define MS_CLIST_GROUPSETEXPANDED "CList/GroupSetExpanded"
+
+//changes the flags for a group v0.1.2.1+
+//wParam=(WPARAM)(HANDLE)hGroup
+//lParam=MAKELPARAM(flags,flagsMask)
+//returns 0 on success, nonzero on failure
+//Only the flags given in flagsMask are altered.
+//CLUI is called on changes to GROUPF_HIDEOFFLINE.
+#define MS_CLIST_GROUPSETFLAGS "CList/GroupSetFlags"
+
+//get the name of a group v0.1.1.0+
+//wParam=(WPARAM)(HANDLE)hGroup
+//lParam=(LPARAM)(int*)&isExpanded
+//returns a static buffer pointing to the name of the group
+//returns NULL if hGroup is invalid.
+//this buffer is only valid until the next call to this service
+//&isExpanded can be NULL if you don't want to know if the group is expanded
+//or not.
+#define MS_CLIST_GROUPGETNAME "CList/GroupGetName"
+
+//get the name of a group v0.1.2.1+
+//wParam=(WPARAM)(HANDLE)hGroup
+//lParam=(LPARAM)(DWORD*)&flags
+//returns a static buffer pointing to the name of the group
+//returns NULL if hGroup is invalid.
+//this buffer is only valid until the next call to this service
+//&flags can be NULL if you don't want any of that info.
+#define GROUPF_EXPANDED 0x04
+#define GROUPF_HIDEOFFLINE 0x08
+#define MS_CLIST_GROUPGETNAME2 "CList/GroupGetName2"
+
+//move a group to directly before another group v0.1.2.1+
+//wParam=(WPARAM)(HANDLE)hGroup
+//lParam=(LPARAM)(HANDLE)hBeforeGroup
+//returns the new handle of the group on success, NULL on failure
+//The order is represented by the order in which MS_CLUI_GROUPADDED is called,
+//however UIs are free to ignore this order and sort alphabetically if they
+//wish.
+#define MS_CLIST_GROUPMOVEBEFORE "CList/GroupMoveBefore"
+
+//rename a group internally v0.1.1.0+
+//wParam=(WPARAM)(HANDLE)hGroup
+//lParam=(LPARAM)(char*)szNewName
+//returns 0 on success, nonzero on failure
+//this will fail if the group name is a duplicate of an existing name
+//CLUI is not called when this change is made
+#define MS_CLIST_GROUPRENAME "CList/GroupRename"
+
+//build a menu of the group tree v0.1.2.1+
+//wParam=0
+//lParam=0
+//returns a HMENU on success, or NULL on failure
+//The return value must be DestroyMenu()ed when you're done with it.
+//NULL will be returned if the user doesn't have any groups
+//The dwItemData of every menu item is the handle to that group.
+//Menu item IDs are assigned starting at 100, in no particular order.
+#define MS_CLIST_GROUPBUILDMENU "CList/GroupBuildMenu"
+
+//changes the 'hide offline contacts' flag and call CLUI v0.1.1.0+
+//wParam=newValue
+//lParam=0
+//returns 0 on success, nonzero on failure
+//newValue is 0 to show all contacts, 1 to only show online contacts
+//or -1 to toggle the value
+#define MS_CLIST_SETHIDEOFFLINE "CList/SetHideOffline"
+
+//do the message processing associated with double clicking a contact v0.1.1.0+
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=0
+//returns 0 on success, nonzero on failure
+#define MS_CLIST_CONTACTDOUBLECLICKED "CList/ContactDoubleClicked"
+
+//do the processing for when some files are dropped on a contact v0.1.2.1+
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=(LPARAM)(char**)ppFiles
+//returns 0 on success, nonzero on failure
+//ppFiles is an array of fully qualified filenames, ending with a NULL.
+#define MS_CLIST_CONTACTFILESDROPPED "CList/ContactFilesDropped"
+
+//change the group a contact belongs to v0.1.1.0+
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=(LPARAM)(HANDLE)hGroup
+//returns 0 on success, nonzero on failure
+//use hGroup=NULL to put the contact in no group
+#define MS_CLIST_CONTACTCHANGEGROUP "CList/ContactChangeGroup"
+
+//determines the ordering of two contacts v0.1.1.0+
+//wParam=(WPARAM)(HANDLE)hContact1
+//lParam=(LPARAM)(HANDLE)hContact2
+//returns 0 if hContact1 is the same as hContact2
+//returns +1 if hContact2 should be displayed after hContact1
+//returns -1 if hContact1 should be displayed after hContact2
+#define MS_CLIST_CONTACTSCOMPARE "CList/ContactsCompare"
+
+/*
+ wParam=0 (not used)
+ lParam=(LPARAM) &MIRANDASYSTRAYNOTIFY
+
+ Affects: Show a message in a ballon tip against a protocol icon (if installed)
+ Returns: 0 on success, non zero on failure
+ Notes : This service will not be created on systems that haven't got the Windows
+ support for ballontips, also note that it's upto Windows if it shows your
+ message and it keeps check of delays (don't be stupid about showing messages)
+
+ Version: 0.3.1a
+*/
+#define NIIF_INFO 0x00000001
+#define NIIF_WARNING 0x00000002
+#define NIIF_ERROR 0x00000003
+#define NIIF_ICON_MASK 0x0000000F
+#define NIIF_NOSOUND 0x00000010
+
+typedef struct {
+ int cbSize; // sizeof(MIRANDASYSTRAY)
+ char *szProto; // protocol to show under (may have no effect)
+ char *szInfoTitle; // only 64chars of it will be used
+ char *szInfo; // only 256chars of it will be used
+ DWORD dwInfoFlags; // see NIIF_* stuff
+ UINT uTimeout; // how long to show the tip for
+} MIRANDASYSTRAYNOTIFY;
+#define MS_CLIST_SYSTRAY_NOTIFY "Miranda/Systray/Notify"
+
+#define SETTING_TOOLWINDOW_DEFAULT 1
+#define SETTING_SHOWMAINMENU_DEFAULT 1
+#define SETTING_SHOWCAPTION_DEFAULT 1
+#define SETTING_CLIENTDRAG_DEFAULT 1
+#define SETTING_ONTOP_DEFAULT 0
+#define SETTING_MIN2TRAY_DEFAULT 1
+#define SETTING_TRAY1CLICK_DEFAULT 0
+#define SETTING_HIDEOFFLINE_DEFAULT 0
+#define SETTING_HIDEEMPTYGROUPS_DEFAULT 0
+#define SETTING_USEGROUPS_DEFAULT 1
+#define SETTING_SORTBYSTATUS_DEFAULT 0
+#define SETTING_SORTBYPROTO_DEFAULT 0
+#define SETTING_TRANSPARENT_DEFAULT 0
+#define SETTING_ALPHA_DEFAULT 200
+#define SETTING_AUTOALPHA_DEFAULT 150
+#define SETTING_CONFIRMDELETE_DEFAULT 1
+#define SETTING_AUTOHIDE_DEFAULT 0
+#define SETTING_HIDETIME_DEFAULT 30
+#define SETTING_CYCLETIME_DEFAULT 4
+#define SETTING_TRAYICON_DEFAULT SETTING_TRAYICON_SINGLE
+#define SETTING_ALWAYSSTATUS_DEFAULT 0
+#define SETTING_ALWAYSMULTI_DEFAULT 0
+
+#define SETTING_TRAYICON_SINGLE 0
+#define SETTING_TRAYICON_CYCLE 1
+#define SETTING_TRAYICON_MULTI 2
+
+#define SETTING_STATE_HIDDEN 0
+#define SETTING_STATE_MINIMIZED 1
+#define SETTING_STATE_NORMAL 2
+
+#define SETTING_BRINGTOFRONT_DEFAULT 0
+
+#endif // M_CLIST_H__
+
diff --git a/miranda-wine/include/m_clistint.h b/miranda-wine/include/m_clistint.h
new file mode 100644
index 0000000..3f97ff6
--- /dev/null
+++ b/miranda-wine/include/m_clistint.h
@@ -0,0 +1,328 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_CLISTINT_H__
+#define M_CLISTINT_H__ 1
+
+#define HCONTACT_ISGROUP 0x80000000
+#define HCONTACT_ISINFO 0xFFFF0000
+#define IsHContactGroup(h) (((unsigned)(h)^HCONTACT_ISGROUP)<(HCONTACT_ISGROUP^HCONTACT_ISINFO))
+#define IsHContactInfo(h) (((unsigned)(h)&HCONTACT_ISINFO)==HCONTACT_ISINFO)
+#define IsHContactContact(h) (((unsigned)(h)&HCONTACT_ISGROUP)==0)
+#define MAXEXTRACOLUMNS 16
+
+#define INTM_NAMECHANGED (WM_USER+10)
+#define INTM_ICONCHANGED (WM_USER+11)
+#define INTM_GROUPCHANGED (WM_USER+12)
+#define INTM_GROUPSCHANGED (WM_USER+13)
+#define INTM_CONTACTADDED (WM_USER+14)
+#define INTM_CONTACTDELETED (WM_USER+15)
+#define INTM_HIDDENCHANGED (WM_USER+16)
+#define INTM_INVALIDATE (WM_USER+17)
+#define INTM_APPARENTMODECHANGED (WM_USER+18)
+#define INTM_SETINFOTIPHOVERTIME (WM_USER+19)
+#define INTM_NOTONLISTCHANGED (WM_USER+20)
+#define INTM_RELOADOPTIONS (WM_USER+21)
+#define INTM_NAMEORDERCHANGED (WM_USER+22)
+#define INTM_IDLECHANGED (WM_USER+23)
+#define INTM_SCROLLBARCHANGED (WM_USER+24)
+#define INTM_PROTOCHANGED (WM_USER+25)
+
+#define TIMERID_RENAME 10
+#define TIMERID_DRAGAUTOSCROLL 11
+#define TIMERID_INFOTIP 13
+#define TIMERID_REBUILDAFTER 14
+#define TIMERID_DELAYEDRESORTCLC 15
+
+#define GROUP_ALLOCATE_STEP 8
+
+struct ClcContact;
+struct ClcData;
+struct CListEvent;
+
+/* templates, where are you... */
+
+typedef struct
+{
+ struct ClcContact** items;
+ int count, limit, increment;
+ void* sortFunc;
+}
+ ContactList;
+
+typedef struct
+{
+ struct CListEvent** items;
+ int count, limit, increment;
+ void* sortFunc;
+}
+ EventList;
+
+struct ClcGroup {
+ ContactList cl;
+ int expanded,hideOffline,groupId;
+ struct ClcGroup *parent;
+ int scanIndex;
+ int totalMembers;
+};
+
+struct ClcFontInfo {
+ HFONT hFont;
+ int fontHeight,changed;
+ COLORREF colour;
+};
+
+#define DRAGSTAGE_NOTMOVED 0
+#define DRAGSTAGE_ACTIVE 1
+#define DRAGSTAGEM_STAGE 0x00FF
+#define DRAGSTAGEF_MAYBERENAME 0x8000
+#define DRAGSTAGEF_OUTSIDE 0x4000
+
+#define CONTACTF_ONLINE 1
+#define CONTACTF_INVISTO 2
+#define CONTACTF_VISTO 4
+#define CONTACTF_NOTONLIST 8
+#define CONTACTF_CHECKED 16
+#define CONTACTF_IDLE 32
+
+#define DROPTARGET_OUTSIDE 0
+#define DROPTARGET_ONSELF 1
+#define DROPTARGET_ONNOTHING 2
+#define DROPTARGET_ONGROUP 3
+#define DROPTARGET_ONCONTACT 4
+#define DROPTARGET_INSERTION 5
+
+#define CLCDEFAULT_ROWHEIGHT 16
+#define CLCDEFAULT_EXSTYLE (CLS_EX_EDITLABELS|CLS_EX_TRACKSELECT|CLS_EX_SHOWGROUPCOUNTS|CLS_EX_HIDECOUNTSWHENEMPTY|CLS_EX_TRACKSELECT|CLS_EX_NOTRANSLUCENTSEL) //plus CLS_EX_NOSMOOTHSCROLL is got from the system
+#define CLCDEFAULT_SCROLLTIME 150
+#define CLCDEFAULT_GROUPINDENT 5
+#define CLCDEFAULT_BKCOLOUR GetSysColor(COLOR_3DFACE)
+#define CLCDEFAULT_USEBITMAP 0
+#define CLCDEFAULT_BKBMPUSE CLB_STRETCH
+#define CLCDEFAULT_OFFLINEMODES MODEF_OFFLINE
+#define CLCDEFAULT_GREYOUTFLAGS 0
+#define CLCDEFAULT_FULLGREYOUTFLAGS (MODEF_OFFLINE|PF2_INVISIBLE|GREYF_UNFOCUS)
+#define CLCDEFAULT_SELBKCOLOUR GetSysColor(COLOR_HIGHLIGHT)
+#define CLCDEFAULT_SELTEXTCOLOUR GetSysColor(COLOR_HIGHLIGHTTEXT)
+#define CLCDEFAULT_HOTTEXTCOLOUR (IsWinVer98Plus()?RGB(0,0,255):GetSysColor(COLOR_HOTLIGHT))
+#define CLCDEFAULT_QUICKSEARCHCOLOUR RGB(255,255,0)
+#define CLCDEFAULT_LEFTMARGIN 0
+#define CLCDEFAULT_GAMMACORRECT 1
+#define CLCDEFAULT_SHOWIDLE 0
+#define CLCDEFAULT_USEWINDOWSCOLOURS 0
+
+// Miranda 0.4.3.0+
+// retrieves the pointer to a CLIST_INTERFACE structure
+// NOTE: valid only for the clist clone building, not for the regular use
+
+#define MS_CLIST_RETRIEVE_INTERFACE "CList/RetrieveInterface"
+
+/***************************************************************************
+ * CLIST_INTERFACE structure definition
+ ***************************************************************************/
+
+typedef struct {
+ char *szProto;
+ DWORD dwStatus;
+}
+ ClcProtoStatus;
+
+typedef struct
+{
+ HANDLE hContact;
+ TCHAR* name;
+ #if defined( _UNICODE )
+ char* szName;
+ #endif
+ TCHAR* group;
+ int isHidden;
+}
+ ClcCacheEntryBase;
+
+typedef struct
+{
+ int version;
+
+ HWND hwndContactList, hwndContactTree, hwndStatus;
+ HMENU hMenuMain;
+ HMODULE hInst;
+
+ int hClcProtoCount;
+ ClcProtoStatus *clcProto;
+
+ /* clc.h */
+ void ( *pfnClcOptionsChanged )( void );
+ void ( *pfnClcBroadcast )( int, WPARAM, LPARAM );
+ HMENU ( *pfnBuildGroupPopupMenu )( struct ClcGroup* );
+
+ LRESULT ( CALLBACK *pfnContactListControlWndProc )( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
+
+ /* clcfiledrop.c */
+ void ( *pfnRegisterFileDropping )( HWND hwnd );
+ void ( *pfnUnregisterFileDropping )( HWND hwnd );
+
+ /* clcidents.c */
+ int ( *pfnGetRowsPriorTo )( struct ClcGroup *group, struct ClcGroup *subgroup, int contactIndex );
+ int ( *pfnFindItem )( HWND hwnd, struct ClcData *dat, HANDLE hItem, struct ClcContact **contact, struct ClcGroup **subgroup, int *isVisible );
+ int ( *pfnGetRowByIndex )( struct ClcData *dat, int testindex, struct ClcContact **contact, struct ClcGroup **subgroup );
+ HANDLE ( *pfnContactToHItem )( struct ClcContact* contact );
+ HANDLE ( *pfnContactToItemHandle )( struct ClcContact * contact, DWORD * nmFlags );
+
+ /* clcitems.c */
+ struct ClcContact* ( *pfnCreateClcContact )( void );
+ struct ClcGroup* ( *pfnAddGroup )( HWND hwnd, struct ClcData *dat, const TCHAR *szName, DWORD flags, int groupId, int calcTotalMembers );
+ struct ClcGroup* ( *pfnRemoveItemFromGroup )(HWND hwnd, struct ClcGroup *group, struct ClcContact *contact, int updateTotalCount);
+
+ void ( *pfnFreeContact )( struct ClcContact *contact );
+ void ( *pfnFreeGroup )( struct ClcGroup *group );
+
+ int ( *pfnAddInfoItemToGroup )(struct ClcGroup *group, int flags, const TCHAR *pszText);
+ int ( *pfnAddItemToGroup )( struct ClcGroup *group,int iAboveItem );
+ int ( *pfnAddContactToGroup )( struct ClcData *dat, struct ClcGroup *group, HANDLE hContact );
+ void ( *pfnAddContactToTree )( HWND hwnd, struct ClcData *dat, HANDLE hContact, int updateTotalCount, int checkHideOffline);
+ void ( *pfnDeleteItemFromTree )( HWND hwnd, HANDLE hItem );
+ void ( *pfnRebuildEntireList )( HWND hwnd, struct ClcData *dat );
+ int ( *pfnGetGroupContentsCount )( struct ClcGroup *group, int visibleOnly );
+ void ( *pfnSortCLC )( HWND hwnd, struct ClcData *dat, int useInsertionSort );
+ void ( *pfnSaveStateAndRebuildList )(HWND hwnd, struct ClcData *dat);
+
+ /* clcmsgs.c */
+ LRESULT ( *pfnProcessExternalMessages )(HWND hwnd, struct ClcData *dat, UINT msg, WPARAM wParam, LPARAM lParam );
+
+ /* clcpaint.c */
+ void ( *pfnPaintClc )( HWND hwnd, struct ClcData *dat, HDC hdc, RECT * rcPaint );
+
+ /* clcutils.c */
+ char* ( *pfnGetGroupCountsText )(struct ClcData *dat, struct ClcContact *contact );
+ int ( *pfnHitTest )( HWND hwnd, struct ClcData *dat, int testx, int testy, struct ClcContact **contact, struct ClcGroup **group, DWORD * flags );
+ void ( *pfnScrollTo )( HWND hwnd, struct ClcData *dat, int desty, int noSmooth );
+ void ( *pfnEnsureVisible )(HWND hwnd, struct ClcData *dat, int iItem, int partialOk );
+ void ( *pfnRecalcScrollBar )( HWND hwnd, struct ClcData *dat );
+ void ( *pfnSetGroupExpand )( HWND hwnd, struct ClcData *dat, struct ClcGroup *group, int newState );
+ void ( *pfnDoSelectionDefaultAction )( HWND hwnd, struct ClcData *dat );
+ int ( *pfnFindRowByText )(HWND hwnd, struct ClcData *dat, const TCHAR *text, int prefixOk );
+ void ( *pfnEndRename )(HWND hwnd, struct ClcData *dat, int save );
+ void ( *pfnDeleteFromContactList )( HWND hwnd, struct ClcData *dat );
+ void ( *pfnBeginRenameSelection )( HWND hwnd, struct ClcData *dat );
+ void ( *pfnCalcEipPosition )( struct ClcData *dat, struct ClcContact *contact, struct ClcGroup *group, POINT *result);
+ int ( *pfnGetDropTargetInformation )( HWND hwnd, struct ClcData *dat, POINT pt );
+ int ( *pfnClcStatusToPf2 )( int status );
+ int ( *pfnIsHiddenMode )( struct ClcData *dat, int status );
+ void ( *pfnHideInfoTip )( HWND hwnd, struct ClcData *dat );
+ void ( *pfnNotifyNewContact )( HWND hwnd, HANDLE hContact );
+ DWORD ( *pfnGetDefaultExStyle )( void );
+ void ( *pfnGetDefaultFontSetting )( int i, LOGFONT* lf, COLORREF* colour );
+ void ( *pfnGetFontSetting )( int i, LOGFONT* lf, COLORREF* colour );
+ void ( *pfnLoadClcOptions )( HWND hwnd, struct ClcData *dat );
+ void ( *pfnRecalculateGroupCheckboxes )( HWND hwnd, struct ClcData *dat );
+ void ( *pfnSetGroupChildCheckboxes )( struct ClcGroup *group, int checked );
+ void ( *pfnInvalidateItem )( HWND hwnd, struct ClcData *dat, int iItem );
+
+ int ( *pfnGetRowBottomY )(struct ClcData *dat, int item);
+ int ( *pfnGetRowHeight )(struct ClcData *dat, int item);
+ int ( *pfnGetRowTopY )(struct ClcData *dat, int item);
+ int ( *pfnGetRowTotalHeight )(struct ClcData *dat);
+ int ( *pfnRowHitTest )(struct ClcData *dat, int y);
+
+ /* clistevents.c */
+ int ( *pfnEventsProcessContactDoubleClick )( HANDLE hContact );
+ int ( *pfnEventsProcessTrayDoubleClick )( void );
+
+ /* clistmod.c */
+ int ( *pfnIconFromStatusMode )( const char *szProto, int status, HANDLE hContact );
+ int ( *pfnShowHide )( WPARAM, LPARAM );
+ TCHAR* ( *pfnGetStatusModeDescription )( int mode, int flags );
+
+ /* clistsettings.c */
+ ClcCacheEntryBase* ( *pfnGetCacheEntry )( HANDLE hContact );
+ ClcCacheEntryBase* ( *pfnCreateCacheItem )( HANDLE hContact );
+ void ( *pfnCheckCacheItem )( ClcCacheEntryBase* );
+ void ( *pfnFreeCacheItem )( ClcCacheEntryBase* );
+
+ TCHAR* ( *pfnGetContactDisplayName )( HANDLE hContact, int mode );
+ void ( *pfnInvalidateDisplayNameCacheEntry )( HANDLE hContact );
+
+ /* clisttray.c */
+ void ( *pfnTrayIconUpdateWithImageList )( int iImage, const TCHAR *szNewTip, char *szPreferredProto );
+ void ( *pfnTrayIconUpdateBase )( const char *szChangedProto );
+ void ( *pfnTrayIconSetToBase )( char *szPreferredProto );
+ void ( *pfnTrayIconIconsChanged )( void );
+ int ( *pfnTrayIconPauseAutoHide )( WPARAM wParam, LPARAM lParam );
+ int ( *pfnTrayIconProcessMessage )( WPARAM wParam, LPARAM lParam );
+ int ( *pfnCListTrayNotify )( MIRANDASYSTRAYNOTIFY* );
+
+ /* clui.c */
+ LRESULT ( CALLBACK *pfnContactListWndProc )( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
+
+ void ( *pfnCluiProtocolStatusChanged )( int status, const char* szProto );
+ void ( *pfnDrawMenuItem )( LPDRAWITEMSTRUCT, HICON, HICON );
+ void ( *pfnLoadCluiGlobalOpts )( void );
+ BOOL ( *pfnInvalidateRect )( HWND hwnd, CONST RECT* lpRect,BOOL bErase );
+ void ( *pfnOnCreateClc )( void );
+
+ /* contact.c */
+ void ( *pfnChangeContactIcon )( HANDLE hContact, int iIcon, int add );
+ void ( *pfnLoadContactTree )( void );
+ int ( *pfnCompareContacts )( const struct ClcContact *contact1, const struct ClcContact *contact2 );
+ void ( *pfnSortContacts )( void );
+ int ( *pfnSetHideOffline )( WPARAM wParam, LPARAM lParam );
+
+ /* docking.c */
+ int ( *pfnDocking_ProcessWindowMessage )( WPARAM wParam, LPARAM lParam );
+
+ /* group.c */
+ TCHAR* ( *pfnGetGroupName )( int idx, DWORD* pdwFlags );
+ int ( *pfnRenameGroup )( int groupID, TCHAR* newName );
+
+ /* keyboard.c */
+ int ( *pfnHotKeysRegister )( HWND hwnd );
+ void ( *pfnHotKeysUnregister )( HWND hwnd );
+ int ( *pfnHotKeysProcess )( HWND hwnd, WPARAM wParam, LPARAM lParam );
+ int ( *pfnHotkeysProcessMessage )( WPARAM wParam, LPARAM lParam );
+
+ /*************************************************************************************
+ * version 2 - events processing
+ *************************************************************************************/
+
+ EventList events;
+
+ struct CListEvent* ( *pfnCreateEvent )( void );
+ void ( *pfnFreeEvent )( struct CListEvent* );
+
+ struct CListEvent* ( *pfnAddEvent )( CLISTEVENT* );
+ CLISTEVENT* ( *pfnGetEvent )( HANDLE hContact, int idx );
+
+ int ( *pfnRemoveEvent )( HANDLE hContact, HANDLE hDbEvent );
+ int ( *pfnGetImlIconIndex )( HICON hIcon );
+
+ /*************************************************************************************
+ * version 3 additions
+ *************************************************************************************/
+
+ int ( *pfnGetWindowVisibleState )( HWND hWnd, int iStepX, int iStepY );
+}
+ CLIST_INTERFACE;
+
+extern CLIST_INTERFACE cli, *pcli;
+
+#endif // M_CLISTINT_H__
diff --git a/miranda-wine/include/m_clui.h b/miranda-wine/include/m_clui.h
new file mode 100644
index 0000000..2c40b9a
--- /dev/null
+++ b/miranda-wine/include/m_clui.h
@@ -0,0 +1,166 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_CLUI_H__
+#define M_CLUI_H__ 1
+
+//this module was created in 0.1.1.0
+//you probably shouldn't need to call anything in here. Look in
+//ui/contactlist/m_clist.h instead
+
+//gets the handle for the contact list window
+//wParam=lParam=0
+//returns the HWND
+//This call has a few very specific purposes internally in Miranda, and
+//shouldn't be gratuitously used. In almost all cases there's another call to
+//do whatever it is you are trying to do.
+#define MS_CLUI_GETHWND "CLUI/GetHwnd"
+
+//get ContactTree hwnd
+#define MS_CLUI_GETHWNDTREE "CLUI/GetHwndTree"
+
+//change protocol-specific status indicators
+//wParam=new status
+//lParam=(LPARAM)(const char*)szProtocolID
+//returns 0 on success, nonzero on failure
+//protocol modules don't want to call this. They want
+//clist/protocolstatuschanged instead
+#define MS_CLUI_PROTOCOLSTATUSCHANGED "CLUI/ProtocolStatusChanged"
+
+//a new group was created. Add it to the list
+//wParam=(WPARAM)(HANDLE)hGroup
+//lParam=newGroup
+//returns 0 on success, nonzero on failure
+//newGroup is set to 1 if the user just created the group, and 0 otherwise
+//this is also called when the contact list is being rebuilt
+//new groups are always created with the name "New Group"
+#define MS_CLUI_GROUPADDED "CLUI/GroupCreated"
+
+//change the icon for a contact
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=iconid
+//returns 0 on sucess, nonzero on failure
+//iconid is an offset in the image list. see clist/geticonsimagelist
+#define MS_CLUI_CONTACTSETICON "CLUI/ContactSetIcon"
+
+//remove a contact from the list
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=0
+//returns 0 on success, nonzero on failure
+//this is not necessarily the same as a contact being actually deleted, since
+//if a contact goes offline while 'hide offline' is on, this will be called
+#define MS_CLUI_CONTACTDELETED "CLUI/ContactDeleted"
+
+//add a contact to the list
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=iconId
+//returns 0 on success, nonzero on failure
+//The caller processes the 'hide offline' setting, so the callee should not do
+//further processing based on the value of this setting.
+//warning: this will be called to re-add a contact when they come online if
+//'hide offline' is on, but it cannot determine if the contact is already on
+//the list, so you may get requests to add a contact when it is already on the
+//list, which you should ignore.
+//You'll also get this whenever an event is added for a contact, since if the
+//contact was offline it needs to be shown to display the message, even if hide
+//offline is on.
+//You should not re-sort the list on this call. A separate resort request will
+//be sent
+//iconid is an offset in the image list. see clist/geticonsimagelist
+#define MS_CLUI_CONTACTADDED "CLUI/ContactAdded"
+
+//rename a contact in the list
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=0
+//returns 0 on success, nonzero on failure
+//you should not re-sort the list on this call. A separate resort request will
+//be sent
+//you get the new name from clist/getcontactdisplayname
+#define MS_CLUI_CONTACTRENAMED "CLUI/ContactRenamed"
+
+//start a rebuild of the contact list
+//wParam=lParam=0
+//returns 0 on success, nonzero on failure
+//this is the cue to clear the existing contents of the list
+//expect to get a series of clui/groupadded calls followed by a series of
+//clui/contactadded calls, then a clui/resortlist
+#define MS_CLUI_LISTBEGINREBUILD "CLUI/ListBeginRebuild"
+
+//end a rebuild of the contact list
+//wParam=lParam=0
+//returns 0 on success, nonzero on failure
+//if you displayed an hourglass in beginrebuild, set it back here
+//you do not need to explicitly sort the list
+#define MS_CLUI_LISTENDREBUILD "CLUI/ListEndRebuild"
+
+//sort the contact list now
+//wParam=lParam=0
+//returns 0 on success, nonzero on failure
+//sorts are buffered so you won't get this message lots of times if the list
+//needs to be re-sorted many times rapidly.
+#define MS_CLUI_SORTLIST "CLUI/SortList"
+
+//Gets a load of capabilities for the loaded CLUI v0.1.2.1+
+//wParam=capability, CLUICAPS_*
+//lParam=0
+//returns the requested value, 0 if wParam is an unknown value
+//If this service is not implemented, it is assumed to return 0 to all input
+#define CLUICAPS_FLAGS1 0
+#define CLUIF_HIDEEMPTYGROUPS 1 //the clist has a checkbox in its options
+ //to set this, which will be hidden if this flag is not set. It is
+ //up to the CLUI to provide support for it, but it just seemed insane
+ //to me to have hide offline and hide empty in different pages.
+ //The setting is "CList"/"HideEmptyGroups", a byte. A complete list
+ //reload is sent whenever the user changes it.
+#define CLUIF_DISABLEGROUPS 2 //can show list without groups. Adds option
+ //to change "CList"/"UseGroups", a byte.
+#define CLUIF_HASONTOPOPTION 4 //the clui options page provides a way to
+ //change "CList"/"OnTop", a byte. When it is changed the clui should
+ //also set the topmost flag on the window using SetWindowPos().
+#define CLUIF_HASAUTOHIDEOPTION 8 //the clui options page provides a way to
+ //change the list auto hide options. It should read and write the
+ //byte "CList"/"AutoHide" and the word "CList"/"HideTime". No other
+ //action is needed.
+#define MS_CLUI_GETCAPS "CLUI/GetCaps"
+
+//a contact is being dragged outside the main window v0.1.2.0+
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=MAKELPARAM(screenX,screenY)
+//return nonzero to make the cursor a 'can drop here', or zero for 'no'
+#define ME_CLUI_CONTACTDRAGGING "CLUI/ContactDragging"
+
+//a contact has just been dropped outside the main window v0.1.2.0+
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=MAKELPARAM(screenX,screenY)
+//return nonzero if your hook processed this, so no other hooks get it
+#define ME_CLUI_CONTACTDROPPED "CLUI/ContactDropped"
+
+//a contact that was being dragged outside the main window has gone back in to
+//the main window. v0.1.2.1+
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=0
+//return zero
+#define ME_CLUI_CONTACTDRAGSTOP "CLUI/ContactDragStop"
+
+#endif // M_CLUI_H__
+
diff --git a/miranda-wine/include/m_contactdir.h b/miranda-wine/include/m_contactdir.h
new file mode 100644
index 0000000..805fa27
--- /dev/null
+++ b/miranda-wine/include/m_contactdir.h
@@ -0,0 +1,162 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2005 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_CONTACTDIR_H__
+#define M_CONTACTDIR_H__ 1
+
+/* Contactdir module was created on 2005/05/17, 0.4.0.1
+
+ -- How you use this module as a protocol --
+
+ On Load() Register your protocol with the setting name that stores unique IDs, example:
+
+ if ( ContactDir_SupportExists() ) g_Atom=ContactDir_Register("ICQ", "UIN");
+
+ This will register your protocol and walk the database looking for all contacts on PROTOCOL_NAME which have
+ a "UIN" setting and store it in memory (converting to a string as needed) You of course have to
+ provide fallback if the services don't exist, it's an idea to keep existing code for that.
+
+ -
+
+ When you add a new contact via MS_DB_CONTACT_ADD, you must register it with your protocol atom too, via
+ ContactDir_AddContact(atom, "UIN #", hContact) and when it is deleted ContactDir_RemoveContact(atom, "UIN #")
+
+ -
+
+ To find a contact, use ContactDir_Lookup(atom, "ICQ #") which will return the hContact.
+
+*/
+
+typedef struct {
+ int cbSize;
+ char * szProto;
+ char * szSetting;
+ HANDLE atom; // out arg
+} CONTACTDIRECTORYDESCRIPTOR;
+
+/*
+ wParam: 0
+ lParam: (LPARAM) &CONTACTDIRECTORYDESCRIPTOR;
+ Affect: Register a given protocol and it's setting name which contains the unique key entry. e.g. ("ICQ", "UIN")
+ and return a HANDLE for use with other lookup services.
+ Returns: 0 on success, non zero on failure -- a returned handle is in .atom
+ Note: The directory will convert dword values into string representations but will not do this for bytes or words
+ used as IDs -- the protocol has to convert the IDs itself (:
+ Note: See ContactDir_Register() for a quicker way.
+ *** WARNING ***: This service does not expect the given module name to have registered as a protocol module, it
+ completely bypasses this information.
+ Version: 0.4.0.1 (2005/05/17+)
+*/
+#define MS_CONTACTDIR_REGISTER "ContactDir/Register"
+
+typedef struct {
+ int cbSize;
+ HANDLE atom; // Atom handle from MS_CONTACTDIR_REGISTER
+ char * szID; // in: value you wish to find (makes its own copy if needed)
+ HANDLE hContact; // out: hContact associated with szID, if any.
+} CONTACTDIRECTORYLOOKUP;
+
+/*
+
+ wParam: 0
+ lParam: (LPARAM) &CONTACTDIRECTORYLOOKUP;
+ Affect: Given an atom and string ID, will find the associated DB hContact value
+ Returns: 0 on success, non zero on failure
+ Version: 0.4.0.1 (2005/05/17+)
+ Note: ContactDir_Lookup() helper macro might be of use.
+*/
+
+#define MS_CONTACTDIR_LOOKUP "ContactDir/Lookup"
+
+/*
+ wParam: 0
+ lParam: (LPARAM)&CONTACTDIRECTORYLOOKUP;
+ Affect: Add a contact to a protocol atom association.
+ Returns: 0 on success, non zero on failure
+ Version: 0.4.0.1 (2005/05/17+)
+ Note: You must call this when you create a contact with MS_DB_CONTACT_ADD, see ContactDir_AddContact()
+*/
+#define MS_CONTACTDIR_ADDCONTACT "ContactDir/AddContact"
+
+/*
+ wParam: 0
+ lParam: (LPARAM)&CONTACTDIRECTORYLOOKUP;
+ Affect: Remove a contact to a protocol atom association.
+ Returns: 0 on success, non zero on failure
+ Version: 0.4.0.1 (2005/05/17+)
+ Note: see ContactDir_RemoveContact()
+*/
+#define MS_CONTACTDIR_REMOVECONTACT "ContactDir/RemoveContact"
+
+
+/* -- Helper functions -- */
+
+static int ContactDir_SupportExists(void)
+{
+ return ServiceExists(MS_CONTACTDIR_REGISTER);
+}
+
+// Only take as valid if ContactDir_SupportExists() returns true.
+static HANDLE ContactDir_Register(char * szProto, char * szSetting)
+{
+ CONTACTDIRECTORYDESCRIPTOR cd;
+ cd.cbSize=sizeof(CONTACTDIRECTORYDESCRIPTOR);
+ cd.szProto=szProto;
+ cd.szSetting=szSetting;
+ cd.atom=NULL;
+ CallService(MS_CONTACTDIR_REGISTER, 0, (LPARAM)&cd);
+ return cd.atom;
+}
+
+static __inline HANDLE ContactDir_Lookup(HANDLE atom, char * szID)
+{
+ CONTACTDIRECTORYLOOKUP f;
+ f.cbSize=sizeof(f);
+ f.atom=atom;
+ f.szID=szID;
+ f.hContact=NULL;
+ CallService(MS_CONTACTDIR_LOOKUP, 0, (LPARAM)&f);
+ return f.hContact;
+}
+
+static __inline void ContactDir_AddContact(HANDLE atom, char * szID, HANDLE hContact)
+{
+ CONTACTDIRECTORYLOOKUP c = {0};
+ c.cbSize=sizeof(CONTACTDIRECTORYLOOKUP);
+ c.atom=atom;
+ c.szID=szID;
+ c.hContact=hContact;
+ CallService(MS_CONTACTDIR_ADDCONTACT, 0, (LPARAM)&c);
+}
+
+static __inline void ContactDir_RemoveContact(HANDLE atom, char * szID)
+{
+ CONTACTDIRECTORYLOOKUP c = {0};
+ c.cbSize=sizeof(CONTACTDIRECTORYLOOKUP);
+ c.atom=atom;
+ c.szID=szID;
+ c.hContact=NULL;
+ CallService(MS_CONTACTDIR_REMOVECONTACT, 0, (LPARAM)&c);
+}
+
+#endif /* M_CONTACTDIR_H__ */ \ No newline at end of file
diff --git a/miranda-wine/include/m_contacts.h b/miranda-wine/include/m_contacts.h
new file mode 100644
index 0000000..fe9a82a
--- /dev/null
+++ b/miranda-wine/include/m_contacts.h
@@ -0,0 +1,106 @@
+/*
+Miranda IM
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef M_CONTACTS_H__
+#define M_CONTACTS_H__ 1
+
+typedef struct {
+ int cbSize;
+ BYTE dwFlag;
+ HANDLE hContact;
+ char *szProto;
+ BYTE type;
+ union {
+ BYTE bVal;
+ WORD wVal;
+ DWORD dVal;
+ TCHAR *pszVal;
+ WORD cchVal;
+ };
+} CONTACTINFO;
+
+// Types of information you can retreive by setting the dwFlag in CONTACTINFO
+#define CNF_FIRSTNAME 1 // returns first name (string)
+#define CNF_LASTNAME 2 // returns last name (string)
+#define CNF_NICK 3 // returns nick name (string)
+#define CNF_CUSTOMNICK 4 // returns custom nick name, clist name (string)
+#define CNF_EMAIL 5 // returns email (string)
+#define CNF_CITY 6 // returns city (string)
+#define CNF_STATE 7 // returns state (string)
+#define CNF_COUNTRY 8 // returns country (string)
+#define CNF_PHONE 9 // returns phone (string)
+#define CNF_HOMEPAGE 10 // returns homepage (string)
+#define CNF_ABOUT 11 // returns about info (string)
+#define CNF_GENDER 12 // returns gender (byte,'M','F' character)
+#define CNF_AGE 13 // returns age (byte, 0==unspecified)
+#define CNF_FIRSTLAST 14 // returns first name + last name (string)
+#define CNF_UNIQUEID 15 // returns uniqueid, protocol username (must check type for type of return)
+#define CNF_FAX 18 // returns fax (string)
+#define CNF_CELLULAR 19 // returns cellular (string)
+#define CNF_TIMEZONE 20 // returns timezone (string)
+#define CNF_MYNOTES 21 // returns user specified notes (string)
+#define CNF_BIRTHDAY 22 // returns birthday day of month (byte)
+#define CNF_BIRTHMONTH 23 // returns birthday month (byte)
+#define CNF_BIRTHYEAR 24 // returns birthday year (word)
+#define CNF_STREET 25 // returns street (string)
+#define CNF_ZIP 26 // returns zip code (string)
+#define CNF_LANGUAGE1 27 // returns language1 (string)
+#define CNF_LANGUAGE2 28 // returns language2 (string)
+#define CNF_LANGUAGE3 29 // returns language3 (string)
+#define CNF_CONAME 30 // returns company name (string)
+#define CNF_CODEPT 31 // returns company department (string)
+#define CNF_COPOSITION 32 // returns company position (string)
+#define CNF_COSTREET 33 // returns company street (string)
+#define CNF_COCITY 34 // returns company city (string)
+#define CNF_COSTATE 35 // returns company state (string)
+#define CNF_COZIP 36 // returns company zip code (string)
+#define CNF_COCOUNTRY 37 // returns company country (string)
+#define CNF_COHOMEPAGE 38 // returns company homepage (string)
+
+// Special types
+// Return the custom name using the name order setting
+// IMPORTANT: When using CNF_DISPLAY you MUST free the string returned
+// You must **NOT** do this from your version of free() you have to use Miranda's free()
+// you can get a function pointer to Miranda's free() via MS_SYSTEM_GET_MMI, see m_system.h
+#define CNF_DISPLAY 16
+// Same as CNF_DISPLAY except the custom handle is not used
+// IMPORTANT: When using CNF_DISPLAYNC you MUST free the string returned
+// You must **NOT** do this from your version of free() you have to use Miranda's free()
+// you can get a function pointer to Miranda's free() via MS_SYSTEM_GET_MMI, see m_system.h
+#define CNF_DISPLAYNC 17
+
+// Add this flag if you want to get the Unicode info
+#define CNF_UNICODE 0x80
+
+// If MS_CONTACT_GETCONTACTINFO returns 0 (valid), then one of the following
+// types is setting telling you what type of info you received
+#define CNFT_BYTE 1
+#define CNFT_WORD 2
+#define CNFT_DWORD 3
+#define CNFT_ASCIIZ 4
+
+// Get contact information
+// wParam = not used
+// lParam = (CONTACTINFO *)
+// Returns 1 on failure to retrieve the info and 0 on success. If
+// sucessful, the type is set and the result is put into the associated
+// member of CONTACTINFO
+#define MS_CONTACT_GETCONTACTINFO "Miranda/Contact/GetContactInfo"
+
+#endif // M_CONTACTS_H__
+
diff --git a/miranda-wine/include/m_database.h b/miranda-wine/include/m_database.h
new file mode 100644
index 0000000..44fdca5
--- /dev/null
+++ b/miranda-wine/include/m_database.h
@@ -0,0 +1,1054 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_DATABASE_H__
+#define M_DATABASE_H__ 1
+
+/******************* DATABASE MODULE ***************************/
+
+/* Notes (as I think of them):
+- The module is 100% thread-safe
+- The database is the main routing point for the vast majority of Miranda.
+ Events are sent from the protocol module to here, and the send/recv message
+ module (for example) hooks the db/event/added event. Events like 'contact
+ online status changed' do not come through here - icqlib will send that one.
+- contacts work much the same. the find/add users module calls db/contact/add
+ and db/contact/writesetting and the contact list will get db/contact/added
+ and db/contact/settingchanged events
+- The user is just a special contact. A hcontact of NULL in most functions
+ means the user. Functions in which it cannot be used will be stated
+- events attached to the user are things like system messages
+- also in this module are crypt/decrypt functions for stuff that should be
+ obfuscated on the disk, and some time functions for dealing with timestamps
+ in events.
+- the contactsettings system is designed for being read by many different
+ modules. eg lots of people will be interested in "ICQ"/"UIN", but the module
+ name passed to contact/writesetting should always be your own. The Mirabilis
+ ICQ database importer clearly has to be an exception to this rule, along with
+ a few other bits.
+- the current database format means that geteventcontact is exceptionally slow.
+ It should be avoidable in most cases so I'm not too concerned, but if people
+ really need to use it a lot, I'll sort it out.
+- handles do not need to be closed unless stated
+- the database is loaded as a memory mapped file. This has various
+ disadvantages but a massive advantage in speed for random access.
+- The database is optimised for reading. Write performance is fairly bad,
+ except for adding events which is the most common activity and pretty good.
+- I'll work on caching to improve this later
+- Deleted items are left as empty space and never reused. All new items are
+ put at the end. A count is kept of this slack space and at some point a
+ separate programme will need to be written to repack the database when the
+ slack gets too high. It's going to be a good few months of usage before this
+ can happen to anyone though, so no rush.
+*/
+
+/******************** GENERALLY USEFUL STUFF***********************/
+
+#include <tchar.h>
+
+//DBVARIANT: used by db/contact/getsetting and db/contact/writesetting
+#define DBVT_DELETED 0 //this setting just got deleted, no other values are valid
+#define DBVT_BYTE 1 //bVal and cVal are valid
+#define DBVT_WORD 2 //wVal and sVal are valid
+#define DBVT_DWORD 4 //dVal and lVal are valid
+#define DBVT_ASCIIZ 255 //pszVal is valid
+#define DBVT_BLOB 254 //cpbVal and pbVal are valid
+#define DBVT_UTF8 253 //pszVal is valid
+#define DBVT_WCHAR 252 //pszVal is valid
+#define DBVTF_VARIABLELENGTH 0x80
+typedef struct {
+ BYTE type;
+ union {
+ BYTE bVal; char cVal;
+ WORD wVal; short sVal;
+ DWORD dVal; long lVal;
+ struct {
+ union {
+ char *pszVal;
+ TCHAR *ptszVal;
+ WCHAR *pwszVal;
+ };
+ WORD cchVal; //only used for db/contact/getsettingstatic
+ };
+ struct {
+ WORD cpbVal;
+ BYTE *pbVal;
+ };
+ };
+} DBVARIANT;
+
+/******************************************************************/
+/************************* SERVICES *******************************/
+/******************************************************************/
+
+/* DB/Contact/GetProfileName service
+Gets the name of the profile currently being used by the database module. This
+is the same as the filename of the database, minus extension
+ wParam=(WPARAM)(UINT)cbName
+ lParam=(LPARAM)(char*)pszName
+pszName is a pointer to the buffer that receives the name of the profile
+cbName is the size in bytes of the pszName buffer
+Returns 0 on success or nonzero otherwise
+*/
+#define MS_DB_GETPROFILENAME "DB/GetProfileName"
+
+/* DB/Contact/GetProfilePath service
+Gets the path of the profile currently being used by the database module. This
+path does not include the last '\'.
+ wParam=(WPARAM)(UINT)cbName
+ lParam=(LPARAM)(char*)pszName
+pszName is a pointer to the buffer that receives the path of the profile
+cbName is the size in bytes of the pszName buffer
+Returns 0 on success or nonzero otherwise
+*/
+#define MS_DB_GETPROFILEPATH "DB/GetProfilePath"
+
+/************************* Contact ********************************/
+
+/* DB/Contact/GetSetting service
+Look up the value of a named setting for a specific contact in the database
+ wParam=(WPARAM)(HANDLE)hContact
+ lParam=(LPARAM)(DBCONTACTGETSETTING*)&dbcgs
+hContact should have been returned by find*contact or addcontact
+Caller is responsible for free()ing dbcgs.pValue->pszVal and pbVal if they are
+returned. This should be done with db/contact/freevariant if you have your own
+heap (like DLLs do).
+Note that DBCONTACTGETSETTING takes a pointer to a DBVARIANT, whereas
+DBCONTACTWRITESETTING contains a DBVARIANT.
+Returns 0 on success or nonzero if the setting name was not found or hContact
+was invalid
+Because this is such a common function there are some short helper function at
+the bottom of this header that use it.
+
+(Added during 0.3.3+ development!!)
+
+If a setting is queried under for contact and it is deleted it will
+not be returned as a successful attempt, prior to 0.3.3 a *deleted*
+setting would be successfully read (which was a bug because the pValue
+was often garbage and maybe not even NULL terminated)
+
+To test for existing but 'deleted' settings, the return value will
+be 2, and pValue->type==DBVT_DELETED, at this point pValue is undefined.
+*/
+typedef struct {
+ const char *szModule; // pointer to name of the module that wrote the
+ // setting to get
+ const char *szSetting; // pointer to name of the setting to get
+ DBVARIANT *pValue; // pointer to variant to receive the value
+} DBCONTACTGETSETTING;
+#define MS_DB_CONTACT_GETSETTING "DB/Contact/GetSetting"
+
+/* DB/Contact/GetSettingString service 0.4.3+
+Same as DB/Contact/GetSetting, but also gets the required string type inside
+the dbcgs->type parameter
+*/
+#define MS_DB_CONTACT_GETSETTING_STR "DB/Contact/GetSettingStr"
+
+/* DB/Contact/GetSettingStatic service
+Look up the value of a named setting for a specific contact in the database
+ wParam=(WPARAM)(HANDLE)hContact
+ lParam=(LPARAM)(DBCONTACTGETSETTING*)&dbcgs
+hContact should have been returned by find*contact or addcontact
+This service differs from db/contact/getsetting in that it won't malloc()
+memory for the return value if it needs to do so. This introduces some extra
+constraints:
+Upon calling dbcgs.pValue->type should be initialised to the expected type of
+the setting. If the setting is of an integral type it won't matter if it's
+wrong and the service will correct it before returning, however if the setting
+is a string or a blob the service needs to know where to put the data and will
+fail if type is set wrongly.
+If dbcgs.pValue->type is DBVT_ASCIIZ or DBVT_BLOB upon calling, the
+corresponding data field (pszVal or pbVal) must point to a buffer allocated by
+the caller and the length field (cchVal or cpbVal) must contain the size of
+that buffer in bytes.
+If the setting type is variable length (DBVT_ASCIIZ or DBVT_BLOB), on exit the
+length field (cchVal or cpbVal) will be filled with the full length of the
+setting's value (excluding the terminating nul if it's DBVT_ASCIIZ).
+This service exists as well as db/contact/getsetting because malloc()/free()
+can be too slow for frequently queried settings.
+Returns 0 on success or nonzero if the setting name was not found or hContact
+was invalid.
+*/
+#define MS_DB_CONTACT_GETSETTINGSTATIC "DB/Contact/GetSettingStatic"
+
+/* DB/Contact/FreeVariant service
+Free the memory in a DBVARIANT that is allocated by a call to
+db/contact/getsetting
+ wParam=0
+ lParam=(LPARAM)(DBVARIANT*)&dbv
+Returns 0 on success, nonzero otherwise
+This service is actually just a wrapper around a call to free() and a test to
+check that it is a string or a blob in the variant. It exists because DLLs have
+their own heap and cannot free the memory allocated in db/contact/getsetting.
+Thus it need not be called if you know the variant contains some form of int,
+and you will often see free() used instead in code written before I noticed
+this problem.
+Good style, of course, dictates that it should be present to match all calls to
+db/contact/getsetting, but that's not going to happen of course.
+There's a helper function for this at the bottom of this header too.
+*/
+#define MS_DB_CONTACT_FREEVARIANT "DB/Contact/FreeVariant"
+
+/* DB/Contact/WriteSetting service
+Change the value of, or create a new value with, a named setting for a specific
+contact in the database to the given value
+ wParam=(WPARAM)(HANDLE)hContact
+ lParam=(LPARAM)(DBCONTACTWRITESETTING*)&dbcws
+hContact should have been returned by find*contact or addcontact
+Returns 0 on success or nonzero if hContact was invalid
+Note that DBCONTACTGETSETTING takes a pointer to a DBVARIANT, whereas
+DBCONTACTWRITESETTING contains a DBVARIANT.
+Because this is such a common function there are some short helper function at
+the bottom of this header that use it.
+Triggers a db/contact/settingchanged event just before it returns.
+*/
+typedef struct {
+ const char *szModule; // pointer to name of the module that wrote the
+ // setting to get
+ const char *szSetting; // pointer to name of the setting to get
+ DBVARIANT value; // variant containing the value to set
+} DBCONTACTWRITESETTING;
+#define MS_DB_CONTACT_WRITESETTING "DB/Contact/WriteSetting"
+
+/* DB/Contact/DeleteSetting service
+Removes a named setting for a specific contact from the database
+ wParam=(WPARAM)(HANDLE)hContact
+ lParam=(LPARAM)(DBCONTACTGETSETTING*)&dbcgs
+hContact should have been returned by find*contact or addcontact
+pValue from dbcgs is not used.
+Returns 0 on success or nonzero if the setting was not present or hContact was
+invalid
+Triggers a db/contact/settingchanged event before it deletes the setting. The
+'new value' of the setting is set to type=0 and all the other fields are
+undefined.
+*/
+#define MS_DB_CONTACT_DELETESETTING "DB/Contact/DeleteSetting"
+
+/* db/contact/enumsettings v0.1.0.1+
+Lists all the settings a specific modules has stored in the database for a
+specific contact.
+wParam=(WPARAM)(HANDLE)hContact
+lParam=(LPARAM)(DBCONTACTENUMSETTINGS*)&dbces
+Returns the return value of the last call to pfnEnumProc, or -1 if there are
+no settings for that module/contact pair
+Writing to or deleting from the database while enumerating will have
+unpredictable results for the enumeration, but the write will succeed.
+Use db/modules/enum to get a complete list of module names
+szSetting is only guaranteed to be valid for the duration of the callback. If
+you want to keep it for longer you must allocation your own storage.
+*/
+typedef int (*DBSETTINGENUMPROC)(const char *szSetting,LPARAM lParam);
+typedef struct {
+ DBSETTINGENUMPROC pfnEnumProc;
+ LPARAM lParam; //passed direct to pfnEnumProc
+ const char *szModule; //name of the module to get settings for
+ DWORD ofsSettings; //filled by the function to contain the offset from
+ //the start of the database of the requested settings group.
+} DBCONTACTENUMSETTINGS;
+#define MS_DB_CONTACT_ENUMSETTINGS "DB/Contact/EnumSettings"
+
+/* DB/Contact/GetCount service
+Gets the number of contacts in the database, which does not count the user
+ wParam=lParam=0
+Returns the number of contacts. They can be retrieved using contact/findfirst
+and contact/findnext
+*/
+#define MS_DB_CONTACT_GETCOUNT "DB/Contact/GetCount"
+
+/* DB/Contact/FindFirst service
+Gets the handle of the first contact in the database. This handle can be used
+with loads of functions. It does not need to be closed.
+ wParam=lParam=0
+Returns a handle to the first contact in the db on success, or NULL if there
+are no contacts in the db.
+*/
+#define MS_DB_CONTACT_FINDFIRST "DB/Contact/FindFirst"
+
+/* DB/Contact/FindNext service
+Gets the handle of the next contact after hContact in the database. This handle
+can be used with loads of functions. It does not need to be closed.
+ wParam=(WPARAM)(HANDLE)hContact
+ lParam=0
+Returns a handle to the contact after hContact in the db on success or NULL if
+hContact was the last contact in the db or hContact was invalid.
+*/
+#define MS_DB_CONTACT_FINDNEXT "DB/Contact/FindNext"
+
+/* DB/Contact/Delete
+Deletes the contact hContact from the database and all events and settings
+associated with it.
+ wParam=(WPARAM)(HANDLE)hContact
+ lParam=0
+Returns 0 on success or nonzero if hContact was invalid
+Please don't try to delete the user contact (hContact=NULL)
+Triggers a db/contact/deleted event just *before* it removes anything
+Because all events are deleted, lots of people may end up with invalid event
+handles from this operation, which they should be prepared for.
+*/
+#define MS_DB_CONTACT_DELETE "DB/Contact/Delete"
+
+/* DB/Contact/Add
+Adds a new contact to the database. New contacts initially have no settings
+whatsoever, they must all be added with db/contacts/writesetting.
+ wParam=lParam=0
+Returns a handle to the newly created contact on success, or NULL otherwise.
+Triggers a db/contact/added event just before it returns.
+*/
+#define MS_DB_CONTACT_ADD "DB/Contact/Add"
+
+/* DB/Contact/Is
+Checks if a given value is a valid contact handle, note that due
+to the nature of multiple threading, a valid contact can still become
+invalid after a call to this service.
+ wParam=(WPARAM)hContact
+ lParam=0
+Returns 1 if the contact is a contact, or 0 if the contact is not valid.
+*/
+#define MS_DB_CONTACT_IS "DB/Contact/Is"
+
+/************************** Event *********************************/
+
+/* DB/Event/GetCount service
+Gets the number of events in the chain belonging to a contact in the database.
+ wParam=(WPARAM)(HANDLE)hContact
+ lParam=0
+Returns the number of events in the chain owned by hContact or -1 if hContact
+is invalid. They can be retrieved using the event/find* services.
+*/
+#define MS_DB_EVENT_GETCOUNT "DB/Event/GetCount"
+
+/* DB/Event/Add
+Adds a new event to a contact's event list
+ wParam=(WPARAM)(HANDLE)hContact
+ lParam=(LPARAM)(DBEVENTINFO*)&dbe
+Returns a handle to the newly added event, or NULL on failure
+Triggers a db/event/added event just before it returns.
+Events are sorted chronologically as they are entered, so you cannot guarantee
+that the new hEvent is the last event in the chain, however if a new event is
+added that has a timestamp less than 90 seconds *before* the event that should
+be after it, it will be added afterwards, to allow for protocols that only
+store times to the nearest minute, and slight delays in transports.
+There are a few predefined eventTypes below for easier compatibility, but
+modules are free to define their own, beginning at 2000
+DBEVENTINFO.timestamp is in GMT, as returned by time(). There are services
+db/time/x below with useful stuff for dealing with it.
+*/
+#define DBEF_FIRST 1 //this is the first event in the chain;
+ //internal only: *do not* use this flag
+#define DBEF_SENT 2 //this event was sent by the user. If not set this
+ //event was received.
+#define DBEF_READ 4 //event has been read by the user. It does not need
+ //to be processed any more except for history.
+#define DBEF_RTL 8 //event contains the right-to-left aligned text
+
+typedef struct {
+ int cbSize; //size of the structure in bytes
+ char *szModule; //pointer to name of the module that 'owns' this
+ //event, ie the one that is in control of the data format
+ DWORD timestamp; //seconds since 00:00, 01/01/1970. Gives us times until
+ //2106 unless you use the standard C library which is
+ //signed and can only do until 2038. In GMT.
+ DWORD flags; //the omnipresent flags
+ WORD eventType; //module-defined event type field
+ DWORD cbBlob; //size of pBlob in bytes
+ PBYTE pBlob; //pointer to buffer containing module-defined event data
+} DBEVENTINFO;
+#define EVENTTYPE_MESSAGE 0
+#define EVENTTYPE_URL 1
+#define EVENTTYPE_CONTACTS 2 //v0.1.2.2+
+#define EVENTTYPE_ADDED 1000 //v0.1.1.0+: these used to be module-
+#define EVENTTYPE_AUTHREQUEST 1001 //specific codes, hence the module-
+#define EVENTTYPE_FILE 1002 //specific limit has been raised to 2000
+#define MS_DB_EVENT_ADD "DB/Event/Add"
+
+/* DB/Event/Delete
+Removes a single event from the database
+ wParam=(WPARAM)(HANDLE)hContact
+ lParam=(LPARAM)(HANDLE)hDbEvent
+hDbEvent should have been returned by db/event/add or db/event/find*event
+Returns 0 on success, or nonzero if hDbEvent was invalid
+Triggers a db/event/deleted event just *before* the event is deleted
+*/
+#define MS_DB_EVENT_DELETE "DB/Event/Delete"
+
+/* DB/Event/GetBlobSize
+Retrieves the space in bytes required to store the blob in hDbEvent
+ wParam=(WPARAM)(HANDLE)hDbEvent
+ lParam=0
+hDbEvent should have been returned by db/event/add or db/event/find*event
+Returns the space required in bytes, or -1 if hDbEvent is invalid
+*/
+#define MS_DB_EVENT_GETBLOBSIZE "DB/Event/GetBlobSize"
+
+/* DB/Event/Get
+Retrieves all the information stored in hDbEvent
+ wParam=(WPARAM)(HANDLE)hDbEvent
+ lParam=(LPARAM)(DBEVENTINFO*)&dbe
+hDbEvent should have been returned by db/event/add or db/event/find*event
+Returns 0 on success or nonzero if hDbEvent is invalid
+Don't forget to set dbe.cbSize, dbe.pBlob and dbe.cbBlob before calling this
+service
+The correct value dbe.cbBlob can be got using db/event/getblobsize
+If successful, all the fields of dbe are filled. dbe.cbBlob is set to the
+actual number of bytes retrieved and put in dbe.pBlob
+If dbe.cbBlob is too small, dbe.pBlob is filled up to the size of dbe.cbBlob
+and then dbe.cbBlob is set to the required size of data to go in dbe.pBlob
+On return, dbe.szModule is a pointer to the database module's own internal list
+of modules. Look but don't touch.
+*/
+#define MS_DB_EVENT_GET "DB/Event/Get"
+
+/* DB/Event/MarkRead
+Changes the flags for an event to mark it as read.
+ wParam=(WPARAM)(HANDLE)hContact
+ lParam=(LPARAM)(HANDLE)hDbEvent
+hDbEvent should have been returned by db/event/add or db/event/find*event
+Returns the entire flag DWORD for the event after the change, or -1 if hDbEvent
+is invalid.
+This is the one database write operation that does not trigger an event.
+Modules should not save flags states for any length of time.
+*/
+#define MS_DB_EVENT_MARKREAD "DB/Event/MarkRead"
+
+/* DB/Event/GetContact
+Retrieves a handle to the contact that owns hDbEvent.
+ wParam=(WPARAM)(HANDLE)hDbEvent
+ lParam=0
+hDbEvent should have been returned by db/event/add or db/event/find*event
+NULL is a valid return value, meaning, as usual, the user.
+Returns (HANDLE)(-1) if hDbEvent is invalid, or the handle to the contact on
+success
+This service is exceptionally slow. Use only when you have no other choice at
+all.
+*/
+#define MS_DB_EVENT_GETCONTACT "DB/Event/GetContact"
+
+/* DB/Event/FindFirst
+Retrieves a handle to the first event in the chain for hContact
+ wParam=(WPARAM)(HANDLE)hContact
+ lParam=0
+Returns the handle, or NULL if hContact is invalid or has no events
+Events in a chain are sorted chronologically automatically
+*/
+#define MS_DB_EVENT_FINDFIRST "DB/Event/FindFirst"
+
+/* DB/Event/FindFirstUnread
+Retrieves a handle to the first unread event in the chain for hContact
+ wParam=(WPARAM)(HANDLE)hContact
+ lParam=0
+Returns the handle, or NULL if hContact is invalid or all its events have been
+read
+Events in a chain are sorted chronologically automatically, but this does not
+necessarily mean that all events after the first unread are unread too. They
+should be checked individually with event/findnext and event/get
+This service is designed for startup, reloading all the events that remained
+unread from last time
+*/
+#define MS_DB_EVENT_FINDFIRSTUNREAD "DB/Event/FindFirstUnread"
+
+/* DB/Event/FindLast
+Retrieves a handle to the last event in the chain for hContact
+ wParam=(WPARAM)(HANDLE)hContact
+ lParam=0
+Returns the handle, or NULL if hContact is invalid or has no events
+Events in a chain are sorted chronologically automatically
+*/
+#define MS_DB_EVENT_FINDLAST "DB/Event/FindLast"
+
+/* DB/Event/FindNext
+Retrieves a handle to the next event in a chain after hDbEvent
+ wParam=(WPARAM)(HANDLE)hDbEvent
+ lParam=0
+Returns the handle, or NULL if hDbEvent is invalid or is the last event
+Events in a chain are sorted chronologically automatically
+*/
+#define MS_DB_EVENT_FINDNEXT "DB/Event/FindNext"
+
+/* DB/Event/FindPrev
+Retrieves a handle to the previous event in a chain before hDbEvent
+ wParam=(WPARAM)(HANDLE)hDbEvent
+ lParam=0
+Returns the handle, or NULL if hDbEvent is invalid or is the first event
+Events in a chain are sorted chronologically automatically
+*/
+#define MS_DB_EVENT_FINDPREV "DB/Event/FindPrev"
+
+/************************** Encryption ****************************/
+
+/* DB/Crypt/EncodeString
+Scrambles pszString in-place using a strange encryption algorithm
+ wParam=(WPARAM)(int)cbString
+ lParam=(LPARAM)(char*)pszString
+cbString is the size of the buffer pointed to by pszString, *not* the length
+of pszString. This service may be changed at a later date such that it
+increases the length of pszString
+Returns 0 always
+*/
+#define MS_DB_CRYPT_ENCODESTRING "DB/Crypt/EncodeString"
+
+/* DB/Crypt/DecodeString
+Descrambles pszString in-place using the strange encryption algorithm
+ wParam=(WPARAM)(int)cbString
+ lParam=(LPARAM)(char*)pszString
+Reverses the operation done by crypt/encodestring
+cbString is the size of the buffer pointed to by pszString, *not* the length
+of pszString.
+Returns 0 always
+*/
+#define MS_DB_CRYPT_DECODESTRING "DB/Crypt/DecodeString"
+
+/**************************** Time ********************************/
+
+/* DB/Time/TimestampToLocal
+Converts a GMT timestamp into local time
+ wParam=(WPARAM)(DWORD)timestamp
+ lParam=0
+Returns the converted value
+Timestamps have zero at midnight 1/1/1970 GMT, this service converts such a
+value to be based at midnight 1/1/1970 local time.
+This service does not use a simple conversion based on the current offset
+between GMT and local. Rather, it figures out whether daylight savings time
+would have been in place at the time of the stamp and gives the local time as
+it would have been at the time and date the stamp contains.
+This service isn't nearly as useful as db/time/TimestampToString below and I
+recommend avoiding its use when possible so that you don't get your timezones
+mixed up (like I did. Living at GMT makes things easier for me, but has certain
+disadvantages :-) ).
+*/
+#define MS_DB_TIME_TIMESTAMPTOLOCAL "DB/Time/TimestampToLocal"
+
+/* DB/Time/TimestampToString
+Converts a GMT timestamp into a customisable local time string
+ wParam=(WPARAM)(DWORD)timestamp
+ lParam=(LPARAM)(DBTIMETOSTRING*)&tts
+Returns 0 always
+Uses db/time/timestamptolocal for the conversion so read that description to
+see what's going on.
+The string is formatted according to the current user's locale, language and
+preferences.
+szFormat can have the following special characters:
+ t Time without seconds, eg hh:mm
+ s Time with seconds, eg hh:mm:ss
+ m Time without minutes, eg hh
+ d Short date, eg dd/mm/yyyy
+ D Long date, eg d mmmm yyyy
+All other characters are copied across to szDest as-is
+*/
+typedef struct {
+ char *szFormat; // format string, as above
+ char *szDest; // place to put the output string
+ int cbDest; // maximum number of bytes to put in szDest
+} DBTIMETOSTRING;
+#define MS_DB_TIME_TIMESTAMPTOSTRING "DB/Time/TimestampToString"
+
+typedef struct {
+ TCHAR *szFormat; // format string, as above
+ TCHAR *szDest; // place to put the output string
+ int cbDest; // maximum number of bytes to put in szDest
+} DBTIMETOSTRINGT;
+#define MS_DB_TIME_TIMESTAMPTOSTRINGT "DB/Time/TimestampToStringT"
+
+/*************************** Random *******************************/
+
+/*
+Switches safety settings on or off
+wParam=(WPARAM)(BOOL)newSetting
+lParam=0
+returns 0 always
+newSetting is TRUE initially.
+Miranda's database is normally protected against corruption by agressively
+flushing data to the disk on writes. If you're doing a lot of writes (eg in
+an import plugin) it can sometimes be desirable to switch this feature off to
+speed up the process. If you do switch it off, you must remember that crashes
+are far more likely to be catastrophic, so switch it back on at the earliest
+possible opportunity.
+Note that if you're doing a lot of setting writes, the flush is already delayed
+so you need not use this service for that purpose.
+*/
+#define MS_DB_SETSAFETYMODE "DB/SetSafetyMode"
+
+/*************************** Modules ******************************/
+
+/* db/modules/enum v0.1.0.1+
+Enumerates the names of all modules that have stored or requested information
+from the database.
+wParam=lParam
+lParam=(WPARAM)(DBMODULEENUMPROC)dbmep
+Returns the value returned by the last call to dbmep
+This service is only really useful for debugging, in conjunction with
+db/contact/enumsettings
+lParam is passed directly to dbmep
+dbmep should return 0 to continue enumeration, or nonzero to stop.
+ofsModuleName is the offset of the module name from the start of the profile
+database, and is only useful for really heavyweight debugging
+Modules names will be enumerated in no particular order
+Writing to the database while module names are being enumerated will cause
+unpredictable results in the enumeration, but the write will work.
+szModuleName is only guaranteed to be valid for the duration of the callback.
+If you want to keep it for longer you must allocation your own storage.
+**BUG**: Prior to 0.1.2.0 dbmep was called as (lParam)(szMod,ofsMod,lParam).
+ This means that the lParam parameter to dbmep was useless, and explains the
+ slightly odd 'wParam=lParam' in the definition.
+*/
+typedef int (*DBMODULEENUMPROC)(const char *szModuleName,DWORD ofsModuleName,LPARAM lParam);
+#define MS_DB_MODULES_ENUM "DB/Modules/Enum"
+
+/******************************************************************/
+/************************** EVENTS ********************************/
+/******************************************************************/
+
+/* DB/Event/Added event
+Called when a new event has been added to the event chain for a contact
+ wParam=(WPARAM)(HANDLE)hContact
+ lParam=(LPARAM)(HANDLE)hDbEvent
+hDbEvent is a valid handle to the event. hContact is a valid handle to the
+contact to which hDbEvent refers.
+Since events are sorted chronologically, you cannot guarantee that hDbEvent is
+at any particular position in the chain.
+*/
+#define ME_DB_EVENT_ADDED "DB/Event/Added"
+
+/* DB/Event/FilterAdd (NOTE: Added during 0.3.3+ development!)
+Called **before** a new event is made of a DBEVENTINFO structure, this
+hook is not SAFE unless you know what you're doing with it, the arguments
+are passed as-is (with errors, pointer problems, if any) from any arguments
+passed to MS_DB_EVENT_ADD.
+
+The point of this hook is to stop any unwanted database events, to stop
+an event being added, return 1, to allow the event to pass through return
+0.
+ wParam=(WPARAM)(HANDLE)hContact
+ lParam=(LPARAM)&DBEVENTINFO
+
+Any changed made to the said DBEVENTINFO are also passed along to the database,
+therefore it is possible to shape the data, however DO NOT DO THIS.
+*/
+#define ME_DB_EVENT_FILTER_ADD "DB/Event/FilterAdd"
+
+/* DB/Event/Deleted event
+Called when an event is about to be deleted from the event chain for a contact
+ wParam=(WPARAM)(HANDLE)hContact
+ lParam=(LPARAM)(HANDLE)hDbEvent
+hDbEvent is a valid handle to the event which is about to be deleted, but it
+won't be once your hook has returned.
+hContact is a valid handle to the contact to which hDbEvent refers, and will
+remain valid.
+Returning nonzero from your hook will not stop the deletion, but it will, as
+usual, stop other hooks from being called.
+*/
+#define ME_DB_EVENT_DELETED "DB/Event/Deleted"
+
+/* DB/Contact/Added event
+Called when a new contact has been added to the database
+ wParam=(WPARAM)(HANDLE)hContact
+ lParam=0
+hContact is a valid handle to the new contact.
+Contacts are initially created without any settings, so if you hook this event
+you will almost certainly also want to hook db/contact/settingchanged as well.
+*/
+#define ME_DB_CONTACT_ADDED "DB/Contact/Added"
+
+/* DB/Contact/Deleted event
+Called when an contact is about to be deleted
+ wParam=(WPARAM)(HANDLE)hContact
+ lParam=0
+hContact is a valid handle to the contact which is about to be deleted, but it
+won't be once your hook has returned.
+Returning nonzero from your hook will not stop the deletion, but it will, as
+usual, stop other hooks from being called.
+Deleting a contact invalidates all events in its chain.
+*/
+#define ME_DB_CONTACT_DELETED "DB/Contact/Deleted"
+
+/* DB/Contact/SettingChanged event
+Called when a contact has had one of its settings changed
+ wParam=(WPARAM)(HANDLE)hContact
+ lParam=(LPARAM)(DBCONTACTWRITESETTING*)&dbcws
+hContact is a valid handle to the contact that has changed.
+This event will be triggered many times rapidly when a whole bunch of values
+are set.
+Modules which hook this should be aware of this fact and quickly return if they
+are not interested in the value that has been changed.
+Careful not to get into infinite loops with this event.
+The structure dbcws is the same one as is passed to the original service, so
+don't change any of the members.
+*/
+#define ME_DB_CONTACT_SETTINGCHANGED "DB/Contact/SettingChanged"
+
+/* DB/Contact/SetSettingResident service (0.6+)
+Disables a setting saving to the database.
+ wParam=(WPARAM)(BOOL)bIsResident
+ lParam=(LPARAM)(char*)pszSettingName
+*/
+#define MS_DB_SETSETTINGRESIDENT "DB/SetSettingResident"
+
+/******************************************************************/
+/********************* SETTINGS HELPER FUNCTIONS ******************/
+/******************************************************************/
+
+#ifndef DB_NOHELPERFUNCTIONS
+
+/* hate typing the fucking jinormous names of the db "helper" functions, ffs. */
+
+#define db_byte_get(a,b,c,d) DBGetContactSettingByte(a,b,c,d)
+#define db_word_get(a,b,c,d) DBGetContactSettingWord(a,b,c,d)
+#define db_dword_get(a,b,c,d) DBGetContactSettingDword(a,b,c,d)
+#define db_get(a,b,c,d) DBGetContactSetting(a,b,c,d)
+
+#define db_byte_set(a,b,c,d) DBWriteContactSettingByte(a,b,c,d);
+#define db_word_set(a,b,c,d) DBWriteContactSettingWord(a,b,c,d);
+#define db_dword_set(a,b,c,d) DBWriteContactSettingDword(a,b,c,d);
+#define db_string_set(a,b,c,d) DBWriteContactSettingString(a,b,c,d);
+
+#define db_unset(a,b,c) DBDeleteContactSetting(a,b,c);
+
+#define DBGetContactSettingByte(a,b,c,d) DBGetContactSettingByte_Helper(a,b,c,d,__FILE__,__LINE__)
+#define DBGetContactSettingWord(a,b,c,d) DBGetContactSettingWord_Helper(a,b,c,d,__FILE__,__LINE__)
+#define DBGetContactSettingDword(a,b,c,d) DBGetContactSettingDword_Helper(a,b,c,d,__FILE__,__LINE__)
+#define DBGetContactSetting(a,b,c,d) DBGetContactSetting_Helper(a,b,c,d,__FILE__,__LINE__)
+#define DBGetContactSettingW(a,b,c,d) DBGetContactSettingW_Helper(a,b,c,d,__FILE__,__LINE__)
+#define DBGetContactSettingTString(a,b,c,d) DBGetContactSettingTString_Helper(a,b,c,d,__FILE__,__LINE__)
+#define DBGetContactSettingWString(a,b,c,d) DBGetContactSettingWString_Helper(a,b,c,d,__FILE__,__LINE__)
+#define DBGetContactSettingStringUtf(a,b,c,d) DBGetContactSettingStringUtf_Helper(a,b,c,d,__FILE__,__LINE__)
+
+#define db_msg_dbg(s) MessageBoxA(0,(s),"",0);
+
+#ifdef _DEBUG
+#include <stdio.h>
+#endif
+
+__inline static int DBGetContactSettingByte_Helper(HANDLE hContact, const char *szModule,
+ const char *szSetting, int errorValue, const char *szFile, const int nLine)
+{
+ DBVARIANT dbv;
+ DBCONTACTGETSETTING cgs;
+
+ cgs.szModule=szModule;
+ cgs.szSetting=szSetting;
+ cgs.pValue=&dbv;
+ if(CallService(MS_DB_CONTACT_GETSETTING,(WPARAM)hContact,(LPARAM)&cgs))
+ return errorValue;
+#ifdef _DEBUG
+ if(dbv.type!=DBVT_BYTE) {
+ char buf[128];
+ _snprintf(buf,sizeof(buf),"%s:%d for %s/%s not a byte, return: %d",szFile,nLine,szModule,szSetting,dbv.type);
+ db_msg_dbg(buf);
+ }
+#endif
+ return dbv.bVal;
+}
+
+__inline static int DBGetContactSettingWord_Helper(HANDLE hContact,const char *szModule,
+ const char *szSetting,int errorValue,const char *szFile, const int nLine)
+{
+ DBVARIANT dbv;
+ DBCONTACTGETSETTING cgs;
+
+ cgs.szModule=szModule;
+ cgs.szSetting=szSetting;
+ cgs.pValue=&dbv;
+ if(CallService(MS_DB_CONTACT_GETSETTING,(WPARAM)hContact,(LPARAM)&cgs))
+ return errorValue;
+#ifdef _DEBUG
+ if(dbv.type!=DBVT_WORD) {
+ char buf[128];
+ _snprintf(buf,sizeof(buf),"%s:%d for %s/%s not a word, return: %d",szFile,nLine,szModule,szSetting,dbv.type);
+ db_msg_dbg(buf);
+ }
+#endif
+ return dbv.wVal;
+}
+
+__inline static DWORD DBGetContactSettingDword_Helper(HANDLE hContact,const char *szModule,
+ const char *szSetting,DWORD errorValue, const char *szFile, const int nLine)
+{
+ DBVARIANT dbv;
+ DBCONTACTGETSETTING cgs;
+
+ cgs.szModule=szModule;
+ cgs.szSetting=szSetting;
+ cgs.pValue=&dbv;
+ if(CallService(MS_DB_CONTACT_GETSETTING,(WPARAM)hContact,(LPARAM)&cgs))
+ return errorValue;
+#ifdef _DEBUG
+ if(dbv.type!=DBVT_DWORD) {
+ char buf[128];
+ _snprintf(buf,sizeof(buf),"%s:%d for %s/%s not a dword, return: %d",szFile,nLine,szModule,szSetting,dbv.type);
+ db_msg_dbg(buf);
+ }
+#endif
+ return dbv.dVal;
+}
+
+__inline static int DBGetContactSettingW_Helper(HANDLE hContact,const char *szModule,
+ const char *szSetting,DBVARIANT *dbv, const char *szFile, const int nLine)
+{
+ int rc;
+ DBCONTACTGETSETTING cgs;
+ cgs.szModule=szModule;
+ cgs.szSetting=szSetting;
+ cgs.pValue=dbv;
+ dbv->type = 0;
+
+ rc=CallService(MS_DB_CONTACT_GETSETTING_STR,(WPARAM)hContact,(LPARAM)&cgs);
+#if defined(_DEBUG) && defined(DBCHECKSETTINGS)
+ if (rc != 0) {
+ char buf[128];
+ _snprintf(buf,sizeof(buf),"%s:%d failed to fetch %s/%s",szFile,nLine,szModule,szSetting);
+ db_msg_dbg(buf);
+ }
+#endif
+ return rc;
+}
+
+__inline static int DBGetContactSettingTString_Helper(HANDLE hContact,const char *szModule,
+ const char *szSetting,DBVARIANT *dbv, const char *szFile, const int nLine)
+{
+ int rc;
+ DBCONTACTGETSETTING cgs;
+ cgs.szModule=szModule;
+ cgs.szSetting=szSetting;
+ cgs.pValue=dbv;
+#if defined(_UNICODE)
+ dbv->type = DBVT_WCHAR;
+#else
+ dbv->type = DBVT_ASCIIZ;
+#endif
+
+ rc=CallService(MS_DB_CONTACT_GETSETTING_STR,(WPARAM)hContact,(LPARAM)&cgs);
+#if defined(_DEBUG) && defined(DBCHECKSETTINGS)
+ if (rc != 0) {
+ char buf[128];
+ _snprintf(buf,sizeof(buf),"%s:%d failed to fetch %s/%s",szFile,nLine,szModule,szSetting);
+ db_msg_dbg(buf);
+ }
+#endif
+ return rc;
+}
+
+__inline static int DBGetContactSettingWString_Helper(HANDLE hContact,const char *szModule,
+ const char *szSetting,DBVARIANT *dbv, const char *szFile, const int nLine)
+{
+ int rc;
+ DBCONTACTGETSETTING cgs;
+ cgs.szModule=szModule;
+ cgs.szSetting=szSetting;
+ cgs.pValue=dbv;
+ dbv->type = DBVT_WCHAR;
+
+ rc=CallService(MS_DB_CONTACT_GETSETTING_STR,(WPARAM)hContact,(LPARAM)&cgs);
+#if defined(_DEBUG) && defined(DBCHECKSETTINGS)
+ if (rc != 0) {
+ char buf[128];
+ _snprintf(buf,sizeof(buf),"%s:%d failed to fetch %s/%s",szFile,nLine,szModule,szSetting);
+ db_msg_dbg(buf);
+ }
+#endif
+ return rc;
+}
+
+__inline static int DBGetContactSettingStringUtf_Helper(HANDLE hContact,const char *szModule,
+ const char *szSetting,DBVARIANT *dbv, const char *szFile, const int nLine)
+{
+ int rc;
+ DBCONTACTGETSETTING cgs;
+ cgs.szModule=szModule;
+ cgs.szSetting=szSetting;
+ cgs.pValue=dbv;
+ dbv->type = DBVT_UTF8;
+
+ rc=CallService(MS_DB_CONTACT_GETSETTING_STR,(WPARAM)hContact,(LPARAM)&cgs);
+#if defined(_DEBUG) && defined(DBCHECKSETTINGS)
+ if (rc != 0) {
+ char buf[128];
+ _snprintf(buf,sizeof(buf),"%s:%d failed to fetch %s/%s",szFile,nLine,szModule,szSetting);
+ db_msg_dbg(buf);
+ }
+#endif
+ return rc;
+}
+
+__inline static int DBGetContactSetting_Helper(HANDLE hContact,const char *szModule,
+ const char *szSetting,DBVARIANT *dbv, const char *szFile, const int nLine)
+{
+ int rc;
+ DBCONTACTGETSETTING cgs;
+ cgs.szModule=szModule;
+ cgs.szSetting=szSetting;
+ cgs.pValue=dbv;
+ rc=CallService(MS_DB_CONTACT_GETSETTING,(WPARAM)hContact,(LPARAM)&cgs);
+#if defined(_DEBUG) && defined(DBCHECKSETTINGS)
+ if (rc != 0) {
+ char buf[128];
+ _snprintf(buf,sizeof(buf),"%s:%d failed to fetch %s/%s",szFile,nLine,szModule,szSetting);
+ db_msg_dbg(buf);
+ }
+#endif
+ return rc;
+}
+
+__inline static int DBFreeVariant(DBVARIANT *dbv)
+{
+ return CallService(MS_DB_CONTACT_FREEVARIANT,0,(LPARAM)dbv);
+}
+
+__inline static int DBDeleteContactSetting(HANDLE hContact,const char *szModule,const char *szSetting)
+{
+ DBCONTACTGETSETTING cgs;
+ cgs.szModule=szModule;
+ cgs.szSetting=szSetting;
+ return CallService(MS_DB_CONTACT_DELETESETTING,(WPARAM)hContact,(LPARAM)&cgs);
+}
+
+__inline static int DBWriteContactSettingByte(HANDLE hContact,const char *szModule,const char *szSetting,BYTE val)
+{
+ DBCONTACTWRITESETTING cws;
+
+ cws.szModule=szModule;
+ cws.szSetting=szSetting;
+ cws.value.type=DBVT_BYTE;
+ cws.value.bVal=val;
+ return CallService(MS_DB_CONTACT_WRITESETTING,(WPARAM)hContact,(LPARAM)&cws);
+}
+
+__inline static int DBWriteContactSettingWord(HANDLE hContact,const char *szModule,const char *szSetting,WORD val)
+{
+ DBCONTACTWRITESETTING cws;
+
+ cws.szModule=szModule;
+ cws.szSetting=szSetting;
+ cws.value.type=DBVT_WORD;
+ cws.value.wVal=val;
+ return CallService(MS_DB_CONTACT_WRITESETTING,(WPARAM)hContact,(LPARAM)&cws);
+}
+
+__inline static int DBWriteContactSettingDword(HANDLE hContact,const char *szModule,const char *szSetting,DWORD val)
+{
+ DBCONTACTWRITESETTING cws;
+
+ cws.szModule=szModule;
+ cws.szSetting=szSetting;
+ cws.value.type=DBVT_DWORD;
+ cws.value.dVal=val;
+ return CallService(MS_DB_CONTACT_WRITESETTING,(WPARAM)hContact,(LPARAM)&cws);
+}
+
+__inline static int DBWriteContactSettingString(HANDLE hContact,const char *szModule,const char *szSetting,const char *val)
+{
+ DBCONTACTWRITESETTING cws;
+
+ cws.szModule=szModule;
+ cws.szSetting=szSetting;
+ cws.value.type=DBVT_ASCIIZ;
+ cws.value.pszVal=(char*)val;
+ return CallService(MS_DB_CONTACT_WRITESETTING,(WPARAM)hContact,(LPARAM)&cws);
+}
+
+__inline static int DBWriteContactSettingTString(HANDLE hContact,const char *szModule,const char *szSetting,const TCHAR *val)
+{
+ DBCONTACTWRITESETTING cws;
+
+ cws.szModule=szModule;
+ cws.szSetting=szSetting;
+ #if defined( _UNICODE )
+ cws.value.type=DBVT_WCHAR;
+ cws.value.pwszVal=(WCHAR*)val;
+ #else
+ cws.value.type=DBVT_ASCIIZ;
+ cws.value.pszVal=(char*)val;
+ #endif
+ return CallService(MS_DB_CONTACT_WRITESETTING,(WPARAM)hContact,(LPARAM)&cws);
+}
+
+__inline static int DBWriteContactSettingWString(HANDLE hContact,const char *szModule,const char *szSetting,const WCHAR *val)
+{
+ DBCONTACTWRITESETTING cws;
+
+ cws.szModule=szModule;
+ cws.szSetting=szSetting;
+ cws.value.type=DBVT_WCHAR;
+ cws.value.pwszVal=(WCHAR*)val;
+ return CallService(MS_DB_CONTACT_WRITESETTING,(WPARAM)hContact,(LPARAM)&cws);
+}
+
+__inline static int DBWriteContactSettingStringUtf(HANDLE hContact,const char *szModule,const char *szSetting,const char *val)
+{
+ DBCONTACTWRITESETTING cws;
+
+ cws.szModule=szModule;
+ cws.szSetting=szSetting;
+ cws.value.type=DBVT_UTF8;
+ cws.value.pszVal=(char*)val;
+ return CallService(MS_DB_CONTACT_WRITESETTING,(WPARAM)hContact,(LPARAM)&cws);
+}
+
+/* inlined range tolerate versions */
+
+__inline static BYTE DBGetContactSettingRangedByte(HANDLE hContact, const char *szModule, const char *szSetting, BYTE errorValue, BYTE minValue, BYTE maxValue) {
+ BYTE bVal = DBGetContactSettingByte(hContact, szModule, szSetting, errorValue);
+
+ if (bVal < minValue || bVal > maxValue) {
+#ifdef _DEBUG
+ char szBuf[MAX_PATH];
+ wsprintfA(szBuf, "(%s:%s) not in range of %d..%d", szModule,szSetting,minValue,maxValue);
+ MessageBoxA(0,szBuf,"DBGetContactSettingRangedByte failed",MB_ICONERROR);
+#endif
+ return errorValue;
+ }
+ else
+ return bVal;
+}
+
+__inline static WORD DBGetContactSettingRangedWord(HANDLE hContact, const char *szModule, const char *szSetting, WORD errorValue, WORD minValue, WORD maxValue) {
+ WORD wVal = DBGetContactSettingWord(hContact, szModule, szSetting, errorValue);
+
+ if (wVal < minValue || wVal > maxValue) {
+#ifdef _DEBUG
+ char szBuf[MAX_PATH];
+ wsprintfA(szBuf, "(%s:%s) not in range of %d..%d", szModule,szSetting,minValue,maxValue);
+ MessageBoxA(0,szBuf,"DBGetContactSettingRangedWord failed",MB_ICONERROR);
+#endif
+ return errorValue;
+ }
+ else
+ return wVal;
+}
+
+__inline static DWORD DBGetContactSettingRangedDword(HANDLE hContact, const char *szModule, const char *szSetting, DWORD errorValue, DWORD minValue, DWORD maxValue) {
+ DWORD dVal = DBGetContactSettingDword(hContact, szModule, szSetting, errorValue);
+
+ if (dVal < minValue || dVal > maxValue) {
+#ifdef _DEBUG
+ char szBuf[MAX_PATH];
+ wsprintfA(szBuf, "(%s:%s) not in range of %d..%d", szModule,szSetting,minValue,maxValue);
+ MessageBoxA(0,szBuf,"DBGetContactSettingRangedDword failed",MB_ICONERROR);
+#endif
+ return errorValue;
+ }
+ else
+ return dVal;
+}
+
+#endif
+
+#endif // M_DATABASE_H__
diff --git a/miranda-wine/include/m_email.h b/miranda-wine/include/m_email.h
new file mode 100644
index 0000000..93f515b
--- /dev/null
+++ b/miranda-wine/include/m_email.h
@@ -0,0 +1,36 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_EMAIL_H__
+#define M_EMAIL_H__ 1
+
+//send an e-mail to the specified contact v0.1.0.1+
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=0
+//returns 0 on success or nonzero on failure
+//if an error occurs the service will display a message box with the error
+//text, so this service should not be used if you do not want this behaviour.
+#define MS_EMAIL_SENDEMAIL "SREMail/SendCommand"
+
+#endif // M_EMAIL_H__
+
diff --git a/miranda-wine/include/m_file.h b/miranda-wine/include/m_file.h
new file mode 100644
index 0000000..e0d6136
--- /dev/null
+++ b/miranda-wine/include/m_file.h
@@ -0,0 +1,62 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_FILE_H__
+#define M_FILE_H__ 1
+
+//brings up the send file dialog for a contact
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=0
+//returns 0 on success or nonzero on failure
+//returns immediately, without waiting for the send
+#define MS_FILE_SENDFILE "SRFile/SendCommand"
+
+//brings up the send file dialog with the specified files already chosen
+//v0.1.2.1+
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=(LPARAM)(const char**)ppFiles
+//returns 0 on success or nonzero on failure
+//returns immediately, without waiting for the send
+//the user is not prevented from changing the filename with the 'choose again'
+//button
+//ppFiles is a NULL-terminated array of fully qualified filenames.
+//To send subdirectories, include their name in the list without a trailing
+//backslash. In order to keep contained files in their correct place on
+//receiving, the subdirectory they're in must preceed the file. This applies
+//to subdirectories themselves too: they must be preceeded by their container
+//if you want to send the container and keep the original directory inside it.
+#define MS_FILE_SENDSPECIFICFILES "SRFile/SendSpecificFiles"
+
+//get the received files folder v0.1.2.2+
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=(LPARAM)(char *)pszOutput
+//returns 0 on success or nonzero on failure
+//pszOutput must be at least MAX_PATH characters long
+//If hContact is NULL this function will retrieve the received files folder
+//name without any appended user names.
+//Note that the directory name returned by this function does not necessarily
+//exist.
+#define MS_FILE_GETRECEIVEDFILESFOLDER "SRFile/GetReceivedFilesFolder"
+
+#endif // M_FILE_H__
+
diff --git a/miranda-wine/include/m_findadd.h b/miranda-wine/include/m_findadd.h
new file mode 100644
index 0000000..9cc61c2
--- /dev/null
+++ b/miranda-wine/include/m_findadd.h
@@ -0,0 +1,35 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_FINDADD_H__
+#define M_FINDADD_H__ 1
+
+/* Opens the find/add users dialog box, or gives it the focus if it's already
+open.
+wParam=lParam=0
+returns 0 always
+*/
+#define MS_FINDADD_FINDADD "FindAdd/FindAddCommand"
+
+#endif // M_FINDADD_H__
+
diff --git a/miranda-wine/include/m_fuse.h b/miranda-wine/include/m_fuse.h
new file mode 100644
index 0000000..71ac3fe
--- /dev/null
+++ b/miranda-wine/include/m_fuse.h
@@ -0,0 +1,32 @@
+#ifdef _ALPHA_FUSE_
+#ifndef _M_FUSE_
+#define _M_FUSE_
+
+#define CALLSERVICE_NOTFOUND ((int)0x80000000)
+#define MAXMODULELABELLENGTH 64
+typedef int (*MIRANDAHOOK)(WPARAM,LPARAM);
+typedef int (*MIRANDASERVICE)(WPARAM,LPARAM);
+
+#define FUSE_INIT 0 // core started, Param=**FUSE_LINK
+#define FUSE_DEINIT 1 // core stopped
+#define FUSE_DEFMOD 3 // LoadDefaultModules() return code, Param=*int
+#define FUSE_DEATH 4 // DestroyingModularEngine() just got called
+
+typedef struct {
+ int cbSize;
+ HANDLE (*CreateHookableEvent)(const char *);
+ int (*DestroyHookableEvent)(HANDLE);
+ int (*NotifyEventHooks)(HANDLE,WPARAM,LPARAM);
+ HANDLE (*HookEvent)(const char *,MIRANDAHOOK);
+ HANDLE (*HookEventMessage)(const char *,HWND,UINT);
+ int (*UnhookEvent)(HANDLE);
+ HANDLE (*CreateServiceFunction)(const char *,MIRANDASERVICE);
+ HANDLE (*CreateTransientServiceFunction)(const char *,MIRANDASERVICE);
+ int (*DestroyServiceFunction)(HANDLE);
+ int (*CallService)(const char *,WPARAM,LPARAM);
+ int (*ServiceExists)(const char *); //v0.1.0.1+
+ int (*CallServiceSync)(const char*,WPARAM,LPARAM); //v0.1.2.2+
+} FUSE_LINK;
+
+#endif
+#endif \ No newline at end of file
diff --git a/miranda-wine/include/m_history.h b/miranda-wine/include/m_history.h
new file mode 100644
index 0000000..3061b45
--- /dev/null
+++ b/miranda-wine/include/m_history.h
@@ -0,0 +1,34 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_HISTORY_H__
+#define M_HISTORY_H__ 1
+
+//show the History dialog box for a contact
+// wParam=(WPARAM)(HANDLE)hContact
+// lParam=0
+//hContact can be NULL to show system messages
+#define MS_HISTORY_SHOWCONTACTHISTORY "History/ShowContactHistory"
+
+#endif // M_HISTORY_H__
+
diff --git a/miranda-wine/include/m_icq.h b/miranda-wine/include/m_icq.h
new file mode 100644
index 0000000..d43c445
--- /dev/null
+++ b/miranda-wine/include/m_icq.h
@@ -0,0 +1,298 @@
+// ---------------------------------------------------------------------------80
+// ICQ plugin 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: 3485 $
+// Last change on : $Date: 2006-08-13 20:00:08 +0400 (Ð’Ñк, 13 Ðвг 2006) $
+// Last change by : $Author: jokusoftware $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#ifndef M_ICQ_H__
+#define M_ICQ_H__ 1
+
+
+// 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"
+
+#endif // M_ICQ_H__
diff --git a/miranda-wine/include/m_idle.h b/miranda-wine/include/m_idle.h
new file mode 100644
index 0000000..390cb6c
--- /dev/null
+++ b/miranda-wine/include/m_idle.h
@@ -0,0 +1,72 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2005 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_IDLE_H__
+#define M_IDLE_H__ 1
+
+/* The idle module checks how long the user has been idle, it can be at the Miranda level
+or the OS level - the user has optional two settings, one for "short" idle and another
+for "long" idle. Thie module will generate long/short events based on these user preferences
+and other information too. If you are unsure which idle mode to report for, report it
+for short idle.*/
+
+#define IDF_ISIDLE 0x1 // idle has become active (if not set, inactive)
+#define IDF_PRIVACY 0x8 // if set, the information provided shouldn't be given to third parties.
+
+/*
+ wParam: 0
+ lParam: IDF_* (or'd field)
+ Affect: This event is fired when information about idle changes.
+ Note: You will get multiple calls with IDF_ISIDLE set, the first is for short idle
+ then long idle, then anytime during you might get IDF_ONFORCE if the screensaver or station
+ become locked.
+
+ It is up to you to keep state, i.e. once the idle that you care about is reported
+ ignore other status notifications with IDF_ISIDLE set until you get one with IDF_ISIDLE isn't
+ set.
+ Version: 0.3.4a+ (2004/09/16)
+*/
+#define ME_IDLE_CHANGED "Miranda/Idle/Changed"
+
+
+typedef struct {
+ int cbSize; // sizeof()
+ unsigned int idleTime; // idle in mins, if zero then disabled
+ int privacy; // user doesnt want other people seeing anything more than they are idle
+ int aaStatus; // status to go to when user is auto away
+ int aaLock; // the status shouldn't be unset if its set
+} MIRANDA_IDLE_INFO;
+
+/*
+ wParam; 0
+ lParam: &MIRANDA_IDLE_INFO
+ Affect: Return information about current idle settings, like short/long idle time in mins
+ and if the user wants that info kept private, etc
+ Returns: zero on success, non zero on failure
+ Version: 0.3.4 (2004/09/16)
+*/
+
+#define MS_IDLE_GETIDLEINFO "Miranda/Idle/GetInfo"
+
+#endif // M_IDLE_H__
+
diff --git a/miranda-wine/include/m_ignore.h b/miranda-wine/include/m_ignore.h
new file mode 100644
index 0000000..b300c6c
--- /dev/null
+++ b/miranda-wine/include/m_ignore.h
@@ -0,0 +1,63 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_IGNORE_H__
+#define M_IGNORE_H__ 1
+
+//this module provides UI and storage for blocking only, protocol modules are
+//responsible for implementing the block
+
+#define IGNOREEVENT_ALL (LPARAM)(-1)
+#define IGNOREEVENT_MESSAGE 1
+#define IGNOREEVENT_URL 2
+#define IGNOREEVENT_FILE 3
+#define IGNOREEVENT_USERONLINE 4
+#define IGNOREEVENT_AUTHORIZATION 5
+#define IGNOREEVENT_YOUWEREADDED 6 // 0.3.3a+
+
+//determines if a message type to a contact should be ignored v0.1.0.1+
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=message type, an ignoreevent_ constant
+//returns 0 if the message should be shown, or nonzero if it should be ignored
+//Use hContact=NULL to retrieve the setting for unknown contacts (not on the
+//contact list, as either permanent or temporary).
+//don't use ignoreevent_all when calling this service
+#define MS_IGNORE_ISIGNORED "Ignore/IsIgnored"
+
+//ignore future messages from a contact v0.1.0.1+
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=message type, an ignoreevent_ constant
+//returns 0 on success or nonzero on failure
+//Use hContact=NULL to retrieve the setting for unknown contacts
+#define MS_IGNORE_IGNORE "Ignore/Ignore"
+
+//receive future messages from a contact v0.1.0.1+
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=message type, an ignoreevent_ constant
+//returns 0 on success or nonzero on failure
+//Use hContact=NULL to retrieve the setting for unknown contacts
+#define MS_IGNORE_UNIGNORE "Ignore/Unignore"
+
+
+#endif // M_IGNORE_H__
+
diff --git a/miranda-wine/include/m_langpack.h b/miranda-wine/include/m_langpack.h
new file mode 100644
index 0000000..ac36940
--- /dev/null
+++ b/miranda-wine/include/m_langpack.h
@@ -0,0 +1,101 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_LANGPACK_H__
+#define M_LANGPACK_H__
+
+#define LANG_UNICODE 0x1000
+
+//translates a single string into the user's local language v0.1.1.0+
+//wParam=0
+//lParam=(LPARAM)(const char*)szEnglish
+//returns a pointer to the localised string. If there is no known translation
+//it will return szEnglish. The return value does not need to be freed in any
+//way
+//Note that the Translate() macro as defined below will crash plugins that are
+//loaded into Miranda 0.1.0.1 and earlier. If anyone's actually using one of
+//these versions, I pity them.
+#define MS_LANGPACK_TRANSLATESTRING "LangPack/TranslateString"
+#define Translate(s) ((char*)CallService(MS_LANGPACK_TRANSLATESTRING,0,(LPARAM)(s)))
+#define TranslateW(s) ((WCHAR*)CallService(MS_LANGPACK_TRANSLATESTRING,LANG_UNICODE,(LPARAM)(s)))
+#if defined( _UNICODE )
+ #define TranslateT(s) TranslateW(_T(s))
+ #define TranslateTS(s) TranslateW(s)
+#else
+ #define TranslateT(s) Translate(s)
+ #define TranslateTS(s) Translate(s)
+#endif
+
+//translates a dialog into the user's local language v0.1.1.0+
+//wParam=0
+//lParam=(LPARAM)(LANGPACKTRANSLATEDIALOG*)&lptd
+//returns 0 on success, nonzero on failure
+//This service only knows about the following controls:
+//Window titles, STATIC, EDIT, Hyperlink, BUTTON
+typedef struct {
+ int cbSize;
+ DWORD flags;
+ HWND hwndDlg;
+ const int *ignoreControls; //zero-terminated list of control IDs *not* to
+ //translate
+} LANGPACKTRANSLATEDIALOG;
+#define LPTDF_NOIGNOREEDIT 1 //translate all edit controls. By default
+ //non-read-only edit controls are not translated
+#define LPTDF_NOTITLE 2 //do not translate the title of the dialog
+
+#define MS_LANGPACK_TRANSLATEDIALOG "LangPack/TranslateDialog"
+__inline static int TranslateDialogDefault(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);
+}
+
+//translates a menu into the user's local language v0.1.1.0+
+//wParam=(WPARAM)(HMENU)hMenu
+//lParam=0
+//returns 0 on success, nonzero on failure
+#define MS_LANGPACK_TRANSLATEMENU "LangPack/TranslateMenu"
+
+//returns the codepage used in the language pack v0.4.3.0+
+//wParam=0
+//lParam=0
+//returns the codepage stated in the langpack, or CP_ACP if no langpack is present
+#define MS_LANGPACK_GETCODEPAGE "LangPack/GetCodePage"
+
+//returns the locale id associated with the language pack v0.4.3.0+
+//wParam=0
+//lParam=0
+//returns the Windows locale id stated in the langpack, or LOCALE_USER_DEFAULT if no langpack is present
+#define MS_LANGPACK_GETLOCALE "LangPack/GetLocale"
+
+//returns the strdup/wcsdup of lparam according to the langpack v0.4.3.0+
+//wParam=0
+//lParam=(LPARAM)(char*)source string
+//returns a string converted from char* to TCHAR* using the langpack codepage.
+//This string should be freed using mir_free() then
+#define MS_LANGPACK_PCHARTOTCHAR "LangPack/PcharToTchar"
+#endif // M_LANGPACK_H__
diff --git a/miranda-wine/include/m_message.h b/miranda-wine/include/m_message.h
new file mode 100644
index 0000000..b5191b9
--- /dev/null
+++ b/miranda-wine/include/m_message.h
@@ -0,0 +1,100 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_MESSAGE_H__
+#define M_MESSAGE_H__ 1
+
+//brings up the send message dialog for a contact
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=(LPARAM)(char*)szText
+//returns 0 on success or nonzero on failure
+//returns immediately, just after the dialog is shown
+//szText is the text to put in the edit box of the window (but not send)
+//szText=NULL will not use any text
+//szText!=NULL is only supported on v0.1.2.0+
+//NB: Current versions of the convers plugin use the name
+//"SRMsg/LaunchMessageWindow" instead. For compatibility you should call
+//both names and the correct one will work.
+#define MS_MSG_SENDMESSAGE "SRMsg/SendCommand"
+
+#define ME_MSG_WINDOWEVENT "MessageAPI/WindowEvent"
+//wparam=0
+//lparam=(WPARAM)(MessageWindowEventData*)hWindowEvent;
+//Event types
+#define MSG_WINDOW_EVT_OPENING 1 //window is about to be opened
+#define MSG_WINDOW_EVT_OPEN 2 //window has been opened
+#define MSG_WINDOW_EVT_CLOSING 3 //window is about to be closed
+#define MSG_WINDOW_EVT_CLOSE 4 //window has been closed
+#define MSG_WINDOW_EVT_CUSTOM 5 //custom event for message plugins to use (custom uFlags may be used)
+
+#define MSG_WINDOW_UFLAG_MSG_FROM 0x00000001
+#define MSG_WINDOW_UFLAG_MSG_TO 0x00000002
+#define MSG_WINDOW_UFLAG_MSG_BOTH 0x00000004
+
+typedef struct {
+ int cbSize;
+ HANDLE hContact;
+ HWND hwndWindow; // top level window for the contact
+ const char* szModule; // used to get plugin type (which means you could use local if needed)
+ unsigned int uType; // see event types above
+ unsigned int uFlags; // used to indicate message direction for all event types except custom
+ void *local; // used to store pointer to custom data
+} MessageWindowEventData;
+
+#define MS_MSG_GETWINDOWAPI "MessageAPI/WindowAPI"
+//wparam=0
+//lparam=0
+//Returns a dword with the current message api version
+//Current version is 0,0,0,3
+
+#define MS_MSG_GETWINDOWCLASS "MessageAPI/WindowClass"
+//wparam=(char*)szBuf
+//lparam=(int)cbSize size of buffer
+//Sets the window class name in wParam (ex. "SRMM" for srmm.dll)
+
+typedef struct {
+ int cbSize;
+ HANDLE hContact;
+ int uFlags; // see uflags above
+} MessageWindowInputData;
+
+#define MSG_WINDOW_STATE_EXISTS 0x00000001 // Window exists should always be true if hwndWindow exists
+#define MSG_WINDOW_STATE_VISIBLE 0x00000002
+#define MSG_WINDOW_STATE_FOCUS 0x00000004
+#define MSG_WINDOW_STATE_ICONIC 0x00000008
+
+typedef struct {
+ int cbSize;
+ HANDLE hContact;
+ int uFlags; // should be same as input data unless 0, then it will be the actual type
+ HWND hwndWindow; //top level window for the contact or NULL if no window exists
+ int uState; // see window states
+ void *local; // used to store pointer to custom data
+} MessageWindowData;
+
+#define MS_MSG_GETWINDOWDATA "MessageAPI/GetWindowData"
+//wparam=(MessageWindowInputData*)
+//lparam=(MessageWindowData*)
+//returns 0 on success and returns non-zero (1) on error or if no window data exists for that hcontact
+#endif // M_MESSAGE_H__
+
diff --git a/miranda-wine/include/m_netlib.h b/miranda-wine/include/m_netlib.h
new file mode 100644
index 0000000..8ee4c92
--- /dev/null
+++ b/miranda-wine/include/m_netlib.h
@@ -0,0 +1,748 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_NETLIB_H__
+#define M_NETLIB_H__ 1
+
+#include "m_utils.h"
+
+//this module was created in 0.1.2.2
+//All error codes are returned via GetLastError() (or WSAGetLastError():
+//they're the same).
+//This module is thread-safe where it is sensible for it to be so. This
+//basically means that you can call anything from any thread, but don't try
+//to predict what will happen if you try to recv() on the same connection from
+//two different threads at the same time.
+//Note that because the vast majority of the routines in this module return
+//a pointer, I have decided to diverge from the rest of Miranda and go with
+//the convention that functions return false on failure and nonzero on success.
+
+struct NETLIBHTTPREQUEST_tag;
+typedef struct NETLIBHTTPREQUEST_tag NETLIBHTTPREQUEST;
+struct NETLIBOPENCONNECTION_tag;
+typedef struct NETLIBOPENCONNECTION_tag NETLIBOPENCONNECTION;
+
+//Initialises the netlib for a set of connections
+//wParam=0
+//lParam=(LPARAM)(NETLIBUSER*)&nu
+//Returns a HANDLE to be used for future netlib calls, NULL on failure
+//NOTE: Netlib is loaded after any plugins, so you need to wait until
+// ME_SYSTEM_MODULESLOADED before calling this function
+//Netlib settings are stored under the module szSettingsModule
+//All netlib settings being with "NL".
+//The default settings for registered users that don't have any settings stored
+//in the database are the same as those displayed by the <All connections> page
+//of the netlib options page.
+//See notes below this function for the behaviour of HTTP gateways
+//Errors: ERROR_INVALID_PARAMETER, ERROR_OUTOFMEMORY, ERROR_DUP_NAME
+typedef int (*NETLIBHTTPGATEWAYINITPROC)(HANDLE hConn,NETLIBOPENCONNECTION *nloc,NETLIBHTTPREQUEST *nlhr);
+typedef int (*NETLIBHTTPGATEWAYBEGINPROC)(HANDLE hConn,NETLIBOPENCONNECTION *nloc);
+typedef int (*NETLIBHTTPGATEWAYWRAPSENDPROC)(HANDLE hConn,PBYTE buf,int len,int flags,MIRANDASERVICE pfnNetlibSend);
+typedef PBYTE (*NETLIBHTTPGATEWAYUNWRAPRECVPROC)(NETLIBHTTPREQUEST *nlhr,PBYTE buf,int len,int *outBufLen,void *(*NetlibRealloc)(void*,size_t));
+typedef struct {
+ int cbSize;
+ char *szSettingsModule; //used for db settings and log
+ char *szDescriptiveName; //used in options dialog, already translated
+ DWORD flags;
+ char *szHttpGatewayHello;
+ char *szHttpGatewayUserAgent; //can be NULL to send no user-agent, also used by HTTPS proxies
+ NETLIBHTTPGATEWAYINITPROC pfnHttpGatewayInit;
+ NETLIBHTTPGATEWAYBEGINPROC pfnHttpGatewayBegin; //can be NULL if no beginning required
+ NETLIBHTTPGATEWAYWRAPSENDPROC pfnHttpGatewayWrapSend; //can be NULL if no wrapping required
+ NETLIBHTTPGATEWAYUNWRAPRECVPROC pfnHttpGatewayUnwrapRecv; //can be NULL if no wrapping required
+ int minIncomingPorts; //only if NUF_INCOMING. Will be used for validation of user input.
+} NETLIBUSER;
+#define NUF_INCOMING 0x01 //binds incoming ports
+#define NUF_OUTGOING 0x02 //makes outgoing plain connections
+#define NUF_HTTPGATEWAY 0x04 //can use HTTP gateway for plain sockets. ???HttpGateway* are valid. Enables the HTTP proxy option in options.
+#define NUF_NOOPTIONS 0x08 //don't create an options page for this. szDescriptiveName is never used.
+#define NUF_HTTPCONNS 0x10 //at least some connections are made for HTTP communication. Enables the HTTP proxy option in options.
+#define NUF_NOHTTPSOPTION 0x20 //disable the HTTPS proxy option in options. Use this if all communication is HTTP.
+#define MS_NETLIB_REGISTERUSER "Netlib/RegisterUser"
+
+//Assign a Netlib user handle a set of dynamic HTTP headers to be used with all
+//
+//HTTP connections that enable the HTTP-use-sticky headers flag.
+//The headers persist until cleared with lParam=NULL.
+//
+//All memory should be allocated by the caller using malloc() from MS_SYSTEM_GET_MMI
+//Once it has passed to Netlib, Netlib is the owner of it, the caller should not refer to the memory
+//In any way after this point.
+//
+//wParam=(WPARAM)hNetLibUser
+//lParam=(LPARAM)(char*)szHeaders
+//
+//NOTE: The szHeaders parameter should be a NULL terminated string following the HTTP header syntax.
+//This string will be injected verbatim, thus the user should be aware of setting strings that are not
+//headers. This service is NOT THREAD SAFE, only a single thread is expected to set the headers and a single
+//thread reading the pointer internally, stopping race conditions and mutual exclusion don't happen.
+//
+//Version 0.3.2a+ (2003/10/27)
+//
+#define MS_NETLIB_SETSTICKYHEADERS "Netlib/SetStickyHeaders"
+
+/* Notes on HTTP gateway usage
+When a connection is initiated through an HTTP proxy using
+MS_NETLIB_OPENCONNECTION, netlib will GET nlu.szHttpGatewayHello and read
+the replied headers. Once this succeeds nlu.pfnHttpGatewayInit will be called
+with a valid handle to the connection, the NETLIBOPENCONNECTION structure that
+MS_NETLIB_OPENCONNECTION was called with, and the replied HTTP headers as its
+parameters. This function is responsible for recving and parsing the data then
+calling MS_NETLIB_SETHTTPPROXYINFO with the appropriate information.
+nlu.pfnHttpGatewayInit should return nonzero on success. If it returns zero
+then the entire connection attempt will return signalling failure. If your
+function needs to return an error code it can do so via SetLastError().
+If nlu.pfnHttpGatewayInit returns success without having called
+MS_NETLIB_SETHTTPPROXYINFO then the connection attempt will fail anyway.
+If you need more fine-tuned control over the GET/POST URLs than just appending
+sequence numbers you can call MS_NETLIB_SETHTTPPROXYINFO from within your
+wrap/unwrap functions (see below).
+
+Just prior to MS_NETLIB_OPENCONNECTION returning nlu.pfnHttpGatewayBegin is
+called with the handle to the connection and the NETLIBOPENCONNECTION structure
+as its parameters. This is for gateways that need special non-protocol
+initialisation. If you do send any packets in this function, you probably want
+to remember to use the MSG_NOHTTPGATEWAYWRAP flag. This function pointer can be
+NULL if this functionality isn't needed. This function must return nonzero on
+success. If it fails the connect attempt will return failure without changing
+LastError.
+
+Whenever MS_NETLIB_SEND is called on a connection through an HTTP proxy and
+the MSG_NOHTTPGATEWAYWRAP flags is not set and nlu.pfnHttpGatewayWrapSend is
+not NULL, nlu.pfnHttpGatewayWrapSend will be called *instead* of sending the
+data. It is this function's responsibility to wrap the sending data
+appropriately for transmission and call pfnNetlibSend to send it again.
+The flags parameter to nlu.pfnHttpGatewayWrapSend should be passed straight
+through to the pfnNetlibSend call. It has already been ORed with
+MSG_NOHTTPGATEWAYWRAP. nlu.pfnHttpGatewayWrapSend should return the a
+number of the same type as MS_NETLIB_SEND, ie the number of bytes sent or
+SOCKET_ERROR. The number of wrapping bytes should be subtracted so that the
+return value appears as if the proxy wasn't there.
+pfnNetlibSend() is identical to CallService(MS_NETLIB_SEND,...) but it's
+quicker to call using this pointer than to do the CallService() lookup again.
+
+Whenever an HTTP reply is received inside MS_NETLIB_RECV the headers and data
+are read into memory. If the headers indicate success then the data is passed
+to nlu.pfnHttpGatewayUnwrapRecv (if it's non-NULL) for processing. This
+function should remove (and do other processing if necessary) all HTTP proxy
+specific headers and return a pointer to the buffer whose size is returned in
+*outBufLen. If the buffer needs to be resized then NetlibRealloc() should be
+used for that purpose, *not* your own CRT's realloc(). NetlibRealloc() behaves
+identically to realloc() so it's possible to free the original buffer and
+create a new one if that's the most sensible way to write your parser.
+If errors are encountered you should SetLastError() and return NULL;
+MS_NETLIB_RECV will return SOCKET_ERROR. If the passed buffer unwraps to
+contain no actual data you should set *outBufLen to 0 but make sure you return
+some non-NULL buffer that can be freed.
+
+When you call MS_NETLIB_SEND or MS_NETLIB_RECV from any of these functions, you
+should use the MSG_DUMPPROXY flag so that the logging is neat.
+*/
+
+//Gets the user-configured settings for a netlib user
+//wParam=(WPARAM)(HANDLE)hUser
+//lParam=(LPARAM)(NETLIBUSERSETTINGS*)&nlus
+//Returns nonzero on success, 0 on failure (!! this is different to most of the rest of Miranda, but consistent with netlib)
+//The pointers referred to in the returned struct will remain valid until
+//the hUser handle is closed, or until the user changes the settings in the
+//options page, so it's best not to rely on them for too long.
+//Errors: ERROR_INVALID_PARAMETER
+#define PROXYTYPE_SOCKS4 1
+#define PROXYTYPE_SOCKS5 2
+#define PROXYTYPE_HTTP 3
+#define PROXYTYPE_HTTPS 4
+typedef struct {
+ int cbSize; //to be filled in before calling
+ int useProxy; //1 or 0
+ int proxyType; //a PROXYTYPE_
+ char *szProxyServer; //can be NULL
+ int wProxyPort; //host byte order
+ int useProxyAuth; //1 or 0. Always 0 for SOCKS4
+ char *szProxyAuthUser; //can be NULL, always used by SOCKS4
+ char *szProxyAuthPassword; //can be NULL
+ int useProxyAuthNtlm; //1 or 0, only used by HTTP, HTTPS
+ int dnsThroughProxy; //1 or 0
+ int specifyIncomingPorts; //1 or 0
+ char *szIncomingPorts; //can be NULL. Of form "1024-1050,1060-1070,2000"
+ int specifyOutgoingPorts; // 0.3.3a+
+ char *szOutgoingPorts; // 0.3.3a+
+} NETLIBUSERSETTINGS;
+#define MS_NETLIB_GETUSERSETTINGS "Netlib/GetUserSettings"
+
+//Changes the user-configurable settings for a netlib user
+//wParam=(WPARAM)(HANDLE)hUser
+//lParam=(LPARAM)(NETLIBUSERSETTINGS*)&nlus
+//Returns nonzero on success, 0 on failure (!! this is different to most of the rest of Miranda, but consistent with netlib)
+//This function is only really useful for people that specify NUF_NOOPTIONS
+//and want to create their own options.
+//Even if a setting is not active (eg szProxyAuthPassword when useProxyAuth is
+//zero) that settings is still set for use in the options dialog.
+//Errors: ERROR_INVALID_PARAMETER
+#define MS_NETLIB_SETUSERSETTINGS "Netlib/SetUserSettings"
+
+//Closes a netlib handle
+//wParam=(WPARAM)(HANDLE)hNetlibHandle
+//lParam=0
+//Returns nonzero on success, 0 on failure (!! this is different to most of the rest of Miranda, but consistent with netlib)
+//This function should be called on all handles returned by netlib functions
+//once you are done with them. If it's called on a socket-type handle, the
+//socket will be closed.
+//Errors: ERROR_INVALID_PARAMETER
+#define MS_NETLIB_CLOSEHANDLE "Netlib/CloseHandle"
+__inline static int Netlib_CloseHandle(HANDLE h) {return CallService(MS_NETLIB_CLOSEHANDLE,(WPARAM)h,0);}
+
+//Open a port and wait for connections on it
+//wParam=(WPARAM)(HANDLE)hUser
+//lParam=(LPARAM)(NETLIBBIND*)&nlb
+//Returns a HANDLE on success, NULL on failure
+//hUser should have been returned by MS_NETLIB_REGISTERUSER
+//This function does the equivalent of socket(), bind(), getsockname(),
+//listen(), accept()
+//Internally this function creates a new thread which waits around in accept()
+//for new connections. When one is received it calls nlb.pfnNewConnection *from
+//this new thread* and then loops back to wait again.
+//Close the returned handle to end the thread and close the open port.
+//Errors: ERROR_INVALID_PARAMETER, any returned by socket() or bind() or
+// listen() or getsockname()
+//
+// Notes:
+//
+// During development of 0.3.1a+ (2003/07/04) passing wPort != 0
+// will result in an attempt to bind on the port given in wPort
+// if this port is taken then you will get an error, so be sure to check
+// for such conditions.
+//
+// passing wPort != 0 is for people who need to open a set port for
+// daemon activities, usually passing wPort==0 is what you want and
+// will result in a free port given by the TCP/IP socket layer and/or
+// seeded from the user selected port ranges.
+//
+// also note that wPort if != 0, will have be converted to network byte order
+//
+/* pExtra was added during 0.3.4+, prior its just two args, since we use the cdecl convention
+it shouldnt matter */
+
+#define NETLIBBIND_SIZEOF_V1 16 // sizeof(NETLIBBIND) prior to 0.3.4+ (2004/08/05)
+#define NETLIBBIND_SIZEOF_V2 20 // sizeof(NETLIBBIND) prior to 0.6+ (2006/07/03)
+
+typedef void (*NETLIBNEWCONNECTIONPROC_V2)(HANDLE hNewConnection,DWORD dwRemoteIP, void * pExtra);
+typedef void (*NETLIBNEWCONNECTIONPROC)(HANDLE hNewConnection,DWORD dwRemoteIP);
+/* This is NETLIBBIND prior to 2004/08/05+, DONT use this anymore unless you want to work
+with older cores, pExtra isnt available on older cores and never will be - for a period of time, the ABI
+for this service was broken and older NETLIBBINDs were not supported, if NULL is returned and the
+argument is good, then tell the user to upgrade to the latest CVS.
+
+The older structure was used til around 2004/08/05 */
+typedef struct {
+ int cbSize;
+ NETLIBNEWCONNECTIONPROC pfnNewConnection;
+ //function to call when there's a new connection. Params are: the
+ //new connection, IP of remote machine (host byte order)
+ DWORD dwInternalIP; //set on return, host byte order
+ WORD wPort; //set on return, host byte order
+} NETLIBBINDOLD;
+
+typedef struct {
+ int cbSize;
+ union { // new code should use V2
+ NETLIBNEWCONNECTIONPROC pfnNewConnection;
+ NETLIBNEWCONNECTIONPROC_V2 pfnNewConnectionV2;
+ };
+ //function to call when there's a new connection. Params are: the
+ //new connection, IP of remote machine (host byte order)
+ DWORD dwInternalIP; //set on return, host byte order
+ WORD wPort; //set on return, host byte order
+ void * pExtra; //argument is sent to callback, added during 0.3.4+
+ DWORD dwExternalIP; //set on return, host byte order
+ WORD wExPort; //set on return, host byte order
+} NETLIBBIND;
+#define MS_NETLIB_BINDPORT "Netlib/BindPort"
+
+//Open a connection
+//wParam=(WPARAM)(HANDLE)hUser
+//lParam=(LPARAM)(NETLIBOPENCONNECTION*)&nloc
+//Returns a HANDLE to the new connection on success, NULL on failure
+//hUser must have been returned by MS_NETLIB_REGISTERUSER
+//Internally this function is the equivalent of socket(), gethostbyname(),
+//connect()
+//If NLOCF_HTTP is set and hUser is configured for an HTTP or HTTPS proxy then
+//this function will connect() to the proxy server only, without performing any
+//initialisation conversation.
+//If hUser is configured for an HTTP proxy and does not support HTTP gateways
+//and you try to open a connection without specifying NLOCF_HTTP then this
+//function will first attempt to open an HTTPS connection, if that fails it
+//will try a direct connection, if that fails it will return failure with the
+//error from the connect() during the direct connection attempt.
+//Errors: ERROR_INVALID_PARAMETER, any returned by socket(), gethostbyname(),
+// connect(), MS_NETLIB_SEND, MS_NETLIB_RECV, select()
+// ERROR_TIMEOUT (during proxy communication)
+// ERROR_BAD_FORMAT (very invalid proxy reply)
+// ERROR_ACCESS_DENIED (by proxy)
+// ERROR_CONNECTION_UNAVAIL (socks proxy can't connect to identd)
+// ERROR_INVALID_ACCESS (proxy refused identd auth)
+// ERROR_INVALID_DATA (proxy returned invalid code)
+// ERROR_INVALID_ID_AUTHORITY (proxy requires use of auth method that's not supported)
+// ERROR_GEN_FAILURE (socks5/https general failure)
+// ERROR_CALL_NOT_IMPLEMENTED (socks5 command not supported)
+// ERROR_INVALID_ADDRESS (socks5 address type not supported)
+// HTTP: anything from nlu.pfnHttpGatewayInit, nlu.pfnHttpGatewayBegin,
+// MS_NETLIB_SENDHTTPREQUEST or MS_NETLIB_RECVHTTPHEADERS
+#define NLOCF_HTTP 0x0001 //this connection will be used for HTTP communications. If configured for an HTTP/HTTPS proxy the connection is opened as if there was no proxy.
+#define NLOCF_STICKYHEADERS 0x0002 //this connection should send the sticky headers associated with NetLib user apart of any HTTP request
+#define NLOCF_V2 0x0004 //this connection understands the newer structure, newer cbSize isnt enough
+
+/* Added during 0.4.0+ development!! (2004/11/29) prior to this, connect() blocks til a connection is made or
+a hard timeout is reached, this can be anywhere between 30-60 seconds, and it stops Miranda from unloading whilst
+this is attempted, clearing sucking - so now you can set a timeout of any value, there is still a hard limit which is
+always reached by Windows, If a timeout occurs, or Miranda is exiting then you will get ERROR_TIMEOUT as soon as possible.
+*/
+#define NETLIBOPENCONNECTION_V1_SIZE 16 /* old sizeof() is 14 bytes, but there is padding of 2 bytes */
+struct NETLIBOPENCONNECTION_tag {
+ int cbSize;
+ const char *szHost; //can contain the string representation of an IP
+ WORD wPort; //host byte order
+ DWORD flags;
+ unsigned int timeout;
+ /* optional, called in the context of the thread that issued the attempt, if it returns 0 the connection attempt is
+ stopped, the remaining timeout value can also be adjusted */
+ int (*waitcallback) (unsigned int * timeout);
+};
+//typedef struct NETLIBOPENCONNECTION_tag NETLIBOPENCONNECTION; //(above for reasons of forward referencing)
+#define MS_NETLIB_OPENCONNECTION "Netlib/OpenConnection"
+
+//Sets the required information for an HTTP proxy connection
+//wParam=(WPARAM)(HANDLE)hConnection
+//lParam=(LPARAM)(NETLIBHTTPPROXYINFO*)&nlhpi
+//Returns nonzero on success, 0 on failure (!! this is different to most of the rest of Miranda, but consistent with netlib)
+//This function is designed to be called from within pfnHttpGatewayInit
+//See notes below MS_NETLIB_REGISTERUSER.
+//Errors: ERROR_INVALID_PARAMETER
+#define NLHPIF_USEGETSEQUENCE 0x0001 //append sequence numbers to GET requests
+#define NLHPIF_USEPOSTSEQUENCE 0x0002 //append sequence numbers to POST requests
+#define NLHPIF_GETPOSTSAMESEQUENCE 0x0004 //GET and POST use the same sequence
+#define NLHPIF_HTTP11 0x0008 //HTTP 1.1 proxy
+typedef struct {
+ int cbSize;
+ DWORD flags;
+ char *szHttpPostUrl;
+ char *szHttpGetUrl;
+ int firstGetSequence,firstPostSequence;
+} NETLIBHTTPPROXYINFO;
+#define MS_NETLIB_SETHTTPPROXYINFO "Netlib/SetHttpProxyInfo"
+
+//Gets the SOCKET associated with a netlib handle
+//wParam=(WPARAM)(HANDLE)hNetlibHandle
+//lParam=0
+//Returns the SOCKET on success, INVALID_SOCKET on failure
+//hNetlibHandle should have been returned by MS_NETLIB_BINDPORT or
+//MS_NETLIB_OPENCONNECTION only.
+//Be careful how you use this socket because you might be connected via an
+//HTTP proxy in which case calling send() or recv() will totally break things.
+//Errors: ERROR_INVALID_PARAMETER
+#define MS_NETLIB_GETSOCKET "Netlib/GetSocket"
+
+//URL-encode a string for x-www-form-urlencoded (and other) transmission
+//wParam=0
+//lParam=(LPARAM)(const char *)pszString
+//Returns a char* containing the new string. This must be freed with
+//HeapFree(GetProcessHeap(),0,pszReturnString) when you're done with it.
+//Returns NULL on error.
+//Errors: ERROR_INVALID_PARAMETER, ERROR_OUTOFMEMORY
+#define MS_NETLIB_URLENCODE "Netlib/UrlEncode"
+
+//Base64 decode a string. See rfc1421.
+//wParam=0
+//lParam=(LPARAM)(NETLIBBASE64*)&nlb64
+//Returns nonzero on success, 0 on failure (!! this is different to most of the rest of Miranda, but consistent with netlib)
+//nlb64.pszEncoded and nlb64.cchEncoded contain the input string and its length
+//(excluding terminating zero).
+//nlb64.pbDecoded and nlb64.cbDecoded contain the buffer in which to put the
+//output and the length of this buffer. The maximum output size for a given
+//input is available from the macro Netlib_GetBase64DecodedBufferSize() below.
+//On return nlb64.cbDecoded is set to the actual length of the decoded data.
+//Errors: ERROR_INVALID_PARAMETER, ERROR_INVALID_DATA, ERROR_BUFFER_OVERFLOW
+typedef struct {
+ char *pszEncoded;
+ int cchEncoded;
+ PBYTE pbDecoded;
+ int cbDecoded;
+} NETLIBBASE64;
+#define Netlib_GetBase64DecodedBufferSize(cchEncoded) (((cchEncoded)>>2)*3)
+#define MS_NETLIB_BASE64DECODE "Netlib/Base64Decode"
+
+//Base64 encode a string. See rfc1421.
+//wParam=0
+//lParam=(LPARAM)(NETLIBBASE64*)&nlb64
+//Returns nonzero on success, 0 on failure (!! this is different to most of the rest of Miranda, but consistent with netlib)
+//nlb64.pbDecoded and nlb64.cbDecoded contain the input buffer and its length
+//nlb64.pszEncoded and nlb64.cchEncoded contain the buffer in which to put the
+//output and the length of this buffer. The maximum output size for a given
+//input is available from the macro Netlib_GetBase64EncodedBufferSize() below.
+//nlb64.pszEncoded is terminated with a 0.
+//On return nlb64.cchEncoded is set to the actual length of the decoded data,
+//excluding the terminating 0.
+//Errors: ERROR_INVALID_PARAMETER, ERROR_BUFFER_OVERFLOW
+#define Netlib_GetBase64EncodedBufferSize(cbDecoded) (((cbDecoded)*4+11)/12*4+1)
+#define MS_NETLIB_BASE64ENCODE "Netlib/Base64Encode"
+
+//Send an HTTP request over a connection
+//wParam=(WPARAM)(HANDLE)hConnection
+//lParam=(LPARAM)(NETLIBHTTPREQUEST*)&nlhr
+//Returns number of bytes sent on success, SOCKET_ERROR on failure
+//hConnection must have been returned by MS_NETLIB_OPENCONNECTION
+//Note that if you use NLHRF_SMARTAUTHHEADER and NTLM authentication is in use
+//then the full NTLM authentication transaction occurs, comprising sending the
+//domain, receiving the challenge, then sending the response.
+//nlhr.resultCode and nlhr.szResultDescr are ignored by this function.
+//Errors: ERROR_INVALID_PARAMETER, anything returned by MS_NETLIB_SEND
+typedef struct {
+ char *szName;
+ char *szValue;
+} NETLIBHTTPHEADER;
+
+#define REQUEST_RESPONSE 0 //used by structure returned by MS_NETLIB_RECVHTTPHEADERS
+#define REQUEST_GET 1
+#define REQUEST_POST 2
+#define REQUEST_CONNECT 3
+#define REQUEST_HEAD 4 // new in 0.5.1
+#define NLHRF_GENERATEHOST 0x00000001 //auto-generate a "Host" header from szUrl
+#define NLHRF_REMOVEHOST 0x00000002 //remove any host and/or protocol portion of szUrl before sending it
+#define NLHRF_SMARTREMOVEHOST 0x00000004 //removes host and/or protocol from szUrl unless the connection was opened through an HTTP or HTTPS proxy.
+#define NLHRF_SMARTAUTHHEADER 0x00000008 //if the connection was opened through an HTTP or HTTPS proxy then send a Proxy-Authorization header if required.
+#define NLHRF_HTTP11 0x00000010 //use HTTP 1.1
+#define NLHRF_NODUMP 0x00010000 //never dump this to the log
+#define NLHRF_NODUMPHEADERS 0x00020000 //don't dump http headers (only useful for POSTs and MS_NETLIB_HTTPTRANSACTION)
+#define NLHRF_DUMPPROXY 0x00040000 //this transaction is a proxy communication. For dump filtering only.
+#define NLHRF_DUMPASTEXT 0x00080000 //dump posted and reply data as text. Headers are always dumped as text.
+struct NETLIBHTTPREQUEST_tag {
+ int cbSize;
+ int requestType; //a REQUEST_
+ DWORD flags;
+ char *szUrl;
+ NETLIBHTTPHEADER *headers; //If this is a POST request and headers
+ //doesn't contain a Content-Length it'll be added automatically
+ int headersCount;
+ char *pData; //data to be sent in POST request.
+ int dataLength; //must be 0 for REQUEST_GET/REQUEST_CONNECT
+ int resultCode;
+ char *szResultDescr;
+ HANDLE nlc;
+};
+//typedef struct NETLIBHTTPREQUEST_tag NETLIBHTTPREQUEST; //(above for reasons of forward referencing)
+#define MS_NETLIB_SENDHTTPREQUEST "Netlib/SendHttpRequest"
+
+//Receive HTTP headers
+//wParam=(WPARAM)(HANDLE)hConnection
+//lParam=0
+//Returns a pointer to a NETLIBHTTPREQUEST structure on success, NULL on
+//failure.
+//Call MS_NETLIB_FREEHTTPREQUESTSTRUCT to free this.
+//hConnection must have been returned by MS_NETLIB_OPENCONNECTION
+//nlhr->pData=NULL and nlhr->dataLength=0 always. The requested data should
+//be retrieved using MS_NETLIB_RECV once the header has been parsed.
+//If the headers haven't finished within 60 seconds the function returns NULL
+//and ERROR_TIMEOUT.
+//Errors: ERROR_INVALID_PARAMETER, any from MS_NETLIB_RECV or select()
+// ERROR_HANDLE_EOF (connection closed before headers complete)
+// ERROR_TIMEOUT (headers still not complete after 60 seconds)
+// ERROR_BAD_FORMAT (invalid character or line ending in headers, or first line is blank)
+// ERROR_BUFFER_OVERFLOW (each header line must be less than 4096 chars long)
+// ERROR_INVALID_DATA (first header line is malformed ("http/[01].[0-9] [0-9]+ .*", or no colon in subsequent line)
+#define MS_NETLIB_RECVHTTPHEADERS "Netlib/RecvHttpHeaders"
+
+//Free the memory used by a NETLIBHTTPREQUEST structure
+//wParam=0
+//lParam=(LPARAM)(NETLIBHTTPREQUEST*)pnlhr
+//Returns nonzero on success, 0 on failure (!! this is different to most of the rest of Miranda, but consistent with netlib)
+//This should only be called on structures returned by
+//MS_NETLIB_RECVHTTPHEADERS or MS_NETLIB_HTTPTRANSACTION. Calling it on an
+//arbitrary structure will have disastrous results.
+//Errors: ERROR_INVALID_PARAMETER
+#define MS_NETLIB_FREEHTTPREQUESTSTRUCT "Netlib/FreeHttpRequestStruct"
+
+//Do an entire HTTP transaction
+//wParam=(WPARAM)(HANDLE)hUser
+//lParam=(LPARAM)(NETLIBHTTPREQUEST*)&nlhr
+//Returns a pointer to another NETLIBHTTPREQUEST structure on success, NULL on
+//failure.
+//Call MS_NETLIB_FREEHTTPREQUESTSTRUCT to free this.
+//hUser must have been returned by MS_NETLIB_REGISTERUSER
+//nlhr.szUrl should be a full HTTP URL. If it does not start with http://, that
+//will be assumed (but it's best not to use this fact, for reasons of
+//extensibility).
+//This function is the equivalent of MS_NETLIB_OPENCONNECTION,
+//MS_NETLIB_SENDHTTPREQ, MS_NETLIB_RECVHTTPHEADERS, MS_NETLIB_RECV,
+//MS_NETLIB_CLOSEHANDLE
+//nlhr.headers will be augmented with the following headers unless they have
+//already been set by the caller:
+// "Host" (regardless of whether it is requested in nlhr.flags)
+// "User-Agent" (of the form "Miranda/0.1.2.2 (alpha)" or "Miranda/0.1.2.2")
+// "Content-Length" (for POSTs only. Set to nlhr.dataLength)
+//If you do not want to send one of these headers, create a nlhr.headers with
+//szValue=NULL.
+//In the return value headers, headerCount, pData, dataLength, resultCode and
+//szResultDescr are all valid.
+//In the return value pData[dataLength]==0 always, as an extra safeguard
+//against programming slips.
+//Note that the function can succeed (ie not return NULL) yet result in an HTTP
+//error code. You should check that resultCode==2xx before proceeding.
+//Errors: ERROR_INVALID_PARAMETER, ERROR_OUTOFMEMORY, anything from the above
+// list of functions
+#define MS_NETLIB_HTTPTRANSACTION "Netlib/HttpTransaction"
+
+//Send data over a connection
+//wParam=(WPARAM)(HANDLE)hConnection
+//lParam=(LPARAM)(NETLIBBUFFER*)&nlb
+//Returns the number of bytes sent on success, SOCKET_ERROR on failure
+//Errors: ERROR_INVALID_PARAMETER
+// anything from send(), nlu.pfnHttpGatewayWrapSend()
+// HTTP proxy: ERROR_GEN_FAILURE (http result code wasn't 2xx)
+// anything from socket(), connect(),
+// MS_NETLIB_SENDHTTPREQUEST, MS_NETLIB_RECVHTTPHEADERS
+//flags:
+#define MSG_NOHTTPGATEWAYWRAP 0x010000 //don't wrap the outgoing packet using nlu.pfnHttpGatewayWrapSend
+#define MSG_NODUMP 0x020000 //don't dump this packet to the log
+#define MSG_DUMPPROXY 0x040000 //this is proxy communiciation. For dump filtering only.
+#define MSG_DUMPASTEXT 0x080000 //this is textual data, don't dump as hex
+#define MSG_RAW 0x100000 //send as raw data, bypass any HTTP proxy stuff
+typedef struct {
+ char *buf;
+ int len;
+ int flags;
+} NETLIBBUFFER;
+#define MS_NETLIB_SEND "Netlib/Send"
+static __inline int Netlib_Send(HANDLE hConn,const char *buf,int len,int flags) {
+ NETLIBBUFFER nlb={(char*)buf,len,flags};
+ return CallService(MS_NETLIB_SEND,(WPARAM)hConn,(LPARAM)&nlb);
+}
+
+//Receive data over a connection
+//wParam=(WPARAM)(HANDLE)hConnection
+//lParam=(LPARAM)(NETLIBBUFFER*)&nlb
+//Returns the number of bytes read on success, SOCKET_ERROR on failure,
+//0 if the connection has been closed
+//Flags supported: MSG_PEEK, MSG_NODUMP, MSG_DUMPPROXY, MSG_NOHTTPGATEWAYWRAP,
+// MSG_DUMPASTEXT, MSG_RAW
+//On using MSG_NOHTTPGATEWAYWRAP: Because packets through an HTTP proxy are
+// batched and cached and stuff, using this flag is not a guarantee that it
+// will be obeyed, and if it is it may even be propogated to future calls
+// even if you don't specify it then. Because of this, the flag should be
+// considered an all-or-nothing thing: either use it for the entire duration
+// of a connection, or not at all.
+//Errors: ERROR_INVALID_PARAMETER, anything from recv()
+// HTTP proxy: ERROR_GEN_FAILURE (http result code wasn't 2xx)
+// ERROR_INVALID_DATA (no Content-Length header in reply)
+// ERROR_NOT_ENOUGH_MEMORY (Content-Length very large)
+// ERROR_HANDLE_EOF (connection closed before Content-Length bytes recved)
+// anything from select(), MS_NETLIB_RECVHTTPHEADERS,
+// nlu.pfnHttpGatewayUnwrapRecv, socket(), connect(),
+// MS_NETLIB_SENDHTTPREQUEST
+#define MS_NETLIB_RECV "Netlib/Recv"
+static __inline int Netlib_Recv(HANDLE hConn,char *buf,int len,int flags) {
+ NETLIBBUFFER nlb={buf,len,flags};
+ return CallService(MS_NETLIB_RECV,(WPARAM)hConn,(LPARAM)&nlb);
+}
+
+//Determine the status of one or more connections
+//wParam=0
+//lParam=(LPARAM)(NETLIBSELECT*)&nls
+//Returns the number of ready connections, SOCKET_ERROR on failure,
+//0 if the timeout expired.
+//All handles passed to this function must have been returned by either
+//MS_NETLIB_OPENCONNECTION or MS_NETLIB_BINDPORT.
+//The last handle in each list must be followed by either NULL or
+//INVALID_HANDLE_VALUE.
+//Errors: ERROR_INVALID_HANDLE, ERROR_INVALID_DATA, anything from select()
+typedef struct {
+ int cbSize;
+ DWORD dwTimeout; //in milliseconds, INFINITE is acceptable
+ HANDLE hReadConns[FD_SETSIZE+1];
+ HANDLE hWriteConns[FD_SETSIZE+1];
+ HANDLE hExceptConns[FD_SETSIZE+1];
+} NETLIBSELECT;
+
+typedef struct {
+ int cbSize;
+ DWORD dwTimeout; //in milliseconds, INFINITE is acceptable
+ HANDLE hReadConns[FD_SETSIZE+1];
+ HANDLE hWriteConns[FD_SETSIZE+1];
+ HANDLE hExceptConns[FD_SETSIZE+1];
+ /* Added in v0.3.3+ */
+ BOOL hReadStatus[FD_SETSIZE+1]; /* out, [in, expected to be FALSE] */
+ BOOL hWriteStatus[FD_SETSIZE+1]; /* out, [in, expected to be FALSE] */
+ BOOL hExceptStatus[FD_SETSIZE+1]; /* out, [in, expected to be FALSE] */
+} NETLIBSELECTEX;
+
+#define MS_NETLIB_SELECT "Netlib/Select"
+// added in v0.3.3
+#define MS_NETLIB_SELECTEX "Netlib/SelectEx"
+
+//Create a packet receiver
+//wParam=(WPARAM)(HANDLE)hConnection
+//lParam=(LPARAM)(int)maxPacketSize
+//Returns a HANDLE on success, NULL on failure
+//The packet receiver implements the common situation where you have variable
+//length packets coming in over a connection and you want to split them up
+//in order to handle them.
+//The major limitation is that the buffer is created in memory, so you can't
+//have arbitrarily large packets.
+//Errors: ERROR_INVALID_PARAMETER, ERROR_OUTOFMEMORY
+#define MS_NETLIB_CREATEPACKETRECVER "Netlib/CreatePacketRecver"
+
+//Get the next set of packets from a packet receiver
+//wParam=(WPARAM)(HANDLE)hPacketRecver
+//lParam=(LPARAM)(NETLIBPACKETRECVER*)&nlpr
+//Returns the total number of bytes available in the buffer, 0 if the
+//connection was closed, SOCKET_ERROR on error.
+//hPacketRecver must have been returned by MS_NETLIB_CREATEPACKETRECVER
+//If nlpr.bytesUsed is set to zero and the buffer is already full up to
+//maxPacketSize, it is assumed that too large a packet has been received. All
+//data in the buffer is discarded and receiving is begun anew. This will
+//probably cause alignment problems so if you think this is likely to happen
+//then you should deal with it yourself.
+//Closing the packet receiver will not close the associated connection, but
+//will discard any bytes still in the buffer, so if you intend to carry on
+//reading from that connection, make sure you have processed the buffer first.
+//This function is the equivalent of a memmove() to remove the first bytesUsed
+//from the buffer, select() if dwTimeout is not INFINITE, then MS_NETLIB_RECV.
+//Errors: ERROR_INVALID_PARAMETER, ERROR_TIMEOUT,
+// anything from select(), MS_NETLIB_RECV
+typedef struct {
+ int cbSize;
+ DWORD dwTimeout; //fill before calling. In milliseconds. INFINITE is valid
+ int bytesUsed; //fill before calling. This many bytes are removed from the start of the buffer. Set to 0 on return
+ int bytesAvailable; //equal to the return value, unless the return value is 0
+ int bufferSize; //same as parameter to MS_NETLIB_CREATEPACKETRECVER
+ BYTE *buffer; //contains the recved data
+} NETLIBPACKETRECVER;
+#define MS_NETLIB_GETMOREPACKETS "Netlib/GetMorePackets"
+
+//Add a message to the log (if it's running)
+//wParam=(WPARAM)(HANDLE)hUser
+//lParam=(LPARAM)(const char *)szMessage
+//Returns nonzero on success, 0 on failure (!! this is different to most of the rest of Miranda, but consistent with netlib)
+//Do not include a final line ending in szMessage.
+//Errors: ERROR_INVALID_PARAMETER
+#define MS_NETLIB_LOG "Netlib/Log"
+
+//Sets a gateway polling timeout interval
+//wParam=(WPARAM)(HANDLE)hConn
+//lParam=(LPARAM)timeout
+//Returns previous timeout value
+//Errors: -1
+#define MS_NETLIB_SETPOLLINGTIMEOUT "Netlib/SetPollingTimeout"
+
+//here's a handy piece of code to let you log using printf-style specifiers:
+//#include <stdarg.h> and <stdio.h> before including this header in order to
+//use it.
+#if defined va_start && (defined _STDIO_DEFINED || defined _STDIO_H_) && (!defined NETLIB_NOLOGGING)
+static __inline int Netlib_Logf(HANDLE hUser,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)hUser,(LPARAM)szText);
+}
+#endif //defined va_start
+
+/* Notes on being backwards compatible with 0.1.2.1
+One way to do back compatibility is to create your own mini netlib that only
+supports a minimal set of features. Here's some sample code:
+
+//This function is called during the ME_SYSTEM_MODULESLOADED hook
+int MyPluginModulesLoaded(WPARAM wParam,LPARAM lParam)
+{
+ //if this is executed on a version of Miranda with netlib then all
+ //these calls will fail and the proper netlib will be used.
+ CreateServiceFunction(MS_NETLIB_CLOSEHANDLE,MiniNetlibCloseHandle);
+ CreateServiceFunction(MS_NETLIB_OPENCONNECTION,MiniNetlibOpenConnection);
+ CreateServiceFunction(MS_NETLIB_SEND,MiniNetlibSend);
+ CreateServiceFunction(MS_NETLIB_RECV,MiniNetlibRecv);
+ CreateServiceFunction(MS_NETLIB_SELECT,MiniNetlibSelect);
+ return 0;
+}
+
+int MiniNetlibCloseHandle(WPARAM wParam,LPARAM lParam)
+{
+ closesocket((SOCKET)wParam);
+ return 1;
+}
+
+int MiniNetlibOpenConnection(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBOPENCONNECTION *nloc=(NETLIBOPENCONNECTION*)lParam;
+ SOCKADDR_IN sin;
+ SOCKET s;
+
+ sin.s_addr=inet_addr(szHost);
+ if(sin.sin_addr.S_un.S_addr==INADDR_NONE) {
+ HOSTENT *host=gethostbyname(szHost);
+ if(host) sin.sin_addr.S_un.S_addr=*(u_long *)host->h_addr_list[0];
+ else return (int)INVALID_SOCKET;
+ }
+ s=socket(AF_INET,SOCK_STREAM,0);
+ sin.sin_family=AF_INET;
+ sin.sin_port=(short)htons(nloc->wPort);
+ if(connect(s,(SOCKADDR*)sin,sizeof(sin))==SOCKET_ERROR) {
+ closesocket(s);
+ return (int)INVALID_SOCKET;
+ }
+ return (int)s;
+}
+
+int MiniNetlibSend(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBBUFFER *nlb=(NETLIBBUFFER*)lParam;
+ return send((SOCKET)wParam,nlb->buf,nlb->len,nlb->flags);
+}
+
+int MiniNetlibRecv(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBBUFFER *nlb=(NETLIBBUFFER*)lParam;
+ return recv((SOCKET)wParam,nlb->buf,nlb->len,nlb->flags);
+}
+
+int MiniNetlibSelect(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBSELECT *nls=(NETLIBSELECT*)lParam;
+ fd_set readfd,writefd,exceptfd;
+ TIMEVAL tv;
+ int i;
+
+ tv.tv_sec=nls->dwTimeout/1000;
+ tv.tv_usec=(nls->dwTimeout%1000)*1000;
+ FD_ZERO(&readfd); for(i=0;nls->hReadConns[i];i++) FD_SET((SOCKET)nls->hReadConns[i],&readfd);
+ FD_ZERO(&writefd); for(i=0;nls->hWriteConns[i];i++) FD_SET((SOCKET)nls->hWriteConns[i],&writefd);
+ FD_ZERO(&exceptfd); for(i=0;nls->hExceptConns[i];i++) FD_SET((SOCKET)nls->hExceptConns[i],&exceptfd);
+ return select(0,&readfd,&writefd,&exceptfd,nls->dwTimeout==INFINITE?NULL:&tv);
+}
+
+///
+NB: I haven't actually tested that this even compiles.
+*/
+
+#endif // M_NETLIB_H__
+
diff --git a/miranda-wine/include/m_options.h b/miranda-wine/include/m_options.h
new file mode 100644
index 0000000..6d521bf
--- /dev/null
+++ b/miranda-wine/include/m_options.h
@@ -0,0 +1,108 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_OPTIONS_H__
+#define M_OPTIONS_H__
+
+/* Opt/Initialise
+The user opened the options dialog. Modules should do whatever initialisation
+they need and call opt/addpage one or more times if they want pages displayed
+in the options dialog
+wParam=addInfo
+lParam=0
+addInfo should be passed straight to the wParam of opt/addpage
+*/
+#define ME_OPT_INITIALISE "Opt/Initialise"
+
+/* Opt/AddPage
+Must only be called during an opt/initialise hook
+Adds a page to the options dialog
+wParam=addInfo
+lParam=(LPARAM)(OPTIONSDIALOGPAGE*)odp
+addInfo must have come straight from the wParam of opt/initialise
+Pages in the options dialog operate just like pages in property sheets. See the
+Microsoft documentation for details on how they operate.
+Strings in the structure can be released as soon as the service returns, but
+icons must be kept around. This is not a problem if you're loading them from a
+resource.
+Prior to v0.1.2.1 the options dialog would resize to fit the largest page, but
+since then it is fixed in size. The largest page that fits neatly is 314x240
+DLUs.
+*/
+typedef struct {
+ int cbSize;
+ int position; //a position number, lower numbers are topmost
+ union {
+ char* pszTitle;
+ TCHAR* ptszTitle;
+ };
+ DLGPROC pfnDlgProc;
+ char *pszTemplate;
+ HINSTANCE hInstance;
+ HICON hIcon; //v0.1.0.1+
+ union {
+ char* pszGroup; //v0.1.0.1+
+ TCHAR* ptszGroup; //v0.1.0.1+
+ };
+ int groupPosition; //v0.1.0.1+
+ HICON hGroupIcon; //v0.1.0.1+
+ DWORD flags; //v0.1.2.1+
+ int nIDBottomSimpleControl; //v0.1.2.1+ if in simple mode the dlg will be cut off after this control, 0 to disable
+ int nIDRightSimpleControl; //v0.1.2.1+ if in simple mode the dlg will be cut off after this control, 0 to disable
+ UINT *expertOnlyControls;
+ int nExpertOnlyControls; //v0.1.2.1+ these controls will be hidden in simple mode. Array must remain valid for duration of dlg.
+} OPTIONSDIALOGPAGE;
+#define ODPF_SIMPLEONLY 1 // page is only shown when in simple mode
+#define ODPF_EXPERTONLY 2 // " expert mode
+#define ODPF_BOLDGROUPS 4 // give group box titles a bold font
+#define ODPF_UNICODE 8 // string fields in OPTIONSDIALOGPAGE are WCHAR*
+
+#if defined( _UNICODE )
+ #define ODPF_TCHAR ODPF_UNICODE
+#else
+ #define ODPF_TCHAR 0
+#endif
+
+#define PSN_EXPERTCHANGED 2 //sent to pages via WM_NOTIFY when the expert checkbox is clicked. lParam=new state
+#define PSM_ISEXPERT (WM_USER+101) //returns true/false
+#define PSM_GETBOLDFONT (WM_USER+102) //returns HFONT used for group box titles
+#define MS_OPT_ADDPAGE "Opt/AddPage"
+
+//Opens the options dialog, optionally at the specified page v0.1.2.1+
+//wParam=0
+//lParam=(LPARAM)(OPENOPTIONSDIALOG*)&ood;
+//Returns 0 on success, nonzero on failure
+//The behaviour if the options dialog is already open is that it will just be
+//activated, the page won't be changed. This may change in the future.
+typedef struct {
+ int cbSize;
+ const char *pszGroup; //set to NULL if it's a root item
+ const char *pszPage; //set to NULL to just open the options at no
+ //specific page
+} OPENOPTIONSDIALOG;
+#define MS_OPT_OPENOPTIONS "Opt/OpenOptions"
+
+#define SETTING_SHOWEXPERT_DEFAULT 1
+
+#endif //M_OPTIONS_H__
+
diff --git a/miranda-wine/include/m_plugins.h b/miranda-wine/include/m_plugins.h
new file mode 100644
index 0000000..c204394
--- /dev/null
+++ b/miranda-wine/include/m_plugins.h
@@ -0,0 +1,82 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_PLUGINS_H__
+#define M_PLUGINS_H__
+
+/*
+ Undocumented: Do NOT use.
+ Version: 0.3.4.1+ (2004/10/04)
+*/
+#define DBPE_DONE 1
+#define DBPE_CONT 0
+#define DBPE_HALT (-1)
+typedef struct PLUGIN_DB_ENUM {
+ int cbSize;
+ // 0 = continue, 1 = found, -1 = stop now
+ int (*pfnEnumCallback) ( char * pluginname, /*DATABASELINK*/ void * link, LPARAM lParam);
+ LPARAM lParam;
+} PLUGIN_DB_ENUM;
+#define MS_PLUGINS_ENUMDBPLUGINS "Plugins/DbEnumerate"
+
+
+#define DEFMOD_PROTOCOLICQ 1 //removed from v0.3 alpha
+#define DEFMOD_PROTOCOLMSN 2 //removed from v0.1.2.0+
+#define DEFMOD_UIFINDADD 3
+#define DEFMOD_UIUSERINFO 4
+#define DEFMOD_SRMESSAGE 5 //removed from v0.3.3a (temp)
+#define DEFMOD_SRURL 6
+#define DEFMOD_SREMAIL 7
+#define DEFMOD_SRAUTH 8
+#define DEFMOD_SRFILE 9
+#define DEFMOD_UIHELP 10
+#define DEFMOD_UIHISTORY 11
+//#define DEFMOD_RNDCHECKUPD 12 //removed from v0.3.1 alpha
+//#define DEFMOD_RNDICQIMPORT 13 //removed from v0.3 alpha
+#define DEFMOD_RNDAUTOAWAY 14
+#define DEFMOD_RNDUSERONLINE 15
+#define DEFMOD_RNDCRYPT 16 //v0.1.0.1-v0.1.2.0
+#define DEFMOD_SRAWAY 17 //v0.1.0.1+
+#define DEFMOD_RNDIGNORE 18 //v0.1.0.1+
+#define DEFMOD_UIVISIBILITY 19 //v0.1.1.0+, options page only
+#define DEFMOD_UICLUI 20 //v0.1.1.0+
+//#define DEFMOD_UIPLUGINOPTS 21 //removed from 0.4.0.1
+#define DEFMOD_PROTOCOLNETLIB 22 //v0.1.2.2+
+#define DEFMOD_RNDIDLE 23 //v0.3.4a+
+#define DEFMOD_CLISTALL 24 //v0.3.4a+ (2004/09/28)
+#define DEFMOD_DB 25 //v0.3.4.3+ (2004/10/11)
+
+#define DEFMOD_HIGHEST 25
+
+//plugins/getdisabledefaultarray
+//gets an array of the modules that the plugins report they want to replace
+//wParam=lParam=0
+//returns a pointer to an array of ints, with elements 1 or 0 indexed by the
+//DEFMOD_ constants. 1 to signify that the default module shouldn't be loaded.
+//this is primarily for use by the core's module initialiser, but could also
+//be used by modules that are doing naughty things that are very
+//feature-dependent
+#define MS_PLUGINS_GETDISABLEDEFAULTARRAY "Plugins/GetDisableDefaultArray"
+
+#endif // M_PLUGINS_H__
+
diff --git a/miranda-wine/include/m_png.h b/miranda-wine/include/m_png.h
new file mode 100644
index 0000000..c5e8b67
--- /dev/null
+++ b/miranda-wine/include/m_png.h
@@ -0,0 +1,64 @@
+/*
+Plugin of Miranda IM for reading/writing PNG images.
+Copyright (c) 2004-5 George Hazan (ghazan@postman.ru)
+
+Portions of this code are gotten from the libpng codebase.
+Copyright 2000, Willem van Schaik. For conditions of distribution and
+use, see the copyright/license/disclaimer notice in png.h
+
+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.
+
+File name : $Source: /cvsroot/miranda/miranda/include/m_png.h,v $
+Revision : $Revision: 2876 $
+Last change on : $Date: 2006-05-17 01:56:03 +0400 (Срд, 17 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+/* Image/Dib2Png
+Converts a Device Independent Bitmap to a png stored in memory
+ wParam=0
+ lParam=(WPARAM)(DIB2PNG*)descr
+*/
+
+typedef struct
+{
+ BITMAPINFO* pbmi;
+ BYTE* pDiData;
+ BYTE* pResult;
+ long* pResultLen;
+}
+ DIB2PNG;
+
+#define MS_DIB2PNG "Image/Dib2Png"
+
+/* Image/Png2Dib
+Converts a png stored in memory to a Device Independent Bitmap
+ wParam=0
+ lParam=(WPARAM)(PNG2DIB*)descr
+*/
+
+typedef struct
+{
+ BYTE* pSource;
+ DWORD cbSourceSize;
+ BITMAPINFOHEADER** pResult;
+}
+ PNG2DIB;
+
+#define MS_PNG2DIB "Image/Png2Dib"
diff --git a/miranda-wine/include/m_popup.h b/miranda-wine/include/m_popup.h
new file mode 100644
index 0000000..2556f83
--- /dev/null
+++ b/miranda-wine/include/m_popup.h
@@ -0,0 +1,317 @@
+/*
+===============================================================================
+ 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_POPUP_H
+#define M_POPUP_H
+
+/*
+NOTE! Since Popup 1.0.1.2 there is a main meun group called "PopUps" where I
+have put a "Enable/Disable" item. You can add your own "enable/disable" items
+by adding these lines before you call MS_CLIST_ADDMAINMENUITEM:
+mi.pszPopUpName = Translate("PopUps");
+mi.position = 0; //You don't need it and it's better if you put it to zero.
+*/
+
+//#define MAX_CONTACTNAME 32
+//#define MAX_SECONDLINE 40
+#define MAX_CONTACTNAME 2048
+#define MAX_SECONDLINE 2048
+
+#define POPUP_USE_SKINNED_BG 0xffffffff
+
+//This is the basic data you'll need to fill and pass to the service function.
+typedef struct {
+ HANDLE lchContact; //Handle to the contact, can be NULL (main contact).
+ HICON lchIcon; //Handle to a icon to be shown. Cannot be NULL.
+ char lpzContactName[MAX_CONTACTNAME]; //This is the contact name or the first line in the plugin. Cannot be NULL.
+ char lpzText[MAX_SECONDLINE]; //This is the second line text. Users can choose to hide it. Cannot be NULL.
+ COLORREF colorBack; //COLORREF to be used for the background. Can be NULL, default will be used.
+ COLORREF colorText; //COLORREF to be used for the text. Can be NULL, default will be used.
+ WNDPROC PluginWindowProc; //Read below. Can be NULL; default will be used.
+ void * PluginData; //Read below. Can be NULL.
+} POPUPDATA, * LPPOPUPDATA;
+
+typedef struct {
+ HANDLE lchContact;
+ HICON lchIcon;
+ char lpzContactName[MAX_CONTACTNAME];
+ char lpzText[MAX_SECONDLINE];
+ COLORREF colorBack; //Set background to POPUP_USE_SKINNED_BG to turn on skinning
+ COLORREF colorText;
+ WNDPROC PluginWindowProc;
+ void * PluginData;
+ int iSeconds; //Custom delay time in seconds. -1 means "forever", 0 means "default time".
+ LPCTSTR lpzClass; //PopUp class. Used with skinning. See PopUp/AddClass for details
+ COLORREF skinBack; //Background color for colorizable skins
+ char cZero[16 - sizeof(LPCTSTR) - sizeof(COLORREF)];
+ //some unused bytes which may come useful in the future.
+} POPUPDATAEX, *LPPOPUPDATAEX;
+
+/*
+When you call MS_POPUP_ADDPOPUP, my plugin will check if the given POPUPDATA structure is filled with acceptable values. If not, the data will be rejected and no popup will be shown.
+
+- lpzText should be given, because it's really bad if a user chooses to have the second line displayed
+and it's empty :-) Just write it and let the user choose if it will be displayed or not.
+
+- PluginWindowProc is a WNDPROC address you have to give me. Why? What? Where? Calm down 8)
+My plugin will take care of the creation of the popup, of the destruction of the popup, of the come into
+view and the hiding of the popup. Transparency, animations... all this stuff.
+My plugin will not (as example) open the MessageWindow when you left click on a popup.
+Why? Because I don't know if your popup desires to open the MessageWindow :))))
+This means that you need to make a WNDPROC which takes care of the WM_messages you need.
+For example, WM_COMMAND or WM_CONTEXTMENU or WM_LMOUSEUP or whatever.
+At the end of your WNDPROC remember to "return DefWindowProc(hwnd, msg, wParam, lParam);"
+When you process a message that needs a return value (an example could be WM_CTLCOLORSTATIC,
+but you don't need to catch it 'cause it's my plugin's job), simply return the nedeed value. :)
+The default WNDPROC does nothing.
+
+- PluginData is a pointer to a void, which means a pointer to anything. You can make your own structure
+to store the data you need (example: a status information, a date, your name, whatever) and give me a
+pointer to that struct.
+You will need to destroy that structure and free the memory when the PopUp is going to be destroyed. You'll know this when you receive a UM_FREEPLUGINDATA. The name tells it all: free your own plugin data.
+
+Appendix A: Messages my plugin will handle and your WNDPROC will never see.
+WM_CREATE, WM_DESTROY, WM_TIMER, WM_ERASEBKGND
+WM_CTLCOLOR* [whatever it may be: WM_CTLCOLORDLG, WM_CTLCOLORSTATIC...]
+WM_PAINT, WM_PRINT, WM_PRINTCLIENT
+
+Appendix B: "What do I need to do?!?".
+Here is an example in C.
+
+//Your plugin is in /plugins/myPlugin/ or in miranda32/something/
+#include "../../plugins/PopUp/m_popup.h"
+
+Define your own plugin data if you need it. In this example, we need it and we'll use NewStatusNotify as example: thsi plugin shows a popup when someone in your contact list changes his/hers status. We'll need to know his status, both current and old one.
+typedef struct {
+ WORD oldStatus;
+ WORD newStatus;
+} MY_PLUGIN_DATA;
+
+When we need to show the popup, we do:
+{
+ POPUPDATA ppd;
+ hContact = A_VALID_HANDLE_YOU_GOT_FROM_SOMEWHERE;
+ hIcon = A_VALID_HANDLE_YOU_GOT_SOMEWHERE;
+ char * lpzContactName = (char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)lhContact,0);
+ //99% of the times you'll just copy this line.
+ //1% of the times you may wish to change the contact's name. I don't know why you should, but you can.
+ char * lpzText;
+ //The text for the second line. You could even make something like: char lpzText[128]; lstrcpy(lpzText, "Hello world!"); It's your choice.
+ COLORREF colorBack = GetSysColor(COLOR_BTNFACE); //The colour of Miranda's option Pages (and many other windows...)
+ COLORREF colorText = RGB(255,255,255); //White.
+ MY_PLUGIN_DATA * mpd = (MY_PLUGIN_DATA*)mir_alloc(sizeof(MY_PLUGIN_DATA));
+
+ ZeroMemory(ppd, sizeof(ppd)); //This is always a good thing to do.
+ ppd.lchContact = (HANDLE)hContact; //Be sure to use a GOOD handle, since this will not be checked.
+ ppd.lchIcon = hIcon;
+ lstrcpy(ppd.lpzContactName, lpzContactName);
+ lstrcpy(ppd.lpzText, lpzText);
+ ppd.colorBack = colorBack;
+ ppd.colorText = colorText;
+ ppd.PluginWindowProc = (WNDPROC)PopupDlgProc;
+
+ //Now the "additional" data.
+ mpd->oldStatus = ID_STATUS_OFFLINE;
+ mpd->newStatus = ID_STATUS_ONLINE;
+
+ //Now that the plugin data has been filled, we add it to the PopUpData.
+ ppd.PluginData = mpd;
+
+ //Now that every field has been filled, we want to see the popup.
+ CallService(MS_POPUP_ADDPOPUP, (WPARAM)&ppd, 0);
+}
+
+Obviously, you have previously declared some:
+static int CALLBACK PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch(message) {
+ case WM_COMMAND:
+ if ((HIWORD)wParam == STN_CLICKED) { //It was a click on the Popup.
+ PUDeletePopUp(hWnd);
+ return TRUE;
+ }
+ break;
+ case UM_FREEPLUGINDATA: {
+ MY_PLUGIN_DATA * mpd = NULL;
+ mpd = (MY_PLUGIN_DATA*)CallService(MS_POPUP_GETPLUGINDATA, (WPARAM)hWnd,(LPARAM)mpd);
+ if (mdp > 0) mir_free(mpd);
+ return TRUE; //TRUE or FALSE is the same, it gets ignored.
+ }
+ default:
+ break;
+ }
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+*/
+
+/*
+Creates, adds and shows a popup, given a (valid) POPUPDATA structure pointer.
+wParam = (WPARAM)(*POPUPDATA)PopUpDataAddress
+lParam = 0
+Returns: > 0 on success, 0 if creation went bad, -1 if the PopUpData contained unacceptable values.
+NOTE: it returns -1 if the PopUpData was not valid, if there were already too many popups, if the module was disabled.
+Otherwise, it can return anything else...
+*/
+#define MS_POPUP_ADDPOPUP "PopUp/AddPopUp"
+static int __inline PUAddPopUp(POPUPDATA* ppdp) {
+ return CallService(MS_POPUP_ADDPOPUP, (WPARAM)ppdp,0);
+}
+
+#define MS_POPUP_ADDPOPUPEX "PopUp/AddPopUpEx"
+static int __inline PUAddPopUpEx(POPUPDATAEX* ppdp) {
+ return CallService(MS_POPUP_ADDPOPUPEX, (WPARAM)ppdp,0);
+}
+
+/*
+Returns the handle to the contact associated to the specified PopUpWindow.
+You will probably need to know this handle inside your WNDPROC. Exampole: you want to open the MessageWindow. :-)
+Call MS_POPUP_GETCONTACT on the hWnd you were given in the WNDPROC.
+wParam = (WPARAM)(HWND)hPopUpWindow
+lParam = 0;
+Returns: the HANDLE of the contact. Can return NULL, meaning it's the main contact. -1 means failure.
+*/
+#define MS_POPUP_GETCONTACT "PopUp/GetContact"
+static HANDLE __inline PUGetContact(HWND hPopUpWindow) {
+ return (HANDLE)CallService(MS_POPUP_GETCONTACT, (WPARAM)hPopUpWindow,0);
+}
+
+/*
+wParam = (WPARAM)(HWND)hPopUpWindow
+lParam = (LPARAM)(PLUGINDATA*)PluginDataAddress;
+Returns: the address of the PLUGINDATA structure. Can return NULL, meaning nothing was given. -1 means failure.
+IMPORTANT NOTE: it doesn't seem to work if you do:
+CallService(..., (LPARAM)aPointerToAStruct);
+and then use that struct.
+Do this, instead:
+aPointerToStruct = CallService(..., (LPARAM)aPointerToAStruct);
+and it will work. Just look at the example I've written above (PopUpDlgProc).
+*/
+#define MS_POPUP_GETPLUGINDATA "PopUp/GetPluginData"
+static void __inline * PUGetPluginData(HWND hPopUpWindow) {
+ long * uselessPointer = NULL;
+ return (void*)CallService(MS_POPUP_GETPLUGINDATA,(WPARAM)hPopUpWindow,(LPARAM)uselessPointer);
+}
+
+/*
+wParam = 0
+lParam = 0
+Returns: 0 if the user has chosen not to have the second line, 1 if he choose to have the second line.
+*/
+#define MS_POPUP_ISSECONDLINESHOWN "PopUp/IsSecondLineShown"
+static BOOL __inline PUIsSecondLineShown() {
+ return (BOOL)CallService(MS_POPUP_ISSECONDLINESHOWN,0,0);
+}
+
+/*
+Requests an action or an answer from PopUp module.
+wParam = (WPARAM)wpQuery
+returns 0 on success, -1 on error, 1 on stupid calls ;-)
+*/
+#define PUQS_ENABLEPOPUPS 1 //returns 0 if state was changed, 1 if state wasn't changed
+#define PUQS_DISABLEPOPUPS 2 // " "
+#define PUQS_GETSTATUS 3 //Returns 1 (TRUE) if popups are enabled, 0 (FALSE) if popups are disabled.
+
+#define MS_POPUP_QUERY "PopUp/Query"
+
+/*
+UM_FREEPLUGINDATA
+wParam = lParam = 0. Process this message if you have allocated your own memory. (i.e.: POPUPDATA.PluginData != NULL)
+*/
+#define UM_FREEPLUGINDATA (WM_USER + 0x0200)
+
+/*
+UM_DESTROYPOPUP
+wParam = lParam = 0. Send this message when you want to destroy the popup, or use the function below.
+*/
+#define UM_DESTROYPOPUP (WM_USER + 0x0201)
+static int __inline PUDeletePopUp(HWND hWndPopUp) {
+ return (int)SendMessage(hWndPopUp, UM_DESTROYPOPUP,0,0);
+}
+
+/*
+UM_INITPOPUP
+wParam = (WPARAM)(HWND)hPopUpWindow (but this is useless, since I'll directly send it to your hPopUpWindow
+lParam = 0.
+This message is sent to the PopUp when its creation has been finished, so POPUPDATA (and thus your PluginData) is reachable.
+Catch it if you needed to catch WM_CREATE or WM_INITDIALOG, which you'll never ever get in your entire popup-life.
+Return value: if you process this message, return 0. If you don't process it, return 0. Do whatever you like ;-)
+*/
+#define UM_INITPOPUP (WM_USER + 0x0202)
+
+/*
+wParam = (WPARAM)(HWND)hPopUpWindow
+lParam = (LPARAM)(char*)lpzNewText
+returns: > 0 for success, -1 for failure, 0 if the failure is due to second line not being shown. (but you could call PUIsSecondLineShown() before changing the text...)
+Changes the text displayed in the second line of the popup.
+*/
+#define MS_POPUP_CHANGETEXT "PopUp/Changetext"
+static int __inline PUChangeText(HWND hWndPopUp, LPCTSTR lpzNewText) {
+ return (int)CallService(MS_POPUP_CHANGETEXT, (WPARAM)hWndPopUp, (LPARAM)lpzNewText);
+}
+
+/*
+wParam = (WPARAM)(HWND)hPopUpWindow
+lParam = (LPARAM)(POPUPDATAEX*)newData
+Changes the entire popup
+*/
+#define MS_POPUP_CHANGE "PopUp/Change"
+static int __inline PUChange(HWND hWndPopUp, POPUPDATAEX *newData) {
+ return (int)CallService(MS_POPUP_CHANGE, (WPARAM)hWndPopUp, (LPARAM)newData);
+}
+
+/*
+This is mainly for developers.
+Shows a warning message in a PopUp. It's useful if you need a "MessageBox" like function, but you don't want a modal window (which will interfere with a DialogProcedure. MessageBox steals focus and control, this one not.
+wParam = (char*) lpzMessage
+lParam = 0;
+Returns: 0 if the popup was shown, -1 in case of failure.
+*/
+#define SM_WARNING 0x01 //Triangle icon.
+#define SM_NOTIFY 0x02 //Exclamation mark icon.
+#define MS_POPUP_SHOWMESSAGE "PopUp/ShowMessage"
+
+static int __inline PUShowMessage(char* lpzText, BYTE kind) {
+ return (int)CallService(MS_POPUP_SHOWMESSAGE, (WPARAM)lpzText,(LPARAM)kind);
+}
+
+/*
+Each skinned popup (e.g. with colorBack == POPUP_USE_SKINNED_BG) should have
+class set. Then you can choose separate skin for each class (for example, you
+can create separate class for your plugin and use it for all ypu popups. User
+would became able to choose skin for your popups independently from others)
+
+You have to register popup class before using it. To do so call "PopUp/AddClass"
+with lParam = (LPARAM)(const char *)popUpClassName.
+
+All class names are translated (via Translate()) before being added to list. You
+should use english names for them.
+
+There are three predefined classes and one for backward compatability.
+
+Note that you can add clases after popup wal loaded, e.g. you shoul intercept
+ME_SYSTEM_MODULESLOADED event
+*/
+#define MS_POPUP_ADDCLASS "PopUp/AddClass"
+#define POPUP_CLASS_DEFAULT "Default"
+#define POPUP_CLASS_WARNING "Warning"
+#define POPUP_CLASS_NOTIFY "Notify"
+#define POPUP_CLASS_OLDAPI "PopUp 1.0.1.x compatability" // for internal purposes
+
+static void __inline PUAddClass(const char *lpzClass){
+ CallService(MS_POPUP_ADDCLASS, 0, (LPARAM)lpzClass);
+}
+
+#endif
diff --git a/miranda-wine/include/m_protocols.h b/miranda-wine/include/m_protocols.h
new file mode 100644
index 0000000..30806d7
--- /dev/null
+++ b/miranda-wine/include/m_protocols.h
@@ -0,0 +1,288 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 module was created in v0.1.1.0
+
+#ifndef M_PROTOCOLS_H__
+#define M_PROTOCOLS_H__ 1
+
+#include "statusmodes.h"
+
+//call a specific protocol service. See the PS_ constants in m_protosvc.h
+__inline static int CallProtoService(const char *szModule,const char *szService,WPARAM wParam,LPARAM lParam)
+{
+ char str[MAXMODULELABELLENGTH];
+ strcpy(str,szModule);
+ strcat(str,szService);
+ return CallService(str,wParam,lParam);
+}
+
+//send a general request through the protocol chain for a contact
+//wParam=0
+//lParam=(LPARAM)(CCSDATA*)&ccs
+//returns the value as documented in the PS_ definition (m_protosvc.h)
+typedef struct {
+ HANDLE hContact;
+ const char *szProtoService; //a PS_ constant
+ WPARAM wParam;
+ LPARAM lParam;
+} CCSDATA;
+#define MS_PROTO_CALLCONTACTSERVICE "Proto/CallContactService"
+__inline static int CallContactService(HANDLE hContact,const char *szProtoService,WPARAM wParam,LPARAM lParam)
+{
+ CCSDATA ccs;
+ ccs.hContact=hContact;
+ ccs.szProtoService=szProtoService;
+ ccs.wParam=wParam;
+ ccs.lParam=lParam;
+ return CallService(MS_PROTO_CALLCONTACTSERVICE,0,(LPARAM)&ccs);
+}
+
+//a general network 'ack'
+//wParam=0
+//lParam=(LPARAM)(ACKDATA*)&ack
+//Note that just because definitions are here doesn't mean they will be sent.
+//Read the documentation for the function you are calling to see what replies
+//you will receive.
+typedef struct {
+ int cbSize;
+ const char *szModule; //the name of the protocol module which initiated this ack
+ HANDLE hContact;
+ int type; //an ACKTYPE_ constant
+ int result; //an ACKRESULT_ constant
+ HANDLE hProcess; //a caller-defined process code
+ LPARAM lParam; //caller-defined extra info
+} ACKDATA;
+#define ACKTYPE_MESSAGE 0
+#define ACKTYPE_URL 1
+#define ACKTYPE_FILE 2
+#define ACKTYPE_CHAT 3
+#define ACKTYPE_AWAYMSG 4
+#define ACKTYPE_AUTHREQ 5
+#define ACKTYPE_ADDED 6
+#define ACKTYPE_GETINFO 7
+#define ACKTYPE_SETINFO 8
+#define ACKTYPE_LOGIN 9
+#define ACKTYPE_SEARCH 10
+#define ACKTYPE_NEWUSER 11
+#define ACKTYPE_STATUS 12
+#define ACKTYPE_CONTACTS 13 //send/recv of contacts
+#define ACKTYPE_AVATAR 14 //send/recv of avatars from a protocol
+#define ACKRESULT_SUCCESS 0
+#define ACKRESULT_FAILED 1
+//'in progress' result codes:
+#define ACKRESULT_CONNECTING 100
+#define ACKRESULT_CONNECTED 101
+#define ACKRESULT_INITIALISING 102
+#define ACKRESULT_SENTREQUEST 103 //waiting for reply...
+#define ACKRESULT_DATA 104 //blob of file data sent/recved, or search result
+#define ACKRESULT_NEXTFILE 105 //file transfer went to next file
+#define ACKRESULT_FILERESUME 106 //a file is about to be received, see PS_FILERESUME
+#define ACKRESULT_DENIED 107 //a file send has been denied
+#define ACKRESULT_STATUS 108 //an ack or a series of acks to do with a task have a status change
+#define ME_PROTO_ACK "Proto/Ack"
+
+// v0.3.2+: When result is ACKRESULT_FAILED or ACKRESULT_DENIED, lParam can point to
+// a human readable string with an explanation. For example: "The message was too
+// long to be delivered". If no error message is specified, lParam must be NULL.
+// Right now only explanations from ACKTYPE_MESSAGE is shown.
+
+//when type==ACKTYPE_FILE && (result==ACKRESULT_DATA || result==ACKRESULT_FILERESUME),
+//lParam points to this
+typedef struct {
+ int cbSize;
+ HANDLE hContact;
+ int sending; //true if sending, false if receiving
+ char **files;
+ int totalFiles;
+ int currentFileNumber;
+ unsigned long totalBytes;
+ unsigned long totalProgress;
+ char *workingDir;
+ char *currentFile;
+ unsigned long currentFileSize;
+ unsigned long currentFileProgress;
+ unsigned long currentFileTime; //as seconds since 1970
+} PROTOFILETRANSFERSTATUS;
+
+//Enumerate the currently running protocols
+//wParam=(WPARAM)(int*)&numberOfProtocols
+//lParam=(LPARAM)(PROTOCOLDESCRIPTOR***)&ppProtocolDescriptors
+//Returns 0 on success, nonzero on failure
+//Neither wParam nor lParam may be NULL
+//The list returned by this service is the protocol modules currently installed
+//and running. It is not the complete list of all protocols that have ever been
+//installed.
+//Note that a protocol module need not be an interface to an Internet server,
+//they can be encryption and loads of other things, too.
+//And yes, before you ask, that is triple indirection. Deal with it.
+//Access members using ppProtocolDescriptors[index]->element
+typedef struct {
+ int cbSize;
+ char *szName; //unique name of the module
+ int type; //module type, see PROTOTYPE_ constants
+} PROTOCOLDESCRIPTOR;
+// v0.3.3+:
+//
+// For recv, it will go from lower to higher, so in this case:
+// check ignore, decrypt (encryption), translate
+//
+// For send, it will go translate, encrypt, ignore(??), send
+//
+// The DB will store higher numbers here, LOWER in the protocol chain, and lower numbers
+// here HIGHER in the protocol chain
+//
+#define PROTOTYPE_IGNORE 50 // added during v0.3.3
+#define PROTOTYPE_PROTOCOL 1000
+#define PROTOTYPE_ENCRYPTION 2000
+#define PROTOTYPE_FILTER 3000
+#define PROTOTYPE_TRANSLATION 4000
+#define PROTOTYPE_OTHER 10000 //avoid using this if at all possible
+#define MS_PROTO_ENUMPROTOCOLS "Proto/EnumProtocols"
+
+//determines if a protocol module is loaded or not
+//wParam=0
+//lParam=(LPARAM)(const char*)szName
+//Returns a pointer to the PROTOCOLDESCRIPTOR if the protocol is loaded, or
+//NULL if it isn't.
+#define MS_PROTO_ISPROTOCOLLOADED "Proto/IsProtocolLoaded"
+
+//gets the network-level protocol associated with a contact
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=0
+//Returns a char* pointing to the asciiz name of the protocol or NULL if the
+//contact has no protocol. There is no need to free() it or anything.
+//This is the name of the module that actually accesses the network for that
+//contact.
+#define MS_PROTO_GETCONTACTBASEPROTO "Proto/GetContactBaseProto"
+
+//determines whether the specified contact has the given protocol in its chain
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=(LPARAM)(const char*)szName
+//Returns nonzero if it does and 0 if it doesn't
+#define MS_PROTO_ISPROTOONCONTACT "Proto/IsProtoOnContact"
+
+#define PROTOTYPE_SELFTYPING_OFF 0
+#define PROTOTYPE_SELFTYPING_ON 1
+//This service is for notifying protocols that the user is typing a message v0.3.3+
+//in a message dialog.
+//This is typically sent by a message dialog when a user in the clist is typing.
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=(LPARAM)(int)typing state
+//NOTE: Only protocols should generally call this service
+#define MS_PROTO_SELFISTYPING "Proto/SelfIsTyping"
+
+#define PROTOTYPE_CONTACTTYPING_OFF 0
+#define PROTOTYPE_CONTACTTYPING_INFINITE 2147483647
+//This service is for notifying message dialogs/other plugins of a user typing. v0.3.3+
+//This is typically sent by a protocol when a user in the clist is typing.
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=(LPARAM)(int)time (secs)
+//NOTE: The time in seconds is used to tell a message dialog (or other plugin)
+//how long to display its notification. If time is 0, then notification
+//of typing ends.
+//NOTE: Only protocols should generally call this service
+#define MS_PROTO_CONTACTISTYPING "Proto/ContactIsTyping"
+
+//This hook notifies when a user is typing. If a message dialog supports sending v0.3.3+
+//typing notifications it should hook this event and fire the
+//ProtoService PSS_USERISTYPING to the contacts protocol *after* verifying
+//that the hContact is not NULL and the the user wishes to send notifications
+//to this user (checked visibility, individual typing blocking, etc).
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=(LPARAM)(int)typing state
+#define ME_PROTO_CONTACTISTYPING "Proto/ContactIsTypingEvent"
+
+
+/* -------------- avatar support ---------------------
+
+First a protocol must report it supports PF4_AVATARS via PS_GETCAPS, secondly
+it will return the following acks for certain events, the protocol must use
+ProtoBroadcastAck(), listeners must hook ME_PROTO_ACK, note that lParam = ACKDATA*
+
+*/
+
+/*
+
+ The following ACKs MUST be sent in order of .result via ProtoBroadcastAck()
+
+ .szModule = protocol module
+ .hContact = contact the avatar is for, or 0 if its for the user
+ .type = ACKTYPE_AVATAR
+ .result = ACKRESULT_CONNECTING, ACKRESULT_CONNECTED, ACKRESULT_SENTREQUEST, ACKRESULT_DATA
+ .hProcess = protocol specific
+ .lParam = 0
+
+ Once the transfer is complete the following ACKs MUST be sent by the protocol
+
+ .result = ACKRESULT_SUCCESS or ACKRESULT_FAILED
+ .hProcess = (HANDLE) &PROTO_AVATAR_INFORMATION
+ .lParam = 0;
+
+ Anytime before or during the ack or series of acks ACKRESULT_STATUS maybe sent, this might
+ be sent a long while before anything else happens (or after anything happening) For avatars
+ it allows callers to identify status information to do with the avatar, including the time
+ before background transport has been created, so that you know an avatar will be exchanged
+ sometime in the future.
+
+ When ACKRESULT_STATUS, hProcess is the result code - the value of this is protocol dependent,
+ See protocol documentation to do with avatars for what codes are defined and what they mean.
+
+*/
+
+#define PA_FORMAT_UNKNOWN 0 // the protocol can not determine much about the "bitmap"
+#define PA_FORMAT_PNG 1 // the image is PNG
+#define PA_FORMAT_JPEG 2
+#define PA_FORMAT_ICON 3
+#define PA_FORMAT_BMP 4
+#define PA_FORMAT_GIF 5
+#define PA_FORMAT_SWF 6
+#define PA_FORMAT_XML 7
+
+typedef struct {
+ int cbSize; // sizeof()
+ HANDLE hContact; // this might have to be set by the caller too
+ int format; // PA_FORMAT_*
+ char filename[MAX_PATH]; // full path to filename which contains the avatar
+} PROTO_AVATAR_INFORMATION;
+
+#define GAIF_FORCE 1 // force an update of the avatar if there is none
+
+#define GAIR_SUCCESS 0 // information about the avatar has been returned
+#define GAIR_WAITFOR 1 // you must hook ME_PROTO_ACK and wait for replies about avatar status
+#define GAIR_NOAVATAR 2 // sorry, this contact has no avatars
+
+/*
+ wParam : GAIF_*
+ lParam : (LPARAM) &PROTO_AVATAR_INFORMATION
+ Affect : Make a request to the protocol to return information about a hContact's avatar (or main user)
+ it can return information, tell you there is none, or if forced start requesting an avatar.
+ Note:
+ Version: 0.3.4+ (2004/09/13)
+*/
+#define PS_GETAVATARINFO "/GetAvatarInformation"
+
+
+#endif // M_PROTOCOLS_H
+
+
diff --git a/miranda-wine/include/m_protomod.h b/miranda-wine/include/m_protomod.h
new file mode 100644
index 0000000..9ab90c1
--- /dev/null
+++ b/miranda-wine/include/m_protomod.h
@@ -0,0 +1,134 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 module was created in v0.1.1.0
+
+//this header file is for the use of protocol modules only. Other users should
+//use the functions exposed in m_protocols.h and m_protosvc.h
+
+#ifndef M_PROTOMOD_H__
+#define M_PROTOMOD_H__ 1
+
+#include "m_protocols.h"
+
+//notify the protocol manager that you're around
+//wParam=0
+//lParam=(PROTOCOLDESCRIPTOR*)&descriptor
+//returns 0 on success, nonzero on failure
+//This service must be called in your module's Load() routine.
+//descriptor.type can be a value other than the PROTOTYPE_ constants specified
+//above to provide more precise positioning information for the contact
+//protocol lists. It is strongly recommended that you give values relative to
+//the constants, however, by adding or subtracting small integers (<=100).
+//PROTOTYPE_PROTOCOL modules must not do this. The value must be exact.
+//See MS_PROTO_ENUMPROTOCOLS for more notes.
+#define MS_PROTO_REGISTERMODULE "Proto/RegisterModule"
+
+//adds the specified protocol module to the chain for a contact
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=(LPARAM)(const char*)szName
+//returns 0 on success, nonzero on failure
+//The module is added in the correct position according to the type given when
+//it was registered.
+#define MS_PROTO_ADDTOCONTACT "Proto/AddToContact"
+
+//removes the specified protocol module from the chain for a contact
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=(LPARAM)(const char*)szName
+//returns 0 on success, nonzero on failure
+#define MS_PROTO_REMOVEFROMCONTACT "Proto/RemoveFromContact"
+
+//Create a protocol service
+//Protocol services are called with wParam and lParam as standard if they are
+//to be called with CallProtoService() (as PS_ services are)
+//If they are called with CallContactService() (PSS_ and PSR_ services) then
+//they are called with lParam=(CCSDATA*)&ccs and wParam an opaque internal
+//reference that should be passed unchanged to MS_PROTO_CHAIN*.
+__inline static HANDLE CreateProtoServiceFunction(const char *szModule,const char *szService,MIRANDASERVICE serviceProc)
+{
+ char str[MAXMODULELABELLENGTH];
+ strcpy(str,szModule);
+ strcat(str,szService);
+ return CreateServiceFunction(str,serviceProc);
+}
+
+//Call the next service in the chain for this send operation
+//wParam=wParam
+//lParam=lParam
+//The return value should be returned immediately
+//wParam and lParam should be passed as the parameters that your service was
+//called with. wParam must remain untouched but lParam is a CCSDATA structure
+//that can be copied and modified if needed.
+//Typically, the last line of any chaining protocol function is
+//return CallService(MS_PROTO_CHAINSEND,wParam,lParam);
+#define MS_PROTO_CHAINSEND "Proto/ChainSend"
+
+//Call the next service in the chain for this receive operation
+//wParam=wParam
+//lParam=lParam
+//The return value should be returned immediately
+//wParam and lParam should be passed as the parameters that your service was
+//called with. wParam must remain untouched but lParam is a CCSDATA structure
+//that can be copied and modified if needed.
+//When being initiated by the network-access protocol module, wParam should be
+//zero.
+//Thread safety: ms_proto_chainrecv is completely thread safe since 0.1.2.0
+//Calls to it are translated to the main thread and passed on from there. The
+//function will not return until all callees have returned, irrepective of
+//differences between threads the functions are in.
+#define MS_PROTO_CHAINRECV "Proto/ChainRecv"
+
+//Broadcast a ME_PROTO_ACK event
+//wParam=0
+//lParam=(LPARAM)(ACKDATA*)&ack
+//returns the return value of the notifyeventhooks() call
+//Thread safety: me_proto_ack is completely thread safe since 0.1.2.0
+//See the notes in core/modules.h under NotifyEventHooks()
+#define MS_PROTO_BROADCASTACK "Proto/BroadcastAck"
+__inline static int ProtoBroadcastAck(const char *szModule,HANDLE hContact,int type,int result,HANDLE hProcess,LPARAM lParam)
+{
+ ACKDATA ack={0};
+ ack.cbSize=sizeof(ACKDATA);
+ ack.szModule=szModule; ack.hContact=hContact;
+ ack.type=type; ack.result=result;
+ ack.hProcess=hProcess; ack.lParam=lParam;
+ return CallService(MS_PROTO_BROADCASTACK,0,(LPARAM)&ack);
+}
+
+/* -- Added during 0.3.4 (2004/09/27) development! -----
+*/
+
+/*
+ wParam: (HANDLE)hContact
+ lParam: 0
+ Affect: Given a hContact, return the protocol that is registered for it, or NULL if no such protocol exists,
+ the returned string does not have to be freed and is valid even for multiple threads.
+ Note: Prior to 2004/09/28 this service WAS NOT THREAD SAFE and was slower
+ Note: Prior to 2004/09/28 this service would return NULL for a hContact if the protocol module
+ associated with the hContact was not currently loaded, no such check is performed now.
+ Version: 0.3.4 (2004/09/28)
+*/
+#define MS_PROTODIR_PROTOFROMCONTACT MS_PROTO_GETCONTACTBASEPROTO
+
+#endif // M_PROTOMOD_H__
+
+
diff --git a/miranda-wine/include/m_protosvc.h b/miranda-wine/include/m_protosvc.h
new file mode 100644
index 0000000..9ef43df
--- /dev/null
+++ b/miranda-wine/include/m_protosvc.h
@@ -0,0 +1,635 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 module was created in v0.1.1.0
+
+//none of these services should be used on their own (ie using CallService,
+//CreateServiceFunction(), etc), hence the PS_ prefix. Instead use the services
+//exposed in m_protocols.h
+
+#ifndef M_PROTOSVC_H__
+#define M_PROTOSVC_H__ 1
+
+#include "m_protocols.h"
+
+/*************************** NON-CONTACT SERVICES ************************/
+//these should be called with CallProtoService()
+
+//Get the capability flags of the module.
+//wParam=flagNum
+//lParam=0
+//Returns a bitfield corresponding to wParam. See the #defines below
+//Should return 0 for unknown values of flagNum
+//Non-network-access modules should return flags to represent the things they
+//actually actively use, not the values that it is known to pass through
+//correctly
+#define PFLAGNUM_1 1
+#define PF1_IMSEND 0x00000001 //supports IM sending
+#define PF1_IMRECV 0x00000002 //supports IM receiving
+#define PF1_IM (PF1_IMSEND|PF1_IMRECV)
+#define PF1_URLSEND 0x00000004 //supports separate URL sending
+#define PF1_URLRECV 0x00000008 //supports separate URL receiving
+#define PF1_URL (PF1_URLSEND|PF1_URLRECV)
+#define PF1_FILESEND 0x00000010 //supports file sending
+#define PF1_FILERECV 0x00000020 //supports file receiving
+#define PF1_FILE (PF1_FILESEND|PF1_FILERECV)
+#define PF1_MODEMSGSEND 0x00000040 //supports broadcasting away messages
+#define PF1_MODEMSGRECV 0x00000080 //supports reading others' away messages
+#define PF1_MODEMSG (PF1_MODEMSGSEND|PF1_MODEMSGRECV)
+#define PF1_SERVERCLIST 0x00000100 //contact lists are stored on the server, not locally. See notes below
+#define PF1_AUTHREQ 0x00000200 //will get authorisation requests for some or all contacts
+#define PF1_ADDED 0x00000400 //will get 'you were added' notifications
+#define PF1_VISLIST 0x00000800 //has an invisible list
+#define PF1_INVISLIST 0x00001000 //has a visible list for when in invisible mode
+#define PF1_INDIVSTATUS 0x00002000 //supports setting different status modes to each contact
+#define PF1_EXTENSIBLE 0x00004000 //the protocol is extensible and supports plugin-defined messages
+#define PF1_PEER2PEER 0x00008000 //supports direct (not server mediated) communication between clients
+#define PF1_NEWUSER 0x00010000 //supports creation of new user IDs
+#define PF1_CHAT 0x00020000 //has a realtime chat capability
+#define PF1_INDIVMODEMSG 0x00040000 //supports replying to a mode message request with different text depending on the contact requesting
+#define PF1_BASICSEARCH 0x00080000 //supports a basic user searching facility
+#define PF1_EXTSEARCH 0x00100000 //supports one or more protocol-specific extended search schemes
+#define PF1_CANRENAMEFILE 0x00200000 //supports renaming of incoming files as they are transferred
+#define PF1_FILERESUME 0x00400000 //can resume broken file transfers, see PS_FILERESUME below
+#define PF1_ADDSEARCHRES 0x00800000 //can add search results to the contact list
+#define PF1_CONTACTSEND 0x01000000 //can send contacts to other users
+#define PF1_CONTACTRECV 0x02000000 //can receive contacts from other users
+#define PF1_CONTACT (PF1_CONTACTSEND|PF1_CONTACTRECV)
+#define PF1_CHANGEINFO 0x04000000 //can change our user information stored on server
+#define PF1_SEARCHBYEMAIL 0x08000000 //supports a search by e-mail feature
+#define PF1_USERIDISEMAIL 0x10000000 //set if the uniquely identifying field of the network is the e-mail address
+#define PF1_SEARCHBYNAME 0x20000000 //supports searching by nick/first/last names
+#define PF1_EXTSEARCHUI 0x40000000 //has a dialog box to allow searching all the possible fields
+#define PF1_NUMERICUSERID 0x80000000 //the unique user IDs for this protocol are numeric
+
+#define PFLAGNUM_2 2 //the status modes that the protocol supports
+#define PF2_ONLINE 0x00000001 //an unadorned online mode
+#define PF2_INVISIBLE 0x00000002
+#define PF2_SHORTAWAY 0x00000004 //Away on ICQ, BRB on MSN
+#define PF2_LONGAWAY 0x00000008 //NA on ICQ, Away on MSN
+#define PF2_LIGHTDND 0x00000010 //Occupied on ICQ, Busy on MSN
+#define PF2_HEAVYDND 0x00000020 //DND on ICQ
+#define PF2_FREECHAT 0x00000040
+#define PF2_OUTTOLUNCH 0x00000080
+#define PF2_ONTHEPHONE 0x00000100
+#define PF2_IDLE 0x00000200 //added during 0.3.4 (2004/09/13)
+
+//the status modes that the protocol supports
+//away-style messages for. Uses the PF2_ flags.
+// PFLAGNUM_3 is implemented by protocol services that support away messages
+// there may be no support and 0 will be returned, if there is
+// support it will consist of a set of PF2_* bits
+#define PFLAGNUM_3 3
+
+// given a status will return what bit flags to test for
+static __inline unsigned long Proto_Status2Flag(int status)
+{
+ switch(status) {
+ case ID_STATUS_ONLINE: return PF2_ONLINE;
+ case ID_STATUS_OFFLINE: return 0;
+ case ID_STATUS_INVISIBLE: return PF2_INVISIBLE;
+ case ID_STATUS_OUTTOLUNCH: return PF2_OUTTOLUNCH;
+ case ID_STATUS_ONTHEPHONE: return PF2_ONTHEPHONE;
+ case ID_STATUS_AWAY: return PF2_SHORTAWAY;
+ case ID_STATUS_NA: return PF2_LONGAWAY;
+ case ID_STATUS_OCCUPIED: return PF2_LIGHTDND;
+ case ID_STATUS_DND: return PF2_HEAVYDND;
+ case ID_STATUS_FREECHAT: return PF2_FREECHAT;
+ case ID_STATUS_IDLE: return PF2_IDLE;
+ }
+ return 0;
+}
+
+#define PFLAGNUM_4 4 //misc options
+#define PF4_FORCEAUTH 0x00000001 // forces auth requests to be sent when adding users
+#define PF4_FORCEADDED 0x00000002 // forces "you were added" requests to be sent
+#define PF4_NOCUSTOMAUTH 0x00000004 // protocol doesn't support custom auth text (doesn't show auth text box)
+#define PF4_SUPPORTTYPING 0x00000008 // protocol supports user is typing messages v0.3.3+
+#define PF4_SUPPORTIDLE 0x00000010 // protocol understands idle, added during v0.3.4+ (2004/09/13)
+#define PF4_AVATARS 0x00000020 // protocol has avatar support, added during v0.3.4 (2004/09/13)
+
+#define PFLAG_UNIQUEIDTEXT 100 //returns a static buffer of text describing the unique field by which this protocol identifies users (already translated), or NULL
+
+#define PFLAG_MAXCONTACTSPERPACKET 200 //v0.1.2.2+: returns the maximum number of contacts which can be sent in a single PSS_CONTACTS.
+
+#define PFLAG_UNIQUEIDSETTING 300 // returns the setting name of where the unique id is stored
+
+#define PFLAG_MAXLENOFMESSAGE 400 // v0.3.2+: return the maximum length of an instant message, lParam=(LPARAM)hContact
+
+/*
+
+ A protocol might not support this cap, it allows a protocol to say that PFLAGNUM_2 is for
+ statuses contacts supports, and that PFLAGNUM_5 is for statuses a protocol can SET TO ITSELF,
+ if this is not replied to, then PFLAGNUM_2 is alone in telling you which statuses a protocol
+ can set to and what statuses a contact can set to as well.
+
+ E.g. A protocol might report 'wireless' users but a login of the protocol from Miranda can
+ not set itself to 'wireless' so PFLAGNUM_2 would return PF2_ONTHEPHONE and PFLAGNUM_5 would
+ return PF2_ONTHEPHONE as well, this means "I will get contacts who are on the phone but you can
+ not set on the phone" and so on.
+
+ Do note that the reply here is a NEGATION of bitflags reported for PFLAGNUM_2, e.g. returning
+ PF2_ONTHEPHONE for PFLAGNUM_2 and returning the same for PFLAGNUM_5 says that you DO NOT SUPPORT
+ PF2_ONTHEPHONE for the user to PS_SETSTATUS to, but you will expect other contacts to have
+ that status, e.g. you can get onthephone for users but can't go online with onthephone.
+
+ The same PF2_* status flags are used in the reply.
+
+Added during 0.3.4 (2004/09/14)
+*/
+#define PFLAGNUM_5 5
+
+/* Deleting contacts from protocols that store the contact list on the server:
+If a contact is deleted while the protocol is online, it is expected that the
+protocol will have hooked me_db_contact_deleted and take the appropriate
+action by itself.
+If a contact is deleted while the protocol is offline, the contact list will
+display a message to the user about the problem, and set the byte setting
+"CList"/"Delete" to 1. Each time such a protocol changes status from offline
+or connecting to online the contact list will check for contacts with this
+flag set and delete them at that time. Your hook for me_db_contact_deleted
+will pick this up and everything will be good.
+*/
+#define PS_GETCAPS "/GetCaps"
+
+//Get a human-readable name for the protocol
+//wParam=cchName
+//lParam=(LPARAM)(char*)szName
+//Returns 0 on success, nonzero on failure
+//cchName is the number of characters in the buffer szName
+//This should be translated before being returned
+//Some example strings are:
+//"ICQ", "AIM", "RSA-1024 Encryption"
+#define PS_GETNAME "/GetName"
+
+//Loads one of the protocol-specific icons
+//wParam=whichIcon
+//lParam=0
+//Returns the HICON, or NULL on failure
+//The returned HICON must be DestroyIcon()ed.
+//The UI should overlay the online icon with a further UI-specified icon to
+//represent the exact status mode.
+#define PLI_PROTOCOL 1 //An icon representing the protocol (eg the multicoloured flower for ICQ)
+#define PLI_ONLINE 2 //Online state icon for that protocol (eg green flower for ICQ)
+#define PLI_OFFLINE 3 //Offline state icon for that protocol (eg red flower for ICQ)
+#define PLIF_LARGE 0 //OR with one of the above to get the large (32x32 by default) icon
+#define PLIF_SMALL 0x10000 //OR with one of the above to get the small (16x16 by default) icon
+#define PS_LOADICON "/LoadIcon"
+
+//Change the protocol's status mode
+//wParam=newMode, from ui/contactlist/statusmodes.h
+//lParam=0
+//returns 0 on success, nonzero on failure
+//Will send an ack with:
+//type=ACKTYPE_STATUS, result=ACKRESULT_SUCCESS, hProcess=(HANDLE)previousMode, lParam=newMode
+//when the change completes. This ack is sent for all changes, not just ones
+//caused by calling this function.
+//Note that newMode can be ID_STATUS_CONNECTING<=newMode<ID_STATUS_CONNECTING+
+//MAX_CONNECT_RETRIES to signify that it's connecting and it's the nth retry.
+//Protocols are initially always in offline mode.
+//Non-network-level protocol modules do not have the concept of a status and
+//should leave this service unimplemented
+//If a protocol doesn't support the specific status mode, it should pick the
+//closest one that it does support, and change to that.
+//If the new mode requires that the protocol switch from offline to online then
+//it will do so, but errors will be reported in the form of an additional ack:
+//type=ACKTYPE_LOGIN, result=ACKRESULT_FAILURE, hProcess=NULL, lParam=LOGINERR_
+// (added during 0.3.4.3) the protocol will send LOGINERR_OTHERLOCATION if the login
+// was disconnected because of a login at another location
+#define LOGINERR_WRONGPASSWORD 1
+#define LOGINERR_NONETWORK 2
+#define LOGINERR_PROXYFAILURE 3
+#define LOGINERR_BADUSERID 4
+#define LOGINERR_NOSERVER 5
+#define LOGINERR_TIMEOUT 6
+#define LOGINERR_WRONGPROTOCOL 7
+#define LOGINERR_OTHERLOCATION 8
+//protocols may define more error codes starting at 1000
+#define PS_SETSTATUS "/SetStatus"
+
+//Sets the status-mode specific message for yourself
+//wParam=status mode
+//lParam=(LPARAM)(const char*)szMessage
+//Returns 0 on success, nonzero on failure
+//Note that this service will not be available unless PF1_MODEMSGSEND is set
+//and PF1_INDIVMODEMSG is *not* set.
+//If PF1_INDIVMODEMSG is set, then see PSS_AWAYMSG for details of
+//the operation of away messages
+//Protocol modules must support szMessage=NULL. It may either mean to use an
+//empty message, or (preferably) to not reply at all to any requests
+#define PS_SETAWAYMSG "/SetAwayMsg"
+
+//Get the status mode that a protocol is currently in
+//wParam=lParam=0
+//Returns the status mode
+//Non-network-level protocol modules do not have the concept of a status and
+//should leave this service unimplemented
+#define PS_GETSTATUS "/GetStatus"
+
+//Allow somebody to add us to their contact list
+//wParam=(WPARAM)(HANDLE)hDbEvent
+//lParam=0
+//Returns 0 on success, nonzero on failure
+//Auth requests come in the form of an event added to the database for the NULL
+//user. The form is:
+//DWORD protocolSpecific
+//ASCIIZ nick, firstName, lastName, e-mail, requestReason
+//hDbEvent must be the handle of such an event
+//One or more fields may be empty if the protocol doesn't support them
+#define PS_AUTHALLOW "/Authorize"
+
+//Deny an authorisation request
+//wParam=(WPARAM)(HANDLE)hDbEvent
+//lParam=(LPARAM)(const char*)szReason
+//Returns 0 on success, nonzero on failure
+//Protocol modules must be able to cope with szReason=NULL
+#define PS_AUTHDENY "/AuthDeny"
+
+// Send a "You were added" event
+// wParam=lParam=0
+// Returns 0 on success, nonzero on failure
+#define PSS_ADDED "/YouWereAdded"
+
+//Send a basic search request
+//wParam=0
+//lParam=(LPARAM)(const char*)szId
+//Returns a handle for the search, or zero on failure
+//All protocols identify users uniquely by a single field. This service will
+//search by that field.
+//Note that if users are identified by an integer (eg ICQ) szId should be a
+//string containing that integer, not the integer itself.
+//All search replies (even protocol-specific extended searches) are replied by
+//means of a series of acks:
+//result acks, one of more of:
+//type=ACKTYPE_SEARCH, result=ACKRESULT_DATA, lParam=(LPARAM)(PROTOSEARCHRESULT*)&psr
+//ending ack:
+//type=ACKTYPE_SEARCH, result=ACKRESULT_SUCCESS, lParam=0
+//Note that the pointers in the structure are not guaranteed to be valid after
+//the ack is complete.
+typedef struct {
+ int cbSize;
+ char *nick;
+ char *firstName;
+ char *lastName;
+ char *email;
+ char reserved[16];
+ //Protocols may extend this structure with extra members at will and supply
+ //a larger cbSize to reflect the new information, but they must not change
+ //any elements above this comment
+ //The 'reserved' field is part of the basic structure, not space to
+ //overwrite with protocol-specific information.
+ //If modules do this, they should take steps to ensure that information
+ //they put there will be retained by anyone trying to save this structure.
+} PROTOSEARCHRESULT;
+#define PS_BASICSEARCH "/BasicSearch"
+
+//Search for users by e-mail address v0.1.2.1+
+//wParam=0
+//lParam=(LPARAM)(char*)szEmail
+//Returns a HANDLE to the search, or NULL on failure
+//Results are returned as for PS_BASICSEARCH.
+//This function is only available if the PF1_SEARCHBYEMAIL capability is set
+//If the PF1_USERIDISEMAIL capability is set then this function and
+//PS_BASICSEARCH should have the same result (and it's best if they are the
+//same function).
+#define PS_SEARCHBYEMAIL "/SearchByEmail"
+
+//Search for users by name v0.1.2.1+
+//wParam=0
+//lParam=(LPARAM)(PROTOSEARCHBYNAME*)&psbn
+//Returns a HANDLE to the search, or NULL on failure
+//Results are returned as for PS_BASICSEARCH.
+//This function is only available if the PF1_SEARCHBYNAME capability is set
+typedef struct {
+ char *pszNick;
+ char *pszFirstName;
+ char *pszLastName;
+} PROTOSEARCHBYNAME;
+#define PS_SEARCHBYNAME "/SearchByName"
+
+//Create the advanced search dialog box v0.1.2.1+
+//wParam=0
+//lParam=(HWND)hwndOwner
+//Returns a HWND, or NULL on failure
+//This function is only available if the PF1_EXTSEARCHUI capability is set
+//Advanced search is very protocol-specific so it is left to the protocol
+//itself to supply a dialog containing the options. This dialog should not
+//have a title bar and contain only search fields. The rest of the UI is
+//supplied by Miranda.
+//The dialog should be created with CreateDialog() or its kin and still be
+//hidden when this function returns.
+//The dialog will be destroyed when the find/add dialog is closed.
+#define PS_CREATEADVSEARCHUI "/CreateAdvSearchUI"
+
+//Search using the advanced search dialog v0.1.2.1+
+//wParam=0
+//lParam=(LPARAM)(HWND)hwndAdvancedSearchDlg
+//Returns a HANDLE to the search, or NULL on failure
+//Results are returned as for PS_BASICSEARCH.
+//This function is only available if the PF1_EXTSEARCHUI capability is set
+#define PS_SEARCHBYADVANCED "/SearchByAdvanced"
+
+//Adds a search result to the contact list
+//wParam=flags
+//lParam=(LPARAM)(PROTOSEARCHRESULT*)&psr
+//Returns a HANDLE to the new contact, or NULL on failure
+//psr must be a result returned by a search function, since the extended
+//information past the end of the official structure may contain important
+//data required by the protocol.
+//The protocol library should not allow duplicate contacts to be added, but if
+//such a request is received it should return the original hContact, and do the
+//appropriate thing with the temporary flag (ie newflag=(oldflag&thisflag))
+#define PALF_TEMPORARY 1 //add the contact temporarily and invisibly, just to get user info or something
+#define PS_ADDTOLIST "/AddToList"
+
+//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.
+#define PS_ADDTOLISTBYEVENT "/AddToListByEvent"
+
+//Changes our user details as stored on the server v0.1.2.0+
+//wParam=infoType
+//lParam=(LPARAM)(void*)pInfoData
+//Returns a HANDLE to the change request, or NULL on failure
+//The details information that is stored on the server is very protocol-
+//specific, so this service just supplies an outline for protocols to use.
+//See protocol-specific documentation for what infoTypes are available and
+//what pInfoData should be for each infoType.
+//Sends an ack type=ACKTYPE_SETINFO, result=ACKRESULT_SUCCESS/FAILURE,
+//lParam=0 on completion.
+#define PS_CHANGEINFO "/ChangeInfo"
+
+//Informs the protocol of the users chosen resume behaviour v0.1.2.2+
+//wParam=(WPARAM)(HANDLE)hFileTransfer
+//lParam=(LPARAM)(PROTOFILERESUME*)&pfr
+//Returns 0 on success, nonzero on failure
+//If the protocol supports file resume (PF1_FILERESUME) then before each
+//individual file receive begins (note: not just each file that already exists)
+//it will broadcast an ack with type=ACKTYPE_FILE, result=ACKRESULT_RESUME,
+//hProcess=hFileTransfer, lParam=(LPARAM)(PROTOFILETRANSFERSTATUS*)&fts. If the
+//UI processes this ack it must return nonzero from its hook. If all the hooks
+//complete without returning nonzero then the protocol will assume that no
+//resume UI was available and will continue the file receive with a default
+//behaviour (overwrite for ICQ). If a hook does return nonzero then that UI
+//must call this function, PS_FILERESUME, at some point. When the protocol
+//module receives this call it will proceed with the file receive using the
+//given information.
+//Having said that PS_FILERESUME must be called, it is also acceptable to call
+//PSS_FILECANCEL to completely abort the transfer instead.
+#define FILERESUME_OVERWRITE 1
+#define FILERESUME_RESUME 2
+#define FILERESUME_RENAME 3
+#define FILERESUME_SKIP 4
+typedef struct {
+ int action; //a FILERESUME_ flag
+ const char *szFilename; //full path. Only valid if action==FILERESUME_RENAME
+} PROTOFILERESUME;
+#define PS_FILERESUME "/FileResume"
+
+/****************************** SENDING SERVICES *************************/
+//these should be called with CallContactService()
+
+//Updates a contact's details from the server
+//wParam=flags
+//lParam=0
+//returns 0 on success, nonzero on failure
+//Will update all the information in the database, and then send acks with
+//type=ACKTYPE_GETINFO, result=ACKRESULT_SUCCESS, hProcess=(HANDLE)(int)nReplies, lParam=thisReply
+//Since some protocols do not allow the library to tell when it has got all
+//the information so it can send a final ack, one ack will be sent after each
+//chunk of data has been received. nReplies contains the number of distinct
+//acks that will be sent to get all the information, thisReply is the zero-
+//based index of this ack. When thisReply=0 the 'minimal' information has just
+//been received. All other numbering is arbitrary.
+#define SGIF_MINIMAL 1 //get only the most basic information. This should
+ //contain at least a Nick and e-mail.
+#define SGIF_ONOPEN 2 //set when the User Info form is being opened
+#define PSS_GETINFO "/GetInfo"
+
+//Send an instant message
+//wParam=flags
+//lParam=(LPARAM)(const char*)szMessage
+//returns a hProcess corresponding to the one in the ack event.
+//Will send an ack when the message actually gets sent
+//type=ACKTYPE_MESSAGE, result=success/failure, lParam=0
+//Protocols modules are free to define flags starting at 0x10000
+//The event will *not* be added to the database automatically.
+#define PSS_MESSAGE "/SendMsg"
+
+//Send an URL message
+//wParam=flags
+//lParam=(LPARAM)(const char*)szMessage
+//returns a hProcess corresponding to the one in the ack event.
+//szMessage should be encoded as the URL followed by the description, the
+//separator being a single nul (\0). If there is no description, do not forget
+//to end the URL with two nuls.
+//Will send an ack when the message actually gets sent
+//type=ACKTYPE_URL, result=success/failure, lParam=0
+//Protocols modules are free to define flags starting at 0x10000
+//The event will *not* be added to the database automatically.
+#define PSS_URL "/SendUrl"
+
+//Send a set of contacts
+//wParam=MAKEWPARAM(flags,nContacts)
+//lParam=(LPARAM)(HANDLE*)hContactsList
+//returns a hProcess corresponding to the one in the ack event, NULL on
+//failure.
+//hContactsList is an array of nContacts handles to contacts. If this array
+//includes one or more contacts that cannot be transferred using this protocol
+//the function will fail.
+//Will send an ack when the contacts actually get sent
+//type=ACKTYPE_CONTACTS, result=success/failure, lParam=0
+//No flags have yet been defined.
+//The event will *not* be added to the database automatically.
+#define PSS_CONTACTS "/SendContacts"
+
+//Send a request to retrieve somebody's mode message.
+//wParam=lParam=0
+//returns an hProcess identifying the request, or 0 on failure
+//This function will fail if the contact's current status mode doesn't have an
+//associated message
+//The reply will be in the form of an ack:
+//type=ACKTYPE_AWAYMSG, result=success/failure, lParam=(const char*)szMessage
+#define PSS_GETAWAYMSG "/GetAwayMsg"
+
+//Sends an away message reply to a user
+//wParam=(WPARAM)(HANDLE)hProcess (of ack)
+//lParam=(LPARAM)(const char*)szMessage
+//Returns 0 on success, nonzero on failure
+//This function must only be used if the protocol has PF1_MODEMSGSEND and
+//PF1_INDIVMODEMSG set. Otherwise, PS_SETAWAYMESSAGE should be used.
+//This function must only be called in response to an ack that a user has
+//requested our away message. The ack is sent as:
+//type=ACKTYPE_AWAYMSG, result=ACKRESULT_SENTREQUEST, lParam=0
+#define PSS_AWAYMSG "/SendAwayMsg"
+
+//Allows a file transfer to begin
+//wParam=(WPARAM)(HANDLE)hTransfer
+//lParam=(LPARAM)(const char*)szPath
+//Returns a new handle to the transfer, to be used from now on
+//If szPath does not point to a directory then:
+// if a single file is being transferred and the protocol supports file
+// renaming (PF1_CANRENAMEFILE) then the file is given this name
+// otherwise the filename is removed and the file(s) are placed in the
+// resulting directory
+//File transfers are marked by an EVENTTYPE_FILE added to the database. The
+//format is:
+//DWORD hTransfer
+//ASCIIZ filename(s), description
+#define PSS_FILEALLOW "/FileAllow"
+
+//Refuses a file transfer request
+//wParam=(WPARAM)(HANDLE)hTransfer
+//lParam=(LPARAM)(const char*)szReason
+//Returns 0 on success, nonzero on failure
+#define PSS_FILEDENY "/FileDeny"
+
+//Cancel an in-progress file transfer
+//wParam=(WPARAM)(HANDLE)hTransfer
+//lParam=0
+//Returns 0 on success, nonzero on failure
+#define PSS_FILECANCEL "/FileCancel"
+
+//Initiate a file send
+//wParam=(WPARAM)(const char*)szDescription
+//lParam=(LPARAM)(char **)ppszFiles
+//Returns a transfer handle on success, NULL on failure
+//All notification is done through acks, with type=ACKTYPE_FILE
+//If result=ACKRESULT_FAILED then lParam=(LPARAM)(const char*)szReason
+#define PSS_FILE "/SendFile"
+
+//Set the status mode you will appear in to a user
+//wParam=statusMode
+//lParam=0
+//Returns 0 on success, nonzero on failure
+//Set statusMode=0 to revert to normal behaviour for the contact
+//ID_STATUS_ONLINE is possible iff PF1_VISLIST
+//ID_STATUS_OFFLINE is possible iff PF1_INVISLIST
+//Other modes are possible iff PF1_INDIVSTATUS
+#define PSS_SETAPPARENTMODE "/SetApparentMode"
+
+// Send an auth request
+// wParam=0
+// lParam=(const char *)szMessage
+// Returns 0 on success, nonzero on failure
+#define PSS_AUTHREQUEST "/AuthRequest"
+
+// Send "User is Typing" (user is typing a message to the user) v0.3.3+
+// wParam=(WPARAM)(HANDLE)hContact
+// lParam=(LPARAM)(int)typing type - see PROTOTYPE_SELFTYPING_X defines in m_protocols.h
+#define PSS_USERISTYPING "/UserIsTyping"
+
+/**************************** RECEIVING SERVICES *************************/
+//These services are not for calling by general modules. They serve a specific
+//role in communicating through protocol module chains before the whole app is
+//notified that an event has occurred.
+//When the respective event is received over the network, the network-level
+//protocol module initiates the chain by calling MS_PROTO_CHAINRECV with wParam
+//set to zero and lParam pointing to the CCSDATA structure.
+//Protocol modules should continue the message up the chain by calling
+//MS_PROTO_CHAINRECV with the same wParam they received and a modified (or not)
+//lParam (CCSDATA). If they do not do this and return nonzero then all further
+//processing for the event will cease and the event will be ignored.
+//Once all non-network protocol modules have been called (in reverse order),
+//the network protocol module will be called so that it can finish its
+//processing using the modified information.
+//This final processing should consist of the protocol module adding the
+//event to the database, and it is the ME_DB_EVENT_ADDED event that people who
+//just want to know the final result should hook.
+//In all cases, the database should store what the user read/wrote.
+
+//An instant message has been received
+//wParam=0
+//lParam=(LPARAM)(PROTORECVEVENT*)&pre
+//DB event: EVENTTYPE_MESSAGE, blob contains szMessage without 0 terminator
+typedef struct {
+ DWORD flags;
+ DWORD timestamp; //unix time
+ char *szMessage;
+ LPARAM lParam; //extra space for the network level protocol module
+} PROTORECVEVENT;
+#define PREF_CREATEREAD 1 //create the database event with the 'read' flag set
+#define PREF_UNICODE 2
+#define PREF_RTL 4 // 0.5+ addition: support for right-to-left messages
+#define PSR_MESSAGE "/RecvMessage"
+
+//An URL has been received
+//wParam=0
+//lParam=(LPARAM)(PROTORECVEVENT*)&pre
+//szMessage is encoded the same as for PSS_URL
+//DB event: EVENTTYPE_URL, blob contains szMessage without 0 terminator
+#define PSR_URL "/RecvUrl"
+
+//Contacts have been received
+//wParam=0
+//lParam=(LPARAM)(PROTORECVEVENT*)&pre
+//pre.szMessage is actually a (PROTOSEARCHRESULT**) list.
+//pre.lParam is the number of contacts in that list.
+//PS_ADDTOLIST can be used to add the contacts to the contact list.
+#define PSR_CONTACTS "/RecvContacts"
+
+/* contacts database event format (EVENTTYPE_CONTACTS)
+repeat {
+ ASCIIZ userNick
+ ASCIIZ userId
+}
+userNick should be a human-readable description of the user. It need not
+be the nick, or even confined to displaying just one type of
+information.
+userId should be a machine-readable representation of the unique
+protocol identifying field of the user. Because of the need to be
+zero-terminated, binary data should be converted to text.
+Use PS_ADDTOLISTBYEVENT to add the contacts from one of these to the list.
+*/
+
+//File(s) have been received
+//wParam=0
+//lParam=(LPARAM)(PROTORECVFILE*)&prf
+typedef struct {
+ DWORD flags;
+ DWORD timestamp; //unix time
+ char *szDescription;
+ char **pFiles;
+ LPARAM lParam; //extra space for the network level protocol module
+} PROTORECVFILE;
+#define PSR_FILE "/RecvFile"
+
+//An away message reply has been received
+//wParam=statusMode
+//lParam=(LPARAM)(PROTORECVEVENT*)&pre
+#define PSR_AWAYMSG "/RecvAwayMsg"
+
+//An authorization request has been received
+//wParam=0
+//lParam=(LPARAM)(PROTORECVEVENT*)&pre
+//pre.szMessage is same format as blob
+//pre.lParam is the size of the blob
+#define PSR_AUTH "/RecvAuth"
+
+#endif // M_PROTOSVC_H__
diff --git a/miranda-wine/include/m_sessions.h b/miranda-wine/include/m_sessions.h
new file mode 100644
index 0000000..ca38998
--- /dev/null
+++ b/miranda-wine/include/m_sessions.h
@@ -0,0 +1,343 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_SESSION_H__
+#define M_SESSION_H__ 1
+
+/* Pipe Messages */
+
+/*
+ szEntity=szUI, szProto (always != NULL)
+ hSession=yes
+
+ A new entity handle is about to be created to bind .szUI for usage by .szProto,
+ note that this handle is not yet in the handle list and the .szProto will
+ get the message first, then the .szUI will.
+
+ .szUI must set up any instance data within the given hSession,
+ this is done with Sion_EntityCookieSet(hSession,SDR_UI,data).
+
+ .szProto may also set up data to associate with the given hSession,
+ this is done with Sion_EntityCookieSet(hSession,SDR_PROTO,data);
+
+ This message is always sent from the main thread (a thread context switch
+ occurs if needed).
+
+*/
+#define ENTITY_CREATE 1
+#define ENTITY_DESTROY 2
+
+/* Services/Hooks */
+
+/* either .dwTo, dwFrom may have an SDR_* type, and SDR_* flag */
+#define SDR_ALL 1
+#define SDR_SION 2
+#define SDR_PROTO 3
+#define SDR_UI 4
+
+/* you may extend this structure but .cbSize must stay and the reserved data
+at the end of the structure must not be rewritten into */
+struct PIPE_DATA {
+ int cbSize;
+ char *szEntity; // can be NULL
+ HANDLE hSession; // ""
+ DWORD dwMsg;
+ DWORD dwTo, dwFrom; // SDR_*, SDR_ALL is not a good thing
+ WPARAM wParam;
+ LPARAM lParam;
+ DWORD reserved[2]; // is actually apart of the structure and is used internally
+};
+
+/*
+wParam=0
+lParam=(LPARAM)&PIPE_DATA
+
+Issue a call to an entity by name, type or to everyone, if you send
+a message to an entity by name, e.g. "ICQ" it will only goto "ICQ" and not
+to anyone else.
+*/
+#define MS_SION_PIPE "Sion/PipeCall"
+
+/*
+wParam=0
+lParam=(LPARAM)&PIPE_DATA
+
+Begin your lovely relationship with everyone else who began a relationship
+before you, uh.. fill a pipe data structure and call this service :
+
+struct PIPE_DATA pd;
+pd.cbSize=sizeof(pd);
+pd.dwTo=SDR_PROTO;
+pd.szEntity="ICQ";
+pd.lParam=(MIRANDASERVICE)MyCallback;
+CallService(MS_SION_PIPEHOOK,0,(LPARAM)&pd);
+
+The service returns 0 on success and non zero on failure, once you have registered either as a UI or a protocol
+your MIRANDASERVICE will be called on the event on a pipe message that is
+either directed to your entity name (.szEntity!=NULL) or by SDR_* type.
+
+Note that the entity name may not be yours, but the pipe system may of been
+instructed to issue the call with the caller's entity name given to you, because
+you know what your entity name is already, you should not rely on .szEntity
+being anything, but if it is there, the message is for you only and no one else
+will get it and the value of .szEntity is dependant on the message.
+
+*/
+#define MS_SION_PIPEHOOK "Sion/PipeHook"
+
+/*
+wParam=0
+lParam=(LPARAM)&SION_ENTITY_DESCRIPTOR
+
+Create an entity handle binded to .szUI and for .szProto, this service will
+switch threads if it needs to to send ENTITY_CREATE to both .szUI and .szProto
+*/
+struct SION_ENTITY_DESCRIPTOR {
+ int cbSize;
+ char *szUI;
+ char *szProto;
+ HANDLE hSession; // returned if successful
+};
+#define MS_SION_ENTITY_CREATE "Sion/EntityCreate"
+
+/*
+wParam=0
+lParam=(LPARAM)HANDLE
+
+Decrement the given handle reference count by one, this will cause the
+handle to be freed if the reference count reaches zero, if this is the case
+there will be a thread switch to the main thread (if not called from the main thread)
+
+During handle shutdown, ENTITY_DESTROY will be sent to the protocol and then the UI,
+note that you do not need to give .szUI or .szProto because the handle knows
+who it is binded to.
+*/
+#define MS_SION_ENTITY_RELEASE "Sion/EntityRelease"
+
+/*
+wParam=0
+lParam=HANDLE
+
+Add one to the reference count of HANDLE.
+*/
+#define MS_SION_ENTITY_CLONE "Sion/EntityClone"
+
+/*
+wParam=0
+lParam=&SION_ENTITY_COOKIE
+
+Given a .hSession and a .dwSdr (SDR_*) code get/set a cookie pointer,
+if you pass data=NULL, then the current data stored for (SDR_*) will be
+returned, if you want to wipe that data, set persist=0
+
+Note that this function is now thread safe for SDR_UI, SDR_PROTO, SDR_SION,
+also note that UI's must store their instance data using this method.
+
+*/
+struct SION_ENTITY_COOKIE {
+ int cbSize;
+ HANDLE hSession;
+ DWORD dwSdr; // SDR_* type to store data against, this can be SDR_UI or SDR_PROTO
+ void *data; // can be NULL
+ int persist; // if TRUE and data is NULL then data will not be wiped
+};
+#define MS_SION_ENTITY_SETCOOKIE "Sion/EntitySetCookie"
+
+/*
+wParam=0
+lParam=&SION_ENTITY_COOKIE
+
+Given .data and SDR_code, finds the associated .hSession and returns
+a reference to it, note that .data can not be NULL, .dwSdr is used
+to match the type of cookie.
+
+*/
+#define MS_SION_ENTITY_FINDCOOKIE "Sion/EntityFindCookie"
+
+/* -- Helper functions -- */
+
+__inline int Sion_PipeRegister(DWORD dwSdr,char *szEntity,MIRANDASERVICE pfnService)
+{
+ struct PIPE_DATA pd;
+ pd.cbSize=sizeof(struct PIPE_DATA);
+ pd.dwTo=dwSdr;
+ pd.szEntity=szEntity;
+ pd.lParam=(LPARAM)pfnService;
+ return CallService(MS_SION_PIPEHOOK,0,(LPARAM)&pd);
+}
+
+__inline HANDLE Sion_EntityCreate(char *szProto, char *szUI)
+{
+ struct SION_ENTITY_DESCRIPTOR sed;
+ sed.cbSize=sizeof(sed);
+ sed.szProto=szProto;
+ sed.szUI=szUI;
+ sed.hSession=NULL;
+ if (!CallService(MS_SION_ENTITY_CREATE,0,(LPARAM)&sed) && sed.hSession) {
+ return sed.hSession;
+ }
+ return NULL;
+}
+
+__inline int Sion_EntityRelease(HANDLE seh)
+{
+ return CallService(MS_SION_ENTITY_RELEASE,0,(LPARAM)seh);
+}
+
+__inline int Sion_EntityClone(HANDLE seh)
+{
+ return CallService(MS_SION_ENTITY_CLONE,0,(LPARAM)seh);
+}
+
+__inline void* Sion_EntityCookieGet(HANDLE seh, DWORD dwSdr)
+{
+ struct SION_ENTITY_COOKIE sec;
+ sec.cbSize=sizeof(sec);
+ sec.hSession=seh;
+ sec.dwSdr=dwSdr;
+ sec.data=NULL;
+ sec.persist=1;
+ CallService(MS_SION_ENTITY_SETCOOKIE,0,(LPARAM)&sec);
+ return sec.data;
+}
+
+__inline int Sion_EntityCookieSet(HANDLE seh, DWORD dwSdr, void* cookie)
+{
+ struct SION_ENTITY_COOKIE sec;
+ sec.cbSize=sizeof(sec);
+ sec.hSession=seh;
+ sec.dwSdr=dwSdr;
+ sec.data=cookie;
+ sec.persist=0;
+ return CallService(MS_SION_ENTITY_SETCOOKIE,0,(LPARAM)&sec);
+}
+
+__inline HANDLE Sion_EntityCookieFind(DWORD dwSdr, void* cookie)
+{
+ struct SION_ENTITY_COOKIE sec;
+ sec.cbSize=sizeof(sec);
+ sec.hSession=NULL;
+ sec.dwSdr=dwSdr;
+ sec.data=cookie;
+ CallService(MS_SION_ENTITY_FINDCOOKIE,0,(LPARAM)&sec);
+ return sec.hSession;
+}
+
+__inline int Sion_PipeBroadcast(char* szEntity, HANDLE hSession, DWORD dwMsg,
+ WPARAM wParam, LPARAM lParam, DWORD dwFrom, DWORD dwTo) {
+ struct PIPE_DATA pd;
+ pd.cbSize=sizeof(struct PIPE_DATA);
+ pd.szEntity=szEntity;
+ pd.hSession=hSession;
+ pd.dwMsg=dwMsg;
+ pd.dwTo=dwTo;
+ pd.dwFrom=dwFrom;
+ pd.wParam=wParam;
+ pd.lParam=lParam;
+ return CallService(MS_SION_PIPE,0,(LPARAM)&pd);
+}
+
+/*
+
+--Pipe Convos--
+
+The following is the planned pathway message, not all may make
+it to the final draft.
+
+Because of the nature of some protocols, there are some
+messages that some protocols can ignore since they have no meaning.
+
+SION : sends ENTITY_CREATE after creating a temporary entity handle
+PROTO,
+UI : both UI and protocol store structures as cookies within the handle
+ which it can later fetch. At this point the UI is assumed single
+ contact.
+
+SION : sends a message to the protocol to let it know it should allocate transport
+PROTO: the proto can assume this from ENTITY_CREATE, but I'm not sure this a good idea.
+
+PROTO: Protocol needs to send a message to tell the UI about basic channel stuff
+ like if it is multiple contact from the start (IRC style) or open to change
+ (MSN style) or if it is private and restricted in all forms of JOIN, INVITE, etc.
+UI : Can use this message to present information in a 2 person format even if
+ the protocol level is widly different.
+
+
+SION : ATTACH_CHANNEL or ATTACH_CONTACT
+PROTO: will send "JOIN" or "INVITE" to request a join/a contact
+ this maybe on the transport just created above.
+ These two messages will be have a HPROCESS code
+ that must be acknowledged later.
+
+ Note that if the protocol does not require contacts
+ to be attached in this way (invited) then just fake the
+ ATTACHED_* messages.
+
+ The contacts(s) will be shown in the channel at the UI level
+ even if they are not yet within the channel at the protocol
+ level.
+
+PROTO: sends ATTACHED_CHANNEL or ATTACHED_CONTACT with the HPROCESS
+ code given by the ATTACH_* messages, this is to signal
+ that the JOIN was successful or that the invited contact
+ has joined.
+
+ Note that there maybe more than one ATTACHED_* message.
+
+PROTO: sends a CHANNEL_WHOLIST
+UI : is supposed to listen out for this WHOLIST and present
+ a list of people already inside the channel.
+
+ if for a single user, the channel list maybe hidden.
+
+PROTO: sends a CHANNEL_TOPIC
+UI : displays the topic inside the channel, this message is optional and may not be sent
+
+PROTO: sends a CHANNEL_MODE
+UI : displays the modes that the channel is in, the modes still have to be abstracted
+ to Miranda, e.g. IRC mode +M have another Miranda spec flag.
+
+PROTO: sends a CHANNEL_DONE
+UI : the UI is now sure that no more messages are expected.
+
+UI : sends a UI_TEXT message, with optional source HCONTACT and of course the message.
+PROTO: picks up on this message and transmits it, it must return
+ a HPROCESS code that is later acknowledged.
+
+ It is upto the protocol if it processes this message with the protocol
+ send chain.
+
+PROTO: sends a UI_TEXTED with HPROCESS code given above
+UI : the UI may show the message as 'sent' or show nothing to the user.
+
+UI : sends UI_IAMTYPING
+PROTO: the protocol may or may not send this message to the other parties
+ but it must process it, this message is also optional.
+
+PROTO: sends UI_CONTACT_ISTYPING (source HCONTACT)
+UI : an HCONTACT within the session is typing, the UI may elect to show this
+ message in a status bar, or with a visual effect.
+*/
+
+#endif // M_SESSION_H__
+
diff --git a/miranda-wine/include/m_skin.h b/miranda-wine/include/m_skin.h
new file mode 100644
index 0000000..b5fe8c8
--- /dev/null
+++ b/miranda-wine/include/m_skin.h
@@ -0,0 +1,145 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_SKIN_H__
+#define M_SKIN_H__ 1
+
+//loads an icon from the user's custom skin library, or from the exe if there
+//isn't one of them
+//wParam=id of icon to load - see below
+//lParam=0
+//returns an hIcon for the new icon. Do *not* DestroyIcon() the return value
+//returns NULL if id is invalid, but will always succeed for a valid id
+#define MS_SKIN_LOADICON "Skin/Icons/Load"
+//nice function to wrap this:
+__inline static HICON LoadSkinnedIcon(int id) {return (HICON)CallService(MS_SKIN_LOADICON,id,0);}
+
+//event icons
+#define SKINICON_EVENT_MESSAGE 100
+#define SKINICON_EVENT_URL 101
+#define SKINICON_EVENT_FILE 102
+//other icons
+#define SKINICON_OTHER_MIRANDA 200
+#define SKINICON_OTHER_EXIT 201
+#define SKINICON_OTHER_SHOWHIDE 202
+#define SKINICON_OTHER_GROUPOPEN 203 //v0.1.1.0+
+#define SKINICON_OTHER_GROUPSHUT 205 //v0.1.1.0+
+#define SKINICON_OTHER_USERONLINE 204 //v0.1.0.1+
+//menu icons are owned by the module that uses them so are not and should not
+//be skinnable. Except exit and show/hide
+
+//status mode icons. NOTE: These are deprecated in favour of LoadSkinnedProtoIcon()
+#define SKINICON_STATUS_OFFLINE 0
+#define SKINICON_STATUS_ONLINE 1
+#define SKINICON_STATUS_AWAY 2
+#define SKINICON_STATUS_NA 3
+#define SKINICON_STATUS_OCCUPIED 4
+#define SKINICON_STATUS_DND 5
+#define SKINICON_STATUS_FREE4CHAT 6
+#define SKINICON_STATUS_INVISIBLE 7
+#define SKINICON_STATUS_ONTHEPHONE 8
+#define SKINICON_STATUS_OUTTOLUNCH 9
+
+//Loads an icon representing the status mode for a particular protocol.
+//wParam=(WPARAM)(const char*)szProto
+//lParam=status
+//returns an hIcon for the new icon. Do *not* DestroyIcon() the return value
+//returns NULL on failure
+//if szProto is NULL the function will load the user's selected 'all protocols'
+//status icon.
+#define MS_SKIN_LOADPROTOICON "Skin/Icons/LoadProto"
+//nice function to wrap this:
+__inline static HICON LoadSkinnedProtoIcon(const char *szProto,int status) {return (HICON)CallService(MS_SKIN_LOADPROTOICON,(WPARAM)szProto,status);}
+
+//add a new sound so it has a default and can be changed in the options dialog
+//wParam=0
+//lParam=(LPARAM)(SKINSOUNDDESC*)ssd;
+//returns 0 on success, nonzero otherwise
+typedef struct {
+ int cbSize;
+ const char *pszName; //name to refer to sound when playing and in db
+ const char *pszDescription; //description for options dialog
+ const char *pszDefaultFile; //default sound file to use
+ const char *pszSection; //section name used to group sounds (NULL is acceptable) (added during 0.3.4+ (2004/10/*))
+} SKINSOUNDDESCEX;
+// Old struct pre 0.3.4
+typedef struct {
+ int cbSize;
+ const char *pszName; //name to refer to sound when playing and in db
+ const char *pszDescription; //description for options dialog
+ const char *pszDefaultFile; //default sound file to use
+} SKINSOUNDDESC;
+#define MS_SKIN_ADDNEWSOUND "Skin/Sounds/AddNew"
+
+// inline only works after 0.3.4+ (2004/10/*)
+__inline static int SkinAddNewSoundEx(const char *name,const char *section,const char *description)
+{
+ SKINSOUNDDESCEX ssd;
+ ZeroMemory(&ssd,sizeof(ssd));
+ ssd.cbSize=sizeof(ssd);
+ ssd.pszName=name;
+ ssd.pszSection=section;
+ ssd.pszDescription=description;
+ return CallService(MS_SKIN_ADDNEWSOUND, 0, (LPARAM)&ssd);
+}
+
+__inline static int SkinAddNewSound(const char *name,const char *description,const char *defaultFile)
+{
+ SKINSOUNDDESC ssd;
+ ZeroMemory(&ssd,sizeof(ssd));
+ ssd.cbSize=sizeof(ssd);
+ ssd.pszName=name;
+ ssd.pszDescription=description;
+ ssd.pszDefaultFile=defaultFile;
+ return CallService(MS_SKIN_ADDNEWSOUND, 0, (LPARAM)&ssd);
+}
+
+//play a named sound event
+//wParam=0
+//lParam=(LPARAM)(const char*)pszName
+//pszName should have been added with Skin/Sounds/AddNew, but if not the
+//function will not fail, it will play the Windows default sound instead.
+#define MS_SKIN_PLAYSOUND "Skin/Sounds/Play"
+__inline static int SkinPlaySound(const char *name) {return CallService(MS_SKIN_PLAYSOUND,0,(LPARAM)name);}
+
+//sent when the icons DLL has been changed in the options dialog, and everyone
+//should re-make their image lists
+//wParam=lParam=0
+#define ME_SKIN_ICONSCHANGED "Skin/IconsChanged"
+
+
+/*
+ wParam: 0 when playing sound (1 when sound is being previewed)
+ lParam: (char*) pszSoundFile
+ Affect: This hook is fired when the sound module needs to play a sound
+ Note : This event has default processing, if no one HookEvent()'s this event then it will
+ use the default hook code, which uses PlaySound()
+ Version: 0.3.4a (2004/09/15)
+*/
+#define ME_SKIN_PLAYINGSOUND "Skin/Sounds/Playing"
+
+//random ideas for the future:
+// Skin/LoadNetworkAnim - get some silly spinner thing when we want to be busy
+
+#endif //M_SKIN_H__
+
+
diff --git a/miranda-wine/include/m_system.h b/miranda-wine/include/m_system.h
new file mode 100644
index 0000000..985f615
--- /dev/null
+++ b/miranda-wine/include/m_system.h
@@ -0,0 +1,366 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_SYSTEM_H__
+#define M_SYSTEM_H__ 1
+
+#ifndef MIRANDANAME
+#define MIRANDANAME "Miranda IM"
+#endif
+#ifndef MIRANDACLASS
+#define MIRANDACLASS "Miranda"
+#endif
+
+//miranda/system/modulesloaded
+//called after all modules have been successfully initialised
+//wParam=lParam=0
+//used to resolve double-dependencies in the module load order
+#define ME_SYSTEM_MODULESLOADED "Miranda/System/ModulesLoaded"
+
+//miranda/system/shutdown event
+//called just before the application terminates
+//the database is still guaranteed to be running during this hook.
+//wParam=lParam=0
+#define ME_SYSTEM_SHUTDOWN "Miranda/System/Shutdown"
+
+//miranda/system/oktoexit event
+//called before the app goes into shutdown routine to make sure everyone is
+//happy to exit
+//wParam=lParam=0
+//return nonzero to stop the exit cycle
+#define ME_SYSTEM_OKTOEXIT "Miranda/System/OkToExitEvent"
+
+//miranda/system/oktoexit service
+//Check if everyone is happy to exit
+//wParam=lParam=0
+//if everyone acknowleges OK to exit then returns true, otherwise false
+#define MS_SYSTEM_OKTOEXIT "Miranda/System/OkToExit"
+
+//gets the version number of Miranda encoded as a DWORD v0.1.0.1+
+//wParam=lParam=0
+//returns the version number, encoded as one version per byte, therefore
+//version 1.2.3.10 is 0x0102030a
+#define MS_SYSTEM_GETVERSION "Miranda/System/GetVersion"
+
+//gets the version of Miranda encoded as text v0.1.0.1+
+//wParam=cch
+//lParam=(LPARAM)(char*)pszVersion
+//cch is the size of the buffer pointed to by pszVersion, in bytes
+//may return a build qualifier, such as "0.1.0.1 alpha"
+//returns 0 on success, nonzero on failure
+#define MS_SYSTEM_GETVERSIONTEXT "Miranda/System/GetVersionText"
+
+//Adds a HANDLE to the list to be checked in the main message loop v0.1.2.0+
+//wParam=(WPARAM)(HANDLE)hObject
+//lParam=(LPARAM)(const char*)pszService
+//returns 0 on success or nonzero on failure
+//Causes pszService to be CallService()d (wParam=hObject,lParam=0) from the
+//main thread whenever hObject is signalled.
+//The Miranda message loop has a MsgWaitForMultipleObjects() call in it to
+//implement this feature. See the documentation for that function for
+//information on what objects are supported.
+//There is a limit of MAXIMUM_WAIT_OBJECTS minus one (MWO is defined in winnt.h
+//to be 64) on the number of handles MSFMO() can process. This service will
+//return nonzero if that many handles are already being waited on.
+
+//As of writing, the following parts of Miranda are thread-safe, so can be
+//called from any thread:
+//All of modules.h except NotifyEventHooks()
+//Read-only parts of m_database.h (since the write parts will call hooks)
+//All of m_langpack.h
+//for all other routines your mileage may vary, but I would strongly recommend
+//that you call them from the main thread, or ask about it on plugin-dev if you
+//think it really ought to work.
+
+//Update during 0.1.2.0 development, 16/10/01:
+//NotifyEventHooks() now translates all calls into the context of the main
+//thread, which means that all of m_database.h is now completely safe.
+
+//Update during 0.1.2.2 development, 17/4/02:
+//The main thread's message loop now also deals with asynchronous procedure
+//calls. Loop up QueueUserAPC() for a neater way to accomplish a lot of the
+//things that used to require ms_system_waitonhandle.
+
+//Miranda is compiled with the multithreaded runtime - don't forget to do the
+//same with your plugin.
+#define MS_SYSTEM_WAITONHANDLE "Miranda/System/WaitOnHandle"
+
+//Removes a HANDLE from the wait list v0.1.2.0+
+//wParam=(WPARAM)(HANDLE)hObject
+//lParam=0
+//returns 0 on success or nonzero on failure.
+#define MS_SYSTEM_REMOVEWAIT "Miranda/System/RemoveWait"
+
+/* Returns Miranda's RTL/CRT function poiners to malloc() free() realloc() -- 0.1.2.2+
+This is useful for preallocation of memory for use with Miranda's services
+that Miranda can free -- or reallocation of a block of memory passed with a service.
+Do not use with memory unless it is explicitly expected the memory *can*
+or *shall* be used in this way. the passed structure is expected to have it's .cbSize initialised
+
+wParam=0, lParam = (LPARAM) &MM_INTERFACE
+*/
+
+struct MM_INTERFACE {
+ int cbSize;
+ void* (*mmi_malloc) (size_t);
+ void* (*mmi_realloc) (void*, size_t);
+ void (*mmi_free) (void*);
+};
+
+#define MS_SYSTEM_GET_MMI "Miranda/System/GetMMI"
+
+/* Returns the pointer to the simple lists manager.
+If the sortFunc member of the list gets assigned, the list becomes sorted
+
+wParam=0, lParam = 0
+*/
+
+typedef int ( *FSortFunc )( void*, void* );
+
+typedef struct
+{
+ void** items;
+ int realCount;
+ int limit;
+ int increment;
+
+ FSortFunc sortFunc;
+}
+ SortedList;
+
+struct LIST_INTERFACE {
+ int cbSize;
+
+ SortedList* ( *List_Create )( int, int );
+ void ( *List_Destroy )( SortedList* );
+
+ void* ( *List_Find )( SortedList*, void* );
+ int ( *List_GetIndex )( SortedList*, void*, int* );
+ int ( *List_Insert )( SortedList*, void*, int );
+ int ( *List_Remove )( SortedList*, int );
+ int ( *List_IndexOf )( SortedList*, void* );
+};
+
+#define MS_SYSTEM_GET_LI "Miranda/System/GetLI"
+
+/*
+
+ -- Thread Safety --
+
+ Proper thread safe shutdown was implemented in 0.3.0.0 (2003/04/18)
+ and not before, therefore it is improper that any MT plugins be used
+ with earlier versions of Miranda (as hav0c will result)
+
+ Note: This does not apply to MT plugins which included their own
+ thread-safe shutdown routines.
+
+ Shutdown thread safety works thusly:
+
+ All new threads must call MS_SYSTEM_THREAD_PUSH and MS_SYSTEM_THREAD_POP
+ when they return.
+
+ Due to the nature of thread creation, it is illegal to assume
+ just a call pair of MS_SYSTEM_THREAD_PUSH inside the thread will
+ be enough -- the source thread may only return when the new child
+ thread has actually executed MS_SYSTEM_THREAD_PUSH
+
+ This is because a thread maybe in an undefined state at the point
+ when the thread creation routine returns, thus Miranda may exit
+ thinking it is safe to do so, because MS_SYSTEM_THREAD_PUSH was not
+ called in time.
+
+ See miranda.c for how this can be done using an event object
+ which is signalled just after the MS_SYSTEM_THREAD_PUSH call is executed
+ and so the source thread knows that the created thread is known to Miranda.
+
+ -- What happens when Miranda exits --
+
+ Miranda will firstly set an event object to signalled, this will
+ make MS_SYSTEM_TERMINATED return TRUE, it will then fire ME_SYSTEM_PRESHUTDOWN
+ at this point, no plugins or modules are unloaded.
+
+ Miranda will then enumerate all active threads and queue an APC call
+ to each thread, so any thread in an alertable state will become active,
+ this functionailty may not be required by your threads: but if you use
+ the Winsock2 event object system or Sleep() please use the alertable
+ wait functions, so that the thread will 'wake up' when Miranda queues
+ a message to it, SleepEx() will return WAIT_IO_COMPLETION if this happens.
+
+ After all threads have been signalled, Miranda will spin on the unwind thread stack waiting
+ for it to become empty, in this time, it will carry on processing thread
+ switches, clearing it's own APC calls (used by NotifyEventHooks(), CallServiceSync())
+
+ So a thread should be written in this kind of form:
+
+ void mythread(void *arg)
+ {
+ // assume all thread pushing/popping is done by forkthread()
+ int run=1;
+ for (;run;)
+ {
+ Beep(4391,500);
+ SleepEx(1500,TRUE);
+ if (Miranda_Terminated()) {
+ Beep(5000,150); run=0;
+ } //if
+ } //for
+ }
+
+ The above will make a nice Beep every 1.5 seconds and when the UI
+ quits, it will make a lower beep and then return.
+
+ As many copies of this thread maybe running, the creator does not need
+ to worry about what to do with previous threads, as long as they're on the
+ unwind stack.If there are any global resources (and they're mutex) you can free() them
+ at Unload(), which will only be called, after all threads have returned.
+
+ -- Summary --
+
+ MS_SYSTEM_TERMINATED (will start returning TRUE)
+ ME_SYSTEM_PRESHUTDOWN will be fired (The CList won't be visible at this point)
+
+ All PROTOTYPE_PROTOCOL registered plugins will be sent ID_STATUS_OFFLINE
+ automatically.
+
+ All the threads will be notified via QueueUserAPC() and then Miranda
+ will poll on the unwind thread queue until it is empty.
+
+ ME_SYSTEM_SHUTDOWN will be fired, the database will be unloaded, the core
+ will be unloaded -- Miranda will return.
+
+*/
+
+/*
+wParam=0
+lParam=0
+
+Add a thread to the unwind wait stack that Miranda will poll on
+when it is tearing down modules.
+
+This must be called in the context of the thread that is to be pushed
+i.e. there are no args, it works out what thread is being called
+and gets itself a handle to the calling thread.
+
+*/
+#define MS_SYSTEM_THREAD_PUSH "Miranda/Thread/Push"
+
+/*
+wParam=0
+lParam=0
+
+Remove a thread from the unwind wait stack -- it is expected
+that the call be made in the context of the thread to be removed.
+
+Miranda will begin to tear down modules and plugins if/when the
+last thread from the unwind stack is removed.
+*/
+#define MS_SYSTEM_THREAD_POP "Miranda/Thread/Pop"
+
+/*
+wParam=0
+lParam=0
+
+This hook is fired just before the thread unwind stack is used,
+it allows MT plugins to shutdown threads if they have any special
+processing to do, etc.
+
+*/
+#define ME_SYSTEM_PRESHUTDOWN "Miranda/System/PShutdown"
+
+/*
+wParam=0
+lParam=0
+
+Returns TRUE when Miranda has got WM_QUIT and is in the process
+of shutting down
+*/
+#define MS_SYSTEM_TERMINATED "Miranda/SysTerm"
+
+/*
+ wParam : 0
+ lParam : (address) void (__cdecl *callback) (void)
+ Affect : Setup a function pointer to be called after main loop iterations, it allows for
+ idle processing, See notes
+ Returns: 1 on success, 0 on failure
+
+ Notes : This service will only allow one function to be registered, if one is registered, 0 will be returned
+ Remember that this uses __cdecl.
+ Version: Added during 0.3.4+
+
+*/
+#define MS_SYSTEM_SETIDLECALLBACK "Miranda/SetIdleCallback"
+
+/*
+ wParam : 0
+ lParam : &tick
+ Affect : return the last window tick where a monitored event was seen, currently WM_CHAR/WM_MOUSEMOVE
+ Returns: Always returns 0
+ Version: Added during 0.3.4+ (2004/09/12)
+*/
+#define MS_SYSTEM_GETIDLE "Miranda/GetIdle"
+
+/*
+ wParam: cchMax (max length of buffer)
+ lParam: pointer to buffer to fill
+ Affect: Returns the build timestamp of the core, as a string of YYYYMMDDhhmmss, this service might
+ not exist and therefore the build is before 2004-09-30
+ Returns: zero on success, non zero on failure
+ Version: 0.3.4a+ (2004/09/30)
+ DEFUNCT: This service was removed on 0.3.4.3+ (2004/11/19) use APILEVEL
+*/
+#define MS_SYSTEM_GETBUILDSTRING "Miranda/GetBuildString"
+
+__inline static int Miranda_Terminated(void)
+{
+ return CallService(MS_SYSTEM_TERMINATED,0,0);
+}
+
+__inline static void miranda_sys_free(void *ptr)
+{
+ if (ptr) {
+ struct MM_INTERFACE mm;
+ mm.cbSize=sizeof(struct MM_INTERFACE);
+ CallService(MS_SYSTEM_GET_MMI,0,(LPARAM)&mm);
+ mm.mmi_free(ptr);
+ }
+}
+
+/* Missing service catcher
+Is being called when one calls the non-existent service.
+All parameters are stored in the special structure
+
+The event handler takes 0 as wParam and TMissingServiceParams* as lParam.
+
+0.4.3+ addition (2006/03/27)
+*/
+
+typedef struct
+{
+ const char* name;
+ WPARAM wParam;
+ LPARAM lParam;
+}
+ MISSING_SERVICE_PARAMS;
+
+#define ME_SYSTEM_MISSINGSERVICE "System/MissingService"
+
+#endif // M_SYSTEM_H
diff --git a/miranda-wine/include/m_url.h b/miranda-wine/include/m_url.h
new file mode 100644
index 0000000..b692724
--- /dev/null
+++ b/miranda-wine/include/m_url.h
@@ -0,0 +1,35 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_URL_H__
+#define M_URL_H__ 1
+
+//bring up the send URL dialog for a user
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=0
+//returns 0 on success or nonzero on failure
+//returns immediately, before the url is sent
+#define MS_URL_SENDURL "SRUrl/SendCommand"
+
+#endif // M_URL_H__
+
diff --git a/miranda-wine/include/m_userinfo.h b/miranda-wine/include/m_userinfo.h
new file mode 100644
index 0000000..13741ba
--- /dev/null
+++ b/miranda-wine/include/m_userinfo.h
@@ -0,0 +1,75 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_USERINFO_H__
+#define M_USERINFO_H__ 1
+
+#include "m_options.h"
+
+//show the User Details dialog box
+//wParam=(WPARAM)(HANDLE)hContact
+//lParam=0
+#define MS_USERINFO_SHOWDIALOG "UserInfo/ShowDialog"
+
+/* UserInfo/Initialise v0.1.2.0+
+The user opened a details dialog. Modules should do whatever initialisation
+they need and call userinfo/addpage one or more times if they want pages
+displayed in the options dialog
+wParam=addInfo
+lParam=(LPARAM)hContact
+addInfo should be passed straight to the wParam of userinfo/addpage
+NB: The built-in userinfo module is loaded after all plugins, so calling
+HookEvent() in your plugin's Load() function will fail if you specify this
+hook. Look up core/m_system.h:me_system_modulesloaded.
+*/
+#define ME_USERINFO_INITIALISE "UserInfo/Initialise"
+
+/* UserInfo/AddPage v0.1.2.0+
+Must only be called during an userinfo/initialise hook
+Adds a page to the details dialog
+wParam=addInfo
+lParam=(LPARAM)(OPTIONSDIALOGPAGE*)odp
+addInfo must have come straight from the wParam of userinfo/initialise
+Pages in the details dialog operate just like pages in property sheets. See the
+Microsoft documentation for info on how they operate.
+When the pages receive WM_INITDIALOG, lParam=(LPARAM)hContact
+Strings in the structure can be released as soon as the service returns, but
+icons must be kept around. This is not a problem if you're loading them from a
+resource
+The 3 'group' elements in the structure are ignored, and will always be ignored
+Unlike the options dialog, the details dialog does not resize to fit its
+largest page. Details dialog pages should be 222x132 dlus.
+The details dialog (currently) has no Cancel button. I'm waiting to see if it's
+sensible to have one.
+Pages will be sent PSN_INFOCHANGED through WM_NOTIFY (idFrom=0) when a protocol
+ack is broadcast for the correct contact and with type=ACKTYPE_GETINFO.
+To help you out, PSN_INFOCHANGED will also be sent to each page just after it's
+created.
+All PSN_ WM_NOTIFY messages have PSHNOTIFY.lParam=(LPARAM)hContact
+*/
+#define PSN_INFOCHANGED 1
+#define PSM_FORCECHANGED (WM_USER+100) //force-send a PSN_INFOCHANGED to all pages
+#define MS_USERINFO_ADDPAGE "UserInfo/AddPage"
+
+#endif // M_USERINFO_H__
+
diff --git a/miranda-wine/include/m_utils.h b/miranda-wine/include/m_utils.h
new file mode 100644
index 0000000..50e2cdb
--- /dev/null
+++ b/miranda-wine/include/m_utils.h
@@ -0,0 +1,325 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_UTILS_H__
+#define M_UTILS_H__ 1
+
+#include <tchar.h>
+
+//this entire module is v0.1.0.1+
+//this module cannot be redefined by a plugin, because it's not useful for it
+//to be possible
+//There are some more utility services in the database for dealing with time
+//and simple string scrambling, but they are very db-orientated
+
+/* Opens a URL in the user's default web browser v0.1.0.1+
+wParam=bOpenInNewWindow
+lParam=(LPARAM)(const char*)szUrl
+returns 0 always
+bOpenInNewWindow should be zero to open the URL in the browser window the user
+last used, or nonzero to open in a new browser window. If there's no browser
+running, one will be opened to show the URL.
+*/
+#define MS_UTILS_OPENURL "Utils/OpenURL"
+
+/* Resizes a dialog by calling a custom routine to move the individual
+controls v0.1.0.1+
+wParam=0
+lParam=(LPARAM)(UTILRESIZEDIALOG*)&urd
+Returns 0 on success, or nonzero on failure
+Does not support dialogtemplateex dialog boxes, and will return failure if you
+try to resize one
+The dialog itself should have been resized prior to calling this service
+pfnResizer is called once for each control in the dialog
+pfnResizer should return a combination of one rd_anchorx_ and one rd_anchory
+constant
+*/
+typedef struct {
+ int cbSize;
+ UINT wId; //control ID
+ RECT rcItem; //original control rectangle, relative to dialog
+ //modify in-place to specify the new position
+ SIZE dlgOriginalSize; //size of dialog client area in template
+ SIZE dlgNewSize; //current size of dialog client area
+} UTILRESIZECONTROL;
+typedef int (*DIALOGRESIZERPROC)(HWND hwndDlg,LPARAM lParam,UTILRESIZECONTROL *urc);
+typedef struct {
+ int cbSize;
+ HWND hwndDlg;
+ HINSTANCE hInstance; //module containing the dialog template
+ LPCSTR lpTemplate; //dialog template
+ LPARAM lParam; //caller-defined
+ DIALOGRESIZERPROC pfnResizer;
+} UTILRESIZEDIALOG;
+#define RD_ANCHORX_CUSTOM 0 //function did everything required to the x axis, do no more processing
+#define RD_ANCHORX_LEFT 0 //move the control to keep it constant distance from the left edge of the dialog
+#define RD_ANCHORX_RIGHT 1 //move the control to keep it constant distance from the right edge of the dialog
+#define RD_ANCHORX_WIDTH 2 //size the control to keep it constant distance from both edges of the dialog
+#define RD_ANCHORX_CENTRE 4 //move the control to keep it constant distance from the centre of the dialog
+#define RD_ANCHORY_CUSTOM 0
+#define RD_ANCHORY_TOP 0
+#define RD_ANCHORY_BOTTOM 8
+#define RD_ANCHORY_HEIGHT 16
+#define RD_ANCHORY_CENTRE 32
+#define MS_UTILS_RESIZEDIALOG "Utils/ResizeDialog"
+
+/* Gets the name of a country given its number v0.1.2.0+
+wParam=countryId
+lParam=0
+Returns a pointer to the string containing the country name on success,
+or NULL on failure
+*/
+#define MS_UTILS_GETCOUNTRYBYNUMBER "Utils/GetCountryByNumber"
+
+/* Gets the full list of country IDs v0.1.2.0+
+wParam=(WPARAM)(int*)piCount
+lParam=(LPARAM)(struct CountryListEntry**)ppList
+Returns 0 always
+Neither wParam nor lParam can be NULL.
+The list is sorted alphabetically by country name, on the assumption that it's
+quicker to search numbers out of order than it is to search names out of order
+*/
+struct CountryListEntry {
+ int id;
+ const char *szName;
+};
+#define MS_UTILS_GETCOUNTRYLIST "Utils/GetCountryList"
+
+/******************************* Window lists *******************************/
+
+//allocate a window list v0.1.0.1+
+//wParam=lParam=0
+//returns a handle to the new window list
+#define MS_UTILS_ALLOCWINDOWLIST "Utils/AllocWindowList"
+
+//adds a window to the specified window list v0.1.0.1+
+//wParam=0
+//lParam=(LPARAM)(WINDOWLISTENTRY*)&wle
+//returns 0 on success, nonzero on failure
+typedef struct {
+ HANDLE hList;
+ HWND hwnd;
+ HANDLE hContact;
+} WINDOWLISTENTRY;
+#define MS_UTILS_ADDTOWINDOWLIST "Utils/AddToWindowList"
+__inline static int WindowList_Add(HANDLE hList,HWND hwnd,HANDLE hContact) {
+ WINDOWLISTENTRY wle;
+ wle.hList=hList; wle.hwnd=hwnd; wle.hContact=hContact;
+ return CallService(MS_UTILS_ADDTOWINDOWLIST,0,(LPARAM)&wle);
+}
+//removes a window from the specified window list v0.1.0.1+
+//wParam=(WPARAM)(HANDLE)hList
+//lParam=(LPARAM)(HWND)hwnd
+//returns 0 on success, nonzero on failure
+#define MS_UTILS_REMOVEFROMWINDOWLIST "Utils/RemoveFromWindowList"
+__inline static int WindowList_Remove(HANDLE hList,HWND hwnd) {
+ return CallService(MS_UTILS_REMOVEFROMWINDOWLIST,(WPARAM)hList,(LPARAM)hwnd);
+}
+
+//finds a window given the hContact v0.1.0.1+
+//wParam=(WPARAM)(HANDLE)hList
+//lParam=(WPARAM)(HANDLE)hContact
+//returns the window handle on success, or NULL on failure
+#define MS_UTILS_FINDWINDOWINLIST "Utils/FindWindowInList"
+__inline static HWND WindowList_Find(HANDLE hList,HANDLE hContact) {
+ return (HWND)CallService(MS_UTILS_FINDWINDOWINLIST,(WPARAM)hList,(LPARAM)hContact);
+}
+
+//broadcasts a message to all windows in a list v0.1.0.1+
+//wParam=(WPARAM)(HANDLE)hList
+//lParam=(LPARAM)(MSG*)&msg
+//returns 0 on success, nonzero on failure
+//Only msg.message, msg.wParam and msg.lParam are used
+#define MS_UTILS_BROADCASTTOWINDOWLIST "Utils/BroadcastToWindowList"
+__inline static int WindowList_Broadcast(HANDLE hList,UINT message,WPARAM wParam,LPARAM lParam) {
+ MSG msg;
+ msg.message=message; msg.wParam=wParam; msg.lParam=lParam;
+ return CallService(MS_UTILS_BROADCASTTOWINDOWLIST,(WPARAM)hList,(LPARAM)&msg);
+}
+
+/*
+ Description: Broadcast a message to all windows in the given list using PostMessage()
+ Version: 0.3.0.0+
+ Inline helper: WindowList_BroadcastAsync
+
+ wParam=(WPARAM)(HANDLE)hList
+ lParam=(LPARAM)(MSG*)&msg
+
+ Returns 0 on success, nonzero on failure, this service does not fail, even if PostMessage() fails for whatever reason
+
+*/
+#define MS_UTILS_BROADCASTTOWINDOWLIST_ASYNC "Utils/BroadcastToWindowListAsync"
+
+__inline static int WindowList_BroadcastAsync(HANDLE hList,UINT message,WPARAM wParam,LPARAM lParam) {
+ MSG msg;
+ msg.message=message; msg.wParam=wParam; msg.lParam=lParam;
+ return CallService(MS_UTILS_BROADCASTTOWINDOWLIST_ASYNC,(WPARAM)hList,(LPARAM)&msg);
+}
+
+/***************************** Hyperlink windows ********************************/
+
+//there aren't any services here, because you don't need them.
+#define WNDCLASS_HYPERLINK _T("Hyperlink")
+//the control will obey the SS_LEFT (0), SS_CENTER (1), and SS_RIGHT (2) styles
+//the control will send STN_CLICKED via WM_COMMAND when the link itself is clicked
+
+// Use this in a SendMessage to set the color of the url when control is enabled
+// wParam=DWORD color
+// lParam=not used
+#define HLK_SETENABLECOLOUR (WM_USER+101) // added in 0.3.1
+// Use this in a SendMessage to set the color of the url when control is disabled
+// wParam=DWORD color
+// lParam=not used
+#define HLK_SETDISABLECOLOUR (WM_USER+102) // added in 0.3.1
+
+/***************************** Window Position Saving ***************************/
+
+//saves the position of a window in the database v0.1.1.0+
+//wParam=0
+//lParam=(LPARAM)(SAVEWINDOWPOS*)&swp
+//returns 0 on success, nonzero on failure
+typedef struct {
+ HWND hwnd;
+ HANDLE hContact;
+ const char *szModule; //module name to store the setting in
+ const char *szNamePrefix; //text to prefix on "x", "width", etc, to form setting names
+} SAVEWINDOWPOS;
+#define MS_UTILS_SAVEWINDOWPOSITION "Utils/SaveWindowPos"
+__inline static int Utils_SaveWindowPosition(HWND hwnd,HANDLE hContact,const char *szModule,const char *szNamePrefix) {
+ SAVEWINDOWPOS swp;
+ swp.hwnd=hwnd; swp.hContact=hContact; swp.szModule=szModule; swp.szNamePrefix=szNamePrefix;
+ return CallService(MS_UTILS_SAVEWINDOWPOSITION,0,(LPARAM)&swp);
+}
+
+//restores the position of a window from the database v0.1.1.0+
+//wParam=flags
+//lParam=(LPARAM)(SAVEWINDOWPOS*)&swp
+//returns 0 on success, nonzero on failure
+//if no position was found in the database, the function returns 1 and does
+//nothing
+//the NoSize version won't use stored size information: the window is left the
+//same size.
+#define RWPF_NOSIZE 1 //don't use stored size info: leave dialog same size
+#define RWPF_NOMOVE 2 //don't use stored position
+#define RWPF_NOACTIVATE 4 //show but don't activate v0.3.3.0+
+#define MS_UTILS_RESTOREWINDOWPOSITION "Utils/RestoreWindowPos"
+__inline static int Utils_RestoreWindowPosition(HWND hwnd,HANDLE hContact,const char *szModule,const char *szNamePrefix) {
+ SAVEWINDOWPOS swp;
+ swp.hwnd=hwnd; swp.hContact=hContact; swp.szModule=szModule; swp.szNamePrefix=szNamePrefix;
+ return CallService(MS_UTILS_RESTOREWINDOWPOSITION,0,(LPARAM)&swp);
+}
+__inline static int Utils_RestoreWindowPositionNoSize(HWND hwnd,HANDLE hContact,const char *szModule,const char *szNamePrefix) {
+ SAVEWINDOWPOS swp;
+ swp.hwnd=hwnd; swp.hContact=hContact; swp.szModule=szModule; swp.szNamePrefix=szNamePrefix;
+ return CallService(MS_UTILS_RESTOREWINDOWPOSITION,RWPF_NOSIZE,(LPARAM)&swp);
+}
+__inline static int Utils_RestoreWindowPositionNoMove(HWND hwnd,HANDLE hContact,const char *szModule,const char *szNamePrefix) {
+ SAVEWINDOWPOS swp;
+ swp.hwnd=hwnd; swp.hContact=hContact; swp.szModule=szModule; swp.szNamePrefix=szNamePrefix;
+ return CallService(MS_UTILS_RESTOREWINDOWPOSITION,RWPF_NOMOVE,(LPARAM)&swp);
+}
+
+/************************ Colour Picker Control (0.1.2.1+) **********************/
+
+#define WNDCLASS_COLOURPICKER _T("ColourPicker")
+
+#define CPM_SETCOLOUR 0x1000 //lParam=new colour
+#define CPM_GETCOLOUR 0x1001 //returns colour
+#define CPM_SETDEFAULTCOLOUR 0x1002 //lParam=default, used as first custom colour
+#define CPM_GETDEFAULTCOLOUR 0x1003 //returns colour
+#define CPN_COLOURCHANGED 1 //sent through WM_COMMAND
+
+/***************************** Bitmap Filter (0.1.2.1+) *************************/
+
+//Loads a bitmap v0.1.2.1+
+//wParam=0
+//lParam=(LPARAM)(const char*)filename
+//returns HBITMAP on success, NULL on failure
+//This function uses OleLoadPicturePath() so supports BMP, JPEG and GIF. It may
+//support PNG on future versions of Windows (or XP for that matter)
+//For speed, if the file extension is .bmp or .rle it'll use LoadImage() so as
+//to avoid the big lag loading OLE.
+//Remember to DeleteObject() when you're done
+#define MS_UTILS_LOADBITMAP "Utils/LoadBitmap"
+
+//Gets the filter strings for use in the open file dialog v0.1.2.1+
+//wParam=cbLengthOfBuffer
+//lParam=(LPARAM)(char*)pszBuffer
+//Returns 0 on success, nonzero on failure
+//See the MSDN under OPENFILENAME.lpstrFilter for the formatting
+//An 'All Bitmaps' item is always first and 'All Files' is last.
+//The returned string is already translated.
+#define MS_UTILS_GETBITMAPFILTERSTRINGS "Utils/GetBitmapFilterStrings"
+
+//Saves a path to a relative path (from the miranda directory)
+//Only saves as a relative path if the file is in the miranda directory (or
+//sub directory)
+//wParam=(WPARAM)(char*)pszPath
+//lParam=(LPARAM)(char*)pszNewPath
+//pszPath is the path to convert and pszNewPath is the buffer that
+//the new path is copied too. pszNewPath MUST be of the size MAX_PATH.
+//Returns numbers of chars copied.
+#define MS_UTILS_PATHTORELATIVE "Utils/PathToRelative"
+
+//Saves a path to a absolute path (from the miranda directory)
+//wParam=(WPARAM)(char*)pszPath
+//lParam=(LPARAM)(char*)pszNewPath
+//pszPath is the path to convert and pszNewPath is the buffer that
+//the new path is copied too. pszNewPath MUST be of the size MAX_PATH.
+//Returns numbers of chars copied.
+#define MS_UTILS_PATHTOABSOLUTE "Utils/PathToAbsolute"
+
+// Added in 0.4.0.1
+// Here are some string wrappers that are more safe than the win32 versions
+
+static __inline int mir_snprintf(char *buffer, size_t count, const char* fmt, ...) {
+ va_list va;
+ int len;
+
+ va_start(va, fmt);
+ len = _vsnprintf(buffer, count-1, fmt, va);
+ va_end(va);
+ buffer[count-1] = 0;
+ return len;
+}
+
+static __inline int mir_sntprintf(TCHAR *buffer, size_t count, const TCHAR* fmt, ...) {
+ va_list va;
+ int len;
+
+ va_start(va, fmt);
+ len = _vsntprintf(buffer, count-1, fmt, va);
+ va_end(va);
+ buffer[count-1] = 0;
+ return len;
+}
+
+static __inline int mir_vsnprintf(char *buffer, size_t count, const char* fmt, va_list va) {
+ int len;
+
+ len = _vsnprintf(buffer, count-1, fmt, va);
+ buffer[count-1] = 0;
+ return len;
+}
+
+#endif // M_UTILS_H__
diff --git a/miranda-wine/include/newpluginapi.h b/miranda-wine/include/newpluginapi.h
new file mode 100644
index 0000000..809c57e
--- /dev/null
+++ b/miranda-wine/include/newpluginapi.h
@@ -0,0 +1,169 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 M_NEWPLUGINAPI_H__
+#define M_NEWPLUGINAPI_H__
+
+#include "m_plugins.h"
+
+#define PLUGIN_MAKE_VERSION(a,b,c,d) (((((DWORD)(a))&0xFF)<<24)|((((DWORD)(b))&0xFF)<<16)|((((DWORD)(c))&0xFF)<<8)|(((DWORD)(d))&0xFF))
+#define MAXMODULELABELLENGTH 64
+
+#if defined( _UNICODE )
+ #define UNICODE_AWARE 1
+#else
+ #define UNICODE_AWARE 0
+#endif
+
+typedef struct {
+ int cbSize;
+ char *shortName;
+ DWORD version;
+ char *description;
+ char *author;
+ char *authorEmail;
+ char *copyright;
+ char *homepage;
+ BYTE isTransient; //leave this as 0 for now
+ int replacesDefaultModule; //one of the DEFMOD_ constants in m_plugins.h or zero
+ //if non-zero, this will supress the loading of the specified built-in module
+ //with the implication that this plugin provides back-end-compatible features
+} PLUGININFO;
+
+#ifndef MODULES_H_
+typedef int (*MIRANDAHOOK)(WPARAM,LPARAM);
+typedef int (*MIRANDASERVICE)(WPARAM,LPARAM);
+#define CALLSERVICE_NOTFOUND ((int)0x80000000)
+#endif
+
+//see modules.h for what all this stuff is
+typedef struct {
+ HANDLE (*CreateHookableEvent)(const char *);
+ int (*DestroyHookableEvent)(HANDLE);
+ int (*NotifyEventHooks)(HANDLE,WPARAM,LPARAM);
+ HANDLE (*HookEvent)(const char *,MIRANDAHOOK);
+ HANDLE (*HookEventMessage)(const char *,HWND,UINT);
+ int (*UnhookEvent)(HANDLE);
+ HANDLE (*CreateServiceFunction)(const char *,MIRANDASERVICE);
+ HANDLE (*CreateTransientServiceFunction)(const char *,MIRANDASERVICE);
+ int (*DestroyServiceFunction)(HANDLE);
+ int (*CallService)(const char *,WPARAM,LPARAM);
+ int (*ServiceExists)(const char *); //v0.1.0.1+
+ int (*CallServiceSync)(const char *,WPARAM,LPARAM); //v0.3.3+
+ int (*CallFunctionAsync) (void (__stdcall *)(void *), void *); //v0.3.4+
+ int (*SetHookDefaultForHookableEvent) (HANDLE, MIRANDAHOOK); // v0.3.4 (2004/09/15)
+} PLUGINLINK;
+
+#ifndef MODULES_H_
+#ifndef NODEFINEDLINKFUNCTIONS
+//relies on a global variable 'pluginLink' in the plugins
+extern PLUGINLINK *pluginLink;
+#define CreateHookableEvent(a) pluginLink->CreateHookableEvent(a)
+#define DestroyHookableEvent(a) pluginLink->DestroyHookableEvent(a)
+#define NotifyEventHooks(a,b,c) pluginLink->NotifyEventHooks(a,b,c)
+#define HookEventMessage(a,b,c) pluginLink->HookEventMessage(a,b,c)
+#define HookEvent(a,b) pluginLink->HookEvent(a,b)
+#define UnhookEvent(a) pluginLink->UnhookEvent(a)
+#define CreateServiceFunction(a,b) pluginLink->CreateServiceFunction(a,b)
+#define CreateTransientServiceFunction(a,b) pluginLink->CreateTransientServiceFunction(a,b)
+#define DestroyServiceFunction(a) pluginLink->DestroyServiceFunction(a)
+#define CallService(a,b,c) pluginLink->CallService(a,b,c)
+#define ServiceExists(a) pluginLink->ServiceExists(a)
+#define CallServiceSync(a,b,c) pluginLink->CallServiceSync(a,b,c)
+#define CallFunctionAsync(a,b) pluginLink->CallFunctionAsync(a,b)
+#define SetHookDefaultForHookableEvent(a,b) pluginLink->SetHookDefaultForHookableEvent(a,b)
+#endif
+#endif
+
+/*
+ Database plugin stuff
+*/
+
+// grokHeader() error codes
+#define EGROKPRF_NOERROR 0
+#define EGROKPRF_CANTREAD 1 // can't open the profile for reading
+#define EGROKPRF_UNKHEADER 2 // header not supported, not a supported profile
+#define EGROKPRF_VERNEWER 3 // header correct, version in profile newer than reader/writer
+#define EGROKPRF_DAMAGED 4 // header/version fine, other internal data missing, damaged.
+
+// makeDatabase() error codes
+#define EMKPRF_CREATEFAILED 1 // for some reason CreateFile() didnt like something
+
+typedef struct {
+ int cbSize;
+
+ /*
+ returns what the driver can do given the flag
+ */
+ int (*getCapability) ( int flag );
+
+ /*
+ buf: pointer to a string buffer
+ cch: length of buffer
+ shortName: if true, the driver should return a short but descriptive name, e.g. "3.xx profile"
+ Affect: The database plugin must return a "friendly name" into buf and not exceed cch bytes,
+ e.g. "Database driver for 3.xx profiles"
+ Returns: 0 on success, non zero on failure
+ */
+ int (*getFriendlyName) ( char * buf, size_t cch, int shortName );
+
+ /*
+ profile: pointer to a string which contains full path + name
+ Affect: The database plugin should create the profile, the filepath will not exist at
+ the time of this call, profile will be C:\..\<name>.dat
+ Note: Do not prompt the user in anyway about this operation.
+ Note: Do not initialise internal data structures at this point!
+ Returns: 0 on success, non zero on failure - error contains extended error information, see EMKPRF_*
+ */
+ int (*makeDatabase) ( char * profile, int * error );
+
+ /*
+ profile: [in] a null terminated string to file path of selected profile
+ error: [in/out] pointer to an int to set with error if any
+ Affect: Ask the database plugin if it supports the given profile, if it does it will
+ return 0, if it doesnt return 1, with the error set in error -- EGROKPRF_* can be valid error
+ condition, most common error would be [EGROKPRF_UNKHEADER]
+ Note: Just because 1 is returned, doesnt mean the profile is not supported, the profile might be damaged
+ etc.
+ Returns: 0 on success, non zero on failure
+ */
+ int (*grokHeader) ( char * profile, int * error );
+
+ /*
+ Affect: Tell the database to create all services/hooks that a 3.xx legecy database might support into link,
+ which is a PLUGINLINK structure
+ Returns: 0 on success, nonzero on failure
+ */
+ int (*Load) ( char * profile, void * link );
+
+ /*
+ Affect: The database plugin should shutdown, unloading things from the core and freeing internal structures
+ Returns: 0 on success, nonzero on failure
+ Note: Unload() might be called even if Load() was never called, wasLoaded is set to 1 if Load() was ever called.
+ */
+ int (*Unload) ( int wasLoaded );
+
+} DATABASELINK;
+
+#endif // M_NEWPLUGINAPI_H__
+
diff --git a/miranda-wine/include/statusmodes.h b/miranda-wine/include/statusmodes.h
new file mode 100644
index 0000000..3b99de2
--- /dev/null
+++ b/miranda-wine/include/statusmodes.h
@@ -0,0 +1,48 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 STATUSMODES_H__
+#define STATUSMODES_H__ 1
+
+//add 1 to ID_STATUS_CONNECTING to mark retries (v0.1.0.1+)
+//eg ID_STATUS_CONNECTING+2 is the third connection attempt, or the second retry
+#define ID_STATUS_CONNECTING 1
+//max retries is just a marker so that the clist knows what numbers represent
+//retries. It does not set any kind of limit on the number of retries you can
+//and/or should do.
+#define MAX_CONNECT_RETRIES 10000
+#define ID_STATUS_OFFLINE 40071
+#define ID_STATUS_ONLINE 40072
+#define ID_STATUS_AWAY 40073
+#define ID_STATUS_DND 40074
+#define ID_STATUS_NA 40075
+#define ID_STATUS_OCCUPIED 40076
+#define ID_STATUS_FREECHAT 40077
+#define ID_STATUS_INVISIBLE 40078
+#define ID_STATUS_ONTHEPHONE 40079
+#define ID_STATUS_OUTTOLUNCH 40080
+#define ID_STATUS_IDLE 40081 /* do not use as a status */
+
+#endif // STATUSMODES_H__
+
+
diff --git a/miranda-wine/include/win2k.h b/miranda-wine/include/win2k.h
new file mode 100644
index 0000000..0853d64
--- /dev/null
+++ b/miranda-wine/include/win2k.h
@@ -0,0 +1,295 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 WIN2K_H__
+#define WIN2K_H__ 1
+
+/*
+This file was made to define the new constants normally provided by the windows
+sdk you can get from http://www.microsoft.com/msdownload/platformsdk/sdkupdate/
+To not need to install the whole sdk you can simply comment out the following lines.
+To make myself clear, you are supposed to use the sdk, this is just a work around.
+
+All constants are normally declared in winuser.h
+
+File created by Christian Kästner, and tweaked a bit by Richard Hughes*/
+
+//Windows versions in order of feature presence is:
+//95, NT4, 98, ME, 2000, XP
+//This is chronological order of release except for ME/2000. ME is barely an
+//improvement on 98.
+//These macros use the above order, not release order.
+#define WinVerMajor() LOBYTE(LOWORD(GetVersion()))
+#define WinVerMinor() HIBYTE(LOWORD(GetVersion()))
+#define IsWinVerNT() ((GetVersion()&0x80000000)==0)
+// IsWinVerNT4Plus() is buggy, Windows 98 is 4.10.1998
+#define IsWinVerNT4Plus() (WinVerMajor()>=5 || WinVerMinor()>0 || IsWinVerNT())
+#define IsWinVer98Plus() (LOWORD(GetVersion())!=4)
+#define IsWinVerMEPlus() (WinVerMajor()>=5 || WinVerMinor()>10)
+#define IsWinVer2000Plus() (WinVerMajor()>=5)
+#define IsWinVerXPPlus() (WinVerMajor()>=5 && LOWORD(GetVersion())!=5)
+
+// put stuff that's not apart of any SDKs but is used nonetheless
+
+#define SIZEOF(X) (sizeof(X)/sizeof(X[0]))
+
+//mii was extended for NT5/Win98, so need the old length for some stuff
+#define MENUITEMINFO_V4_SIZE (offsetof(MENUITEMINFO,cch)+sizeof((*((MENUITEMINFO*)0)).cch))
+
+#if _MSC_VER >= 1300
+#define NOWIN2K
+#endif
+
+#if WINVER >= 0x501
+#define NOWIN2K
+#endif
+
+#ifdef _MSC_VER
+#define BIGI(x) x##i64
+#else
+#define BIGI(x) x##LL
+#endif
+
+#if _MSC_VER
+ // uxtheme.h defines
+ #ifndef THEMEAPI
+ #define WM_THEMECHANGED 0x031A // when windows changes themes
+ #define BP_PUSHBUTTON 1 // Push Button Type
+ #define PBS_NORMAL 1
+ #define PBS_HOT 2
+ #define PBS_PRESSED 3
+ #define PBS_DISABLED 4
+ #define PBS_DEFAULTED 5
+ #define BP_CHECKBOX 3 // CheckBox Type
+ #define TP_BUTTON 1
+ #define TS_NORMAL 1
+ #define TS_HOT 2
+ #define TS_PRESSED 3
+ #define TS_DISABLED 4
+ #define TS_CHECKED 5
+ #define TS_HOTCHECKED 6
+ #define CBS_UNCHECKEDNORMAL 1
+ #define CBS_UNCHECKEDHOT 2
+ #define CBS_CHECKEDNORMAL 5
+ #define CBS_CHECKEDHOT 6
+ #endif
+#endif
+
+#if defined (__GNUC__)
+ #define SECURITY_ENTRYPOINTA "InitSecurityInterfaceA"
+ #define SECURITY_ENTRYPOINT SECURITY_ENTRYPOINTA
+ #define FreeCredentialsHandle FreeCredentialsHandle
+ #ifndef CDSIZEOF_STRUCT
+ #define CDSIZEOF_STRUCT(structname, member) (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member))
+ #endif
+ #ifndef OPENFILENAME_SIZE_VERSION_400
+ #define OPENFILENAME_SIZE_VERSION_400 CDSIZEOF_STRUCT(OPENFILENAME,lpTemplateName)
+ #endif
+ #ifndef NOTIFYICONDATAA_V1_SIZE
+ #define NOTIFYICONDATAA_V1_SIZE CDSIZEOF_STRUCT(NOTIFYICONDATAA, szTip[64])
+ #endif
+ #ifndef NOTIFYICONDATA_V1_SIZE
+ #define NOTIFYICONDATA_V1_SIZE CDSIZEOF_STRUCT(NOTIFYICONDATA, szTip[64])
+ #endif
+ typedef struct tagNMKEY {
+ NMHDR hdr;
+ UINT nVKey;
+ UINT uFlags;
+ } NMKEY, *LPNMKEY;
+ #define ODS_HOTLIGHT 0x0040
+ #define ODS_INACTIVE 0x0080
+ #define SPI_GETFLATMENU 0x1022
+ #define COLOR_HOTLIGHT 26
+ #define COLOR_MENUBAR 30
+ #define COLOR_MENUHILIGHT 29
+ #define COLOR_HIGHLIGHT 13
+ #define BP_PUSHBUTTON 1 // Push Button Type
+ #define PBS_NORMAL 1
+ #define PBS_HOT 2
+ #define PBS_PRESSED 3
+ #define PBS_DISABLED 4
+ #define PBS_DEFAULTED 5
+ #define BP_CHECKBOX 3 // CheckBox Type
+ #define TP_BUTTON 1
+ #define TS_NORMAL 1
+ #define TS_HOT 2
+ #define TS_PRESSED 3
+ #define TS_DISABLED 4
+ #define TS_CHECKED 5
+ #define TS_HOTCHECKED 6
+ #define CBS_UNCHECKEDNORMAL 1
+ #define CBS_UNCHECKEDHOT 2
+ #define CBS_CHECKEDNORMAL 5
+ #define CBS_CHECKEDHOT 6
+// SDK isn't present or some older VC compiler was used, include missing things.
+#elif !defined(NOWIN2K) && (!defined WS_EX_LAYERED || !defined IDC_HAND)
+
+ #pragma message("win2k.h")
+
+ #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
+
+ #define PSDK_WORKAROUND
+
+ #define MONITOR_DEFAULTTONEAREST 2
+
+ #ifndef EM_SETTEXTEX
+ #define EM_SETTEXTEX (WM_USER + 97)
+ #define ST_DEFAULT 0
+ #define ST_KEEPUNDO 1
+ #define ST_SELECTION 2
+ #define ST_NEWCHARS 4
+ typedef struct _settextex
+ {
+ DWORD flags;
+ UINT codepage;
+ } SETTEXTEX;
+ #endif
+
+ #if(_WIN32_WINNT >= 0x0500)
+ #define WS_EX_LAYERED 0x00080000
+ #define MIIM_STRING 0x00000040
+ #define MIIM_BITMAP 0x00000080
+ #define MIIM_FTYPE 0x00000100
+ #define HBMMENU_CALLBACK ((HBITMAP) -1)
+ #define ODS_HOTLIGHT 0x0040
+ #define ODS_INACTIVE 0x0080
+ #define IDC_HAND MAKEINTRESOURCE(32649)
+ #define COLOR_HOTLIGHT 26
+ #define COLOR_MENUBAR 30
+ #define COLOR_MENUHILIGHT 29
+ #define COLOR_HIGHLIGHT 13
+ #define SPI_GETFLATMENU 0x1022
+ #define TVS_NOHSCROLL 0x8000
+ #define SPI_GETLISTBOXSMOOTHSCROLLING 0x1006
+ #define SPI_GETHOTTRACKING 0x100E
+ #define BIF_NEWDIALOGSTYLE 0x0040
+ #define LVS_EX_LABELTIP 0x00004000
+ #define DFCS_HOT 0x1000
+ #define FLASHW_TRAY 0x00000002;
+ typedef struct {
+ UINT cbSize;
+ HWND hwnd;
+ DWORD dwFlags;
+ UINT uCount;
+ DWORD dwTimeout;
+ } FLASHWINFO;
+ /* for the help plugin without the SDK */
+ #define SM_XVIRTUALSCREEN 76
+ #define SM_YVIRTUALSCREEN 77
+ #define SM_CXVIRTUALSCREEN 78
+ #define SM_CYVIRTUALSCREEN 79
+ #define COLOR_HOTLIGHT 26
+ #define VK_OEM_PLUS 0xBB
+ #define VK_OEM_MINUS 0xBD
+
+ /* the structure only needs to be defined for VC5 or lower */
+ #if _MSC_VER < 1200
+ typedef struct tagLASTINPUTINFO {
+ UINT cbSize;
+ DWORD dwTime;
+ } LASTINPUTINFO, *PLASTINPUTINFO;
+ #endif /* #if _MSC_VER < 1200 */
+
+ #ifndef OPENFILENAME_SIZE_VERSION_400
+ #define OPENFILENAME_SIZE_VERSION_400 sizeof(OPENFILENAME)
+ #endif
+
+ #ifndef CCM_SETVERSION
+ #define CCM_SETVERSION (CCM_FIRST + 0x7)
+ #endif
+
+ #define SYSRGN 4
+ WINGDIAPI int WINAPI GetRandomRgn(IN HDC, IN HRGN, IN INT);
+
+ #endif /* _WIN32_WINNT >= 0x0500 */
+
+ #define LWA_ALPHA 0x00000002
+ #define AW_HIDE 0x00010000
+ #define AW_BLEND 0x00080000
+ #define SPI_GETSCREENSAVERRUNNING 114
+ #define SM_CMONITORS 80
+
+ #ifndef AW_ACTIVATE
+ #define AW_ACTIVATE 0x00020000
+ #define AW_SLIDE 0x00040000
+ #define AW_VER_NEGATIVE 0x00000008
+ #define AW_HOR_POSITIVE 0x00000001
+ #endif
+
+ #ifndef DWORD_PTR
+ typedef DWORD DWORD_PTR;
+ #endif
+
+ #ifndef HMONITOR
+ DECLARE_HANDLE(HMONITOR);
+ typedef struct tagMONITORINFO
+ {
+ DWORD cbSize;
+ RECT rcMonitor;
+ RECT rcWork;
+ DWORD dwFlags;
+ } MONITORINFO, *LPMONITORINFO;
+ #endif
+
+
+ #ifndef IDropTargetHelper
+ #define INTERFACE IDropTargetHelper
+ DECLARE_INTERFACE_( IDropTargetHelper, IUnknown )
+ {
+ // IUnknown methods
+ STDMETHOD (QueryInterface)(THIS_ REFIID riid, void **ppv) PURE;
+ STDMETHOD_(ULONG, AddRef) ( THIS ) PURE;
+ STDMETHOD_(ULONG, Release) ( THIS ) PURE;
+
+ // IDropTargetHelper
+ STDMETHOD (DragEnter)(THIS_ HWND hwndTarget, IDataObject* pDataObject,
+ POINT* ppt, DWORD dwEffect) PURE;
+ STDMETHOD (DragLeave)(THIS) PURE;
+ STDMETHOD (DragOver)(THIS_ POINT* ppt, DWORD dwEffect) PURE;
+ STDMETHOD (Drop)(THIS_ IDataObject* pDataObject, POINT* ppt,
+ DWORD dwEffect) PURE;
+ STDMETHOD (Show)(THIS_ BOOL fShow) PURE;
+
+ };
+ #endif /* IDropTargetHelper */
+
+ #define WM_MENURBUTTONUP 0x0122
+
+// tabsrmm uses these
+
+#define SES_EXTENDBACKCOLOR 4
+#define EM_SETEDITSTYLE (WM_USER + 204)
+#define EM_SETSCROLLPOS (WM_USER + 222)
+#define SF_USECODEPAGE 0x00000020
+
+#define TreeView_SetItemState(hwndTV, hti, data, _mask) \
+{ TVITEM _TVi; \
+ _TVi.mask = TVIF_STATE; \
+ _TVi.hItem = hti; \
+ _TVi.stateMask = _mask; \
+ _TVi.state = data; \
+ SendMessage((hwndTV), TVM_SETITEM, 0, (LPARAM)(TV_ITEM *)&_TVi); \
+}
+
+#endif /* SDK check */
+#endif // WIN2K_H__
diff --git a/miranda-wine/plugins/clist/clc.h b/miranda-wine/plugins/clist/clc.h
new file mode 100644
index 0000000..7b825dd
--- /dev/null
+++ b/miranda-wine/plugins/clist/clc.h
@@ -0,0 +1,83 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 FONTID_LAST 7
+
+struct ClcContact {
+ BYTE type;
+ BYTE flags;
+ union {
+ struct {
+ WORD iImage;
+ HANDLE hContact;
+ };
+ struct {
+ WORD groupId;
+ struct ClcGroup *group;
+ };
+ };
+ BYTE iExtraImage[MAXEXTRACOLUMNS];
+ TCHAR szText[120-MAXEXTRACOLUMNS];
+ char * proto; // MS_PROTO_GETBASEPROTO
+};
+
+struct ClcData {
+ struct ClcGroup list;
+ int rowHeight;
+ int yScroll;
+ int selection;
+ struct ClcFontInfo fontInfo[FONTID_MAX+1];
+ int scrollTime;
+ HIMAGELIST himlHighlight;
+ int groupIndent;
+ TCHAR szQuickSearch[128];
+ int iconXSpace;
+ HWND hwndRenameEdit;
+ COLORREF bkColour,selBkColour,selTextColour,hotTextColour,quickSearchColour;
+ int iDragItem,iInsertionMark;
+ int dragStage;
+ POINT ptDragStart;
+ int dragAutoScrolling;
+ int dragAutoScrollHeight;
+ int leftMargin;
+ int insertionMarkHitHeight;
+ HBITMAP hBmpBackground;
+ int backgroundBmpUse,bkChanged;
+ int iHotTrack;
+ int gammaCorrection;
+ DWORD greyoutFlags; //see m_clc.h
+ DWORD offlineModes;
+ DWORD exStyle;
+ POINT ptInfoTip;
+ int infoTipTimeout;
+ HANDLE hInfoTipItem;
+ HIMAGELIST himlExtraColumns;
+ int extraColumnsCount;
+ int extraColumnSpacing;
+ int checkboxSize;
+ int showSelAlways;
+ int showIdle;
+ int noVScrollbar;
+ int useWindowsColours;
+ int needsResort;
+};
diff --git a/miranda-wine/plugins/clist/clcopts.c b/miranda-wine/plugins/clist/clcopts.c
new file mode 100644
index 0000000..81f4950
--- /dev/null
+++ b/miranda-wine/plugins/clist/clcopts.c
@@ -0,0 +1,923 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+#define DBFONTF_BOLD 1
+#define DBFONTF_ITALIC 2
+#define DBFONTF_UNDERLINE 4
+
+struct CheckBoxToStyleEx_t
+{
+ int id;
+ DWORD flag;
+ int not;
+}
+
+static const checkBoxToStyleEx[] = {
+ {IDC_DISABLEDRAGDROP, CLS_EX_DISABLEDRAGDROP, 0},
+ {IDC_NOTEDITLABELS, CLS_EX_EDITLABELS, 1},
+ {IDC_SHOWSELALWAYS, CLS_EX_SHOWSELALWAYS, 0},
+ {IDC_TRACKSELECT, CLS_EX_TRACKSELECT, 0},
+ {IDC_SHOWGROUPCOUNTS, CLS_EX_SHOWGROUPCOUNTS, 0},
+ {IDC_HIDECOUNTSWHENEMPTY, CLS_EX_HIDECOUNTSWHENEMPTY, 0},
+ {IDC_DIVIDERONOFF, CLS_EX_DIVIDERONOFF, 0},
+ {IDC_NOTNOTRANSLUCENTSEL, CLS_EX_NOTRANSLUCENTSEL, 1},
+ {IDC_LINEWITHGROUPS, CLS_EX_LINEWITHGROUPS, 0},
+ {IDC_QUICKSEARCHVISONLY, CLS_EX_QUICKSEARCHVISONLY, 0},
+ {IDC_SORTGROUPSALPHA, CLS_EX_SORTGROUPSALPHA, 0},
+ {IDC_NOTNOSMOOTHSCROLLING, CLS_EX_NOSMOOTHSCROLLING, 1}
+};
+
+struct CheckBoxValues_t
+{
+ DWORD style;
+ TCHAR* szDescr;
+};
+
+static const struct CheckBoxValues_t greyoutValues[] = {
+ { GREYF_UNFOCUS, _T("Not focused") },
+ { MODEF_OFFLINE, _T("Offline") },
+ { PF2_ONLINE, _T("Online") },
+ { PF2_SHORTAWAY, _T("Away") },
+ { PF2_LONGAWAY, _T("NA") },
+ { PF2_LIGHTDND, _T("Occupied") },
+ { PF2_HEAVYDND, _T("DND") },
+ { PF2_FREECHAT, _T("Free for chat") },
+ { PF2_INVISIBLE, _T("Invisible") },
+ { PF2_OUTTOLUNCH, _T("Out to lunch") },
+ { PF2_ONTHEPHONE, _T("On the phone") }
+};
+
+static const struct CheckBoxValues_t offlineValues[] = {
+ { MODEF_OFFLINE, _T("Offline") },
+ { PF2_ONLINE, _T("Online") },
+ { PF2_SHORTAWAY, _T("Away") },
+ { PF2_LONGAWAY, _T("NA") },
+ { PF2_LIGHTDND, _T("Occupied") },
+ { PF2_HEAVYDND, _T("DND") },
+ { PF2_FREECHAT, _T("Free for chat") },
+ { PF2_INVISIBLE, _T("Invisible") },
+ { PF2_OUTTOLUNCH, _T("Out to lunch") },
+ { PF2_ONTHEPHONE, _T("On the phone") }
+};
+
+static void FillCheckBoxTree(HWND hwndTree, const struct CheckBoxValues_t *values, int nValues, DWORD style)
+{
+ TVINSERTSTRUCT tvis;
+ int i;
+
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_LAST;
+ tvis.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_STATE;
+ for (i = 0; i < nValues; i++) {
+ tvis.item.lParam = values[i].style;
+ tvis.item.pszText = TranslateTS( values[i].szDescr );
+ tvis.item.stateMask = TVIS_STATEIMAGEMASK;
+ tvis.item.state = INDEXTOSTATEIMAGEMASK((style & tvis.item.lParam) != 0 ? 2 : 1);
+ TreeView_InsertItem( hwndTree, &tvis);
+} }
+
+static DWORD MakeCheckBoxTreeFlags(HWND hwndTree)
+{
+ DWORD flags = 0;
+ TVITEM tvi;
+
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE;
+ tvi.hItem = TreeView_GetRoot(hwndTree);
+ while (tvi.hItem) {
+ TreeView_GetItem(hwndTree, &tvi);
+ if (((tvi.state & TVIS_STATEIMAGEMASK) >> 12 == 2))
+ flags |= tvi.lParam;
+ tvi.hItem = TreeView_GetNextSibling(hwndTree, tvi.hItem);
+ }
+ return flags;
+}
+
+static BOOL CALLBACK DlgProcClcMainOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLong(GetDlgItem(hwndDlg, IDC_GREYOUTOPTS), GWL_STYLE,
+ GetWindowLong(GetDlgItem(hwndDlg, IDC_GREYOUTOPTS), GWL_STYLE) | TVS_NOHSCROLL | TVS_CHECKBOXES);
+ SetWindowLong(GetDlgItem(hwndDlg, IDC_HIDEOFFLINEOPTS), GWL_STYLE,
+ GetWindowLong(GetDlgItem(hwndDlg, IDC_HIDEOFFLINEOPTS), GWL_STYLE) | TVS_NOHSCROLL | TVS_CHECKBOXES);
+ {
+ int i;
+ DWORD exStyle = DBGetContactSettingDword(NULL, "CLC", "ExStyle", pcli->pfnGetDefaultExStyle());
+ for (i = 0; i < SIZEOF(checkBoxToStyleEx); i++)
+ CheckDlgButton(hwndDlg, checkBoxToStyleEx[i].id,
+ (exStyle & checkBoxToStyleEx[i].flag) ^ (checkBoxToStyleEx[i].flag *
+ checkBoxToStyleEx[i].not) ? BST_CHECKED : BST_UNCHECKED);
+ }
+ {
+ UDACCEL accel[2] = { {0, 10} , {2, 50} };
+ SendDlgItemMessage(hwndDlg, IDC_SMOOTHTIMESPIN, UDM_SETRANGE, 0, MAKELONG(999, 0));
+ SendDlgItemMessage(hwndDlg, IDC_SMOOTHTIMESPIN, UDM_SETACCEL, SIZEOF(accel), (LPARAM) & accel);
+ SendDlgItemMessage(hwndDlg, IDC_SMOOTHTIMESPIN, UDM_SETPOS, 0,
+ MAKELONG(DBGetContactSettingWord(NULL, "CLC", "ScrollTime", CLCDEFAULT_SCROLLTIME), 0));
+ }
+ CheckDlgButton(hwndDlg, IDC_IDLE, DBGetContactSettingByte(NULL, "CLC", "ShowIdle", CLCDEFAULT_SHOWIDLE) ? BST_CHECKED : BST_UNCHECKED);
+ SendDlgItemMessage(hwndDlg, IDC_LEFTMARGINSPIN, UDM_SETRANGE, 0, MAKELONG(64, 0));
+ SendDlgItemMessage(hwndDlg, IDC_LEFTMARGINSPIN, UDM_SETPOS, 0,
+ MAKELONG(DBGetContactSettingByte(NULL, "CLC", "LeftMargin", CLCDEFAULT_LEFTMARGIN), 0));
+ SendDlgItemMessage(hwndDlg, IDC_GROUPINDENTSPIN, UDM_SETRANGE, 0, MAKELONG(50, 0));
+ SendDlgItemMessage(hwndDlg, IDC_GROUPINDENTSPIN, UDM_SETPOS, 0,
+ MAKELONG(DBGetContactSettingByte(NULL, "CLC", "GroupIndent", CLCDEFAULT_GROUPINDENT), 0));
+ CheckDlgButton(hwndDlg, IDC_GREYOUT,
+ DBGetContactSettingDword(NULL, "CLC", "GreyoutFlags", CLCDEFAULT_GREYOUTFLAGS) ? BST_CHECKED : BST_UNCHECKED);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SMOOTHTIME), IsDlgButtonChecked(hwndDlg, IDC_NOTNOSMOOTHSCROLLING));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_GREYOUTOPTS), IsDlgButtonChecked(hwndDlg, IDC_GREYOUT));
+ FillCheckBoxTree(GetDlgItem(hwndDlg, IDC_GREYOUTOPTS), greyoutValues, SIZEOF(greyoutValues),
+ DBGetContactSettingDword(NULL, "CLC", "FullGreyoutFlags", CLCDEFAULT_FULLGREYOUTFLAGS));
+ FillCheckBoxTree(GetDlgItem(hwndDlg, IDC_HIDEOFFLINEOPTS), offlineValues, SIZEOF(offlineValues),
+ DBGetContactSettingDword(NULL, "CLC", "OfflineModes", CLCDEFAULT_OFFLINEMODES));
+ CheckDlgButton(hwndDlg, IDC_NOSCROLLBAR, DBGetContactSettingByte(NULL, "CLC", "NoVScrollBar", 0) ? BST_CHECKED : BST_UNCHECKED);
+ return TRUE;
+ case WM_VSCROLL:
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDC_NOTNOSMOOTHSCROLLING)
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SMOOTHTIME), IsDlgButtonChecked(hwndDlg, IDC_NOTNOSMOOTHSCROLLING));
+ if (LOWORD(wParam) == IDC_GREYOUT)
+ EnableWindow(GetDlgItem(hwndDlg, IDC_GREYOUTOPTS), IsDlgButtonChecked(hwndDlg, IDC_GREYOUT));
+ if ((LOWORD(wParam) == IDC_LEFTMARGIN || LOWORD(wParam) == IDC_SMOOTHTIME || LOWORD(wParam) == IDC_GROUPINDENT)
+ && (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus()))
+ return 0;
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch (((LPNMHDR) lParam)->idFrom) {
+ case IDC_GREYOUTOPTS:
+ case IDC_HIDEOFFLINEOPTS:
+ if (((LPNMHDR) lParam)->code == NM_CLICK) {
+ TVHITTESTINFO hti;
+ hti.pt.x = (short) LOWORD(GetMessagePos());
+ hti.pt.y = (short) HIWORD(GetMessagePos());
+ ScreenToClient(((LPNMHDR) lParam)->hwndFrom, &hti.pt);
+ if (TreeView_HitTest(((LPNMHDR) lParam)->hwndFrom, &hti))
+ if (hti.flags & TVHT_ONITEMSTATEICON) {
+ TVITEM tvi;
+ tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ tvi.hItem = hti.hItem;
+ TreeView_GetItem(((LPNMHDR) lParam)->hwndFrom, &tvi);
+ tvi.iImage = tvi.iSelectedImage = tvi.iImage == 1 ? 2 : 1;
+ TreeView_SetItem(((LPNMHDR) lParam)->hwndFrom, &tvi);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ }
+ break;
+ case 0:
+ if (((LPNMHDR) lParam)->code == PSN_APPLY ) {
+ int i;
+ DWORD exStyle = 0;
+ for (i = 0; i < SIZEOF(checkBoxToStyleEx); i++)
+ if ((IsDlgButtonChecked(hwndDlg, checkBoxToStyleEx[i].id) == 0) == checkBoxToStyleEx[i].not)
+ exStyle |= checkBoxToStyleEx[i].flag;
+
+ DBWriteContactSettingDword(NULL, "CLC", "ExStyle", exStyle);
+ {
+ DWORD fullGreyoutFlags = MakeCheckBoxTreeFlags(GetDlgItem(hwndDlg, IDC_GREYOUTOPTS));
+ DBWriteContactSettingDword(NULL, "CLC", "FullGreyoutFlags", fullGreyoutFlags);
+ if (IsDlgButtonChecked(hwndDlg, IDC_GREYOUT))
+ DBWriteContactSettingDword(NULL, "CLC", "GreyoutFlags", fullGreyoutFlags);
+ else
+ DBWriteContactSettingDword(NULL, "CLC", "GreyoutFlags", 0);
+ }
+ DBWriteContactSettingByte(NULL, "CLC", "ShowIdle", (BYTE) (IsDlgButtonChecked(hwndDlg, IDC_IDLE) ? 1 : 0));
+ DBWriteContactSettingDword(NULL, "CLC", "OfflineModes", MakeCheckBoxTreeFlags(GetDlgItem(hwndDlg, IDC_HIDEOFFLINEOPTS)));
+ DBWriteContactSettingByte(NULL, "CLC", "LeftMargin",
+ (BYTE) SendDlgItemMessage(hwndDlg, IDC_LEFTMARGINSPIN, UDM_GETPOS, 0, 0));
+ DBWriteContactSettingWord(NULL, "CLC", "ScrollTime",
+ (WORD) SendDlgItemMessage(hwndDlg, IDC_SMOOTHTIMESPIN, UDM_GETPOS, 0, 0));
+ DBWriteContactSettingByte(NULL, "CLC", "GroupIndent",
+ (BYTE) SendDlgItemMessage(hwndDlg, IDC_GROUPINDENTSPIN, UDM_GETPOS, 0, 0));
+ DBWriteContactSettingByte(NULL, "CLC", "NoVScrollBar", (BYTE) (IsDlgButtonChecked(hwndDlg, IDC_NOSCROLLBAR) ? 1 : 0));
+ pcli->pfnClcOptionsChanged();
+ return TRUE;
+ }
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ ImageList_Destroy(TreeView_GetImageList(GetDlgItem(hwndDlg, IDC_GREYOUTOPTS), TVSIL_NORMAL));
+ break;
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK DlgProcClcBkgOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ CheckDlgButton(hwndDlg, IDC_BITMAP,
+ DBGetContactSettingByte(NULL, "CLC", "UseBitmap", CLCDEFAULT_USEBITMAP) ? BST_CHECKED : BST_UNCHECKED);
+ SendMessage(hwndDlg, WM_USER + 10, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_BKGCOLOUR, CPM_SETDEFAULTCOLOUR, 0, CLCDEFAULT_BKCOLOUR);
+ SendDlgItemMessage(hwndDlg, IDC_BKGCOLOUR, CPM_SETCOLOUR, 0, DBGetContactSettingDword(NULL, "CLC", "BkColour", CLCDEFAULT_BKCOLOUR));
+ SendDlgItemMessage(hwndDlg, IDC_SELCOLOUR, CPM_SETDEFAULTCOLOUR, 0, CLCDEFAULT_SELBKCOLOUR);
+ SendDlgItemMessage(hwndDlg, IDC_SELCOLOUR, CPM_SETCOLOUR, 0,
+ DBGetContactSettingDword(NULL, "CLC", "SelBkColour", CLCDEFAULT_SELBKCOLOUR));
+ CheckDlgButton(hwndDlg, IDC_WINCOLOUR, DBGetContactSettingByte(NULL, "CLC", "UseWinColours", 0));
+ SendMessage(hwndDlg, WM_USER + 11, 0, 0);
+ {
+ DBVARIANT dbv;
+ if (!DBGetContactSetting(NULL, "CLC", "BkBitmap", &dbv)) {
+ SetDlgItemTextA(hwndDlg, IDC_FILENAME, dbv.pszVal);
+ if (ServiceExists(MS_UTILS_PATHTOABSOLUTE)) {
+ char szPath[MAX_PATH];
+
+ if (CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM) dbv.pszVal, (LPARAM) szPath))
+ SetDlgItemTextA(hwndDlg, IDC_FILENAME, szPath);
+ }
+ else
+ mir_free(dbv.pszVal);
+ }
+ }
+ {
+ WORD bmpUse = DBGetContactSettingWord(NULL, "CLC", "BkBmpUse", CLCDEFAULT_BKBMPUSE);
+ CheckDlgButton(hwndDlg, IDC_STRETCHH, bmpUse & CLB_STRETCHH ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_STRETCHV, bmpUse & CLB_STRETCHV ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_TILEH, bmpUse & CLBF_TILEH ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_TILEV, bmpUse & CLBF_TILEV ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SCROLL, bmpUse & CLBF_SCROLL ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_PROPORTIONAL, bmpUse & CLBF_PROPORTIONAL ? BST_CHECKED : BST_UNCHECKED);
+ }
+ {
+ HRESULT(STDAPICALLTYPE * MySHAutoComplete) (HWND, DWORD);
+ MySHAutoComplete = (HRESULT(STDAPICALLTYPE *) (HWND, DWORD)) GetProcAddress(GetModuleHandleA("shlwapi"), "SHAutoComplete");
+ if (MySHAutoComplete)
+ MySHAutoComplete(GetDlgItem(hwndDlg, IDC_FILENAME), 1);
+ }
+ return TRUE;
+ case WM_USER + 10:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FILENAME), IsDlgButtonChecked(hwndDlg, IDC_BITMAP));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), IsDlgButtonChecked(hwndDlg, IDC_BITMAP));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_STRETCHH), IsDlgButtonChecked(hwndDlg, IDC_BITMAP));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_STRETCHV), IsDlgButtonChecked(hwndDlg, IDC_BITMAP));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_TILEH), IsDlgButtonChecked(hwndDlg, IDC_BITMAP));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_TILEV), IsDlgButtonChecked(hwndDlg, IDC_BITMAP));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SCROLL), IsDlgButtonChecked(hwndDlg, IDC_BITMAP));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_PROPORTIONAL), IsDlgButtonChecked(hwndDlg, IDC_BITMAP));
+ break;
+ case WM_USER + 11:
+ {
+ BOOL b = IsDlgButtonChecked(hwndDlg, IDC_WINCOLOUR);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BKGCOLOUR), !b);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SELCOLOUR), !b);
+ break;
+ }
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDC_BROWSE) {
+ char str[MAX_PATH];
+ OPENFILENAMEA ofn = { 0 };
+ char filter[512];
+
+ GetDlgItemTextA(hwndDlg, IDC_FILENAME, str, SIZEOF(str));
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner = hwndDlg;
+ ofn.hInstance = NULL;
+ CallService(MS_UTILS_GETBITMAPFILTERSTRINGS, SIZEOF(filter), (LPARAM) filter);
+ ofn.lpstrFilter = filter;
+ ofn.lpstrFile = str;
+ ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
+ ofn.nMaxFile = SIZEOF(str);
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.lpstrDefExt = "bmp";
+ if (!GetOpenFileNameA(&ofn))
+ break;
+ SetDlgItemTextA(hwndDlg, IDC_FILENAME, str);
+ }
+ else if (LOWORD(wParam) == IDC_FILENAME && HIWORD(wParam) != EN_CHANGE)
+ break;
+ if (LOWORD(wParam) == IDC_BITMAP)
+ SendMessage(hwndDlg, WM_USER + 10, 0, 0);
+ if (LOWORD(wParam) == IDC_WINCOLOUR)
+ SendMessage(hwndDlg, WM_USER + 11, 0, 0);
+ if (LOWORD(wParam) == IDC_FILENAME && (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus()))
+ return 0;
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch (((LPNMHDR) lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR) lParam)->code) {
+ case PSN_APPLY:
+ DBWriteContactSettingByte(NULL, "CLC", "UseBitmap", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_BITMAP));
+ {
+ COLORREF col;
+ col = SendDlgItemMessage(hwndDlg, IDC_BKGCOLOUR, CPM_GETCOLOUR, 0, 0);
+ if (col == CLCDEFAULT_BKCOLOUR)
+ DBDeleteContactSetting(NULL, "CLC", "BkColour");
+ else
+ DBWriteContactSettingDword(NULL, "CLC", "BkColour", col);
+ col = SendDlgItemMessage(hwndDlg, IDC_SELCOLOUR, CPM_GETCOLOUR, 0, 0);
+ if (col == CLCDEFAULT_SELBKCOLOUR)
+ DBDeleteContactSetting(NULL, "CLC", "SelBkColour");
+ else
+ DBWriteContactSettingDword(NULL, "CLC", "SelBkColour", col);
+ DBWriteContactSettingByte(NULL, "CLC", "UseWinColours", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_WINCOLOUR)));
+ }
+ {
+ char str[MAX_PATH], strrel[MAX_PATH];
+ GetDlgItemTextA(hwndDlg, IDC_FILENAME, str, SIZEOF(str));
+ if (ServiceExists(MS_UTILS_PATHTORELATIVE)) {
+ if (CallService(MS_UTILS_PATHTORELATIVE, (WPARAM) str, (LPARAM) strrel))
+ DBWriteContactSettingString(NULL, "CLC", "BkBitmap", strrel);
+ else
+ DBWriteContactSettingString(NULL, "CLC", "BkBitmap", str);
+ }
+ else
+ DBWriteContactSettingString(NULL, "CLC", "BkBitmap", str);
+ }
+ {
+ WORD flags = 0;
+ if (IsDlgButtonChecked(hwndDlg, IDC_STRETCHH))
+ flags |= CLB_STRETCHH;
+ if (IsDlgButtonChecked(hwndDlg, IDC_STRETCHV))
+ flags |= CLB_STRETCHV;
+ if (IsDlgButtonChecked(hwndDlg, IDC_TILEH))
+ flags |= CLBF_TILEH;
+ if (IsDlgButtonChecked(hwndDlg, IDC_TILEV))
+ flags |= CLBF_TILEV;
+ if (IsDlgButtonChecked(hwndDlg, IDC_SCROLL))
+ flags |= CLBF_SCROLL;
+ if (IsDlgButtonChecked(hwndDlg, IDC_PROPORTIONAL))
+ flags |= CLBF_PROPORTIONAL;
+ DBWriteContactSettingWord(NULL, "CLC", "BkBmpUse", flags);
+ }
+ pcli->pfnClcOptionsChanged();
+ return TRUE;
+ }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static const TCHAR* szFontIdDescr[FONTID_LAST + 1] =
+{
+ _T("Standard contacts"),
+ _T("Online contacts to whom you have a different visibility"),
+ _T("Offline contacts"),
+ _T("Contacts which are 'not on list'"),
+ _T("Groups"),
+ _T("Group member counts"),
+ _T("Dividers"),
+ _T("Offline contacts to whom you have a different visibility")
+};
+
+#define SAMEASF_FACE 1
+#define SAMEASF_SIZE 2
+#define SAMEASF_STYLE 4
+#define SAMEASF_COLOUR 8
+#include <pshpack1.h>
+struct
+{
+ BYTE sameAsFlags, sameAs;
+ COLORREF colour;
+ char size;
+ BYTE style;
+ BYTE charset;
+ TCHAR szFace[LF_FACESIZE];
+}
+static fontSettings[FONTID_LAST + 1];
+#include <poppack.h>
+static WORD fontSameAsDefault[FONTID_LAST + 1] = { 0x00FF, 0x0B00, 0x0F00, 0x0700, 0x0B00, 0x0104, 0x0D00, 0x0B02 };
+static char *fontSizes[] = { "7", "8", "10", "14", "16", "18", "20", "24", "28" };
+static int fontListOrder[FONTID_LAST + 1] =
+{ FONTID_CONTACTS, FONTID_INVIS, FONTID_OFFLINE, FONTID_OFFINVIS, FONTID_NOTONLIST, FONTID_GROUPS, FONTID_GROUPCOUNTS, FONTID_DIVIDERS };
+
+#define M_REBUILDFONTGROUP (WM_USER+10)
+#define M_REMAKESAMPLE (WM_USER+11)
+#define M_RECALCONEFONT (WM_USER+12)
+#define M_RECALCOTHERFONTS (WM_USER+13)
+#define M_SAVEFONT (WM_USER+14)
+#define M_REFRESHSAMEASBOXES (WM_USER+15)
+#define M_FILLSCRIPTCOMBO (WM_USER+16)
+#define M_REDOROWHEIGHT (WM_USER+17)
+#define M_LOADFONT (WM_USER+18)
+#define M_GUESSSAMEASBOXES (WM_USER+19)
+#define M_SETSAMEASBOXES (WM_USER+20)
+
+static int CALLBACK EnumFontsProc(ENUMLOGFONTEX * lpelfe, NEWTEXTMETRICEX * lpntme, int FontType, LPARAM lParam)
+{
+ if (!IsWindow((HWND) lParam))
+ return FALSE;
+ if (SendMessage((HWND) lParam, CB_FINDSTRINGEXACT, -1, (LPARAM) lpelfe->elfLogFont.lfFaceName) == CB_ERR)
+ SendMessage((HWND) lParam, CB_ADDSTRING, 0, (LPARAM) lpelfe->elfLogFont.lfFaceName);
+ return TRUE;
+}
+
+void FillFontListThread(HWND hwndDlg)
+{
+ LOGFONT lf = { 0 };
+ HDC hdc = GetDC(hwndDlg);
+ lf.lfCharSet = DEFAULT_CHARSET;
+ lf.lfFaceName[0] = 0;
+ lf.lfPitchAndFamily = 0;
+ EnumFontFamiliesEx(hdc, &lf, (FONTENUMPROC) EnumFontsProc, (LPARAM) GetDlgItem(hwndDlg, IDC_TYPEFACE), 0);
+ ReleaseDC(hwndDlg, hdc);
+ return;
+}
+
+static int CALLBACK EnumFontScriptsProc(ENUMLOGFONTEX * lpelfe, NEWTEXTMETRICEX * lpntme, int FontType, LPARAM lParam)
+{
+ if (SendMessage((HWND) lParam, CB_FINDSTRINGEXACT, -1, (LPARAM) lpelfe->elfScript) == CB_ERR) {
+ int i = SendMessage((HWND) lParam, CB_ADDSTRING, 0, (LPARAM) lpelfe->elfScript);
+ SendMessage((HWND) lParam, CB_SETITEMDATA, i, lpelfe->elfLogFont.lfCharSet);
+ }
+ return TRUE;
+}
+
+static int TextOptsDlgResizer(HWND hwndDlg, LPARAM lParam, UTILRESIZECONTROL * urc)
+{
+ return RD_ANCHORX_LEFT | RD_ANCHORY_TOP;
+}
+
+static void SwitchTextDlgToMode(HWND hwndDlg, int expert)
+{
+ ShowWindow(GetDlgItem(hwndDlg, IDC_GAMMACORRECT), expert ? SW_SHOW : SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_STSAMETEXT), expert ? SW_SHOW : SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SAMETYPE), expert ? SW_SHOW : SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SAMESIZE), expert ? SW_SHOW : SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SAMESTYLE), expert ? SW_SHOW : SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SAMECOLOUR), expert ? SW_SHOW : SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_STSIZETEXT), expert ? SW_HIDE : SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_STCOLOURTEXT), expert ? SW_HIDE : SW_SHOW);
+ SetDlgItemText(hwndDlg, IDC_STASTEXT, TranslateTS(expert ? _T("as:") : _T("based on:")));
+ {
+ UTILRESIZEDIALOG urd = { 0 };
+ urd.cbSize = sizeof(urd);
+ urd.hwndDlg = hwndDlg;
+ urd.hInstance = g_hInst;
+ urd.lpTemplate = MAKEINTRESOURCEA(expert ? IDD_OPT_CLCTEXT : IDD_OPT_CLCTEXTSIMPLE);
+ urd.pfnResizer = TextOptsDlgResizer;
+ CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM) & urd);
+ }
+ //resizer breaks the sizing of the edit box
+ SendDlgItemMessage(hwndDlg, IDC_ROWHEIGHTSPIN, UDM_SETBUDDY, (WPARAM) GetDlgItem(hwndDlg, IDC_ROWHEIGHT), 0);
+ SendMessage(hwndDlg, M_REFRESHSAMEASBOXES,
+ SendDlgItemMessage(hwndDlg, IDC_FONTID, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, IDC_FONTID, CB_GETCURSEL, 0, 0), 0), 0);
+}
+
+static BOOL CALLBACK DlgProcClcTextOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static HFONT hFontSample;
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ hFontSample = NULL;
+ SetDlgItemTextA(hwndDlg, IDC_SAMPLE, "Sample");
+ TranslateDialogDefault(hwndDlg);
+ if (!SendMessage(GetParent(hwndDlg), PSM_ISEXPERT, 0, 0))
+ SwitchTextDlgToMode(hwndDlg, 0);
+ forkthread(FillFontListThread, 0, hwndDlg);
+ {
+ int i, itemId, fontId;
+ LOGFONT lf;
+ COLORREF colour;
+ WORD sameAs;
+ char str[32];
+
+ for (i = 0; i <= FONTID_LAST; i++) {
+ fontId = fontListOrder[i];
+ pcli->pfnGetFontSetting(fontId, &lf, &colour);
+ wsprintfA(str, "Font%dAs", fontId);
+ sameAs = DBGetContactSettingWord(NULL, "CLC", str, fontSameAsDefault[fontId]);
+ fontSettings[fontId].sameAsFlags = HIBYTE(sameAs);
+ fontSettings[fontId].sameAs = LOBYTE(sameAs);
+ fontSettings[fontId].style =
+ (lf.lfWeight == FW_NORMAL ? 0 : DBFONTF_BOLD) | (lf.lfItalic ? DBFONTF_ITALIC : 0) | (lf.lfUnderline ? DBFONTF_UNDERLINE : 0);
+ if (lf.lfHeight < 0) {
+ HDC hdc;
+ SIZE size;
+ HFONT hFont = CreateFontIndirect(&lf);
+ hdc = GetDC(hwndDlg);
+ SelectObject(hdc, hFont);
+ GetTextExtentPoint32A(hdc, "_W", 2, &size);
+ ReleaseDC(hwndDlg, hdc);
+ DeleteObject(hFont);
+ fontSettings[fontId].size = (char) size.cy;
+ }
+ else fontSettings[fontId].size = (char) lf.lfHeight;
+ fontSettings[fontId].charset = lf.lfCharSet;
+ fontSettings[fontId].colour = colour;
+ lstrcpy(fontSettings[fontId].szFace, lf.lfFaceName);
+ itemId = SendDlgItemMessage(hwndDlg, IDC_FONTID, CB_ADDSTRING, 0, (LPARAM) TranslateTS( szFontIdDescr[fontId] ));
+ SendDlgItemMessage(hwndDlg, IDC_FONTID, CB_SETITEMDATA, itemId, fontId);
+ }
+ SendDlgItemMessage(hwndDlg, IDC_FONTID, CB_SETCURSEL, 0, 0);
+ for (i = 0; i < SIZEOF(fontSizes); i++)
+ SendDlgItemMessageA(hwndDlg, IDC_FONTSIZE, CB_ADDSTRING, 0, (LPARAM) fontSizes[i]);
+ }
+ SendDlgItemMessage(hwndDlg, IDC_ROWHEIGHTSPIN, UDM_SETRANGE, 0, MAKELONG(255, 0));
+ SendDlgItemMessage(hwndDlg, IDC_ROWHEIGHTSPIN, UDM_SETPOS, 0, MAKELONG(DBGetContactSettingByte(NULL, "CLC", "RowHeight", CLCDEFAULT_ROWHEIGHT), 0));
+ SendMessage(hwndDlg, M_REBUILDFONTGROUP, 0, 0);
+ SendMessage(hwndDlg, M_SAVEFONT, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_HOTCOLOUR, CPM_SETDEFAULTCOLOUR, 0, CLCDEFAULT_HOTTEXTCOLOUR);
+ SendDlgItemMessage(hwndDlg, IDC_HOTCOLOUR, CPM_SETCOLOUR, 0, DBGetContactSettingDword(NULL, "CLC", "HotTextColour", CLCDEFAULT_HOTTEXTCOLOUR));
+ CheckDlgButton(hwndDlg, IDC_GAMMACORRECT, DBGetContactSettingByte(NULL, "CLC", "GammaCorrect", CLCDEFAULT_GAMMACORRECT) ? BST_CHECKED : BST_UNCHECKED);
+ SendDlgItemMessage(hwndDlg, IDC_SELCOLOUR, CPM_SETDEFAULTCOLOUR, 0, CLCDEFAULT_SELTEXTCOLOUR);
+ SendDlgItemMessage(hwndDlg, IDC_SELCOLOUR, CPM_SETCOLOUR, 0, DBGetContactSettingDword(NULL, "CLC", "SelTextColour", CLCDEFAULT_SELTEXTCOLOUR));
+ SendDlgItemMessage(hwndDlg, IDC_QUICKCOLOUR, CPM_SETDEFAULTCOLOUR, 0, CLCDEFAULT_QUICKSEARCHCOLOUR);
+ SendDlgItemMessage(hwndDlg, IDC_QUICKCOLOUR, CPM_SETCOLOUR, 0, DBGetContactSettingDword(NULL, "CLC", "QuickSearchColour", CLCDEFAULT_QUICKSEARCHCOLOUR));
+ return TRUE;
+ case M_REBUILDFONTGROUP: //remake all the needed controls when the user changes the font selector at the top
+ {
+ int i = SendDlgItemMessage(hwndDlg, IDC_FONTID, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, IDC_FONTID, CB_GETCURSEL, 0, 0), 0);
+ SendMessage(hwndDlg, M_SETSAMEASBOXES, i, 0);
+ {
+ int j, id, itemId;
+ char szText[256];
+ SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_RESETCONTENT, 0, 0);
+ itemId = SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_ADDSTRING, 0, (LPARAM) TranslateT("<none>"));
+ SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_SETITEMDATA, itemId, 0xFF);
+ if (0xFF == fontSettings[i].sameAs)
+ SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_SETCURSEL, itemId, 0);
+ for (j = 0; j <= FONTID_LAST; j++) {
+ SendDlgItemMessage(hwndDlg, IDC_FONTID, CB_GETLBTEXT, j, (LPARAM) szText);
+ id = SendDlgItemMessage(hwndDlg, IDC_FONTID, CB_GETITEMDATA, j, 0);
+ if (id == i)
+ continue;
+ itemId = SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_ADDSTRING, 0, (LPARAM) szText);
+ SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_SETITEMDATA, itemId, id);
+ if (id == fontSettings[i].sameAs)
+ SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_SETCURSEL, itemId, 0);
+ }
+ }
+ SendMessage(hwndDlg, M_LOADFONT, i, 0);
+ SendMessage(hwndDlg, M_REFRESHSAMEASBOXES, i, 0);
+ SendMessage(hwndDlg, M_REMAKESAMPLE, 0, 0);
+ break;
+ }
+ case M_SETSAMEASBOXES: //set the check mark in the 'same as' boxes to the right value for fontid wParam
+ CheckDlgButton(hwndDlg, IDC_SAMETYPE, fontSettings[wParam].sameAsFlags & SAMEASF_FACE ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SAMESIZE, fontSettings[wParam].sameAsFlags & SAMEASF_SIZE ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SAMESTYLE, fontSettings[wParam].sameAsFlags & SAMEASF_STYLE ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SAMECOLOUR, fontSettings[wParam].sameAsFlags & SAMEASF_COLOUR ? BST_CHECKED : BST_UNCHECKED);
+ break;
+ case M_FILLSCRIPTCOMBO: //fill the script combo box and set the selection to the value for fontid wParam
+ {
+ LOGFONT lf = { 0 };
+ int i;
+ HDC hdc = GetDC(hwndDlg);
+ lf.lfCharSet = DEFAULT_CHARSET;
+ GetDlgItemText(hwndDlg, IDC_TYPEFACE, lf.lfFaceName, LF_FACESIZE );
+ lf.lfPitchAndFamily = 0;
+ SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_RESETCONTENT, 0, 0);
+ EnumFontFamiliesEx(hdc, &lf, (FONTENUMPROC) EnumFontScriptsProc, (LPARAM) GetDlgItem(hwndDlg, IDC_SCRIPT), 0);
+ ReleaseDC(hwndDlg, hdc);
+ for (i = SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_GETCOUNT, 0, 0) - 1; i >= 0; i--) {
+ if (SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_GETITEMDATA, i, 0) == fontSettings[wParam].charset) {
+ SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_SETCURSEL, i, 0);
+ break;
+ }
+ }
+ if (i < 0)
+ SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_SETCURSEL, 0, 0);
+ break;
+ }
+ case WM_CTLCOLORSTATIC:
+ if ((HWND) lParam == GetDlgItem(hwndDlg, IDC_SAMPLE)) {
+ SetTextColor((HDC) wParam, SendDlgItemMessage(hwndDlg, IDC_COLOUR, CPM_GETCOLOUR, 0, 0));
+ SetBkColor((HDC) wParam, GetSysColor(COLOR_3DFACE));
+ return (BOOL) GetSysColorBrush(COLOR_3DFACE);
+ }
+ break;
+ case M_REFRESHSAMEASBOXES: //set the disabled flag on the 'same as' checkboxes to the values for fontid wParam
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAMETYPE), fontSettings[wParam].sameAs != 0xFF);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAMESIZE), fontSettings[wParam].sameAs != 0xFF);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAMESTYLE), fontSettings[wParam].sameAs != 0xFF);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAMECOLOUR), fontSettings[wParam].sameAs != 0xFF);
+ if (SendMessage(GetParent(hwndDlg), PSM_ISEXPERT, 0, 0)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_TYPEFACE), fontSettings[wParam].sameAs == 0xFF
+ || !(fontSettings[wParam].sameAsFlags & SAMEASF_FACE));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SCRIPT), fontSettings[wParam].sameAs == 0xFF
+ || !(fontSettings[wParam].sameAsFlags & SAMEASF_FACE));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FONTSIZE), fontSettings[wParam].sameAs == 0xFF
+ || !(fontSettings[wParam].sameAsFlags & SAMEASF_SIZE));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BOLD), fontSettings[wParam].sameAs == 0xFF
+ || !(fontSettings[wParam].sameAsFlags & SAMEASF_STYLE));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ITALIC), fontSettings[wParam].sameAs == 0xFF
+ || !(fontSettings[wParam].sameAsFlags & SAMEASF_STYLE));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_UNDERLINE), fontSettings[wParam].sameAs == 0xFF
+ || !(fontSettings[wParam].sameAsFlags & SAMEASF_STYLE));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_COLOUR), fontSettings[wParam].sameAs == 0xFF
+ || !(fontSettings[wParam].sameAsFlags & SAMEASF_COLOUR));
+ }
+ else {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_TYPEFACE), TRUE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SCRIPT), TRUE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FONTSIZE), TRUE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BOLD), TRUE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ITALIC), TRUE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_UNDERLINE), TRUE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_COLOUR), TRUE);
+ }
+ break;
+ case M_REMAKESAMPLE: //remake the sample edit box font based on the settings in the controls
+ {
+ LOGFONTA lf;
+ if (hFontSample) {
+ SendDlgItemMessage(hwndDlg, IDC_SAMPLE, WM_SETFONT, SendDlgItemMessage(hwndDlg, IDC_FONTID, WM_GETFONT, 0, 0), 0);
+ DeleteObject(hFontSample);
+ }
+ lf.lfHeight = GetDlgItemInt(hwndDlg, IDC_FONTSIZE, NULL, FALSE);
+ {
+ HDC hdc = GetDC(NULL);
+ lf.lfHeight = -MulDiv(lf.lfHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72);
+ ReleaseDC(NULL, hdc);
+ }
+ lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
+ lf.lfWeight = IsDlgButtonChecked(hwndDlg, IDC_BOLD) ? FW_BOLD : FW_NORMAL;
+ lf.lfItalic = IsDlgButtonChecked(hwndDlg, IDC_ITALIC);
+ lf.lfUnderline = IsDlgButtonChecked(hwndDlg, IDC_UNDERLINE);
+ lf.lfStrikeOut = 0;
+ lf.lfCharSet = (BYTE) SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_GETCURSEL, 0, 0), 0);
+ lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
+ lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf.lfQuality = DEFAULT_QUALITY;
+ lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ GetDlgItemTextA(hwndDlg, IDC_TYPEFACE, lf.lfFaceName, SIZEOF(lf.lfFaceName));
+ hFontSample = CreateFontIndirectA(&lf);
+ SendDlgItemMessage(hwndDlg, IDC_SAMPLE, WM_SETFONT, (WPARAM) hFontSample, TRUE);
+ break;
+ }
+ case M_RECALCONEFONT: //copy the 'same as' settings for fontid wParam from their sources
+ if (fontSettings[wParam].sameAs == 0xFF)
+ break;
+ if (fontSettings[wParam].sameAsFlags & SAMEASF_FACE) {
+ lstrcpy(fontSettings[wParam].szFace, fontSettings[fontSettings[wParam].sameAs].szFace);
+ fontSettings[wParam].charset = fontSettings[fontSettings[wParam].sameAs].charset;
+ }
+ if (fontSettings[wParam].sameAsFlags & SAMEASF_SIZE)
+ fontSettings[wParam].size = fontSettings[fontSettings[wParam].sameAs].size;
+ if (fontSettings[wParam].sameAsFlags & SAMEASF_STYLE)
+ fontSettings[wParam].style = fontSettings[fontSettings[wParam].sameAs].style;
+ if (fontSettings[wParam].sameAsFlags & SAMEASF_COLOUR)
+ fontSettings[wParam].colour = fontSettings[fontSettings[wParam].sameAs].colour;
+ break;
+ case M_RECALCOTHERFONTS: //recalculate the 'same as' settings for all fonts but wParam
+ {
+ int i;
+ for (i = 0; i <= FONTID_LAST; i++) {
+ if (i == (int) wParam)
+ continue;
+ SendMessage(hwndDlg, M_RECALCONEFONT, i, 0);
+ }
+ break;
+ }
+ case M_SAVEFONT: //save the font settings from the controls to font wParam
+ fontSettings[wParam].sameAsFlags =
+ (IsDlgButtonChecked(hwndDlg, IDC_SAMETYPE) ? SAMEASF_FACE : 0) | (IsDlgButtonChecked(hwndDlg, IDC_SAMESIZE) ? SAMEASF_SIZE : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_SAMESTYLE) ? SAMEASF_STYLE : 0) | (IsDlgButtonChecked(hwndDlg, IDC_SAMECOLOUR) ? SAMEASF_COLOUR : 0);
+ fontSettings[wParam].sameAs =
+ (BYTE) SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_GETCURSEL, 0, 0), 0);
+ GetDlgItemText(hwndDlg, IDC_TYPEFACE, fontSettings[wParam].szFace, SIZEOF( fontSettings[wParam].szFace ));
+ fontSettings[wParam].charset =
+ (BYTE) SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_GETCURSEL, 0, 0), 0);
+ fontSettings[wParam].size = (char) GetDlgItemInt(hwndDlg, IDC_FONTSIZE, NULL, FALSE);
+ fontSettings[wParam].style =
+ (IsDlgButtonChecked(hwndDlg, IDC_BOLD) ? DBFONTF_BOLD : 0) | (IsDlgButtonChecked(hwndDlg, IDC_ITALIC) ? DBFONTF_ITALIC : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_UNDERLINE) ? DBFONTF_UNDERLINE : 0);
+ fontSettings[wParam].colour = SendDlgItemMessage(hwndDlg, IDC_COLOUR, CPM_GETCOLOUR, 0, 0);
+ SendMessage(hwndDlg, M_REDOROWHEIGHT, 0, 0);
+ break;
+ case M_REDOROWHEIGHT: //recalculate the minimum feasible row height
+ {
+ int i;
+ int minHeight = GetSystemMetrics(SM_CYSMICON);
+ for (i = 0; i <= FONTID_LAST; i++)
+ if (fontSettings[i].size > minHeight)
+ minHeight = fontSettings[i].size;
+ i = SendDlgItemMessage(hwndDlg, IDC_ROWHEIGHTSPIN, UDM_GETPOS, 0, 0);
+ if (i < minHeight)
+ SendDlgItemMessage(hwndDlg, IDC_ROWHEIGHTSPIN, UDM_SETPOS, 0, MAKELONG(minHeight, 0));
+ break;
+ }
+ case M_LOADFONT: //load font wParam into the controls
+ SetDlgItemText(hwndDlg, IDC_TYPEFACE, fontSettings[wParam].szFace);
+ SendMessage(hwndDlg, M_FILLSCRIPTCOMBO, wParam, 0);
+ SetDlgItemInt(hwndDlg, IDC_FONTSIZE, fontSettings[wParam].size, FALSE);
+ CheckDlgButton(hwndDlg, IDC_BOLD, fontSettings[wParam].style & DBFONTF_BOLD ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_ITALIC, fontSettings[wParam].style & DBFONTF_ITALIC ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_UNDERLINE, fontSettings[wParam].style & DBFONTF_UNDERLINE ? BST_CHECKED : BST_UNCHECKED);
+ {
+ LOGFONT lf;
+ COLORREF colour;
+ pcli->pfnGetDefaultFontSetting(wParam, &lf, &colour);
+ SendDlgItemMessage(hwndDlg, IDC_COLOUR, CPM_SETDEFAULTCOLOUR, 0, colour);
+ }
+ SendDlgItemMessage(hwndDlg, IDC_COLOUR, CPM_SETCOLOUR, 0, fontSettings[wParam].colour);
+ break;
+ case M_GUESSSAMEASBOXES: //guess suitable values for the 'same as' checkboxes for fontId wParam
+ fontSettings[wParam].sameAsFlags = 0;
+ if (fontSettings[wParam].sameAs == 0xFF)
+ break;
+ if (!lstrcmp(fontSettings[wParam].szFace, fontSettings[fontSettings[wParam].sameAs].szFace) &&
+ fontSettings[wParam].charset == fontSettings[fontSettings[wParam].sameAs].charset)
+ fontSettings[wParam].sameAsFlags |= SAMEASF_FACE;
+ if (fontSettings[wParam].size == fontSettings[fontSettings[wParam].sameAs].size)
+ fontSettings[wParam].sameAsFlags |= SAMEASF_SIZE;
+ if (fontSettings[wParam].style == fontSettings[fontSettings[wParam].sameAs].style)
+ fontSettings[wParam].sameAsFlags |= SAMEASF_STYLE;
+ if (fontSettings[wParam].colour == fontSettings[fontSettings[wParam].sameAs].colour)
+ fontSettings[wParam].sameAsFlags |= SAMEASF_COLOUR;
+ SendMessage(hwndDlg, M_SETSAMEASBOXES, wParam, 0);
+ break;
+ case WM_VSCROLL:
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_COMMAND:
+ {
+ int fontId = SendDlgItemMessage(hwndDlg, IDC_FONTID, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, IDC_FONTID, CB_GETCURSEL, 0, 0), 0);
+ switch (LOWORD(wParam)) {
+ case IDC_FONTID:
+ if (HIWORD(wParam) != CBN_SELCHANGE)
+ return FALSE;
+ SendMessage(hwndDlg, M_REBUILDFONTGROUP, 0, 0);
+ return 0;
+ case IDC_SAMETYPE:
+ case IDC_SAMESIZE:
+ case IDC_SAMESTYLE:
+ case IDC_SAMECOLOUR:
+ SendMessage(hwndDlg, M_SAVEFONT, fontId, 0);
+ SendMessage(hwndDlg, M_RECALCONEFONT, fontId, 0);
+ SendMessage(hwndDlg, M_REMAKESAMPLE, 0, 0);
+ SendMessage(hwndDlg, M_REFRESHSAMEASBOXES, fontId, 0);
+ break;
+ case IDC_SAMEAS:
+ if (HIWORD(wParam) != CBN_SELCHANGE)
+ return FALSE;
+ if (SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_GETCURSEL, 0, 0), 0) ==
+ fontId)
+ SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_SETCURSEL, 0, 0);
+ if (!SendMessage(GetParent(hwndDlg), PSM_ISEXPERT, 0, 0)) {
+ int sameAs =
+ SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_GETCURSEL, 0, 0), 0);
+ if (sameAs != 0xFF)
+ SendMessage(hwndDlg, M_LOADFONT, sameAs, 0);
+ SendMessage(hwndDlg, M_SAVEFONT, fontId, 0);
+ SendMessage(hwndDlg, M_GUESSSAMEASBOXES, fontId, 0);
+ }
+ else
+ SendMessage(hwndDlg, M_SAVEFONT, fontId, 0);
+ SendMessage(hwndDlg, M_RECALCONEFONT, fontId, 0);
+ SendMessage(hwndDlg, M_FILLSCRIPTCOMBO, fontId, 0);
+ SendMessage(hwndDlg, M_REMAKESAMPLE, 0, 0);
+ SendMessage(hwndDlg, M_REFRESHSAMEASBOXES, fontId, 0);
+ break;
+ case IDC_TYPEFACE:
+ case IDC_SCRIPT:
+ case IDC_FONTSIZE:
+ if (HIWORD(wParam) != CBN_EDITCHANGE && HIWORD(wParam) != CBN_SELCHANGE)
+ return FALSE;
+ if (HIWORD(wParam) == CBN_SELCHANGE) {
+ SendDlgItemMessage(hwndDlg, LOWORD(wParam), CB_SETCURSEL, SendDlgItemMessage(hwndDlg, LOWORD(wParam), CB_GETCURSEL, 0, 0), 0);
+ }
+ if (LOWORD(wParam) == IDC_TYPEFACE)
+ SendMessage(hwndDlg, M_FILLSCRIPTCOMBO, fontId, 0);
+ //fall through
+ case IDC_BOLD:
+ case IDC_ITALIC:
+ case IDC_UNDERLINE:
+ case IDC_COLOUR:
+ SendMessage(hwndDlg, M_SAVEFONT, fontId, 0);
+ if (!SendMessage(GetParent(hwndDlg), PSM_ISEXPERT, 0, 0)) {
+ SendMessage(hwndDlg, M_GUESSSAMEASBOXES, fontId, 0);
+ SendMessage(hwndDlg, M_REFRESHSAMEASBOXES, fontId, 0);
+ }
+ SendMessage(hwndDlg, M_RECALCOTHERFONTS, fontId, 0);
+ SendMessage(hwndDlg, M_REMAKESAMPLE, 0, 0);
+ SendMessage(hwndDlg, M_REDOROWHEIGHT, 0, 0);
+ break;
+ case IDC_SAMPLE:
+ return 0;
+ case IDC_ROWHEIGHT:
+ if (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus())
+ return 0;
+ break;
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ case WM_NOTIFY:
+ switch (((LPNMHDR) lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR) lParam)->code) {
+ case PSN_APPLY:
+ {
+ int i;
+ char str[20];
+
+ // Force min height calculation
+ // This prevents users from setting the row height to be too low
+ SendMessage(hwndDlg, M_REDOROWHEIGHT, 0, 0);
+ for (i = 0; i <= FONTID_LAST; i++) {
+ wsprintfA(str, "Font%dName", i);
+ DBWriteContactSettingTString(NULL, "CLC", str, fontSettings[i].szFace);
+ wsprintfA(str, "Font%dSet", i);
+ DBWriteContactSettingByte(NULL, "CLC", str, fontSettings[i].charset);
+ wsprintfA(str, "Font%dSize", i);
+ DBWriteContactSettingByte(NULL, "CLC", str, fontSettings[i].size);
+ wsprintfA(str, "Font%dSty", i);
+ DBWriteContactSettingByte(NULL, "CLC", str, fontSettings[i].style);
+ wsprintfA(str, "Font%dCol", i);
+ DBWriteContactSettingDword(NULL, "CLC", str, fontSettings[i].colour);
+ wsprintfA(str, "Font%dAs", i);
+ DBWriteContactSettingWord(NULL, "CLC", str, (WORD) ((fontSettings[i].sameAsFlags << 8) | fontSettings[i].sameAs));
+ }
+ }
+ {
+ COLORREF col;
+ col = SendDlgItemMessage(hwndDlg, IDC_SELCOLOUR, CPM_GETCOLOUR, 0, 0);
+ if (col == CLCDEFAULT_SELTEXTCOLOUR)
+ DBDeleteContactSetting(NULL, "CLC", "SelTextColour");
+ else
+ DBWriteContactSettingDword(NULL, "CLC", "SelTextColour", col);
+ col = SendDlgItemMessage(hwndDlg, IDC_HOTCOLOUR, CPM_GETCOLOUR, 0, 0);
+ if (col == CLCDEFAULT_HOTTEXTCOLOUR)
+ DBDeleteContactSetting(NULL, "CLC", "HotTextColour");
+ else
+ DBWriteContactSettingDword(NULL, "CLC", "HotTextColour", col);
+ col = SendDlgItemMessage(hwndDlg, IDC_QUICKCOLOUR, CPM_GETCOLOUR, 0, 0);
+ if (col == CLCDEFAULT_QUICKSEARCHCOLOUR)
+ DBDeleteContactSetting(NULL, "CLC", "QuickSearchColour");
+ else
+ DBWriteContactSettingDword(NULL, "CLC", "QuickSearchColour", col);
+ }
+ DBWriteContactSettingByte(NULL, "CLC", "RowHeight", (BYTE) SendDlgItemMessage(hwndDlg, IDC_ROWHEIGHTSPIN, UDM_GETPOS, 0, 0));
+ DBWriteContactSettingByte(NULL, "CLC", "GammaCorrect", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_GAMMACORRECT));
+ pcli->pfnClcOptionsChanged();
+ return TRUE;
+ case PSN_EXPERTCHANGED:
+ SwitchTextDlgToMode(hwndDlg, ((PSHNOTIFY *) lParam)->lParam);
+ break;
+ }
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ if (hFontSample) {
+ SendDlgItemMessage(hwndDlg, IDC_SAMPLE, WM_SETFONT, SendDlgItemMessage(hwndDlg, IDC_FONTID, WM_GETFONT, 0, 0), 0);
+ DeleteObject(hFontSample);
+ }
+ break;
+ }
+ return FALSE;
+}
+
+/****************************************************************************************/
+
+int ClcOptInit(WPARAM wParam, LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp;
+
+ ZeroMemory(&odp, sizeof(odp));
+ odp.cbSize = sizeof(odp);
+ odp.position = 0;
+ odp.hInstance = g_hInst;
+ odp.pszGroup = "Contact List";
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_CLC);
+ odp.pszTitle = "List";
+ odp.pfnDlgProc = DlgProcClcMainOpts;
+ odp.flags = ODPF_BOLDGROUPS | ODPF_EXPERTONLY;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) & odp);
+
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_CLCBKG);
+ odp.pszTitle = "List Background";
+ odp.pfnDlgProc = DlgProcClcBkgOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) & odp);
+
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_CLCTEXT);
+ odp.pszTitle = "List Text";
+ odp.pfnDlgProc = DlgProcClcTextOpts;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) & odp);
+ return 0;
+}
diff --git a/miranda-wine/plugins/clist/clcpaint.c b/miranda-wine/plugins/clist/clcpaint.c
new file mode 100644
index 0000000..d244c88
--- /dev/null
+++ b/miranda-wine/plugins/clist/clcpaint.c
@@ -0,0 +1,590 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+extern HIMAGELIST himlCListClc;
+static BYTE divide3[765] = { 255 };
+
+static void ChangeToFont(HDC hdc, struct ClcData *dat, int id, int *fontHeight)
+{
+ SelectObject(hdc, dat->fontInfo[id].hFont);
+ SetTextColor(hdc, dat->fontInfo[id].colour);
+ if (fontHeight)
+ *fontHeight = dat->fontInfo[id].fontHeight;
+}
+
+static void __inline SetHotTrackColour(HDC hdc, struct ClcData *dat)
+{
+ if (dat->gammaCorrection) {
+ COLORREF oldCol, newCol;
+ int oldLum, newLum;
+
+ oldCol = GetTextColor(hdc);
+ oldLum = (GetRValue(oldCol) * 30 + GetGValue(oldCol) * 59 + GetBValue(oldCol) * 11) / 100;
+ newLum = (GetRValue(dat->hotTextColour) * 30 + GetGValue(dat->hotTextColour) * 59 + GetBValue(dat->hotTextColour) * 11) / 100;
+ if (newLum == 0) {
+ SetTextColor(hdc, dat->hotTextColour);
+ return;
+ }
+ if (newLum >= oldLum + 20) {
+ oldLum += 20;
+ newCol =
+ RGB(GetRValue(dat->hotTextColour) * oldLum / newLum, GetGValue(dat->hotTextColour) * oldLum / newLum,
+ GetBValue(dat->hotTextColour) * oldLum / newLum);
+ }
+ else if (newLum <= oldLum) {
+ int r, g, b;
+ r = GetRValue(dat->hotTextColour) * oldLum / newLum;
+ g = GetGValue(dat->hotTextColour) * oldLum / newLum;
+ b = GetBValue(dat->hotTextColour) * oldLum / newLum;
+ if (r > 255) {
+ g += (r - 255) * 3 / 7;
+ b += (r - 255) * 3 / 7;
+ r = 255;
+ }
+ if (g > 255) {
+ r += (g - 255) * 59 / 41;
+ if (r > 255)
+ r = 255;
+ b += (g - 255) * 59 / 41;
+ g = 255;
+ }
+ if (b > 255) {
+ r += (b - 255) * 11 / 89;
+ if (r > 255)
+ r = 255;
+ g += (b - 255) * 11 / 89;
+ if (g > 255)
+ g = 255;
+ b = 255;
+ }
+ newCol = RGB(r, g, b);
+ }
+ else
+ newCol = dat->hotTextColour;
+ SetTextColor(hdc, newCol);
+ }
+ else
+ SetTextColor(hdc, dat->hotTextColour);
+}
+
+static int GetStatusOnlineness(int status)
+{
+ switch (status) {
+ case ID_STATUS_FREECHAT: return 110;
+ case ID_STATUS_ONLINE: return 100;
+ case ID_STATUS_OCCUPIED: return 60;
+ case ID_STATUS_ONTHEPHONE: return 50;
+ case ID_STATUS_DND: return 40;
+ case ID_STATUS_AWAY: return 30;
+ case ID_STATUS_OUTTOLUNCH: return 20;
+ case ID_STATUS_NA: return 10;
+ case ID_STATUS_INVISIBLE: return 5;
+ }
+ return 0;
+}
+
+static int GetGeneralisedStatus(void)
+{
+ int i, status, thisStatus, statusOnlineness, thisOnlineness;
+
+ status = ID_STATUS_OFFLINE;
+ statusOnlineness = 0;
+
+ for (i = 0; i < pcli->hClcProtoCount; i++) {
+ thisStatus = pcli->clcProto[i].dwStatus;
+ if (thisStatus == ID_STATUS_INVISIBLE)
+ return ID_STATUS_INVISIBLE;
+ thisOnlineness = GetStatusOnlineness(thisStatus);
+ if (thisOnlineness > statusOnlineness) {
+ status = thisStatus;
+ statusOnlineness = thisOnlineness;
+ }
+ }
+ return status;
+}
+
+static int GetRealStatus(struct ClcContact *contact, int status)
+{
+ int i;
+ char *szProto = contact->proto;
+ if (!szProto)
+ return status;
+ for (i = 0; i < pcli->hClcProtoCount; i++) {
+ if (!lstrcmpA(pcli->clcProto[i].szProto, szProto)) {
+ return pcli->clcProto[i].dwStatus;
+ }
+ }
+ return status;
+}
+
+static HMODULE themeAPIHandle = NULL; // handle to uxtheme.dll
+static HANDLE(WINAPI * MyOpenThemeData) (HWND, LPCWSTR);
+static HRESULT(WINAPI * MyCloseThemeData) (HANDLE);
+static HRESULT(WINAPI * MyDrawThemeBackground) (HANDLE, HDC, int, int, const RECT *, const RECT *);
+
+#define MGPROC(x) GetProcAddress(themeAPIHandle,x)
+void PaintClc(HWND hwnd, struct ClcData *dat, HDC hdc, RECT * rcPaint)
+{
+ HDC hdcMem;
+ RECT clRect;
+ int y, indent, index, fontHeight;
+ struct ClcGroup *group;
+ HBITMAP hBmpOsb, hOldBitmap;
+ HFONT hOldFont;
+ DWORD style = GetWindowLong(hwnd, GWL_STYLE);
+ int status = GetGeneralisedStatus();
+ int grey = 0, groupCountsFontTopShift;
+ HBRUSH hBrushAlternateGrey = NULL;
+ // yes I know about GetSysColorBrush()
+ COLORREF tmpbkcolour = style & CLS_CONTACTLIST ? (dat->useWindowsColours ? GetSysColor(COLOR_3DFACE) : dat->bkColour) : dat->bkColour;
+
+ if (dat->greyoutFlags & pcli->pfnClcStatusToPf2(status) || style & WS_DISABLED)
+ grey = 1;
+ else if (GetFocus() != hwnd && dat->greyoutFlags & GREYF_UNFOCUS)
+ grey = 1;
+ GetClientRect(hwnd, &clRect);
+ if (rcPaint == NULL)
+ rcPaint = &clRect;
+ if (IsRectEmpty(rcPaint))
+ return;
+ y = -dat->yScroll;
+ hdcMem = CreateCompatibleDC(hdc);
+ hBmpOsb = CreateBitmap(clRect.right, clRect.bottom, 1, GetDeviceCaps(hdc, BITSPIXEL), NULL);
+ hOldBitmap = SelectObject(hdcMem, hBmpOsb);
+ {
+ TEXTMETRIC tm;
+ hOldFont = SelectObject(hdcMem, dat->fontInfo[FONTID_GROUPS].hFont);
+ GetTextMetrics(hdcMem, &tm);
+ groupCountsFontTopShift = tm.tmAscent;
+ SelectObject(hdcMem, dat->fontInfo[FONTID_GROUPCOUNTS].hFont);
+ GetTextMetrics(hdcMem, &tm);
+ groupCountsFontTopShift -= tm.tmAscent;
+ }
+ if (style & CLS_GREYALTERNATE)
+ hBrushAlternateGrey =
+ CreateSolidBrush(GetNearestColor(hdcMem, RGB(GetRValue(tmpbkcolour) - 10, GetGValue(tmpbkcolour) - 10, GetBValue(tmpbkcolour) - 10)));
+
+ ChangeToFont(hdcMem, dat, FONTID_CONTACTS, &fontHeight);
+ SetBkMode(hdcMem, TRANSPARENT);
+ {
+ HBRUSH hBrush, hoBrush;
+
+ hBrush = CreateSolidBrush(tmpbkcolour);
+ hoBrush = (HBRUSH) SelectObject(hdcMem, hBrush);
+ FillRect(hdcMem, rcPaint, hBrush);
+ SelectObject(hdcMem, hoBrush);
+ DeleteObject(hBrush);
+ if (dat->hBmpBackground) {
+ BITMAP bmp;
+ HDC hdcBmp;
+ int x, y;
+ int maxx, maxy;
+ int destw, desth;
+
+ // XXX: Halftone isnt supported on 9x, however the scretch problems dont happen on 98.
+ SetStretchBltMode(hdcMem, HALFTONE);
+
+ GetObject(dat->hBmpBackground, sizeof(bmp), &bmp);
+ hdcBmp = CreateCompatibleDC(hdcMem);
+ SelectObject(hdcBmp, dat->hBmpBackground);
+ y = dat->backgroundBmpUse & CLBF_SCROLL ? -dat->yScroll : 0;
+ maxx = dat->backgroundBmpUse & CLBF_TILEH ? clRect.right : 1;
+ maxy = dat->backgroundBmpUse & CLBF_TILEV ? maxy = rcPaint->bottom : y + 1;
+ switch (dat->backgroundBmpUse & CLBM_TYPE) {
+ case CLB_STRETCH:
+ if (dat->backgroundBmpUse & CLBF_PROPORTIONAL) {
+ if (clRect.right * bmp.bmHeight < clRect.bottom * bmp.bmWidth) {
+ desth = clRect.bottom;
+ destw = desth * bmp.bmWidth / bmp.bmHeight;
+ }
+ else {
+ destw = clRect.right;
+ desth = destw * bmp.bmHeight / bmp.bmWidth;
+ }
+ }
+ else {
+ destw = clRect.right;
+ desth = clRect.bottom;
+ }
+ break;
+ case CLB_STRETCHH:
+ if (dat->backgroundBmpUse & CLBF_PROPORTIONAL) {
+ destw = clRect.right;
+ desth = destw * bmp.bmHeight / bmp.bmWidth;
+ }
+ else {
+ destw = clRect.right;
+ desth = bmp.bmHeight;
+ }
+ break;
+ case CLB_STRETCHV:
+ if (dat->backgroundBmpUse & CLBF_PROPORTIONAL) {
+ desth = clRect.bottom;
+ destw = desth * bmp.bmWidth / bmp.bmHeight;
+ }
+ else {
+ destw = bmp.bmWidth;
+ desth = clRect.bottom;
+ }
+ break;
+ default: //clb_topleft
+ destw = bmp.bmWidth;
+ desth = bmp.bmHeight;
+ break;
+ }
+ for (; y < maxy; y += desth) {
+ if (y < rcPaint->top - desth)
+ continue;
+ for (x = 0; x < maxx; x += destw)
+ StretchBlt(hdcMem, x, y, destw, desth, hdcBmp, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
+ }
+ DeleteDC(hdcBmp);
+ }
+ }
+ group = &dat->list;
+ group->scanIndex = 0;
+ indent = 0;
+ for (index = 0; y < rcPaint->bottom;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ indent--;
+ if (group == NULL)
+ break;
+ group->scanIndex++;
+ continue;
+ }
+ if (y > rcPaint->top - dat->rowHeight) {
+ int iImage = -1;
+ int selected = index == dat->selection && (dat->showSelAlways || dat->exStyle & CLS_EX_SHOWSELALWAYS || GetFocus() == hwnd)
+ && group->cl.items[group->scanIndex]->type != CLCIT_DIVIDER;
+ int hottrack = dat->exStyle & CLS_EX_TRACKSELECT && group->cl.items[group->scanIndex]->type != CLCIT_DIVIDER && dat->iHotTrack == index;
+ SIZE textSize, countsSize, spaceSize;
+ int width, checkboxWidth;
+ char *szCounts;
+
+ //alternating grey
+ if (style & CLS_GREYALTERNATE && index & 1) {
+ RECT rc;
+ rc.top = y;
+ rc.bottom = rc.top + dat->rowHeight;
+ rc.left = 0;
+ rc.right = clRect.right;
+ FillRect(hdcMem, &rc, hBrushAlternateGrey);
+ }
+
+ //setup
+ if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP)
+ ChangeToFont(hdcMem, dat, FONTID_GROUPS, &fontHeight);
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_INFO) {
+ if (group->cl.items[group->scanIndex]->flags & CLCIIF_GROUPFONT)
+ ChangeToFont(hdcMem, dat, FONTID_GROUPS, &fontHeight);
+ else
+ ChangeToFont(hdcMem, dat, FONTID_CONTACTS, &fontHeight);
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_DIVIDER)
+ ChangeToFont(hdcMem, dat, FONTID_DIVIDERS, &fontHeight);
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT && group->cl.items[group->scanIndex]->flags & CONTACTF_NOTONLIST)
+ ChangeToFont(hdcMem, dat, FONTID_NOTONLIST, &fontHeight);
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT &&
+ ((group->cl.items[group->scanIndex]->flags & CONTACTF_INVISTO
+ && GetRealStatus(group->cl.items[group->scanIndex], status) != ID_STATUS_INVISIBLE)
+ || (group->cl.items[group->scanIndex]->flags & CONTACTF_VISTO
+ && GetRealStatus(group->cl.items[group->scanIndex], status) == ID_STATUS_INVISIBLE)
+ )
+ ) {
+ // the contact is in the always visible list and the proto is invisible
+ // the contact is in the always invisible and the proto is in any other mode
+ ChangeToFont(hdcMem, dat, group->cl.items[group->scanIndex]->flags & CONTACTF_ONLINE ? FONTID_INVIS : FONTID_OFFINVIS, &fontHeight);
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT && !(group->cl.items[group->scanIndex]->flags & CONTACTF_ONLINE))
+ ChangeToFont(hdcMem, dat, FONTID_OFFLINE, &fontHeight);
+ else
+ ChangeToFont(hdcMem, dat, FONTID_CONTACTS, &fontHeight);
+ GetTextExtentPoint32(hdcMem, group->cl.items[group->scanIndex]->szText, lstrlen(group->cl.items[group->scanIndex]->szText), &textSize);
+ width = textSize.cx;
+ if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ szCounts = pcli->pfnGetGroupCountsText(dat, group->cl.items[group->scanIndex]);
+ if (szCounts[0]) {
+ GetTextExtentPoint32A(hdcMem, " ", 1, &spaceSize);
+ ChangeToFont(hdcMem, dat, FONTID_GROUPCOUNTS, &fontHeight);
+ GetTextExtentPoint32A(hdcMem, szCounts, lstrlenA(szCounts), &countsSize);
+ width += spaceSize.cx + countsSize.cx;
+ }
+ }
+
+ if ((style & CLS_CHECKBOXES && group->cl.items[group->scanIndex]->type == CLCIT_CONTACT) ||
+ (style & CLS_GROUPCHECKBOXES && group->cl.items[group->scanIndex]->type == CLCIT_GROUP) ||
+ (group->cl.items[group->scanIndex]->type == CLCIT_INFO && group->cl.items[group->scanIndex]->flags & CLCIIF_CHECKBOX))
+ checkboxWidth = dat->checkboxSize + 2;
+ else
+ checkboxWidth = 0;
+
+ //background
+ if (selected) {
+ int x = dat->leftMargin + indent * dat->groupIndent + checkboxWidth + dat->iconXSpace - 2;
+ ImageList_DrawEx(dat->himlHighlight, 0, hdcMem, x, y, min(width + 5, clRect.right - x), dat->rowHeight, CLR_NONE, CLR_NONE,
+ dat->exStyle & CLS_EX_NOTRANSLUCENTSEL ? ILD_NORMAL : ILD_BLEND25);
+ SetTextColor(hdcMem, dat->selTextColour);
+ }
+ else if (hottrack)
+ SetHotTrackColour(hdcMem, dat);
+
+ //checkboxes
+ if (checkboxWidth) {
+ RECT rc;
+ HANDLE hTheme = NULL;
+
+ // THEME
+ if (IsWinVerXPPlus()) {
+ if (!themeAPIHandle) {
+ themeAPIHandle = GetModuleHandleA("uxtheme");
+ if (themeAPIHandle) {
+ MyOpenThemeData = (HANDLE(WINAPI *) (HWND, LPCWSTR)) MGPROC("OpenThemeData");
+ MyCloseThemeData = (HRESULT(WINAPI *) (HANDLE)) MGPROC("CloseThemeData");
+ MyDrawThemeBackground =
+ (HRESULT(WINAPI *) (HANDLE, HDC, int, int, const RECT *, const RECT *)) MGPROC("DrawThemeBackground");
+ }
+ }
+ // Make sure all of these methods are valid (i would hope either all or none work)
+ if (MyOpenThemeData && MyCloseThemeData && MyDrawThemeBackground) {
+ hTheme = MyOpenThemeData(hwnd, L"BUTTON");
+ }
+ }
+ rc.left = dat->leftMargin + indent * dat->groupIndent;
+ rc.right = rc.left + dat->checkboxSize;
+ rc.top = y + ((dat->rowHeight - dat->checkboxSize) >> 1);
+ rc.bottom = rc.top + dat->checkboxSize;
+ if (hTheme) {
+ MyDrawThemeBackground(hTheme, hdcMem, BP_CHECKBOX, group->cl.items[group->scanIndex]->flags & CONTACTF_CHECKED ? (hottrack ? CBS_CHECKEDHOT : CBS_CHECKEDNORMAL) : (hottrack ? CBS_UNCHECKEDHOT : CBS_UNCHECKEDNORMAL), &rc, &rc);
+ }
+ else
+ DrawFrameControl(hdcMem, &rc, DFC_BUTTON, DFCS_BUTTONCHECK | DFCS_FLAT | (group->cl.items[group->scanIndex]->flags & CONTACTF_CHECKED ? DFCS_CHECKED : 0) | (hottrack ? DFCS_HOT : 0));
+ if (hTheme && MyCloseThemeData) {
+ MyCloseThemeData(hTheme);
+ hTheme = NULL;
+ }
+ }
+
+ //icon
+ if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP)
+ iImage = group->cl.items[group->scanIndex]->group->expanded ? IMAGE_GROUPOPEN : IMAGE_GROUPSHUT;
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT)
+ iImage = group->cl.items[group->scanIndex]->iImage;
+ if (iImage != -1) {
+ /*COLORREF colourFg=dat->selBkColour;
+ int mode=ILD_NORMAL;
+ if(selected) mode=ILD_SELECTED;
+ else if(hottrack) {mode=ILD_FOCUS; colourFg=dat->hotTextColour;}
+ else if(group->cl.items[group->scanIndex]->type==CLCIT_CONTACT && group->cl.items[group->scanIndex]->flags&CONTACTF_NOTONLIST) {colourFg=dat->fontInfo[FONTID_NOTONLIST].colour; mode=ILD_BLEND50;}
+ ImageList_DrawEx(himlCListClc,iImage,hdcMem,dat->leftMargin+indent*dat->groupIndent+checkboxWidth,y+((dat->rowHeight-16)>>1),0,0,CLR_NONE,colourFg,mode);
+ */
+ // this doesnt use CLS_CONTACTLIST since the colour prolly wont match anyway
+ COLORREF colourFg = dat->selBkColour;
+ int mode = ILD_NORMAL;
+ if (hottrack) {
+ colourFg = dat->hotTextColour;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT && group->cl.items[group->scanIndex]->flags & CONTACTF_NOTONLIST) {
+ colourFg = dat->fontInfo[FONTID_NOTONLIST].colour;
+ mode = ILD_BLEND50;
+ }
+ if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT && dat->showIdle
+ && (group->cl.items[group->scanIndex]->flags & CONTACTF_IDLE)
+ && GetRealStatus(group->cl.items[group->scanIndex], ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE)
+ mode = ILD_SELECTED;
+ ImageList_DrawEx(himlCListClc, iImage, hdcMem, dat->leftMargin + indent * dat->groupIndent + checkboxWidth,
+ y + ((dat->rowHeight - 16) >> 1), 0, 0, CLR_NONE, colourFg, mode);
+ }
+
+ //text
+ if (group->cl.items[group->scanIndex]->type == CLCIT_DIVIDER) {
+ RECT rc;
+ rc.top = y + (dat->rowHeight >> 1);
+ rc.bottom = rc.top + 2;
+ rc.left = dat->leftMargin + indent * dat->groupIndent;
+ rc.right = rc.left + ((clRect.right - rc.left - textSize.cx) >> 1) - 3;
+ DrawEdge(hdcMem, &rc, BDR_SUNKENOUTER, BF_RECT);
+ TextOut(hdcMem, rc.right + 3, y + ((dat->rowHeight - fontHeight) >> 1), group->cl.items[group->scanIndex]->szText,
+ lstrlen(group->cl.items[group->scanIndex]->szText));
+ rc.left = rc.right + 6 + textSize.cx;
+ rc.right = clRect.right;
+ DrawEdge(hdcMem, &rc, BDR_SUNKENOUTER, BF_RECT);
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ RECT rc;
+ if (szCounts[0]) {
+ fontHeight = dat->fontInfo[FONTID_GROUPS].fontHeight;
+ rc.left = dat->leftMargin + indent * dat->groupIndent + checkboxWidth + dat->iconXSpace;
+ rc.right = min(clRect.right - countsSize.cx, rc.left + textSize.cx + spaceSize.cx);
+ rc.top = y + ((dat->rowHeight - fontHeight) >> 1);
+ rc.bottom = rc.top + textSize.cy;
+ if (rc.right < rc.left + 4)
+ rc.right = clRect.right + 1;
+ else
+ TextOutA(hdcMem, rc.right, rc.top + groupCountsFontTopShift, szCounts, lstrlenA(szCounts));
+ ChangeToFont(hdcMem, dat, FONTID_GROUPS, &fontHeight);
+ if (selected)
+ SetTextColor(hdcMem, dat->selTextColour);
+ else if (hottrack)
+ SetHotTrackColour(hdcMem, dat);
+ rc.right--;
+ ExtTextOut(hdcMem, rc.left, rc.top, ETO_CLIPPED, &rc, group->cl.items[group->scanIndex]->szText,
+ lstrlen(group->cl.items[group->scanIndex]->szText), NULL);
+ }
+ else
+ TextOut(hdcMem, dat->leftMargin + indent * dat->groupIndent + checkboxWidth + dat->iconXSpace,
+ y + ((dat->rowHeight - fontHeight) >> 1), group->cl.items[group->scanIndex]->szText,
+ lstrlen(group->cl.items[group->scanIndex]->szText));
+ if (dat->exStyle & CLS_EX_LINEWITHGROUPS) {
+ rc.top = y + (dat->rowHeight >> 1);
+ rc.bottom = rc.top + 2;
+ rc.left = dat->leftMargin + indent * dat->groupIndent + checkboxWidth + dat->iconXSpace + width + 3;
+ rc.right = clRect.right - 1 - dat->extraColumnSpacing * dat->extraColumnsCount;
+ if (rc.right - rc.left > 1)
+ DrawEdge(hdcMem, &rc, BDR_SUNKENOUTER, BF_RECT);
+ }
+ }
+ else {
+ TCHAR *szText = group->cl.items[group->scanIndex]->szText;
+ RECT rc;
+ rc.left = dat->leftMargin + indent * dat->groupIndent + checkboxWidth + dat->iconXSpace;
+ rc.top = y + ((dat->rowHeight - fontHeight) >> 1);
+ rc.right = (clRect.right - clRect.left);
+ rc.bottom = rc.top;
+ DrawText(hdcMem, szText, lstrlen(szText), &rc, DT_EDITCONTROL | DT_NOPREFIX | DT_NOCLIP | DT_WORD_ELLIPSIS | DT_SINGLELINE);
+ }
+ if (selected) {
+ if (group->cl.items[group->scanIndex]->type != CLCIT_DIVIDER) {
+ TCHAR *szText = group->cl.items[group->scanIndex]->szText;
+ RECT rc;
+ int qlen = lstrlen(dat->szQuickSearch);
+ SetTextColor(hdcMem, dat->quickSearchColour);
+ rc.left = dat->leftMargin + indent * dat->groupIndent + checkboxWidth + dat->iconXSpace;
+ rc.top = y + ((dat->rowHeight - fontHeight) >> 1);
+ rc.right = (clRect.right - clRect.left);
+ rc.bottom = rc.top;
+ if (qlen)
+ DrawText(hdcMem, szText, qlen, &rc, DT_EDITCONTROL | DT_NOPREFIX | DT_NOCLIP | DT_WORD_ELLIPSIS | DT_SINGLELINE);
+ }
+ }
+
+ //extra icons
+ for (iImage = 0; iImage < dat->extraColumnsCount; iImage++) {
+ COLORREF colourFg = dat->selBkColour;
+ int mode = ILD_NORMAL;
+ if (group->cl.items[group->scanIndex]->iExtraImage[iImage] == 0xFF)
+ continue;
+ if (selected)
+ mode = ILD_SELECTED;
+ else if (hottrack) {
+ mode = ILD_FOCUS;
+ colourFg = dat->hotTextColour;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT && group->cl.items[group->scanIndex]->flags & CONTACTF_NOTONLIST) {
+ colourFg = dat->fontInfo[FONTID_NOTONLIST].colour;
+ mode = ILD_BLEND50;
+ }
+ ImageList_DrawEx(dat->himlExtraColumns, group->cl.items[group->scanIndex]->iExtraImage[iImage], hdcMem,
+ clRect.right - dat->extraColumnSpacing * (dat->extraColumnsCount - iImage), y + ((dat->rowHeight - 16) >> 1), 0, 0,
+ CLR_NONE, colourFg, mode);
+ }
+ }
+ index++;
+ y += dat->rowHeight;
+ if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP && group->cl.items[group->scanIndex]->group->expanded) {
+ group = group->cl.items[group->scanIndex]->group;
+ indent++;
+ group->scanIndex = 0;
+ continue;
+ }
+ group->scanIndex++;
+ }
+ if (dat->iInsertionMark != -1) { //insertion mark
+ HBRUSH hBrush, hoBrush;
+ POINT pts[8];
+ HRGN hRgn;
+
+ pts[0].x = dat->leftMargin;
+ pts[0].y = dat->iInsertionMark * dat->rowHeight - dat->yScroll - 4;
+ pts[1].x = pts[0].x + 2;
+ pts[1].y = pts[0].y + 3;
+ pts[2].x = clRect.right - 4;
+ pts[2].y = pts[1].y;
+ pts[3].x = clRect.right - 1;
+ pts[3].y = pts[0].y - 1;
+ pts[4].x = pts[3].x;
+ pts[4].y = pts[0].y + 7;
+ pts[5].x = pts[2].x + 1;
+ pts[5].y = pts[1].y + 2;
+ pts[6].x = pts[1].x;
+ pts[6].y = pts[5].y;
+ pts[7].x = pts[0].x;
+ pts[7].y = pts[4].y;
+ hRgn = CreatePolygonRgn(pts, SIZEOF(pts), ALTERNATE);
+ hBrush = CreateSolidBrush(dat->fontInfo[FONTID_CONTACTS].colour);
+ hoBrush = (HBRUSH) SelectObject(hdcMem, hBrush);
+ FillRgn(hdcMem, hRgn, hBrush);
+ SelectObject(hdcMem, hoBrush);
+ DeleteObject(hBrush);
+ }
+ if (!grey)
+ BitBlt(hdc, rcPaint->left, rcPaint->top, rcPaint->right - rcPaint->left, rcPaint->bottom - rcPaint->top, hdcMem, rcPaint->left, rcPaint->top,
+ SRCCOPY);
+ SelectObject(hdcMem,hOldBitmap);
+ SelectObject(hdcMem,hOldFont);
+ DeleteDC(hdcMem);
+ if (hBrushAlternateGrey)
+ DeleteObject(hBrushAlternateGrey);
+ if (grey) {
+ PBYTE bits;
+ BITMAPINFOHEADER bmih = { 0 };
+ int i;
+ int greyRed, greyGreen, greyBlue;
+ COLORREF greyColour;
+ bmih.biBitCount = 32;
+ bmih.biSize = sizeof(bmih);
+ bmih.biCompression = BI_RGB;
+ bmih.biHeight = -clRect.bottom;
+ bmih.biPlanes = 1;
+ bmih.biWidth = clRect.right;
+ bits = (PBYTE) malloc(4 * bmih.biWidth * -bmih.biHeight);
+ GetDIBits(hdc, hBmpOsb, 0, clRect.bottom, bits, (BITMAPINFO *) & bmih, DIB_RGB_COLORS);
+ greyColour = GetSysColor(COLOR_3DFACE);
+ greyRed = GetRValue(greyColour) * 2;
+ greyGreen = GetGValue(greyColour) * 2;
+ greyBlue = GetBValue(greyColour) * 2;
+ if (divide3[0] == 255) {
+ for (i = 0; i < SIZEOF(divide3); i++)
+ divide3[i] = (i + 1) / 3;
+ }
+ for (i = 4 * clRect.right * clRect.bottom - 4; i >= 0; i -= 4) {
+ bits[i] = divide3[bits[i] + greyBlue];
+ bits[i + 1] = divide3[bits[i + 1] + greyGreen];
+ bits[i + 2] = divide3[bits[i + 2] + greyRed];
+ }
+ SetDIBitsToDevice(hdc, 0, 0, clRect.right, clRect.bottom, 0, 0, 0, clRect.bottom, bits, (BITMAPINFO *) & bmih, DIB_RGB_COLORS);
+ free(bits);
+ }
+ DeleteObject(hBmpOsb);
+}
diff --git a/miranda-wine/plugins/clist/clist.h b/miranda-wine/plugins/clist/clist.h
new file mode 100644
index 0000000..4184dbe
--- /dev/null
+++ b/miranda-wine/plugins/clist/clist.h
@@ -0,0 +1,30 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+void LoadContactTree(void);
+int IconFromStatusMode(const char *szProto,int status);
+HTREEITEM GetTreeItemByHContact(HANDLE hContact);
+void TrayIconUpdateWithImageList(int iImage,const char *szNewTip,char *szPreferredProto);
+void SortContacts(void);
+void ChangeContactIcon(HANDLE hContact,int iIcon,int add);
+
+#define NEWSTR_ALLOCA(A) (A==NULL)?NULL:strcpy((char*)alloca(strlen(A)+1),A)
diff --git a/miranda-wine/plugins/clist/clistmenus.c b/miranda-wine/plugins/clist/clistmenus.c
new file mode 100644
index 0000000..0480afa
--- /dev/null
+++ b/miranda-wine/plugins/clist/clistmenus.c
@@ -0,0 +1,947 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+#define FIRSTCUSTOMMENUITEMID 30000
+#define MENU_CUSTOMITEMMAIN 0x80000000
+#define MENU_CUSTOMITEMCONTEXT 0x40000000
+#define SEPARATORPOSITIONINTERVAL 100000
+
+struct CListMenuItem
+{
+ WORD id;
+ int iconId;
+ CLISTMENUITEM mi;
+};
+
+static int nextMenuId;
+static struct CListMenuItem *mainMenuItem, *contextMenuItem;
+static int mainItemCount, contextItemCount;
+static HIMAGELIST hImlMenuIcons;
+static HANDLE hPreBuildContactMenuEvent, hAckHook;
+static HMENU hMainMenu, hStatusMenu, hRootMenu;
+int currentStatusMenuItem, currentDesiredStatusMode;
+static int statusModeList[] =
+{
+ ID_STATUS_OFFLINE, ID_STATUS_ONLINE, ID_STATUS_AWAY, ID_STATUS_NA, ID_STATUS_OCCUPIED, ID_STATUS_DND, ID_STATUS_FREECHAT, ID_STATUS_INVISIBLE,
+ ID_STATUS_ONTHEPHONE, ID_STATUS_OUTTOLUNCH
+};
+
+static int skinIconStatusList[] =
+{
+ SKINICON_STATUS_OFFLINE, SKINICON_STATUS_ONLINE, SKINICON_STATUS_AWAY, SKINICON_STATUS_NA, SKINICON_STATUS_OCCUPIED, SKINICON_STATUS_DND,
+ SKINICON_STATUS_FREE4CHAT, SKINICON_STATUS_INVISIBLE, SKINICON_STATUS_ONTHEPHONE, SKINICON_STATUS_OUTTOLUNCH
+};
+
+static int statusModePf2List[] =
+{ 0xFFFFFFFF, PF2_ONLINE, PF2_SHORTAWAY, PF2_LONGAWAY, PF2_LIGHTDND, PF2_HEAVYDND, PF2_FREECHAT, PF2_INVISIBLE, PF2_ONTHEPHONE, PF2_OUTTOLUNCH };
+
+extern HANDLE hStatusModeChangeEvent;
+
+static TCHAR* LangPackPcharToTchar( const char* pszStr )
+{
+ if ( pszStr == NULL )
+ return NULL;
+
+ #if defined( _UNICODE )
+ { int len = strlen( pszStr );
+ TCHAR* result = ( TCHAR* )alloca(( len+1 )*sizeof( TCHAR ));
+ MultiByteToWideChar( CallService( MS_LANGPACK_GETCODEPAGE, 0, 0 ), 0, pszStr, -1, result, len );
+ result[len] = 0;
+ return wcsdup( TranslateW( result ));
+ }
+ #else
+ return _strdup( Translate( pszStr ));
+ #endif
+}
+
+static void InsertMenuItemWithSeparators(HMENU hMenu, int uItem, BOOL fByPosition, MENUITEMINFO* lpmii)
+{
+ int thisItemPosition, needSeparator;
+ MENUITEMINFO mii;
+
+ if (lpmii->fMask & MIIM_SUBMENU)
+ thisItemPosition = (int) lpmii->dwItemData;
+ else
+ thisItemPosition = mainMenuItem[lpmii->dwItemData & ~MENU_CUSTOMITEMMAIN].mi.position;
+ ZeroMemory(&mii, sizeof(mii));
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ //check for separator before
+ if (uItem) {
+ mii.fMask = MIIM_SUBMENU | MIIM_DATA | MIIM_TYPE;
+ GetMenuItemInfo(hMenu, uItem - 1, TRUE, &mii);
+ if (mii.fType == MFT_SEPARATOR)
+ needSeparator = 0;
+ else if (mii.hSubMenu == NULL && (mii.dwItemData & MENU_CUSTOMITEMMAIN) == 0)
+ needSeparator = 0;
+ else if (mii.hSubMenu == NULL)
+ needSeparator =
+ ((mainMenuItem[mii.dwItemData & ~MENU_CUSTOMITEMMAIN].mi.position) / SEPARATORPOSITIONINTERVAL) !=
+ thisItemPosition / SEPARATORPOSITIONINTERVAL;
+ else
+ needSeparator = ((int) mii.dwItemData) / SEPARATORPOSITIONINTERVAL != thisItemPosition / SEPARATORPOSITIONINTERVAL;
+ if (needSeparator) {
+ //but might be supposed to be after the next one instead
+ mii.fType = 0;
+ if (uItem < GetMenuItemCount(hMenu)) {
+ mii.fMask = MIIM_SUBMENU | MIIM_DATA | MIIM_TYPE;
+ GetMenuItemInfo(hMenu, uItem, TRUE, &mii);
+ }
+ if (mii.fType != MFT_SEPARATOR) {
+ mii.fMask = MIIM_TYPE;
+ mii.fType = MFT_SEPARATOR;
+ InsertMenuItem(hMenu, uItem, TRUE, &mii);
+ }
+ uItem++;
+ }
+ }
+ //check for separator after
+ if (uItem < GetMenuItemCount(hMenu)) {
+ mii.fMask = MIIM_SUBMENU | MIIM_DATA | MIIM_TYPE;
+ mii.cch = 0;
+ GetMenuItemInfo(hMenu, uItem, TRUE, &mii);
+ if (mii.fType == MFT_SEPARATOR)
+ needSeparator = 0;
+ else if (mii.hSubMenu == NULL && (mii.dwItemData & MENU_CUSTOMITEMMAIN) == 0)
+ needSeparator = 0;
+ else if (mii.hSubMenu == NULL)
+ needSeparator =
+ ((mainMenuItem[mii.dwItemData & ~MENU_CUSTOMITEMMAIN].mi.position) / SEPARATORPOSITIONINTERVAL) !=
+ thisItemPosition / SEPARATORPOSITIONINTERVAL;
+ else
+ needSeparator = ((int) mii.dwItemData) / SEPARATORPOSITIONINTERVAL != thisItemPosition / SEPARATORPOSITIONINTERVAL;
+ if (needSeparator) {
+ mii.fMask = MIIM_TYPE;
+ mii.fType = MFT_SEPARATOR;
+ InsertMenuItem(hMenu, uItem, TRUE, &mii);
+ }
+ }
+ if (uItem == GetMenuItemCount(hMenu) - 1) {
+ TCHAR str[32];
+ mii.fMask = MIIM_SUBMENU | MIIM_DATA | MIIM_TYPE;
+ mii.dwTypeData = str;
+ mii.cch = SIZEOF(str);
+ GetMenuItemInfo(hMenu, uItem, TRUE, &mii);
+ if (mii.fType == MFT_STRING && !_tcscmp(mii.dwTypeData, TranslateT("E&xit"))) {
+ //make sure we keep the separator before the exit menu item
+ mii.fMask = MIIM_TYPE;
+ mii.fType = MFT_SEPARATOR;
+ InsertMenuItem(hMenu, uItem, TRUE, &mii);
+ }
+ }
+ InsertMenuItem(hMenu, uItem, TRUE, lpmii);
+}
+
+//#define PUTPOSITIONSONMENU
+static int AddMainMenuItem(WPARAM wParam, LPARAM lParam)
+{
+ CLISTMENUITEM *mi = (CLISTMENUITEM *) lParam;
+ MENUITEMINFO mii;
+ TCHAR* ptszName;
+ int i;
+ HMENU hMenu;
+
+ if (mi==NULL || mi->cbSize != sizeof(CLISTMENUITEM))
+ return 0;
+ mainMenuItem = (struct CListMenuItem *) realloc(mainMenuItem, sizeof(struct CListMenuItem) * (mainItemCount + 1));
+ mainMenuItem[mainItemCount].id = nextMenuId++;
+ mainMenuItem[mainItemCount].mi = *mi;
+ mainMenuItem[mainItemCount].mi.pszService = strdup(mi->pszService);
+ mainMenuItem[mainItemCount].mi.pszContactOwner = NULL;
+ mainMenuItem[mainItemCount].mi.pszName = NULL;
+ if (mi->hIcon == NULL)
+ mainMenuItem[mainItemCount].iconId = -1;
+ else
+ mainMenuItem[mainItemCount].iconId = ImageList_AddIcon(hImlMenuIcons, mi->hIcon);
+ hMenu = hMainMenu;
+ ZeroMemory(&mii, sizeof(mii));
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ mii.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_DATA;
+ if (mi->pszPopupName != NULL) {
+ TCHAR str[80];
+ TCHAR* ptszPopupName = LangPackPcharToTchar( mi->pszPopupName );
+ for (i = GetMenuItemCount(hMenu) - 1; i >= 0; i--) {
+ mii.cch = SIZEOF(str);
+ mii.dwTypeData = str;
+ GetMenuItemInfo(hMenu, i, TRUE, &mii);
+#ifdef PUTPOSITIONSONMENU
+ if (mii.hSubMenu != NULL && !_tcsnicmp(str, ptszPopupName, _tcslen(ptszPopupName)))
+ break;
+#else
+ if (mii.hSubMenu != NULL && !_tcsicmp(str, ptszPopupName))
+ break;
+#endif
+ }
+ if (i < 0) {
+ mii.fMask = MIIM_SUBMENU | MIIM_DATA | MIIM_TYPE;
+ for (i = GetMenuItemCount(hMenu) - 1; i >= 0; i--) {
+ mii.cch = SIZEOF(str);
+ mii.dwTypeData = str;
+ GetMenuItemInfo(hMenu, i, TRUE, &mii);
+ if (mii.fType == MFT_SEPARATOR)
+ continue;
+ if (mii.hSubMenu == NULL && (mii.dwItemData & MENU_CUSTOMITEMMAIN) == 0)
+ continue;
+ if (mii.hSubMenu == NULL) {
+ if (mainMenuItem[mii.dwItemData & ~MENU_CUSTOMITEMMAIN].mi.position <= mainMenuItem[mainItemCount].mi.popupPosition)
+ break;
+ }
+ else {
+ if ((int) mii.dwItemData <= mainMenuItem[mainItemCount].mi.popupPosition)
+ break;
+ } }
+
+ i++;
+ mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_SUBMENU;
+ mii.fType = MFT_STRING;
+ mii.dwItemData = (DWORD) mi->popupPosition;
+ mii.hSubMenu = CreatePopupMenu();
+#ifdef PUTPOSITIONSONMENU
+ {
+ TCHAR str[256];
+ mir_sntprintf(str, SIZEOF(str), "%s (%d)", ptszPopupName, mi->popupPosition);
+ mii.dwTypeData = str;
+ InsertMenuItemWithSeparators(hMenu, i, TRUE, &mii);
+ }
+#else
+ mii.dwTypeData = ptszPopupName;
+ InsertMenuItemWithSeparators(hMenu, i, TRUE, &mii);
+#endif
+ }
+ free(ptszPopupName);
+ hMenu = mii.hSubMenu;
+ }
+ mii.fMask = MIIM_SUBMENU | MIIM_DATA;
+ for (i = GetMenuItemCount(hMenu) - 1; i >= 0; i--) {
+ GetMenuItemInfo(hMenu, i, TRUE, &mii);
+ if (mii.fType == MFT_SEPARATOR)
+ continue;
+ if (mii.hSubMenu == NULL && (mii.dwItemData & MENU_CUSTOMITEMMAIN) == 0)
+ continue;
+ if (mii.hSubMenu == NULL) {
+ if (mainMenuItem[mii.dwItemData & ~MENU_CUSTOMITEMMAIN].mi.position <= mainMenuItem[mainItemCount].mi.position)
+ break;
+ }
+ else {
+ if ((int) mii.dwItemData <= mainMenuItem[mainItemCount].mi.position)
+ break;
+ }
+ }
+ i++;
+ if (!IsWinVer98Plus()) {
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID;
+ }
+ else {
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_DATA | MIIM_ID | MIIM_STRING;
+ if (mainMenuItem[mainItemCount].iconId != -1)
+ mii.fMask |= MIIM_BITMAP;
+ }
+ ptszName = LangPackPcharToTchar( mi->pszName );
+
+ mii.fType = MFT_STRING;
+ mii.wID = mainMenuItem[mainItemCount].id;
+ mii.dwItemData = mainItemCount | MENU_CUSTOMITEMMAIN;
+ mii.hbmpItem = HBMMENU_CALLBACK;
+#ifdef PUTPOSITIONSONMENU
+ {
+ TCHAR str[256];
+ mir_sntprintf(str, SIZEOF(str), "%s (%d)", ptszName, mi->position);
+ mii.dwTypeData = str;
+ InsertMenuItemWithSeparators(hMenu, i, TRUE, &mii);
+ }
+#else
+ mii.dwTypeData = ptszName;
+ InsertMenuItemWithSeparators(hMenu, i, TRUE, &mii);
+#endif
+ free( ptszName );
+ mainItemCount++;
+ return MENU_CUSTOMITEMMAIN | (mainItemCount - 1);
+}
+
+static int AddContactMenuItem(WPARAM wParam, LPARAM lParam)
+{
+ CLISTMENUITEM *mi = (CLISTMENUITEM *) lParam;
+
+ if (mi==NULL || mi->cbSize != sizeof(CLISTMENUITEM))
+ return 0;
+ contextMenuItem = (struct CListMenuItem *) realloc(contextMenuItem, sizeof(struct CListMenuItem) * (contextItemCount + 1));
+ contextMenuItem[contextItemCount].id = nextMenuId++;
+ contextMenuItem[contextItemCount].mi = *mi;
+ contextMenuItem[contextItemCount].mi.pszService = strdup(mi->pszService);
+ contextMenuItem[contextItemCount].mi.ptszName = LangPackPcharToTchar(mi->pszName);
+ if (mi->pszContactOwner != NULL)
+ contextMenuItem[contextItemCount].mi.pszContactOwner = strdup(mi->pszContactOwner);
+ if (mi->hIcon == NULL)
+ contextMenuItem[contextItemCount].iconId = -1;
+ else
+ contextMenuItem[contextItemCount].iconId = ImageList_AddIcon(hImlMenuIcons, mi->hIcon);
+ contextItemCount++;
+ return MENU_CUSTOMITEMCONTEXT | (contextItemCount - 1);
+}
+
+static int ModifyCustomMenuItem(WPARAM wParam, LPARAM lParam)
+{
+ struct CListMenuItem *clmi;
+ CLISTMENUITEM *mi = (CLISTMENUITEM *) lParam;
+ MENUITEMINFO mii;
+
+ if (mi==NULL || mi->cbSize != sizeof(CLISTMENUITEM))
+ return 1;
+ if (wParam & MENU_CUSTOMITEMMAIN) {
+ if ((int) (wParam & ~MENU_CUSTOMITEMMAIN) >= mainItemCount)
+ return 1;
+ clmi = mainMenuItem + (wParam & ~MENU_CUSTOMITEMMAIN);
+ }
+ else if (wParam & MENU_CUSTOMITEMCONTEXT) {
+ if ((int) (wParam & ~MENU_CUSTOMITEMCONTEXT) >= contextItemCount)
+ return 1;
+ clmi = contextMenuItem + (wParam & ~MENU_CUSTOMITEMCONTEXT);
+ }
+ else
+ return 1;
+ ZeroMemory(&mii, sizeof(mii));
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ if (mi->flags & CMIM_NAME) {
+ if (clmi->mi.pszName != NULL)
+ free(clmi->mi.pszName);
+ clmi->mi.ptszName = LangPackPcharToTchar(mi->pszName);
+ if (wParam & MENU_CUSTOMITEMMAIN) {
+ mii.fMask = IsWinVer98Plus()? MIIM_STRING : MIIM_TYPE;
+ mii.fType = MFT_STRING;
+ mii.dwTypeData = clmi->mi.ptszName;
+ SetMenuItemInfo(hMainMenu, clmi->id, FALSE, &mii);
+ }
+ }
+ if (mi->flags & CMIM_FLAGS) {
+ clmi->mi.flags = mi->flags & ~CMIM_ALL;
+ if (wParam & MENU_CUSTOMITEMMAIN) {
+ mii.fMask = MIIM_STATE;
+ mii.fState = ((clmi->mi.flags & CMIF_GRAYED) ? MFS_GRAYED : 0) | ((clmi->mi.flags & CMIF_CHECKED) ? MFS_CHECKED : 0);
+ SetMenuItemInfo(hMainMenu, clmi->id, FALSE, &mii);
+ }
+ }
+ if (mi->flags & CMIM_ICON) {
+ clmi->mi.hIcon = mi->hIcon;
+ if (mi->hIcon != NULL)
+ clmi->iconId = ImageList_ReplaceIcon(hImlMenuIcons, clmi->iconId, mi->hIcon);
+ else
+ clmi->iconId = -1; //fixme, should remove old icon & shuffle all iconIds
+ }
+ if (mi->flags & CMIM_HOTKEY) {
+ clmi->mi.hotKey = mi->hotKey;
+ }
+ return 0;
+}
+
+int MenuProcessCommand(WPARAM wParam, LPARAM lParam)
+{
+ int i;
+ PROTOCOLDESCRIPTOR **proto;
+ int protoCount;
+
+ if (HIWORD(wParam) & MPCF_MAINMENU) {
+ int newStatus, protoIndex;
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM) & protoCount, (LPARAM) & proto);
+ if (LOWORD(wParam) >= ID_STATUS_OFFLINE + SIZEOF(statusModeList)
+ && LOWORD(wParam) < ID_STATUS_OFFLINE + (protoCount + 1) * SIZEOF(statusModeList)) {
+ // one of the protocol-specific status menus
+ protoIndex = (LOWORD(wParam) - ID_STATUS_OFFLINE) / SIZEOF(statusModeList) - 1;
+ newStatus = (LOWORD(wParam) - ID_STATUS_OFFLINE) % SIZEOF(statusModeList) + ID_STATUS_OFFLINE;
+ // let the world know, this need's the translated ID_STATUS_* NOT LOWORD(wParam)
+ // which is offseted by some degree depending on protocol used
+ CallProtoService(proto[protoIndex]->szName, PS_SETSTATUS, newStatus, 0);
+ NotifyEventHooks(hStatusModeChangeEvent, newStatus, (LPARAM) proto[protoIndex]->szName);
+ }
+ switch (LOWORD(wParam)) {
+ case ID_STATUS_OFFLINE:
+ case ID_STATUS_ONLINE:
+ case ID_STATUS_AWAY:
+ case ID_STATUS_DND:
+ case ID_STATUS_NA:
+ case ID_STATUS_OCCUPIED:
+ case ID_STATUS_FREECHAT:
+ case ID_STATUS_INVISIBLE:
+ case ID_STATUS_OUTTOLUNCH:
+ case ID_STATUS_ONTHEPHONE:
+ currentDesiredStatusMode = LOWORD(wParam);
+ for (i = 0; i < protoCount; i++)
+ CallProtoService(proto[i]->szName, PS_SETSTATUS, LOWORD(wParam), 0);
+ DBWriteContactSettingWord(NULL, "CList", "Status", (WORD) currentDesiredStatusMode);
+ NotifyEventHooks(hStatusModeChangeEvent, LOWORD(wParam), 0);
+ return 1;
+ }
+ for (i = 0; i < mainItemCount; i++) {
+ if (LOWORD(wParam) == mainMenuItem[i].id) {
+ CallService(mainMenuItem[i].mi.pszService, 0, (LPARAM) NULL);
+ return 1;
+ }
+ }
+ }
+ if (HIWORD(wParam) & MPCF_CONTACTMENU) {
+ for (i = 0; i < contextItemCount; i++) {
+ if (LOWORD(wParam) == contextMenuItem[i].id) {
+ if ((HANDLE) lParam != NULL)
+ CallService(contextMenuItem[i].mi.pszService, lParam, (LPARAM) (HWND) NULL);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int MenuProcessHotkey(WPARAM vKey, LPARAM lParam)
+{
+ int i;
+
+ if (lParam & MPCF_MAINMENU) {
+ if (vKey >= '0' && vKey <= '9' && GetKeyState(VK_CONTROL) & 0x8000 && !(GetKeyState(VK_MENU) & 0x8000) && !(GetKeyState(VK_SHIFT) & 0x8000)) {
+ MenuProcessCommand(MAKEWPARAM(statusModeList[vKey - '0'], MPCF_MAINMENU), 0);
+ return 1;
+ }
+ for (i = 0; i < mainItemCount; i++) {
+ if (mainMenuItem[i].mi.hotKey == 0)
+ continue;
+ if (HIWORD(mainMenuItem[i].mi.hotKey) != vKey)
+ continue;
+ if (!(LOWORD(mainMenuItem[i].mi.hotKey) & MOD_ALT) != !(GetKeyState(VK_MENU) & 0x8000))
+ continue;
+ if (!(LOWORD(mainMenuItem[i].mi.hotKey) & MOD_CONTROL) != !(GetKeyState(VK_CONTROL) & 0x8000))
+ continue;
+ if (!(LOWORD(mainMenuItem[i].mi.hotKey) & MOD_SHIFT) != !(GetKeyState(VK_SHIFT) & 0x8000))
+ continue;
+ CallService(mainMenuItem[i].mi.pszService, 0, (LPARAM) NULL);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+//straight subtraction is not possible because I was getting overflows
+static int MenuSortProc(int *item1, int *item2)
+{
+ if (contextMenuItem[*item2].mi.position > contextMenuItem[*item1].mi.position)
+ return 1;
+ if (contextMenuItem[*item2].mi.position < contextMenuItem[*item1].mi.position)
+ return -1;
+ return 0;
+}
+
+static int BuildContactMenu(WPARAM wParam, LPARAM lParam)
+{
+ HMENU hMenu;
+ MENUITEMINFO mii;
+ int i;
+ int *itemOrder, itemCount;
+ int isOnline, isOnList;
+ HANDLE hContact = (HANDLE) wParam;
+ int prevPosition;
+ int chatRoom;
+ DWORD miim_bitmap_verSpecific;
+ char *szProto;
+
+ NotifyEventHooks(hPreBuildContactMenuEvent, (WPARAM) hContact, 0);
+
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ isOnList = 0 == DBGetContactSettingByte(hContact, "CList", "NotOnList", 0);
+ isOnline = szProto != NULL && ID_STATUS_OFFLINE != DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE);
+ chatRoom = szProto?DBGetContactSettingByte(hContact, szProto, "ChatRoom", 0):0;
+ if ( contextItemCount ) {
+ itemOrder = (int *) malloc(sizeof(int) * contextItemCount);
+ ZeroMemory(itemOrder, sizeof(int) * contextItemCount);
+ } else {
+ itemOrder = (int *) malloc(sizeof(int) * 1);
+ ZeroMemory(itemOrder, sizeof(int) * 1);
+ }
+ itemCount = 0;
+ for (i = 0; i < contextItemCount; i++) {
+ if (contextMenuItem[i].id == 0)
+ continue;
+ if (szProto == NULL)
+ continue;
+ // Begin Ugly hack to hide chat room menus
+ if (chatRoom) {
+ if (!strcmp(contextMenuItem[i].mi.pszName,Translate("&Message")))
+ continue;
+ if (!strcmp(contextMenuItem[i].mi.pszName,Translate("&File")))
+ continue;
+ if (!strcmp(contextMenuItem[i].mi.pszName,Translate("User &Details")))
+ continue;
+ if (!strcmp(contextMenuItem[i].mi.pszName,Translate("View &History")))
+ continue;
+ }
+ // End ugly hack
+ if (contextMenuItem[i].mi.pszContactOwner != NULL) {
+ if (strcmp(contextMenuItem[i].mi.pszContactOwner, szProto))
+ continue;
+ }
+ if (contextMenuItem[i].mi.flags & CMIF_HIDDEN)
+ continue;
+ if (contextMenuItem[i].mi.flags & CMIF_NOTONLIST && isOnList)
+ continue;
+ if (contextMenuItem[i].mi.flags & CMIF_NOTOFFLIST && !isOnList)
+ continue;
+ if (contextMenuItem[i].mi.flags & CMIF_NOTONLINE && isOnline)
+ continue;
+ if (contextMenuItem[i].mi.flags & CMIF_NOTOFFLINE && !isOnline)
+ continue;
+ itemOrder[itemCount] = i;
+ itemCount++;
+ }
+ //sorts in reverse order since it's easiest to add items bottom to top
+ qsort(itemOrder, itemCount, sizeof(int), (int (*)(const void *, const void *)) MenuSortProc);
+ hMenu = CreatePopupMenu();
+ ZeroMemory(&mii, sizeof(mii));
+ if (!IsWinVer98Plus()) {
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ mii.fMask = MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_TYPE;
+ miim_bitmap_verSpecific = 0;
+ }
+ else {
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_STRING;
+ miim_bitmap_verSpecific = MIIM_BITMAP;
+ }
+ mii.fType = MFT_STRING;
+ mii.hbmpItem = HBMMENU_CALLBACK;
+ prevPosition = contextMenuItem[itemOrder[0]].mi.position;
+ for (i = 0; i < itemCount; i++) {
+ if (prevPosition / SEPARATORPOSITIONINTERVAL != contextMenuItem[itemOrder[i]].mi.position / SEPARATORPOSITIONINTERVAL) {
+ UINT oldMask = mii.fMask;
+ mii.fMask = MIIM_TYPE;
+ mii.fType = MFT_SEPARATOR;
+ InsertMenuItem(hMenu, 0, TRUE, &mii);
+ mii.fMask = oldMask;
+ mii.fType = MFT_STRING;
+ }
+ prevPosition = contextMenuItem[itemOrder[i]].mi.position;
+ if (contextMenuItem[itemOrder[i]].iconId == -1)
+ mii.fMask &= ~miim_bitmap_verSpecific;
+ else
+ mii.fMask |= miim_bitmap_verSpecific;
+ mii.dwItemData = itemOrder[i] | MENU_CUSTOMITEMCONTEXT;
+ mii.fState =
+ ((contextMenuItem[itemOrder[i]].mi.flags & CMIF_GRAYED) ? MFS_GRAYED : MFS_ENABLED) | ((contextMenuItem[itemOrder[i]].mi.
+ flags & CMIF_CHECKED) ? MFS_CHECKED :
+ MFS_UNCHECKED);
+ mii.wID = contextMenuItem[itemOrder[i]].id;
+ mii.dwTypeData = contextMenuItem[itemOrder[i]].mi.ptszName;
+#ifdef _DEBUG
+ if (GetKeyState(VK_CONTROL) & 0x8000) {
+ TCHAR str[256];
+ wsprintf(str, _T("%s (%d)"), contextMenuItem[itemOrder[i]].mi.pszName, contextMenuItem[itemOrder[i]].mi.position);
+ mii.dwTypeData = str;
+ InsertMenuItem(hMenu, 0, TRUE, &mii);
+ }
+ else InsertMenuItem(hMenu, 0, TRUE, &mii);
+#else
+ InsertMenuItem(hMenu, 0, TRUE, &mii);
+#endif
+ }
+ free(itemOrder);
+ return (int) hMenu;
+}
+
+static int MenuIconsChanged(WPARAM wParam, LPARAM lParam)
+{
+ int i, protoCount, networkProtoCount, j;
+ PROTOCOLDESCRIPTOR **proto;
+ DWORD flags;
+ MENUITEMINFO mii;
+
+ ZeroMemory(&mii, sizeof(mii));
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_DATA;
+
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM) & protoCount, (LPARAM) & proto);
+ networkProtoCount = 0;
+ for (i = 0; i < protoCount; i++)
+ if (proto[i]->type == PROTOTYPE_PROTOCOL)
+ networkProtoCount++;
+ if (networkProtoCount > 1) {
+ for (i = 0; i < protoCount; i++) {
+ if (proto[i]->type != PROTOTYPE_PROTOCOL)
+ continue;
+ flags = CallProtoService(proto[i]->szName, PS_GETCAPS, PFLAGNUM_2, 0);
+ for (j = 0; j < SIZEOF(statusModeList); j++) {
+ if (!(flags & statusModePf2List[j]))
+ continue;
+ if (!GetMenuItemInfo(hStatusMenu, (i + 1) * SIZEOF(statusModeList) + statusModeList[j], FALSE, &mii))
+ continue;
+ if ((mii.dwItemData & MENU_CUSTOMITEMMAIN) != MENU_CUSTOMITEMMAIN)
+ continue;
+ ImageList_ReplaceIcon(hImlMenuIcons, mainMenuItem[mii.dwItemData & ~MENU_CUSTOMITEMMAIN].iconId,
+ LoadSkinnedProtoIcon(proto[i]->szName, statusModeList[j]));
+ } } }
+
+ for (i = 0; i < SIZEOF(statusModeList); i++) {
+ if (!GetMenuItemInfo(hStatusMenu, statusModeList[i], FALSE, &mii))
+ continue;
+ if ((mii.dwItemData & MENU_CUSTOMITEMMAIN) != MENU_CUSTOMITEMMAIN)
+ continue;
+ ImageList_ReplaceIcon(hImlMenuIcons, mainMenuItem[mii.dwItemData & ~MENU_CUSTOMITEMMAIN].iconId,
+ LoadSkinnedProtoIcon(NULL, statusModeList[i]));
+ }
+ return 0;
+}
+
+static void GiveExistingItemAnIcon(UINT id, HICON hIcon)
+{
+ MENUITEMINFO mii;
+
+ mainMenuItem = (struct CListMenuItem *) realloc(mainMenuItem, sizeof(struct CListMenuItem) * (mainItemCount + 1));
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_BITMAP | MIIM_DATA;
+ mii.dwItemData = MENU_CUSTOMITEMMAIN | mainItemCount;
+ mii.hbmpItem = HBMMENU_CALLBACK;
+ mainMenuItem[mainItemCount].iconId = ImageList_AddIcon(hImlMenuIcons, hIcon);
+ mainMenuItem[mainItemCount].id = 0xFFFF;
+ mainMenuItem[mainItemCount].mi.hotKey = 0;
+ mainMenuItem[mainItemCount].mi.pszName = NULL;
+ mainMenuItem[mainItemCount].mi.pszService = NULL;
+ SetMenuItemInfo(hStatusMenu, id, FALSE, &mii);
+ mainItemCount++;
+}
+
+static int MeasureMenuItem(WPARAM wParam, LPARAM lParam)
+{
+ struct CListMenuItem *clmi = NULL;
+ LPMEASUREITEMSTRUCT mis = (LPMEASUREITEMSTRUCT) lParam;
+ if (mis->itemData & MENU_CUSTOMITEMCONTEXT)
+ clmi = &contextMenuItem[mis->itemData & ~MENU_CUSTOMITEMCONTEXT];
+ else if (mis->itemData & MENU_CUSTOMITEMMAIN)
+ clmi = &mainMenuItem[mis->itemData & ~MENU_CUSTOMITEMMAIN];
+ if (clmi == NULL)
+ return FALSE;
+ if (clmi->iconId == -1)
+ return FALSE;
+
+ mis->itemWidth = max(0, GetSystemMetrics(SM_CXSMICON) - GetSystemMetrics(SM_CXMENUCHECK) + 4);
+ mis->itemHeight = GetSystemMetrics(SM_CYSMICON) + 2;
+ return TRUE;
+}
+
+static int DrawMenuItem(WPARAM wParam, LPARAM lParam)
+{
+ struct CListMenuItem *clmi = NULL;
+ int y;
+ LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT) lParam;
+
+ if (dis->itemData & MENU_CUSTOMITEMCONTEXT)
+ clmi = &contextMenuItem[dis->itemData & ~MENU_CUSTOMITEMCONTEXT];
+ else if (dis->itemData & MENU_CUSTOMITEMMAIN)
+ clmi = &mainMenuItem[dis->itemData & ~MENU_CUSTOMITEMMAIN];
+ if (clmi == NULL)
+ return FALSE;
+ if (clmi->iconId == -1)
+ return FALSE;
+
+ y = (dis->rcItem.bottom - dis->rcItem.top - GetSystemMetrics(SM_CYSMICON)) / 2 + 1;
+ if (dis->itemState & ODS_SELECTED) {
+ if (dis->itemState & ODS_CHECKED) {
+ RECT rc;
+ rc.left = 2;
+ rc.right = GetSystemMetrics(SM_CXSMICON) + 2;
+ rc.top = y;
+ rc.bottom = rc.top + GetSystemMetrics(SM_CYSMICON) + 2;
+ FillRect(dis->hDC, &rc, GetSysColorBrush(COLOR_HIGHLIGHT));
+ ImageList_DrawEx(hImlMenuIcons, clmi->iconId, dis->hDC, 2, y, 0, 0, CLR_NONE, CLR_DEFAULT, ILD_SELECTED);
+ }
+ else
+ ImageList_DrawEx(hImlMenuIcons, clmi->iconId, dis->hDC, 2, y, 0, 0, CLR_NONE, CLR_DEFAULT, ILD_FOCUS);
+ }
+ else {
+ if (dis->itemState & ODS_CHECKED) {
+ HBRUSH hBrush;
+ RECT rc;
+ COLORREF menuCol, hiliteCol;
+ rc.left = 0;
+ rc.right = GetSystemMetrics(SM_CXSMICON) + 4;
+ rc.top = y - 2;
+ rc.bottom = rc.top + GetSystemMetrics(SM_CYSMICON) + 4;
+ DrawEdge(dis->hDC, &rc, BDR_SUNKENOUTER, BF_RECT);
+ InflateRect(&rc, -1, -1);
+ menuCol = GetSysColor(COLOR_MENU);
+ hiliteCol = GetSysColor(COLOR_3DHIGHLIGHT);
+ hBrush =
+ CreateSolidBrush(RGB
+ ((GetRValue(menuCol) + GetRValue(hiliteCol)) / 2, (GetGValue(menuCol) + GetGValue(hiliteCol)) / 2,
+ (GetBValue(menuCol) + GetBValue(hiliteCol)) / 2));
+ FillRect(dis->hDC, &rc, hBrush);
+ DeleteObject(hBrush);
+ ImageList_DrawEx(hImlMenuIcons, clmi->iconId, dis->hDC, 2, y, 0, 0, CLR_NONE, GetSysColor(COLOR_MENU), ILD_BLEND25);
+ }
+ else ImageList_DrawEx(hImlMenuIcons, clmi->iconId, dis->hDC, 2, y, 0, 0, CLR_NONE, CLR_NONE, ILD_NORMAL);
+ }
+ return TRUE;
+}
+
+static int MenuGetMain(WPARAM wParam, LPARAM lParam)
+{
+ return (int) hMainMenu;
+}
+
+static int MenuGetStatus(WPARAM wParam, LPARAM lParam)
+{
+ return (int) hStatusMenu;
+}
+
+static int MenuModulesLoaded(WPARAM wParam, LPARAM lParam)
+{
+ int i, protoCount, networkProtoCount;
+ char *szProto = NULL;
+ char *szLastProto = NULL;
+ PROTOCOLDESCRIPTOR **proto;
+ DWORD statusFlags = 0, flags, moreflags = 0;
+
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM) & protoCount, (LPARAM) & proto);
+ networkProtoCount = 0;
+ for (i = 0; i < protoCount; i++) /* look for valid protocols */
+ if (proto[i]->type == PROTOTYPE_PROTOCOL && CallProtoService(proto[i]->szName, PS_GETCAPS, PFLAGNUM_2, 0) != 0) {
+ networkProtoCount++;
+ szLastProto = proto[i]->szName; /* remember the protocol name, since it maybe the last */
+ } //if
+
+ if (IsWinVer98Plus()) {
+ /* if a single network protocol is used, load the iconset for the global menu by name */
+ if (networkProtoCount == 1)
+ szProto = szLastProto;
+ for (i = 0; i < SIZEOF(statusModeList); i++) {
+ GiveExistingItemAnIcon(statusModeList[i], LoadSkinnedProtoIcon(szProto, statusModeList[i]));
+ }
+ HookEvent(ME_SKIN_ICONSCHANGED, MenuIconsChanged);
+ }
+
+ if (networkProtoCount > 1) {
+ MENUITEMINFO mii;
+ ZeroMemory(&mii, sizeof(mii));
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ mii.fMask = MIIM_TYPE;
+ mii.fType = MFT_SEPARATOR;
+ mii.dwTypeData = _T("");
+ InsertMenuItem(hStatusMenu, 0, TRUE, &mii);
+ }
+ for (i = 0; i < protoCount; i++) {
+ if (proto[i]->type != PROTOTYPE_PROTOCOL || CallProtoService(proto[i]->szName, PS_GETCAPS, PFLAGNUM_2, 0) == 0)
+ continue;
+ flags = CallProtoService(proto[i]->szName, PS_GETCAPS, PFLAGNUM_2, 0);
+ moreflags = CallProtoService(proto[i]->szName, PS_GETCAPS, PFLAGNUM_5, 0);
+ if (networkProtoCount > 1) {
+ MENUITEMINFO mii;
+ char protoName[128];
+ int j;
+ HMENU hMenu = GetSubMenu(LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_CLISTMENU)), 1);
+ ZeroMemory(&mii, sizeof(mii));
+ for (j = 0; j < SIZEOF(statusModeList); j++) {
+ if (!(flags & statusModePf2List[j]))
+ DeleteMenu(hMenu, statusModeList[j], MF_BYCOMMAND);
+ else if (moreflags & statusModePf2List[j] && j > 0)
+ DeleteMenu(hMenu, statusModeList[j], MF_BYCOMMAND);
+ else {
+ TCHAR text[128], *ptab;
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ mii.fMask = MIIM_TYPE;
+ mii.cch = SIZEOF(text);
+ mii.dwTypeData = text;
+ GetMenuItemInfo(hMenu, statusModeList[j], FALSE, &mii);
+ _tcscpy(text, TranslateTS(text));
+ ptab = _tcschr(text, '\t');
+ if (ptab != NULL)
+ *ptab = '\0';
+ if (IsWinVer98Plus()) {
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_ID | MIIM_BITMAP | MIIM_DATA | MIIM_STRING;
+ mainMenuItem = (struct CListMenuItem *)realloc(mainMenuItem, sizeof(struct CListMenuItem) * (mainItemCount + 1));
+ mainMenuItem[mainItemCount].iconId =
+ ImageList_AddIcon(hImlMenuIcons, LoadSkinnedProtoIcon(proto[i]->szName, statusModeList[j]));
+ mainMenuItem[mainItemCount].id = 0xFFFF;
+ mainMenuItem[mainItemCount].mi.hotKey = 0;
+ mainMenuItem[mainItemCount].mi.pszName = NULL;
+ mainMenuItem[mainItemCount].mi.pszService = NULL;
+ mii.dwItemData = MENU_CUSTOMITEMMAIN | mainItemCount;
+ mii.hbmpItem = HBMMENU_CALLBACK;
+ mainItemCount++;
+ }
+ else
+ mii.fMask = MIIM_ID | MIIM_TYPE;
+ mii.wID = statusModeList[j] + (i + 1) * SIZEOF(statusModeList);
+ SetMenuItemInfo(hMenu, statusModeList[j], FALSE, &mii);
+ }
+ }
+ if (IsWinVer98Plus()) {
+ HICON hIcon;
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_SUBMENU | MIIM_BITMAP | MIIM_DATA | MIIM_STRING;
+ mainMenuItem = (struct CListMenuItem *) realloc(mainMenuItem, sizeof(struct CListMenuItem) * (mainItemCount + 1));
+ hIcon = (HICON) CallProtoService(proto[i]->szName, PS_LOADICON, PLI_PROTOCOL | PLIF_SMALL, 0);
+ mainMenuItem[mainItemCount].iconId = ImageList_AddIcon(hImlMenuIcons, hIcon);
+ DestroyIcon(hIcon);
+ mainMenuItem[mainItemCount].id = 0xFFFF;
+ mainMenuItem[mainItemCount].mi.hotKey = 0;
+ mainMenuItem[mainItemCount].mi.pszName = NULL;
+ mainMenuItem[mainItemCount].mi.pszService = NULL;
+ mii.dwItemData = MENU_CUSTOMITEMMAIN | mainItemCount;
+ mii.hbmpItem = HBMMENU_CALLBACK;
+ mainItemCount++;
+ }
+ else {
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ mii.fMask = MIIM_SUBMENU | MIIM_TYPE;
+ }
+ mii.fType = MFT_STRING;
+ mii.hSubMenu = hMenu;
+ CallProtoService(proto[i]->szName, PS_GETNAME, SIZEOF(protoName), (LPARAM) protoName);
+ { TCHAR* ptszProtoName = LangPackPcharToTchar(protoName);
+ mii.dwTypeData = ptszProtoName;
+ InsertMenuItem(hStatusMenu, 0, TRUE, &mii);
+ free(ptszProtoName);
+ } }
+ statusFlags |= ( flags & ~moreflags );
+ }
+ for (i = 0; i < SIZEOF(statusModeList); i++)
+ if (!(statusFlags & statusModePf2List[i]))
+ DeleteMenu(hStatusMenu, statusModeList[i], MF_BYCOMMAND);
+ return 0;
+}
+
+static int MenuProtoAck(WPARAM wParam, LPARAM lParam)
+{
+ int protoCount, i, networkProtoCount;
+ PROTOCOLDESCRIPTOR **proto;
+ ACKDATA *ack = (ACKDATA *) lParam;
+ int overallStatus = 0, thisStatus;
+
+ if (ack->type != ACKTYPE_STATUS)
+ return 0;
+ if (ack->result != ACKRESULT_SUCCESS)
+ return 0;
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM) & protoCount, (LPARAM) & proto);
+ networkProtoCount = 0;
+ for (i = 0; i < protoCount; i++)
+ if (proto[i]->type == PROTOTYPE_PROTOCOL) {
+ thisStatus = CallProtoService(proto[i]->szName, PS_GETSTATUS, 0, 0);
+ if (overallStatus == 0)
+ overallStatus = thisStatus;
+ else if (overallStatus != thisStatus)
+ overallStatus = -1;
+ networkProtoCount++;
+ }
+ if (overallStatus > ID_STATUS_CONNECTING) {
+ CheckMenuItem(hStatusMenu, currentStatusMenuItem, MF_BYCOMMAND | MF_UNCHECKED);
+ currentStatusMenuItem = overallStatus;
+ CheckMenuItem(hStatusMenu, currentStatusMenuItem, MF_BYCOMMAND | MF_CHECKED);
+ SetMenuDefaultItem(hStatusMenu, currentStatusMenuItem, FALSE);
+ currentDesiredStatusMode = currentStatusMenuItem;
+ }
+ else {
+ CheckMenuItem(hStatusMenu, currentStatusMenuItem, MF_BYCOMMAND | MF_UNCHECKED);
+ SetMenuDefaultItem(hStatusMenu, -1, FALSE);
+ currentStatusMenuItem = 0;
+ }
+ if (networkProtoCount <= 1)
+ return 0;
+ for (i = 0; i < protoCount; i++)
+ if (!strcmp(proto[i]->szName, ack->szModule))
+ break;
+ //hProcess is previous mode, lParam is new mode
+ if ((int) ack->hProcess >= ID_STATUS_OFFLINE && (int) ack->hProcess < ID_STATUS_OFFLINE + SIZEOF(statusModeList))
+ CheckMenuItem(hStatusMenu, (i + 1) * SIZEOF(statusModeList) + (int) ack->hProcess, MF_BYCOMMAND | MF_UNCHECKED);
+ if (ack->lParam >= ID_STATUS_OFFLINE && ack->lParam < ID_STATUS_OFFLINE + SIZEOF(statusModeList))
+ CheckMenuItem(hStatusMenu, (i + 1) * SIZEOF(statusModeList) + ack->lParam, MF_BYCOMMAND | MF_CHECKED);
+ return 0;
+}
+
+static int MenuModulesShutdown(WPARAM wParam, LPARAM lParam)
+{
+ UnhookEvent(hAckHook);
+ return 0;
+}
+
+int InitCustomMenus(void)
+{
+ CreateServiceFunction(MS_CLIST_ADDMAINMENUITEM, AddMainMenuItem);
+ CreateServiceFunction(MS_CLIST_ADDCONTACTMENUITEM, AddContactMenuItem);
+ CreateServiceFunction(MS_CLIST_MODIFYMENUITEM, ModifyCustomMenuItem);
+ CreateServiceFunction(MS_CLIST_MENUMEASUREITEM, MeasureMenuItem);
+ CreateServiceFunction(MS_CLIST_MENUDRAWITEM, DrawMenuItem);
+ CreateServiceFunction(MS_CLIST_MENUBUILDCONTACT, BuildContactMenu);
+ CreateServiceFunction(MS_CLIST_MENUGETMAIN, MenuGetMain);
+ CreateServiceFunction(MS_CLIST_MENUGETSTATUS, MenuGetStatus);
+ CreateServiceFunction(MS_CLIST_MENUPROCESSCOMMAND, MenuProcessCommand);
+ CreateServiceFunction(MS_CLIST_MENUPROCESSHOTKEY, MenuProcessHotkey);
+ hPreBuildContactMenuEvent = CreateHookableEvent(ME_CLIST_PREBUILDCONTACTMENU);
+ hAckHook = (HANDLE) HookEvent(ME_PROTO_ACK, MenuProtoAck);
+ hRootMenu = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_CLISTMENU));
+ hMainMenu = GetSubMenu(hRootMenu, 0);
+ hStatusMenu = GetSubMenu(hRootMenu, 1);
+ CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) hMainMenu, 0);
+ CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) hStatusMenu, 0);
+ nextMenuId = FIRSTCUSTOMMENUITEMID;
+ mainMenuItem = contextMenuItem = NULL;
+ mainItemCount = contextItemCount = 0;
+ if (IsWinVerXPPlus()) //need 32-bit icons on XP for alpha channels
+ hImlMenuIcons = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR32 | ILC_MASK, 15, 100);
+ else //Win2k won't blend icons with imagelist_drawex when color-depth>16-bit. Don't know about WinME, but it certainly doesn't support alpha channels
+ hImlMenuIcons = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR16 | ILC_MASK, 15, 100);
+
+ currentStatusMenuItem = ID_STATUS_OFFLINE;
+ currentDesiredStatusMode = ID_STATUS_OFFLINE;
+ {
+ MENUITEMINFO mii;
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ mii.fMask = MIIM_STATE;
+ mii.fState = MFS_CHECKED | MFS_DEFAULT;
+ SetMenuItemInfo(hStatusMenu, currentStatusMenuItem, FALSE, &mii);
+ }
+
+ HookEvent(ME_SYSTEM_MODULESLOADED, MenuModulesLoaded);
+ HookEvent(ME_SYSTEM_SHUTDOWN, MenuModulesShutdown);
+ return 0;
+}
+
+void UninitCustomMenus(void)
+{
+ int i;
+
+ ImageList_Destroy(hImlMenuIcons);
+ for (i = 0; i < mainItemCount; i++) {
+ if (mainMenuItem[i].mi.pszName != NULL)
+ free(mainMenuItem[i].mi.pszName);
+ if (mainMenuItem[i].mi.pszService != NULL)
+ free(mainMenuItem[i].mi.pszService);
+ }
+ for (i = 0; i < contextItemCount; i++) {
+ if (contextMenuItem[i].mi.pszName != NULL)
+ free(contextMenuItem[i].mi.pszName);
+ if (contextMenuItem[i].mi.pszService != NULL)
+ free(contextMenuItem[i].mi.pszService);
+ if (contextMenuItem[i].mi.pszContactOwner != NULL)
+ free(contextMenuItem[i].mi.pszContactOwner);
+ }
+ free(mainMenuItem);
+ free(contextMenuItem);
+ DestroyMenu(hStatusMenu);
+ DestroyMenu(hMainMenu);
+ DestroyMenu(hRootMenu);
+}
diff --git a/miranda-wine/plugins/clist/clistopts.c b/miranda-wine/plugins/clist/clistopts.c
new file mode 100644
index 0000000..7db1efa
--- /dev/null
+++ b/miranda-wine/plugins/clist/clistopts.c
@@ -0,0 +1,353 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+static BOOL CALLBACK DlgProcGenOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_USER + 1:
+ {
+ HANDLE hContact = (HANDLE) wParam;
+ DBCONTACTWRITESETTING *ws = (DBCONTACTWRITESETTING *) lParam;
+ if (hContact == NULL && ws != NULL && ws->szModule != NULL && ws->szSetting != NULL
+ && lstrcmpiA(ws->szModule, "CList") == 0 && lstrcmpiA(ws->szSetting, "UseGroups") == 0 && IsWindowVisible(hwndDlg)) {
+ CheckDlgButton(hwndDlg, IDC_DISABLEGROUPS, ws->value.bVal == 0);
+ }
+ break;
+ }
+ case WM_DESTROY:
+ {
+ UnhookEvent((HANDLE) GetWindowLong(hwndDlg, GWL_USERDATA));
+ break;
+ }
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLong(hwndDlg, GWL_USERDATA, (LONG) HookEventMessage(ME_DB_CONTACT_SETTINGCHANGED, hwndDlg, WM_USER + 1));
+ CheckDlgButton(hwndDlg, IDC_ONTOP, DBGetContactSettingByte(NULL, "CList", "OnTop", SETTING_ONTOP_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_HIDEOFFLINE,
+ DBGetContactSettingByte(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_HIDEEMPTYGROUPS,
+ DBGetContactSettingByte(NULL, "CList", "HideEmptyGroups", SETTING_HIDEEMPTYGROUPS_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_DISABLEGROUPS,
+ DBGetContactSettingByte(NULL, "CList", "UseGroups", SETTING_USEGROUPS_DEFAULT) ? BST_UNCHECKED : BST_CHECKED);
+ CheckDlgButton(hwndDlg, IDC_SORTBYNAME, !DBGetContactSettingByte(NULL, "CList", "SortByStatus", SETTING_SORTBYSTATUS_DEFAULT)
+ && !DBGetContactSettingByte(NULL, "CList", "SortByProto", SETTING_SORTBYPROTO_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SORTBYSTATUS,
+ DBGetContactSettingByte(NULL, "CList", "SortByStatus", SETTING_SORTBYSTATUS_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SORTBYPROTO,
+ DBGetContactSettingByte(NULL, "CList", "SortByProto", SETTING_SORTBYPROTO_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_CONFIRMDELETE,
+ DBGetContactSettingByte(NULL, "CList", "ConfirmDelete", SETTING_CONFIRMDELETE_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_AUTOHIDE,
+ DBGetContactSettingByte(NULL, "CList", "AutoHide", SETTING_AUTOHIDE_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_HIDETIME), IsDlgButtonChecked(hwndDlg, IDC_AUTOHIDE));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_HIDETIMESPIN), IsDlgButtonChecked(hwndDlg, IDC_AUTOHIDE));
+ {
+ DWORD caps = CallService(MS_CLUI_GETCAPS, CLUICAPS_FLAGS1, 0);
+ if (!(caps & CLUIF_HIDEEMPTYGROUPS))
+ ShowWindow(GetDlgItem(hwndDlg, IDC_HIDEEMPTYGROUPS), SW_HIDE);
+ if (!(caps & CLUIF_DISABLEGROUPS))
+ ShowWindow(GetDlgItem(hwndDlg, IDC_DISABLEGROUPS), SW_HIDE);
+ if (caps & CLUIF_HASONTOPOPTION)
+ ShowWindow(GetDlgItem(hwndDlg, IDC_ONTOP), SW_HIDE);
+ if (caps & CLUIF_HASAUTOHIDEOPTION) {
+ ShowWindow(GetDlgItem(hwndDlg, IDC_AUTOHIDE), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_HIDETIME), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_HIDETIMESPIN), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_STAUTOHIDESECS), SW_HIDE);
+ }
+ }
+ SendDlgItemMessage(hwndDlg, IDC_HIDETIMESPIN, UDM_SETRANGE, 0, MAKELONG(900, 1));
+ SendDlgItemMessage(hwndDlg, IDC_HIDETIMESPIN, UDM_SETPOS, 0,
+ MAKELONG(DBGetContactSettingWord(NULL, "CList", "HideTime", SETTING_HIDETIME_DEFAULT), 0));
+ CheckDlgButton(hwndDlg, IDC_ONECLK,
+ DBGetContactSettingByte(NULL, "CList", "Tray1Click", SETTING_TRAY1CLICK_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_ALWAYSSTATUS,
+ DBGetContactSettingByte(NULL, "CList", "AlwaysStatus", SETTING_ALWAYSSTATUS_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_ALWAYSMULTI,
+ !DBGetContactSettingByte(NULL, "CList", "AlwaysMulti", SETTING_ALWAYSMULTI_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_DONTCYCLE,
+ DBGetContactSettingByte(NULL, "CList", "TrayIcon",
+ SETTING_TRAYICON_DEFAULT) == SETTING_TRAYICON_SINGLE ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_CYCLE,
+ DBGetContactSettingByte(NULL, "CList", "TrayIcon",
+ SETTING_TRAYICON_DEFAULT) == SETTING_TRAYICON_CYCLE ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_MULTITRAY,
+ DBGetContactSettingByte(NULL, "CList", "TrayIcon",
+ SETTING_TRAYICON_DEFAULT) == SETTING_TRAYICON_MULTI ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_DISABLEBLINK,
+ DBGetContactSettingByte(NULL, "CList", "DisableTrayFlash", 0) == 1 ? BST_CHECKED : BST_UNCHECKED);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BLINKTIME), !IsDlgButtonChecked(hwndDlg, IDC_DISABLEBLINK));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BLINKSPIN), !IsDlgButtonChecked(hwndDlg, IDC_DISABLEBLINK));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_STMSDELAY), !IsDlgButtonChecked(hwndDlg, IDC_DISABLEBLINK));
+ CheckDlgButton(hwndDlg, IDC_ICONBLINK, DBGetContactSettingByte(NULL, "CList", "NoIconBlink", 0) == 1 ? BST_CHECKED : BST_UNCHECKED);
+ if (IsDlgButtonChecked(hwndDlg, IDC_DONTCYCLE)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CYCLETIMESPIN), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CYCLETIME), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALWAYSMULTI), FALSE);
+ }
+ if (IsDlgButtonChecked(hwndDlg, IDC_CYCLE)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_PRIMARYSTATUS), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALWAYSMULTI), FALSE);
+ }
+ if (IsDlgButtonChecked(hwndDlg, IDC_MULTITRAY)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CYCLETIMESPIN), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CYCLETIME), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_PRIMARYSTATUS), FALSE);
+ }
+ SendDlgItemMessage(hwndDlg, IDC_CYCLETIMESPIN, UDM_SETRANGE, 0, MAKELONG(120, 1));
+ SendDlgItemMessage(hwndDlg, IDC_CYCLETIMESPIN, UDM_SETPOS, 0,
+ MAKELONG(DBGetContactSettingWord(NULL, "CList", "CycleTime", SETTING_CYCLETIME_DEFAULT), 0));
+ {
+ int i, count, item;
+ PROTOCOLDESCRIPTOR **protos;
+ char szName[64];
+ DBVARIANT dbv = { DBVT_DELETED };
+ DBGetContactSetting(NULL, "CList", "PrimaryStatus", &dbv);
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM) & count, (LPARAM) & protos);
+ item = SendDlgItemMessage(hwndDlg, IDC_PRIMARYSTATUS, CB_ADDSTRING, 0, (LPARAM) TranslateT("Global"));
+ SendDlgItemMessage(hwndDlg, IDC_PRIMARYSTATUS, CB_SETITEMDATA, item, (LPARAM) 0);
+ for (i = 0; i < count; i++) {
+ if (protos[i]->type != PROTOTYPE_PROTOCOL || CallProtoService(protos[i]->szName, PS_GETCAPS, PFLAGNUM_2, 0) == 0)
+ continue;
+ CallProtoService(protos[i]->szName, PS_GETNAME, SIZEOF(szName), (LPARAM) szName);
+ item = SendDlgItemMessageA(hwndDlg, IDC_PRIMARYSTATUS, CB_ADDSTRING, 0, (LPARAM) szName);
+ SendDlgItemMessage(hwndDlg, IDC_PRIMARYSTATUS, CB_SETITEMDATA, item, (LPARAM) protos[i]);
+ if (dbv.type == DBVT_ASCIIZ && !lstrcmpA(dbv.pszVal, protos[i]->szName))
+ SendDlgItemMessage(hwndDlg, IDC_PRIMARYSTATUS, CB_SETCURSEL, item, 0);
+ }
+ DBFreeVariant(&dbv);
+ }
+ if (-1 == (int) SendDlgItemMessage(hwndDlg, IDC_PRIMARYSTATUS, CB_GETCURSEL, 0, 0))
+ SendDlgItemMessage(hwndDlg, IDC_PRIMARYSTATUS, CB_SETCURSEL, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_BLINKSPIN, UDM_SETBUDDY, (WPARAM) GetDlgItem(hwndDlg, IDC_BLINKTIME), 0); // set buddy
+ SendDlgItemMessage(hwndDlg, IDC_BLINKSPIN, UDM_SETRANGE, 0, MAKELONG(0x3FFF, 250));
+ SendDlgItemMessage(hwndDlg, IDC_BLINKSPIN, UDM_SETPOS, 0, MAKELONG(DBGetContactSettingWord(NULL, "CList", "IconFlashTime", 550), 0));
+ return TRUE;
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDC_AUTOHIDE) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_HIDETIME), IsDlgButtonChecked(hwndDlg, IDC_AUTOHIDE));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_HIDETIMESPIN), IsDlgButtonChecked(hwndDlg, IDC_AUTOHIDE));
+ }
+ if (LOWORD(wParam) == IDC_DONTCYCLE || LOWORD(wParam) == IDC_CYCLE || LOWORD(wParam) == IDC_MULTITRAY) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_PRIMARYSTATUS), IsDlgButtonChecked(hwndDlg, IDC_DONTCYCLE));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CYCLETIME), IsDlgButtonChecked(hwndDlg, IDC_CYCLE));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CYCLETIMESPIN), IsDlgButtonChecked(hwndDlg, IDC_CYCLE));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALWAYSMULTI), IsDlgButtonChecked(hwndDlg, IDC_MULTITRAY));
+ }
+ if (LOWORD(wParam) == IDC_DISABLEBLINK) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BLINKTIME), !IsDlgButtonChecked(hwndDlg, IDC_DISABLEBLINK));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BLINKSPIN), !IsDlgButtonChecked(hwndDlg, IDC_DISABLEBLINK));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_STMSDELAY), !IsDlgButtonChecked(hwndDlg, IDC_DISABLEBLINK));
+ }
+ if ((LOWORD(wParam) == IDC_HIDETIME || LOWORD(wParam) == IDC_CYCLETIME) && HIWORD(wParam) != EN_CHANGE)
+ break;
+ if (LOWORD(wParam) == IDC_PRIMARYSTATUS && HIWORD(wParam) != CBN_SELCHANGE)
+ break;
+ if ((LOWORD(wParam) == IDC_HIDETIME || LOWORD(wParam) == IDC_CYCLETIME) && (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus()))
+ return 0;
+ if (LOWORD(wParam) == IDC_BLINKTIME && HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus())
+ return 0; // dont make apply enabled during buddy set crap
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch (((LPNMHDR) lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR) lParam)->code) {
+ case PSN_APPLY:
+ DBWriteContactSettingByte(NULL, "CList", "HideOffline", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_HIDEOFFLINE));
+ {
+ DWORD caps = CallService(MS_CLUI_GETCAPS, CLUICAPS_FLAGS1, 0);
+ if (caps & CLUIF_HIDEEMPTYGROUPS)
+ DBWriteContactSettingByte(NULL, "CList", "HideEmptyGroups",
+ (BYTE) IsDlgButtonChecked(hwndDlg, IDC_HIDEEMPTYGROUPS));
+ if (caps & CLUIF_DISABLEGROUPS)
+ DBWriteContactSettingByte(NULL, "CList", "UseGroups", (BYTE) ! IsDlgButtonChecked(hwndDlg, IDC_DISABLEGROUPS));
+ if (!(caps & CLUIF_HASONTOPOPTION)) {
+ DBWriteContactSettingByte(NULL, "CList", "OnTop", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_ONTOP));
+ SetWindowPos((HWND) CallService(MS_CLUI_GETHWND, 0, 0),
+ IsDlgButtonChecked(hwndDlg, IDC_ONTOP) ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE);
+ }
+ if (!(caps & CLUIF_HASAUTOHIDEOPTION)) {
+ DBWriteContactSettingByte(NULL, "CList", "AutoHide", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_AUTOHIDE));
+ DBWriteContactSettingWord(NULL, "CList", "HideTime",
+ (WORD) SendDlgItemMessage(hwndDlg, IDC_HIDETIMESPIN, UDM_GETPOS, 0, 0));
+ }
+ }
+ DBWriteContactSettingByte(NULL, "CList", "SortByStatus", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SORTBYSTATUS));
+ DBWriteContactSettingByte(NULL, "CList", "SortByProto", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SORTBYPROTO));
+ DBWriteContactSettingByte(NULL, "CList", "ConfirmDelete", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_CONFIRMDELETE));
+ DBWriteContactSettingByte(NULL, "CList", "Tray1Click", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_ONECLK));
+ DBWriteContactSettingByte(NULL, "CList", "AlwaysStatus", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_ALWAYSSTATUS));
+ DBWriteContactSettingByte(NULL, "CList", "AlwaysMulti", (BYTE) ! IsDlgButtonChecked(hwndDlg, IDC_ALWAYSMULTI));
+ DBWriteContactSettingByte(NULL, "CList", "TrayIcon",
+ (BYTE) (IsDlgButtonChecked(hwndDlg, IDC_DONTCYCLE) ? SETTING_TRAYICON_SINGLE
+ : (IsDlgButtonChecked(hwndDlg, IDC_CYCLE) ? SETTING_TRAYICON_CYCLE :
+ SETTING_TRAYICON_MULTI)));
+ DBWriteContactSettingWord(NULL, "CList", "CycleTime",
+ (WORD) SendDlgItemMessage(hwndDlg, IDC_CYCLETIMESPIN, UDM_GETPOS, 0, 0));
+ DBWriteContactSettingWord(NULL, "CList", "IconFlashTime",
+ (WORD) SendDlgItemMessage(hwndDlg, IDC_BLINKSPIN, UDM_GETPOS, 0, 0));
+ DBWriteContactSettingByte(NULL, "CList", "DisableTrayFlash", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_DISABLEBLINK));
+ DBWriteContactSettingByte(NULL, "CList", "NoIconBlink", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_ICONBLINK));
+ if (!SendDlgItemMessage
+ (hwndDlg, IDC_PRIMARYSTATUS, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, IDC_PRIMARYSTATUS, CB_GETCURSEL, 0, 0), 0))
+ DBDeleteContactSetting(NULL, "CList", "PrimaryStatus");
+ else
+ DBWriteContactSettingString(NULL, "CList", "PrimaryStatus",
+ ((PROTOCOLDESCRIPTOR *)
+ SendDlgItemMessage(hwndDlg, IDC_PRIMARYSTATUS, CB_GETITEMDATA,
+ SendDlgItemMessage(hwndDlg, IDC_PRIMARYSTATUS, CB_GETCURSEL, 0, 0),
+ 0))->szName);
+ pcli->pfnTrayIconIconsChanged();
+ pcli->pfnLoadContactTree(); /* this won't do job properly since it only really works when changes happen */
+ pcli->pfnInvalidateDisplayNameCacheEntry( INVALID_HANDLE_VALUE ); /* force reshuffle */
+ return TRUE;
+ }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK DlgProcHotkeyOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ DBVARIANT dbv;
+
+ TranslateDialogDefault(hwndDlg);
+
+ CheckDlgButton(hwndDlg, IDC_SHOWHIDE, DBGetContactSettingByte(NULL, "CList", "HKEnShowHide", 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_READMSG, DBGetContactSettingByte(NULL, "CList", "HKEnReadMsg", 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_NETSEARCH, DBGetContactSettingByte(NULL, "CList", "HKEnNetSearch", 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SHOWOPTIONS, DBGetContactSettingByte(NULL, "CList", "HKEnShowOptions", 0) ? BST_CHECKED : BST_UNCHECKED);
+
+ EnableWindow(GetDlgItem(hwndDlg, IDC_HKSHOWHIDE), IsDlgButtonChecked(hwndDlg, IDC_SHOWHIDE));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_HKREADMSG), IsDlgButtonChecked(hwndDlg, IDC_READMSG));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_HKSEARCH), IsDlgButtonChecked(hwndDlg, IDC_NETSEARCH));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SEARCHURL), IsDlgButtonChecked(hwndDlg, IDC_NETSEARCH));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SEARCHNEWWND), IsDlgButtonChecked(hwndDlg, IDC_NETSEARCH));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_HOTKEYURLSTR), IsDlgButtonChecked(hwndDlg, IDC_NETSEARCH));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_HKSHOWOPTIONS), IsDlgButtonChecked(hwndDlg, IDC_SHOWOPTIONS));
+
+ SendDlgItemMessage(hwndDlg, IDC_HKSHOWHIDE, HKM_SETHOTKEY,
+ DBGetContactSettingWord(NULL, "CList", "HKShowHide", MAKEWORD('A', HOTKEYF_CONTROL | HOTKEYF_SHIFT)), 0);
+ SendDlgItemMessage(hwndDlg, IDC_HKREADMSG, HKM_SETHOTKEY,
+ DBGetContactSettingWord(NULL, "CList", "HKReadMsg", MAKEWORD('I', HOTKEYF_CONTROL | HOTKEYF_SHIFT)), 0);
+ SendDlgItemMessage(hwndDlg, IDC_HKSEARCH, HKM_SETHOTKEY,
+ DBGetContactSettingWord(NULL, "CList", "HKNetSearch", MAKEWORD('S', HOTKEYF_CONTROL | HOTKEYF_SHIFT)), 0);
+ SendDlgItemMessage(hwndDlg, IDC_HKSHOWOPTIONS, HKM_SETHOTKEY,
+ DBGetContactSettingWord(NULL, "CList", "HKShowOptions", MAKEWORD('O', HOTKEYF_CONTROL | HOTKEYF_SHIFT)), 0);
+ if (!DBGetContactSetting(NULL, "CList", "SearchUrl", &dbv)) {
+ SetDlgItemTextA(hwndDlg, IDC_SEARCHURL, dbv.pszVal);
+ mir_free(dbv.pszVal);
+ }
+ else
+ SetDlgItemTextA(hwndDlg, IDC_SEARCHURL, "http://www.google.com/");
+ CheckDlgButton(hwndDlg, IDC_SEARCHNEWWND, DBGetContactSettingByte(NULL, "CList", "HKSearchNewWnd", 0) ? BST_CHECKED : BST_UNCHECKED);
+ return TRUE;
+ }
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDC_SEARCHURL && (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus()))
+ return 0;
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ switch (LOWORD(wParam)) {
+ case IDC_SHOWHIDE:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_HKSHOWHIDE), IsDlgButtonChecked(hwndDlg, IDC_SHOWHIDE));
+ break;
+ case IDC_READMSG:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_HKREADMSG), IsDlgButtonChecked(hwndDlg, IDC_READMSG));
+ break;
+ case IDC_NETSEARCH:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_HKSEARCH), IsDlgButtonChecked(hwndDlg, IDC_NETSEARCH));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SEARCHURL), IsDlgButtonChecked(hwndDlg, IDC_NETSEARCH));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SEARCHNEWWND), IsDlgButtonChecked(hwndDlg, IDC_NETSEARCH));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_HOTKEYURLSTR), IsDlgButtonChecked(hwndDlg, IDC_NETSEARCH));
+ break;
+ case IDC_SHOWOPTIONS:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_HKSHOWOPTIONS), IsDlgButtonChecked(hwndDlg, IDC_SHOWOPTIONS));
+ break;
+ }
+ break;
+ case WM_NOTIFY:
+ switch (((LPNMHDR) lParam)->code) {
+ case PSN_APPLY:
+ {
+ char str[256];
+ pcli->pfnHotKeysUnregister((HWND) CallService(MS_CLUI_GETHWND, 0, 0));
+ DBWriteContactSettingByte(NULL, "CList", "HKEnShowHide", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SHOWHIDE));
+ DBWriteContactSettingWord(NULL, "CList", "HKShowHide", (WORD) SendDlgItemMessage(hwndDlg, IDC_HKSHOWHIDE, HKM_GETHOTKEY, 0, 0));
+ DBWriteContactSettingByte(NULL, "CList", "HKEnReadMsg", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_READMSG));
+ DBWriteContactSettingWord(NULL, "CList", "HKReadMsg", (WORD) SendDlgItemMessage(hwndDlg, IDC_HKREADMSG, HKM_GETHOTKEY, 0, 0));
+ DBWriteContactSettingByte(NULL, "CList", "HKEnNetSearch", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_NETSEARCH));
+ DBWriteContactSettingWord(NULL, "CList", "HKNetSearch", (WORD) SendDlgItemMessage(hwndDlg, IDC_HKSEARCH, HKM_GETHOTKEY, 0, 0));
+ GetDlgItemTextA(hwndDlg, IDC_SEARCHURL, str, SIZEOF(str));
+ DBWriteContactSettingString(NULL, "CList", "SearchUrl", str);
+ DBWriteContactSettingByte(NULL, "CList", "HKSearchNewWnd", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SEARCHNEWWND));
+ DBWriteContactSettingByte(NULL, "CList", "HKEnShowOptions", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SHOWOPTIONS));
+ DBWriteContactSettingWord(NULL, "CList", "HKShowOptions", (WORD) SendDlgItemMessage(hwndDlg, IDC_HKSHOWOPTIONS, HKM_GETHOTKEY, 0, 0));
+ pcli->pfnHotKeysRegister((HWND) CallService(MS_CLUI_GETHWND, 0, 0));
+ return TRUE;
+ }
+ }
+ break;
+ }
+ return FALSE;
+}
+
+/****************************************************************************************/
+
+static UINT expertOnlyControls[] = { IDC_ALWAYSSTATUS };
+
+int CListOptInit(WPARAM wParam, LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp;
+
+ ZeroMemory(&odp, sizeof(odp));
+ odp.cbSize = sizeof(odp);
+ odp.position = -1000000000;
+ odp.hInstance = g_hInst;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_CLIST);
+ odp.pszTitle = "Contact List";
+ odp.pfnDlgProc = DlgProcGenOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.nIDBottomSimpleControl = IDC_STCLISTGROUP;
+ odp.expertOnlyControls = expertOnlyControls;
+ odp.nExpertOnlyControls = SIZEOF(expertOnlyControls);
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) & odp);
+
+ odp.position = -900000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_HOTKEY);
+ odp.pszTitle = "Hotkeys";
+ odp.pszGroup = "Events";
+ odp.pfnDlgProc = DlgProcHotkeyOpts;
+ odp.nIDBottomSimpleControl = 0;
+ odp.nExpertOnlyControls = 0;
+ odp.expertOnlyControls = NULL;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) & odp);
+ return 0;
+}
diff --git a/miranda-wine/plugins/clist/cluiopts.c b/miranda-wine/plugins/clist/cluiopts.c
new file mode 100644
index 0000000..588d3b1
--- /dev/null
+++ b/miranda-wine/plugins/clist/cluiopts.c
@@ -0,0 +1,346 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+extern BOOL(WINAPI * MySetLayeredWindowAttributes) (HWND, COLORREF, BYTE, DWORD);
+
+static BOOL CALLBACK DlgProcCluiOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ CheckDlgButton(hwndDlg, IDC_BRINGTOFRONT,
+ DBGetContactSettingByte(NULL, "CList", "BringToFront", SETTING_BRINGTOFRONT_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_ONTOP, DBGetContactSettingByte(NULL, "CList", "OnTop", SETTING_ONTOP_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_TOOLWND,
+ DBGetContactSettingByte(NULL, "CList", "ToolWindow", SETTING_TOOLWINDOW_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_MIN2TRAY,
+ DBGetContactSettingByte(NULL, "CList", "Min2Tray", SETTING_MIN2TRAY_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ if (IsDlgButtonChecked(hwndDlg, IDC_TOOLWND))
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MIN2TRAY), FALSE);
+ CheckDlgButton(hwndDlg, IDC_SHOWCAPTION,
+ DBGetContactSettingByte(NULL, "CLUI", "ShowCaption", SETTING_SHOWCAPTION_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SHOWMAINMENU,
+ DBGetContactSettingByte(NULL, "CLUI", "ShowMainMenu", SETTING_SHOWMAINMENU_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_CLIENTDRAG,
+ DBGetContactSettingByte(NULL, "CLUI", "ClientAreaDrag", SETTING_CLIENTDRAG_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ if (!IsDlgButtonChecked(hwndDlg, IDC_SHOWCAPTION)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MIN2TRAY), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_TOOLWND), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_TITLETEXT), FALSE);
+ }
+ CheckDlgButton(hwndDlg, IDC_FADEINOUT, DBGetContactSettingByte(NULL, "CLUI", "FadeInOut", 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_AUTOSIZE, DBGetContactSettingByte(NULL, "CLUI", "AutoSize", 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_DROPSHADOW, DBGetContactSettingByte(NULL, "CList", "WindowShadow", 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_ONDESKTOP, DBGetContactSettingByte(NULL, "CList", "OnDesktop", 0) ? BST_CHECKED : BST_UNCHECKED);
+ SendDlgItemMessage(hwndDlg, IDC_MAXSIZESPIN, UDM_SETRANGE, 0, MAKELONG(100, 0));
+ SendDlgItemMessage(hwndDlg, IDC_MAXSIZESPIN, UDM_SETPOS, 0, DBGetContactSettingByte(NULL, "CLUI", "MaxSizeHeight", 75));
+ CheckDlgButton(hwndDlg, IDC_AUTOSIZEUPWARD, DBGetContactSettingByte(NULL, "CLUI", "AutoSizeUpward", 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_AUTOHIDE,
+ DBGetContactSettingByte(NULL, "CList", "AutoHide", SETTING_AUTOHIDE_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ SendDlgItemMessage(hwndDlg, IDC_HIDETIMESPIN, UDM_SETRANGE, 0, MAKELONG(900, 1));
+ SendDlgItemMessage(hwndDlg, IDC_HIDETIMESPIN, UDM_SETPOS, 0,
+ MAKELONG(DBGetContactSettingWord(NULL, "CList", "HideTime", SETTING_HIDETIME_DEFAULT), 0));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_HIDETIME), IsDlgButtonChecked(hwndDlg, IDC_AUTOHIDE));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_HIDETIMESPIN), IsDlgButtonChecked(hwndDlg, IDC_AUTOHIDE));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_STATIC01), IsDlgButtonChecked(hwndDlg, IDC_AUTOHIDE));
+ if (!IsDlgButtonChecked(hwndDlg, IDC_AUTOSIZE)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_STATIC21), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_STATIC22), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MAXSIZEHEIGHT), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MAXSIZESPIN), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_AUTOSIZEUPWARD), FALSE);
+ }
+
+ { DBVARIANT dbv;
+ if ( !DBGetContactSettingTString(NULL, "CList", "TitleText", &dbv)) {
+ SetDlgItemText(hwndDlg, IDC_TITLETEXT, dbv.ptszVal);
+ DBFreeVariant( &dbv );
+ }
+ else SetDlgItemTextA(hwndDlg, IDC_TITLETEXT, MIRANDANAME);
+ }
+ if (!IsWinVer2000Plus()) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FADEINOUT), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_TRANSPARENT), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_DROPSHADOW), FALSE);
+ }
+ else
+ CheckDlgButton(hwndDlg, IDC_TRANSPARENT,
+ DBGetContactSettingByte(NULL, "CList", "Transparent", SETTING_TRANSPARENT_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+
+ if (!IsDlgButtonChecked(hwndDlg, IDC_TRANSPARENT)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_STATIC11), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_STATIC12), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_TRANSACTIVE), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_TRANSINACTIVE), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ACTIVEPERC), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_INACTIVEPERC), FALSE);
+ }
+ SendDlgItemMessage(hwndDlg, IDC_TRANSACTIVE, TBM_SETRANGE, FALSE, MAKELONG(1, 255));
+ SendDlgItemMessage(hwndDlg, IDC_TRANSINACTIVE, TBM_SETRANGE, FALSE, MAKELONG(1, 255));
+ SendDlgItemMessage(hwndDlg, IDC_TRANSACTIVE, TBM_SETPOS, TRUE, DBGetContactSettingByte(NULL, "CList", "Alpha", SETTING_ALPHA_DEFAULT));
+ SendDlgItemMessage(hwndDlg, IDC_TRANSINACTIVE, TBM_SETPOS, TRUE,
+ DBGetContactSettingByte(NULL, "CList", "AutoAlpha", SETTING_AUTOALPHA_DEFAULT));
+ SendMessage(hwndDlg, WM_HSCROLL, 0x12345678, 0);
+ return TRUE;
+
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDC_AUTOHIDE) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_HIDETIME), IsDlgButtonChecked(hwndDlg, IDC_AUTOHIDE));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_HIDETIMESPIN), IsDlgButtonChecked(hwndDlg, IDC_AUTOHIDE));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_STATIC01), IsDlgButtonChecked(hwndDlg, IDC_AUTOHIDE));
+ }
+ else if (LOWORD(wParam) == IDC_TRANSPARENT) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_STATIC11), IsDlgButtonChecked(hwndDlg, IDC_TRANSPARENT));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_STATIC12), IsDlgButtonChecked(hwndDlg, IDC_TRANSPARENT));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_TRANSACTIVE), IsDlgButtonChecked(hwndDlg, IDC_TRANSPARENT));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_TRANSINACTIVE), IsDlgButtonChecked(hwndDlg, IDC_TRANSPARENT));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ACTIVEPERC), IsDlgButtonChecked(hwndDlg, IDC_TRANSPARENT));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_INACTIVEPERC), IsDlgButtonChecked(hwndDlg, IDC_TRANSPARENT));
+ }
+ else if (LOWORD(wParam) == IDC_AUTOSIZE) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_STATIC21), IsDlgButtonChecked(hwndDlg, IDC_AUTOSIZE));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_STATIC22), IsDlgButtonChecked(hwndDlg, IDC_AUTOSIZE));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MAXSIZEHEIGHT), IsDlgButtonChecked(hwndDlg, IDC_AUTOSIZE));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MAXSIZESPIN), IsDlgButtonChecked(hwndDlg, IDC_AUTOSIZE));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_AUTOSIZEUPWARD), IsDlgButtonChecked(hwndDlg, IDC_AUTOSIZE));
+ }
+ else if (LOWORD(wParam) == IDC_TOOLWND) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MIN2TRAY), !IsDlgButtonChecked(hwndDlg, IDC_TOOLWND));
+ }
+ else if (LOWORD(wParam) == IDC_SHOWCAPTION) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_TOOLWND), IsDlgButtonChecked(hwndDlg, IDC_SHOWCAPTION));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MIN2TRAY), !IsDlgButtonChecked(hwndDlg, IDC_TOOLWND)
+ && IsDlgButtonChecked(hwndDlg, IDC_SHOWCAPTION));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_TITLETEXT), IsDlgButtonChecked(hwndDlg, IDC_SHOWCAPTION));
+ }
+
+ if ((LOWORD(wParam) == IDC_HIDETIME || LOWORD(wParam) == IDC_TITLETEXT || LOWORD(wParam) == IDC_MAXSIZEHEIGHT) &&
+ (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus()))
+ return 0;
+
+ // Enable apply button
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case WM_HSCROLL:
+ {
+ char str[10];
+ wsprintfA(str, "%d%%", 100 * SendDlgItemMessage(hwndDlg, IDC_TRANSINACTIVE, TBM_GETPOS, 0, 0) / 255);
+ SetDlgItemTextA(hwndDlg, IDC_INACTIVEPERC, str);
+ wsprintfA(str, "%d%%", 100 * SendDlgItemMessage(hwndDlg, IDC_TRANSACTIVE, TBM_GETPOS, 0, 0) / 255);
+ SetDlgItemTextA(hwndDlg, IDC_ACTIVEPERC, str);
+ }
+ if (wParam != 0x12345678)
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ if (((LPNMHDR) lParam)->code == PSN_APPLY) {
+ DBWriteContactSettingByte(NULL, "CList", "OnTop", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_ONTOP));
+ DBWriteContactSettingByte(NULL, "CList", "ToolWindow", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_TOOLWND));
+ DBWriteContactSettingByte(NULL, "CList", "BringToFront", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_BRINGTOFRONT));
+ DBWriteContactSettingByte(NULL, "CLUI", "FadeInOut", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_FADEINOUT));
+ DBWriteContactSettingByte(NULL, "CLUI", "AutoSize", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_AUTOSIZE));
+ DBWriteContactSettingByte(NULL, "CLUI", "MaxSizeHeight", (BYTE) GetDlgItemInt(hwndDlg, IDC_MAXSIZEHEIGHT, NULL, FALSE));
+ DBWriteContactSettingByte(NULL, "CLUI", "AutoSizeUpward", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_AUTOSIZEUPWARD));
+ DBWriteContactSettingByte(NULL, "CList", "AutoHide", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_AUTOHIDE));
+ DBWriteContactSettingWord(NULL, "CList", "HideTime", (WORD) SendDlgItemMessage(hwndDlg, IDC_HIDETIMESPIN, UDM_GETPOS, 0, 0));
+ DBWriteContactSettingByte(NULL, "CList", "Transparent", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_TRANSPARENT));
+ DBWriteContactSettingByte(NULL, "CList", "Alpha", (BYTE) SendDlgItemMessage(hwndDlg, IDC_TRANSACTIVE, TBM_GETPOS, 0, 0));
+ DBWriteContactSettingByte(NULL, "CList", "AutoAlpha", (BYTE) SendDlgItemMessage(hwndDlg, IDC_TRANSINACTIVE, TBM_GETPOS, 0, 0));
+ DBWriteContactSettingByte(NULL, "CList", "WindowShadow", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_DROPSHADOW));
+ DBWriteContactSettingByte(NULL, "CList", "OnDesktop", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_ONDESKTOP));
+ DBWriteContactSettingByte(NULL, "CLUI", "ShowCaption", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SHOWCAPTION));
+ DBWriteContactSettingByte(NULL, "CLUI", "ShowMainMenu", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SHOWMAINMENU));
+ DBWriteContactSettingByte(NULL, "CLUI", "ClientAreaDrag", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_CLIENTDRAG));
+ DBWriteContactSettingByte(NULL, "CList", "Min2Tray", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_MIN2TRAY));
+ {
+ TCHAR title[256];
+ GetDlgItemText(hwndDlg, IDC_TITLETEXT, title, SIZEOF(title));
+ DBWriteContactSettingTString(NULL, "CList", "TitleText", title);
+ SetWindowText(pcli->hwndContactList, title);
+ }
+ pcli->pfnLoadCluiGlobalOpts();
+ SetWindowPos(pcli->hwndContactList, IsDlgButtonChecked(hwndDlg, IDC_ONTOP) ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE);
+ if (IsDlgButtonChecked(hwndDlg, IDC_TOOLWND)) {
+ // Window must be hidden to dynamically remove the taskbar button.
+ // See http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_int/shell_int_programming/taskbar.asp
+ WINDOWPLACEMENT p;
+ p.length = sizeof(p);
+ GetWindowPlacement(pcli->hwndContactList, &p);
+ ShowWindow(pcli->hwndContactList, SW_HIDE);
+ SetWindowLong(pcli->hwndContactList, GWL_EXSTYLE,
+ GetWindowLong(pcli->hwndContactList, GWL_EXSTYLE) | WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE);
+ SetWindowPlacement(pcli->hwndContactList, &p);
+ }
+ else SetWindowLong(pcli->hwndContactList, GWL_EXSTYLE, GetWindowLong(pcli->hwndContactList, GWL_EXSTYLE) & ~WS_EX_TOOLWINDOW);
+
+ if (IsDlgButtonChecked(hwndDlg, IDC_ONDESKTOP)) {
+ HWND hProgMan = FindWindowA("Progman", NULL);
+ if (IsWindow(hProgMan))
+ SetParent(pcli->hwndContactList, hProgMan);
+ }
+ else SetParent(pcli->hwndContactList, NULL);
+
+ if (IsDlgButtonChecked(hwndDlg, IDC_SHOWCAPTION))
+ SetWindowLong(pcli->hwndContactList, GWL_STYLE,
+ GetWindowLong(pcli->hwndContactList, GWL_STYLE) | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX);
+ else
+ SetWindowLong(pcli->hwndContactList, GWL_STYLE,
+ GetWindowLong(pcli->hwndContactList, GWL_STYLE) & ~(WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX));
+ if (!IsDlgButtonChecked(hwndDlg, IDC_SHOWMAINMENU))
+ SetMenu(pcli->hwndContactList, NULL);
+ else
+ SetMenu(pcli->hwndContactList, pcli->hMenuMain);
+ SetWindowPos(pcli->hwndContactList, 0, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
+ RedrawWindow(pcli->hwndContactList, NULL, NULL, RDW_FRAME | RDW_INVALIDATE);
+ if (IsIconic(pcli->hwndContactList) && !IsDlgButtonChecked(hwndDlg, IDC_TOOLWND))
+ ShowWindow(pcli->hwndContactList, IsDlgButtonChecked(hwndDlg, IDC_MIN2TRAY) ? SW_HIDE : SW_SHOW);
+ if (IsDlgButtonChecked(hwndDlg, IDC_TRANSPARENT)) {
+ SetWindowLong(pcli->hwndContactList, GWL_EXSTYLE, GetWindowLong(pcli->hwndContactList, GWL_EXSTYLE) | WS_EX_LAYERED);
+ if (MySetLayeredWindowAttributes)
+ MySetLayeredWindowAttributes(pcli->hwndContactList, RGB(0, 0, 0),
+ (BYTE) DBGetContactSettingByte(NULL, "CList", "AutoAlpha", SETTING_AUTOALPHA_DEFAULT),
+ LWA_ALPHA);
+ }
+ else SetWindowLong(pcli->hwndContactList, GWL_EXSTYLE, GetWindowLong(pcli->hwndContactList, GWL_EXSTYLE) & ~WS_EX_LAYERED);
+
+ SendMessage(pcli->hwndContactTree, WM_SIZE, 0, 0); //forces it to send a cln_listsizechanged
+ return TRUE;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK DlgProcSBarOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ CheckDlgButton(hwndDlg, IDC_SHOWSBAR, DBGetContactSettingByte(NULL, "CLUI", "ShowSBar", 1) ? BST_CHECKED : BST_UNCHECKED);
+ {
+ BYTE showOpts = DBGetContactSettingByte(NULL, "CLUI", "SBarShow", 1);
+ CheckDlgButton(hwndDlg, IDC_SHOWICON, showOpts & 1 ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SHOWPROTO, showOpts & 2 ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SHOWSTATUS, showOpts & 4 ? BST_CHECKED : BST_UNCHECKED);
+ }
+ CheckDlgButton(hwndDlg, IDC_RIGHTSTATUS, DBGetContactSettingByte(NULL, "CLUI", "SBarRightClk", 0) ? BST_UNCHECKED : BST_CHECKED);
+ CheckDlgButton(hwndDlg, IDC_RIGHTMIRANDA, !IsDlgButtonChecked(hwndDlg, IDC_RIGHTSTATUS) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_EQUALSECTIONS, DBGetContactSettingByte(NULL, "CLUI", "EqualSections", 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SBPANELBEVEL, DBGetContactSettingByte(NULL, "CLUI", "SBarBevel", 1) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SHOWGRIP, DBGetContactSettingByte(NULL, "CLUI", "ShowGrip", 1) ? BST_CHECKED : BST_UNCHECKED);
+ if (!IsDlgButtonChecked(hwndDlg, IDC_SHOWSBAR)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SHOWICON), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SHOWPROTO), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SHOWSTATUS), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_RIGHTSTATUS), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_RIGHTMIRANDA), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_EQUALSECTIONS), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SBPANELBEVEL), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SHOWGRIP), FALSE);
+ }
+ return TRUE;
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDC_SHOWSBAR) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SHOWICON), IsDlgButtonChecked(hwndDlg, IDC_SHOWSBAR));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SHOWPROTO), IsDlgButtonChecked(hwndDlg, IDC_SHOWSBAR));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SHOWSTATUS), IsDlgButtonChecked(hwndDlg, IDC_SHOWSBAR));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_RIGHTSTATUS), IsDlgButtonChecked(hwndDlg, IDC_SHOWSBAR));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_RIGHTMIRANDA), IsDlgButtonChecked(hwndDlg, IDC_SHOWSBAR));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_EQUALSECTIONS), IsDlgButtonChecked(hwndDlg, IDC_SHOWSBAR));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SBPANELBEVEL), IsDlgButtonChecked(hwndDlg, IDC_SHOWSBAR));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SHOWGRIP), IsDlgButtonChecked(hwndDlg, IDC_SHOWSBAR));
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ if (((LPNMHDR) lParam)->code == PSN_APPLY ) {
+ DBWriteContactSettingByte(NULL, "CLUI", "ShowSBar", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SHOWSBAR));
+ DBWriteContactSettingByte(NULL, "CLUI", "SBarShow",
+ (BYTE) ((IsDlgButtonChecked(hwndDlg, IDC_SHOWICON) ? 1 : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_SHOWPROTO) ? 2 : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_SHOWSTATUS) ? 4 : 0)));
+ DBWriteContactSettingByte(NULL, "CLUI", "SBarRightClk", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_RIGHTMIRANDA));
+ DBWriteContactSettingByte(NULL, "CLUI", "EqualSections", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_EQUALSECTIONS));
+ DBWriteContactSettingByte(NULL, "CLUI", "SBarBevel", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SBPANELBEVEL));
+ pcli->pfnLoadCluiGlobalOpts();
+ if (DBGetContactSettingByte(NULL, "CLUI", "ShowGrip", 1) != (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SHOWGRIP)) {
+ HWND parent = GetParent(pcli->hwndStatus);
+ int flags = WS_CHILD | CCS_BOTTOM;
+ DBWriteContactSettingByte(NULL, "CLUI", "ShowGrip", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SHOWGRIP));
+ ShowWindow(pcli->hwndStatus, SW_HIDE);
+ DestroyWindow(pcli->hwndStatus);
+ flags |= DBGetContactSettingByte(NULL, "CLUI", "ShowSBar", 1) ? WS_VISIBLE : 0;
+ flags |= DBGetContactSettingByte(NULL, "CLUI", "ShowGrip", 1) ? SBARS_SIZEGRIP : 0;
+ pcli->hwndStatus = CreateWindow(STATUSCLASSNAME, NULL, flags, 0, 0, 0, 0, parent, NULL, g_hInst, NULL);
+ }
+ if (IsDlgButtonChecked(hwndDlg, IDC_SHOWSBAR))
+ ShowWindow(pcli->hwndStatus, SW_SHOW);
+ else
+ ShowWindow(pcli->hwndStatus, SW_HIDE);
+ SendMessage(pcli->hwndContactList, WM_SIZE, 0, 0);
+ return TRUE;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+/****************************************************************************************/
+
+static UINT expertOnlyControls[] =
+{
+ IDC_BRINGTOFRONT, IDC_AUTOSIZE, IDC_STATIC21, IDC_MAXSIZEHEIGHT, IDC_MAXSIZESPIN,
+ IDC_STATIC22, IDC_AUTOSIZEUPWARD, IDC_SHOWMAINMENU, IDC_SHOWCAPTION, IDC_CLIENTDRAG
+};
+
+int CluiOptInit(WPARAM wParam, LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp;
+
+ ZeroMemory(&odp, sizeof(odp));
+ odp.cbSize = sizeof(odp);
+ odp.position = 0;
+ odp.hInstance = g_hInst;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_CLUI);
+ odp.pszTitle = "Window";
+ odp.pszGroup = "Contact List";
+ odp.pfnDlgProc = DlgProcCluiOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.nIDBottomSimpleControl = IDC_STWINDOWGROUP;
+ odp.expertOnlyControls = expertOnlyControls;
+ odp.nExpertOnlyControls = SIZEOF(expertOnlyControls);
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) & odp);
+
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_SBAR);
+ odp.pszTitle = "Status Bar";
+ odp.pfnDlgProc = DlgProcSBarOpts;
+ odp.flags = ODPF_BOLDGROUPS | ODPF_EXPERTONLY;
+ odp.nIDBottomSimpleControl = 0;
+ odp.nExpertOnlyControls = 0;
+ odp.expertOnlyControls = NULL;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) & odp);
+ return 0;
+}
diff --git a/miranda-wine/plugins/clist/commonheaders.c b/miranda-wine/plugins/clist/commonheaders.c
new file mode 100644
index 0000000..14f99f7
--- /dev/null
+++ b/miranda-wine/plugins/clist/commonheaders.c
@@ -0,0 +1 @@
+#include "commonheaders.h"
diff --git a/miranda-wine/plugins/clist/commonheaders.h b/miranda-wine/plugins/clist/commonheaders.h
new file mode 100644
index 0000000..6a061ff
--- /dev/null
+++ b/miranda-wine/plugins/clist/commonheaders.h
@@ -0,0 +1,96 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2005 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 defined(UNICODE)
+#define _UNICODE 1
+#endif
+
+#include <tchar.h>
+#include <malloc.h>
+
+#ifdef _DEBUG
+# define _CRTDBG_MAP_ALLOC
+# include <stdlib.h>
+# include <crtdbg.h>
+#endif
+
+#define _WIN32_WINNT 0x0501
+#include <windows.h>
+#include <commctrl.h>
+#include <stdio.h>
+#include <time.h>
+#include <stddef.h>
+#include <process.h>
+#include <io.h>
+#include <string.h>
+#include <direct.h>
+#include "resource.h"
+#include "forkthread.h"
+#include <win2k.h>
+#include <newpluginapi.h>
+#include <m_clist.h>
+#include <m_clc.h>
+#include <m_clistint.h>
+#include <m_clui.h>
+#include <m_plugins.h>
+#include <m_system.h>
+#include <m_database.h>
+#include <m_langpack.h>
+#include <m_button.h>
+#include <m_options.h>
+#include <m_protosvc.h>
+#include <m_utils.h>
+#include <m_skin.h>
+#include <m_contacts.h>
+#include <m_file.h>
+#include <m_addcontact.h>
+#include "clc.h"
+#include "clist.h"
+
+// shared vars
+extern HINSTANCE g_hInst;
+
+/* most free()'s are invalid when the code is executed from a dll, so this changes
+ all the bad free()'s to good ones, however it's still incorrect code. The reasons for not
+ changing them include:
+
+ * DBFreeVariant has a CallService() lookup
+ * free() is executed in some large loops to do with clist creation of group data
+ * easy search and replace
+
+*/
+
+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)
+
+static __inline char * mir_strdup(const char * src)
+{
+ char * p = 0;
+ if ( src == NULL ) return NULL;
+ p=mir_alloc( strlen(src)+1 );
+ strcpy(p, src);
+ return p;
+}
diff --git a/miranda-wine/plugins/clist/forkthread.c b/miranda-wine/plugins/clist/forkthread.c
new file mode 100644
index 0000000..920fc1f
--- /dev/null
+++ b/miranda-wine/plugins/clist/forkthread.c
@@ -0,0 +1,94 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.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);
+ __try {
+ callercode(arg);
+ }
+ __finally {
+ 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);
+ } //if
+ 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);
+ __try {
+ rc = threadcode(arg);
+ }
+ __finally {
+ 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/plugins/clist/forkthread.h b/miranda-wine/plugins/clist/forkthread.h
new file mode 100644
index 0000000..9abcf5e
--- /dev/null
+++ b/miranda-wine/plugins/clist/forkthread.h
@@ -0,0 +1,63 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/*
+
+Purpose:
+
+ A safe version of _beginthread()
+
+Description:
+
+ 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 unsure
+ that Miranda will wait for all created threads to return as well.
+
+Cavets:
+
+ The function must be reimplemented across MT plugins, since thread
+ creation depends on CRT which can not be shared.
+
+*/
+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/plugins/clist/init.c b/miranda-wine/plugins/clist/init.c
new file mode 100644
index 0000000..843a5bb
--- /dev/null
+++ b/miranda-wine/plugins/clist/init.c
@@ -0,0 +1,175 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2005 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+HINSTANCE g_hInst = 0;
+PLUGINLINK *pluginLink;
+CLIST_INTERFACE* pcli = NULL;
+HIMAGELIST himlCListClc = NULL;
+HANDLE hStatusModeChangeEvent;
+
+extern int currentDesiredStatusMode;
+
+struct MM_INTERFACE memoryManagerInterface;
+BOOL(WINAPI * MySetLayeredWindowAttributes) (HWND, COLORREF, BYTE, DWORD) = NULL;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// external functions
+
+int MenuProcessCommand(WPARAM wParam, LPARAM lParam);
+int InitCustomMenus(void);
+void UninitCustomMenus(void);
+
+void PaintClc(HWND hwnd, struct ClcData *dat, HDC hdc, RECT * rcPaint);
+
+int ClcOptInit(WPARAM wParam, LPARAM lParam);
+int CluiOptInit(WPARAM wParam, LPARAM lParam);
+int CListOptInit(WPARAM wParam, LPARAM lParam);
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// dll stub
+
+BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD dwReason, LPVOID reserved)
+{
+ g_hInst = hInstDLL;
+ DisableThreadLibraryCalls(g_hInst);
+ return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// returns the plugin information
+
+PLUGININFO pluginInfo = {
+ sizeof(PLUGININFO),
+ #if defined( _UNICODE )
+ "Classic contact list (Unicode)",
+ #else
+ "Classic contact list",
+ #endif
+ PLUGIN_MAKE_VERSION(0, 5, 1, 1),
+
+ "Display contacts, event notifications, protocol status",
+ "Miranda IM project",
+ "ghazan@miranda-im.org",
+ "Copyright 2000-2006 Miranda IM project",
+ "http://www.miranda-im.org",
+ UNICODE_AWARE,
+ DEFMOD_CLISTALL
+};
+
+__declspec(dllexport) PLUGININFO *MirandaPluginInfo(DWORD mirandaVersion)
+{
+ if (mirandaVersion < PLUGIN_MAKE_VERSION(0, 4, 3, 0))
+ return NULL;
+ return &pluginInfo;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// called when all modules got loaded
+
+static int OnModulesLoaded( WPARAM wParam, LPARAM lParam )
+{
+ himlCListClc = (HIMAGELIST) CallService(MS_CLIST_GETICONSIMAGELIST, 0, 0);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// options iniatialization
+
+static int OnOptsInit(WPARAM wParam, LPARAM lParam)
+{
+ ClcOptInit(wParam, lParam);
+ CluiOptInit(wParam, lParam);
+ CListOptInit(wParam, lParam);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// menu status services
+
+static int SetStatusMode(WPARAM wParam, LPARAM lParam)
+{
+ //todo: check wParam is valid so people can't use this to run random menu items
+ MenuProcessCommand(MAKEWPARAM(LOWORD(wParam), MPCF_MAINMENU), 0);
+ return 0;
+}
+
+static int GetStatusMode(WPARAM wParam, LPARAM lParam)
+{
+ return currentDesiredStatusMode;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// main clist initialization routine
+
+int __declspec(dllexport) CListInitialise(PLUGINLINK * link)
+{
+ int rc = 0;
+ pluginLink = link;
+ #ifdef _DEBUG
+ _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
+ #endif
+
+ // get the internal malloc/free()
+ memset(&memoryManagerInterface, 0, sizeof(memoryManagerInterface));
+ memoryManagerInterface.cbSize = sizeof(memoryManagerInterface);
+ CallService(MS_SYSTEM_GET_MMI, 0, (LPARAM) & memoryManagerInterface);
+
+ pcli = ( CLIST_INTERFACE* )CallService(MS_CLIST_RETRIEVE_INTERFACE, 0, (LPARAM)g_hInst);
+ if ( (int)pcli == CALLSERVICE_NOTFOUND ) {
+ MessageBoxA( NULL, "This version of plugin requires Miranda IM 0.5 or later", "Fatal error", MB_OK );
+ return 1;
+ }
+ pcli->pfnPaintClc = PaintClc;
+
+ MySetLayeredWindowAttributes = (BOOL(WINAPI *) (HWND, COLORREF, BYTE, DWORD)) GetProcAddress(
+ LoadLibraryA("user32.dll"), "SetLayeredWindowAttributes");
+
+ HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded);
+ HookEvent(ME_OPT_INITIALISE, OnOptsInit);
+
+ hStatusModeChangeEvent = CreateHookableEvent(ME_CLIST_STATUSMODECHANGE);
+
+ InitCustomMenus();
+ CreateServiceFunction(MS_CLIST_SETSTATUSMODE, SetStatusMode);
+ CreateServiceFunction(MS_CLIST_GETSTATUSMODE, GetStatusMode);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// a plugin loader aware of CList exports will never call this.
+
+int __declspec(dllexport) Load(PLUGINLINK * link)
+{
+ return 1;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// a plugin unloader
+
+int __declspec(dllexport) Unload(void)
+{
+ UninitCustomMenus();
+ return 0;
+}
diff --git a/miranda-wine/plugins/clist/res/blank.ico b/miranda-wine/plugins/clist/res/blank.ico
new file mode 100644
index 0000000..7845f62
--- /dev/null
+++ b/miranda-wine/plugins/clist/res/blank.ico
Binary files differ
diff --git a/miranda-wine/plugins/clist/res/delete.ico b/miranda-wine/plugins/clist/res/delete.ico
new file mode 100644
index 0000000..9b0f0ff
--- /dev/null
+++ b/miranda-wine/plugins/clist/res/delete.ico
Binary files differ
diff --git a/miranda-wine/plugins/clist/res/dragcopy.cur b/miranda-wine/plugins/clist/res/dragcopy.cur
new file mode 100644
index 0000000..89c7c96
--- /dev/null
+++ b/miranda-wine/plugins/clist/res/dragcopy.cur
Binary files differ
diff --git a/miranda-wine/plugins/clist/res/dropuser.cur b/miranda-wine/plugins/clist/res/dropuser.cur
new file mode 100644
index 0000000..a84b19e
--- /dev/null
+++ b/miranda-wine/plugins/clist/res/dropuser.cur
Binary files differ
diff --git a/miranda-wine/plugins/clist/res/hyperlin.cur b/miranda-wine/plugins/clist/res/hyperlin.cur
new file mode 100644
index 0000000..f0f548c
--- /dev/null
+++ b/miranda-wine/plugins/clist/res/hyperlin.cur
Binary files differ
diff --git a/miranda-wine/plugins/clist/res/rename.ico b/miranda-wine/plugins/clist/res/rename.ico
new file mode 100644
index 0000000..2c6bc2a
--- /dev/null
+++ b/miranda-wine/plugins/clist/res/rename.ico
Binary files differ
diff --git a/miranda-wine/plugins/clist/resource.h b/miranda-wine/plugins/clist/resource.h
new file mode 100644
index 0000000..d6aeddf
--- /dev/null
+++ b/miranda-wine/plugins/clist/resource.h
@@ -0,0 +1,554 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by resource.rc
+//
+#define IDC_AUTHICON 1
+#define IDC_NOTOALL 3
+#define IDC_APPLY 3
+#define IDI_MIRANDA 102
+#define IDD_ABOUT 103
+#define IDI_SMS 103
+#define IDI_ONLINE 104
+#define IDI_OFFLINE 105
+#define IDD_GNUPL 110
+#define IDD_ADDED 115
+#define IDD_URLSEND 119
+#define IDD_URLRECV 120
+#define IDD_AUTHREQ 121
+#define IDD_DETAILS 125
+#define IDD_OPT_CLIST 126
+#define IDD_HISTORY 127
+#define IDI_AWAY 128
+#define IDI_FREE4CHAT 129
+#define IDI_INVISIBLE 130
+#define IDI_NA 131
+#define IDD_OPT_SOUND 134
+#define IDI_SENDURL 135
+#define IDI_RECVMSG 136
+#define IDI_SENDMSG 137
+#define IDI_URL 138
+#define IDI_DND 158
+#define IDI_OCCUPIED 159
+#define IDI_USERDETAILS 160
+#define IDI_FINDUSER 161
+#define IDI_HELP 162
+#define IDI_OPTIONS 163
+#define IDI_MIRANDAWEBSITE 172
+#define IDI_RENAME 173
+#define IDI_HISTORY 174
+#define IDI_DELETE 175
+#define IDR_CONTEXT 180
+#define IDC_DROP 183
+#define IDD_OPT_HOTKEY 184
+#define IDD_HISTORY_FIND 192
+#define IDI_SENDEMAIL 193
+#define IDD_FILERECV 194
+#define IDD_PROFILEMANAGER 197
+#define IDD_NEWPROFILE 198
+#define IDR_CLISTMENU 199
+#define IDI_BLANK 200
+#define IDD_FINDADD 201
+#define IDI_USERONLINE 201
+#define IDD_OPT_AUTOAWAY 202
+#define IDI_GROUPSHUT 202
+#define IDD_OPTIONS 203
+#define IDI_GROUPOPEN 203
+#define IDD_PLUGINCONFLICT 204
+#define IDD_FILESEND 205
+#define IDI_NOTICK 205
+#define IDD_OPT_PLUGINS 206
+#define IDI_TICK 206
+#define IDD_OPT_ICONS 207
+#define IDI_FILE 207
+#define IDI_TIMESTAMP 208
+#define IDI_CHANGEFONT 209
+#define IDI_ADDCONTACT 210
+#define IDI_SMALLDOT 211
+#define IDI_FILLEDBLOB 212
+#define IDD_READAWAYMSG 213
+#define IDI_EMPTYBLOB 213
+#define IDD_OPT_IGNORE 214
+#define IDC_HYPERLINKHAND 214
+#define IDD_OPT_VISIBILITY 215
+#define IDC_DROPUSER 215
+#define IDD_SETAWAYMSG 216
+#define IDI_DETAILSLOGO 216
+#define IDD_OPT_AWAYMSG 217
+#define IDD_OPT_CLUI 218
+#define IDD_INFO_SUMMARY 220
+#define IDD_INFO_CONTACT 221
+#define IDD_INFO_BACKGROUND 222
+#define IDD_INFO_NOTES 223
+#define IDD_ADDEMAIL 226
+#define IDD_ICONINDEX 227
+#define IDD_OPT_CLC 228
+#define IDD_OPT_CLCTEXT 229
+#define IDD_OPT_CLCBKG 230
+#define IDD_INFO_LOCATION 231
+#define IDD_INFO_WORK 232
+#define IDD_ADDPHONE 233
+#define IDD_OPT_SBAR 234
+#define IDD_INSTALLINI 235
+#define IDD_WARNINICHANGE 236
+#define IDD_INIIMPORTDONE 237
+#define IDD_OPT_CLCTEXTSIMPLE 239
+#define IDB_SORTCOLUP 239
+#define IDB_SORTCOLDOWN 240
+#define IDD_OPT_NETLIB 246
+#define IDD_NETLIBLOGOPTS 247
+#define IDD_FILETRANSFERINFO 249
+#define IDD_OPT_FILETRANSFER 250
+#define IDD_FILEEXISTS 251
+#define IDD_DELETECONTACT 254
+#define IDD_DENYREASON 256
+#define IDD_ADDCONTACT 257
+#define IDD_OPT_CONTACT 261
+#define IDI_MULTISEND 263
+#define IDI_DOWNARROW 264
+#define IDD_CREDITS 265
+#define IDD_OPT_IDLE 268
+#define IDC_SAVE 1001
+#define IDI_ONTHEPHONE 1002
+#define IDC_MESSAGE 1002
+#define IDI_OUTTOLUNCH 1003
+#define IDC_AUTOCLOSE 1004
+#define IDC_FROM 1005
+#define IDC_AUTOMIN 1005
+#define IDC_DATE 1006
+#define IDC_DUMPRECV 1006
+#define IDC_MSG 1008
+#define IDC_PROXYDNS 1008
+#define IDC_NAME 1009
+#define IDC_PROXYTYPE 1009
+#define IDC_STATIC23 1010
+#define IDC_SPECIFYPORTS 1013
+#define IDC_ST_ENTERMSG 1013
+#define IDC_ST_ENTERURL 1014
+#define IDC_SPECIFYPORTSO 1014
+#define IDC_TEXT 1019
+#define IDC_SHOWNAMES 1024
+#define IDC_ABOUT 1032
+#define IDC_MYNOTES 1033
+#define IDC_URLS 1037
+#define IDC_REPLY 1039
+#define IDC_URL 1041
+#define IDC_REASON 1046
+#define IDC_EMAIL 1048
+#define IDC_NAMENICK 1049
+#define IDC_NAMEFIRST 1050
+#define IDC_NAMELAST 1051
+#define IDC_NICK 1053
+#define IDC_GENDER 1060
+#define IDC_CITY 1061
+#define IDC_STATE 1062
+#define IDC_COUNTRY 1063
+#define IDC_AGE 1064
+#define IDC_ZIP 1064
+#define IDC_PHONE 1065
+#define IDC_STREET 1065
+#define IDC_COMPANY 1066
+#define IDC_LANGUAGE1 1066
+#define IDC_TIMEZONE 1067
+#define IDC_DEPARTMENT 1067
+#define IDC_LOCALTIME 1068
+#define IDC_DETAILS 1069
+#define IDC_POSITION 1069
+#define IDC_LANGUAGE2 1069
+#define IDC_ADD 1070
+#define IDC_LANGUAGE3 1070
+#define IDC_MOREOPTIONS 1071
+#define IDC_USERMENU 1071
+#define IDC_MIN2TRAY 1073
+#define IDC_ONTOP 1074
+#define IDC_SHOWMAINMENU 1075
+#define IDC_CLIENTDRAG 1076
+#define IDC_EDIT 1078
+#define IDC_LIST 1079
+#define IDC_HISTORY 1080
+#define IDC_USESOUND 1085
+#define IDC_TOOLWND 1097
+#define IDC_ONECLK 1098
+#define IDC_SHOWCAPTION 1098
+#define IDC_HIDEOFFLINE 1099
+#define IDC_SHOWHIDE 1100
+#define IDC_HIDEEMPTYGROUPS 1100
+#define IDC_SORTBYSTATUS 1101
+#define IDC_FADEINOUT 1101
+#define IDC_READMSG 1102
+#define IDC_AUTOSIZE 1102
+#define IDC_DISABLEGROUPS 1102
+#define IDC_AUTOSIZEUPWARD 1103
+#define IDC_ALWAYSSTATUS 1103
+#define IDC_NETSEARCH 1104
+#define IDC_CONFIRMDELETE 1104
+#define IDC_SORTBYPROTO 1105
+#define IDC_SHOWOPTIONS 1105
+#define IDC_SEARCHURL 1106
+#define IDC_BUILDTIME 1108
+#define IDC_NUMBER 1113
+#define IDC_UIN 1123
+#define IDC_TRANSPARENT 1124
+#define IDC_TRANSINACTIVE 1126
+#define IDC_TRANSACTIVE 1128
+#define IDC_FINDWHAT 1131
+#define IDC_FIND 1132
+#define IDC_FILE 1133
+#define IDC_PROFILELIST 1134
+#define IDC_NEWPROFILE 1135
+#define IDC_NEWPROFILENAME 1136
+#define IDC_TABS 1141
+#define IDC_RESULTS 1142
+#define IDC_STATUS 1144
+#define IDC_SCREENSAVE 1145
+#define IDC_TIMED 1146
+#define IDC_AWAYTIME 1147
+#define IDC_USEPROXY 1148
+#define IDC_SETNA 1148
+#define IDC_PROXYAUTH 1149
+#define IDC_NATIME 1149
+#define IDC_PROXYHOST 1150
+#define IDC_PROXYPORT 1151
+#define IDC_PROXYUSER 1152
+#define IDC_PROXYPASS 1153
+#define IDC_STATIC11 1154
+#define IDC_STATIC12 1155
+#define IDC_STATIC21 1156
+#define IDC_STATIC22 1157
+#define IDC_STATIC31 1158
+#define IDC_STATIC32 1159
+#define IDC_PROXYAUTHNTLM 1160
+#define IDC_HKSHOWHIDE 1162
+#define IDC_HKREADMSG 1163
+#define IDC_SOUNDLIST 1163
+#define IDC_HKSEARCH 1164
+#define IDC_CHANGE 1164
+#define IDC_PREVIEW 1165
+#define IDC_HKSHOWOPTIONS 1165
+#define IDC_PLUGINLIST 1167
+#define IDC_FEATURENAME 1168
+#define IDC_CHOOSE 1169
+#define IDC_TO 1170
+#define IDC_ABOUTGROUP 1175
+#define IDC_DESCRIPTION 1176
+#define IDC_AUTHOR 1177
+#define IDC_COPYRIGHT 1178
+#define IDC_VERSION 1179
+#define IDC_HOMEPAGE 1181
+#define IDC_RESTARTREQD 1182
+#define IDC_ICONSET 1183
+#define IDC_BROWSE 1184
+#define IDC_RUNATSTARTBROWSE 1185
+#define IDC_PAGETREE 1186
+#define IDC_RUNNOW 1186
+#define IDC_INACTIVEPERC 1187
+#define IDC_ACTIVEPERC 1188
+#define IDC_SEARCHNEWWND 1188
+#define IDC_RETRIEVING 1193
+#define IDC_TITLETEXT 1196
+#define IDC_GETMORE 1200
+#define IDC_VISIBLEICON 1204
+#define IDC_INVISIBLEICON 1205
+#define IDC_FILEICON 1206
+#define IDC_ONLINEICON 1207
+#define IDC_FILENAMES 1208
+#define IDC_ALLICON 1208
+#define IDC_DONTREPLY 1209
+#define IDC_NONEICON 1209
+#define IDC_USEPREVIOUS 1210
+#define IDC_NODIALOG 1211
+#define IDC_USESPECIFIC 1212
+#define IDC_FILEDIR 1213
+#define IDC_ALLFILESPROGRESS 1217
+#define IDC_CURRENTSPEED 1219
+#define IDC_STAWAYTYPE 1220
+#define IDC_WHITERECT 1221
+#define IDC_ALLSPEED 1221
+#define IDC_CURRENTFILEPROGRESS 1222
+#define IDC_CURRENTFILEGROUP 1223
+#define IDC_FIRSTNAME 1224
+#define IDC_LASTNAME 1225
+#define IDC_CURRENTTRANSFERRED 1225
+#define IDC_DOBDAY 1226
+#define IDC_DOBMONTH 1227
+#define IDC_WEBPAGE 1228
+#define IDC_DOBYEAR 1228
+#define IDC_UPDATING 1231
+#define IDC_NAMEORDER 1234
+#define IDC_AUTOHIDE 1235
+#define IDC_HIDETIME 1236
+#define IDC_RECONNECTREQD 1239
+#define IDC_IMPORT 1241
+#define IDC_TOMAIN 1243
+#define IDC_TOPROTO 1244
+#define IDC_PROTOLIST 1245
+#define IDC_TODEFICON 1246
+#define IDC_IMPORTMULTI 1247
+#define IDC_MAXSIZEHEIGHT 1254
+#define IDC_MAXSIZESPIN 1255
+#define IDC_FONTID 1256
+#define IDC_SAMETYPE 1257
+#define IDC_SAMESTYLE 1258
+#define IDC_SAMECOLOUR 1259
+#define IDC_SAMEAS 1260
+#define IDC_TYPEFACE 1261
+#define IDC_BOLD 1262
+#define IDC_ITALIC 1263
+#define IDC_COLOUR 1264
+#define IDC_UNDERLINE 1265
+#define IDC_HOTCOLOUR 1267
+#define IDC_SAMESIZE 1268
+#define IDC_BKGCOLOUR 1269
+#define IDC_FILENAME 1271
+#define IDC_SCROLL 1277
+#define IDC_PROPORTIONAL 1278
+#define IDC_SELCOLOUR 1281
+#define IDC_QUICKCOLOUR 1282
+#define IDC_SMOOTHTIME 1283
+#define IDC_SMOOTHTIMESPIN 1284
+#define IDC_GREYOUT 1285
+#define IDC_ROWHEIGHT 1285
+#define IDC_ROWHEIGHTSPIN 1286
+#define IDC_GREYOUTOPTS 1288
+#define IDC_GROUPINDENT 1289
+#define IDC_GROUPINDENTSPIN 1290
+#define IDC_LEFTMARGIN 1291
+#define IDC_SAMPLE 1292
+#define IDC_LEFTMARGINSPIN 1292
+#define IDC_FONTSIZE 1293
+#define IDC_STRETCHH 1298
+#define IDC_STRETCHV 1299
+#define IDC_TILEH 1300
+#define IDC_SCRIPT 1300
+#define IDC_TILEV 1301
+#define IDC_GAMMACORRECT 1302
+#define IDC_INTERESTS 1305
+#define IDC_EMAILS 1306
+#define IDC_PAST 1307
+#define IDC_HIDEOFFLINEOPTS 1308
+#define IDC_PHONES 1308
+#define IDC_SMS 1310
+#define IDC_AREA 1312
+#define IDC_UPDATE 1313
+#define IDC_DONTCYCLE 1315
+#define IDC_PRIMARYSTATUS 1316
+#define IDC_CYCLE 1317
+#define IDC_CYCLETIME 1318
+#define IDC_CYCLETIMESPIN 1319
+#define IDC_HIDETIMESPIN 1320
+#define IDC_MULTITRAY 1321
+#define IDC_ALWAYSMULTI 1322
+#define IDC_SHOWICON 1323
+#define IDC_SHOWPROTO 1324
+#define IDC_SHOWSTATUS 1325
+#define IDC_EQUALSECTIONS 1326
+#define IDC_SHOWSBAR 1329
+#define IDC_RIGHTMIRANDA 1330
+#define IDC_RIGHTSTATUS 1331
+#define IDC_ININAME 1333
+#define IDC_VIEWINI 1334
+#define IDC_SECURITYINFO 1335
+#define IDC_SETTINGNAME 1336
+#define IDC_NEWVALUE 1337
+#define IDC_WARNNOMORE 1338
+#define IDC_DELETE 1339
+#define IDC_RECYCLE 1340
+#define IDC_NEWNAME 1341
+#define IDC_MOVE 1342
+#define IDC_LEAVE 1343
+#define IDC_EXPERT 1346
+#define IDC_SORTBYNAME 1347
+#define IDC_STAUTOHIDESECS 1349
+#define IDC_STCLISTGROUP 1350
+#define IDC_DISABLEDRAGDROP 1351
+#define IDC_NOTEDITLABELS 1352
+#define IDC_SHOWSELALWAYS 1353
+#define IDC_TRACKSELECT 1354
+#define IDC_SHOWGROUPCOUNTS 1355
+#define IDC_HIDECOUNTSWHENEMPTY 1356
+#define IDC_DIVIDERONOFF 1357
+#define IDC_NOTNOTRANSLUCENTSEL 1358
+#define IDC_LINEWITHGROUPS 1359
+#define IDC_QUICKSEARCHVISONLY 1360
+#define IDC_SORTGROUPSALPHA 1361
+#define IDC_NOTNOSMOOTHSCROLLING 1362
+#define IDC_BITMAP 1363
+#define IDC_STWINDOWGROUP 1364
+#define IDC_STATIC01 1365
+#define IDC_CATEGORYLIST 1366
+#define IDC_LOADICONS 1369
+#define IDC_STICONSGROUP 1371
+#define IDC_MSGICON 1375
+#define IDC_URLICON 1376
+#define IDC_STNOPAGE 1377
+#define IDC_STCHECKMARKS 1380
+#define IDC_STSAMETEXT 1382
+#define IDC_STASTEXT 1383
+#define IDC_STSIZETEXT 1384
+#define IDC_STCOLOURTEXT 1385
+#define IDC_STHORZBAR 1386
+#define IDC_MIRANDA 1388
+#define IDC_STATUSBAR 1389
+#define IDC_PROTOIDGROUP 1392
+#define IDC_BYPROTOID 1393
+#define IDC_PROTOID 1394
+#define IDC_EMAILGROUP 1395
+#define IDC_BYEMAIL 1396
+#define IDC_STNAMENICK 1397
+#define IDC_NAMEGROUP 1398
+#define IDC_BYNAME 1399
+#define IDC_STNAMEFIRST 1400
+#define IDC_STNAMELAST 1401
+#define IDC_ADVANCEDGROUP 1402
+#define IDC_BYADVANCED 1403
+#define IDC_ADVANCED 1404
+#define IDC_STSIMPLERIGHT 1440
+#define IDC_NETLIBUSERS 1443
+#define IDC_STOFTENPORT 1445
+#define IDC_STATIC51 1446
+#define IDC_STATIC52 1447
+#define IDC_STATIC43 1448
+#define IDC_LOGOPTIONS 1449
+#define IDC_PORTSRANGE 1450
+#define IDC_TOCONSOLE 1451
+#define IDC_STATIC53 1451
+#define IDC_SHOWCONSOLEATSTART 1452
+#define IDC_PORTSRANGEO 1452
+#define IDC_STATIC54 1453
+#define IDC_SHOWCONSOLE 1454
+#define IDC_TOOUTPUTDEBUGSTRING 1455
+#define IDC_TOFILE 1456
+#define IDC_CLEARCONSOLE 1457
+#define IDC_RUNATSTART 1458
+#define IDC_DUMPSENT 1464
+#define IDC_DUMPPROXY 1466
+#define IDC_TEXTDUMPS 1467
+#define IDC_AUTODETECTTEXT 1468
+#define IDC_TIMEFORMAT 1469
+#define IDC_FILENAMEBROWSE 1470
+#define IDC_SHOWTHISDLGATSTART 1471
+#define IDC_FILEDIRBROWSE 1475
+#define IDC_ALLFILESGROUP 1476
+#define IDC_SCANCMDLINEBROWSE 1476
+#define IDC_ALLTRANSFERRED 1477
+#define IDC_OPENFOLDER 1478
+#define IDC_OPENFILE 1479
+#define IDC_TOTALSIZE 1480
+#define IDC_APPENDNICKTODIR 1483
+#define IDC_AUTOACCEPT 1484
+#define IDC_SCANCMDLINE 1485
+#define IDC_WARNBEFOREOPENING 1488
+#define IDC_SCANDURINGDL 1489
+#define IDC_SCANAFTERDL 1490
+#define IDC_NOSCANNER 1491
+#define IDC_ST_CMDLINE 1492
+#define IDC_ST_CMDLINEHELP 1493
+#define IDC_PROPERTIES 1496
+#define IDC_RESUME 1497
+#define IDC_EXISTINGICON 1499
+#define IDC_RESUMEALL 1500
+#define IDC_OVERWRITE 1501
+#define IDC_OVERWRITEALL 1502
+#define IDC_SKIP 1503
+#define IDC_EXISTINGSIZE 1506
+#define IDC_EXISTINGDATE 1507
+#define IDC_EXISTINGTYPE 1508
+#define IDC_NEWICON 1509
+#define IDC_NEWSIZE 1510
+#define IDC_NEWDATE 1511
+#define IDC_NEWTYPE 1512
+#define IDC_SAVEAS 1513
+#define IDC_ASK 1516
+#define IDC_RENAME 1519
+#define IDC_VIRUSSCANNERGROUP 1520
+#define IDC_HIDE 1534
+#define IDC_TOPLINE 1535
+#define IDC_GPLBTN 1536
+#define IDC_MAIL 1536
+#define IDC_MYHANDLE 1540
+#define IDC_GROUP 1541
+#define IDC_ADDED 1542
+#define IDC_AUTH 1543
+#define IDC_PLUGINSTATIC1 1559
+#define IDC_DELETEHISTORY 1560
+#define IDC_HOTKEYURLSTR 1567
+#define IDC_SETNASTR 1568
+#define IDC_AAUTHOR 1569
+#define IDC_AHOMEPAGE 1570
+#define IDC_AVERSION 1571
+#define IDC_ACOPYRIGHT 1572
+#define IDC_ADESCRIPTION 1573
+#define IDC_PLUGINENABLE 1574
+#define IDC_AUTHREQ 1577
+#define IDC_AUTHGB 1578
+#define IDC_BRINGTOFRONT 1579
+#define IDC_PROTOCOL 1580
+#define IDC_CONTRIBLINK 1586
+#define IDC_HOMELINK 1587
+#define IDC_SUPPORTLINK 1588
+#define IDC_DEVS 1589
+#define IDC_GPL 1590
+#define IDC_LOGO 1591
+#define IDC_CREDITSTEXT 1595
+#define IDC_WSLOCK 1599
+#define IDC_BLINKTIME 1607
+#define IDC_BLINKSPIN 1608
+#define IDC_DISABLEBLINK 1609
+#define IDC_IDLE 1610
+#define IDC_SBPANELBEVEL 1611
+#define IDC_DROPSHADOW 1612
+#define IDC_SHOWGRIP 1612
+#define IDC_NOSCROLLBAR 1613
+#define IDC_BUTTON1 1633
+#define IDC_IDLECHECK 1636
+#define IDC_IDLEONWINDOWS 1637
+#define IDC_IDLEONMIRANDA 1638
+#define IDC_IDLEUSEGLI 1639
+#define IDC_SCREENSAVER 1642
+#define IDC_LOCKED 1643
+#define IDC_IDLESHORT 1644
+#define IDC_IDLELONG 1645
+#define IDC_IDLE1STTIME 1646
+#define IDC_IDLE2NDTIME 1647
+#define IDC_IDLEPRIVATE 1649
+#define IDC_AASTATUS 1650
+#define IDC_AASHORTIDLE 1651
+#define IDC_AALONGSTATUS 1652
+#define IDC_AALONGIDLE 1656
+#define IDC_ONDESKTOP 1657
+#define IDC_WINCOLOUR 1659
+#define IDC_ICONBLINK 1660
+#define IDC_STMSDELAY 1661
+#define IDI_SEARCHALL 32548
+#define ID_ICQ_EXIT 40001
+#define IDM_COPY 40001
+#define ID_RESET 40002
+#define POPUP_HIDEEMPTYGROUPS 40003
+#define POPUP_NEWSUBGROUP 40004
+#define POPUP_HIDEOFFLINE 40005
+#define POPUP_GROUPHIDEOFFLINE 40006
+#define POPUP_HIDEOFFLINEROOT 40007
+#define POPUP_DISABLEGROUPS 40008
+#define IDC_SENDMESSAGE 40009
+#define IDM_COPYALL 40011
+#define IDM_SELECTALL 40012
+#define IDM_CLEAR 40013
+#define IDM_OPENNEW 40014
+#define IDM_OPENEXISTING 40015
+#define IDM_COPYLINK 40016
+#define POPUP_HIDEMIRANDA 40017
+#define ID_TRAY_HIDE 40038
+#define ID_TRAY_EXIT 40040
+#define POPUP_NEWGROUP 40050
+#define POPUP_RENAMEGROUP 40052
+#define POPUP_DELETEGROUP 40053
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 269
+#define _APS_NEXT_COMMAND_VALUE 40018
+#define _APS_NEXT_CONTROL_VALUE 1662
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/miranda-wine/plugins/clist/resource.rc b/miranda-wine/plugins/clist/resource.rc
new file mode 100644
index 0000000..698307c
--- /dev/null
+++ b/miranda-wine/plugins/clist/resource.rc
@@ -0,0 +1,706 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include <windows.h>
+#include <winres.h>
+#include <statusmodes.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
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_DELETECONTACT DIALOGEX 0, 0, 284, 90
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS |
+ DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Delete Contact"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "No",IDNO,162,38,65,14
+ PUSHBUTTON "Yes",IDYES,54,38,65,14
+ CONTROL "Hide from list only, in order to keep their history and ignore/visibility settings",
+ IDC_HIDE,"Button",BS_AUTOCHECKBOX | BS_MULTILINE |
+ WS_TABSTOP,7,65,270,9
+ LTEXT "Use Options->Ignore (expert mode) to unhide contacts.",
+ IDC_STATIC,20,78,257,8
+ CONTROL "Are you sure you want to delete %s?",IDC_TOPLINE,"Static",
+ SS_SIMPLE | SS_NOPREFIX | WS_GROUP,7,7,270,8
+ LTEXT "This will erase all history and settings for this contact!",
+ IDC_STATIC,7,18,239,14
+END
+
+IDD_OPT_HOTKEY DIALOGEX 0, 0, 238, 136
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Hotkeys",IDC_STATIC,4,4,230,126
+ CONTROL "Show/Hide:",IDC_SHOWHIDE,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,14,19,78,9
+ CONTROL "HotKey1",IDC_HKSHOWHIDE,"msctls_hotkey32",WS_BORDER |
+ WS_TABSTOP,92,17,93,12
+ CONTROL "Read Msg:",IDC_READMSG,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,14,36,78,9
+ CONTROL "HotKey1",IDC_HKREADMSG,"msctls_hotkey32",WS_BORDER |
+ WS_TABSTOP,92,34,93,12
+ CONTROL "Net Search:",IDC_NETSEARCH,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,14,53,78,9
+ CONTROL "HotKey1",IDC_HKSEARCH,"msctls_hotkey32",WS_BORDER |
+ WS_TABSTOP,92,51,93,12
+ LTEXT "URL:",IDC_HOTKEYURLSTR,26,71,22,8
+ EDITTEXT IDC_SEARCHURL,92,69,136,12,ES_AUTOHSCROLL
+ CONTROL "Open in new browser window",IDC_SEARCHNEWWND,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,92,86,136,10
+ CONTROL "Show Options",IDC_SHOWOPTIONS,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,14,107,71,9
+ CONTROL "HotKey1",IDC_HKSHOWOPTIONS,"msctls_hotkey32",WS_BORDER |
+ WS_TABSTOP,92,105,93,12
+END
+
+IDD_OPT_CLIST DIALOGEX 0, 0, 314, 204
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "Hide offline users",IDC_HIDEOFFLINE,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,10,17,124,10
+ CONTROL "Hide empty groups",IDC_HIDEEMPTYGROUPS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,10,33,124,10
+ CONTROL "Disable groups",IDC_DISABLEGROUPS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,10,50,124,10
+ CONTROL "Ask before deleting contacts",IDC_CONFIRMDELETE,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,10,67,124,10
+ CONTROL "Sort contacts by name",IDC_SORTBYNAME,"Button",
+ BS_AUTORADIOBUTTON | WS_GROUP,153,14,144,10
+ CONTROL "Sort contacts by status",IDC_SORTBYSTATUS,"Button",
+ BS_AUTORADIOBUTTON,153,26,149,10
+ CONTROL "Sort contacts by protocol",IDC_SORTBYPROTO,"Button",
+ BS_AUTORADIOBUTTON,153,38,151,10
+ CONTROL "Single click interface",IDC_ONECLK,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,152,68,150,10
+ CONTROL "Always show status in tooltip",IDC_ALWAYSSTATUS,"Button",
+ BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,152,
+ 81,151,11
+ CONTROL "Disable icon blinking",IDC_DISABLEBLINK,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,152,95,86,9
+ EDITTEXT IDC_BLINKTIME,153,109,35,12,ES_NUMBER
+ LTEXT "ms delay",IDC_STMSDELAY,192,110,113,8
+ CONTROL "Show",IDC_DONTCYCLE,"Button",BS_AUTORADIOBUTTON |
+ WS_GROUP,10,143,97,10
+ COMBOBOX IDC_PRIMARYSTATUS,107,142,78,70,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ LTEXT "icon when statuses differ",IDC_STATIC,189,144,116,8,NOT
+ WS_GROUP
+ CONTROL "Cycle icons every",IDC_CYCLE,"Button",
+ BS_AUTORADIOBUTTON,10,160,97,10
+ EDITTEXT IDC_CYCLETIME,107,159,30,12,ES_RIGHT | ES_NUMBER
+ CONTROL "Spin1",IDC_CYCLETIMESPIN,"msctls_updown32",
+ UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY |
+ UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,127,158,
+ 10,14
+ LTEXT "seconds, when statuses differ",IDC_STATIC,140,161,165,8,
+ NOT WS_GROUP
+ CONTROL "Show multiple icons",IDC_MULTITRAY,"Button",
+ BS_AUTORADIOBUTTON,10,177,98,10
+ CONTROL "Only when statuses differ",IDC_ALWAYSMULTI,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,108,177,198,10
+ GROUPBOX "Contact List",IDC_STCLISTGROUP,2,2,135,126
+ GROUPBOX "System tray icon",IDC_STATIC,143,57,169,70
+ GROUPBOX "System tray icon when using multiple protocols",
+ IDC_STATIC,2,131,310,66
+ GROUPBOX "Contact List Sorting",IDC_STATIC,143,2,169,54,WS_GROUP
+ CONTROL "Spin5",IDC_BLINKSPIN,"msctls_updown32",UDS_SETBUDDYINT |
+ UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS |
+ UDS_HOTTRACK,173,97,11,21
+ CONTROL "Disable icon blinking",IDC_ICONBLINK,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,10,84,97,10
+END
+
+IDD_OPT_CLUI DIALOGEX 0, 0, 313, 245
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Window",IDC_STWINDOWGROUP,4,4,305,154
+ CONTROL "Always on top",IDC_ONTOP,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,13,18,128,10
+ CONTROL "Tool style main window",IDC_TOOLWND,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,13,32,128,10
+ CONTROL "Minimize to tray",IDC_MIN2TRAY,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,13,46,128,10
+ CONTROL "Hide contact list after it has been idle for",
+ IDC_AUTOHIDE,"Button",BS_AUTOCHECKBOX | BS_TOP |
+ BS_MULTILINE | WS_TABSTOP,141,18,162,10
+ EDITTEXT IDC_HIDETIME,151,33,30,12,ES_RIGHT | ES_NUMBER
+ CONTROL "Spin1",IDC_HIDETIMESPIN,"msctls_updown32",
+ UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY |
+ UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,172,32,10,
+ 14
+ LTEXT "seconds",IDC_STATIC01,186,35,56,8
+ CONTROL "Automatically resize window to height of list",
+ IDC_AUTOSIZE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,141,
+ 55,162,10
+ LTEXT "maximum",IDC_STATIC21,151,71,45,8
+ EDITTEXT IDC_MAXSIZEHEIGHT,197,69,31,12,ES_RIGHT | ES_AUTOHSCROLL |
+ ES_NUMBER
+ CONTROL "Spin1",IDC_MAXSIZESPIN,"msctls_updown32",
+ UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY |
+ UDS_ARROWKEYS | UDS_HOTTRACK,218,68,10,14
+ LTEXT "% of screen",IDC_STATIC22,230,71,69,8
+ CONTROL "Size upwards",IDC_AUTOSIZEUPWARD,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,151,86,147,10
+ LTEXT "Title bar text:",IDC_STATIC,12,106,51,8
+ GROUPBOX "Translucency options (Windows 2000/XP only)",IDC_STATIC,
+ 4,161,305,80
+ CONTROL "Fade contact list in/out",IDC_FADEINOUT,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,13,174,163,10
+ CONTROL "Transparent contact list",IDC_TRANSPARENT,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,13,191,151,9
+ LTEXT "Inactive opacity:",IDC_STATIC11,23,206,89,8
+ CONTROL "Slider2",IDC_TRANSINACTIVE,"msctls_trackbar32",TBS_TOP |
+ TBS_NOTICKS | WS_TABSTOP,112,205,130,11
+ LTEXT "Active opacity:",IDC_STATIC12,23,221,89,8
+ CONTROL "Slider2",IDC_TRANSACTIVE,"msctls_trackbar32",TBS_TOP |
+ TBS_NOTICKS | WS_TABSTOP,112,221,130,11
+ LTEXT "000%",IDC_INACTIVEPERC,246,206,29,8,SS_NOPREFIX
+ LTEXT "000%",IDC_ACTIVEPERC,246,222,29,8,SS_NOPREFIX
+ CONTROL "Show menu bar",IDC_SHOWMAINMENU,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,13,60,128,10
+ CONTROL "Easy move",IDC_CLIENTDRAG,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,13,74,128,10
+ CONTROL "Show title bar",IDC_SHOWCAPTION,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,13,88,128,10
+ CONTROL "If window is partially covered, bring to front instead of hiding",
+ IDC_BRINGTOFRONT,"Button",BS_AUTOCHECKBOX | BS_MULTILINE |
+ WS_TABSTOP,141,102,162,16
+ EDITTEXT IDC_TITLETEXT,63,104,72,12,ES_AUTOHSCROLL
+ CONTROL "Show drop shadow (restart required)",IDC_DROPSHADOW,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,122,138,10
+ CONTROL "Pin to desktop",IDC_ONDESKTOP,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,13,137,128,10
+END
+
+IDD_OPT_CLC DIALOGEX 0, 0, 314, 251
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Items",IDC_STATIC,2,2,310,114
+ CONTROL "Show divider between online and offline contacts",
+ IDC_DIVIDERONOFF,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 11,13,179,10
+ CONTROL "Hot track items as mouse passes over",IDC_TRACKSELECT,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,28,179,10
+ CONTROL "Disable drag and drop of items",IDC_DISABLEDRAGDROP,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,43,179,10
+ CONTROL "Disable rename of items by clicking twice",
+ IDC_NOTEDITLABELS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 11,58,179,10
+ CONTROL "Show selection even when list is not focused",
+ IDC_SHOWSELALWAYS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 11,73,179,10
+ CONTROL "Make selection highlight translucent",
+ IDC_NOTNOTRANSLUCENTSEL,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,11,88,179,10
+ LTEXT "'Hide Offline' means to hide:",IDC_STATIC,191,10,112,8
+ CONTROL "Tree1",IDC_HIDEOFFLINEOPTS,"SysTreeView32",
+ TVS_DISABLEDRAGDROP | TVS_NOTOOLTIPS | WS_BORDER |
+ WS_TABSTOP | 0x4000,191,20,112,86
+ GROUPBOX "Groups",IDC_STATIC,2,120,148,121
+ CONTROL "Draw a line alongside group names",IDC_LINEWITHGROUPS,
+ "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,11,
+ 129,131,16
+ CONTROL "Show counts of number of contacts in a group",
+ IDC_SHOWGROUPCOUNTS,"Button",BS_AUTOCHECKBOX |
+ BS_MULTILINE | WS_TABSTOP,11,147,131,16
+ CONTROL "Hide group counts when there are none online",
+ IDC_HIDECOUNTSWHENEMPTY,"Button",BS_AUTOCHECKBOX |
+ BS_MULTILINE | WS_TABSTOP,11,165,131,16
+ CONTROL "Sort groups alphabetically",IDC_SORTGROUPSALPHA,"Button",
+ BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,11,183,131,
+ 16
+ CONTROL "Quicksearch in open groups only",IDC_QUICKSEARCHVISONLY,
+ "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,11,
+ 201,131,16
+ LTEXT "Indent groups by:",IDC_STATIC,11,221,67,8
+ EDITTEXT IDC_GROUPINDENT,78,219,31,12,ES_RIGHT | ES_NUMBER
+ CONTROL "Spin1",IDC_GROUPINDENTSPIN,"msctls_updown32",
+ UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY |
+ UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,95,215,10,
+ 14
+ LTEXT "pixels",IDC_STATIC,112,221,36,8
+ GROUPBOX "Visual",IDC_STATIC,156,120,156,121
+ CONTROL "Scroll list smoothly",IDC_NOTNOSMOOTHSCROLLING,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,164,130,139,10
+ LTEXT "Time:",IDC_STATIC11,174,144,42,8
+ EDITTEXT IDC_SMOOTHTIME,216,142,31,12,ES_RIGHT | ES_NUMBER
+ CONTROL "Spin1",IDC_SMOOTHTIMESPIN,"msctls_updown32",
+ UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY |
+ UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,237,137,
+ 10,14
+ LTEXT "milliseconds",IDC_STATIC12,250,140,56,8,SS_CENTERIMAGE
+ LTEXT "Left margin:",IDC_STATIC,165,180,52,8
+ EDITTEXT IDC_LEFTMARGIN,215,180,31,12,ES_RIGHT | ES_NUMBER
+ CONTROL "Spin1",IDC_LEFTMARGINSPIN,"msctls_updown32",
+ UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY |
+ UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,240,180,
+ 10,14
+ LTEXT "pixels",IDC_STATIC,250,180,54,8
+ CONTROL "Grey out entire list when:",IDC_GREYOUT,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,165,195,139,10
+ CONTROL "Tree1",IDC_GREYOUTOPTS,"SysTreeView32",
+ TVS_DISABLEDRAGDROP | TVS_NOTOOLTIPS | WS_BORDER |
+ WS_TABSTOP | 0x4000,165,205,139,30
+ CONTROL "Dim idle contacts",IDC_IDLE,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,11,102,153,10
+ CONTROL "Hide vertical scroll bar",IDC_NOSCROLLBAR,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,165,160,140,10
+END
+
+IDD_OPT_CLCTEXT DIALOGEX 0, 0, 277, 240
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Fonts",IDC_STATIC,4,4,269,125
+ COMBOBOX IDC_FONTID,12,17,253,87,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ LTEXT "same",IDC_STSAMETEXT,19,32,45,10,SS_CENTERIMAGE
+ CONTROL "Typeface",IDC_SAMETYPE,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,64,32,52,10
+ CONTROL "Size",IDC_SAMESIZE,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,117,32,45,10
+ CONTROL "Style",IDC_SAMESTYLE,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,163,32,48,10
+ CONTROL "Colour",IDC_SAMECOLOUR,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,212,32,53,10
+ LTEXT "as:",IDC_STASTEXT,19,46,45,10,SS_CENTERIMAGE
+ COMBOBOX IDC_SAMEAS,64,45,196,88,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ CONTROL "",IDC_STHORZBAR,"Static",SS_ETCHEDHORZ,9,64,259,1
+ COMBOBOX IDC_TYPEFACE,12,72,136,182,CBS_DROPDOWN | CBS_SORT |
+ WS_VSCROLL | WS_TABSTOP
+ COMBOBOX IDC_SCRIPT,156,72,60,68,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ COMBOBOX IDC_FONTSIZE,225,72,40,69,CBS_DROPDOWN | WS_VSCROLL |
+ WS_TABSTOP
+ CONTROL "Bold",IDC_BOLD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,
+ 88,45,10
+ CONTROL "Italic",IDC_ITALIC,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,65,88,52,10
+ CONTROL "Underline",IDC_UNDERLINE,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,117,88,66,10
+ CONTROL "",IDC_COLOUR,"ColourPicker",WS_TABSTOP,206,87,59,12
+ EDITTEXT IDC_SAMPLE,63,104,151,16,ES_CENTER | ES_READONLY | NOT
+ WS_TABSTOP
+ GROUPBOX "Rows",IDC_STATIC,4,134,269,31
+ LTEXT "Row height:",IDC_STATIC,12,148,65,8
+ EDITTEXT IDC_ROWHEIGHT,77,146,31,12,ES_RIGHT | ES_NUMBER
+ CONTROL "Spin1",IDC_ROWHEIGHTSPIN,"msctls_updown32",
+ UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY |
+ UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,97,145,10,
+ 14
+ LTEXT "pixels",IDC_STATIC,112,148,62,8
+ GROUPBOX "Additional Colours",IDC_STATIC,4,171,269,65
+ LTEXT "Selected text:",IDC_STATIC,12,186,65,8
+ CONTROL "",IDC_SELCOLOUR,"ColourPicker",WS_TABSTOP,77,184,29,12
+ LTEXT "Hottrack text:",IDC_STATIC,12,202,65,8
+ CONTROL "",IDC_HOTCOLOUR,"ColourPicker",WS_TABSTOP,77,200,29,12
+ CONTROL "Gamma correction",IDC_GAMMACORRECT,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,119,201,117,10
+ LTEXT "Quicksearch text:",IDC_STATIC,12,218,65,8
+ CONTROL "",IDC_QUICKCOLOUR,"ColourPicker",WS_TABSTOP,77,216,29,
+ 12
+ LTEXT "Size:",IDC_STSIZETEXT,231,114,34,8,NOT WS_VISIBLE
+ LTEXT "Colour:",IDC_STCOLOURTEXT,228,102,37,8,NOT WS_VISIBLE
+END
+
+IDD_OPT_CLCBKG DIALOGEX 0, 0, 235, 154
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Contact List Background",IDC_STATIC,4,4,227,146
+ LTEXT "Background colour",IDC_STATIC,59,35,72,8,NOT WS_GROUP
+ CONTROL "",IDC_BKGCOLOUR,"ColourPicker",WS_TABSTOP,22,35,32,10
+ LTEXT "Selection colour",IDC_STATIC,59,51,72,8
+ CONTROL "",IDC_SELCOLOUR,"ColourPicker",WS_TABSTOP,22,51,32,10
+ CONTROL "Use background image",IDC_BITMAP,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,12,70,161,10
+ EDITTEXT IDC_FILENAME,22,88,184,12,ES_AUTOHSCROLL
+ PUSHBUTTON "...",IDC_BROWSE,208,88,15,11
+ CONTROL "Stretch to width",IDC_STRETCHH,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,22,105,100,10
+ CONTROL "Stretch to height",IDC_STRETCHV,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,122,105,101,10
+ CONTROL "Tile horizontally",IDC_TILEH,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,22,118,100,10
+ CONTROL "Tile vertically",IDC_TILEV,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,122,118,101,10
+ CONTROL "Scroll with text",IDC_SCROLL,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,22,131,100,10
+ CONTROL "Stretch proportionally",IDC_PROPORTIONAL,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,122,131,101,10
+ CONTROL "Use Windows colours",IDC_WINCOLOUR,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,12,20,156,10
+END
+
+IDD_OPT_SBAR DIALOGEX 0, 0, 178, 212
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Status Bar",IDC_STATIC,4,4,170,204
+ CONTROL "Show status bar",IDC_SHOWSBAR,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,12,17,152,10
+ CONTROL "Show icons",IDC_SHOWICON,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,22,33,142,10
+ CONTROL "Show protocol names",IDC_SHOWPROTO,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,22,48,142,10
+ CONTROL "Show status text",IDC_SHOWSTATUS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,22,63,142,10
+ CONTROL "Right click opens status menu",IDC_RIGHTSTATUS,"Button",
+ BS_AUTORADIOBUTTON,22,160,142,10
+ CONTROL "Right click opens Miranda IM menu",IDC_RIGHTMIRANDA,
+ "Button",BS_AUTORADIOBUTTON,22,147,142,10
+ CONTROL "Make sections equal width",IDC_EQUALSECTIONS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,22,78,142,10
+ CONTROL "Show bevels on panels",IDC_SBPANELBEVEL,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,22,94,107,10
+ CONTROL "Show resize grip indicator",IDC_SHOWGRIP,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,22,110,96,10
+END
+
+IDD_OPT_CLCTEXTSIMPLE DIALOGEX 0, 0, 277, 240
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Fonts",IDC_STATIC,4,4,269,125
+ COMBOBOX IDC_FONTID,12,17,253,87,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ LTEXT "as:",IDC_STASTEXT,25,34,52,10,SS_CENTERIMAGE
+ COMBOBOX IDC_SAMEAS,77,33,163,88,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ CONTROL "",IDC_STHORZBAR,"Static",SS_ETCHEDHORZ,9,51,259,1
+ COMBOBOX IDC_TYPEFACE,12,58,172,182,CBS_DROPDOWN | CBS_SORT |
+ WS_VSCROLL | WS_TABSTOP
+ COMBOBOX IDC_SCRIPT,192,58,73,68,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ LTEXT "Size:",IDC_STSIZETEXT,33,76,34,8
+ COMBOBOX IDC_FONTSIZE,67,74,54,69,CBS_DROPDOWN | WS_VSCROLL |
+ WS_TABSTOP
+ LTEXT "Colour:",IDC_STCOLOURTEXT,147,76,37,8
+ CONTROL "",IDC_COLOUR,"ColourPicker",WS_TABSTOP,184,74,59,12
+ CONTROL "Bold",IDC_BOLD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,58,
+ 90,45,10
+ CONTROL "Italic",IDC_ITALIC,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,117,90,52,10
+ CONTROL "Underline",IDC_UNDERLINE,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,179,90,66,10
+ EDITTEXT IDC_SAMPLE,63,104,151,16,ES_CENTER | ES_READONLY | NOT
+ WS_TABSTOP
+ GROUPBOX "Rows",IDC_STATIC,4,134,269,31
+ LTEXT "Row height:",IDC_STATIC,12,148,65,8
+ EDITTEXT IDC_ROWHEIGHT,77,146,31,12,ES_RIGHT | ES_NUMBER
+ CONTROL "Spin1",IDC_ROWHEIGHTSPIN,"msctls_updown32",
+ UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY |
+ UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,97,145,10,
+ 14
+ LTEXT "pixels",IDC_STATIC,112,148,62,8
+ GROUPBOX "Additional Colours",IDC_STATIC,4,171,269,65
+ LTEXT "Selected text:",IDC_STATIC,12,186,65,8
+ CONTROL "",IDC_SELCOLOUR,"ColourPicker",WS_TABSTOP,77,184,29,12
+ LTEXT "Hottrack text:",IDC_STATIC,12,202,65,8
+ CONTROL "",IDC_HOTCOLOUR,"ColourPicker",WS_TABSTOP,77,200,29,12
+ LTEXT "Quicksearch text:",IDC_STATIC,12,218,65,8
+ CONTROL "",IDC_QUICKCOLOUR,"ColourPicker",WS_TABSTOP,77,216,29,
+ 12
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_DELETECONTACT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 277
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 85
+ END
+
+ IDD_OPT_HOTKEY, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 234
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 132
+ HORZGUIDE, 23
+ HORZGUIDE, 40
+ HORZGUIDE, 57
+ END
+
+ IDD_OPT_CLIST, DIALOG
+ BEGIN
+ LEFTMARGIN, 2
+ RIGHTMARGIN, 312
+ VERTGUIDE, 10
+ VERTGUIDE, 107
+ TOPMARGIN, 2
+ BOTTOMMARGIN, 202
+ HORZGUIDE, 179
+ HORZGUIDE, 196
+ END
+
+ IDD_OPT_CLUI, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 309
+ VERTGUIDE, 13
+ VERTGUIDE, 23
+ VERTGUIDE, 112
+ VERTGUIDE, 141
+ VERTGUIDE, 151
+ VERTGUIDE, 175
+ VERTGUIDE, 242
+ VERTGUIDE, 246
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 241
+ HORZGUIDE, 18
+ HORZGUIDE, 39
+ HORZGUIDE, 75
+ HORZGUIDE, 180
+ HORZGUIDE, 196
+ END
+
+ IDD_OPT_CLC, DIALOG
+ BEGIN
+ LEFTMARGIN, 2
+ RIGHTMARGIN, 312
+ VERTGUIDE, 11
+ VERTGUIDE, 164
+ VERTGUIDE, 216
+ TOPMARGIN, 2
+ BOTTOMMARGIN, 249
+ HORZGUIDE, 145
+ HORZGUIDE, 163
+ HORZGUIDE, 222
+ END
+
+ IDD_OPT_CLCTEXT, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 273
+ VERTGUIDE, 12
+ VERTGUIDE, 19
+ VERTGUIDE, 77
+ VERTGUIDE, 258
+ VERTGUIDE, 265
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 236
+ HORZGUIDE, 37
+ HORZGUIDE, 51
+ HORZGUIDE, 79
+ HORZGUIDE, 94
+ HORZGUIDE, 152
+ HORZGUIDE, 190
+ HORZGUIDE, 206
+ HORZGUIDE, 222
+ END
+
+ IDD_OPT_CLCBKG, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 231
+ VERTGUIDE, 12
+ VERTGUIDE, 22
+ VERTGUIDE, 122
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 150
+ HORZGUIDE, 24
+ HORZGUIDE, 35
+ HORZGUIDE, 73
+ HORZGUIDE, 89
+ HORZGUIDE, 102
+ HORZGUIDE, 115
+ END
+
+ IDD_OPT_SBAR, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 174
+ VERTGUIDE, 12
+ VERTGUIDE, 22
+ VERTGUIDE, 164
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 208
+ END
+
+ IDD_OPT_CLCTEXTSIMPLE, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 273
+ VERTGUIDE, 12
+ VERTGUIDE, 19
+ VERTGUIDE, 77
+ VERTGUIDE, 258
+ VERTGUIDE, 265
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 236
+ HORZGUIDE, 37
+ HORZGUIDE, 64
+ HORZGUIDE, 80
+ HORZGUIDE, 95
+ HORZGUIDE, 152
+ HORZGUIDE, 190
+ HORZGUIDE, 206
+ HORZGUIDE, 222
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include <windows.h>\r\n"
+ "#include <winres.h>\r\n"
+ "#include <statusmodes.h>\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_RENAME ICON "res\\rename.ico"
+IDI_BLANK ICON "res\\blank.ico"
+IDI_DELETE ICON "res\\delete.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Cursor
+//
+
+IDC_HYPERLINKHAND CURSOR "res\\hyperlin.cur"
+IDC_DROP CURSOR "res\\dragcopy.cur"
+IDC_DROPUSER CURSOR "res\\dropuser.cur"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_CLISTMENU MENU
+BEGIN
+ POPUP "&¤"
+ BEGIN
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit", ID_ICQ_EXIT
+ END
+ POPUP "&Status"
+ BEGIN
+ MENUITEM "&Offline\tCtrl+0", ID_STATUS_OFFLINE, CHECKED
+ MENUITEM "On&line\tCtrl+1", ID_STATUS_ONLINE
+ MENUITEM "&Away\tCtrl+2", ID_STATUS_AWAY
+ MENUITEM "&NA\tCtrl+3", ID_STATUS_NA
+ MENUITEM "Occ&upied\tCtrl+4", ID_STATUS_OCCUPIED
+ MENUITEM "&DND\tCtrl+5", ID_STATUS_DND
+ MENUITEM "&Free for chat\tCtrl+6", ID_STATUS_FREECHAT
+ MENUITEM "&Invisible\tCtrl+7", ID_STATUS_INVISIBLE
+ MENUITEM "On the &Phone\tCtrl+8", ID_STATUS_ONTHEPHONE
+ MENUITEM "Out to &Lunch\tCtrl+9", ID_STATUS_OUTTOLUNCH
+ END
+END
+
+IDR_CONTEXT MENU
+BEGIN
+ POPUP "Tray"
+ BEGIN
+ MENUITEM "&Hide/Show", ID_TRAY_HIDE
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit", ID_TRAY_EXIT
+ END
+ POPUP "Nowhere"
+ BEGIN
+ MENUITEM "&New Group", POPUP_NEWGROUP
+ MENUITEM SEPARATOR
+ MENUITEM "&Hide Offline Users", POPUP_HIDEOFFLINE
+ MENUITEM "Hide &Offline Users out here", POPUP_HIDEOFFLINEROOT
+ MENUITEM "Hide &Empty Groups", POPUP_HIDEEMPTYGROUPS
+ MENUITEM "Disable &Groups", POPUP_DISABLEGROUPS
+ MENUITEM SEPARATOR
+ MENUITEM "Hide Miranda", POPUP_HIDEMIRANDA
+ END
+ POPUP "Group"
+ BEGIN
+ MENUITEM "&New Subgroup", POPUP_NEWSUBGROUP
+ MENUITEM "&Hide Offline Users in here", POPUP_GROUPHIDEOFFLINE
+ MENUITEM SEPARATOR
+ MENUITEM "&Rename Group", POPUP_RENAMEGROUP
+ MENUITEM "&Delete Group", POPUP_DELETEGROUP
+ END
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/miranda-wine/plugins/db3x/Makefile b/miranda-wine/plugins/db3x/Makefile
new file mode 100644
index 0000000..5a75630
--- /dev/null
+++ b/miranda-wine/plugins/db3x/Makefile
@@ -0,0 +1,53 @@
+SRC = commonheaders.c \
+ database.c \
+ dbcache.c \
+ dbcontacts.c \
+ dbevents.c \
+ dbheaders.c \
+ dbini.c \
+ dblists.c \
+ dbmodulechain.c \
+ dbsettings.c \
+ dbtime.c \
+ encrypt.c \
+ init.c
+OBJ = $(SRC:.c=.o)
+RES = resource.res
+LIB = -lgdi32 -lversion -lcomctl32 -lcomdlg32 -lole32
+
+CC = gcc
+RC = windres
+RM = rm
+
+# Install location
+ifdef DEBUG
+BIN = ..\..\bin\debug\plugins\dbx_3x.dll
+else
+BIN = ..\..\bin\release\plugins\dbx_3x.dll
+endif
+
+# Defines
+DEFINES = -DWIN32 -D__SEH_NOOP
+ifdef DEBUG
+DEFINES := $(DEFINES) -D_DEBUG
+endif
+
+# Flags
+LFLAGS = -shared
+RCFLAGS = --input-format rc --output-format coff
+ifdef DEBUG
+CFLAGS = -g $(DEFINES) -I../../include
+else
+CFLAGS = -O1 $(DEFINES) -I../../include
+endif
+
+# Targets
+all : $(OBJ) $(RES)
+ $(CC) $(LFLAGS) $(CFLAGS) -o $(BIN) $(OBJ) $(RES) $(LIB) -Wl
+
+$(RES) : $(RES:.res=.rc) $(RES:.res=.h) Makefile
+ $(RC) $(RCFLAGS) -o $(RES) -i $(RES:.res=.rc)
+
+clean :
+ $(RM) -f $(OBJ) $(RES)
+
diff --git a/miranda-wine/plugins/db3x/commonheaders.c b/miranda-wine/plugins/db3x/commonheaders.c
new file mode 100644
index 0000000..14f99f7
--- /dev/null
+++ b/miranda-wine/plugins/db3x/commonheaders.c
@@ -0,0 +1 @@
+#include "commonheaders.h"
diff --git a/miranda-wine/plugins/db3x/commonheaders.h b/miranda-wine/plugins/db3x/commonheaders.h
new file mode 100644
index 0000000..c0a8146
--- /dev/null
+++ b/miranda-wine/plugins/db3x/commonheaders.h
@@ -0,0 +1,66 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 _WIN32_WINNT 0x0501
+#include <windows.h>
+
+#include <malloc.h>
+
+#ifdef _DEBUG
+# define _ALPHA_BASE_ 1 // defined for CVS builds
+# define _ALPHA_FUSE_ 1 // defined for fuse powered core
+# define _CRTDBG_MAP_ALLOC
+# include <stdlib.h>
+# include <crtdbg.h>
+#endif
+
+#include <commctrl.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <stddef.h>
+#include <process.h>
+#include <io.h>
+#include <string.h>
+#include <direct.h>
+#include "resource.h"
+#include <newpluginapi.h>
+#include <win2k.h>
+#include <m_system.h>
+#include <m_database.h>
+#include <m_langpack.h>
+
+extern PLUGINLINK *pluginLink;
+
+extern struct MM_INTERFACE memoryManagerInterface;
+extern struct LIST_INTERFACE li;
+
+#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)
+
+#ifdef __GNUC__
+#define mir_i64(x) (x##LL)
+#else
+#define mir_i64(x) (x##i64)
+#endif
diff --git a/miranda-wine/plugins/db3x/database.c b/miranda-wine/plugins/db3x/database.c
new file mode 100644
index 0000000..38843a7
--- /dev/null
+++ b/miranda-wine/plugins/db3x/database.c
@@ -0,0 +1,186 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "database.h"
+
+int ProfileManager(char *szDbDest,int cbDbDest);
+int ShouldAutoCreate(void);
+int CreateDbHeaders(HANDLE hFile);
+int InitialiseDbHeaders(void);
+int InitSettings(void);
+void UninitSettings(void);
+int InitContacts(void);
+void UninitContacts(void);
+int InitEvents(void);
+void UninitEvents(void);
+int InitCrypt(void);
+int InitTime(void);
+int InitModuleNames(void);
+void UninitModuleNames(void);
+int InitCache(void);
+void UninitCache(void);
+int InitIni(void);
+void UninitIni(void);
+
+HANDLE hDbFile=INVALID_HANDLE_VALUE;
+CRITICAL_SECTION csDbAccess;
+struct DBHeader dbHeader;
+char szDbPath[MAX_PATH];
+
+static void UnloadDatabase(void)
+{
+ CloseHandle(hDbFile);
+}
+
+DWORD CreateNewSpace(int bytes)
+{
+ DWORD ofsNew;
+
+ ofsNew=dbHeader.ofsFileEnd;
+ dbHeader.ofsFileEnd+=bytes;
+ DBWrite(0,&dbHeader,sizeof(dbHeader));
+ log2("newspace %d@%08x",bytes,ofsNew);
+ return ofsNew;
+}
+
+void DeleteSpace(DWORD ofs,int bytes)
+{
+ PBYTE buf;
+ log2("deletespace %d@%08x",bytes,ofs);
+ dbHeader.slackSpace+=bytes;
+ DBWrite(0,&dbHeader,sizeof(dbHeader));
+ buf=(PBYTE)mir_alloc(bytes);
+ memset(buf,0,bytes);
+ DBWrite(ofs,buf,bytes);
+ mir_free(buf);
+}
+
+void UnloadDatabaseModule(void)
+{
+ //UninitIni();
+ UninitEvents();
+ UninitSettings();
+ UninitContacts();
+ UninitModuleNames();
+ UninitCache();
+ UnloadDatabase();
+ DeleteCriticalSection(&csDbAccess);
+}
+
+static int GetProfileName(WPARAM wParam, LPARAM lParam)
+{
+ char * p = 0;
+ p = strrchr(szDbPath, '\\');
+ if ( p == 0 ) return 1;
+ p++;
+ strncpy((char*)lParam, p, (size_t) wParam);
+ return 0;
+}
+
+static int GetProfilePath(WPARAM wParam, LPARAM lParam)
+{
+ char * dst = (char*)lParam;
+ char * p = 0;
+ strncpy(dst,szDbPath,wParam);
+ p = strrchr(dst, '\\');
+ if ( p == NULL ) return 1;
+ *p=0;
+ return 0;
+}
+
+int LoadDatabaseModule(void)
+{
+ InitializeCriticalSection(&csDbAccess);
+ log0("DB logging running");
+ {
+ DWORD dummy=0;
+ hDbFile=CreateFile(szDbPath,GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, 0, NULL);
+ if ( hDbFile == INVALID_HANDLE_VALUE ) {
+ return 1;
+ }
+ if ( !ReadFile(hDbFile,&dbHeader,sizeof(dbHeader),&dummy,NULL) ) {
+ CloseHandle(hDbFile);
+ return 1;
+ }
+ }
+ //if(ParseCommandLine()) return 1;
+ if(InitCache()) return 1;
+ if(InitModuleNames()) return 1;
+ if(InitContacts()) return 1;
+ if(InitSettings()) return 1;
+ if(InitEvents()) return 1;
+ if(InitCrypt()) return 1;
+ //if(InitTime()) return 1;
+ //if(InitIni()) return 1;
+ CreateServiceFunction(MS_DB_GETPROFILENAME,GetProfileName);
+ CreateServiceFunction(MS_DB_GETPROFILEPATH,GetProfilePath);
+ return 0;
+}
+
+static DWORD DatabaseCorrupted=0;
+
+void __cdecl dbpanic(void *arg)
+{
+
+ MessageBox(0,Translate("Miranda has detected corruption in your database. This corruption maybe fixed by DBTool. Please download it from http://www.miranda-im.org. Miranda will now shutdown."),Translate("Database Panic"),MB_SETFOREGROUND|MB_TOPMOST|MB_APPLMODAL|MB_ICONWARNING|MB_OK);
+ TerminateProcess(GetCurrentProcess(),255);
+ return;
+}
+
+void DatabaseCorruption(void)
+{
+ int kill=0;
+
+ EnterCriticalSection(&csDbAccess);
+ if (DatabaseCorrupted==0) {
+ DatabaseCorrupted++;
+ kill++;
+ } else {
+ /* db is already corrupted, someone else is dealing with it, wait here
+ so that we don't do any more damage */
+ LeaveCriticalSection(&csDbAccess);
+ Sleep(INFINITE);
+ return;
+ }
+ LeaveCriticalSection(&csDbAccess);
+ if (kill) {
+ _beginthread(dbpanic,0,NULL);
+ Sleep(INFINITE);
+ }
+}
+
+#ifdef DBLOGGING
+void DBLog(const char *file,int line,const char *fmt,...)
+{
+ FILE *fp;
+ va_list vararg;
+ char str[1024];
+
+ va_start(vararg,fmt);
+ mir_vsnprintf(str,sizeof(str),fmt,vararg);
+ va_end(vararg);
+ fp=fopen("c:\\mirandadatabase.log.txt","at");
+ fprintf(fp,"%u: %s %d: %s\n",GetTickCount(),file,line,str);
+ fclose(fp);
+}
+#endif
diff --git a/miranda-wine/plugins/db3x/database.h b/miranda-wine/plugins/db3x/database.h
new file mode 100644
index 0000000..d2a6a8f
--- /dev/null
+++ b/miranda-wine/plugins/db3x/database.h
@@ -0,0 +1,218 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+
+//all offsets are relative to the start of the file
+//offsets are 0 if there is nothing in the chain or this is the last in the
+//chain
+
+/* tree diagram
+
+DBHeader
+ |-->end of file (plain offset)
+ |-->first contact (DBContact)
+ | |-->next contact (DBContact)
+ | | \--> ...
+ | |-->first settings (DBContactSettings)
+ | | |-->next settings (DBContactSettings)
+ | | | \--> ...
+ | | \-->module name (DBModuleName)
+ | \-->first/last/firstunread event
+ |-->user contact (DBContact)
+ | |-->next contact=NULL
+ | |-->first settings as above
+ | \-->first/last/firstunread event as above
+ \-->first module name (DBModuleName)
+ \-->next module name (DBModuleName)
+ \--> ...
+*/
+
+#define DB_RESIZE_GRANULARITY 16384
+#define DB_THIS_VERSION 0x00000700u
+#define DB_SETTINGS_RESIZE_GRANULARITY 128
+
+#include <pshpack1.h>
+struct DBHeader {
+ BYTE signature[16]; // 'Miranda ICQ DB',0,26
+ DWORD version; //as 4 bytes, ie 1.2.3.10=0x0102030a
+ //this version is 0x00000700
+ DWORD ofsFileEnd; //offset of the end of the database - place to write
+ //new structures
+ DWORD slackSpace; //a counter of the number of bytes that have been
+ //wasted so far due to deleting structures and/or
+ //re-making them at the end. We should compact when
+ //this gets above a threshold
+ DWORD contactCount; //number of contacts in the chain,excluding the user
+ DWORD ofsFirstContact; //offset to first struct DBContact in the chain
+ DWORD ofsUser; //offset to struct DBContact representing the user
+ DWORD ofsFirstModuleName; //offset to first struct DBModuleName in the chain
+};
+
+#define DBCONTACT_SIGNATURE 0x43DECADEu
+struct DBContact {
+ DWORD signature;
+ DWORD ofsNext; //offset to the next contact in the chain. zero if
+ //this is the 'user' contact or the last contact
+ //in the chain
+ DWORD ofsFirstSettings; //offset to the first DBContactSettings in the
+ //chain for this contact.
+ DWORD eventCount; //number of events in the chain for this contact
+ DWORD ofsFirstEvent,ofsLastEvent; //offsets to the first and last DBEvent in
+ //the chain for this contact
+ DWORD ofsFirstUnreadEvent; //offset to the first (chronological) unread event
+ //in the chain, 0 if all are read
+ DWORD timestampFirstUnread; //timestamp of the event at ofsFirstUnreadEvent
+};
+
+#define DBMODULENAME_SIGNATURE 0x4DDECADEu
+struct DBModuleName {
+ DWORD signature;
+ DWORD ofsNext; //offset to the next module name in the chain
+ BYTE cbName; //number of characters in this module name
+ char name[1]; //name, no nul terminator
+};
+
+#define DBCONTACTSETTINGS_SIGNATURE 0x53DECADEu
+struct DBContactSettings {
+ DWORD signature;
+ DWORD ofsNext; //offset to the next contactsettings in the chain
+ DWORD ofsModuleName; //offset to the DBModuleName of the owner of these
+ //settings
+ DWORD cbBlob; //size of the blob in bytes. May be larger than the
+ //actual size for reducing the number of moves
+ //required using granularity in resizing
+ BYTE blob[1]; //the blob. a back-to-back sequence of DBSetting
+ //structs, the last has cbName=0
+};
+
+/* not a valid structure, content is figured out on the fly
+struct DBSetting {
+ BYTE cbName; //number of bytes in the name of this setting
+ //this =0 marks the end
+ char szName[...]; //setting name, excluding nul
+ BYTE dataType; //type of data. see m_database.h, db/contact/getsetting
+ union { //a load of types of data, length is defined by dataType
+ BYTE bVal; WORD wVal; DWORD dVal;
+ struct {
+ WORD cbString;
+ char szVal[...]; //excludes nul terminator
+ };
+ struct {
+ WORD cbBlob;
+ BYTE blobVal[...];
+ };
+ };
+};
+*/
+
+#define DBEVENT_SIGNATURE 0x45DECADEu
+struct DBEvent {
+ DWORD signature;
+ DWORD ofsPrev,ofsNext; //offset to the previous and next events in the
+ //chain. Chain is sorted chronologically
+ DWORD ofsModuleName; //offset to a DBModuleName struct of the name of
+ //the owner of this event
+ DWORD timestamp; //seconds since 00:00:00 01/01/1970
+ DWORD flags; //see m_database.h, db/event/add
+ WORD eventType; //module-defined event type
+ DWORD cbBlob; //number of bytes in the blob
+ BYTE blob[1]; //the blob. module-defined formatting
+};
+#include <poppack.h>
+
+typedef struct
+{
+ BYTE bIsResident;
+ char name[1];
+}
+ DBCachedSettingName;
+
+typedef struct
+{
+ char* name;
+ DBVARIANT value;
+}
+ DBCachedGlobalValue;
+
+typedef struct DBCachedContactValue_tag
+{
+ char* name;
+ DBVARIANT value;
+ struct DBCachedContactValue_tag* next;
+}
+ DBCachedContactValue;
+
+typedef struct
+{
+ HANDLE hContact;
+ HANDLE hNext;
+ DBCachedContactValue* first;
+}
+ DBCachedContactValueList;
+
+
+//databasecorruption: called if any signatures are broken. very very fatal
+void DatabaseCorruption(void);
+PBYTE DBRead(DWORD ofs,int bytesRequired,int *bytesAvail); //any preview result could be invalidated by the next call
+void DBWrite(DWORD ofs,PVOID pData,int count);
+void DBFlush(int setting);
+void DBMoveChunk(DWORD ofsDest,DWORD ofsSource,int bytes);
+DWORD CreateNewSpace(int bytes);
+void DeleteSpace(DWORD ofs,int bytes);
+void GetProfileDirectory(char *szPath,int cbPath);
+int GetDefaultProfilePath(char *szPath,int cbPath,int *specified);
+int ShouldShowProfileManager(void);
+int CheckDbHeaders(struct DBHeader * hdr);
+int CreateDbHeaders(HANDLE hFile);
+int LoadDatabaseModule(void);
+void UnloadDatabaseModule(void);
+
+void Utf8Decode( char* str, wchar_t** ucs2 );
+char* Utf8Encode( const char* src );
+char* Utf8EncodeUcs2( const wchar_t* src );
+
+#ifdef _DEBUG
+#define MAXCACHEDREADSIZE 512
+#else
+#define MAXCACHEDREADSIZE 2048 //push it to 1K //technically 4096 would work, but I'm not going to push it
+#endif
+
+#ifdef _DEBUG
+//#define DBLOGGING
+#endif
+#ifdef DBLOGGING
+void DBLog(const char *file,int line,const char *fmt,...);
+#define logg() DBLog(__FILE__,__LINE__,"")
+#define log0(s) DBLog(__FILE__,__LINE__,s)
+#define log1(s,a) DBLog(__FILE__,__LINE__,s,a)
+#define log2(s,a,b) DBLog(__FILE__,__LINE__,s,a,b)
+#define log3(s,a,b,c) DBLog(__FILE__,__LINE__,s,a,b,c)
+#define log4(s,a,b,c,d) DBLog(__FILE__,__LINE__,s,a,b,c,d)
+#else
+#define logg()
+#define log0(s)
+#define log1(s,a)
+#define log2(s,a,b)
+#define log3(s,a,b,c)
+#define log4(s,a,b,c,d)
+#endif
diff --git a/miranda-wine/plugins/db3x/dbcache.c b/miranda-wine/plugins/db3x/dbcache.c
new file mode 100644
index 0000000..dd3bc5a
--- /dev/null
+++ b/miranda-wine/plugins/db3x/dbcache.c
@@ -0,0 +1,229 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "database.h"
+
+
+#define CACHESECTIONSIZE 4096
+#define CACHESECTIONCOUNT 32
+
+extern HANDLE hDbFile;
+extern CRITICAL_SECTION csDbAccess;
+
+static BOOL safetyMode=TRUE;
+static PBYTE pDbCache;
+static DWORD lastUseCounter;
+struct DBCacheSectionInfo {
+ DWORD ofsBase;
+ DWORD lastUsed;
+} static cacheSectionInfo[CACHESECTIONCOUNT];
+
+static __inline int FindSectionForOffset(const DWORD ofs)
+{
+ int i;
+ for(i=0;i<CACHESECTIONCOUNT;i++)
+ if(ofs>=cacheSectionInfo[i].ofsBase && ofs<cacheSectionInfo[i].ofsBase+CACHESECTIONSIZE)
+ return i;
+ return -1;
+}
+
+static __inline int FindLRUSection(void)
+{
+ int i,lru=0;
+ DWORD lowestLastUse=cacheSectionInfo[0].lastUsed;
+ for(i=1;i<CACHESECTIONCOUNT;i++) if(cacheSectionInfo[i].lastUsed<lowestLastUse) {lru=i; lowestLastUse=cacheSectionInfo[i].lastUsed;}
+ return lru;
+}
+
+static __inline void LoadSection(const int i,DWORD ofs)
+{
+ cacheSectionInfo[i].ofsBase=ofs-ofs%CACHESECTIONSIZE;
+ log1("readsect %08x",ofs);
+ SetFilePointer(hDbFile,cacheSectionInfo[i].ofsBase,NULL,FILE_BEGIN);
+ ReadFile(hDbFile,pDbCache+i*CACHESECTIONSIZE,CACHESECTIONSIZE,&ofs,NULL);
+}
+
+static __inline void MoveSection(int *sectId,int dest)
+{
+ CopyMemory(pDbCache+dest*CACHESECTIONSIZE,pDbCache+(*sectId)*CACHESECTIONSIZE,CACHESECTIONSIZE);
+ cacheSectionInfo[dest].ofsBase=cacheSectionInfo[*sectId].ofsBase;
+ *sectId=dest;
+}
+
+
+
+//we are assumed to be in a mutex here
+PBYTE DBRead(DWORD ofs,int bytesRequired,int *bytesAvail)
+{
+
+ int part1sect;
+ int part2sect;
+
+
+ part1sect = FindSectionForOffset(ofs);
+ if (ofs%CACHESECTIONSIZE+bytesRequired<CACHESECTIONSIZE) {
+ //only one section required
+ if(part1sect==-1) {
+ part1sect=FindLRUSection();
+ LoadSection(part1sect,ofs);
+ }
+ cacheSectionInfo[part1sect].lastUsed=++lastUseCounter;
+ if(bytesAvail!=NULL) *bytesAvail=cacheSectionInfo[part1sect].ofsBase+CACHESECTIONSIZE-ofs;
+ return pDbCache+part1sect*CACHESECTIONSIZE+(ofs-cacheSectionInfo[part1sect].ofsBase);
+ }
+ //two sections are required
+ part2sect=FindSectionForOffset(ofs+CACHESECTIONSIZE);
+ if(part1sect!=-1) {
+ if(part2sect==-1) { //first part in cache, but not second part
+ if(part1sect==CACHESECTIONCOUNT-1) MoveSection(&part1sect,0);
+ LoadSection(part1sect+1,ofs+CACHESECTIONSIZE);
+ }
+ else if(part2sect!=part1sect+1) { //both parts are in cache, but not already consecutive
+ if(part1sect==CACHESECTIONCOUNT-1) {
+ //first part is at end, move to before second part
+ if(part2sect==0) //second part is at start: need to move both
+ MoveSection(&part2sect,1);
+ MoveSection(&part1sect,part2sect-1);
+ }
+ else //move second part to after first part
+ MoveSection(&part2sect,part1sect+1);
+ }
+ }
+ else {
+ if(part2sect==-1) { //neither section is in cache
+ part1sect=0; part2sect=1;
+ LoadSection(part1sect,ofs); LoadSection(part2sect,ofs+CACHESECTIONSIZE);
+ }
+ else { //part 2 is in cache, but not part 1
+ if(part2sect==0) MoveSection(&part2sect,1);
+ part1sect=part2sect-1;
+ LoadSection(part1sect,ofs);
+ }
+ }
+ //both sections are now consecutive, starting at part1sect
+ cacheSectionInfo[part1sect].lastUsed=++lastUseCounter;
+ cacheSectionInfo[part1sect+1].lastUsed=++lastUseCounter;
+ if(bytesAvail!=NULL) *bytesAvail=cacheSectionInfo[part1sect+1].ofsBase+CACHESECTIONSIZE-ofs;
+ return pDbCache+part1sect*CACHESECTIONSIZE+(ofs-cacheSectionInfo[part1sect].ofsBase);
+}
+
+
+
+//we are assumed to be in a mutex here
+void DBWrite(DWORD ofs,PVOID pData,int bytes)
+{
+ //write direct, and rely on Windows' write caching
+ DWORD bytesWritten;
+ int i;
+
+ log2("write %d@%08x",bytes,ofs);
+ SetFilePointer(hDbFile,ofs,NULL,FILE_BEGIN);
+ if (WriteFile(hDbFile,pData,bytes,&bytesWritten,NULL)==0)
+ {
+ DatabaseCorruption();
+ }
+ logg();
+ //check if any of the cache sections contain this bit
+ for(i=0;i<CACHESECTIONCOUNT;i++) {
+ if(ofs+bytes>=cacheSectionInfo[i].ofsBase && ofs<cacheSectionInfo[i].ofsBase+CACHESECTIONSIZE) {
+ if(ofs<cacheSectionInfo[i].ofsBase) { //don't start at beginning
+ if(ofs+bytes>=cacheSectionInfo[i].ofsBase+CACHESECTIONSIZE) //don't finish at end
+ CopyMemory(pDbCache+i*CACHESECTIONSIZE,(PBYTE)pData+cacheSectionInfo[i].ofsBase-ofs,CACHESECTIONSIZE);
+ else CopyMemory(pDbCache+i*CACHESECTIONSIZE,(PBYTE)pData+cacheSectionInfo[i].ofsBase-ofs,bytes-(cacheSectionInfo[i].ofsBase-ofs));
+ }
+ else { //start at beginning
+ if(ofs+bytes>=cacheSectionInfo[i].ofsBase+CACHESECTIONSIZE) //don't finish at end
+ CopyMemory(pDbCache+i*CACHESECTIONSIZE+ofs-cacheSectionInfo[i].ofsBase,pData,cacheSectionInfo[i].ofsBase+CACHESECTIONSIZE-ofs);
+ else CopyMemory(pDbCache+i*CACHESECTIONSIZE+ofs-cacheSectionInfo[i].ofsBase,pData,bytes);
+ }
+ }
+ }
+}
+
+void DBMoveChunk(DWORD ofsDest,DWORD ofsSource,int bytes)
+{
+ DWORD bytesRead;
+ PBYTE buf;
+
+ log3("move %d %08x->%08x",bytes,ofsSource,ofsDest);
+ buf=(PBYTE)mir_alloc(bytes);
+ SetFilePointer(hDbFile,ofsSource,NULL,FILE_BEGIN);
+ ReadFile(hDbFile,buf,bytes,&bytesRead,NULL);
+ DBWrite(ofsDest,buf,bytes);
+ mir_free(buf);
+ logg();
+}
+
+static int flushBuffersTimerId;
+static VOID CALLBACK DoBufferFlushTimerProc(HWND hwnd,UINT message,UINT idEvent,DWORD dwTime)
+{
+ KillTimer(NULL,flushBuffersTimerId);
+ log0("tflush1");
+ FlushFileBuffers(hDbFile);
+ log0("tflush2");
+}
+
+void DBFlush(int setting)
+{
+ if(!setting) {
+ log0("nflush1");
+ if(safetyMode) FlushFileBuffers(hDbFile);
+ log0("nflush2");
+ return;
+ }
+ KillTimer(NULL,flushBuffersTimerId);
+ flushBuffersTimerId=SetTimer(NULL,flushBuffersTimerId,50,DoBufferFlushTimerProc);
+}
+
+static int CacheSetSafetyMode(WPARAM wParam,LPARAM lParam)
+{
+ EnterCriticalSection(&csDbAccess);
+ safetyMode=wParam;
+ LeaveCriticalSection(&csDbAccess);
+ if(safetyMode) FlushFileBuffers(hDbFile);
+ return 0;
+}
+
+int InitCache(void)
+{
+ int i;
+ DWORD bytesRead;
+
+ CreateServiceFunction(MS_DB_SETSAFETYMODE,CacheSetSafetyMode);
+ pDbCache=(PBYTE)mir_alloc(CACHESECTIONSIZE*CACHESECTIONCOUNT);
+ lastUseCounter=CACHESECTIONCOUNT;
+ for(i=0;i<CACHESECTIONCOUNT;i++) {
+ cacheSectionInfo[i].ofsBase=0;
+ cacheSectionInfo[i].lastUsed=i;
+ SetFilePointer(hDbFile,cacheSectionInfo[i].ofsBase,NULL,FILE_BEGIN);
+ ReadFile(hDbFile,pDbCache+i*CACHESECTIONSIZE,CACHESECTIONSIZE,&bytesRead,NULL);
+ }
+ return 0;
+}
+
+void UninitCache(void)
+{
+ mir_free(pDbCache);
+ KillTimer(NULL,flushBuffersTimerId);
+}
diff --git a/miranda-wine/plugins/db3x/dbcontacts.c b/miranda-wine/plugins/db3x/dbcontacts.c
new file mode 100644
index 0000000..2a8d038
--- /dev/null
+++ b/miranda-wine/plugins/db3x/dbcontacts.c
@@ -0,0 +1,270 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "database.h"
+
+static int GetContactCount(WPARAM wParam,LPARAM lParam);
+static int FindFirstContact(WPARAM wParam,LPARAM lParam);
+static int FindNextContact(WPARAM wParam,LPARAM lParam);
+static int DeleteContact(WPARAM wParam,LPARAM lParam);
+static int AddContact(WPARAM wParam,LPARAM lParam);
+static int IsDbContact(WPARAM wParam,LPARAM lParam);
+
+extern CRITICAL_SECTION csDbAccess;
+extern struct DBHeader dbHeader;
+static HANDLE hContactDeletedEvent,hContactAddedEvent;
+
+extern HANDLE hCacheHeap;
+extern SortedList lContacts;
+
+int InitContacts(void)
+{
+ CreateServiceFunction(MS_DB_CONTACT_GETCOUNT,GetContactCount);
+ CreateServiceFunction(MS_DB_CONTACT_FINDFIRST,FindFirstContact);
+ CreateServiceFunction(MS_DB_CONTACT_FINDNEXT,FindNextContact);
+ CreateServiceFunction(MS_DB_CONTACT_DELETE,DeleteContact);
+ CreateServiceFunction(MS_DB_CONTACT_ADD,AddContact);
+ CreateServiceFunction(MS_DB_CONTACT_IS,IsDbContact);
+ hContactDeletedEvent=CreateHookableEvent(ME_DB_CONTACT_DELETED);
+ hContactAddedEvent=CreateHookableEvent(ME_DB_CONTACT_ADDED);
+ return 0;
+}
+
+void UninitContacts(void)
+{
+}
+
+static int GetContactCount(WPARAM wParam,LPARAM lParam)
+{
+ int ret;
+
+ EnterCriticalSection(&csDbAccess);
+ ret=dbHeader.contactCount;
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+}
+
+static int FindFirstContact(WPARAM wParam,LPARAM lParam)
+{
+ int ret = 0;
+ EnterCriticalSection(&csDbAccess);
+ ret = (int)(HANDLE)dbHeader.ofsFirstContact;
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+}
+
+static int FindNextContact(WPARAM wParam,LPARAM lParam)
+{
+ int ret, index;
+ struct DBContact *dbc;
+ DBCachedContactValueList *VL = NULL;
+
+ EnterCriticalSection(&csDbAccess);
+ {
+ DBCachedContactValueList VLtemp;
+ VLtemp.hContact = (HANDLE)wParam;
+ if ( li.List_GetIndex(&lContacts,&VLtemp,&index)) {
+ VL = ( DBCachedContactValueList* )lContacts.items[index];
+ if ( VL->hNext != NULL ) {
+ LeaveCriticalSection(&csDbAccess);
+ return (int)VL->hNext;
+ } } }
+
+ dbc=(struct DBContact*)DBRead(wParam,sizeof(struct DBContact),NULL);
+ if(dbc->signature!=DBCONTACT_SIGNATURE)
+ ret=(int)(HANDLE)NULL;
+ else {
+ if ( VL == NULL ) {
+ VL = (DBCachedContactValueList*)HeapAlloc(hCacheHeap,HEAP_NO_SERIALIZE+HEAP_ZERO_MEMORY,sizeof(DBCachedContactValueList));
+ VL->hContact = (HANDLE)wParam;
+ li.List_Insert(&lContacts,VL,index);
+ }
+ VL->hNext = (HANDLE)dbc->ofsNext;
+ ret=(int)(HANDLE)dbc->ofsNext;
+ }
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+}
+
+static int DeleteContact(WPARAM wParam,LPARAM lParam)
+{
+ struct DBContact *dbc,*dbcPrev;
+ DWORD ofsThis,ofsNext,ofsFirstEvent;
+ struct DBContactSettings *dbcs;
+ struct DBEvent *dbe;
+ int index;
+
+ if((HANDLE)wParam==NULL) return 1;
+ EnterCriticalSection(&csDbAccess);
+ dbc=(struct DBContact*)DBRead(wParam,sizeof(struct DBContact),NULL);
+ if(dbc->signature!=DBCONTACT_SIGNATURE) {
+ LeaveCriticalSection(&csDbAccess);
+ return 1;
+ }
+ if ( (HANDLE)wParam == (HANDLE)dbHeader.ofsUser ) {
+ LeaveCriticalSection(&csDbAccess);
+ log0("FATAL: del of user chain attempted.");
+ return 1;
+ }
+ log0("del contact");
+ LeaveCriticalSection(&csDbAccess);
+ //call notifier while outside mutex
+ NotifyEventHooks(hContactDeletedEvent,wParam,0);
+ //get back in
+ EnterCriticalSection(&csDbAccess);
+
+ { DBCachedContactValueList VLtemp;
+ VLtemp.hContact = (HANDLE)wParam;
+ if ( li.List_GetIndex(&lContacts,&VLtemp,&index))
+ {
+ DBCachedContactValueList *VL = ( DBCachedContactValueList* )lContacts.items[index];
+ DBCachedContactValue* V = VL->first;
+ while ( V != NULL ) {
+ DBCachedContactValue* V1 = V->next;
+ if ( V->value.type == DBVT_ASCIIZ )
+ HeapFree( hCacheHeap, HEAP_NO_SERIALIZE, V->value.pszVal );
+ HeapFree( hCacheHeap, HEAP_NO_SERIALIZE, V );
+ V = V1;
+ }
+ HeapFree( hCacheHeap, HEAP_NO_SERIALIZE, VL );
+
+ li.List_Remove(&lContacts,index);
+ } }
+
+ dbc=(struct DBContact*)DBRead(wParam,sizeof(struct DBContact),NULL);
+ //delete settings chain
+ ofsThis=dbc->ofsFirstSettings;
+ ofsFirstEvent=dbc->ofsFirstEvent;
+ while(ofsThis) {
+ dbcs=(struct DBContactSettings*)DBRead(ofsThis,sizeof(struct DBContactSettings),NULL);
+ ofsNext=dbcs->ofsNext;
+ DeleteSpace(ofsThis,offsetof(struct DBContactSettings,blob)+dbcs->cbBlob);
+ ofsThis=ofsNext;
+ }
+ //delete event chain
+ ofsThis=ofsFirstEvent;
+ while(ofsThis) {
+ dbe=(struct DBEvent*)DBRead(ofsThis,sizeof(struct DBEvent),NULL);
+ ofsNext=dbe->ofsNext;
+ DeleteSpace(ofsThis,offsetof(struct DBEvent,blob)+dbe->cbBlob);
+ ofsThis=ofsNext;
+ }
+ //find previous contact in chain and change ofsNext
+ dbc=(struct DBContact*)DBRead(wParam,sizeof(struct DBContact),NULL);
+ if(dbHeader.ofsFirstContact==wParam) {
+ dbHeader.ofsFirstContact=dbc->ofsNext;
+ DBWrite(0,&dbHeader,sizeof(dbHeader));
+ }
+ else {
+ ofsNext=dbc->ofsNext;
+ ofsThis=dbHeader.ofsFirstContact;
+ dbcPrev=(struct DBContact*)DBRead(ofsThis,sizeof(struct DBContact),NULL);
+ while(dbcPrev->ofsNext!=wParam) {
+ if(dbcPrev->ofsNext==0) DatabaseCorruption();
+ ofsThis=dbcPrev->ofsNext;
+ dbcPrev=(struct DBContact*)DBRead(ofsThis,sizeof(struct DBContact),NULL);
+ }
+ dbcPrev->ofsNext=ofsNext;
+ DBWrite(ofsThis,dbcPrev,sizeof(struct DBContact));
+ {
+ DBCachedContactValueList VLtemp;
+ VLtemp.hContact = (HANDLE)ofsThis;
+ if ( li.List_GetIndex(&lContacts,&VLtemp,&index))
+ {
+ DBCachedContactValueList *VL = ( DBCachedContactValueList* )lContacts.items[index];
+ VL->hNext = ( HANDLE )ofsNext;
+ } }
+ }
+ //delete contact
+ DeleteSpace(wParam,sizeof(struct DBContact));
+ //decrement contact count
+ dbHeader.contactCount--;
+ DBWrite(0,&dbHeader,sizeof(dbHeader));
+ DBFlush(0);
+ //quit
+ LeaveCriticalSection(&csDbAccess);
+ return 0;
+}
+
+static int AddContact(WPARAM wParam,LPARAM lParam)
+{
+ struct DBContact dbc;
+ DWORD ofsNew;
+
+ log0("add contact");
+ EnterCriticalSection(&csDbAccess);
+ ofsNew=CreateNewSpace(sizeof(struct DBContact));
+ dbc.signature=DBCONTACT_SIGNATURE;
+ dbc.eventCount=0;
+ dbc.ofsFirstEvent=dbc.ofsLastEvent=0;
+ dbc.ofsFirstSettings=0;
+ dbc.ofsNext=dbHeader.ofsFirstContact;
+ dbc.ofsFirstUnreadEvent=0;
+ dbc.timestampFirstUnread=0;
+ dbHeader.ofsFirstContact=ofsNew;
+ dbHeader.contactCount++;
+ DBWrite(ofsNew,&dbc,sizeof(struct DBContact));
+ DBWrite(0,&dbHeader,sizeof(dbHeader));
+ DBFlush(0);
+
+ { int index;
+
+ DBCachedContactValueList *VL = (DBCachedContactValueList*)HeapAlloc(hCacheHeap,HEAP_NO_SERIALIZE+HEAP_ZERO_MEMORY,sizeof(DBCachedContactValueList));
+ VL->hContact = (HANDLE)ofsNew;
+
+ li.List_GetIndex(&lContacts,VL,&index);
+ li.List_Insert(&lContacts,VL,index);
+ }
+
+ LeaveCriticalSection(&csDbAccess);
+ NotifyEventHooks(hContactAddedEvent,(WPARAM)ofsNew,0);
+ return (int)ofsNew;
+}
+
+static int IsDbContact(WPARAM wParam,LPARAM lParam)
+{
+ struct DBContact dbc;
+ DWORD ofsContact=(DWORD)wParam;
+ int ret;
+
+ EnterCriticalSection(&csDbAccess);
+ {
+ int index;
+ DBCachedContactValueList VLtemp,*VL;
+ VLtemp.hContact = (HANDLE)wParam;
+ if ( li.List_GetIndex(&lContacts,&VLtemp,&index))
+ ret = TRUE;
+ else {
+ dbc=*(struct DBContact*)DBRead(ofsContact,sizeof(struct DBContact),NULL);
+ ret=dbc.signature==DBCONTACT_SIGNATURE;
+
+ if (ret) {
+ VL = (DBCachedContactValueList*)HeapAlloc(hCacheHeap,HEAP_NO_SERIALIZE+HEAP_ZERO_MEMORY,sizeof(DBCachedContactValueList));
+ VL->hContact = (HANDLE)wParam;
+ li.List_Insert(&lContacts,VL,index);
+ } } }
+
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+}
diff --git a/miranda-wine/plugins/db3x/dbevents.c b/miranda-wine/plugins/db3x/dbevents.c
new file mode 100644
index 0000000..ffc5eed
--- /dev/null
+++ b/miranda-wine/plugins/db3x/dbevents.c
@@ -0,0 +1,436 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "database.h"
+
+
+DWORD GetModuleNameOfs(const char *szName);
+char *GetModuleNameByOfs(DWORD ofs);
+
+static int GetEventCount(WPARAM wParam,LPARAM lParam);
+static int AddEvent(WPARAM wParam,LPARAM lParam);
+static int DeleteEvent(WPARAM wParam,LPARAM lParam);
+static int GetBlobSize(WPARAM wParam,LPARAM lParam);
+static int GetEvent(WPARAM wParam,LPARAM lParam);
+static int MarkEventRead(WPARAM wParam,LPARAM lParam);
+static int GetEventContact(WPARAM wParam,LPARAM lParam);
+static int FindFirstEvent(WPARAM wParam,LPARAM lParam);
+static int FindFirstUnreadEvent(WPARAM wParam,LPARAM lParam);
+static int FindLastEvent(WPARAM wParam,LPARAM lParam);
+static int FindNextEvent(WPARAM wParam,LPARAM lParam);
+static int FindPrevEvent(WPARAM wParam,LPARAM lParam);
+
+extern CRITICAL_SECTION csDbAccess;
+extern struct DBHeader dbHeader;
+
+static HANDLE hEventDeletedEvent,hEventAddedEvent,hEventFilterAddedEvent;
+
+int InitEvents(void)
+{
+ CreateServiceFunction(MS_DB_EVENT_GETCOUNT,GetEventCount);
+ CreateServiceFunction(MS_DB_EVENT_ADD,AddEvent);
+ CreateServiceFunction(MS_DB_EVENT_DELETE,DeleteEvent);
+ CreateServiceFunction(MS_DB_EVENT_GETBLOBSIZE,GetBlobSize);
+ CreateServiceFunction(MS_DB_EVENT_GET,GetEvent);
+ CreateServiceFunction(MS_DB_EVENT_MARKREAD,MarkEventRead);
+ CreateServiceFunction(MS_DB_EVENT_GETCONTACT,GetEventContact);
+ CreateServiceFunction(MS_DB_EVENT_FINDFIRST,FindFirstEvent);
+ CreateServiceFunction(MS_DB_EVENT_FINDFIRSTUNREAD,FindFirstUnreadEvent);
+ CreateServiceFunction(MS_DB_EVENT_FINDLAST,FindLastEvent);
+ CreateServiceFunction(MS_DB_EVENT_FINDNEXT,FindNextEvent);
+ CreateServiceFunction(MS_DB_EVENT_FINDPREV,FindPrevEvent);
+ hEventDeletedEvent=CreateHookableEvent(ME_DB_EVENT_DELETED);
+ hEventAddedEvent=CreateHookableEvent(ME_DB_EVENT_ADDED);
+ hEventFilterAddedEvent=CreateHookableEvent(ME_DB_EVENT_FILTER_ADD);
+ return 0;
+}
+
+void UninitEvents(void)
+{
+}
+
+static int GetEventCount(WPARAM wParam,LPARAM lParam)
+{
+ int ret;
+ struct DBContact *dbc;
+
+ EnterCriticalSection(&csDbAccess);
+ if(wParam==0) wParam=dbHeader.ofsUser;
+ dbc=(struct DBContact*)DBRead(wParam,sizeof(struct DBContact),NULL);
+ if(dbc->signature!=DBCONTACT_SIGNATURE) ret=-1;
+ else ret=dbc->eventCount;
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+}
+
+static int AddEvent(WPARAM wParam,LPARAM lParam)
+{
+ DBEVENTINFO *dbei=(DBEVENTINFO*)lParam;
+ struct DBContact dbc;
+ struct DBEvent dbe,*dbeTest;
+ DWORD ofsNew,ofsModuleName,ofsContact,ofsThis;
+
+ if(dbei==NULL||dbei->cbSize!=sizeof(DBEVENTINFO)) return (int)NULL;
+ if(dbei->timestamp==0) return (int)NULL;
+ if (NotifyEventHooks(hEventFilterAddedEvent,wParam,lParam)) {
+ return (int)NULL;
+ }
+ EnterCriticalSection(&csDbAccess);
+ if(wParam==0) ofsContact=dbHeader.ofsUser;
+ else ofsContact=wParam;
+ dbc=*(struct DBContact*)DBRead(ofsContact,sizeof(struct DBContact),NULL);
+ if(dbc.signature!=DBCONTACT_SIGNATURE) {
+ LeaveCriticalSection(&csDbAccess);
+ return (int)NULL;
+ }
+ ofsNew=CreateNewSpace(offsetof(struct DBEvent,blob)+dbei->cbBlob);
+ ofsModuleName=GetModuleNameOfs(dbei->szModule);
+
+ dbe.signature=DBEVENT_SIGNATURE;
+ dbe.ofsModuleName=ofsModuleName;
+ dbe.timestamp=dbei->timestamp;
+ dbe.flags=dbei->flags;
+ dbe.eventType=dbei->eventType;
+ dbe.cbBlob=dbei->cbBlob;
+ //find where to put it - sort by timestamp
+ if(dbc.eventCount==0) {
+ dbe.ofsPrev=wParam;
+ dbe.ofsNext=0;
+ dbe.flags|=DBEF_FIRST;
+ dbc.ofsFirstEvent=dbc.ofsLastEvent=ofsNew;
+ }
+ else {
+ dbeTest=(struct DBEvent*)DBRead(dbc.ofsFirstEvent,sizeof(struct DBEvent),NULL);
+ // Should new event be placed before first event in chain?
+ if (dbei->timestamp < dbeTest->timestamp) {
+ dbe.ofsPrev=wParam;
+ dbe.ofsNext=dbc.ofsFirstEvent;
+ dbe.flags|=DBEF_FIRST;
+ dbc.ofsFirstEvent=ofsNew;
+ dbeTest=(struct DBEvent*)DBRead(dbe.ofsNext,sizeof(struct DBEvent),NULL);
+ dbeTest->flags&=~DBEF_FIRST;
+ dbeTest->ofsPrev=ofsNew;
+ DBWrite(dbe.ofsNext,dbeTest,sizeof(struct DBEvent));
+ }
+ else {
+ // Loop through the chain, starting at the end
+ ofsThis = dbc.ofsLastEvent;
+ dbeTest = (struct DBEvent*)DBRead(ofsThis, sizeof(struct DBEvent), NULL);
+ for(;;) {
+ // If the new event's timesstamp is equal to or greater than the
+ // current dbevent, it will be inserted after. If not, continue
+ // with the previous dbevent in chain.
+ if (dbe.timestamp >= dbeTest->timestamp) {
+ dbe.ofsPrev = ofsThis;
+ dbe.ofsNext = dbeTest->ofsNext;
+ dbeTest->ofsNext = ofsNew;
+ DBWrite(ofsThis, dbeTest, sizeof(struct DBEvent));
+ if (dbe.ofsNext == 0)
+ dbc.ofsLastEvent = ofsNew;
+ else {
+ dbeTest = (struct DBEvent*)DBRead(dbe.ofsNext, sizeof(struct DBEvent), NULL);
+ dbeTest->ofsPrev = ofsNew;
+ DBWrite(dbe.ofsNext, dbeTest, sizeof(struct DBEvent));
+ }
+ break;
+ }
+ ofsThis = dbeTest->ofsPrev;
+ dbeTest = (struct DBEvent*)DBRead(ofsThis, sizeof(struct DBEvent), NULL);
+ }
+ }
+ }
+ dbc.eventCount++;
+ if(!(dbe.flags&(DBEF_READ|DBEF_SENT))) {
+ if(dbe.timestamp<dbc.timestampFirstUnread || dbc.timestampFirstUnread==0) {
+ dbc.timestampFirstUnread=dbe.timestamp;
+ dbc.ofsFirstUnreadEvent=ofsNew;
+ }
+ }
+ DBWrite(ofsContact,&dbc,sizeof(struct DBContact));
+ DBWrite(ofsNew,&dbe,offsetof(struct DBEvent,blob));
+ DBWrite(ofsNew+offsetof(struct DBEvent,blob),dbei->pBlob,dbei->cbBlob);
+ DBFlush(0);
+ LeaveCriticalSection(&csDbAccess);
+ log1("add event @ %08x",ofsNew);
+ NotifyEventHooks(hEventAddedEvent,wParam,(LPARAM)ofsNew);
+ return (int)ofsNew;
+}
+
+static int DeleteEvent(WPARAM wParam,LPARAM lParam)
+{
+ struct DBContact dbc;
+ DWORD ofsContact,ofsThis;
+ struct DBEvent dbe,*dbeNext,*dbePrev;
+
+ EnterCriticalSection(&csDbAccess);
+ if(wParam==0) ofsContact=dbHeader.ofsUser;
+ else ofsContact=wParam;
+ dbc=*(struct DBContact*)DBRead(ofsContact,sizeof(struct DBContact),NULL);
+ dbe=*(struct DBEvent*)DBRead(lParam,sizeof(struct DBEvent),NULL);
+ if(dbc.signature!=DBCONTACT_SIGNATURE || dbe.signature!=DBEVENT_SIGNATURE) {
+ LeaveCriticalSection(&csDbAccess);
+ return 1;
+ }
+ log1("delete event @ %08x",wParam);
+ LeaveCriticalSection(&csDbAccess);
+ //call notifier while outside mutex
+ NotifyEventHooks(hEventDeletedEvent,wParam,lParam);
+ //get back in
+ EnterCriticalSection(&csDbAccess);
+ dbc=*(struct DBContact*)DBRead(ofsContact,sizeof(struct DBContact),NULL);
+ dbe=*(struct DBEvent*)DBRead(lParam,sizeof(struct DBEvent),NULL);
+ //check if this was the first unread, if so, recalc the first unread
+ if(dbc.ofsFirstUnreadEvent==(DWORD)lParam) {
+ dbeNext=&dbe;
+ for(;;) {
+ if(dbeNext->ofsNext==0) {
+ dbc.ofsFirstUnreadEvent=0;
+ dbc.timestampFirstUnread=0;
+ break;
+ }
+ ofsThis=dbeNext->ofsNext;
+ dbeNext=(struct DBEvent*)DBRead(ofsThis,sizeof(struct DBEvent),NULL);
+ if(!(dbeNext->flags&(DBEF_READ|DBEF_SENT))) {
+ dbc.ofsFirstUnreadEvent=ofsThis;
+ dbc.timestampFirstUnread=dbeNext->timestamp;
+ break;
+ }
+ }
+ }
+ //get previous and next events in chain and change offsets
+ if(dbe.flags&DBEF_FIRST) {
+ if(dbe.ofsNext==0) {
+ dbc.ofsFirstEvent=dbc.ofsLastEvent=0;
+ }
+ else {
+ dbeNext=(struct DBEvent*)DBRead(dbe.ofsNext,sizeof(struct DBEvent),NULL);
+ dbeNext->flags|=DBEF_FIRST;
+ dbeNext->ofsPrev=dbe.ofsPrev;
+ DBWrite(dbe.ofsNext,dbeNext,sizeof(struct DBEvent));
+ dbc.ofsFirstEvent=dbe.ofsNext;
+ }
+ }
+ else {
+ if(dbe.ofsNext==0) {
+ dbePrev=(struct DBEvent*)DBRead(dbe.ofsPrev,sizeof(struct DBEvent),NULL);
+ dbePrev->ofsNext=0;
+ DBWrite(dbe.ofsPrev,dbePrev,sizeof(struct DBEvent));
+ dbc.ofsLastEvent=dbe.ofsPrev;
+ }
+ else {
+ dbePrev=(struct DBEvent*)DBRead(dbe.ofsPrev,sizeof(struct DBEvent),NULL);
+ dbePrev->ofsNext=dbe.ofsNext;
+ DBWrite(dbe.ofsPrev,dbePrev,sizeof(struct DBEvent));
+ dbeNext=(struct DBEvent*)DBRead(dbe.ofsNext,sizeof(struct DBEvent),NULL);
+ dbeNext->ofsPrev=dbe.ofsPrev;
+ DBWrite(dbe.ofsNext,dbeNext,sizeof(struct DBEvent));
+ }
+ }
+ //delete event
+ DeleteSpace(lParam,offsetof(struct DBEvent,blob)+dbe.cbBlob);
+ //decrement event count
+ dbc.eventCount--;
+ DBWrite(ofsContact,&dbc,sizeof(struct DBContact));
+ DBFlush(0);
+ //quit
+ LeaveCriticalSection(&csDbAccess);
+ return 0;
+}
+
+static int GetBlobSize(WPARAM wParam,LPARAM lParam)
+{
+ int ret;
+ struct DBEvent *dbe;
+
+ EnterCriticalSection(&csDbAccess);
+ dbe=(struct DBEvent*)DBRead(wParam,sizeof(struct DBEvent),NULL);
+ if(dbe->signature!=DBEVENT_SIGNATURE) ret=-1;
+ else ret=dbe->cbBlob;
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+}
+
+static int GetEvent(WPARAM wParam,LPARAM lParam)
+{
+ struct DBEvent *dbe;
+ DBEVENTINFO *dbei=(DBEVENTINFO*)lParam;
+ int bytesToCopy,i;
+
+ if(dbei==NULL||dbei->cbSize!=sizeof(DBEVENTINFO)) return 1;
+ EnterCriticalSection(&csDbAccess);
+ dbe=(struct DBEvent*)DBRead(wParam,sizeof(struct DBEvent),NULL);
+ if(dbe->signature!=DBEVENT_SIGNATURE) {
+ LeaveCriticalSection(&csDbAccess);
+ return 1;
+ }
+ dbei->szModule=GetModuleNameByOfs(dbe->ofsModuleName);
+ dbei->timestamp=dbe->timestamp;
+ dbei->flags=dbe->flags;
+ dbei->eventType=dbe->eventType;
+ if(dbei->cbBlob<dbe->cbBlob) bytesToCopy=dbei->cbBlob;
+ else bytesToCopy=dbe->cbBlob;
+ dbei->cbBlob=dbe->cbBlob;
+ for(i=0;;i+=MAXCACHEDREADSIZE) {
+ if(bytesToCopy-i<=MAXCACHEDREADSIZE) {
+ CopyMemory(dbei->pBlob+i,DBRead(wParam+offsetof(struct DBEvent,blob)+i,bytesToCopy-i,NULL),bytesToCopy-i);
+ break;
+ }
+ CopyMemory(dbei->pBlob+i,DBRead(wParam+offsetof(struct DBEvent,blob)+i,MAXCACHEDREADSIZE,NULL),MAXCACHEDREADSIZE);
+ }
+ LeaveCriticalSection(&csDbAccess);
+ return 0;
+}
+
+static int MarkEventRead(WPARAM wParam,LPARAM lParam)
+{
+ int ret;
+ struct DBEvent *dbe;
+ struct DBContact dbc;
+ DWORD ofsThis;
+
+ EnterCriticalSection(&csDbAccess);
+ if(wParam==0) wParam=dbHeader.ofsUser;
+ dbc=*(struct DBContact*)DBRead(wParam,sizeof(struct DBContact),NULL);
+ dbe=(struct DBEvent*)DBRead(lParam,sizeof(struct DBEvent),NULL);
+ if(dbe->signature!=DBEVENT_SIGNATURE || dbc.signature!=DBCONTACT_SIGNATURE) {
+ LeaveCriticalSection(&csDbAccess);
+ return -1;
+ }
+ if(dbe->flags&DBEF_READ || dbe->flags&DBEF_SENT) {
+ ret=(int)dbe->flags;
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+ }
+ log1("mark read @ %08x",wParam);
+ dbe->flags|=DBEF_READ;
+ DBWrite(lParam,dbe,sizeof(struct DBEvent));
+ ret=(int)dbe->flags;
+ if(dbc.ofsFirstUnreadEvent==(DWORD)lParam) {
+ for(;;) {
+ if(dbe->ofsNext==0) {
+ dbc.ofsFirstUnreadEvent=0;
+ dbc.timestampFirstUnread=0;
+ break;
+ }
+ ofsThis=dbe->ofsNext;
+ dbe=(struct DBEvent*)DBRead(ofsThis,sizeof(struct DBEvent),NULL);
+ if(!(dbe->flags&(DBEF_READ|DBEF_SENT))) {
+ dbc.ofsFirstUnreadEvent=ofsThis;
+ dbc.timestampFirstUnread=dbe->timestamp;
+ break;
+ }
+ }
+ }
+ DBWrite(wParam,&dbc,sizeof(struct DBContact));
+ DBFlush(0);
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+}
+
+static int GetEventContact(WPARAM wParam,LPARAM lParam)
+{
+ int ret;
+ struct DBEvent *dbe;
+
+ EnterCriticalSection(&csDbAccess);
+ dbe=(struct DBEvent*)DBRead(wParam,sizeof(struct DBEvent),NULL);
+ if(dbe->signature!=DBEVENT_SIGNATURE) {
+ LeaveCriticalSection(&csDbAccess);
+ return -1;
+ }
+ while(!(dbe->flags&DBEF_FIRST))
+ dbe=(struct DBEvent*)DBRead(dbe->ofsPrev,sizeof(struct DBEvent),NULL);
+ ret=(int)(HANDLE)dbe->ofsPrev;
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+}
+
+static int FindFirstEvent(WPARAM wParam,LPARAM lParam)
+{
+ int ret;
+ struct DBContact *dbc;
+
+ EnterCriticalSection(&csDbAccess);
+ if(wParam==0) wParam=dbHeader.ofsUser;
+ dbc=(struct DBContact*)DBRead(wParam,sizeof(struct DBContact),NULL);
+ if(dbc->signature!=DBCONTACT_SIGNATURE) ret=(int)(HANDLE)NULL;
+ else ret=(int)dbc->ofsFirstEvent;
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+}
+
+static int FindFirstUnreadEvent(WPARAM wParam,LPARAM lParam)
+{
+ int ret;
+ struct DBContact *dbc;
+
+ EnterCriticalSection(&csDbAccess);
+ if(wParam==0) wParam=dbHeader.ofsUser;
+ dbc=(struct DBContact*)DBRead(wParam,sizeof(struct DBContact),NULL);
+ if(dbc->signature!=DBCONTACT_SIGNATURE) ret=(int)(HANDLE)NULL;
+ else ret=(int)dbc->ofsFirstUnreadEvent;
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+}
+
+static int FindLastEvent(WPARAM wParam,LPARAM lParam)
+{
+ int ret;
+ struct DBContact *dbc;
+
+ EnterCriticalSection(&csDbAccess);
+ if(wParam==0) wParam=dbHeader.ofsUser;
+ dbc=(struct DBContact*)DBRead(wParam,sizeof(struct DBContact),NULL);
+ if(dbc->signature!=DBCONTACT_SIGNATURE) ret=(int)(HANDLE)NULL;
+ else ret=(int)dbc->ofsLastEvent;
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+}
+
+static int FindNextEvent(WPARAM wParam,LPARAM lParam)
+{
+ int ret;
+ struct DBEvent *dbe;
+
+ EnterCriticalSection(&csDbAccess);
+ dbe=(struct DBEvent*)DBRead(wParam,sizeof(struct DBEvent),NULL);
+ if(dbe->signature!=DBEVENT_SIGNATURE) ret=(int)(HANDLE)NULL;
+ else ret=(int)(HANDLE)dbe->ofsNext;
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+}
+
+static int FindPrevEvent(WPARAM wParam,LPARAM lParam)
+{
+ int ret;
+ struct DBEvent *dbe;
+
+ EnterCriticalSection(&csDbAccess);
+ dbe=(struct DBEvent*)DBRead(wParam,sizeof(struct DBEvent),NULL);
+ if(dbe->signature!=DBEVENT_SIGNATURE) ret=(int)(HANDLE)NULL;
+ else if(dbe->flags&DBEF_FIRST) ret=(int)(HANDLE)NULL;
+ else ret=(int)(HANDLE)dbe->ofsPrev;
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+}
diff --git a/miranda-wine/plugins/db3x/dbheaders.c b/miranda-wine/plugins/db3x/dbheaders.c
new file mode 100644
index 0000000..da7cb6e
--- /dev/null
+++ b/miranda-wine/plugins/db3x/dbheaders.c
@@ -0,0 +1,78 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "database.h"
+
+extern struct DBHeader dbHeader;
+extern HANDLE hDbFile;
+
+struct DBSignature {
+ char name[15];
+ BYTE eof;
+};
+static struct DBSignature dbSignature={"Miranda ICQ DB",0x1A};
+
+//the cache has not been loaded when these functions are used
+
+int CreateDbHeaders(HANDLE hFile)
+{
+ struct DBContact user;
+ DWORD bytesWritten;
+
+ CopyMemory(dbHeader.signature,&dbSignature,sizeof(dbHeader.signature));
+ dbHeader.version=DB_THIS_VERSION;
+ dbHeader.ofsFileEnd=sizeof(struct DBHeader);
+ dbHeader.slackSpace=0;
+ dbHeader.contactCount=0;
+ dbHeader.ofsFirstContact=0;
+ dbHeader.ofsFirstModuleName=0;
+ dbHeader.ofsUser=0;
+ //create user
+ dbHeader.ofsUser=dbHeader.ofsFileEnd;
+ dbHeader.ofsFileEnd+=sizeof(struct DBContact);
+ SetFilePointer(hFile,0,NULL,FILE_BEGIN);
+ WriteFile(hFile,&dbHeader,sizeof(dbHeader),&bytesWritten,NULL);
+ user.signature=DBCONTACT_SIGNATURE;
+ user.ofsNext=0;
+ user.ofsFirstSettings=0;
+ user.eventCount=0;
+ user.ofsFirstEvent=user.ofsLastEvent=0;
+ SetFilePointer(hFile,dbHeader.ofsUser,NULL,FILE_BEGIN);
+ WriteFile(hFile,&user,sizeof(struct DBContact),&bytesWritten,NULL);
+ FlushFileBuffers(hFile);
+ return 0;
+}
+
+int CheckDbHeaders(struct DBHeader * hdr)
+{
+ if(memcmp(hdr->signature,&dbSignature,sizeof(hdr->signature))) return 1;
+ if(hdr->version!=DB_THIS_VERSION) return 2;
+ if(hdr->ofsUser==0) return 3;
+ return 0;
+}
+
+int InitialiseDbHeaders(void)
+{
+ return 0;
+}
diff --git a/miranda-wine/plugins/db3x/dbmodulechain.c b/miranda-wine/plugins/db3x/dbmodulechain.c
new file mode 100644
index 0000000..352a06c
--- /dev/null
+++ b/miranda-wine/plugins/db3x/dbmodulechain.c
@@ -0,0 +1,132 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "database.h"
+
+extern struct DBHeader dbHeader;
+
+static int EnumModuleNames(WPARAM wParam,LPARAM lParam);
+
+struct ModuleName {
+ char *name;
+ DWORD hash;
+ DWORD ofs;
+};
+static struct ModuleName *moduleName;
+static int moduleNameCount;
+
+int InitModuleNames(void)
+{
+ struct DBModuleName *dbmn;
+ DWORD ofsThis,ofsNext;
+ int nameLen;
+
+ moduleNameCount=0;
+ moduleName=NULL;
+ ofsThis=dbHeader.ofsFirstModuleName;
+ dbmn=(struct DBModuleName*)DBRead(ofsThis,sizeof(struct DBModuleName),NULL);
+ while(ofsThis) {
+ if(dbmn->signature!=DBMODULENAME_SIGNATURE) DatabaseCorruption();
+ moduleName=(struct ModuleName*)mir_realloc(moduleName,sizeof(struct ModuleName)*(moduleNameCount+1));
+ moduleName[moduleNameCount].ofs=ofsThis;
+ moduleName[moduleNameCount].hash=dbmn->cbName; //very very simple hash so far
+ moduleName[moduleNameCount].name=(char*)mir_alloc(dbmn->cbName+1);
+ ofsNext=dbmn->ofsNext;
+ nameLen=dbmn->cbName;
+ CopyMemory(moduleName[moduleNameCount].name,DBRead(ofsThis+offsetof(struct DBModuleName,name),nameLen,NULL),nameLen);
+ moduleName[moduleNameCount].name[nameLen]=0;
+ moduleNameCount++;
+ ofsThis=ofsNext;
+ dbmn=(struct DBModuleName*)DBRead(ofsThis,sizeof(struct DBModuleName),NULL);
+ }
+ CreateServiceFunction(MS_DB_MODULES_ENUM,EnumModuleNames);
+ return 0;
+}
+
+void UninitModuleNames(void)
+{
+ int i;
+ for(i=0;i<moduleNameCount;i++) mir_free(moduleName[i].name);
+ if(moduleNameCount) mir_free(moduleName);
+}
+
+static DWORD FindExistingModuleNameOfs(const char *szName,int nameLen)
+{
+ int i;
+ for(i=0;i<moduleNameCount;i++)
+ if(moduleName[i].hash==(DWORD)nameLen && !strcmp(moduleName[i].name,szName)) return moduleName[i].ofs;
+ return 0;
+}
+
+//will create the offset if it needs to
+DWORD GetModuleNameOfs(const char *szName)
+{
+ struct DBModuleName dbmn;
+ int nameLen=strlen(szName);
+ DWORD ofsNew,ofsExisting;
+
+ ofsExisting=FindExistingModuleNameOfs(szName,nameLen);
+ if(ofsExisting) return ofsExisting;
+ //need to create the module name
+ ofsNew=CreateNewSpace(nameLen+offsetof(struct DBModuleName,name));
+ dbmn.signature=DBMODULENAME_SIGNATURE;
+ dbmn.cbName=nameLen;
+ dbmn.ofsNext=dbHeader.ofsFirstModuleName;
+ dbHeader.ofsFirstModuleName=ofsNew;
+ DBWrite(0,&dbHeader,sizeof(dbHeader));
+ DBWrite(ofsNew,&dbmn,offsetof(struct DBModuleName,name));
+ DBWrite(ofsNew+offsetof(struct DBModuleName,name),(PVOID)szName,nameLen);
+ DBFlush(0);
+ //add to cache
+ moduleName=(struct ModuleName*)mir_realloc(moduleName,sizeof(struct ModuleName)*(moduleNameCount+1));
+ moduleName[moduleNameCount].ofs=ofsNew;
+ moduleName[moduleNameCount].hash=nameLen; //very very simple hash so far
+ moduleName[moduleNameCount].name=(char*)mir_alloc(nameLen+1);
+ strcpy(moduleName[moduleNameCount].name,szName);
+ moduleNameCount++;
+ //quit
+ return ofsNew;
+}
+
+//it's OK that this is a bit slow - it's rarely used
+char *GetModuleNameByOfs(DWORD ofs)
+{
+ int i;
+
+ for(i=0;i<moduleNameCount;i++)
+ if(moduleName[i].ofs==ofs) return moduleName[i].name;
+ DatabaseCorruption();
+ return NULL;
+}
+
+static int EnumModuleNames(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ int ret;
+ for(i=0;i<moduleNameCount;i++) {
+ ret=((DBMODULEENUMPROC)lParam)(moduleName[i].name,moduleName[i].ofs,wParam);
+ if(ret) return ret;
+ }
+ return 0;
+}
diff --git a/miranda-wine/plugins/db3x/dbsettings.c b/miranda-wine/plugins/db3x/dbsettings.c
new file mode 100644
index 0000000..d01988e
--- /dev/null
+++ b/miranda-wine/plugins/db3x/dbsettings.c
@@ -0,0 +1,957 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+#include "database.h"
+
+DWORD GetModuleNameOfs(const char *szName);
+
+extern CRITICAL_SECTION csDbAccess;
+extern struct DBHeader dbHeader;
+
+HANDLE hCacheHeap = NULL;
+SortedList lContacts;
+
+static SortedList lSettings, lGlobalSettings;
+static HANDLE hSettingChangeEvent = NULL;
+
+#define SETTINGSGROUPOFSCOUNT 32
+struct SettingsGroupOfsCacheEntry {
+ DWORD ofsContact;
+ DWORD ofsModuleName;
+ DWORD ofsSettingsGroup;
+};
+static struct SettingsGroupOfsCacheEntry settingsGroupOfsCache[SETTINGSGROUPOFSCOUNT];
+static int nextSGOCacheEntry;
+
+//this function caches results
+static DWORD GetSettingsGroupOfsByModuleNameOfs(struct DBContact *dbc,DWORD ofsContact,DWORD ofsModuleName)
+{
+ struct DBContactSettings *dbcs;
+ DWORD ofsThis;
+ int i;
+
+ for(i=0;i<SETTINGSGROUPOFSCOUNT;i++) {
+ if(settingsGroupOfsCache[i].ofsContact==ofsContact && settingsGroupOfsCache[i].ofsModuleName==ofsModuleName)
+ return settingsGroupOfsCache[i].ofsSettingsGroup;
+ }
+ ofsThis=dbc->ofsFirstSettings;
+ while(ofsThis) {
+ dbcs=(struct DBContactSettings*)DBRead(ofsThis,sizeof(struct DBContactSettings),NULL);
+ if(dbcs->signature!=DBCONTACTSETTINGS_SIGNATURE) DatabaseCorruption();
+ if(dbcs->ofsModuleName==ofsModuleName) {
+ settingsGroupOfsCache[nextSGOCacheEntry].ofsContact=ofsContact;
+ settingsGroupOfsCache[nextSGOCacheEntry].ofsModuleName=ofsModuleName;
+ settingsGroupOfsCache[nextSGOCacheEntry].ofsSettingsGroup=ofsThis;
+ if(++nextSGOCacheEntry==SETTINGSGROUPOFSCOUNT) nextSGOCacheEntry=0;
+ return ofsThis;
+ }
+ ofsThis=dbcs->ofsNext;
+ }
+ return 0;
+}
+
+static void InvalidateSettingsGroupOfsCacheEntry(DWORD ofsSettingsGroup)
+{
+ int i;
+
+ for(i=0;i<SETTINGSGROUPOFSCOUNT;i++) {
+ if(settingsGroupOfsCache[i].ofsSettingsGroup==ofsSettingsGroup) {
+ settingsGroupOfsCache[i].ofsContact=0;
+ settingsGroupOfsCache[i].ofsModuleName=0;
+ settingsGroupOfsCache[i].ofsSettingsGroup=0;
+ break;
+} } }
+
+static DWORD __inline GetSettingValueLength(PBYTE pSetting)
+{
+ if(pSetting[0]&DBVTF_VARIABLELENGTH) return 2+*(PWORD)(pSetting+1);
+ return pSetting[0];
+}
+
+static char* InsertCachedSetting( const char* szName, size_t cbNameLen, int index )
+{
+ char* newValue = (char*)HeapAlloc( hCacheHeap, HEAP_NO_SERIALIZE, cbNameLen );
+ *newValue = 0;
+ strcpy(newValue+1,szName+1);
+ li.List_Insert(&lSettings,newValue,index);
+ return newValue;
+}
+
+static char* GetCachedSetting(const char *szModuleName,const char *szSettingName,int settingNameLen)
+{
+ int moduleNameLen = strlen(szModuleName),index;
+ char *szFullName = (char*)alloca(moduleNameLen+settingNameLen+3);
+
+ strcpy(szFullName+1,szModuleName);
+ szFullName[moduleNameLen+1]='/';
+ strcpy(szFullName+moduleNameLen+2,szSettingName);
+
+ if ( li.List_GetIndex(&lSettings, szFullName, &index))
+ return((char*)lSettings.items[index] + 1);
+
+ return InsertCachedSetting( szFullName, moduleNameLen+settingNameLen+3, index )+1;
+}
+
+static void SetCachedVariant( DBVARIANT* s /* new */, DBVARIANT* d /* cached */ )
+{
+ char* szSave = ( d->type == DBVT_UTF8 || d->type == DBVT_ASCIIZ ) ? d->pszVal : NULL;
+
+ memcpy( d, s, sizeof( DBVARIANT ));
+ if (( s->type == DBVT_UTF8 || s->type == DBVT_ASCIIZ ) && s->pszVal != NULL ) {
+ if ( szSave != NULL )
+ d->pszVal = (char*)HeapReAlloc(hCacheHeap,HEAP_NO_SERIALIZE,szSave,strlen(s->pszVal)+1);
+ else
+ d->pszVal = (char*)HeapAlloc(hCacheHeap,HEAP_NO_SERIALIZE,strlen(s->pszVal)+1);
+ strcpy(d->pszVal,s->pszVal);
+ }
+
+ switch( d->type ) {
+ case DBVT_BYTE: log1( "set cached byte: %d", d->bVal ); break;
+ case DBVT_WORD: log1( "set cached word: %d", d->wVal ); break;
+ case DBVT_DWORD: log1( "set cached dword: %d", d->dVal ); break;
+ case DBVT_UTF8:
+ case DBVT_ASCIIZ: log1( "set cached string: '%s'", d->pszVal ); break;
+ default: log1( "set cached crap: %d", d->type ); break;
+} }
+
+static void FreeCachedVariant( DBVARIANT* V )
+{
+ if (( V->type == DBVT_ASCIIZ || V->type == DBVT_UTF8 ) && V->pszVal != NULL )
+ HeapFree(hCacheHeap,HEAP_NO_SERIALIZE,V->pszVal);
+}
+
+static DBVARIANT* GetCachedValuePtr( HANDLE hContact, char* szSetting, int bAllocate )
+{
+ int index;
+
+ if ( hContact == 0 ) {
+ DBCachedGlobalValue Vtemp, *V;
+ Vtemp.name = szSetting;
+ if ( li.List_GetIndex(&lGlobalSettings,&Vtemp,&index)) {
+ V = (DBCachedGlobalValue*)lGlobalSettings.items[index];
+ if ( bAllocate == -1 ) {
+ FreeCachedVariant( &V->value );
+ li.List_Remove(&lGlobalSettings,index);
+ HeapFree(hCacheHeap,HEAP_NO_SERIALIZE,V);
+ return NULL;
+ } }
+ else {
+ if ( bAllocate != 1 )
+ return NULL;
+
+ V = (DBCachedGlobalValue*)HeapAlloc(hCacheHeap,HEAP_NO_SERIALIZE+HEAP_ZERO_MEMORY,sizeof(DBCachedGlobalValue));
+ V->name = szSetting;
+ li.List_Insert(&lGlobalSettings,V,index);
+ }
+
+ return &V->value;
+ }
+ else {
+ DBCachedContactValue *V, *V1;
+ DBCachedContactValueList VLtemp,*VL;
+
+ VLtemp.hContact=hContact;
+ if ( li.List_GetIndex(&lContacts,&VLtemp,&index)) {
+ VL = (DBCachedContactValueList*)lContacts.items[index];
+ }
+ else {
+ if ( bAllocate == -1 )
+ return NULL;
+
+ VL = (DBCachedContactValueList*)HeapAlloc(hCacheHeap,HEAP_NO_SERIALIZE+HEAP_ZERO_MEMORY,sizeof(DBCachedContactValueList));
+ VL->hContact = hContact;
+ li.List_Insert(&lContacts,VL,index);
+ }
+
+ for ( V = VL->first; V != NULL; V = V->next)
+ if (strcmp(V->name,szSetting)==0)
+ break;
+
+ if ( V == NULL )
+ { if ( bAllocate != 1 )
+ return NULL;
+
+ V = HeapAlloc(hCacheHeap,HEAP_NO_SERIALIZE+HEAP_ZERO_MEMORY,sizeof(DBCachedContactValue));
+ V->next = VL->first;
+ VL->first = V;
+ V->name = szSetting;
+ }
+ else if ( bAllocate == -1 ) {
+ FreeCachedVariant(&V->value);
+ if ( VL->first == V )
+ VL->first = V->next;
+ for ( V1=VL->first; V1 != NULL; V1 = V1->next )
+ if ( V1->next == V ) {
+ V1->next = V->next;
+ break;
+ }
+ HeapFree(hCacheHeap,HEAP_NO_SERIALIZE,V);
+ return NULL;
+ }
+
+ return &V->value;
+} }
+
+#define NeedBytes(n) if(bytesRemaining<(n)) pBlob=(PBYTE)DBRead(ofsBlobPtr,(n),&bytesRemaining)
+#define MoveAlong(n) {int x=n; pBlob+=(x); ofsBlobPtr+=(x); bytesRemaining-=(x);}
+#define VLT(n) ((n==DBVT_UTF8)?DBVT_ASCIIZ:n)
+static __inline int GetContactSettingWorker(HANDLE hContact,DBCONTACTGETSETTING *dbcgs,int isStatic)
+{
+ struct DBContact dbc;
+ struct DBContactSettings dbcs;
+ DWORD ofsModuleName,ofsContact,ofsSettingsGroup,ofsBlobPtr;
+ int settingNameLen;
+ int bytesRemaining;
+ PBYTE pBlob;
+ char* szCachedSettingName;
+
+ if ((!dbcgs->szSetting) || (!dbcgs->szModule))
+ return 1;
+ settingNameLen=strlen(dbcgs->szSetting);
+
+ EnterCriticalSection(&csDbAccess);
+
+ log3("get [%08p] %s/%s",hContact,dbcgs->szModule,dbcgs->szSetting);
+
+ szCachedSettingName = GetCachedSetting(dbcgs->szModule,dbcgs->szSetting,settingNameLen);
+ {
+ DBVARIANT* pCachedValue = GetCachedValuePtr( hContact, szCachedSettingName, 0 );
+ if ( pCachedValue != NULL ) {
+ if ( pCachedValue->type == DBVT_ASCIIZ || pCachedValue->type == DBVT_UTF8 ) {
+ int cbOrigLen = dbcgs->pValue->cchVal;
+ char* cbOrigPtr = dbcgs->pValue->pszVal;
+ memcpy( dbcgs->pValue, pCachedValue, sizeof( DBVARIANT ));
+ if ( isStatic ) {
+ int cbLen = 0;
+ if ( pCachedValue->pszVal != NULL )
+ cbLen = strlen( pCachedValue->pszVal );
+
+ cbOrigLen--;
+ dbcgs->pValue->pszVal = cbOrigPtr;
+ if(cbLen<cbOrigLen) cbOrigLen=cbLen;
+ CopyMemory(dbcgs->pValue->pszVal,pCachedValue->pszVal,cbOrigLen);
+ dbcgs->pValue->pszVal[cbOrigLen]=0;
+ dbcgs->pValue->cchVal=cbLen;
+ }
+ else {
+ dbcgs->pValue->pszVal = (char*)mir_alloc(strlen(pCachedValue->pszVal)+1);
+ strcpy(dbcgs->pValue->pszVal,pCachedValue->pszVal);
+ }
+ }
+ else
+ memcpy( dbcgs->pValue, pCachedValue, sizeof( DBVARIANT ));
+
+ switch( dbcgs->pValue->type ) {
+ case DBVT_BYTE: log1( "get cached byte: %d", dbcgs->pValue->bVal ); break;
+ case DBVT_WORD: log1( "get cached word: %d", dbcgs->pValue->wVal ); break;
+ case DBVT_DWORD: log1( "get cached dword: %d", dbcgs->pValue->dVal ); break;
+ case DBVT_UTF8:
+ case DBVT_ASCIIZ: log1( "get cached string: '%s'", dbcgs->pValue->pszVal); break;
+ default: log1( "get cached crap: %d", dbcgs->pValue->type ); break;
+ }
+
+ LeaveCriticalSection(&csDbAccess);
+ return ( pCachedValue->type == DBVT_DELETED ) ? 1 : 0;
+ } }
+
+ ofsModuleName=GetModuleNameOfs(dbcgs->szModule);
+ if(hContact==NULL) ofsContact=dbHeader.ofsUser;
+ else ofsContact=(DWORD)hContact;
+ dbc=*(struct DBContact*)DBRead(ofsContact,sizeof(struct DBContact),NULL);
+ if(dbc.signature!=DBCONTACT_SIGNATURE) {
+ LeaveCriticalSection(&csDbAccess);
+ return 1;
+ }
+ ofsSettingsGroup=GetSettingsGroupOfsByModuleNameOfs(&dbc,ofsContact,ofsModuleName);
+ if(ofsSettingsGroup) {
+ dbcs=*(struct DBContactSettings*)DBRead(ofsSettingsGroup,sizeof(struct DBContactSettings),&bytesRemaining);
+ ofsBlobPtr=ofsSettingsGroup+offsetof(struct DBContactSettings,blob);
+ pBlob=(PBYTE)DBRead(ofsBlobPtr,1,&bytesRemaining);
+ while(pBlob[0]) {
+ NeedBytes(1+settingNameLen);
+ if(pBlob[0]==settingNameLen && !memcmp(pBlob+1,dbcgs->szSetting,settingNameLen)) {
+ MoveAlong(1+settingNameLen);
+ NeedBytes(5);
+ if(isStatic && pBlob[0]&DBVTF_VARIABLELENGTH && VLT(dbcgs->pValue->type) != VLT(pBlob[0])) {
+ LeaveCriticalSection(&csDbAccess);
+ return 1;
+ }
+ dbcgs->pValue->type=pBlob[0];
+ switch(pBlob[0]) {
+ case DBVT_DELETED: { /* this setting is deleted */
+ dbcgs->pValue->type=DBVT_DELETED;
+ LeaveCriticalSection(&csDbAccess);
+ return 2;
+ }
+ case DBVT_BYTE: dbcgs->pValue->bVal=pBlob[1]; break;
+ case DBVT_WORD: dbcgs->pValue->wVal=*(PWORD)(pBlob+1); break;
+ case DBVT_DWORD: dbcgs->pValue->dVal=*(PDWORD)(pBlob+1); break;
+ case DBVT_UTF8:
+ case DBVT_ASCIIZ:
+ NeedBytes(3+*(PWORD)(pBlob+1));
+ if(isStatic) {
+ dbcgs->pValue->cchVal--;
+ if(*(PWORD)(pBlob+1)<dbcgs->pValue->cchVal) dbcgs->pValue->cchVal=*(PWORD)(pBlob+1);
+ CopyMemory(dbcgs->pValue->pszVal,pBlob+3,dbcgs->pValue->cchVal);
+ dbcgs->pValue->pszVal[dbcgs->pValue->cchVal]=0;
+ dbcgs->pValue->cchVal=*(PWORD)(pBlob+1);
+ }
+ else {
+ dbcgs->pValue->pszVal=(char*)mir_alloc(1+*(PWORD)(pBlob+1));
+ CopyMemory(dbcgs->pValue->pszVal,pBlob+3,*(PWORD)(pBlob+1));
+ dbcgs->pValue->pszVal[*(PWORD)(pBlob+1)]=0;
+ }
+ break;
+ case DBVT_BLOB:
+ NeedBytes(3+*(PWORD)(pBlob+1));
+ if(isStatic) {
+ if(*(PWORD)(pBlob+1)<dbcgs->pValue->cpbVal) dbcgs->pValue->cpbVal=*(PWORD)(pBlob+1);
+ CopyMemory(dbcgs->pValue->pbVal,pBlob+3,dbcgs->pValue->cchVal);
+ }
+ else {
+ dbcgs->pValue->pbVal=(char*)mir_alloc(*(PWORD)(pBlob+1));
+ CopyMemory(dbcgs->pValue->pbVal,pBlob+3,*(PWORD)(pBlob+1));
+ }
+ dbcgs->pValue->cpbVal=*(PWORD)(pBlob+1);
+ break;
+ }
+
+ /**** add to cache **********************/
+ if ( dbcgs->pValue->type != DBVT_BLOB )
+ {
+ DBVARIANT* pCachedValue = GetCachedValuePtr( hContact, szCachedSettingName, 1 );
+ if ( pCachedValue != NULL )
+ SetCachedVariant(dbcgs->pValue,pCachedValue);
+ }
+
+ LeaveCriticalSection(&csDbAccess);
+ logg();
+ return 0;
+ }
+ NeedBytes(1);
+ MoveAlong(pBlob[0]+1);
+ NeedBytes(3);
+ MoveAlong(1+GetSettingValueLength(pBlob));
+ NeedBytes(1);
+ } }
+
+ /**** add missing setting to cache **********************/
+ if ( dbcgs->pValue->type != DBVT_BLOB )
+ {
+ DBVARIANT* pCachedValue = GetCachedValuePtr( hContact, szCachedSettingName, 1 );
+ if ( pCachedValue != NULL )
+ pCachedValue->type = DBVT_DELETED;
+ }
+
+ LeaveCriticalSection(&csDbAccess);
+ logg();
+ return 1;
+}
+
+static int GetContactSetting(WPARAM wParam,LPARAM lParam)
+{
+ DBCONTACTGETSETTING* dgs = ( DBCONTACTGETSETTING* )lParam;
+ dgs->pValue->type = 0;
+ if ( GetContactSettingWorker(( HANDLE )wParam, dgs, 0 ))
+ return 1;
+
+ if ( dgs->pValue->type == DBVT_UTF8 ) {
+ Utf8Decode( dgs->pValue->pszVal, NULL );
+ dgs->pValue->type = DBVT_ASCIIZ;
+ }
+
+ return 0;
+}
+
+static int GetContactSettingStr(WPARAM wParam,LPARAM lParam)
+{
+ DBCONTACTGETSETTING* dgs = (DBCONTACTGETSETTING*)lParam;
+ int iSaveType = dgs->pValue->type;
+
+ if ( GetContactSettingWorker(( HANDLE )wParam, dgs, 0 ))
+ return 1;
+
+ if ( iSaveType == 0 || iSaveType == dgs->pValue->type )
+ return 0;
+
+ if ( dgs->pValue->type != DBVT_ASCIIZ && dgs->pValue->type != DBVT_UTF8 )
+ return 0;
+
+ if ( iSaveType == DBVT_WCHAR ) {
+ if ( dgs->pValue->type != DBVT_UTF8 ) {
+ int len = MultiByteToWideChar( CP_ACP, 0, dgs->pValue->pszVal, -1, NULL, 0 );
+ wchar_t* wszResult = ( wchar_t* )mir_alloc(( len+1 )*sizeof( wchar_t ));
+ if ( wszResult == NULL )
+ return 1;
+
+ MultiByteToWideChar( CP_ACP, 0, dgs->pValue->pszVal, -1, wszResult, len );
+ wszResult[ len ] = 0;
+ mir_free( dgs->pValue->pszVal );
+ dgs->pValue->pwszVal = wszResult;
+ }
+ else {
+ char* savePtr = dgs->pValue->pszVal;
+ Utf8Decode( dgs->pValue->pszVal, &dgs->pValue->pwszVal );
+ mir_free( savePtr );
+ }
+ }
+ else if ( iSaveType == DBVT_UTF8 ) {
+ char* tmpBuf = Utf8Encode( dgs->pValue->pszVal );
+ if ( tmpBuf == NULL )
+ return 1;
+
+ mir_free( dgs->pValue->pszVal );
+ dgs->pValue->pszVal = tmpBuf;
+ }
+ else if ( iSaveType == DBVT_ASCIIZ )
+ Utf8Decode( dgs->pValue->pszVal, NULL );
+
+ dgs->pValue->type = iSaveType;
+ return 0;
+}
+
+static int GetContactSettingStatic(WPARAM wParam,LPARAM lParam)
+{
+ DBCONTACTGETSETTING* dgs = (DBCONTACTGETSETTING*)lParam;
+ if ( GetContactSettingWorker(( HANDLE )wParam, dgs, 1 ))
+ return 1;
+
+ if ( dgs->pValue->type == DBVT_UTF8 ) {
+ Utf8Decode( dgs->pValue->pszVal, NULL );
+ dgs->pValue->type = DBVT_ASCIIZ;
+ }
+
+ return 0;
+}
+
+static int FreeVariant(WPARAM wParam,LPARAM lParam)
+{
+ DBVARIANT *dbv=(DBVARIANT*)lParam;
+ if ( dbv == 0 ) return 1;
+ switch ( dbv->type ) {
+ case DBVT_ASCIIZ:
+ case DBVT_UTF8:
+ case DBVT_WCHAR:
+ {
+ if ( dbv->pszVal ) mir_free(dbv->pszVal);
+ dbv->pszVal=0;
+ break;
+ }
+ case DBVT_BLOB:
+ {
+ if ( dbv->pbVal ) mir_free(dbv->pbVal);
+ dbv->pbVal=0;
+ break;
+ }
+ }
+ dbv->type=0;
+ return 0;
+}
+
+static int SetSettingResident(WPARAM wParam,LPARAM lParam)
+{
+ char* szSetting;
+ size_t cbSettingNameLen = strlen(( char* )lParam );
+ int idx;
+ char* szTemp = ( char* )alloca( cbSettingNameLen+2 );
+ strcpy( szTemp+1, ( char* )lParam );
+
+ EnterCriticalSection(&csDbAccess);
+ if ( !li.List_GetIndex( &lSettings, szTemp, &idx ))
+ szSetting = InsertCachedSetting( szTemp, cbSettingNameLen+2, idx );
+ else
+ szSetting = lSettings.items[ idx ];
+
+ *szSetting = (char)wParam;
+
+ LeaveCriticalSection(&csDbAccess);
+ return 0;
+}
+
+static int WriteContactSetting(WPARAM wParam,LPARAM lParam)
+{
+ DBCONTACTWRITESETTING *dbcws=(DBCONTACTWRITESETTING*)lParam;
+ struct DBContact dbc;
+ DWORD ofsModuleName;
+ struct DBContactSettings dbcs;
+ PBYTE pBlob;
+ int settingNameLen=0;
+ int moduleNameLen=0;
+ int settingDataLen=0;
+
+ int bytesRequired,bytesRemaining;
+ DWORD ofsContact,ofsSettingsGroup,ofsBlobPtr;
+
+ if (dbcws == NULL)
+ return 1;
+
+ if (dbcws->value.type == DBVT_WCHAR) {
+ if (dbcws->value.pszVal != NULL) {
+ char* val = Utf8EncodeUcs2(dbcws->value.pwszVal);
+ if ( val == NULL )
+ return 1;
+
+ dbcws->value.pszVal = ( char* )alloca( strlen( val )+1 );
+ strcpy( dbcws->value.pszVal, val );
+ mir_free(val);
+ dbcws->value.type = DBVT_UTF8;
+ }
+ else return 1;
+ }
+
+ if(dbcws->value.type!=DBVT_BYTE && dbcws->value.type!=DBVT_WORD && dbcws->value.type!=DBVT_DWORD && dbcws->value.type!=DBVT_ASCIIZ && dbcws->value.type!=DBVT_UTF8 && dbcws->value.type!=DBVT_BLOB)
+ return 1;
+ if ((!dbcws->szModule) || (!dbcws->szSetting) || ((dbcws->value.type == DBVT_ASCIIZ || dbcws->value.type == DBVT_UTF8 )&& dbcws->value.pszVal == NULL) || (dbcws->value.type == DBVT_BLOB && dbcws->value.pbVal == NULL) )
+ return 1;
+ // the db format can't tolerate more than 255 bytes of space (incl. null) for settings+module name
+ settingNameLen=strlen(dbcws->szSetting);
+ moduleNameLen=strlen(dbcws->szModule);
+ if ( settingNameLen > 0xFE )
+ {
+ #ifdef _DEBUG
+ OutputDebugString("WriteContactSetting() got a > 255 setting name length. \n");
+ #endif
+ return 1;
+ }
+ if ( moduleNameLen > 0xFE )
+ {
+ #ifdef _DEBUG
+ OutputDebugString("WriteContactSetting() got a > 255 module name length. \n");
+ #endif
+ return 1;
+ }
+
+ // the db can not tolerate strings/blobs longer than 0xFFFF since the format writes 2 lengths
+ switch( dbcws->value.type ) {
+ case DBVT_ASCIIZ: case DBVT_BLOB: case DBVT_UTF8:
+ { int len = ( dbcws->value.type != DBVT_BLOB ) ? strlen(dbcws->value.pszVal) : dbcws->value.cpbVal;
+ if ( len >= 0xFFFF ) {
+ #ifdef _DEBUG
+ OutputDebugString("WriteContactSetting() writing huge string/blob, rejecting ( >= 0xFFFF ) \n");
+ #endif
+ return 1;
+ }
+ }
+ }
+
+ EnterCriticalSection(&csDbAccess);
+ {
+ char* szCachedSettingName = GetCachedSetting(dbcws->szModule, dbcws->szSetting, settingNameLen);
+ if ( dbcws->value.type != DBVT_BLOB ) {
+ DBVARIANT* pCachedValue = GetCachedValuePtr((HANDLE)wParam, szCachedSettingName, 1);
+ if ( pCachedValue != NULL ) {
+ BOOL bIsIdentical = FALSE;
+ if ( pCachedValue->type == dbcws->value.type ) {
+ switch(dbcws->value.type) {
+ case DBVT_BYTE: bIsIdentical = pCachedValue->bVal == dbcws->value.bVal; break;
+ case DBVT_WORD: bIsIdentical = pCachedValue->wVal == dbcws->value.wVal; break;
+ case DBVT_DWORD: bIsIdentical = pCachedValue->dVal == dbcws->value.dVal; break;
+ case DBVT_UTF8:
+ case DBVT_ASCIIZ: bIsIdentical = strcmp( pCachedValue->pszVal, dbcws->value.pszVal ) == 0; break;
+ }
+ if ( bIsIdentical ) {
+ LeaveCriticalSection(&csDbAccess);
+ return 0;
+ }
+ }
+ SetCachedVariant(&dbcws->value, pCachedValue);
+ }
+ if ( szCachedSettingName[-1] != 0 ) {
+ LeaveCriticalSection(&csDbAccess);
+ NotifyEventHooks(hSettingChangeEvent,wParam,lParam);
+ return 0;
+ }
+ }
+ else GetCachedValuePtr((HANDLE)wParam, szCachedSettingName, -1);
+ }
+
+ ofsModuleName=GetModuleNameOfs(dbcws->szModule);
+ if(wParam==0) ofsContact=dbHeader.ofsUser;
+ else ofsContact=wParam;
+
+ dbc=*(struct DBContact*)DBRead(ofsContact,sizeof(struct DBContact),NULL);
+ if(dbc.signature!=DBCONTACT_SIGNATURE) {
+ LeaveCriticalSection(&csDbAccess);
+ return 1;
+ }
+ log0("write setting");
+ //make sure the module group exists
+ ofsSettingsGroup=GetSettingsGroupOfsByModuleNameOfs(&dbc,ofsContact,ofsModuleName);
+ if(ofsSettingsGroup==0) { //module group didn't exist - make it
+ if(dbcws->value.type&DBVTF_VARIABLELENGTH) {
+ if(dbcws->value.type==DBVT_ASCIIZ || dbcws->value.type==DBVT_UTF8) bytesRequired=strlen(dbcws->value.pszVal)+2;
+ else if(dbcws->value.type==DBVT_BLOB) bytesRequired=dbcws->value.cpbVal+2;
+ }
+ else bytesRequired=dbcws->value.type;
+ bytesRequired+=2+settingNameLen;
+ bytesRequired+=(DB_SETTINGS_RESIZE_GRANULARITY-(bytesRequired%DB_SETTINGS_RESIZE_GRANULARITY))%DB_SETTINGS_RESIZE_GRANULARITY;
+ ofsSettingsGroup=CreateNewSpace(bytesRequired+offsetof(struct DBContactSettings,blob));
+ dbcs.signature=DBCONTACTSETTINGS_SIGNATURE;
+ dbcs.ofsNext=dbc.ofsFirstSettings;
+ dbcs.ofsModuleName=ofsModuleName;
+ dbcs.cbBlob=bytesRequired;
+ dbcs.blob[0]=0;
+ dbc.ofsFirstSettings=ofsSettingsGroup;
+ DBWrite(ofsContact,&dbc,sizeof(struct DBContact));
+ DBWrite(ofsSettingsGroup,&dbcs,sizeof(struct DBContactSettings));
+ ofsBlobPtr=ofsSettingsGroup+offsetof(struct DBContactSettings,blob);
+ pBlob=(PBYTE)DBRead(ofsBlobPtr,1,&bytesRemaining);
+ }
+ else {
+ dbcs=*(struct DBContactSettings*)DBRead(ofsSettingsGroup,sizeof(struct DBContactSettings),&bytesRemaining);
+ //find if the setting exists
+ ofsBlobPtr=ofsSettingsGroup+offsetof(struct DBContactSettings,blob);
+ pBlob=(PBYTE)DBRead(ofsBlobPtr,1,&bytesRemaining);
+ while(pBlob[0]) {
+ NeedBytes(settingNameLen+1);
+ if(pBlob[0]==settingNameLen && !memcmp(pBlob+1,dbcws->szSetting,settingNameLen))
+ break;
+ NeedBytes(1);
+ MoveAlong(pBlob[0]+1);
+ NeedBytes(3);
+ MoveAlong(1+GetSettingValueLength(pBlob));
+ NeedBytes(1);
+ }
+ if(pBlob[0]) { //setting already existed, and up to end of name is in cache
+ MoveAlong(1+settingNameLen);
+ //if different type or variable length and length is different
+ NeedBytes(3);
+ if(pBlob[0]!=dbcws->value.type || ((pBlob[0]==DBVT_ASCIIZ || pBlob[0]==DBVT_UTF8) && *(PWORD)(pBlob+1)!=strlen(dbcws->value.pszVal)) || (pBlob[0]==DBVT_BLOB && *(PWORD)(pBlob+1)!=dbcws->value.cpbVal)) {
+ //bin it
+ int nameLen,valLen;
+ DWORD ofsSettingToCut;
+ NeedBytes(3);
+ nameLen=1+settingNameLen;
+ valLen=1+GetSettingValueLength(pBlob);
+ ofsSettingToCut=ofsBlobPtr-nameLen;
+ MoveAlong(valLen);
+ NeedBytes(1);
+ while(pBlob[0]) {
+ MoveAlong(pBlob[0]+1);
+ NeedBytes(3);
+ MoveAlong(1+GetSettingValueLength(pBlob));
+ NeedBytes(1);
+ }
+ DBMoveChunk(ofsSettingToCut,ofsSettingToCut+nameLen+valLen,ofsBlobPtr+1-ofsSettingToCut);
+ ofsBlobPtr-=nameLen+valLen;
+ pBlob=(PBYTE)DBRead(ofsBlobPtr,1,&bytesRemaining);
+ }
+ else {
+ //replace existing setting at pBlob
+ MoveAlong(1); //skip data type
+ switch(dbcws->value.type) {
+ case DBVT_BYTE: DBWrite(ofsBlobPtr,&dbcws->value.bVal,1); break;
+ case DBVT_WORD: DBWrite(ofsBlobPtr,&dbcws->value.wVal,2); break;
+ case DBVT_DWORD: DBWrite(ofsBlobPtr,&dbcws->value.dVal,4); break;
+ case DBVT_UTF8:
+ case DBVT_ASCIIZ: DBWrite(ofsBlobPtr+2,dbcws->value.pszVal,strlen(dbcws->value.pszVal)); break;
+ case DBVT_BLOB: DBWrite(ofsBlobPtr+2,dbcws->value.pbVal,dbcws->value.cpbVal); break;
+ }
+ //quit
+ DBFlush(1);
+ LeaveCriticalSection(&csDbAccess);
+ //notify
+ NotifyEventHooks(hSettingChangeEvent,wParam,lParam);
+ return 0;
+ }
+ }
+ }
+ //cannot do a simple replace, add setting to end of list
+ //pBlob already points to end of list
+ //see if it fits
+ if(dbcws->value.type&DBVTF_VARIABLELENGTH) {
+ if(dbcws->value.type==DBVT_ASCIIZ || dbcws->value.type==DBVT_UTF8) bytesRequired=strlen(dbcws->value.pszVal)+2;
+ else if(dbcws->value.type==DBVT_BLOB) bytesRequired=dbcws->value.cpbVal+2;
+ }
+ else bytesRequired=dbcws->value.type;
+ bytesRequired+=2+settingNameLen;
+ bytesRequired+=ofsBlobPtr+1-(ofsSettingsGroup+offsetof(struct DBContactSettings,blob));
+ if((DWORD)bytesRequired>dbcs.cbBlob) {
+ //doesn't fit: move entire group
+ struct DBContactSettings *dbcsPrev;
+ DWORD ofsDbcsPrev,oldSize,ofsNew;
+
+ InvalidateSettingsGroupOfsCacheEntry(ofsSettingsGroup);
+ bytesRequired+=(DB_SETTINGS_RESIZE_GRANULARITY-(bytesRequired%DB_SETTINGS_RESIZE_GRANULARITY))%DB_SETTINGS_RESIZE_GRANULARITY;
+ //find previous group to change its offset
+ ofsDbcsPrev=dbc.ofsFirstSettings;
+ if(ofsDbcsPrev==ofsSettingsGroup) ofsDbcsPrev=0;
+ else {
+ dbcsPrev=(struct DBContactSettings*)DBRead(ofsDbcsPrev,sizeof(struct DBContactSettings),NULL);
+ while(dbcsPrev->ofsNext!=ofsSettingsGroup) {
+ if(dbcsPrev->ofsNext==0) DatabaseCorruption();
+ ofsDbcsPrev=dbcsPrev->ofsNext;
+ dbcsPrev=(struct DBContactSettings*)DBRead(ofsDbcsPrev,sizeof(struct DBContactSettings),NULL);
+ }
+ }
+ //create the new one
+ ofsNew=CreateNewSpace(bytesRequired+offsetof(struct DBContactSettings,blob));
+ //copy across
+ DBMoveChunk(ofsNew,ofsSettingsGroup,bytesRequired+offsetof(struct DBContactSettings,blob));
+ oldSize=dbcs.cbBlob;
+ dbcs.cbBlob=bytesRequired;
+ DBWrite(ofsNew,&dbcs,offsetof(struct DBContactSettings,blob));
+ if(ofsDbcsPrev==0) {
+ dbc.ofsFirstSettings=ofsNew;
+ DBWrite(ofsContact,&dbc,sizeof(struct DBContact));
+ }
+ else {
+ dbcsPrev=(struct DBContactSettings*)DBRead(ofsDbcsPrev,sizeof(struct DBContactSettings),NULL);
+ dbcsPrev->ofsNext=ofsNew;
+ DBWrite(ofsDbcsPrev,dbcsPrev,offsetof(struct DBContactSettings,blob));
+ }
+ DeleteSpace(ofsSettingsGroup,oldSize+offsetof(struct DBContactSettings,blob));
+ ofsBlobPtr+=ofsNew-ofsSettingsGroup;
+ ofsSettingsGroup=ofsNew;
+ pBlob=(PBYTE)DBRead(ofsBlobPtr,1,&bytesRemaining);
+ }
+ //we now have a place to put it and enough space: make it
+ DBWrite(ofsBlobPtr,&settingNameLen,1);
+ DBWrite(ofsBlobPtr+1,(PVOID)dbcws->szSetting,settingNameLen);
+ MoveAlong(1+settingNameLen);
+ DBWrite(ofsBlobPtr,&dbcws->value.type,1);
+ MoveAlong(1);
+ switch(dbcws->value.type) {
+ case DBVT_BYTE: DBWrite(ofsBlobPtr,&dbcws->value.bVal,1); MoveAlong(1); break;
+ case DBVT_WORD: DBWrite(ofsBlobPtr,&dbcws->value.wVal,2); MoveAlong(2); break;
+ case DBVT_DWORD: DBWrite(ofsBlobPtr,&dbcws->value.dVal,4); MoveAlong(4); break;
+ case DBVT_UTF8:
+ case DBVT_ASCIIZ:
+ { int len=strlen(dbcws->value.pszVal);
+ DBWrite(ofsBlobPtr,&len,2);
+ DBWrite(ofsBlobPtr+2,dbcws->value.pszVal,len);
+ MoveAlong(2+len);
+ }
+ break;
+ case DBVT_BLOB:
+ DBWrite(ofsBlobPtr,&dbcws->value.cpbVal,2);
+ DBWrite(ofsBlobPtr+2,dbcws->value.pbVal,dbcws->value.cpbVal);
+ MoveAlong(2+dbcws->value.cpbVal);
+ break;
+ }
+ { BYTE zero=0;
+ DBWrite(ofsBlobPtr,&zero,1);
+ }
+ //quit
+ DBFlush(1);
+ LeaveCriticalSection(&csDbAccess);
+ //notify
+ NotifyEventHooks(hSettingChangeEvent,wParam,lParam);
+ return 0;
+}
+
+static int DeleteContactSetting(WPARAM wParam,LPARAM lParam)
+{
+ DBCONTACTGETSETTING *dbcgs=(DBCONTACTGETSETTING*)lParam;
+ struct DBContact *dbc;
+ DWORD ofsModuleName,ofsSettingsGroup,ofsBlobPtr;
+ struct DBContactSettings dbcs;
+ PBYTE pBlob;
+ int settingNameLen=strlen(dbcgs->szSetting),bytesRemaining;
+ char* szCachedSettingName;
+ WPARAM saveWparam = wParam;
+
+ if ((!dbcgs->szModule) || (!dbcgs->szSetting))
+ return 1;
+
+ EnterCriticalSection(&csDbAccess);
+ ofsModuleName=GetModuleNameOfs(dbcgs->szModule);
+ if(wParam==0) wParam=dbHeader.ofsUser;
+
+ dbc=(struct DBContact*)DBRead(wParam,sizeof(struct DBContact),NULL);
+ if(dbc->signature!=DBCONTACT_SIGNATURE) {
+ LeaveCriticalSection(&csDbAccess);
+ return 1;
+ }
+ //make sure the module group exists
+ ofsSettingsGroup=GetSettingsGroupOfsByModuleNameOfs(dbc,wParam,ofsModuleName);
+ if(ofsSettingsGroup==0) {
+ LeaveCriticalSection(&csDbAccess);
+ return 1;
+ }
+ dbc=(struct DBContact*)DBRead(wParam,sizeof(struct DBContact),NULL);
+ if(dbc->signature!=DBCONTACT_SIGNATURE) {
+ LeaveCriticalSection(&csDbAccess);
+ return 1;
+ }
+ ofsSettingsGroup=GetSettingsGroupOfsByModuleNameOfs(dbc,wParam,ofsModuleName);
+ if(ofsSettingsGroup==0) {
+ LeaveCriticalSection(&csDbAccess);
+ return 1;
+ }
+ dbcs=*(struct DBContactSettings*)DBRead(ofsSettingsGroup,sizeof(struct DBContactSettings),NULL);
+ //find if the setting exists
+ ofsBlobPtr=ofsSettingsGroup+offsetof(struct DBContactSettings,blob);
+ pBlob=(PBYTE)DBRead(ofsBlobPtr,1,&bytesRemaining);
+ while(pBlob[0]) {
+ NeedBytes(settingNameLen+1);
+ if(pBlob[0]==settingNameLen && !memcmp(pBlob+1,dbcgs->szSetting,settingNameLen))
+ break;
+ NeedBytes(1);
+ MoveAlong(pBlob[0]+1);
+ NeedBytes(3);
+ MoveAlong(1+GetSettingValueLength(pBlob));
+ NeedBytes(1);
+ }
+ if(!pBlob[0]) { //setting didn't exist
+ LeaveCriticalSection(&csDbAccess);
+ return 1;
+ }
+ { //bin it
+ int nameLen,valLen;
+ DWORD ofsSettingToCut;
+ MoveAlong(1+settingNameLen);
+ NeedBytes(3);
+ nameLen=1+settingNameLen;
+ valLen=1+GetSettingValueLength(pBlob);
+ ofsSettingToCut=ofsBlobPtr-nameLen;
+ MoveAlong(valLen);
+ NeedBytes(1);
+ while(pBlob[0]) {
+ MoveAlong(pBlob[0]+1);
+ NeedBytes(3);
+ MoveAlong(1+GetSettingValueLength(pBlob));
+ NeedBytes(1);
+ }
+ DBMoveChunk(ofsSettingToCut,ofsSettingToCut+nameLen+valLen,ofsBlobPtr+1-ofsSettingToCut);
+ }
+
+ szCachedSettingName = GetCachedSetting(dbcgs->szModule,dbcgs->szSetting,settingNameLen);
+ GetCachedValuePtr((HANDLE)saveWparam, szCachedSettingName, -1 );
+
+ //quit
+ DBFlush(1);
+ LeaveCriticalSection(&csDbAccess);
+ { //notify
+ DBCONTACTWRITESETTING dbcws;
+ dbcws.szModule=dbcgs->szModule;
+ dbcws.szSetting=dbcgs->szSetting;
+ dbcws.value.type=DBVT_DELETED;
+ NotifyEventHooks(hSettingChangeEvent,saveWparam,(LPARAM)&dbcws);
+ }
+ return 0;
+}
+
+static int EnumContactSettings(WPARAM wParam,LPARAM lParam)
+{
+ DBCONTACTENUMSETTINGS *dbces=(DBCONTACTENUMSETTINGS*)lParam;
+ struct DBContact dbc;
+ struct DBContactSettings dbcs;
+ DWORD ofsModuleName,ofsContact,ofsBlobPtr;
+ int bytesRemaining, result;
+ PBYTE pBlob;
+ char szSetting[256];
+
+ if (!dbces->szModule)
+ return -1;
+
+ EnterCriticalSection(&csDbAccess);
+
+ ofsModuleName=GetModuleNameOfs(dbces->szModule);
+ if(wParam==0) ofsContact=dbHeader.ofsUser;
+ else ofsContact=wParam;
+ dbc=*(struct DBContact*)DBRead(ofsContact,sizeof(struct DBContact),NULL);
+ if(dbc.signature!=DBCONTACT_SIGNATURE) {
+ LeaveCriticalSection(&csDbAccess);
+ return -1;
+ }
+ dbces->ofsSettings=GetSettingsGroupOfsByModuleNameOfs(&dbc,ofsContact,ofsModuleName);
+ if(!dbces->ofsSettings) {
+ LeaveCriticalSection(&csDbAccess);
+ return -1;
+ }
+ dbcs=*(struct DBContactSettings*)DBRead(dbces->ofsSettings,sizeof(struct DBContactSettings),&bytesRemaining);
+ ofsBlobPtr=dbces->ofsSettings+offsetof(struct DBContactSettings,blob);
+ pBlob=(PBYTE)DBRead(ofsBlobPtr,1,&bytesRemaining);
+ if(pBlob[0]==0) {
+ LeaveCriticalSection(&csDbAccess);
+ return -1;
+ }
+ result = 0;
+ while(pBlob[0]) {
+ NeedBytes(1);
+ NeedBytes(1+pBlob[0]);
+ CopyMemory(szSetting,pBlob+1,pBlob[0]); szSetting[pBlob[0]]=0;
+ result = (dbces->pfnEnumProc)(szSetting,dbces->lParam);
+ MoveAlong(1+pBlob[0]);
+ NeedBytes(3);
+ MoveAlong(1+GetSettingValueLength(pBlob));
+ NeedBytes(1);
+ }
+ LeaveCriticalSection(&csDbAccess);
+ return result;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+//
+// Module initialization procedure
+
+static int stringCompare( DBCachedSettingName* p1, DBCachedSettingName* p2 )
+{
+ return strcmp( p1->name, p2->name );
+}
+
+static int stringCompare2( DBCachedGlobalValue* p1, DBCachedGlobalValue* p2 )
+{
+ return strcmp( p1->name, p2->name );
+}
+
+static int handleCompare( void* p1, void* p2 )
+{
+ if ( *( long* )p1 == *( long* )p2 )
+ return 0;
+
+ return *( long* )p1 - *( long* )p2;
+}
+
+int InitSettings(void)
+{
+ CreateServiceFunction(MS_DB_CONTACT_GETSETTING,GetContactSetting);
+ CreateServiceFunction(MS_DB_CONTACT_GETSETTING_STR,GetContactSettingStr);
+ CreateServiceFunction(MS_DB_CONTACT_GETSETTINGSTATIC,GetContactSettingStatic);
+ CreateServiceFunction(MS_DB_CONTACT_FREEVARIANT,FreeVariant);
+ CreateServiceFunction(MS_DB_CONTACT_WRITESETTING,WriteContactSetting);
+ CreateServiceFunction(MS_DB_CONTACT_DELETESETTING,DeleteContactSetting);
+ CreateServiceFunction(MS_DB_CONTACT_ENUMSETTINGS,EnumContactSettings);
+ CreateServiceFunction(MS_DB_SETSETTINGRESIDENT,SetSettingResident);
+ hSettingChangeEvent=CreateHookableEvent(ME_DB_CONTACT_SETTINGCHANGED);
+
+ hCacheHeap=HeapCreate(HEAP_NO_SERIALIZE,0,0);
+ lSettings.sortFunc=stringCompare;
+ lSettings.increment=50;
+ lContacts.sortFunc=handleCompare;
+ lContacts.increment=100;
+ lGlobalSettings.sortFunc=stringCompare2;
+ lGlobalSettings.increment=100;
+ return 0;
+}
+
+void UninitSettings(void)
+{
+ HeapDestroy(hCacheHeap);
+ li.List_Destroy(&lContacts);
+ li.List_Destroy(&lSettings);
+ li.List_Destroy(&lGlobalSettings);
+}
diff --git a/miranda-wine/plugins/db3x/dbtime.c b/miranda-wine/plugins/db3x/dbtime.c
new file mode 100644
index 0000000..e9189b9
--- /dev/null
+++ b/miranda-wine/plugins/db3x/dbtime.c
@@ -0,0 +1,163 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "database.h"
+
+static int daysInMonth[12]={31,28,31,30,31,30,31,31,30,31,30,31};
+static int IsLeapYear(int year)
+{
+ if(year&3) return 0;
+ if(year%100) return 1;
+ if(year%400) return 0;
+ return 1;
+}
+
+static int CompareSystemTimes(SYSTEMTIME *st,SYSTEMTIME *switchDate)
+{
+ FILETIME ft1,ft2;
+
+ if(switchDate->wYear==0) { //strange day-in-month thing
+ SYSTEMTIME tempst;
+
+ //short-circuit if the months aren't the same
+ if(st->wMonth<switchDate->wMonth) return -1;
+ if(st->wMonth>switchDate->wMonth) return 1;
+
+ tempst=*switchDate;
+ tempst.wYear=st->wYear;
+ tempst.wDay=1;
+ SystemTimeToFileTime(&tempst,&ft1);
+ FileTimeToSystemTime(&ft1,&tempst); //gets the day of week of the first of the month
+ tempst.wDay=1+(7+switchDate->wDayOfWeek-tempst.wDayOfWeek)%7;
+ if(switchDate->wDay==5) { //last wDayOfWeek in month
+ if(tempst.wMonth==2) {
+ if(IsLeapYear(tempst.wYear)) daysInMonth[1]=29;
+ else daysInMonth[1]=28;
+ }
+ tempst.wDay+=7*3; //can't be less than 4 of that day in the month
+ if(tempst.wDay+7<=daysInMonth[switchDate->wMonth-1]) tempst.wDay+=7;
+ }
+ else tempst.wDay+=7*(switchDate->wDay-1); //nth of month
+ SystemTimeToFileTime(&tempst,&ft2);
+ }
+ else {
+ switchDate->wYear=st->wYear;
+ SystemTimeToFileTime(switchDate,&ft2);
+ }
+ SystemTimeToFileTime(st,&ft1);
+ return CompareFileTime(&ft1,&ft2);
+}
+
+static int TimestampToLocal(WPARAM wParam,LPARAM lParam)
+{
+ TIME_ZONE_INFORMATION tzInfo;
+ LARGE_INTEGER liFiletime;
+ FILETIME filetime;
+ SYSTEMTIME st;
+
+ GetTimeZoneInformation(&tzInfo);
+ if(tzInfo.StandardDate.wMonth==0) { //no daylight savings time
+ return (int)(wParam-tzInfo.Bias*60);
+ }
+ //this huge number is the difference between 1970 and 1601 in seconds
+ liFiletime.QuadPart=(mir_i64(11644473600)+(__int64)wParam)*10000000;
+ filetime.dwHighDateTime=liFiletime.HighPart;
+ filetime.dwLowDateTime=liFiletime.LowPart;
+ FileTimeToSystemTime(&filetime,&st);
+ if(tzInfo.DaylightDate.wMonth<tzInfo.StandardDate.wMonth) {
+ //northern hemisphere
+ if(CompareSystemTimes(&st,&tzInfo.DaylightDate)<0 ||
+ CompareSystemTimes(&st,&tzInfo.StandardDate)>0) {
+ return (int)(wParam-(tzInfo.Bias+tzInfo.StandardBias)*60);
+ }
+ return (int)(wParam-(tzInfo.Bias+tzInfo.DaylightBias)*60);
+ }
+ else {
+ //southern hemisphere
+ if(CompareSystemTimes(&st,&tzInfo.StandardDate)<0 ||
+ CompareSystemTimes(&st,&tzInfo.DaylightDate)>0) {
+ return (int)(wParam-(tzInfo.Bias+tzInfo.DaylightBias)*60);
+ }
+ return (int)(wParam-(tzInfo.Bias+tzInfo.StandardBias)*60);
+ }
+ return 0;
+}
+
+static int TimestampToString(WPARAM wParam,LPARAM lParam)
+{
+ DBTIMETOSTRING *tts=(DBTIMETOSTRING*)lParam;
+ LARGE_INTEGER liFiletime;
+ FILETIME filetime;
+ SYSTEMTIME st;
+ char dateTimeStr[64];
+ char *pDest,*pFormat;
+ int destCharsLeft,dateTimeStrLen;
+
+ //this huge number is the difference between 1970 and 1601 in seconds
+ liFiletime.QuadPart=(mir_i64(11644473600)+(__int64)(DWORD)TimestampToLocal(wParam,0))*10000000;
+ filetime.dwHighDateTime=liFiletime.HighPart;
+ filetime.dwLowDateTime=liFiletime.LowPart;
+ FileTimeToSystemTime(&filetime,&st);
+ destCharsLeft=tts->cbDest;
+ for(pFormat=tts->szFormat,pDest=tts->szDest;*pFormat;pFormat++) {
+ switch(*pFormat) {
+ case 't':
+ GetTimeFormat(LOCALE_USER_DEFAULT,TIME_NOSECONDS,&st,NULL,dateTimeStr,sizeof(dateTimeStr));
+ break;
+ case 's':
+ GetTimeFormat(LOCALE_USER_DEFAULT,0,&st,NULL,dateTimeStr,sizeof(dateTimeStr));
+ break;
+ case 'm':
+ GetTimeFormat(LOCALE_USER_DEFAULT,TIME_NOMINUTESORSECONDS,&st,NULL,dateTimeStr,sizeof(dateTimeStr));
+ break;
+ case 'd':
+ GetDateFormat(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&st,NULL,dateTimeStr,sizeof(dateTimeStr));
+ break;
+ case 'D':
+ GetDateFormat(LOCALE_USER_DEFAULT,DATE_LONGDATE,&st,NULL,dateTimeStr,sizeof(dateTimeStr));
+ break;
+ default:
+ if(destCharsLeft) {
+ *pDest++=*pFormat;
+ destCharsLeft--;
+ }
+ continue;
+ }
+ dateTimeStrLen=strlen(dateTimeStr);
+ if(destCharsLeft<dateTimeStrLen) dateTimeStrLen=destCharsLeft;
+ CopyMemory(pDest,dateTimeStr,dateTimeStrLen);
+ destCharsLeft-=dateTimeStrLen;
+ pDest+=dateTimeStrLen;
+ }
+ if(destCharsLeft) *pDest=0;
+ else tts->szDest[tts->cbDest-1]=0;
+ return 0;
+}
+
+int InitTime(void)
+{
+ CreateServiceFunction(MS_DB_TIME_TIMESTAMPTOLOCAL,TimestampToLocal);
+ CreateServiceFunction(MS_DB_TIME_TIMESTAMPTOSTRING,TimestampToString);
+ return 0;
+}
diff --git a/miranda-wine/plugins/db3x/encrypt.c b/miranda-wine/plugins/db3x/encrypt.c
new file mode 100644
index 0000000..1382a27
--- /dev/null
+++ b/miranda-wine/plugins/db3x/encrypt.c
@@ -0,0 +1,67 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "database.h"
+
+//VERY VERY VERY BASIC ENCRYPTION FUNCTION
+
+
+void Encrypt(char*msg,BOOL up)
+{
+ int i;
+ int jump;
+ if (up)
+ {
+ jump=5;
+ }
+ else
+ {
+ jump=-5;
+ }
+
+ for (i=0;msg[i];i++)
+ {
+ msg[i]=msg[i]+jump;
+ }
+
+}
+
+static int EncodeString(WPARAM wParam,LPARAM lParam)
+{
+ Encrypt((char*)lParam,TRUE);
+ return 0;
+}
+
+static int DecodeString(WPARAM wParam,LPARAM lParam)
+{
+ Encrypt((char*)lParam,FALSE);
+ return 0;
+}
+
+int InitCrypt(void)
+{
+ CreateServiceFunction(MS_DB_CRYPT_ENCODESTRING,EncodeString);
+ CreateServiceFunction(MS_DB_CRYPT_DECODESTRING,DecodeString);
+ return 0;
+}
diff --git a/miranda-wine/plugins/db3x/encryption.h b/miranda-wine/plugins/db3x/encryption.h
new file mode 100644
index 0000000..73c2d7e
--- /dev/null
+++ b/miranda-wine/plugins/db3x/encryption.h
@@ -0,0 +1,23 @@
+/*
+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.
+*/
+#ifndef MODULAR
+#include <windows.h>
+
+void Encrypt(char*msg,BOOL up);
+#endif \ No newline at end of file
diff --git a/miranda-wine/plugins/db3x/init.c b/miranda-wine/plugins/db3x/init.c
new file mode 100644
index 0000000..91834ed
--- /dev/null
+++ b/miranda-wine/plugins/db3x/init.c
@@ -0,0 +1,193 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "database.h"
+#include <m_plugins.h>
+
+struct MM_INTERFACE memoryManagerInterface;
+struct LIST_INTERFACE li;
+extern char szDbPath[MAX_PATH];
+
+HINSTANCE g_hInst=NULL;
+PLUGINLINK *pluginLink;
+
+static int getCapability( int flag )
+{
+ return 0;
+}
+
+// returns 0 if the profile is created, EMKPRF*
+static int makeDatabase(char * profile, int * error)
+{
+ HANDLE hFile=CreateFile(profile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
+ if ( hFile != INVALID_HANDLE_VALUE ) {
+ CreateDbHeaders(hFile);
+ CloseHandle(hFile);
+ return 0;
+ }
+ if ( error != NULL ) *error=EMKPRF_CREATEFAILED;
+ return 1;
+}
+
+// returns 0 if the given profile has a valid header
+static int grokHeader( char * profile, int * error )
+{
+ int rc=1;
+ int chk=0;
+ struct DBHeader hdr;
+ HANDLE hFile = INVALID_HANDLE_VALUE;
+ DWORD dummy=0;
+
+ hFile = CreateFile(profile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+ if ( hFile == INVALID_HANDLE_VALUE ) {
+ if ( error != NULL ) *error=EGROKPRF_CANTREAD;
+ return 1;
+ }
+ // read the header, which can fail (for various reasons)
+ if ( !ReadFile(hFile, &hdr, sizeof(struct DBHeader), &dummy, NULL) ) {
+ if ( error != NULL) *error=EGROKPRF_CANTREAD;
+ CloseHandle(hFile);
+ return 1;
+ }
+ chk=CheckDbHeaders(&hdr);
+ if ( chk == 0 ) {
+ // all the internal tests passed, hurrah
+ rc=0;
+ if ( error != NULL ) *error=0;
+ } else {
+ // didn't pass at all, or some did.
+ switch ( chk ) {
+ case 1:
+ {
+ // "Miranda ICQ DB" wasn't present
+ if ( error != NULL ) *error = EGROKPRF_UNKHEADER;
+ break;
+ }
+ case 2:
+ {
+ // header was present, but version information newer
+ if ( error != NULL ) *error= EGROKPRF_VERNEWER;
+ break;
+ }
+ case 3:
+ {
+ // header/version OK, internal data missing
+ if ( error != NULL ) *error=EGROKPRF_DAMAGED;
+ break;
+ }
+ } // switch
+ } //if
+ CloseHandle(hFile);
+ return rc;
+}
+
+// returns 0 if all the APIs are injected otherwise, 1
+static int LoadDatabase( char * profile, void * plink )
+{
+ PLUGINLINK *link = plink;
+#ifdef _DEBUG
+ _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
+#endif
+ // don't need thread notifications
+ strncpy(szDbPath, profile, sizeof(szDbPath));
+ // this is like Load()'s pluginLink
+ pluginLink=link;
+ // set the memory manager
+ memoryManagerInterface.cbSize=sizeof(struct MM_INTERFACE);
+ CallService(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 version of plugin requires Miranda IM 0.5 or later", "Fatal error", MB_OK );
+ return 1;
+ }
+
+ // inject all APIs and hooks into the core
+ return LoadDatabaseModule();
+}
+
+static int UnloadDatabase(int wasLoaded)
+{
+ if ( !wasLoaded) return 0;
+ UnloadDatabaseModule();
+ return 0;
+}
+
+static int getFriendlyName( char * buf, size_t cch, int shortName )
+{
+ strncpy(buf,shortName ? "db3x driver" : "db3x database support",cch);
+ return 0;
+}
+
+
+static DATABASELINK dblink = {
+ sizeof(DATABASELINK),
+ getCapability,
+ getFriendlyName,
+ makeDatabase,
+ grokHeader,
+ LoadDatabase,
+ UnloadDatabase,
+};
+
+static PLUGININFO pluginInfo = {
+ sizeof(PLUGININFO),
+ "Miranda database driver",
+ PLUGIN_MAKE_VERSION(0,6,0,0),
+ "Provides Miranda database support: global settings, contacts, history, settings per contact.",
+ "Miranda-IM project",
+ "ghazan@miranda-im.org",
+ "Copyright 2000-2006 Miranda IM project",
+ "",
+ 0,
+ DEFMOD_DB
+};
+
+
+BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD dwReason, LPVOID reserved)
+{
+ g_hInst=hInstDLL;
+ return TRUE;
+}
+
+__declspec(dllexport) DATABASELINK* DatabasePluginInfo(void * reserved)
+{
+ return &dblink;
+}
+
+__declspec(dllexport) PLUGININFO * MirandaPluginInfo(DWORD mirandaVersion)
+{
+ if ( mirandaVersion < PLUGIN_MAKE_VERSION(0,4,0,0) ) return NULL;
+ return &pluginInfo;
+}
+
+int __declspec(dllexport) Load(PLUGINLINK * link)
+{
+ return 1;
+}
+
+int __declspec(dllexport) Unload(void)
+{
+ return 0;
+}
diff --git a/miranda-wine/plugins/db3x/resource.h b/miranda-wine/plugins/db3x/resource.h
new file mode 100644
index 0000000..96abbff
--- /dev/null
+++ b/miranda-wine/plugins/db3x/resource.h
@@ -0,0 +1,30 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by resource.rc
+//
+#define IDC_NOTOALL 3
+#define IDD_INSTALLINI 235
+#define IDD_WARNINICHANGE 236
+#define IDD_INIIMPORTDONE 237
+#define IDC_ININAME 1333
+#define IDC_VIEWINI 1334
+#define IDC_SECURITYINFO 1335
+#define IDC_SETTINGNAME 1336
+#define IDC_NEWVALUE 1337
+#define IDC_WARNNOMORE 1338
+#define IDC_DELETE 1339
+#define IDC_RECYCLE 1340
+#define IDC_NEWNAME 1341
+#define IDC_MOVE 1342
+#define IDC_LEAVE 1343
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 269
+#define _APS_NEXT_COMMAND_VALUE 40018
+#define _APS_NEXT_CONTROL_VALUE 1657
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/miranda-wine/plugins/db3x/resource.rc b/miranda-wine/plugins/db3x/resource.rc
new file mode 100644
index 0000000..daa99f3
--- /dev/null
+++ b/miranda-wine/plugins/db3x/resource.rc
@@ -0,0 +1,169 @@
+//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
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_INSTALLINI DIALOGEX 0, 0, 212, 102
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Install Database Settings"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "Yes",IDOK,26,83,50,14
+ PUSHBUTTON "No",IDCANCEL,81,83,50,14
+ LTEXT "A file containing new database settings has been placed in the Miranda IM directory.",
+ IDC_STATIC,5,5,202,16
+ LTEXT "Do you want to import the settings now?",IDC_STATIC,5,
+ 69,202,8
+ PUSHBUTTON "No to all",IDC_NOTOALL,136,83,50,14
+ LTEXT "",IDC_ININAME,5,24,143,16,SS_NOPREFIX | SS_CENTERIMAGE
+ PUSHBUTTON "&View contents",IDC_VIEWINI,149,25,58,14
+ LTEXT "Security systems to prevent malicious changes are in place and you will be warned before changes that are not known to be safe.",
+ IDC_SECURITYINFO,5,43,202,24
+END
+
+IDD_WARNINICHANGE DIALOGEX 0, 0, 187, 113
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Database Setting Change"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Database settings are being imported from",IDC_STATIC,5,
+ 5,177,8
+ CONTROL "",IDC_ININAME,"Static",SS_SIMPLE | SS_NOPREFIX |
+ WS_GROUP,5,13,177,8
+ LTEXT "This file wishes to change the setting",IDC_STATIC,5,24,
+ 177,8
+ CONTROL "",IDC_SETTINGNAME,"Static",SS_SIMPLE | SS_NOPREFIX |
+ WS_GROUP,12,33,170,8
+ LTEXT "to the value",IDC_STATIC,5,42,177,8
+ CONTROL "",IDC_NEWVALUE,"Static",SS_SIMPLE | SS_NOPREFIX |
+ WS_GROUP,12,51,170,8
+ LTEXT "",IDC_SECURITYINFO,5,60,177,8
+ LTEXT "Do you want to allow this change?",IDC_STATIC,5,71,177,
+ 8
+ CONTROL "&Allow all further changes to this section",
+ IDC_WARNNOMORE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,
+ 80,169,10
+ DEFPUSHBUTTON "&Yes",IDYES,5,94,50,14
+ PUSHBUTTON "&No",IDNO,59,94,50,14
+ PUSHBUTTON "Cancel Import",IDCANCEL,123,94,59,14
+END
+
+IDD_INIIMPORTDONE DIALOGEX 0, 0, 186, 73
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Database Import Complete"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "The import has completed from",IDC_STATIC,5,5,176,8
+ CONTROL "",IDC_ININAME,"Static",SS_SIMPLE | SS_NOPREFIX |
+ WS_GROUP,5,13,176,8
+ LTEXT "What do you want to do with the file now?",IDC_STATIC,5,
+ 24,176,8
+ PUSHBUTTON "&Recycle",IDC_RECYCLE,5,36,50,14
+ PUSHBUTTON "&Delete",IDC_DELETE,68,36,50,14
+ EDITTEXT IDC_NEWNAME,5,55,117,12,ES_AUTOHSCROLL
+ PUSHBUTTON "&Move/Rename",IDC_MOVE,124,54,57,14
+ PUSHBUTTON "&Leave",IDC_LEAVE,131,36,50,14
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_INSTALLINI, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 207
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 97
+ END
+
+ IDD_WARNINICHANGE, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 182
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 108
+ END
+
+ IDD_INIIMPORTDONE, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 181
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 68
+ 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
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
diff --git a/miranda-wine/plugins/db3x/utf.c b/miranda-wine/plugins/db3x/utf.c
new file mode 100644
index 0000000..52064a6
--- /dev/null
+++ b/miranda-wine/plugins/db3x/utf.c
@@ -0,0 +1,166 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "database.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Utf8Decode - converts UTF8-encoded string to the UCS2/MBCS format
+
+void Utf8Decode( char* str, wchar_t** ucs2 )
+{
+ int len;
+ wchar_t* tempBuf;
+
+ if ( str == NULL )
+ return;
+
+ 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;
+ }
+
+ 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* )mir_alloc( 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* Utf8Encode( const char* src )
+{
+ int len;
+ char* result;
+ wchar_t* tempBuf;
+
+ if ( src == NULL )
+ return NULL;
+
+ len = strlen( src );
+ result = ( char* )mir_alloc( len*3 + 1 );
+ if ( result == NULL )
+ return NULL;
+
+ 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* Utf8EncodeUcs2( const wchar_t* src )
+{
+ int len = wcslen( src );
+ char* result = ( char* )mir_alloc( 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;
+}
diff --git a/miranda-wine/plugins/png2dib/m_png.h b/miranda-wine/plugins/png2dib/m_png.h
new file mode 100644
index 0000000..cd037ba
--- /dev/null
+++ b/miranda-wine/plugins/png2dib/m_png.h
@@ -0,0 +1,64 @@
+/*
+Plugin of Miranda IM for reading/writing PNG images.
+Copyright (c) 2004-6 George Hazan (ghazan@postman.ru)
+
+Portions of this code are gotten from the libpng codebase.
+Copyright 2000, Willem van Schaik. For conditions of distribution and
+use, see the copyright/license/disclaimer notice in png.h
+
+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.
+
+File name : $Source: /cvsroot/miranda/miranda/plugins/png2dib/m_png.h,v $
+Revision : $Revision: 3502 $
+Last change on : $Date: 2006-08-16 01:21:49 +0400 (Срд, 16 Ðвг 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+/* Image/Dib2Png
+Converts a Device Independent Bitmap to a png stored in memory
+ wParam=0
+ lParam=(WPARAM)(DIB2PNG*)descr
+*/
+
+typedef struct
+{
+ BITMAPINFO* pbmi;
+ BYTE* pDiData;
+ BYTE* pResult;
+ long* pResultLen;
+}
+ DIB2PNG;
+
+#define MS_DIB2PNG "Image/Dib2Png"
+
+/* Image/Png2Dib
+Converts a png stored in memory to a Device Independent Bitmap
+ wParam=0
+ lParam=(WPARAM)(PNG2DIB*)descr
+*/
+
+typedef struct
+{
+ BYTE* pSource;
+ DWORD cbSourceSize;
+ BITMAPINFOHEADER** pResult;
+}
+ PNG2DIB;
+
+#define MS_PNG2DIB "Image/Png2Dib"
diff --git a/miranda-wine/plugins/png2dib/png2dib.c b/miranda-wine/plugins/png2dib/png2dib.c
new file mode 100644
index 0000000..5e531ef
--- /dev/null
+++ b/miranda-wine/plugins/png2dib/png2dib.c
@@ -0,0 +1,411 @@
+/*
+Plugin of Miranda IM for reading/writing PNG images.
+Copyright (c) 2004-6 George Hazan (ghazan@postman.ru)
+
+Portions of this code are gotten from the libpng codebase.
+Copyright 2000, Willem van Schaik. For conditions of distribution and
+use, see the copyright/license/disclaimer notice in png.h
+
+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.
+
+File name : $Source: /cvsroot/miranda/miranda/plugins/png2dib/png2dib.c,v $
+Revision : $Revision: 3502 $
+Last change on : $Date: 2006-08-16 01:21:49 +0400 (Срд, 16 Ðвг 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include <windows.h>
+#include <commdlg.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "libpng/png.h"
+
+#include "newpluginapi.h"
+#include "version.h"
+#include "m_png.h"
+
+DWORD __declspec(dllexport) getver( void )
+{
+ return __VERSION_DWORD;
+}
+
+// PNG image handler functions
+
+typedef struct {
+ char* mBuffer;
+ size_t mBufSize;
+ size_t mBufPtr;
+}
+ HMemBufInfo;
+
+static void png_read_data( png_structp png_ptr, png_bytep data, png_size_t length )
+{
+ HMemBufInfo* io = ( HMemBufInfo* )png_ptr->io_ptr;
+ if ( length + io->mBufPtr > io->mBufSize )
+ length = io->mBufSize - io->mBufPtr;
+
+ if ( length > 0 ) {
+ memcpy( data, io->mBuffer + io->mBufPtr, length );
+ io->mBufPtr += length;
+ }
+ else png_error(png_ptr, "Read Error");
+}
+
+static void png_write_data( png_structp png_ptr, png_bytep data, png_size_t length )
+{
+ HMemBufInfo* io = ( HMemBufInfo* )png_ptr->io_ptr;
+ if ( io->mBuffer != NULL )
+ memcpy( io->mBuffer + io->mBufPtr, data, length );
+
+ io->mBufPtr += length;
+}
+
+static void png_flush( png_structp png_ptr )
+{
+}
+
+/*
+ * Converting a png image into a bitmap
+ */
+
+BOOL __declspec(dllexport) mempng2dib(
+ BYTE* pSource,
+ DWORD cbSourceSize,
+ BITMAPINFOHEADER** ppDibData )
+{
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+ HMemBufInfo sBuffer = { pSource, cbSourceSize, 8 };
+
+ BOOL bResult = FALSE;
+ int iWidth;
+ int iHeight;
+ png_color pBkgColor;
+ int iBitDepth;
+ int iColorType;
+ double dGamma;
+ png_color_16* pBackground;
+ png_uint_32 ulChannels;
+ png_uint_32 ulRowBytes;
+ png_byte* pbImageData;
+ png_byte** ppbRowPointers = NULL;
+ int i;
+ int wDIRowBytes;
+ BYTE* pImageData;
+
+ *ppDibData = NULL;
+
+ if ( pSource == NULL || cbSourceSize == 0 )
+ return FALSE;
+
+ if ( !png_check_sig( pSource, 8 ))
+ return FALSE;
+
+ // create the two png(-info) structures
+ png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
+ if (!png_ptr)
+ return FALSE;
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if ( !info_ptr ) {
+ png_destroy_read_struct(&png_ptr, NULL, NULL);
+ return FALSE;
+ }
+
+ // initialize the png structure
+ png_set_read_fn(png_ptr, (png_voidp)&sBuffer, png_read_data);
+ png_set_sig_bytes(png_ptr, 8);
+
+ // read all PNG info up to image data
+ png_read_info(png_ptr, info_ptr);
+
+ // get width, height, bit-depth and color-type
+
+ png_get_IHDR(png_ptr, info_ptr, &iWidth, &iHeight, &iBitDepth, &iColorType, NULL, NULL, NULL);
+
+ // expand images of all color-type and bit-depth to 3x8 bit RGB images
+ // let the library process things like alpha, transparency, background
+
+ if ( iBitDepth == 16 )
+ png_set_strip_16( png_ptr );
+ if ( iColorType == PNG_COLOR_TYPE_PALETTE )
+ png_set_expand( png_ptr );
+ if ( iBitDepth < 8 )
+ png_set_expand( png_ptr );
+ if (png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS ))
+ png_set_expand( png_ptr );
+ if ( iColorType == PNG_COLOR_TYPE_GRAY || iColorType == PNG_COLOR_TYPE_GRAY_ALPHA )
+ png_set_gray_to_rgb( png_ptr );
+
+ // set the background color to draw transparent and alpha images over.
+ if (png_get_bKGD( png_ptr, info_ptr, &pBackground )) {
+ png_set_background(png_ptr, pBackground, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
+ pBkgColor.red = (byte) pBackground->red;
+ pBkgColor.green = (byte) pBackground->green;
+ pBkgColor.blue = (byte) pBackground->blue;
+ }
+
+ // if required set gamma conversion
+ if ( png_get_gAMA( png_ptr, info_ptr, &dGamma ))
+ png_set_gamma( png_ptr, (double) 2.2, dGamma );
+
+ // after the transformations have been registered update info_ptr data
+ png_read_update_info(png_ptr, info_ptr);
+
+ // get again width, height and the new bit-depth and color-type
+ png_get_IHDR(png_ptr, info_ptr, &iWidth, &iHeight, &iBitDepth, &iColorType, NULL, NULL, NULL);
+
+ // row_bytes is the width x number of channels
+ ulRowBytes = png_get_rowbytes(png_ptr, info_ptr);
+ ulChannels = png_get_channels(png_ptr, info_ptr);
+ wDIRowBytes = (WORD) (( ulChannels * iWidth + 3L) >> 2) << 2;
+
+ // now we can allocate memory to store the image
+ { DWORD cbMemSize = sizeof( BITMAPINFOHEADER );
+ cbMemSize += wDIRowBytes * iHeight;
+ if (( pbImageData = ( png_byte* )GlobalAlloc( LPTR, cbMemSize )) == NULL ) {
+ png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
+ return FALSE;
+ } }
+
+ // initialize the dib-structure
+ { BITMAPINFOHEADER* pbmih = ( BITMAPINFOHEADER* )pbImageData;
+ *ppDibData = pbmih;
+
+ pbmih->biSize = sizeof( BITMAPINFOHEADER );
+ pbmih->biWidth = iWidth;
+ pbmih->biHeight = iHeight;
+ pbmih->biPlanes = 1;
+ pbmih->biBitCount = ulChannels * 8;
+ pbmih->biCompression = 0;
+ pbmih->biSizeImage = iWidth * iHeight * ulChannels;
+
+ pbImageData += sizeof( BITMAPINFOHEADER );
+ }
+
+ pImageData = (BYTE*)malloc( ulRowBytes * iHeight );
+ if ( pImageData == NULL ) {
+ png_destroy_read_struct(&png_ptr, NULL, NULL);
+ return FALSE;
+ }
+
+ // and allocate memory for an array of row-pointers
+ ppbRowPointers = ( png_bytepp )alloca( iHeight * sizeof( png_bytep ));
+
+ // set the individual row-pointers to point at the correct offsets
+ for ( i = 0; i < iHeight; i++ )
+ ppbRowPointers[i] = ( png_bytep )&pImageData[ i*ulRowBytes ];
+
+ // now we can go ahead and just read the whole image
+ png_read_image( png_ptr, ppbRowPointers );
+ png_read_end(png_ptr, NULL);
+
+ // repack bytes to fill the bitmap
+ for ( i = iHeight-1; i >= 0; i-- )
+ {
+ int j;
+ png_byte a;
+ png_bytep s = ppbRowPointers[i];
+ BYTE* dest = pbImageData; pbImageData += wDIRowBytes;
+
+ for ( j = 0; j < iWidth; j++ ) {
+ png_byte r = *s++;
+ png_byte g = *s++;
+ png_byte b = *s++;
+ if ( ulChannels == 4 )
+ a = *s++;
+
+ *dest++ = b;
+ *dest++ = g;
+ *dest++ = r;
+ if ( ulChannels == 4 )
+ *dest++ = a;
+ } }
+
+ free( pImageData );
+ png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
+ return TRUE;
+}
+
+/*
+ * Converting a bitmap into a png image
+ */
+
+BOOL __declspec(dllexport) dib2mempng( BITMAPINFO* pbmi, png_byte* pDiData, BYTE* pResult, long* pResultLen )
+{
+ int ciBitDepth = 8;
+ int ciChannels = pbmi->bmiHeader.biBitCount / 8;
+
+ png_uint_32 ulSrcRowBytes, ulDstRowBytes;
+ int i;
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+ png_bytepp ppbRowPointers;
+ png_bytep pTempBuffer;
+
+ HMemBufInfo sBuffer = { pResult, 0, 0 };
+
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, (png_error_ptr)NULL, (png_error_ptr)NULL);
+ if (!png_ptr)
+ return FALSE;
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr) {
+ png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
+ return FALSE;
+ }
+
+ // initialize the png structure
+ png_set_write_fn(png_ptr, (png_voidp)&sBuffer, png_write_data, png_flush);
+
+ png_set_IHDR(png_ptr, info_ptr, pbmi->bmiHeader.biWidth, pbmi->bmiHeader.biHeight, ciBitDepth,
+ PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+ // write the file header information
+ png_write_info(png_ptr, info_ptr);
+
+ // swap the BGR pixels in the DiData structure to RGB
+ png_set_bgr(png_ptr);
+
+ // row_bytes is the width x number of channels
+ ulSrcRowBytes = ((( pbmi->bmiHeader.biWidth * ciChannels + 3 ) >> 2 ) << 2 );
+ ulDstRowBytes = ((( pbmi->bmiHeader.biWidth * 3 + 3 ) >> 2 ) << 2 );
+
+ ppbRowPointers = (png_bytepp)alloca( pbmi->bmiHeader.biHeight * sizeof(png_bytep));
+
+ pTempBuffer = ( png_bytep )malloc( pbmi->bmiHeader.biHeight * ulDstRowBytes );
+ if ( pTempBuffer != NULL ) {
+ png_bytep pDest = pTempBuffer;
+ for ( i = pbmi->bmiHeader.biHeight-1; i >= 0; i--) {
+ BYTE *s, *d;
+ int j;
+ s = pDiData; pDiData += ulSrcRowBytes;
+ d = ppbRowPointers[i] = pDest; pDest += ulDstRowBytes;
+
+ if ( ciChannels >= 3 ) {
+ for ( j = 0; j < pbmi->bmiHeader.biWidth; j++ ) {
+ png_byte b = *s++;
+ png_byte g = *s++;
+ png_byte r = *s++;
+ png_byte a = 0;
+
+ if ( ciChannels == 4 )
+ a = *s++;
+
+ *d++ = b;
+ *d++ = g;
+ *d++ = r;
+ } }
+ else {
+ for ( j = 0; j < pbmi->bmiHeader.biWidth; j++ ) {
+ DWORD point;
+ if ( ciChannels == 1 ) {
+ *d++ = ( BYTE )( point & 0x03 ) << 6;
+ *d++ = ( BYTE )(( point & 0x0C ) >> 2 ) << 6;
+ *d++ = ( BYTE )(( point & 0x30 ) >> 4 ) << 6;
+ point = *s++;
+ }
+ else {
+ point = *( WORD* )s;
+ s += sizeof( WORD );
+ *d++ = ( BYTE )(( point & 0x001F ) << 3 );
+ *d++ = ( BYTE )((( point & 0x07e0 ) >> 6 ) << 3 );
+ *d++ = ( BYTE )((( point & 0xF800 ) >> 11 ) << 3 );
+ } } } }
+
+ png_write_image (png_ptr, ppbRowPointers);
+ png_write_end(png_ptr, info_ptr);
+
+ if ( pResultLen != NULL )
+ *pResultLen = sBuffer.mBufPtr;
+
+ free( pTempBuffer );
+ }
+
+ png_destroy_write_struct(&png_ptr, &info_ptr );
+ return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Standard Miranda structures & functions
+
+HINSTANCE hInst = NULL;
+PLUGINLINK *pluginLink;
+
+static HANDLE hDib2mempng = NULL;
+static HANDLE hMempng2Dib = NULL;
+
+PLUGININFO pluginInfo = {
+ sizeof( PLUGININFO ),
+ "PNG images processor",
+ __VERSION_DWORD,
+ "png2dib plugin for Miranda IM ( "__DATE__" )",
+ "George Hazan",
+ "ghazan@miranda-im.org",
+ "(c) 2004-06 George Hazan",
+ "http://addons.miranda-im.org/details.php?action=viewfile&id=1420",
+ 0,
+ 0
+};
+
+__declspec( dllexport ) PLUGININFO* MirandaPluginInfo( DWORD mirandaVersion )
+{
+ if ( mirandaVersion < PLUGIN_MAKE_VERSION( 0,4,3,0 )) {
+ MessageBox( NULL, "The png2dib plugin cannot be loaded. It requires Miranda IM 0.5 or later.", "png2dib Plugin", MB_OK|MB_ICONWARNING|MB_SETFOREGROUND|MB_TOPMOST );
+ return NULL;
+ }
+
+ return &pluginInfo;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Load - initializes the plugin instance
+
+static int serviceDib2Png( WPARAM wParam, LPARAM lParam )
+{
+ DIB2PNG* param = ( DIB2PNG* )lParam;
+ return dib2mempng( param->pbmi, param->pDiData, param->pResult, param->pResultLen );
+}
+
+static int servicePng2Dib( WPARAM wParam, LPARAM lParam )
+{
+ PNG2DIB* param = ( PNG2DIB* )lParam;
+ return mempng2dib( param->pSource, param->cbSourceSize, param->pResult );
+}
+
+int __declspec( dllexport ) Load( PLUGINLINK *link )
+{
+ pluginLink = link;
+
+ hDib2mempng = CreateServiceFunction( MS_DIB2PNG, serviceDib2Png );
+ hMempng2Dib = CreateServiceFunction( MS_PNG2DIB, servicePng2Dib );
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Unload - destroys the plugin instance
+
+int __declspec( dllexport ) Unload( void )
+{
+ DestroyServiceFunction( hDib2mempng );
+ DestroyServiceFunction( hMempng2Dib );
+ return 0;
+}
diff --git a/miranda-wine/plugins/png2dib/version.h b/miranda-wine/plugins/png2dib/version.h
new file mode 100644
index 0000000..d21c408
--- /dev/null
+++ b/miranda-wine/plugins/png2dib/version.h
@@ -0,0 +1,3 @@
+#define __FILEVERSION_STRING 0,1,3,1
+#define __VERSION_STRING "0.1.3.1"
+#define __VERSION_DWORD 0x00010301
diff --git a/miranda-wine/plugins/png2dib/version.rc b/miranda-wine/plugins/png2dib/version.rc
new file mode 100644
index 0000000..e9f49ed
--- /dev/null
+++ b/miranda-wine/plugins/png2dib/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 png2dib plugin"
+ VALUE "FileVersion", __VERSION_STRING
+ VALUE "InternalName", "png2dib"
+ VALUE "LegalCopyright", "Copyright c 2004-2006 George Hazan"
+ VALUE "OriginalFilename", "png2dib.dll"
+ VALUE "ProductName", "Miranda"
+ VALUE "ProductVersion", __VERSION_STRING
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0, 1200
+ END
+END
diff --git a/miranda-wine/plugins/srmm/cmdlist.c b/miranda-wine/plugins/srmm/cmdlist.c
new file mode 100644
index 0000000..4897751
--- /dev/null
+++ b/miranda-wine/plugins/srmm/cmdlist.c
@@ -0,0 +1,124 @@
+/*
+SRMM
+
+Copyright 2000-2005 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 <stdlib.h>
+#include <string.h>
+#include "commonheaders.h"
+
+static unsigned long tcmdlist_hash(const CMDCHAR *data) {
+ unsigned long hash = 0;
+ int i, shift = 0;
+
+ for(i=0; data[i]; i++) {
+ hash ^= data[i]<<shift;
+ if(shift>24) hash ^= (data[i]>>(32-shift))&0x7F;
+ shift = (shift+5)&0x1F;
+ }
+ return hash;
+}
+
+TCmdList *tcmdlist_append(TCmdList *list, CMDCHAR *data) {
+ TCmdList *n;
+ TCmdList *new_list = malloc(sizeof(TCmdList));
+ TCmdList *attach_to = NULL;
+
+ if (!data) {
+ free(new_list);
+ return list;
+ }
+ new_list->next = NULL;
+#ifdef _UNICODE
+ new_list->szCmd = _tcsdup(data);
+#else
+ new_list->szCmd = _strdup(data);
+#endif
+ new_list->hash = tcmdlist_hash(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;
+ if (tcmdlist_len(list)>20) {
+ list = tcmdlist_remove(list, list->szCmd);
+ }
+ return list;
+ }
+}
+
+TCmdList *tcmdlist_remove(TCmdList *list, CMDCHAR *data) {
+ TCmdList *n;
+ unsigned long hash;
+
+ if (!data) return list;
+ hash = tcmdlist_hash(data);
+ for (n=list; n!=NULL; n=n->next) {
+#ifdef _UNICODE
+ if (n->hash==hash&&!_tcscmp(n->szCmd, data)) {
+#else
+ if (n->hash==hash&&!strcmp(n->szCmd, data)) {
+#endif
+ if (n->next) n->next->prev = n->prev;
+ if (n->prev) n->prev->next = n->next;
+ if (n==list) list = n->next;
+ free(n->szCmd);
+ free(n);
+ return list;
+ }
+ }
+ return list;
+}
+
+int tcmdlist_len(TCmdList *list) {
+ TCmdList *n;
+ int i = 0;
+
+ for (n=list; n!=NULL; n=n->next) {
+ i++;
+ }
+ return i;
+}
+
+TCmdList *tcmdlist_last(TCmdList *list) {
+ TCmdList *n;
+
+ for (n=list; n!=NULL; n=n->next) {
+ if (!n->next)
+ return n;
+ }
+ return NULL;
+}
+
+void tcmdlist_free(TCmdList *list) {
+ TCmdList *n = list, *next;
+
+ while (n!=NULL) {
+ next = n->next;
+ free(n->szCmd);
+ free(n);
+ n = next;
+ }
+}
diff --git a/miranda-wine/plugins/srmm/cmdlist.h b/miranda-wine/plugins/srmm/cmdlist.h
new file mode 100644
index 0000000..54b057a
--- /dev/null
+++ b/miranda-wine/plugins/srmm/cmdlist.h
@@ -0,0 +1,48 @@
+/*
+SRMM
+
+Copyright 2000-2005 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 SRMM_CMDLIST_H
+#define SRMM_CMDLIST_H
+
+#ifdef _UNICODE
+ #define CMDCHAR TCHAR
+#else
+ #define CMDCHAR char
+#endif
+
+typedef struct _TCmdList {
+ struct _TCmdList *next;
+ struct _TCmdList *prev;
+#ifdef _UNICODE
+ wchar_t *szCmd;
+#else
+ char *szCmd;
+#endif
+ unsigned long hash;
+} TCmdList;
+
+TCmdList *tcmdlist_append(TCmdList *list, CMDCHAR *data);
+TCmdList *tcmdlist_remove(TCmdList *list, CMDCHAR *data);
+int tcmdlist_len(TCmdList *list);
+TCmdList *tcmdlist_last(TCmdList *list);
+void tcmdlist_free(TCmdList * list);
+
+#endif
diff --git a/miranda-wine/plugins/srmm/commonheaders.h b/miranda-wine/plugins/srmm/commonheaders.h
new file mode 100644
index 0000000..4236248
--- /dev/null
+++ b/miranda-wine/plugins/srmm/commonheaders.h
@@ -0,0 +1,57 @@
+/*
+SRMM
+
+Copyright 2000-2005 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 defined(UNICODE) && !defined(_UNICODE)
+ #define _UNICODE
+#endif
+#include <tchar.h>
+#define _WIN32_WINNT 0x0501
+#include <windows.h>
+#include <commctrl.h>
+#include <stdio.h>
+#include <time.h>
+#include <stddef.h>
+#include <process.h>
+#include "resource.h"
+#include <win2k.h>
+#include <newpluginapi.h>
+#include <m_system.h>
+#include <m_database.h>
+#include <m_langpack.h>
+#include <m_button.h>
+#include <m_clist.h>
+#include <m_clc.h>
+#include <m_clui.h>
+#include <m_options.h>
+#include <m_protosvc.h>
+#include <m_utils.h>
+#include <m_skin.h>
+#include <m_contacts.h>
+#include <m_userinfo.h>
+#include <m_history.h>
+#include <m_addcontact.h>
+#include <m_message.h>
+#include <m_file.h>
+#include "cmdlist.h"
+#include "msgs.h"
+#include "globals.h"
+#include "richutil.h"
diff --git a/miranda-wine/plugins/srmm/globals.c b/miranda-wine/plugins/srmm/globals.c
new file mode 100644
index 0000000..3247e1a
--- /dev/null
+++ b/miranda-wine/plugins/srmm/globals.c
@@ -0,0 +1,107 @@
+/*
+SRMM
+
+Copyright 2000-2005 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+struct GlobalMessageData *g_dat=NULL;
+extern HINSTANCE g_hInst;
+static HANDLE g_hDbEvent = 0, g_hAck = 0;
+static int dbaddedevent(WPARAM wParam, LPARAM lParam);
+static int ackevent(WPARAM wParam, LPARAM lParam);
+
+void InitGlobals() {
+ g_dat = (struct GlobalMessageData *)malloc(sizeof(struct GlobalMessageData));
+ g_dat->hMessageWindowList = (HANDLE) CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0);
+ g_hDbEvent = HookEvent(ME_DB_EVENT_ADDED, dbaddedevent);
+ g_hAck = HookEvent(ME_PROTO_ACK, ackevent);
+ ReloadGlobals();
+ g_dat->hIcons[SMF_ICON_ADD] = (HICON) LoadImage(g_hInst, MAKEINTRESOURCE(IDI_ADDCONTACT), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
+ g_dat->hIcons[SMF_ICON_USERDETAIL] = (HICON) LoadImage(g_hInst, MAKEINTRESOURCE(IDI_USERDETAILS), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
+ g_dat->hIcons[SMF_ICON_HISTORY] = (HICON) LoadImage(g_hInst, MAKEINTRESOURCE(IDI_HISTORY), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
+ g_dat->hIcons[SMF_ICON_ARROW] = (HICON) LoadImage(g_hInst, MAKEINTRESOURCE(IDI_DOWNARROW), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
+ g_dat->hIcons[SMF_ICON_TYPING] = (HICON) LoadImage(g_hInst, MAKEINTRESOURCE(IDI_TYPING), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
+}
+
+void FreeGlobals() {
+ int i;
+
+ if (g_dat) {
+ for (i=0; i < SIZEOF(g_dat->hIcons); i++)
+ DestroyIcon(g_dat->hIcons[i]);
+ free(g_dat);
+ }
+ if (g_hDbEvent) UnhookEvent(g_hDbEvent);
+ if (g_hAck) UnhookEvent(g_hAck);
+}
+
+void ReloadGlobals() {
+ g_dat->flags = 0;
+ if (DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWINFOLINE, SRMSGDEFSET_SHOWINFOLINE))
+ g_dat->flags |= SMF_SHOWINFO;
+ if (DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWBUTTONLINE, SRMSGDEFSET_SHOWBUTTONLINE))
+ g_dat->flags |= SMF_SHOWBTNS;
+ if (DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SENDBUTTON, SRMSGDEFSET_SENDBUTTON))
+ g_dat->flags |= SMF_SENDBTN;
+ if (DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWTYPING, SRMSGDEFSET_SHOWTYPING))
+ g_dat->flags |= SMF_SHOWTYPING;
+ if (DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWTYPINGWIN, SRMSGDEFSET_SHOWTYPINGWIN))
+ g_dat->flags |= SMF_SHOWTYPINGWIN;
+ if (DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWTYPINGNOWIN, SRMSGDEFSET_SHOWTYPINGNOWIN))
+ g_dat->flags |= SMF_SHOWTYPINGTRAY;
+ if (DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWTYPINGCLIST, SRMSGDEFSET_SHOWTYPINGCLIST))
+ g_dat->flags |= SMF_SHOWTYPINGCLIST;
+ if (DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWLOGICONS, SRMSGDEFSET_SHOWLOGICONS))
+ g_dat->flags |= SMF_SHOWICONS;
+ if (DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWTIME, SRMSGDEFSET_SHOWTIME))
+ g_dat->flags |= SMF_SHOWTIME;
+ if (DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_AVATARENABLE, SRMSGDEFSET_AVATARENABLE))
+ g_dat->flags |= SMF_AVATAR;
+ if (DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWDATE, SRMSGDEFSET_SHOWDATE))
+ g_dat->flags |= SMF_SHOWDATE;
+ if (DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWSECS, SRMSGDEFSET_SHOWSECS))
+ g_dat->flags |= SMF_SHOWSECS;
+ if (DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_HIDENAMES, SRMSGDEFSET_HIDENAMES))
+ g_dat->flags |= SMF_HIDENAMES;
+ g_dat->openFlags = DBGetContactSettingDword(NULL, SRMMMOD, SRMSGSET_POPFLAGS, SRMSGDEFSET_POPFLAGS);
+}
+
+static int dbaddedevent(WPARAM wParam, LPARAM lParam) {
+ if (wParam) {
+ HWND h = WindowList_Find(g_dat->hMessageWindowList, (HANDLE)wParam);
+ if(h) SendMessage(h, HM_DBEVENTADDED, wParam, lParam);
+ }
+ return 0;
+}
+
+static int ackevent(WPARAM wParam, LPARAM lParam) {
+ ACKDATA *pAck = (ACKDATA *)lParam;
+
+ if (!pAck) return 0;
+ else if (pAck->type==ACKTYPE_AVATAR) {
+ HWND h = WindowList_Find(g_dat->hMessageWindowList, (HANDLE)pAck->hContact);
+ if(h) SendMessage(h, HM_AVATARACK, wParam, lParam);
+ }
+ else if (pAck->type==ACKTYPE_MESSAGE) {
+ HWND h = WindowList_Find(g_dat->hMessageWindowList, (HANDLE)pAck->hContact);
+ if(h) SendMessage(h, HM_EVENTSENT, wParam, lParam);
+ }
+ return 0;
+}
diff --git a/miranda-wine/plugins/srmm/globals.h b/miranda-wine/plugins/srmm/globals.h
new file mode 100644
index 0000000..12723fa
--- /dev/null
+++ b/miranda-wine/plugins/srmm/globals.h
@@ -0,0 +1,59 @@
+/*
+SRMM
+
+Copyright 2000-2005 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 SRMM_GLOBALS_H
+#define SRMM_GLOBALS_H
+
+#define SMF_SHOWINFO 0x00000001
+#define SMF_SHOWBTNS 0x00000002
+#define SMF_SENDBTN 0x00000004
+#define SMF_SHOWTYPING 0x00000008
+#define SMF_SHOWTYPINGWIN 0x00000010
+#define SMF_SHOWTYPINGTRAY 0x00000020
+#define SMF_SHOWTYPINGCLIST 0x00000040
+#define SMF_SHOWICONS 0x00000080
+#define SMF_SHOWTIME 0x00000100
+#define SMF_AVATAR 0x00000200
+#define SMF_SHOWDATE 0x00000400
+#define SMF_HIDENAMES 0x00000800
+#define SMF_SHOWSECS 0x00001000
+
+#define SMF_ICON_ADD 0
+#define SMF_ICON_USERDETAIL 1
+#define SMF_ICON_HISTORY 2
+#define SMF_ICON_ARROW 3
+#define SMF_ICON_TYPING 4
+
+struct GlobalMessageData
+{
+ unsigned int flags;
+ HICON hIcons[5];
+ HANDLE hMessageWindowList;
+ DWORD openFlags;
+};
+
+void InitGlobals();
+void FreeGlobals();
+void ReloadGlobals();
+
+extern struct GlobalMessageData *g_dat;
+
+#endif
diff --git a/miranda-wine/plugins/srmm/msgdialog.c b/miranda-wine/plugins/srmm/msgdialog.c
new file mode 100644
index 0000000..0d8085e
--- /dev/null
+++ b/miranda-wine/plugins/srmm/msgdialog.c
@@ -0,0 +1,1859 @@
+/*
+SRMM
+
+Copyright 2000-2005 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 _USE_32BIT_TIME_T
+
+#include "commonheaders.h"
+#pragma hdrstop
+
+#include <malloc.h>
+
+#define TIMERID_MSGSEND 0
+#define TIMERID_FLASHWND 1
+#define TIMERID_TYPE 2
+#define TIMEOUT_FLASHWND 900
+#define TIMEOUT_TYPEOFF 10000 //send type off after 10 seconds of inactivity
+#define SB_CHAR_WIDTH 45;
+#define VALID_AVATAR(x) (x==PA_FORMAT_PNG||x==PA_FORMAT_JPEG||x==PA_FORMAT_ICON||x==PA_FORMAT_BMP||x==PA_FORMAT_GIF)
+
+#if defined(_UNICODE)
+ #define SEND_FLAGS PREF_UNICODE
+#else
+ #define SEND_FLAGS 0
+#endif
+
+extern HCURSOR hCurSplitNS, hCurSplitWE, hCurHyperlinkHand;
+extern HANDLE hHookWinEvt;
+extern struct CREOleCallback reOleCallback;
+extern HINSTANCE g_hInst;
+
+static void UpdateReadChars(HWND hwndDlg, HWND hwndStatus);
+
+static WNDPROC OldMessageEditProc, OldSplitterProc;
+static const UINT infoLineControls[] = { IDC_PROTOCOL, IDC_NAME };
+static const UINT buttonLineControls[] = { IDC_ADD, IDC_USERMENU, IDC_DETAILS, IDC_HISTORY };
+static const UINT sendControls[] = { IDC_MESSAGE };
+
+static void NotifyLocalWinEvent(HANDLE hContact, HWND hwnd, unsigned int type) {
+ MessageWindowEventData mwe = { 0 };
+
+ if (hContact==NULL || hwnd==NULL) return;
+ mwe.cbSize = sizeof(mwe);
+ mwe.hContact = hContact;
+ mwe.hwndWindow = hwnd;
+ mwe.szModule = SRMMMOD;
+ mwe.uType = type;
+ mwe.uFlags = MSG_WINDOW_UFLAG_MSG_BOTH;
+ NotifyEventHooks(hHookWinEvt, 0, (LPARAM)&mwe);
+}
+
+static char *MsgServiceName(HANDLE hContact)
+{
+#ifdef _UNICODE
+ char szServiceName[100];
+ char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ if (szProto == NULL)
+ return PSS_MESSAGE;
+
+ mir_snprintf(szServiceName, SIZEOF(szServiceName), "%s%sW", szProto, PSS_MESSAGE);
+ if (ServiceExists(szServiceName))
+ return PSS_MESSAGE "W";
+#endif
+ return PSS_MESSAGE;
+}
+
+#if defined(_UNICODE)
+static int RTL_Detect(WCHAR *pszwText)
+{
+ WORD *infoTypeC2;
+ int i;
+ int iLen = lstrlenW(pszwText);
+
+ infoTypeC2 = (WORD *)malloc(sizeof(WORD) * (iLen + 2));
+
+ if(infoTypeC2) {
+ ZeroMemory(infoTypeC2, sizeof(WORD) * (iLen + 2));
+
+ GetStringTypeW(CT_CTYPE2, pszwText, iLen, infoTypeC2);
+
+ for(i = 0; i < iLen; i++) {
+ if(infoTypeC2[i] == C2_RIGHTTOLEFT) {
+ free(infoTypeC2);
+ //_DebugTraceA("RTL text found");
+ return 1;
+ }
+ }
+ free(infoTypeC2);
+ //_DebugTraceA("NO RTL text detected");
+ }
+ return 0;
+}
+#endif
+
+// mod from tabsrmm
+static void AddToFileList(char ***pppFiles,int *totalCount,const char *szFilename) {
+ *pppFiles=(char**)realloc(*pppFiles,(++*totalCount+1)*sizeof(char*));
+ (*pppFiles)[*totalCount]=NULL;
+ (*pppFiles)[*totalCount-1]=_strdup(szFilename);
+ if(GetFileAttributesA(szFilename)&FILE_ATTRIBUTE_DIRECTORY) {
+ WIN32_FIND_DATAA fd;
+ HANDLE hFind;
+ char szPath[MAX_PATH];
+ lstrcpyA(szPath,szFilename);
+ lstrcatA(szPath,"\\*");
+ if(hFind=FindFirstFileA(szPath,&fd)) {
+ do {
+ if(!lstrcmpA(fd.cFileName,".") || !lstrcmpA(fd.cFileName,"..")) continue;
+ lstrcpyA(szPath,szFilename);
+ lstrcatA(szPath,"\\");
+ lstrcatA(szPath,fd.cFileName);
+ AddToFileList(pppFiles,totalCount,szPath);
+ } while(FindNextFileA(hFind,&fd));
+ FindClose(hFind);
+ }
+ }
+}
+
+static void ShowMultipleControls(HWND hwndDlg, const UINT * controls, int cControls, int state)
+{
+ int i;
+ for (i = 0; i < cControls; i++)
+ ShowWindow(GetDlgItem(hwndDlg, controls[i]), state);
+}
+
+static void SetDialogToType(HWND hwndDlg)
+{
+ struct MessageWindowData *dat;
+ WINDOWPLACEMENT pl = { 0 };
+
+ dat = (struct MessageWindowData *) GetWindowLong(hwndDlg, GWL_USERDATA);
+ if (dat->hContact) {
+ ShowMultipleControls(hwndDlg, infoLineControls, SIZEOF(infoLineControls), (g_dat->flags&SMF_SHOWINFO) ? SW_SHOW : SW_HIDE);
+ }
+ else
+ ShowMultipleControls(hwndDlg, infoLineControls, SIZEOF(infoLineControls), SW_HIDE);
+ if (dat->hContact) {
+ ShowMultipleControls(hwndDlg, buttonLineControls, SIZEOF(buttonLineControls), (g_dat->flags&SMF_SHOWBTNS) ? SW_SHOW : SW_HIDE);
+ if (!DBGetContactSettingByte(dat->hContact, "CList", "NotOnList", 0))
+ ShowWindow(GetDlgItem(hwndDlg, IDC_ADD), SW_HIDE);
+ }
+ else {
+ ShowMultipleControls(hwndDlg, buttonLineControls, SIZEOF(buttonLineControls), SW_HIDE);
+ }
+ ShowMultipleControls(hwndDlg, sendControls, SIZEOF(sendControls), SW_SHOW);
+ if (!dat->hwndStatus) {
+ dat->hwndStatus = CreateWindowEx(0, STATUSCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP, 0, 0, 0, 0, hwndDlg, NULL, g_hInst, NULL);
+ SendMessage(dat->hwndStatus, SB_SETMINHEIGHT, GetSystemMetrics(SM_CYSMICON), 0);
+ }
+ if (DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_CHARCOUNT, SRMSGDEFSET_CHARCOUNT)) {
+ RECT rc;
+ int statwidths[2];
+
+ GetWindowRect(dat->hwndStatus, &rc);
+ statwidths[0] = rc.right - rc.left - SB_CHAR_WIDTH;
+ statwidths[1] = -1;
+ SendMessage(dat->hwndStatus, SB_SETPARTS, 2, (LPARAM) statwidths);
+ }
+ else {
+ int statwidths[] = { -1 };
+
+ SendMessage(dat->hwndStatus, SB_SETPARTS, 1, (LPARAM) statwidths);
+ }
+ UpdateReadChars(hwndDlg, dat->hwndStatus);
+ ShowWindow(GetDlgItem(hwndDlg, IDCANCEL), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SPLITTER), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDOK), (g_dat->flags&SMF_SENDBTN) ? SW_SHOW : SW_HIDE);
+ EnableWindow(GetDlgItem(hwndDlg, IDOK), GetWindowTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE))?TRUE:FALSE);
+ if (dat->avatarPic==0||!(g_dat->flags&SMF_AVATAR))
+ ShowWindow(GetDlgItem(hwndDlg, IDC_AVATAR), SW_HIDE);
+ SendMessage(hwndDlg, DM_UPDATETITLE, 0, 0);
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ pl.length = sizeof(pl);
+ GetWindowPlacement(hwndDlg, &pl);
+ if (!IsWindowVisible(hwndDlg))
+ pl.showCmd = SW_HIDE;
+ SetWindowPlacement(hwndDlg, &pl); //in case size is smaller than new minimum
+}
+
+struct SavedMessageData
+{
+ UINT message;
+ WPARAM wParam;
+ LPARAM lParam;
+ DWORD keyStates; //use MOD_ defines from RegisterHotKey()
+};
+
+struct MsgEditSubclassData
+{
+ DWORD lastEnterTime;
+ struct SavedMessageData *keyboardMsgQueue;
+ int msgQueueCount;
+};
+
+static void SaveKeyboardMessage(struct MsgEditSubclassData *dat, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ dat->keyboardMsgQueue = (struct SavedMessageData *) realloc(dat->keyboardMsgQueue, sizeof(struct SavedMessageData) * (dat->msgQueueCount + 1));
+ dat->keyboardMsgQueue[dat->msgQueueCount].message = message;
+ dat->keyboardMsgQueue[dat->msgQueueCount].wParam = wParam;
+ dat->keyboardMsgQueue[dat->msgQueueCount].lParam = lParam;
+ dat->keyboardMsgQueue[dat->msgQueueCount].keyStates = (GetKeyState(VK_SHIFT) & 0x8000 ? MOD_SHIFT : 0) | (GetKeyState(VK_CONTROL) & 0x8000 ? MOD_CONTROL : 0) | (GetKeyState(VK_MENU) & 0x8000 ? MOD_ALT : 0);
+ dat->msgQueueCount++;
+}
+
+#define EM_REPLAYSAVEDKEYSTROKES (WM_USER+0x100)
+#define EM_SUBCLASSED (WM_USER+0x101)
+#define EM_UNSUBCLASSED (WM_USER+0x102)
+#define ENTERCLICKTIME 1000 //max time in ms during which a double-tap on enter will cause a send
+#define EDITMSGQUEUE_PASSTHRUCLIPBOARD //if set the typing queue won't capture ctrl-C etc because people might want to use them on the read only text
+ //todo: decide if this should be set or not
+static LRESULT CALLBACK MessageEditSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct MsgEditSubclassData *dat;
+ struct MessageWindowData *pdat;
+
+ pdat=(struct MessageWindowData *)GetWindowLong(GetParent(hwnd),GWL_USERDATA);
+ dat = (struct MsgEditSubclassData *) GetWindowLong(hwnd, GWL_USERDATA);
+ switch (msg) {
+ case WM_DROPFILES:
+ SendMessage(GetParent(hwnd), WM_DROPFILES, (WPARAM)wParam, (LPARAM)lParam);
+ break;
+ case EM_SUBCLASSED:
+ dat = (struct MsgEditSubclassData *) malloc(sizeof(struct MsgEditSubclassData));
+ SetWindowLong(hwnd, GWL_USERDATA, (LONG) dat);
+ dat->lastEnterTime = 0;
+ dat->keyboardMsgQueue = NULL;
+ dat->msgQueueCount = 0;
+ return 0;
+ case EM_SETREADONLY:
+ if (wParam) {
+ if (dat->keyboardMsgQueue)
+ free(dat->keyboardMsgQueue);
+ dat->keyboardMsgQueue = NULL;
+ dat->msgQueueCount = 0;
+ }
+ break;
+ case EM_REPLAYSAVEDKEYSTROKES:
+ {
+ int i;
+ BYTE keyStateArray[256], originalKeyStateArray[256];
+ MSG msg;
+
+ while (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ GetKeyboardState(originalKeyStateArray);
+ GetKeyboardState(keyStateArray);
+ for (i = 0; i < dat->msgQueueCount; i++) {
+ keyStateArray[VK_SHIFT] = dat->keyboardMsgQueue[i].keyStates & MOD_SHIFT ? 0x80 : 0;
+ keyStateArray[VK_CONTROL] = dat->keyboardMsgQueue[i].keyStates & MOD_CONTROL ? 0x80 : 0;
+ keyStateArray[VK_MENU] = dat->keyboardMsgQueue[i].keyStates & MOD_ALT ? 0x80 : 0;
+ SetKeyboardState(keyStateArray);
+ PostMessage(hwnd, dat->keyboardMsgQueue[i].message, dat->keyboardMsgQueue[i].wParam, dat->keyboardMsgQueue[i].lParam);
+ while (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ if (dat->keyboardMsgQueue)
+ free(dat->keyboardMsgQueue);
+ dat->keyboardMsgQueue = NULL;
+ dat->msgQueueCount = 0;
+ SetKeyboardState(originalKeyStateArray);
+ return 0;
+ }
+ case WM_CHAR:
+ if (GetWindowLong(hwnd, GWL_STYLE) & ES_READONLY)
+ break;
+ //for saved msg queue the keyup/keydowns generate wm_chars themselves
+ if (wParam == '\n' || wParam == '\r') {
+ if (((GetKeyState(VK_CONTROL) & 0x8000) != 0) ^ (0 != DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SENDONENTER, SRMSGDEFSET_SENDONENTER))) {
+ PostMessage(GetParent(hwnd), WM_COMMAND, IDOK, 0);
+ return 0;
+ }
+ if (DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SENDONDBLENTER, SRMSGDEFSET_SENDONDBLENTER)) {
+ if (dat->lastEnterTime + ENTERCLICKTIME < GetTickCount())
+ dat->lastEnterTime = GetTickCount();
+ else {
+ SendMessage(hwnd, WM_CHAR, '\b', 0);
+ PostMessage(GetParent(hwnd), WM_COMMAND, IDOK, 0);
+ return 0;
+ }
+ }
+ }
+ else
+ dat->lastEnterTime = 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;
+ TCHAR *text;
+ int textLen;
+ 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);
+ textLen = GetWindowTextLength(hwnd);
+ text = (TCHAR *) malloc(sizeof(TCHAR) * (textLen + 1));
+ GetWindowText(hwnd, text, textLen + 1);
+ MoveMemory(text + start, text + end, sizeof(TCHAR) * (textLen + 1 - end));
+ SetWindowText(hwnd, text);
+ free(text);
+ SendMessage(hwnd, EM_SETSEL, start, start);
+ SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), EN_CHANGE), (LPARAM) hwnd);
+ return 0;
+ }
+ break;
+ case WM_KEYUP:
+ if (GetWindowLong(hwnd, GWL_STYLE) & ES_READONLY) {
+ int i;
+ //mustn't allow keyups for which there is no keydown
+ for (i = 0; i < dat->msgQueueCount; i++)
+ if (dat->keyboardMsgQueue[i].message == WM_KEYDOWN && dat->keyboardMsgQueue[i].wParam == wParam)
+ break;
+ if (i == dat->msgQueueCount)
+ break;
+ #ifdef EDITMSGQUEUE_PASSTHRUCLIPBOARD
+ if (GetKeyState(VK_CONTROL) & 0x8000) {
+ if (wParam == 'X' || wParam == 'C' || wParam == 'V' || wParam == VK_INSERT)
+ break;
+ }
+ if (GetKeyState(VK_SHIFT) & 0x8000) {
+ if (wParam == VK_INSERT || wParam == VK_DELETE)
+ break;
+ }
+ #endif
+ SaveKeyboardMessage(dat, msg, wParam, lParam);
+ return 0;
+ }
+ break;
+ case WM_KEYDOWN:
+ if (GetWindowLong(hwnd, GWL_STYLE) & ES_READONLY) {
+ #ifdef EDITMSGQUEUE_PASSTHRUCLIPBOARD
+ if (GetKeyState(VK_CONTROL) & 0x8000) {
+ if (wParam == 'X' || wParam == 'C' || wParam == 'V' || wParam == VK_INSERT)
+ break;
+ }
+ if (GetKeyState(VK_SHIFT) & 0x8000) {
+ if (wParam == VK_INSERT || wParam == VK_DELETE)
+ break;
+ }
+ #endif
+ SaveKeyboardMessage(dat, msg, wParam, lParam);
+ return 0;
+ }
+ if (wParam == VK_UP && (GetKeyState(VK_CONTROL) & 0x8000) && DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_CTRLSUPPORT, SRMSGDEFSET_CTRLSUPPORT) && !DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_AUTOCLOSE, SRMSGDEFSET_AUTOCLOSE)) {
+ if (pdat->cmdList) {
+ if (!pdat->cmdListCurrent) {
+ pdat->cmdListCurrent = tcmdlist_last(pdat->cmdList);
+ SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
+ SetWindowText(hwnd, pdat->cmdListCurrent->szCmd);
+ SendMessage(hwnd, EM_SCROLLCARET, 0,0);
+ SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
+ SendMessage(hwnd, EM_SETSEL, 0, -1);
+ }
+ else if (pdat->cmdListCurrent->prev) {
+ pdat->cmdListCurrent = pdat->cmdListCurrent->prev;
+ SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
+ SetWindowText(hwnd, pdat->cmdListCurrent->szCmd);
+ SendMessage(hwnd, EM_SCROLLCARET, 0,0);
+ SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
+ SendMessage(hwnd, EM_SETSEL, 0, -1);
+ }
+ }
+ EnableWindow(GetDlgItem(GetParent(hwnd), IDOK), GetWindowTextLength(GetDlgItem(GetParent(hwnd), IDC_MESSAGE)) != 0);
+ UpdateReadChars(GetParent(hwnd), pdat->hwndStatus);
+ }
+ else if (wParam == VK_DOWN && (GetKeyState(VK_CONTROL) & 0x8000) && DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_CTRLSUPPORT, SRMSGDEFSET_CTRLSUPPORT) && !DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_AUTOCLOSE, SRMSGDEFSET_AUTOCLOSE)) {
+ if (pdat->cmdList) {
+ if (!pdat->cmdListCurrent)
+ pdat->cmdListCurrent = tcmdlist_last(pdat->cmdList);
+ if (pdat->cmdListCurrent->next) {
+ pdat->cmdListCurrent = pdat->cmdListCurrent->next;
+ SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
+ SetWindowText(hwnd, pdat->cmdListCurrent->szCmd);
+ SendMessage(hwnd, EM_SCROLLCARET, 0,0);
+ SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
+ SendMessage(hwnd, EM_SETSEL, 0, -1);
+ }
+ else {
+ pdat->cmdListCurrent = 0;
+ SetWindowTextA(hwnd, "");
+ }
+ }
+ EnableWindow(GetDlgItem(GetParent(hwnd), IDOK), GetWindowTextLength(GetDlgItem(GetParent(hwnd), IDC_MESSAGE)) != 0);
+ UpdateReadChars(GetParent(hwnd), pdat->hwndStatus);
+ }
+ if (wParam == VK_RETURN)
+ break;
+ //fall through
+ case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_MOUSEWHEEL:
+ case WM_KILLFOCUS:
+ dat->lastEnterTime = 0;
+ break;
+ case WM_SYSCHAR:
+ dat->lastEnterTime = 0;
+ if ((wParam == 's' || wParam == 'S') && GetKeyState(VK_MENU) & 0x8000) {
+ if (GetWindowLong(hwnd, GWL_STYLE) & ES_READONLY)
+ SaveKeyboardMessage(dat, msg, wParam, lParam);
+ else
+ PostMessage(GetParent(hwnd), WM_COMMAND, IDOK, 0);
+ return 0;
+ }
+ break;
+ case EM_UNSUBCLASSED:
+ if (dat->keyboardMsgQueue)
+ free(dat->keyboardMsgQueue);
+ free(dat);
+ return 0;
+ }
+ return CallWindowProc(OldMessageEditProc, hwnd, msg, wParam, lParam);
+}
+
+static LRESULT CALLBACK SplitterSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_NCHITTEST:
+ return HTCLIENT;
+ case WM_SETCURSOR:
+ {
+ RECT rc;
+ GetClientRect(hwnd, &rc);
+ SetCursor(rc.right > rc.bottom ? hCurSplitNS : hCurSplitWE);
+ return TRUE;
+ }
+ case WM_LBUTTONDOWN:
+ SetCapture(hwnd);
+ return 0;
+ case WM_MOUSEMOVE:
+ if (GetCapture() == hwnd) {
+ RECT rc;
+ GetClientRect(hwnd, &rc);
+ SendMessage(GetParent(hwnd), DM_SPLITTERMOVED, rc.right > rc.bottom ? (short) HIWORD(GetMessagePos()) + rc.bottom / 2 : (short) LOWORD(GetMessagePos()) + rc.right / 2, (LPARAM) hwnd);
+ }
+ return 0;
+ case WM_LBUTTONUP:
+ ReleaseCapture();
+ return 0;
+ }
+ return CallWindowProc(OldSplitterProc, hwnd, msg, wParam, lParam);
+}
+
+static int MessageDialogResize(HWND hwndDlg, LPARAM lParam, UTILRESIZECONTROL * urc)
+{
+ struct MessageWindowData *dat = (struct MessageWindowData *) lParam;
+
+ if (!(g_dat->flags&SMF_SHOWINFO) && !(g_dat->flags&SMF_SHOWBTNS)) {
+ int i;
+ for (i = 0; i < SIZEOF(buttonLineControls); i++)
+ if (buttonLineControls[i] == urc->wId)
+ OffsetRect(&urc->rcItem, 0, -dat->lineHeight);
+ }
+ switch (urc->wId) {
+ case IDC_NAME:
+ {
+ int len;
+ HWND h;
+
+ h = GetDlgItem(hwndDlg, IDC_NAME);
+ len = GetWindowTextLength(h);
+ if (len > 0) {
+ HDC hdc;
+ SIZE textSize;
+ TCHAR buf[256];
+ HFONT hFont;
+
+ GetWindowText(h, buf, SIZEOF(buf));
+
+ hdc = GetDC(h);
+ hFont = SelectObject(hdc, (HFONT) SendMessage(GetDlgItem(hwndDlg, IDOK), WM_GETFONT, 0, 0));
+ GetTextExtentPoint32(hdc, buf, lstrlen(buf), &textSize);
+ urc->rcItem.right = urc->rcItem.left + textSize.cx + 10;
+ if ((g_dat->flags&SMF_SHOWBTNS) && urc->rcItem.right > urc->dlgNewSize.cx - dat->nLabelRight)
+ urc->rcItem.right = urc->dlgNewSize.cx - dat->nLabelRight;
+ SelectObject(hdc, hFont);
+ ReleaseDC(h, hdc);
+ }
+ }
+ case IDC_PROTOCOL:
+ return RD_ANCHORX_LEFT | RD_ANCHORY_TOP;
+ case IDC_ADD:
+ case IDC_USERMENU:
+ case IDC_DETAILS:
+ case IDC_HISTORY:
+ return RD_ANCHORX_RIGHT | RD_ANCHORY_TOP;
+ case IDC_LOG:
+ if (!(g_dat->flags&SMF_SHOWINFO) && !(g_dat->flags&SMF_SHOWBTNS))
+ urc->rcItem.top -= dat->lineHeight;
+ urc->rcItem.bottom -= dat->splitterPos - dat->originalSplitterPos;
+ return RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT;
+ case IDC_SPLITTER:
+ urc->rcItem.top -= dat->splitterPos - dat->originalSplitterPos;
+ urc->rcItem.bottom -= dat->splitterPos - dat->originalSplitterPos;
+ return RD_ANCHORX_WIDTH | RD_ANCHORY_BOTTOM;
+ case IDC_MESSAGE:
+ {
+ if (!(g_dat->flags&SMF_SENDBTN))
+ urc->rcItem.right = urc->dlgNewSize.cx - urc->rcItem.left;
+ if ((g_dat->flags&SMF_AVATAR)&&dat->avatarPic) {
+ urc->rcItem.left = dat->avatarWidth+4;
+ }
+ urc->rcItem.top -= dat->splitterPos - dat->originalSplitterPos;
+ if (!(g_dat->flags&SMF_SENDBTN))
+ return RD_ANCHORX_CUSTOM | RD_ANCHORY_BOTTOM;
+ return RD_ANCHORX_WIDTH | RD_ANCHORY_BOTTOM;
+ }
+ case IDCANCEL:
+ case IDOK:
+ urc->rcItem.top -= dat->splitterPos - dat->originalSplitterPos;
+ return RD_ANCHORX_RIGHT | RD_ANCHORY_BOTTOM;
+ case IDC_AVATAR:
+ urc->rcItem.top=urc->rcItem.bottom-(dat->avatarHeight + 2);
+ urc->rcItem.right=urc->rcItem.left+(dat->avatarWidth + 2);
+ return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM;
+ }
+ return RD_ANCHORX_LEFT | RD_ANCHORY_TOP;
+}
+
+static void UpdateReadChars(HWND hwndDlg, HWND hwndStatus)
+{
+ if (hwndStatus && SendMessage(hwndStatus, SB_GETPARTS, 0, 0) == 2) {
+ TCHAR buf[128];
+ int len = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE));
+
+ mir_sntprintf(buf, SIZEOF(buf), _T("%d"), len);
+ SendMessage(hwndStatus, SB_SETTEXT, 1, (LPARAM) buf);
+ }
+}
+
+void ShowAvatar(HWND hwndDlg, struct MessageWindowData *dat) {
+ DBVARIANT dbv;
+
+ if (dat->avatarPic) {
+ DeleteObject(dat->avatarPic);
+ dat->avatarPic=0;
+ }
+ if (!DBGetContactSetting(dat->hContact, SRMMMOD, SRMSGSET_AVATAR, &dbv)) {
+ if(dbv.pszVal) {
+ HANDLE hFile;
+
+ hFile = CreateFileA(dbv.pszVal, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFile!=INVALID_HANDLE_VALUE) {
+ dat->avatarPic=(HBITMAP)CallService(MS_UTILS_LOADBITMAP,0,(LPARAM)dbv.pszVal);
+ CloseHandle(hFile);
+ }
+ }
+ DBFreeVariant(&dbv);
+ }
+ SendMessage(hwndDlg, DM_UPDATESIZEBAR, 0, 0);
+ SendMessage(hwndDlg, DM_AVATARSIZECHANGE, 0, 0);
+}
+
+static void NotifyTyping(struct MessageWindowData *dat, int mode)
+{
+ DWORD protoStatus;
+ DWORD protoCaps;
+ DWORD typeCaps;
+
+ if (!dat->hContact)
+ return;
+ // Don't send to protocols who don't support typing
+ // Don't send to users who are unchecked in the typing notification options
+ // Don't send to protocols that are offline
+ // Don't send to users who are not visible and
+ // Don't send to users who are not on the visible list when you are in invisible mode.
+ if (!DBGetContactSettingByte(dat->hContact, SRMMMOD, SRMSGSET_TYPING, DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_TYPINGNEW, SRMSGDEFSET_TYPINGNEW)))
+ return;
+ if (!dat->szProto)
+ return;
+ protoStatus = CallProtoService(dat->szProto, PS_GETSTATUS, 0, 0);
+ protoCaps = CallProtoService(dat->szProto, PS_GETCAPS, PFLAGNUM_1, 0);
+ typeCaps = CallProtoService(dat->szProto, PS_GETCAPS, PFLAGNUM_4, 0);
+
+ if (!(typeCaps & PF4_SUPPORTTYPING))
+ return;
+ if (protoStatus < ID_STATUS_ONLINE)
+ return;
+ if (protoCaps & PF1_VISLIST && DBGetContactSettingWord(dat->hContact, dat->szProto, "ApparentMode", 0) == ID_STATUS_OFFLINE)
+ return;
+ if (protoCaps & PF1_INVISLIST && protoStatus == ID_STATUS_INVISIBLE && DBGetContactSettingWord(dat->hContact, dat->szProto, "ApparentMode", 0) != ID_STATUS_ONLINE)
+ return;
+ if (DBGetContactSettingByte(dat->hContact, "CList", "NotOnList", 0)
+ && !DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_TYPINGUNKNOWN, SRMSGDEFSET_TYPINGUNKNOWN))
+ return;
+ // End user check
+ dat->nTypeMode = mode;
+ CallService(MS_PROTO_SELFISTYPING, (WPARAM) dat->hContact, dat->nTypeMode);
+}
+
+BOOL CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct MessageWindowData *dat;
+
+ dat = (struct MessageWindowData *) GetWindowLong(hwndDlg, GWL_USERDATA);
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ struct NewMessageWindowLParam *newData = (struct NewMessageWindowLParam *) lParam;
+ TranslateDialogDefault(hwndDlg);
+ dat = (struct MessageWindowData *) calloc(sizeof(struct MessageWindowData),1);
+ SetWindowLong(hwndDlg, GWL_USERDATA, (LONG) dat);
+ {
+ dat->hContact = newData->hContact;
+ NotifyLocalWinEvent(dat->hContact, hwndDlg, MSG_WINDOW_EVT_OPENING);
+ if (newData->szInitialText) {
+ int len;
+#if defined(_UNICODE)
+ if(newData->isWchar)
+ SetDlgItemText(hwndDlg, IDC_MESSAGE, (TCHAR *)newData->szInitialText);
+ else
+ SetDlgItemTextA(hwndDlg, IDC_MESSAGE, newData->szInitialText);
+#else
+ SetDlgItemTextA(hwndDlg, IDC_MESSAGE, newData->szInitialText);
+#endif
+ len = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE));
+ PostMessage(GetDlgItem(hwndDlg, IDC_MESSAGE), EM_SETSEL, len, len);
+ }
+ }
+ dat->szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) dat->hContact, 0);
+ RichUtil_SubClass(GetDlgItem(hwndDlg, IDC_LOG));
+ { // avatar stuff
+ dat->avatarPic = 0;
+ dat->avatarWidth = 0;
+ dat->avatarHeight = 0;
+ dat->limitAvatarH = DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_LIMITAVHEIGHT, SRMSGDEFSET_LIMITAVHEIGHT)?DBGetContactSettingDword(NULL, SRMMMOD, SRMSGSET_AVHEIGHT, SRMSGDEFSET_AVHEIGHT):0;
+ }
+ if (dat->hContact && dat->szProto != NULL)
+ dat->wStatus = DBGetContactSettingWord(dat->hContact, dat->szProto, "Status", ID_STATUS_OFFLINE);
+ else
+ dat->wStatus = ID_STATUS_OFFLINE;
+ dat->wOldStatus = dat->wStatus;
+ dat->hSendId = NULL;
+ dat->hBkgBrush = NULL;
+ dat->hDbEventFirst = NULL;
+ dat->sendBuffer = NULL;
+ dat->splitterPos = (int) DBGetContactSettingDword(DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SAVEPERCONTACT, SRMSGDEFSET_SAVEPERCONTACT)?dat->hContact:NULL, SRMMMOD, "splitterPos", (DWORD) - 1);
+ dat->windowWasCascaded = 0;
+ dat->nFlash = 0;
+ dat->nTypeSecs = 0;
+ dat->nLastTyping = 0;
+ dat->showTyping = 0;
+ dat->cmdList = 0;
+ dat->cmdListCurrent = 0;
+ dat->nTypeMode = PROTOTYPE_SELFTYPING_OFF;
+ SetTimer(hwndDlg, TIMERID_TYPE, 1000, NULL);
+ dat->lastMessage = 0;
+ dat->lastEventType = -1;
+ dat->nFlashMax = DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_FLASHCOUNT, SRMSGDEFSET_FLASHCOUNT);
+ {
+ RECT rc, rc2;
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_USERMENU), &rc);
+ GetWindowRect(hwndDlg, &rc2);
+ dat->nLabelRight = rc2.right - rc.left;
+ }
+ {
+ RECT rc;
+ POINT pt;
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_SPLITTER), &rc);
+ pt.y = (rc.top + rc.bottom) / 2;
+ pt.x = 0;
+ ScreenToClient(hwndDlg, &pt);
+ dat->originalSplitterPos = pt.y;
+ if (dat->splitterPos == -1)
+ dat->splitterPos = dat->originalSplitterPos;// + 60;
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_ADD), &rc);
+ dat->lineHeight = rc.bottom - rc.top + 3;
+ }
+ WindowList_Add(g_dat->hMessageWindowList, hwndDlg, dat->hContact);
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_MESSAGE), &dat->minEditInit);
+ SendMessage(hwndDlg, DM_UPDATESIZEBAR, 0, 0);
+ dat->hwndStatus = NULL;
+ SendDlgItemMessage(hwndDlg, IDC_ADD, BM_SETIMAGE, IMAGE_ICON, (LPARAM) g_dat->hIcons[SMF_ICON_ADD]);
+ SendDlgItemMessage(hwndDlg, IDC_DETAILS, BM_SETIMAGE, IMAGE_ICON, (LPARAM) g_dat->hIcons[SMF_ICON_USERDETAIL]);
+ SendDlgItemMessage(hwndDlg, IDC_HISTORY, BM_SETIMAGE, IMAGE_ICON, (LPARAM) g_dat->hIcons[SMF_ICON_HISTORY]);
+ SendDlgItemMessage(hwndDlg, IDC_USERMENU, BM_SETIMAGE, IMAGE_ICON, (LPARAM) g_dat->hIcons[SMF_ICON_ARROW]);
+ // Make them flat buttons
+ {
+ int i;
+
+ SendMessage(GetDlgItem(hwndDlg, IDC_NAME), BUTTONSETASFLATBTN, 0, 0);
+ for (i = 0; i < SIZEOF(buttonLineControls); i++)
+ SendMessage(GetDlgItem(hwndDlg, buttonLineControls[i]), BUTTONSETASFLATBTN, 0, 0);
+ }
+ SendMessage(GetDlgItem(hwndDlg, IDC_ADD), BUTTONADDTOOLTIP, (WPARAM) Translate("Add Contact Permanently to List"), 0);
+ SendMessage(GetDlgItem(hwndDlg, IDC_USERMENU), BUTTONADDTOOLTIP, (WPARAM) Translate("User Menu"), 0);
+ SendMessage(GetDlgItem(hwndDlg, IDC_DETAILS), BUTTONADDTOOLTIP, (WPARAM) Translate("View User's Details"), 0);
+ SendMessage(GetDlgItem(hwndDlg, IDC_HISTORY), BUTTONADDTOOLTIP, (WPARAM) Translate("View User's History"), 0);
+
+ EnableWindow(GetDlgItem(hwndDlg, IDC_PROTOCOL), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_AVATAR), FALSE);
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETOLECALLBACK, 0, (LPARAM) & reOleCallback);
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_LINK);
+ /* duh, how come we didnt use this from the start? */
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_AUTOURLDETECT, (WPARAM) TRUE, 0);
+ if (dat->hContact) {
+ if (dat->szProto) {
+ int nMax;
+ nMax = CallProtoService(dat->szProto, PS_GETCAPS, PFLAG_MAXLENOFMESSAGE, (LPARAM) dat->hContact);
+ if (nMax)
+ SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_LIMITTEXT, (WPARAM) nMax, 0);
+ /* get around a lame bug in the Windows template resource code where richedits are limited to 0x7FFF */
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_LIMITTEXT, (WPARAM) sizeof(TCHAR) * 0x7FFFFFFF, 0);
+ }
+ }
+ OldMessageEditProc = (WNDPROC) SetWindowLong(GetDlgItem(hwndDlg, IDC_MESSAGE), GWL_WNDPROC, (LONG) MessageEditSubclassProc);
+ SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SUBCLASSED, 0, 0);
+ OldSplitterProc = (WNDPROC) SetWindowLong(GetDlgItem(hwndDlg, IDC_SPLITTER), GWL_WNDPROC, (LONG) SplitterSubclassProc);
+ if (dat->hContact) {
+ int historyMode = DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_LOADHISTORY, SRMSGDEFSET_LOADHISTORY);
+ // This finds the first message to display, it works like shit
+ dat->hDbEventFirst = (HANDLE) CallService(MS_DB_EVENT_FINDFIRSTUNREAD, (WPARAM) dat->hContact, 0);
+ switch (historyMode) {
+ case LOADHISTORY_COUNT:
+ {
+ int i;
+ HANDLE hPrevEvent;
+ DBEVENTINFO dbei = { 0 };
+ dbei.cbSize = sizeof(dbei);
+ for (i = DBGetContactSettingWord(NULL, SRMMMOD, SRMSGSET_LOADCOUNT, SRMSGDEFSET_LOADCOUNT); i > 0; i--) {
+ if (dat->hDbEventFirst == NULL)
+ hPrevEvent = (HANDLE) CallService(MS_DB_EVENT_FINDLAST, (WPARAM) dat->hContact, 0);
+ else
+ hPrevEvent = (HANDLE) CallService(MS_DB_EVENT_FINDPREV, (WPARAM) dat->hDbEventFirst, 0);
+ if (hPrevEvent == NULL)
+ break;
+ dbei.cbBlob = 0;
+ dat->hDbEventFirst = hPrevEvent;
+ CallService(MS_DB_EVENT_GET, (WPARAM) dat->hDbEventFirst, (LPARAM) & dbei);
+ if (!DbEventIsShown(&dbei, dat))
+ i++;
+ }
+ break;
+ }
+ case LOADHISTORY_TIME:
+ {
+ HANDLE hPrevEvent;
+ DBEVENTINFO dbei = { 0 };
+ DWORD firstTime;
+
+ dbei.cbSize = sizeof(dbei);
+ if (dat->hDbEventFirst == NULL)
+ dbei.timestamp = time(NULL);
+ else
+ CallService(MS_DB_EVENT_GET, (WPARAM) dat->hDbEventFirst, (LPARAM) & dbei);
+ firstTime = dbei.timestamp - 60 * DBGetContactSettingWord(NULL, SRMMMOD, SRMSGSET_LOADTIME, SRMSGDEFSET_LOADTIME);
+ for (;;) {
+ if (dat->hDbEventFirst == NULL)
+ hPrevEvent = (HANDLE) CallService(MS_DB_EVENT_FINDLAST, (WPARAM) dat->hContact, 0);
+ else
+ hPrevEvent = (HANDLE) CallService(MS_DB_EVENT_FINDPREV, (WPARAM) dat->hDbEventFirst, 0);
+ if (hPrevEvent == NULL)
+ break;
+ dbei.cbBlob = 0;
+ CallService(MS_DB_EVENT_GET, (WPARAM) hPrevEvent, (LPARAM) & dbei);
+ if (dbei.timestamp < firstTime)
+ break;
+ dat->hDbEventFirst = hPrevEvent;
+ }
+ break;
+ }
+ }
+ }
+ SendMessage(hwndDlg, DM_OPTIONSAPPLIED, 1, 0);
+ {
+ int savePerContact = DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SAVEPERCONTACT, SRMSGDEFSET_SAVEPERCONTACT);
+ if (Utils_RestoreWindowPosition(hwndDlg, savePerContact ? dat->hContact : NULL, SRMMMOD, "")) {
+ if (savePerContact) {
+ if (Utils_RestoreWindowPositionNoMove(hwndDlg, NULL, SRMMMOD, ""))
+ SetWindowPos(hwndDlg, 0, 0, 0, 450, 300, SWP_NOZORDER | SWP_NOMOVE);
+ }
+ else
+ SetWindowPos(hwndDlg, 0, 0, 0, 450, 300, SWP_NOZORDER | SWP_NOMOVE);
+ }
+ if (!savePerContact && DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_CASCADE, SRMSGDEFSET_CASCADE))
+ WindowList_Broadcast(g_dat->hMessageWindowList, DM_CASCADENEWWINDOW, (WPARAM) hwndDlg, (LPARAM) & dat->windowWasCascaded);
+ }
+ {
+ DBEVENTINFO dbei = { 0 };
+ HANDLE hdbEvent;
+
+ dbei.cbSize = sizeof(dbei);
+ hdbEvent = (HANDLE) CallService(MS_DB_EVENT_FINDLAST, (WPARAM) dat->hContact, 0);
+ if (hdbEvent) {
+ do {
+ ZeroMemory(&dbei, sizeof(dbei));
+ dbei.cbSize = sizeof(dbei);
+ CallService(MS_DB_EVENT_GET, (WPARAM) hdbEvent, (LPARAM) & dbei);
+ if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT)) {
+ dat->lastMessage = dbei.timestamp;
+ SendMessage(hwndDlg, DM_UPDATELASTMESSAGE, 0, 0);
+ break;
+ }
+ }
+ while (hdbEvent = (HANDLE) CallService(MS_DB_EVENT_FINDPREV, (WPARAM) hdbEvent, 0));
+ }
+
+ }
+ SendMessage(hwndDlg, DM_GETAVATAR, 0, 0);
+ ShowWindow(hwndDlg, SW_SHOWNORMAL);
+ NotifyLocalWinEvent(dat->hContact, hwndDlg, MSG_WINDOW_EVT_OPEN);
+ return TRUE;
+ }
+ case WM_CONTEXTMENU:
+ {
+ if (dat->hwndStatus && dat->hwndStatus == (HWND) wParam) {
+ POINT pt;
+ HMENU hMenu = (HMENU) CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM) dat->hContact, 0);
+
+ GetCursorPos(&pt);
+ TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, hwndDlg, NULL);
+ DestroyMenu(hMenu);
+ }
+ break;
+ }
+ // Mod from tabsrmm
+ case WM_DROPFILES:
+ {
+ if (dat->szProto==NULL) break;
+ if (!(CallProtoService(dat->szProto, PS_GETCAPS, PFLAGNUM_1,0)&PF1_FILESEND)) break;
+ if (dat->wStatus==ID_STATUS_OFFLINE) break;
+ if (dat->hContact!=NULL) {
+ HDROP hDrop;
+ char **ppFiles=NULL;
+ char szFilename[MAX_PATH];
+ int fileCount,totalCount=0,i;
+
+ hDrop=(HDROP)wParam;
+ fileCount=DragQueryFile(hDrop,-1,NULL,0);
+ ppFiles=NULL;
+ for(i=0;i<fileCount;i++) {
+ DragQueryFileA(hDrop, i, szFilename, SIZEOF(szFilename));
+ AddToFileList(&ppFiles, &totalCount, szFilename);
+ }
+ CallServiceSync(MS_FILE_SENDSPECIFICFILES, (WPARAM)dat->hContact, (LPARAM)ppFiles);
+ for(i=0;ppFiles[i];i++) free(ppFiles[i]);
+ free(ppFiles);
+ }
+ break;
+ }
+ case HM_AVATARACK:
+ {
+ ACKDATA *pAck = (ACKDATA *)lParam;
+ PROTO_AVATAR_INFORMATION *pai = (PROTO_AVATAR_INFORMATION *)pAck->hProcess;
+ HWND hwnd = 0;
+
+ if (pAck->hContact!=dat->hContact)
+ return 0;
+ if (pAck->type != ACKTYPE_AVATAR)
+ return 0;
+ if (pAck->result == ACKRESULT_STATUS) {
+ SendMessage(hwndDlg, DM_GETAVATAR, 0, 0);
+ break;
+ }
+ if (pai==NULL)
+ return 0;
+ if (pAck->result == ACKRESULT_SUCCESS) {
+ if (pai->filename&&strlen(pai->filename)&&VALID_AVATAR(pai->format)) {
+ DBWriteContactSettingString(dat->hContact, SRMMMOD, SRMSGSET_AVATAR, pai->filename);
+ ShowAvatar(hwndDlg, dat);
+ }
+ }
+ else if (pAck->result == ACKRESULT_FAILED) {
+ DBWriteContactSettingString(dat->hContact, SRMMMOD, SRMSGSET_AVATAR, "");
+ ShowAvatar(hwndDlg, dat);
+ }
+ break;
+ }
+ case DM_AVATARCALCSIZE:
+ {
+ BITMAP bminfo;
+
+ if (dat->avatarPic==0||!(g_dat->flags&SMF_AVATAR)) {
+ dat->avatarWidth=50;
+ dat->avatarHeight=50;
+ ShowWindow(GetDlgItem(hwndDlg, IDC_AVATAR), SW_HIDE);
+ return 0;
+ }
+ GetObject(dat->avatarPic, sizeof(bminfo), &bminfo);
+ dat->avatarWidth=bminfo.bmWidth+2;
+ dat->avatarHeight=bminfo.bmHeight+2;
+ if (dat->limitAvatarH&&dat->avatarHeight>dat->limitAvatarH) {
+ double aspect = 0;
+
+ aspect = (double)dat->limitAvatarH / (double)bminfo.bmHeight;
+ dat->avatarWidth = (int)(bminfo.bmWidth * aspect + 2);
+ dat->avatarHeight = dat->limitAvatarH + 2;
+ }
+ ShowWindow(GetDlgItem(hwndDlg, IDC_AVATAR), SW_SHOW);
+ break;
+ }
+ case DM_UPDATESIZEBAR:
+ {
+ dat->minEditBoxSize.cx = dat->minEditInit.right - dat->minEditInit.left;
+ dat->minEditBoxSize.cy = dat->minEditInit.bottom - dat->minEditInit.top;
+ if (g_dat->flags&SMF_AVATAR) {
+ SendMessage(hwndDlg, DM_AVATARCALCSIZE, 0, 0);
+ if(dat->avatarPic) {
+ if (dat->minEditBoxSize.cy<=dat->avatarHeight)
+ dat->minEditBoxSize.cy = dat->avatarHeight;
+ }
+ }
+ break;
+ }
+ case DM_AVATARSIZECHANGE:
+ {
+ RECT rc;
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_MESSAGE), &rc);
+ if (rc.bottom-rc.top<dat->minEditBoxSize.cy) {
+ SendMessage(hwndDlg, DM_SPLITTERMOVED, rc.top-(rc.bottom-rc.top-dat->minEditBoxSize.cy-4), (LPARAM) GetDlgItem(hwndDlg, IDC_SPLITTER));
+ }
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ SendMessage(hwndDlg, DM_SCROLLLOGTOBOTTOM, 0, 0);
+ break;
+ }
+ case DM_GETAVATAR:
+ {
+ PROTO_AVATAR_INFORMATION pai;
+ int caps = 0, result;
+
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, 0);
+ if (!(g_dat->flags&SMF_AVATAR)||!(CallProtoService(dat->szProto, PS_GETCAPS, PFLAGNUM_4, 0)&PF4_AVATARS)) {
+ SendMessage(hwndDlg, DM_UPDATESIZEBAR, 0, 0);
+ SendMessage(hwndDlg, DM_AVATARSIZECHANGE, 0, 0);
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, 1);
+ return 0;
+ }
+ if(DBGetContactSettingWord(dat->hContact, dat->szProto, "Status", ID_STATUS_OFFLINE) == ID_STATUS_OFFLINE) {
+ ShowAvatar(hwndDlg, dat);
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, 1);
+ return 0;
+ }
+ ZeroMemory((void *)&pai, sizeof(pai));
+ pai.cbSize = sizeof(pai);
+ pai.hContact = dat->hContact;
+ pai.format = PA_FORMAT_UNKNOWN;
+ strcpy(pai.filename, "");
+ result = CallProtoService(dat->szProto, PS_GETAVATARINFO, GAIF_FORCE, (LPARAM)&pai);
+ if (result==GAIR_SUCCESS) {
+ if (VALID_AVATAR(pai.format))
+ DBWriteContactSettingString(dat->hContact, SRMMMOD, SRMSGSET_AVATAR, pai.filename);
+ else DBWriteContactSettingString(dat->hContact, SRMMMOD, SRMSGSET_AVATAR, "");
+ ShowAvatar(hwndDlg, dat);
+ } else if (result == GAIR_NOAVATAR) {
+ DBWriteContactSettingString(dat->hContact, SRMMMOD, SRMSGSET_AVATAR, "");
+ ShowAvatar(hwndDlg, dat);
+ }
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, 1);
+ break;
+ }
+ case DM_TYPING:
+ {
+ dat->nTypeSecs = (int) lParam > 0 ? (int) lParam : 0;
+ break;
+ }
+ case DM_UPDATEWINICON:
+ {
+ if (DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_STATUSICON, SRMSGDEFSET_STATUSICON)) {
+ WORD wStatus;
+
+ if (dat->szProto) {
+ wStatus = DBGetContactSettingWord(dat->hContact, dat->szProto, "Status", ID_STATUS_OFFLINE);
+ SendMessage(hwndDlg, WM_SETICON, (WPARAM) ICON_BIG, (LPARAM) LoadSkinnedProtoIcon(dat->szProto, wStatus));
+ break;
+ }
+ }
+ SendMessage(hwndDlg, WM_SETICON, (WPARAM) ICON_BIG, (LPARAM) LoadSkinnedIcon(SKINICON_EVENT_MESSAGE));
+ break;
+ }
+ case DM_USERNAMETOCLIP:
+ {
+ CONTACTINFO ci;
+ char buf[128];
+ HGLOBAL hData;
+
+ buf[0] = 0;
+ if(dat->hContact) {
+ ZeroMemory(&ci, sizeof(ci));
+ ci.cbSize = sizeof(ci);
+ ci.hContact = dat->hContact;
+ ci.szProto = dat->szProto;
+ ci.dwFlag = CNF_UNIQUEID;
+ if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
+ switch (ci.type) {
+ case CNFT_ASCIIZ:
+ mir_snprintf(buf, SIZEOF(buf), "%s", ci.pszVal);
+ miranda_sys_free(ci.pszVal);
+ break;
+ case CNFT_DWORD:
+ mir_snprintf(buf, SIZEOF(buf), "%u", ci.dVal);
+ break;
+ }
+ }
+ if (!OpenClipboard(hwndDlg) || !lstrlenA(buf)) break;
+ EmptyClipboard();
+ hData = GlobalAlloc(GMEM_MOVEABLE, lstrlenA(buf) + 1);
+ lstrcpyA(GlobalLock(hData), buf);
+ GlobalUnlock(hData);
+ SetClipboardData(CF_TEXT, hData);
+ CloseClipboard();
+ }
+ break;
+ }
+ case DM_UPDATELASTMESSAGE:
+ {
+ if (!dat->hwndStatus || dat->nTypeSecs)
+ break;
+ if (dat->lastMessage) {
+ DBTIMETOSTRINGT dbtts;
+ TCHAR date[64], time[64], fmt[128];
+
+ dbtts.szFormat = _T("d");
+ dbtts.cbDest = SIZEOF(date);
+ dbtts.szDest = date;
+ CallService(MS_DB_TIME_TIMESTAMPTOSTRINGT, dat->lastMessage, (LPARAM) & dbtts);
+ dbtts.szFormat = _T("t");
+ dbtts.cbDest = SIZEOF(time);
+ dbtts.szDest = time;
+ CallService(MS_DB_TIME_TIMESTAMPTOSTRINGT, dat->lastMessage, (LPARAM) & dbtts);
+ mir_sntprintf(fmt, SIZEOF(fmt), TranslateT("Last message received on %s at %s."), date, time);
+ SendMessage(dat->hwndStatus, SB_SETTEXT, 0, (LPARAM) fmt);
+ SendMessage(dat->hwndStatus, SB_SETICON, 0, (LPARAM) NULL);
+ }
+ else {
+ SendMessage(dat->hwndStatus, SB_SETTEXT, 0, (LPARAM) _T(""));
+ SendMessage(dat->hwndStatus, SB_SETICON, 0, (LPARAM) NULL);
+ }
+ break;
+ }
+ case DM_OPTIONSAPPLIED:
+ SetDialogToType(hwndDlg);
+ if (dat->hBkgBrush)
+ DeleteObject(dat->hBkgBrush);
+ {
+ COLORREF colour = DBGetContactSettingDword(NULL, SRMMMOD, SRMSGSET_BKGCOLOUR, SRMSGDEFSET_BKGCOLOUR);
+ dat->hBkgBrush = CreateSolidBrush(colour);
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETBKGNDCOLOR, 0, colour);
+ }
+ { // avatar stuff
+ dat->avatarPic = 0;
+ dat->limitAvatarH = 0;
+ if (CallProtoService(dat->szProto, PS_GETCAPS, PFLAGNUM_4, 0)&PF4_AVATARS) {
+ dat->limitAvatarH = DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_LIMITAVHEIGHT, SRMSGDEFSET_LIMITAVHEIGHT)?DBGetContactSettingDword(NULL, SRMMMOD, SRMSGSET_AVHEIGHT, SRMSGDEFSET_AVHEIGHT):0;
+ }
+ if (!wParam) SendMessage(hwndDlg, DM_GETAVATAR, 0, 0);
+ }
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_MESSAGE), NULL, FALSE);
+ {
+ HFONT hFont;
+ LOGFONT lf;
+ hFont = (HFONT) SendDlgItemMessage(hwndDlg, IDC_MESSAGE, WM_GETFONT, 0, 0);
+ if (hFont != NULL && hFont != (HFONT) SendDlgItemMessage(hwndDlg, IDOK, WM_GETFONT, 0, 0))
+ DeleteObject(hFont);
+ LoadMsgDlgFont(MSGFONTID_MESSAGEAREA, &lf, NULL);
+ hFont = CreateFontIndirect(&lf);
+ SendDlgItemMessage(hwndDlg, IDC_MESSAGE, WM_SETFONT, (WPARAM) hFont, MAKELPARAM(TRUE, 0));
+ }
+
+ /*
+ * configure message history for proper RTL formatting
+ */
+
+ {
+ PARAFORMAT2 pf2;
+ ZeroMemory((void *)&pf2, sizeof(pf2));
+ pf2.cbSize = sizeof(pf2);
+
+ pf2.wEffects = PFE_RTLPARA;
+ pf2.dwMask = PFM_RTLPARA;
+ SetDlgItemText(hwndDlg, IDC_LOG, _T(""));
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
+ pf2.wEffects = 0;
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETLANGOPTIONS, 0, (LPARAM) SendDlgItemMessage(hwndDlg, IDC_LOG, EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD);
+ }
+ SendMessage(hwndDlg, DM_REMAKELOG, 0, 0);
+ SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0);
+ break;
+ case DM_UPDATETITLE:
+ {
+ TCHAR newtitle[256], oldtitle[256], *szStatus;
+ TCHAR *contactName, *pszNewTitleEnd;
+ DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *) wParam;
+
+ pszNewTitleEnd = _T("Message Session");
+ if (dat->hContact) {
+ if (dat->szProto) {
+ CONTACTINFO ci;
+ char buf[128];
+ int statusIcon = DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_STATUSICON, SRMSGDEFSET_STATUSICON);
+
+ buf[0] = 0;
+ dat->wStatus = DBGetContactSettingWord(dat->hContact, dat->szProto, "Status", ID_STATUS_OFFLINE);
+ contactName = ( TCHAR* )CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) dat->hContact, GCDNF_TCHAR);
+ ZeroMemory(&ci, sizeof(ci));
+ ci.cbSize = sizeof(ci);
+ ci.hContact = dat->hContact;
+ ci.szProto = dat->szProto;
+ ci.dwFlag = CNF_UNIQUEID;
+ if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
+ switch (ci.type) {
+ case CNFT_ASCIIZ:
+ mir_snprintf(buf, SIZEOF(buf), "%s", ci.pszVal);
+ miranda_sys_free(ci.pszVal);
+ break;
+ case CNFT_DWORD:
+ mir_snprintf(buf, SIZEOF(buf), "%u", ci.dVal);
+ break;
+ }
+ }
+ if ( buf[0] )
+ SetDlgItemTextA(hwndDlg, IDC_NAME, buf );
+ else
+ SetDlgItemText(hwndDlg, IDC_NAME, contactName);
+
+ szStatus = (TCHAR*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, dat->szProto == NULL ? ID_STATUS_OFFLINE : DBGetContactSettingWord(dat->hContact, dat->szProto, "Status", ID_STATUS_OFFLINE), GCMDF_TCHAR);
+ if (statusIcon)
+ mir_sntprintf(newtitle, SIZEOF(newtitle), _T("%s - %s"), contactName, TranslateTS(pszNewTitleEnd));
+ else
+ mir_sntprintf(newtitle, SIZEOF(newtitle), _T("%s (%s): %s"), contactName, szStatus, TranslateTS(pszNewTitleEnd));
+ if (!cws || (!strcmp(cws->szModule, dat->szProto) && !strcmp(cws->szSetting, "Status"))) {
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_PROTOCOL), NULL, TRUE);
+ if (statusIcon) {
+ SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0);
+ }
+ }
+
+ // log
+ if ((dat->wStatus != dat->wOldStatus || lParam != 0)
+ && DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWSTATUSCH, SRMSGDEFSET_SHOWSTATUSCH)) {
+ DBEVENTINFO dbei;
+ TCHAR buffer[200];
+ HANDLE hNewEvent;
+ int iLen;
+
+ TCHAR *szOldStatus = (TCHAR*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, (WPARAM) dat->wOldStatus, GCMDF_TCHAR);
+ TCHAR *szNewStatus = (TCHAR*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, (WPARAM) dat->wStatus, GCMDF_TCHAR);
+
+ if (dat->wStatus == ID_STATUS_OFFLINE) {
+ iLen = mir_sntprintf(buffer, SIZEOF(buffer), TranslateT("signed off (was %s)"), szOldStatus);
+ SendMessage(hwndDlg, DM_TYPING, 0, 0);
+ }
+ else if (dat->wOldStatus == ID_STATUS_OFFLINE)
+ iLen = mir_sntprintf(buffer, SIZEOF(buffer), TranslateT("signed on (%s)"), szNewStatus);
+ else
+ iLen = mir_sntprintf(buffer, SIZEOF(buffer), TranslateT("is now %s (was %s)"), szNewStatus, szOldStatus);
+
+ {
+ char* blob = ( char* )alloca( 1000 );
+ #if defined( _UNICODE )
+ int ansiLen = WideCharToMultiByte(CP_ACP, 0, buffer, -1, blob, 1000, 0, 0);
+ memcpy( blob+ansiLen, buffer, sizeof(TCHAR)*(iLen+1));
+ dbei.cbBlob = ansiLen + sizeof(TCHAR)*(iLen+1);
+ #else
+ int wLen = MultiByteToWideChar(CP_ACP, 0, buffer, -1, NULL, 0 );
+ memcpy( blob, buffer, iLen+1 );
+ MultiByteToWideChar(CP_ACP, 0, buffer, -1, (WCHAR*)&blob[iLen+1], wLen+1 );
+ dbei.cbBlob = iLen+1 + sizeof(WCHAR)*wLen;
+ #endif
+
+ dbei.cbSize = sizeof(dbei);
+ dbei.pBlob = (PBYTE) blob;
+ dbei.eventType = EVENTTYPE_STATUSCHANGE;
+ dbei.flags = 0;
+ dbei.timestamp = time(NULL);
+ dbei.szModule = dat->szProto;
+ hNewEvent = (HANDLE) CallService(MS_DB_EVENT_ADD, (WPARAM) dat->hContact, (LPARAM) & dbei);
+ if (dat->hDbEventFirst == NULL) {
+ dat->hDbEventFirst = hNewEvent;
+ SendMessage(hwndDlg, DM_REMAKELOG, 0, 0);
+ }
+ }
+ }
+ dat->wOldStatus = dat->wStatus;
+ }
+ }
+ else lstrcpyn(newtitle, pszNewTitleEnd, SIZEOF(newtitle));
+
+ GetWindowText(hwndDlg, oldtitle, SIZEOF(oldtitle));
+ if ( lstrcmp(newtitle, oldtitle )) { //swt() flickers even if the title hasn't actually changed
+ SetWindowText(hwndDlg, newtitle);
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ }
+ break;
+ }
+ case DM_GETWINDOWSTATE:
+ {
+ UINT state = 0;
+
+ state |= MSG_WINDOW_STATE_EXISTS;
+ if (IsWindowVisible(hwndDlg))
+ state |= MSG_WINDOW_STATE_VISIBLE;
+ if (GetForegroundWindow()==hwndDlg)
+ state |= MSG_WINDOW_STATE_FOCUS;
+ if (IsIconic(hwndDlg))
+ state |= MSG_WINDOW_STATE_ICONIC;
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, state);
+ return TRUE;
+
+ }
+ case DM_CASCADENEWWINDOW:
+ if ((HWND) wParam == hwndDlg)
+ break;
+ {
+ RECT rcThis, rcNew;
+ GetWindowRect(hwndDlg, &rcThis);
+ GetWindowRect((HWND) wParam, &rcNew);
+ if (abs(rcThis.left - rcNew.left) < 3 && abs(rcThis.top - rcNew.top) < 3) {
+ int offset = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFRAME);
+ SetWindowPos((HWND) wParam, 0, rcNew.left + offset, rcNew.top + offset, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
+ *(int *) lParam = 1;
+ }
+ }
+ break;
+ case WM_ACTIVATE:
+ if (LOWORD(wParam) != WA_ACTIVE)
+ break;
+ //fall through
+ case WM_MOUSEACTIVATE:
+ if (KillTimer(hwndDlg, TIMERID_FLASHWND))
+ FlashWindow(hwndDlg, FALSE);
+ break;
+ case WM_SETFOCUS:
+ SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+ break;
+ case WM_GETMINMAXINFO:
+ {
+ MINMAXINFO *mmi = (MINMAXINFO *) lParam;
+ RECT rcWindow, rcLog;
+ GetWindowRect(hwndDlg, &rcWindow);
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_LOG), &rcLog);
+ mmi->ptMinTrackSize.x = rcWindow.right - rcWindow.left - ((rcLog.right - rcLog.left) - dat->minEditBoxSize.cx);
+ mmi->ptMinTrackSize.y = rcWindow.bottom - rcWindow.top - ((rcLog.bottom - rcLog.top) - dat->minEditBoxSize.cy);
+ return 0;
+ }
+ case WM_SIZE:
+ {
+ UTILRESIZEDIALOG urd;
+ if (IsIconic(hwndDlg))
+ break;
+ if (dat->hwndStatus) {
+ SendMessage(dat->hwndStatus, WM_SIZE, 0, 0);
+ if (SendMessage(dat->hwndStatus, SB_GETPARTS, 0, 0) == 2) {
+ int statwidths[2];
+ RECT rc;
+
+ GetWindowRect(dat->hwndStatus, &rc);
+ statwidths[0] = rc.right - rc.left - SB_CHAR_WIDTH;
+ statwidths[1] = -1;
+ SendMessage(dat->hwndStatus, SB_SETPARTS, 2, (LPARAM) statwidths);
+ }
+ }
+ ZeroMemory(&urd, sizeof(urd));
+ urd.cbSize = sizeof(urd);
+ urd.hInstance = g_hInst;
+ urd.hwndDlg = hwndDlg;
+ urd.lParam = (LPARAM) dat;
+ urd.lpTemplate = MAKEINTRESOURCEA(IDD_MSG);
+ urd.pfnResizer = MessageDialogResize;
+ CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM) & urd);
+ // The statusbar sometimes draws over these 2 controls so
+ // redraw them
+ if (dat->hwndStatus) {
+ RedrawWindow(GetDlgItem(hwndDlg, IDOK), NULL, NULL, RDW_INVALIDATE);
+ RedrawWindow(GetDlgItem(hwndDlg, IDC_MESSAGE), NULL, NULL, RDW_INVALIDATE);
+ }
+ if ((g_dat->flags&SMF_AVATAR)&&dat->avatarPic)
+ RedrawWindow(GetDlgItem(hwndDlg, IDC_AVATAR), NULL, NULL, RDW_INVALIDATE);
+ break;
+ }
+ case DM_SPLITTERMOVED:
+ {
+ POINT pt;
+ RECT rc;
+ RECT rcLog;
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_LOG), &rcLog);
+ if ((HWND) lParam == GetDlgItem(hwndDlg, IDC_SPLITTER)) {
+ int oldSplitterY;
+ GetClientRect(hwndDlg, &rc);
+ pt.x = 0;
+ pt.y = wParam;
+ ScreenToClient(hwndDlg, &pt);
+
+ oldSplitterY = dat->splitterPos;
+ dat->splitterPos = rc.bottom - pt.y + 23;
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_MESSAGE), &rc);
+ if (rc.bottom - rc.top + (dat->splitterPos - oldSplitterY) < dat->minEditBoxSize.cy)
+ dat->splitterPos = oldSplitterY + dat->minEditBoxSize.cy - (rc.bottom - rc.top);
+ if (rcLog.bottom - rcLog.top - (dat->splitterPos - oldSplitterY) < dat->minEditBoxSize.cy)
+ dat->splitterPos = oldSplitterY - dat->minEditBoxSize.cy + (rcLog.bottom - rcLog.top);
+ }
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ break;
+ }
+ case DM_REMAKELOG:
+ dat->lastEventType = -1;
+ StreamInEvents(hwndDlg, dat->hDbEventFirst, -1, 0);
+ break;
+ case DM_APPENDTOLOG: //takes wParam=hDbEvent
+ StreamInEvents(hwndDlg, (HANDLE) wParam, 1, 1);
+ break;
+ case DM_SCROLLLOGTOBOTTOM:
+ {
+ SCROLLINFO si = { 0 };
+ if ((GetWindowLong(GetDlgItem(hwndDlg, IDC_LOG), GWL_STYLE) & WS_VSCROLL) == 0)
+ break;
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_PAGE | SIF_RANGE;
+ GetScrollInfo(GetDlgItem(hwndDlg, IDC_LOG), SB_VERT, &si);
+ si.fMask = SIF_POS;
+ si.nPos = si.nMax - si.nPage + 1;
+ SetScrollInfo(GetDlgItem(hwndDlg, IDC_LOG), SB_VERT, &si, TRUE);
+ PostMessage(GetDlgItem(hwndDlg, IDC_LOG), WM_VSCROLL, MAKEWPARAM(SB_BOTTOM, 0), 0);
+ break;
+ }
+ case HM_DBEVENTADDED:
+ if ((HANDLE) wParam != dat->hContact)
+ break;
+ {
+ DBEVENTINFO dbei = { 0 };
+
+ dbei.cbSize = sizeof(dbei);
+ dbei.cbBlob = 0;
+ CallService(MS_DB_EVENT_GET, lParam, (LPARAM) & dbei);
+ if (dat->hDbEventFirst == NULL)
+ dat->hDbEventFirst = (HANDLE) lParam;
+ if (dbei.eventType == EVENTTYPE_MESSAGE && (dbei.flags & DBEF_READ))
+ break;
+ if (DbEventIsShown(&dbei, dat)) {
+ if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & (DBEF_SENT))) {
+ if (GetForegroundWindow()==hwndDlg)
+ SkinPlaySound("RecvMsgActive");
+ else SkinPlaySound("RecvMsgInactive");
+ }
+ if (dbei.eventType == EVENTTYPE_MESSAGE && dat->hwndStatus && !(dbei.flags & (DBEF_SENT))) {
+ dat->lastMessage = dbei.timestamp;
+ SendMessage(hwndDlg, DM_UPDATELASTMESSAGE, 0, 0);
+ }
+ if ((HANDLE) lParam != dat->hDbEventFirst && (HANDLE) CallService(MS_DB_EVENT_FINDNEXT, lParam, 0) == NULL)
+ SendMessage(hwndDlg, DM_APPENDTOLOG, lParam, 0);
+ else
+ SendMessage(hwndDlg, DM_REMAKELOG, 0, 0);
+ if ((GetActiveWindow() != hwndDlg || GetForegroundWindow() != hwndDlg) && !(dbei.flags & DBEF_SENT)
+ && dbei.eventType != EVENTTYPE_STATUSCHANGE) {
+ SetTimer(hwndDlg, TIMERID_FLASHWND, TIMEOUT_FLASHWND, NULL);
+ }
+ }
+ break;
+ }
+ case WM_TIMER:
+ if (wParam == TIMERID_MSGSEND) {
+ KillTimer(hwndDlg, wParam);
+ ShowWindow(hwndDlg, SW_SHOWNORMAL);
+ EnableWindow(hwndDlg, FALSE);
+ CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_MSGSENDERROR), hwndDlg, ErrorDlgProc, (LPARAM) strdup( Translate("The message send timed out.")));
+ }
+ else if (wParam == TIMERID_FLASHWND) {
+ FlashWindow(hwndDlg, TRUE);
+ if (dat->nFlash > dat->nFlashMax) {
+ KillTimer(hwndDlg, TIMERID_FLASHWND);
+ FlashWindow(hwndDlg, FALSE);
+ dat->nFlash = 0;
+ }
+ dat->nFlash++;
+ }
+ else if (wParam == TIMERID_TYPE) {
+ if (dat->nTypeMode == PROTOTYPE_SELFTYPING_ON && GetTickCount() - dat->nLastTyping > TIMEOUT_TYPEOFF) {
+ NotifyTyping(dat, PROTOTYPE_SELFTYPING_OFF);
+ }
+ if (dat->showTyping) {
+ if (dat->nTypeSecs) {
+ dat->nTypeSecs--;
+ if (GetForegroundWindow() == hwndDlg)
+ SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0);
+ }
+ else {
+ SendMessage(hwndDlg, DM_UPDATELASTMESSAGE, 0, 0);
+ if (g_dat->flags&SMF_SHOWTYPINGWIN)
+ SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0);
+ dat->showTyping = 0;
+ }
+ }
+ else {
+ if (dat->nTypeSecs) {
+ TCHAR szBuf[256];
+ TCHAR *szContactName = ( TCHAR* ) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) dat->hContact, GCDNF_TCHAR);
+
+ mir_sntprintf(szBuf, SIZEOF(szBuf), TranslateT("%s is typing a message..."), szContactName);
+ dat->nTypeSecs--;
+ SendMessage(dat->hwndStatus, SB_SETTEXT, 0, (LPARAM) szBuf);
+ SendMessage(dat->hwndStatus, SB_SETICON, 0, (LPARAM) g_dat->hIcons[SMF_ICON_TYPING]);
+ if ((g_dat->flags&SMF_SHOWTYPINGWIN) && GetForegroundWindow() != hwndDlg)
+ SendMessage(hwndDlg, WM_SETICON, (WPARAM) ICON_BIG, (LPARAM) g_dat->hIcons[SMF_ICON_TYPING]);
+ dat->showTyping = 1;
+ }
+ }
+ }
+ break;
+ case DM_ERRORDECIDED:
+ EnableWindow(hwndDlg, TRUE);
+ switch (wParam) {
+ case MSGERROR_CANCEL:
+ EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE);
+ SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETREADONLY, FALSE, 0);
+ SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+ break;
+ case MSGERROR_RETRY:
+ {
+ if (dat->hSendId == NULL && dat->hContact == NULL)
+ return 0;
+ dat->hSendId = (HANDLE) CallContactService(dat->hContact, MsgServiceName(dat->hContact), SEND_FLAGS, (LPARAM) dat->sendBuffer);
+ }
+ SetTimer(hwndDlg, TIMERID_MSGSEND, DBGetContactSettingDword(NULL, SRMMMOD, SRMSGSET_MSGTIMEOUT, SRMSGDEFSET_MSGTIMEOUT), NULL);
+ break;
+ }
+ break;
+ case WM_CTLCOLOREDIT:
+ {
+ COLORREF colour;
+ if ((HWND) lParam != GetDlgItem(hwndDlg, IDC_MESSAGE))
+ break;
+ LoadMsgDlgFont(MSGFONTID_MESSAGEAREA, NULL, &colour);
+ SetTextColor((HDC) wParam, colour);
+ SetBkColor((HDC) wParam, DBGetContactSettingDword(NULL, SRMMMOD, SRMSGSET_BKGCOLOUR, SRMSGDEFSET_BKGCOLOUR));
+ return (BOOL) dat->hBkgBrush;
+ }
+ case WM_MEASUREITEM:
+ return CallService(MS_CLIST_MENUMEASUREITEM, wParam, lParam);
+ case WM_DRAWITEM:
+ {
+ LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT) lParam;
+ if (dis->hwndItem == GetDlgItem(hwndDlg, IDC_PROTOCOL)) {
+ if (dat->szProto) {
+ HICON hIcon;
+ int dwStatus;
+
+ dwStatus = DBGetContactSettingWord(dat->hContact, dat->szProto, "Status", ID_STATUS_OFFLINE);
+ hIcon = LoadSkinnedProtoIcon(dat->szProto, dwStatus);
+ if (hIcon) {
+ if (DBGetContactSettingDword(dat->hContact, dat->szProto, "IdleTS", 0)) {
+ HIMAGELIST hImageList;
+
+ hImageList = ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON), IsWinVerXPPlus()? ILC_COLOR32 | ILC_MASK : ILC_COLOR16 | ILC_MASK, 1, 0);
+ ImageList_AddIcon(hImageList, hIcon);
+ ImageList_DrawEx(hImageList, 0, dis->hDC, dis->rcItem.left, dis->rcItem.top, 0, 0, CLR_NONE, CLR_NONE, ILD_SELECTED);
+ ImageList_RemoveAll(hImageList);
+ ImageList_Destroy(hImageList);
+ }
+ else DrawIconEx(dis->hDC, dis->rcItem.left, dis->rcItem.top, hIcon, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0, NULL, DI_NORMAL);
+ }
+ }
+ }
+ else if (dis->hwndItem == GetDlgItem(hwndDlg, IDC_AVATAR) && dat->avatarPic && (g_dat->flags&SMF_AVATAR)) {
+ BITMAP bminfo;
+ HPEN hPen, hOldPen;
+
+ hPen = CreatePen(PS_SOLID, 1, RGB(0,0,0));
+ hOldPen = SelectObject(dis->hDC, hPen);
+ Rectangle(dis->hDC, 0, 0, dat->avatarWidth, dat->avatarHeight);
+ SelectObject(dis->hDC,hOldPen);
+ DeleteObject(hPen);
+ GetObject(dat->avatarPic, sizeof(bminfo), &bminfo);
+ {
+ HDC hdcMem = CreateCompatibleDC(dis->hDC);
+ HBITMAP hbmMem = (HBITMAP)SelectObject(hdcMem, dat->avatarPic);
+ {
+ double aspect = 0, w = 0;
+
+ aspect = (double)dat->limitAvatarH / (double)bminfo.bmHeight;
+ w = (double)bminfo.bmWidth * aspect;
+ SetStretchBltMode(dis->hDC, HALFTONE);
+ StretchBlt(dis->hDC, 1, 1, dat->avatarWidth-2, dat->avatarHeight-2, hdcMem, 0, 0, bminfo.bmWidth, bminfo.bmHeight, SRCCOPY);
+ }
+ SelectObject(hdcMem,hbmMem);
+ DeleteDC(hdcMem);
+ }
+ }
+ return CallService(MS_CLIST_MENUDRAWITEM, wParam, lParam);
+ }
+ case WM_COMMAND:
+ if (CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_CONTACTMENU), (LPARAM) dat->hContact))
+ break;
+ switch (LOWORD(wParam)) {
+ case IDOK:
+ if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDOK)))
+ break;
+ {
+ int flags = SEND_FLAGS;
+ //this is a 'send' button
+ int bufSize = GetWindowTextLengthA(GetDlgItem(hwndDlg, IDC_MESSAGE)) + 1;
+ dat->sendBuffer = (char *) realloc(dat->sendBuffer, bufSize * (sizeof(TCHAR) + 1));
+ dat->bIsRtl = 0;
+ GetDlgItemTextA(hwndDlg, IDC_MESSAGE, dat->sendBuffer, bufSize);
+ #if defined( _UNICODE )
+ // all that crap with temporary buffers is related to the bug #0001466 (empty messages
+ // on x64 machines). GetDlgItemTextW should use the 2-byte aligned buffer
+ { WCHAR* temp = ( WCHAR* )alloca( bufSize * sizeof( TCHAR ));
+ GetDlgItemTextW(hwndDlg, IDC_MESSAGE, temp, bufSize);
+ memcpy(( TCHAR*)&dat->sendBuffer[bufSize], temp, bufSize * sizeof( TCHAR ));
+ if ( RTL_Detect( temp )) {
+ flags |= PREF_RTL;
+ dat->bIsRtl = 1;
+ }
+ }
+ #endif
+ if (dat->sendBuffer[0] == 0)
+ break;
+ #if defined( _UNICODE )
+ dat->cmdList = tcmdlist_append(dat->cmdList, (TCHAR *) & dat->sendBuffer[bufSize]);
+ #else
+ dat->cmdList = tcmdlist_append(dat->cmdList, dat->sendBuffer);
+ #endif
+ dat->cmdListCurrent = 0;
+ if (dat->nTypeMode == PROTOTYPE_SELFTYPING_ON) {
+ NotifyTyping(dat, PROTOTYPE_SELFTYPING_OFF);
+ }
+
+ if (dat->hContact == NULL)
+ break; //never happens
+ dat->sendCount = 1;
+ dat->hSendId = (HANDLE) CallContactService(dat->hContact, MsgServiceName(dat->hContact), flags, (LPARAM) dat->sendBuffer);
+ EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
+ SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETREADONLY, TRUE, 0);
+
+ //create a timeout timer
+ SetTimer(hwndDlg, TIMERID_MSGSEND, DBGetContactSettingDword(NULL, SRMMMOD, SRMSGSET_MSGTIMEOUT, SRMSGDEFSET_MSGTIMEOUT), NULL);
+ if (DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_AUTOMIN, SRMSGDEFSET_AUTOMIN))
+ ShowWindow(hwndDlg, SW_MINIMIZE);
+ }
+ return TRUE;
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ case IDC_USERMENU:
+ case IDC_NAME:
+ {
+ if(GetKeyState(VK_SHIFT) & 0x8000) { // copy user name
+ SendMessage(hwndDlg, DM_USERNAMETOCLIP, 0, 0);
+ }
+ else {
+ RECT rc;
+ HMENU hMenu = (HMENU) CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM) dat->hContact, 0);
+ GetWindowRect(GetDlgItem(hwndDlg, LOWORD(wParam)), &rc);
+ TrackPopupMenu(hMenu, 0, rc.left, rc.bottom, 0, hwndDlg, NULL);
+ DestroyMenu(hMenu);
+ }
+ }
+ break;
+ case IDC_HISTORY:
+ CallService(MS_HISTORY_SHOWCONTACTHISTORY, (WPARAM) dat->hContact, 0);
+ break;
+ case IDC_DETAILS:
+ CallService(MS_USERINFO_SHOWDIALOG, (WPARAM) dat->hContact, 0);
+ break;
+ case IDC_ADD:
+ {
+ ADDCONTACTSTRUCT acs = { 0 };
+
+ acs.handle = dat->hContact;
+ acs.handleType = HANDLE_CONTACT;
+ acs.szProto = 0;
+ CallService(MS_ADDCONTACT_SHOW, (WPARAM) hwndDlg, (LPARAM) & acs);
+ }
+ if (!DBGetContactSettingByte(dat->hContact, "CList", "NotOnList", 0)) {
+ ShowWindow(GetDlgItem(hwndDlg, IDC_ADD), FALSE);
+ }
+ break;
+ case IDC_MESSAGE:
+ if (HIWORD(wParam) == EN_CHANGE) {
+ int len = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE));
+ UpdateReadChars(hwndDlg, dat->hwndStatus);
+ EnableWindow(GetDlgItem(hwndDlg, IDOK), len != 0);
+ if (!(GetKeyState(VK_CONTROL) & 0x8000) && !(GetKeyState(VK_SHIFT) & 0x8000)) {
+ dat->nLastTyping = GetTickCount();
+ if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE))) {
+ if (dat->nTypeMode == PROTOTYPE_SELFTYPING_OFF) {
+ NotifyTyping(dat, PROTOTYPE_SELFTYPING_ON);
+ }
+ }
+ else {
+ if (dat->nTypeMode == PROTOTYPE_SELFTYPING_ON) {
+ NotifyTyping(dat, PROTOTYPE_SELFTYPING_OFF);
+ }
+ }
+ }
+ }
+ break;
+ }
+ break;
+ case WM_NOTIFY:
+ switch (((NMHDR *) lParam)->idFrom) {
+ case IDC_LOG:
+ switch (((NMHDR *) lParam)->code) {
+ case EN_MSGFILTER:
+ switch (((MSGFILTER *) lParam)->msg) {
+ case WM_LBUTTONDOWN:
+ {
+ HCURSOR hCur = GetCursor();
+ if (hCur == LoadCursor(NULL, IDC_SIZENS) || hCur == LoadCursor(NULL, IDC_SIZEWE)
+ || hCur == LoadCursor(NULL, IDC_SIZENESW) || hCur == LoadCursor(NULL, IDC_SIZENWSE)) {
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, TRUE);
+ return TRUE;
+ }
+ break;
+ }
+ case WM_MOUSEMOVE:
+ {
+ HCURSOR hCur = GetCursor();
+ if (hCur == LoadCursor(NULL, IDC_SIZENS) || hCur == LoadCursor(NULL, IDC_SIZEWE)
+ || hCur == LoadCursor(NULL, IDC_SIZENESW) || hCur == LoadCursor(NULL, IDC_SIZENWSE))
+ SetCursor(LoadCursor(NULL, IDC_ARROW));
+ break;
+ }
+ case WM_RBUTTONUP:
+ {
+ HMENU hMenu, hSubMenu;
+ POINT pt;
+ CHARRANGE sel, all = { 0, -1 };
+
+ hMenu = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_CONTEXT));
+ hSubMenu = GetSubMenu(hMenu, 0);
+ CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) hSubMenu, 0);
+ SendMessage(((NMHDR *) lParam)->hwndFrom, EM_EXGETSEL, 0, (LPARAM) & sel);
+ if (sel.cpMin == sel.cpMax)
+ EnableMenuItem(hSubMenu, IDM_COPY, MF_BYCOMMAND | MF_GRAYED);
+ pt.x = (short) LOWORD(((ENLINK *) lParam)->lParam);
+ pt.y = (short) HIWORD(((ENLINK *) lParam)->lParam);
+ ClientToScreen(((NMHDR *) lParam)->hwndFrom, &pt);
+ switch (TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL)) {
+ case IDM_COPY:
+ SendMessage(((NMHDR *) lParam)->hwndFrom, WM_COPY, 0, 0);
+ break;
+ case IDM_COPYALL:
+ SendMessage(((NMHDR *) lParam)->hwndFrom, EM_EXSETSEL, 0, (LPARAM) & all);
+ SendMessage(((NMHDR *) lParam)->hwndFrom, WM_COPY, 0, 0);
+ SendMessage(((NMHDR *) lParam)->hwndFrom, EM_EXSETSEL, 0, (LPARAM) & sel);
+ break;
+ case IDM_SELECTALL:
+ SendMessage(((NMHDR *) lParam)->hwndFrom, EM_EXSETSEL, 0, (LPARAM) & all);
+ break;
+ case IDM_CLEAR:
+ SetDlgItemText(hwndDlg, IDC_LOG, _T(""));
+ dat->hDbEventFirst = NULL;
+ break;
+ }
+ DestroyMenu(hMenu);
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, TRUE);
+ return TRUE;
+ }
+ }
+ break;
+ case EN_LINK:
+ switch (((ENLINK *) lParam)->msg) {
+ case WM_SETCURSOR:
+ SetCursor(hCurHyperlinkHand);
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, TRUE);
+ return TRUE;
+ case WM_RBUTTONDOWN:
+ case WM_LBUTTONUP:
+ {
+ TEXTRANGEA tr;
+ CHARRANGE sel;
+
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_EXGETSEL, 0, (LPARAM) & sel);
+ if (sel.cpMin != sel.cpMax)
+ break;
+ tr.chrg = ((ENLINK *) lParam)->chrg;
+ tr.lpstrText = malloc(tr.chrg.cpMax - tr.chrg.cpMin + 8);
+ SendDlgItemMessageA(hwndDlg, IDC_LOG, EM_GETTEXTRANGE, 0, (LPARAM) & tr);
+ if (strchr(tr.lpstrText, '@') != NULL && strchr(tr.lpstrText, ':') == NULL && strchr(tr.lpstrText, '/') == NULL) {
+ MoveMemory(tr.lpstrText + 7, tr.lpstrText, tr.chrg.cpMax - tr.chrg.cpMin + 1);
+ CopyMemory(tr.lpstrText, "mailto:", 7);
+ }
+ if (((ENLINK *) lParam)->msg == WM_RBUTTONDOWN) {
+ HMENU hMenu, hSubMenu;
+ POINT pt;
+
+ hMenu = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_CONTEXT));
+ hSubMenu = GetSubMenu(hMenu, 1);
+ CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) hSubMenu, 0);
+ pt.x = (short) LOWORD(((ENLINK *) lParam)->lParam);
+ pt.y = (short) HIWORD(((ENLINK *) lParam)->lParam);
+ ClientToScreen(((NMHDR *) lParam)->hwndFrom, &pt);
+ switch (TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL)) {
+ case IDM_OPENNEW:
+ CallService(MS_UTILS_OPENURL, 1, (LPARAM) tr.lpstrText);
+ break;
+ case IDM_OPENEXISTING:
+ CallService(MS_UTILS_OPENURL, 0, (LPARAM) tr.lpstrText);
+ break;
+ case IDM_COPYLINK:
+ {
+ HGLOBAL hData;
+ if (!OpenClipboard(hwndDlg))
+ break;
+ EmptyClipboard();
+ hData = GlobalAlloc(GMEM_MOVEABLE, lstrlenA(tr.lpstrText) + 1);
+ lstrcpyA(GlobalLock(hData), tr.lpstrText);
+ GlobalUnlock(hData);
+ SetClipboardData(CF_TEXT, hData);
+ CloseClipboard();
+ break;
+ }
+ }
+ free(tr.lpstrText);
+ DestroyMenu(hMenu);
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, TRUE);
+ return TRUE;
+ }
+ else {
+ CallService(MS_UTILS_OPENURL, 1, (LPARAM) tr.lpstrText);
+ SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+ }
+
+ free(tr.lpstrText);
+ break;
+ }
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ case HM_EVENTSENT:
+ {
+ ACKDATA *ack = (ACKDATA *) lParam;
+ DBEVENTINFO dbei = { 0 };
+ HANDLE hNewEvent;
+
+ if (ack->type != ACKTYPE_MESSAGE)
+ break;
+ if (dat->sendCount==0)
+ break;
+ switch (ack->result) {
+ case ACKRESULT_FAILED:
+ KillTimer(hwndDlg, TIMERID_MSGSEND);
+ ShowWindow(hwndDlg, SW_SHOWNORMAL);
+ EnableWindow(hwndDlg, FALSE);
+ CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_MSGSENDERROR), hwndDlg, ErrorDlgProc, (ack->lParam == 0) ? 0 : (LPARAM) strdup((char *) ack->lParam));
+ return 0;
+ }
+ if (dat->sendBuffer==NULL) return 0;
+ dbei.cbSize = sizeof(dbei);
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ dbei.flags = DBEF_SENT + (( dat->bIsRtl ) ? DBEF_RTL : 0 );
+
+ dbei.szModule = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) dat->hContact, 0);
+ dbei.timestamp = time(NULL);
+ dbei.cbBlob = lstrlenA(dat->sendBuffer) + 1;
+ #if defined( _UNICODE )
+ dbei.cbBlob *= sizeof(TCHAR) + 1;
+ #endif
+ dbei.pBlob = (PBYTE) dat->sendBuffer;
+ hNewEvent = (HANDLE) CallService(MS_DB_EVENT_ADD, (WPARAM) dat->hContact, (LPARAM) & dbei);
+ SkinPlaySound("SendMsg");
+ if (dat->hDbEventFirst == NULL) {
+ dat->hDbEventFirst = hNewEvent;
+ SendMessage(hwndDlg, DM_REMAKELOG, 0, 0);
+ }
+
+ dat->hSendId = NULL;
+ {
+ int len;
+ //all messages sent
+ dat->sendCount = 0;
+ KillTimer(hwndDlg, TIMERID_MSGSEND);
+ SetDlgItemText(hwndDlg, IDC_MESSAGE, _T(""));
+ EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
+ SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETREADONLY, FALSE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_REPLAYSAVEDKEYSTROKES, 0, 0);
+ if (GetForegroundWindow() == hwndDlg)
+ SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+ len = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE));
+ UpdateReadChars(hwndDlg, dat->hwndStatus);
+ EnableWindow(GetDlgItem(hwndDlg, IDOK), len != 0);
+ if (DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_AUTOCLOSE, SRMSGDEFSET_AUTOCLOSE))
+ DestroyWindow(hwndDlg);
+ }
+ break;
+ }
+ case WM_DESTROY:
+ NotifyLocalWinEvent(dat->hContact, hwndDlg, MSG_WINDOW_EVT_CLOSING);
+ if (dat->nTypeMode == PROTOTYPE_SELFTYPING_ON) {
+ NotifyTyping(dat, PROTOTYPE_SELFTYPING_OFF);
+ }
+ if (dat->hBkgBrush)
+ DeleteObject(dat->hBkgBrush);
+ if (dat->sendBuffer != NULL)
+ free(dat->sendBuffer);
+ if (dat->hwndStatus)
+ DestroyWindow(dat->hwndStatus);
+ tcmdlist_free(dat->cmdList);
+ WindowList_Remove(g_dat->hMessageWindowList, hwndDlg);
+ DBWriteContactSettingDword(DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SAVEPERCONTACT, SRMSGDEFSET_SAVEPERCONTACT)?dat->hContact:NULL, SRMMMOD, "splitterPos", dat->splitterPos);
+ SetWindowLong(GetDlgItem(hwndDlg, IDC_SPLITTER), GWL_WNDPROC, (LONG) OldSplitterProc);
+ SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_UNSUBCLASSED, 0, 0);
+ SetWindowLong(GetDlgItem(hwndDlg, IDC_MESSAGE), GWL_WNDPROC, (LONG) OldMessageEditProc);
+ {
+ HFONT hFont;
+ hFont = (HFONT) SendDlgItemMessage(hwndDlg, IDC_MESSAGE, WM_GETFONT, 0, 0);
+ if (hFont != NULL && hFont != (HFONT) SendDlgItemMessage(hwndDlg, IDOK, WM_GETFONT, 0, 0))
+ DeleteObject(hFont);
+ }
+ {
+ WINDOWPLACEMENT wp = { 0 };
+ HANDLE hContact;
+
+ if (DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SAVEPERCONTACT, SRMSGDEFSET_SAVEPERCONTACT))
+ hContact = dat->hContact;
+ else
+ hContact = NULL;
+ wp.length = sizeof(wp);
+ GetWindowPlacement(hwndDlg, &wp);
+ if (!dat->windowWasCascaded) {
+ DBWriteContactSettingDword(hContact, SRMMMOD, "x", wp.rcNormalPosition.left);
+ DBWriteContactSettingDword(hContact, SRMMMOD, "y", wp.rcNormalPosition.top);
+ }
+ DBWriteContactSettingDword(hContact, SRMMMOD, "width", wp.rcNormalPosition.right - wp.rcNormalPosition.left);
+ DBWriteContactSettingDword(hContact, SRMMMOD, "height", wp.rcNormalPosition.bottom - wp.rcNormalPosition.top);
+ }
+ if (dat->avatarPic)
+ DeleteObject(dat->avatarPic);
+ NotifyLocalWinEvent(dat->hContact, hwndDlg, MSG_WINDOW_EVT_CLOSE);
+ if (dat->hContact&&DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_DELTEMP, SRMSGDEFSET_DELTEMP)) {
+ if (DBGetContactSettingByte(dat->hContact, "CList", "NotOnList", 0)) {
+ CallService(MS_DB_CONTACT_DELETE, (WPARAM)dat->hContact, 0);
+ }
+ }
+ free(dat);
+ SetWindowLong(hwndDlg, GWL_USERDATA, 0);
+ break;
+ }
+ return FALSE;
+}
diff --git a/miranda-wine/plugins/srmm/msglog.c b/miranda-wine/plugins/srmm/msglog.c
new file mode 100644
index 0000000..a988868
--- /dev/null
+++ b/miranda-wine/plugins/srmm/msglog.c
@@ -0,0 +1,549 @@
+/*
+SRMM
+
+Copyright 2000-2005 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#pragma hdrstop
+#include <ctype.h>
+#include <malloc.h>
+#include <mbstring.h>
+
+extern HINSTANCE g_hInst;
+
+static int logPixelSY;
+#define LOGICON_MSG_IN 0
+#define LOGICON_MSG_OUT 1
+#define LOGICON_MSG_NOTICE 2
+static PBYTE pLogIconBmpBits[3];
+static int logIconBmpSize[ SIZEOF(pLogIconBmpBits) ];
+static HIMAGELIST g_hImageList;
+
+#define STREAMSTAGE_HEADER 0
+#define STREAMSTAGE_EVENTS 1
+#define STREAMSTAGE_TAIL 2
+#define STREAMSTAGE_STOP 3
+struct LogStreamData
+{
+ int stage;
+ HANDLE hContact;
+ HANDLE hDbEvent, hDbEventLast;
+ char *buffer;
+ int bufferOffset, bufferLen;
+ int eventsToInsert;
+ int isEmpty;
+ struct MessageWindowData *dlgDat;
+};
+
+static char szSep2[40], szSep2_RTL[50];
+
+static void AppendToBuffer(char **buffer, int *cbBufferEnd, int *cbBufferAlloced, const char *fmt, ...)
+{
+ va_list va;
+ int charsDone;
+
+ va_start(va, fmt);
+ for (;;) {
+ charsDone = mir_vsnprintf(*buffer + *cbBufferEnd, *cbBufferAlloced - *cbBufferEnd, fmt, va);
+ if (charsDone >= 0)
+ break;
+ *cbBufferAlloced += 1024;
+ *buffer = (char *) realloc(*buffer, *cbBufferAlloced);
+ }
+ va_end(va);
+ *cbBufferEnd += charsDone;
+}
+
+static int AppendToBufferWithRTF(char **buffer, int *cbBufferEnd, int *cbBufferAlloced, TCHAR* line)
+{
+ DWORD textCharsCount = 0;
+ char *d;
+
+ int lineLen = _tcslen(line) * 9 + 8;
+ if (*cbBufferEnd + lineLen > *cbBufferAlloced) {
+ cbBufferAlloced[0] += (lineLen + 1024 - lineLen % 1024);
+ *buffer = (char *) realloc(*buffer, *cbBufferAlloced);
+ }
+
+ d = *buffer + *cbBufferEnd;
+ strcpy(d, "{\\uc1 ");
+ d += 6;
+
+ for (; *line; line++, textCharsCount++) {
+ if (*line == '\r' && line[1] == '\n') {
+ CopyMemory(d, "\\par ", 5);
+ line++;
+ d += 5;
+ }
+ else if (*line == '\n') {
+ CopyMemory(d, "\\par ", 5);
+ d += 5;
+ }
+ else if (*line == '\t') {
+ CopyMemory(d, "\\tab ", 5);
+ d += 5;
+ }
+ else if (*line == '\\' || *line == '{' || *line == '}') {
+ *d++ = '\\';
+ *d++ = (char) *line;
+ }
+ else if (*line < 128) {
+ *d++ = (char) *line;
+ }
+ else d += sprintf(d, "\\u%d ?", *line);
+ }
+
+ strcpy(d, "}");
+ d++;
+
+ *cbBufferEnd = (int) (d - *buffer);
+ return textCharsCount;
+}
+
+#if defined( _UNICODE )
+ #define FONT_FORMAT "{\\f%u\\fnil\\fcharset%u %S;}"
+#else
+ #define FONT_FORMAT "{\\f%u\\fnil\\fcharset%u %s;}"
+#endif
+
+static char *CreateRTFHeader(struct MessageWindowData *dat)
+{
+ char *buffer;
+ int bufferAlloced, bufferEnd;
+ int i;
+ LOGFONT lf;
+ COLORREF colour;
+ HDC hdc;
+
+ hdc = GetDC(NULL);
+ logPixelSY = GetDeviceCaps(hdc, LOGPIXELSY);
+ ReleaseDC(NULL, hdc);
+ bufferEnd = 0;
+ bufferAlloced = 1024;
+ buffer = (char *) malloc(bufferAlloced);
+ buffer[0] = '\0';
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "{\\rtf1\\ansi\\deff0{\\fonttbl");
+
+ for (i = 0; i < msgDlgFontCount; i++) {
+ LoadMsgDlgFont(i, &lf, NULL);
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, FONT_FORMAT, i, lf.lfCharSet, lf.lfFaceName);
+ }
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "}{\\colortbl ");
+ for (i = 0; i < msgDlgFontCount; i++) {
+ LoadMsgDlgFont(i, NULL, &colour);
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(colour), GetGValue(colour), GetBValue(colour));
+ }
+ if (GetSysColorBrush(COLOR_HOTLIGHT) == NULL)
+ colour = RGB(0, 0, 255);
+ else
+ colour = GetSysColor(COLOR_HOTLIGHT);
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(colour), GetGValue(colour), GetBValue(colour));
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "}");
+ //AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "}\\pard");
+ return buffer;
+}
+
+//free() the return value
+static char *CreateRTFTail(struct MessageWindowData *dat)
+{
+ char *buffer;
+ int bufferAlloced, bufferEnd;
+
+ bufferEnd = 0;
+ bufferAlloced = 1024;
+ buffer = (char *) malloc(bufferAlloced);
+ buffer[0] = '\0';
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "}");
+ return buffer;
+}
+
+//return value is static
+static char *SetToStyle(int style)
+{
+ static char szStyle[128];
+ LOGFONT lf;
+
+ LoadMsgDlgFont(style, &lf, NULL);
+ wsprintfA(szStyle, "\\f%u\\cf%u\\b%d\\i%d\\fs%u", style, style, lf.lfWeight >= FW_BOLD ? 1 : 0, lf.lfItalic, 2 * abs(lf.lfHeight) * 74 / logPixelSY);
+ return szStyle;
+}
+
+int DbEventIsShown(DBEVENTINFO * dbei, struct MessageWindowData *dat)
+{
+ switch (dbei->eventType) {
+ case EVENTTYPE_MESSAGE:
+ return 1;
+ case EVENTTYPE_STATUSCHANGE:
+ if (dbei->flags & DBEF_READ)
+ return 0;
+ return 1;
+ }
+ return 0;
+}
+
+//free() the return value
+static char *CreateRTFFromDbEvent(struct MessageWindowData *dat, HANDLE hContact, HANDLE hDbEvent, struct LogStreamData *streamData)
+{
+ char *buffer;
+ int bufferAlloced, bufferEnd;
+ DBEVENTINFO dbei = { 0 };
+ int showColon = 0;
+
+ dbei.cbSize = sizeof(dbei);
+ dbei.cbBlob = CallService(MS_DB_EVENT_GETBLOBSIZE, (WPARAM) hDbEvent, 0);
+ if (dbei.cbBlob == -1)
+ return NULL;
+ dbei.pBlob = (PBYTE) malloc(dbei.cbBlob);
+ CallService(MS_DB_EVENT_GET, (WPARAM) hDbEvent, (LPARAM) & dbei);
+ if (!DbEventIsShown(&dbei, dat)) {
+ free(dbei.pBlob);
+ return NULL;
+ }
+ if (!(dbei.flags & DBEF_SENT) && dbei.eventType == EVENTTYPE_MESSAGE) {
+ CallService(MS_DB_EVENT_MARKREAD, (WPARAM) hContact, (LPARAM) hDbEvent);
+ CallService(MS_CLIST_REMOVEEVENT, (WPARAM) hContact, (LPARAM) hDbEvent);
+ }
+ else if (dbei.eventType == EVENTTYPE_STATUSCHANGE) {
+ CallService(MS_DB_EVENT_MARKREAD, (WPARAM) hContact, (LPARAM) hDbEvent);
+ }
+ bufferEnd = 0;
+ bufferAlloced = 1024;
+ buffer = (char *) malloc(bufferAlloced);
+ buffer[0] = '\0';
+
+ if (!dat->bIsAutoRTL && !streamData->isEmpty)
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\par");
+
+ if (dbei.flags & DBEF_RTL) {
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\rtlpar");
+ dat->bIsAutoRTL = TRUE;
+ }
+ else
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\ltrpar");
+
+ streamData->isEmpty = 0;
+
+ if (dat->bIsAutoRTL) {
+ if(dbei.flags & DBEF_RTL) {
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\ltrch\\rtlch");
+ }else{
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\rtlch\\ltrch");
+ }
+ }
+
+ if (g_dat->flags&SMF_SHOWICONS) {
+ int i;
+
+ switch (dbei.eventType) {
+ case EVENTTYPE_MESSAGE:
+ if (dbei.flags & DBEF_SENT) {
+ i = LOGICON_MSG_OUT;
+ }
+ else {
+ i = LOGICON_MSG_IN;
+ }
+ break;
+ case EVENTTYPE_STATUSCHANGE:
+ i = LOGICON_MSG_NOTICE;
+ break;
+ }
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\f0\\fs14");
+ while (bufferAlloced - bufferEnd < logIconBmpSize[i])
+ bufferAlloced += 1024;
+ buffer = (char *) realloc(buffer, bufferAlloced);
+ CopyMemory(buffer + bufferEnd, pLogIconBmpBits[i], logIconBmpSize[i]);
+ bufferEnd += logIconBmpSize[i];
+ }
+ if (g_dat->flags&SMF_SHOWTIME) {
+ DBTIMETOSTRINGT dbtts;
+ TCHAR str[64];
+
+ if (g_dat->flags&SMF_SHOWSECS)
+ dbtts.szFormat = g_dat->flags&SMF_SHOWDATE ? _T("d s") : _T("s");
+ else
+ dbtts.szFormat = g_dat->flags&SMF_SHOWDATE ? _T("d t") : _T("t");
+ dbtts.cbDest = SIZEOF(str);
+ dbtts.szDest = str;
+ CallService(MS_DB_TIME_TIMESTAMPTOSTRINGT, dbei.timestamp, (LPARAM)&dbtts);
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, " %s ", SetToStyle(dbei.flags & DBEF_SENT ? MSGFONTID_MYTIME : MSGFONTID_YOURTIME));
+ AppendToBufferWithRTF(&buffer, &bufferEnd, &bufferAlloced, str);
+ showColon = 1;
+ }
+ if (!(g_dat->flags&SMF_HIDENAMES) && dbei.eventType != EVENTTYPE_STATUSCHANGE) {
+ TCHAR* szName;
+ CONTACTINFO ci;
+ ZeroMemory(&ci, sizeof(ci));
+
+ if (dbei.flags & DBEF_SENT) {
+ ci.cbSize = sizeof(ci);
+ ci.hContact = NULL;
+ ci.szProto = dbei.szModule;
+ ci.dwFlag = CNF_DISPLAY;
+ #if defined( _UNICODE )
+ ci.dwFlag += CNF_UNICODE;
+ #endif
+ if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
+ // CNF_DISPLAY always returns a string type
+ szName = ( TCHAR* )ci.pszVal;
+ }
+ }
+ else szName = ( TCHAR* ) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) hContact, GCDNF_TCHAR);
+
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, " %s ", SetToStyle(dbei.flags & DBEF_SENT ? MSGFONTID_MYNAME : MSGFONTID_YOURNAME));
+ AppendToBufferWithRTF(&buffer, &bufferEnd, &bufferAlloced, szName);
+ showColon = 1;
+ if (ci.pszVal)
+ miranda_sys_free(ci.pszVal);
+ }
+
+ if (showColon)
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s :", SetToStyle(dbei.flags & DBEF_SENT ? MSGFONTID_MYCOLON : MSGFONTID_YOURCOLON));
+
+ switch (dbei.eventType) {
+ case EVENTTYPE_MESSAGE:
+ {
+ TCHAR* msg;
+
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, " %s ", SetToStyle(dbei.flags & DBEF_SENT ? MSGFONTID_MYMSG : MSGFONTID_YOURMSG));
+
+ #if defined( _UNICODE )
+ {
+ int msglen = strlen((char *) dbei.pBlob) + 1;
+ if (msglen != (int) dbei.cbBlob)
+ msg = (TCHAR *) & dbei.pBlob[msglen];
+ else {
+ msg = (TCHAR *) alloca(sizeof(TCHAR) * msglen);
+ MultiByteToWideChar(CP_ACP, 0, (char *) dbei.pBlob, -1, msg, msglen);
+ }
+ }
+ #else
+ msg = (BYTE *) dbei.pBlob;
+ #endif
+ AppendToBufferWithRTF(&buffer, &bufferEnd, &bufferAlloced, msg);
+ break;
+ }
+ case EVENTTYPE_STATUSCHANGE:
+ {
+ TCHAR *msg, *szName;
+ CONTACTINFO ci;
+ ZeroMemory(&ci, sizeof(ci));
+
+ if (dbei.flags & DBEF_SENT) {
+ ci.cbSize = sizeof(ci);
+ ci.hContact = NULL;
+ ci.szProto = dbei.szModule;
+ ci.dwFlag = CNF_DISPLAY;
+ #if defined( _UNICODE )
+ ci.dwFlag += CNF_UNICODE;
+ #endif
+ if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
+ // CNF_DISPLAY always returns a string type
+ szName = ( TCHAR* )ci.pszVal;
+ }
+ }
+ else szName = ( TCHAR* )CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) hContact, GCDNF_TCHAR);
+
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, " %s ", SetToStyle(MSGFONTID_NOTICE));
+ AppendToBufferWithRTF(&buffer, &bufferEnd, &bufferAlloced, szName);
+ AppendToBufferWithRTF(&buffer, &bufferEnd, &bufferAlloced, _T(" "));
+ #if defined( _UNICODE )
+ {
+ int msglen = strlen((char *) dbei.pBlob) + 1;
+ msg = ( TCHAR* )alloca(sizeof(TCHAR) * msglen);
+ MultiByteToWideChar(CP_ACP, 0, (char *) dbei.pBlob, -1, msg, msglen);
+ }
+ #else
+ msg = (BYTE *) dbei.pBlob;
+ #endif
+ AppendToBufferWithRTF(&buffer, &bufferEnd, &bufferAlloced, msg);
+ if (ci.pszVal)
+ miranda_sys_free(ci.pszVal);
+ break;
+ }
+ }
+ if(dat->bIsAutoRTL)
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\par");
+
+ dat->lastEventType = dbei.flags;
+ free(dbei.pBlob);
+ return buffer;
+}
+
+static DWORD CALLBACK LogStreamInEvents(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG * pcb)
+{
+ struct LogStreamData *dat = (struct LogStreamData *) dwCookie;
+
+ if (dat->buffer == NULL) {
+ dat->bufferOffset = 0;
+ switch (dat->stage) {
+ case STREAMSTAGE_HEADER:
+ dat->buffer = CreateRTFHeader(dat->dlgDat);
+ dat->stage = STREAMSTAGE_EVENTS;
+ break;
+ case STREAMSTAGE_EVENTS:
+ if (dat->eventsToInsert) {
+ do {
+ dat->buffer = CreateRTFFromDbEvent(dat->dlgDat, dat->hContact, dat->hDbEvent, dat);
+ if (dat->buffer)
+ dat->hDbEventLast = dat->hDbEvent;
+ dat->hDbEvent = (HANDLE) CallService(MS_DB_EVENT_FINDNEXT, (WPARAM) dat->hDbEvent, 0);
+ if (--dat->eventsToInsert == 0)
+ break;
+ } while (dat->buffer == NULL && dat->hDbEvent);
+ if (dat->buffer) {
+ dat->isEmpty = 0;
+ break;
+ }
+ }
+ dat->stage = STREAMSTAGE_TAIL;
+ //fall through
+ case STREAMSTAGE_TAIL:
+ dat->buffer = CreateRTFTail(dat->dlgDat);
+ dat->stage = STREAMSTAGE_STOP;
+ break;
+ case STREAMSTAGE_STOP:
+ *pcb = 0;
+ return 0;
+ }
+ dat->bufferLen = lstrlenA(dat->buffer);
+ }
+ *pcb = min(cb, dat->bufferLen - dat->bufferOffset);
+ CopyMemory(pbBuff, dat->buffer + dat->bufferOffset, *pcb);
+ dat->bufferOffset += *pcb;
+ if (dat->bufferOffset == dat->bufferLen) {
+ free(dat->buffer);
+ dat->buffer = NULL;
+ }
+ return 0;
+}
+
+void StreamInEvents(HWND hwndDlg, HANDLE hDbEventFirst, int count, int fAppend)
+{
+ EDITSTREAM stream = { 0 };
+ struct LogStreamData streamData = { 0 };
+ struct MessageWindowData *dat = (struct MessageWindowData *) GetWindowLong(hwndDlg, GWL_USERDATA);
+ CHARRANGE oldSel, sel;
+
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_HIDESELECTION, TRUE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_EXGETSEL, 0, (LPARAM) & oldSel);
+ streamData.hContact = dat->hContact;
+ streamData.hDbEvent = hDbEventFirst;
+ streamData.dlgDat = dat;
+ streamData.eventsToInsert = count;
+ streamData.isEmpty = fAppend ? GetWindowTextLength(GetDlgItem(hwndDlg, IDC_LOG)) == 0 : 1;
+ stream.pfnCallback = LogStreamInEvents;
+ stream.dwCookie = (DWORD_PTR) & streamData;
+ if (fAppend) {
+ sel.cpMin = sel.cpMax = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_LOG));
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_EXSETSEL, 0, (LPARAM) & sel);
+ }
+ else dat->bIsFirstAppend = TRUE;
+
+ strcpy(szSep2, fAppend ? "\\par\\sl0" : "\\sl1000");
+ strcpy(szSep2_RTL, fAppend ? "\\rtlpar\\rtlmark\\par\\sl1000" : "\\sl1000");
+
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_STREAMIN, fAppend ? SFF_SELECTION | SF_RTF : SFF_SELECTION | SF_RTF, (LPARAM) & stream);
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_EXSETSEL, 0, (LPARAM) & oldSel);
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_HIDESELECTION, FALSE, 0);
+ dat->hDbEventLast = streamData.hDbEventLast;
+ if (GetWindowLong(GetDlgItem(hwndDlg, IDC_LOG), GWL_STYLE) & WS_VSCROLL)
+ PostMessage(hwndDlg, DM_SCROLLLOGTOBOTTOM, 0, 0);
+}
+
+#define RTFPICTHEADERMAXSIZE 78
+void LoadMsgLogIcons(void)
+{
+ HICON hIcon;
+ HBITMAP hBmp, hoBmp;
+ HDC hdc, hdcMem;
+ BITMAPINFOHEADER bih = { 0 };
+ int widthBytes, i;
+ RECT rc;
+ HBRUSH hBkgBrush;
+ int rtfHeaderSize;
+ PBYTE pBmpBits;
+
+ g_hImageList = ImageList_Create(10, 10, IsWinVerXPPlus()? ILC_COLOR32 | ILC_MASK : ILC_COLOR8 | ILC_MASK, SIZEOF(pLogIconBmpBits), 0);
+ hBkgBrush = CreateSolidBrush(DBGetContactSettingDword(NULL, SRMMMOD, SRMSGSET_BKGCOLOUR, SRMSGDEFSET_BKGCOLOUR));
+ bih.biSize = sizeof(bih);
+ bih.biBitCount = 24;
+ bih.biCompression = BI_RGB;
+ bih.biHeight = 10;
+ bih.biPlanes = 1;
+ bih.biWidth = 10;
+ widthBytes = ((bih.biWidth * bih.biBitCount + 31) >> 5) * 4;
+ rc.top = rc.left = 0;
+ rc.right = bih.biWidth;
+ rc.bottom = bih.biHeight;
+ hdc = GetDC(NULL);
+ hBmp = CreateCompatibleBitmap(hdc, bih.biWidth, bih.biHeight);
+ hdcMem = CreateCompatibleDC(hdc);
+ pBmpBits = (PBYTE) malloc(widthBytes * bih.biHeight);
+ for (i = 0; i < SIZEOF(pLogIconBmpBits); i++) {
+ switch (i) {
+ case LOGICON_MSG_IN:
+ hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_INCOMING));
+ ImageList_AddIcon(g_hImageList, hIcon);
+ hIcon = ImageList_GetIcon(g_hImageList, LOGICON_MSG_IN, ILD_NORMAL);
+ break;
+ case LOGICON_MSG_OUT:
+ hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_OUTGOING));
+ ImageList_AddIcon(g_hImageList, hIcon);
+ hIcon = ImageList_GetIcon(g_hImageList, LOGICON_MSG_OUT, ILD_NORMAL);
+ break;
+ case LOGICON_MSG_NOTICE:
+ hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_NOTICE));
+ ImageList_AddIcon(g_hImageList, hIcon);
+ hIcon = ImageList_GetIcon(g_hImageList, LOGICON_MSG_NOTICE, ILD_NORMAL);
+ break;
+ }
+ pLogIconBmpBits[i] = (PBYTE) malloc(RTFPICTHEADERMAXSIZE + (bih.biSize + widthBytes * bih.biHeight) * 2);
+ //I can't seem to get binary mode working. No matter.
+ rtfHeaderSize = sprintf(pLogIconBmpBits[i], "{\\pict\\dibitmap0\\wbmbitspixel%u\\wbmplanes1\\wbmwidthbytes%u\\picw%u\\pich%u ", bih.biBitCount, widthBytes, bih.biWidth, bih.biHeight);
+ hoBmp = (HBITMAP) SelectObject(hdcMem, hBmp);
+ FillRect(hdcMem, &rc, hBkgBrush);
+ DrawIconEx(hdcMem, 0, 0, hIcon, bih.biWidth, bih.biHeight, 0, NULL, DI_NORMAL);
+ SelectObject(hdcMem, hoBmp);
+ GetDIBits(hdc, hBmp, 0, bih.biHeight, pBmpBits, (BITMAPINFO *) & bih, DIB_RGB_COLORS);
+ DestroyIcon(hIcon);
+ {
+ int n;
+ for (n = 0; n < sizeof(BITMAPINFOHEADER); n++)
+ sprintf(pLogIconBmpBits[i] + rtfHeaderSize + n * 2, "%02X", ((PBYTE) & bih)[n]);
+ for (n = 0; n < widthBytes * bih.biHeight; n += 4)
+ sprintf(pLogIconBmpBits[i] + rtfHeaderSize + (bih.biSize + n) * 2, "%02X%02X%02X%02X", pBmpBits[n], pBmpBits[n + 1], pBmpBits[n + 2], pBmpBits[n + 3]);
+ }
+ logIconBmpSize[i] = rtfHeaderSize + (bih.biSize + widthBytes * bih.biHeight) * 2 + 1;
+ pLogIconBmpBits[i][logIconBmpSize[i] - 1] = '}';
+ }
+ free(pBmpBits);
+ DeleteDC(hdcMem);
+ DeleteObject(hBmp);
+ ReleaseDC(NULL, hdc);
+ DeleteObject(hBkgBrush);
+}
+
+void FreeMsgLogIcons(void)
+{
+ int i;
+ for (i = 0; i < SIZEOF(pLogIconBmpBits); i++)
+ free(pLogIconBmpBits[i]);
+ ImageList_RemoveAll(g_hImageList);
+ ImageList_Destroy(g_hImageList);
+}
diff --git a/miranda-wine/plugins/srmm/msgoptions.c b/miranda-wine/plugins/srmm/msgoptions.c
new file mode 100644
index 0000000..4bb89e7
--- /dev/null
+++ b/miranda-wine/plugins/srmm/msgoptions.c
@@ -0,0 +1,723 @@
+/*
+SRMM
+
+Copyright 2000-2005 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#pragma hdrstop
+
+extern HINSTANCE g_hInst;
+
+#define FONTF_BOLD 1
+#define FONTF_ITALIC 2
+struct FontOptionsList
+{
+ TCHAR* szDescr;
+ COLORREF defColour;
+ TCHAR* szDefFace;
+ BYTE defCharset, defStyle;
+ char defSize;
+ COLORREF colour;
+ TCHAR szFace[LF_FACESIZE];
+ BYTE charset, style;
+ char size;
+}
+static fontOptionsList[] = {
+ {_T("Outgoing messages"), RGB(106, 106, 106), _T("Arial"), DEFAULT_CHARSET, 0, -12},
+ {_T("Incoming messages"), RGB(0, 0, 0), _T("Arial"), DEFAULT_CHARSET, 0, -12},
+ {_T("Outgoing name"), RGB(89, 89, 89), _T("Arial"), DEFAULT_CHARSET, FONTF_BOLD, -12},
+ {_T("Outgoing time"), RGB(0, 0, 0), _T("Terminal"), DEFAULT_CHARSET, FONTF_BOLD, -9},
+ {_T("Outgoing colon"), RGB(89, 89, 89), _T("Arial"), DEFAULT_CHARSET, 0, -11},
+ {_T("Incoming name"), RGB(215, 0, 0), _T("Arial"), DEFAULT_CHARSET, FONTF_BOLD, -12},
+ {_T("Incoming time"), RGB(0, 0, 0), _T("Terminal"), DEFAULT_CHARSET, FONTF_BOLD, -9},
+ {_T("Incoming colon"), RGB(215, 0, 0), _T("Arial"), DEFAULT_CHARSET, 0, -11},
+ {_T("Message area"), RGB(0, 0, 0), _T("Arial"), DEFAULT_CHARSET, 0, -12},
+ {_T("Notices"), RGB(90, 90, 160), _T("Arial"), DEFAULT_CHARSET, 0, -12},
+};
+const int msgDlgFontCount = SIZEOF(fontOptionsList);
+
+void LoadMsgDlgFont(int i, LOGFONT* lf, COLORREF * colour)
+{
+ char str[32];
+ int style;
+ DBVARIANT dbv;
+
+ if (colour) {
+ wsprintfA(str, "SRMFont%dCol", i);
+ *colour = DBGetContactSettingDword(NULL, SRMMMOD, str, fontOptionsList[i].defColour);
+ }
+ if (lf) {
+ wsprintfA(str, "SRMFont%dSize", i);
+ lf->lfHeight = (char) DBGetContactSettingByte(NULL, SRMMMOD, str, fontOptionsList[i].defSize);
+ lf->lfWidth = 0;
+ lf->lfEscapement = 0;
+ lf->lfOrientation = 0;
+ wsprintfA(str, "SRMFont%dSty", i);
+ style = DBGetContactSettingByte(NULL, SRMMMOD, str, fontOptionsList[i].defStyle);
+ lf->lfWeight = style & FONTF_BOLD ? FW_BOLD : FW_NORMAL;
+ lf->lfItalic = style & FONTF_ITALIC ? 1 : 0;
+ lf->lfUnderline = 0;
+ lf->lfStrikeOut = 0;
+ wsprintfA(str, "SRMFont%dSet", i);
+ lf->lfCharSet = DBGetContactSettingByte(NULL, SRMMMOD, str, fontOptionsList[i].defCharset);
+ lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
+ lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf->lfQuality = DEFAULT_QUALITY;
+ lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ wsprintfA(str, "SRMFont%d", i);
+ if (DBGetContactSettingTString(NULL, SRMMMOD, str, &dbv))
+ lstrcpy(lf->lfFaceName, fontOptionsList[i].szDefFace);
+ else {
+ lstrcpyn(lf->lfFaceName, dbv.ptszVal, SIZEOF(lf->lfFaceName));
+ DBFreeVariant(&dbv);
+ }
+ }
+}
+struct CheckBoxValues_t
+{
+ DWORD style;
+ TCHAR* szDescr;
+}
+static const statusValues[] =
+{
+ { PF2_ONLINE, _T("Online") },
+ { PF2_SHORTAWAY, _T("Away") },
+ { PF2_LONGAWAY, _T("NA") },
+ { PF2_LIGHTDND, _T("Occupied") },
+ { PF2_HEAVYDND, _T("DND") },
+ { PF2_FREECHAT, _T("Free for chat") },
+ { PF2_INVISIBLE, _T("Invisible") },
+ { PF2_OUTTOLUNCH, _T("Out to lunch") },
+ { PF2_ONTHEPHONE, _T("On the phone") }
+};
+
+static void FillCheckBoxTree(HWND hwndTree, const struct CheckBoxValues_t *values, int nValues, DWORD style)
+{
+ TVINSERTSTRUCT tvis;
+ int i;
+
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_LAST;
+ tvis.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_STATE;
+ for (i = 0; i < nValues; i++) {
+ tvis.item.lParam = values[i].style;
+ tvis.item.pszText = TranslateTS(values[i].szDescr);
+ tvis.item.stateMask = TVIS_STATEIMAGEMASK;
+ tvis.item.state = INDEXTOSTATEIMAGEMASK((style & tvis.item.lParam) != 0 ? 2 : 1);
+ TreeView_InsertItem( hwndTree, &tvis );
+} }
+
+static DWORD MakeCheckBoxTreeFlags(HWND hwndTree)
+{
+ DWORD flags = 0;
+ TVITEM tvi;
+
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE;
+ tvi.hItem = TreeView_GetRoot(hwndTree);
+ while (tvi.hItem) {
+ TreeView_GetItem(hwndTree, &tvi);
+ if (((tvi.state & TVIS_STATEIMAGEMASK) >> 12 == 2))
+ flags |= tvi.lParam;
+ tvi.hItem = TreeView_GetNextSibling(hwndTree, tvi.hItem);
+ }
+ return flags;
+}
+
+static BOOL CALLBACK DlgProcOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ DWORD msgTimeout, avatarHeight;
+
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLong(GetDlgItem(hwndDlg, IDC_POPLIST), GWL_STYLE, GetWindowLong(GetDlgItem(hwndDlg, IDC_POPLIST), GWL_STYLE) | TVS_NOHSCROLL | TVS_CHECKBOXES);
+ FillCheckBoxTree(GetDlgItem(hwndDlg, IDC_POPLIST), statusValues, SIZEOF(statusValues),
+ DBGetContactSettingDword(NULL, SRMMMOD, SRMSGSET_POPFLAGS, SRMSGDEFSET_POPFLAGS));
+ CheckDlgButton(hwndDlg, IDC_SHOWBUTTONLINE, g_dat->flags&SMF_SHOWBTNS);
+ CheckDlgButton(hwndDlg, IDC_SHOWINFOLINE, g_dat->flags&SMF_SHOWINFO);
+ CheckDlgButton(hwndDlg, IDC_AUTOMIN, DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_AUTOMIN, SRMSGDEFSET_AUTOMIN));
+ CheckDlgButton(hwndDlg, IDC_AUTOCLOSE, DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_AUTOCLOSE, SRMSGDEFSET_AUTOCLOSE));
+ CheckDlgButton(hwndDlg, IDC_SAVEPERCONTACT, DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SAVEPERCONTACT, SRMSGDEFSET_SAVEPERCONTACT));
+ CheckDlgButton(hwndDlg, IDC_CASCADE, DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_CASCADE, SRMSGDEFSET_CASCADE));
+ CheckDlgButton(hwndDlg, IDC_SENDONENTER, DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SENDONENTER, SRMSGDEFSET_SENDONENTER));
+ CheckDlgButton(hwndDlg, IDC_SENDONDBLENTER, DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SENDONDBLENTER, SRMSGDEFSET_SENDONDBLENTER));
+ CheckDlgButton(hwndDlg, IDC_STATUSWIN, DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_STATUSICON, SRMSGDEFSET_STATUSICON));
+
+ CheckDlgButton(hwndDlg, IDC_AVATARSUPPORT, g_dat->flags&SMF_AVATAR);
+ CheckDlgButton(hwndDlg, IDC_LIMITAVATARH, DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_LIMITAVHEIGHT, SRMSGDEFSET_LIMITAVHEIGHT));
+ avatarHeight = DBGetContactSettingDword(NULL, SRMMMOD, SRMSGSET_AVHEIGHT, SRMSGDEFSET_AVHEIGHT);
+ SetDlgItemInt(hwndDlg, IDC_AVATARHEIGHT, avatarHeight, FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_LIMITAVATARH), IsDlgButtonChecked(hwndDlg, IDC_AVATARSUPPORT));
+ if (!IsDlgButtonChecked(hwndDlg, IDC_AVATARSUPPORT))
+ EnableWindow(GetDlgItem(hwndDlg, IDC_AVATARHEIGHT), FALSE);
+ else EnableWindow(GetDlgItem(hwndDlg, IDC_AVATARHEIGHT), IsDlgButtonChecked(hwndDlg, IDC_LIMITAVATARH));
+ CheckDlgButton(hwndDlg, IDC_SHOWSENDBTN, g_dat->flags&SMF_SENDBTN);
+ CheckDlgButton(hwndDlg, IDC_CHARCOUNT, DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_CHARCOUNT, SRMSGDEFSET_CHARCOUNT));
+ CheckDlgButton(hwndDlg, IDC_CTRLSUPPORT, DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_CTRLSUPPORT, SRMSGDEFSET_CTRLSUPPORT));
+ CheckDlgButton(hwndDlg, IDC_DELTEMP, DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_DELTEMP, SRMSGDEFSET_DELTEMP));
+ msgTimeout = DBGetContactSettingDword(NULL, SRMMMOD, SRMSGSET_MSGTIMEOUT, SRMSGDEFSET_MSGTIMEOUT);
+ SetDlgItemInt(hwndDlg, IDC_SECONDS, msgTimeout >= SRMSGSET_MSGTIMEOUT_MIN ? msgTimeout / 1000 : SRMSGDEFSET_MSGTIMEOUT / 1000, FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CASCADE), !IsDlgButtonChecked(hwndDlg, IDC_SAVEPERCONTACT));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CTRLSUPPORT), !IsDlgButtonChecked(hwndDlg, IDC_AUTOCLOSE));
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_AUTOMIN:
+ CheckDlgButton(hwndDlg, IDC_AUTOCLOSE, BST_UNCHECKED);
+ break;
+ case IDC_AUTOCLOSE:
+ CheckDlgButton(hwndDlg, IDC_AUTOMIN, BST_UNCHECKED);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CTRLSUPPORT), !IsDlgButtonChecked(hwndDlg, IDC_AUTOCLOSE));
+ break;
+ case IDC_SENDONENTER:
+ CheckDlgButton(hwndDlg, IDC_SENDONDBLENTER, BST_UNCHECKED);
+ break;
+ case IDC_SENDONDBLENTER:
+ CheckDlgButton(hwndDlg, IDC_SENDONENTER, BST_UNCHECKED);
+ break;
+ case IDC_SAVEPERCONTACT:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CASCADE), !IsDlgButtonChecked(hwndDlg, IDC_SAVEPERCONTACT));
+ break;
+ case IDC_SECONDS:
+ if (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus())
+ return 0;
+ break;
+ case IDC_AVATARSUPPORT:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_LIMITAVATARH), IsDlgButtonChecked(hwndDlg, IDC_AVATARSUPPORT));
+ if (!IsDlgButtonChecked(hwndDlg, IDC_AVATARSUPPORT))
+ EnableWindow(GetDlgItem(hwndDlg, IDC_AVATARHEIGHT), FALSE);
+ else EnableWindow(GetDlgItem(hwndDlg, IDC_AVATARHEIGHT), IsDlgButtonChecked(hwndDlg, IDC_LIMITAVATARH));
+ break;
+ case IDC_LIMITAVATARH:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_AVATARHEIGHT), IsDlgButtonChecked(hwndDlg, IDC_LIMITAVATARH));
+ break;
+ case IDC_AVATARHEIGHT:
+ if (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus())
+ return 0;
+ break;
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch (((LPNMHDR) lParam)->idFrom) {
+ case IDC_POPLIST:
+ if (((LPNMHDR) lParam)->code == NM_CLICK) {
+ TVHITTESTINFO hti;
+ hti.pt.x = (short) LOWORD(GetMessagePos());
+ hti.pt.y = (short) HIWORD(GetMessagePos());
+ ScreenToClient(((LPNMHDR) lParam)->hwndFrom, &hti.pt);
+ if (TreeView_HitTest(((LPNMHDR) lParam)->hwndFrom, &hti))
+ if (hti.flags & TVHT_ONITEMSTATEICON) {
+ TVITEM tvi;
+ tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ tvi.hItem = hti.hItem;
+ TreeView_GetItem(((LPNMHDR) lParam)->hwndFrom, &tvi);
+ tvi.iImage = tvi.iSelectedImage = tvi.iImage == 1 ? 2 : 1;
+ TreeView_SetItem(((LPNMHDR) lParam)->hwndFrom, &tvi);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ }
+ break;
+ case 0:
+ switch (((LPNMHDR) lParam)->code) {
+ case PSN_APPLY:
+ {
+ DWORD msgTimeout, avatarHeight;
+
+ DBWriteContactSettingDword(NULL, SRMMMOD, SRMSGSET_POPFLAGS, MakeCheckBoxTreeFlags(GetDlgItem(hwndDlg, IDC_POPLIST)));
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWBUTTONLINE, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SHOWBUTTONLINE));
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWINFOLINE, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SHOWINFOLINE));
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_AUTOMIN, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_AUTOMIN));
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_AUTOCLOSE, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_AUTOCLOSE));
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_SAVEPERCONTACT, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SAVEPERCONTACT));
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_CASCADE, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_CASCADE));
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_SENDONENTER, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SENDONENTER));
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_SENDONDBLENTER, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SENDONDBLENTER));
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_STATUSICON, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_STATUSWIN));
+
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_AVATARENABLE, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_AVATARSUPPORT));
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_LIMITAVHEIGHT, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_LIMITAVATARH));
+ avatarHeight = GetDlgItemInt(hwndDlg, IDC_AVATARHEIGHT, NULL, TRUE);
+ DBWriteContactSettingDword(NULL, SRMMMOD, SRMSGSET_AVHEIGHT, avatarHeight<=0?SRMSGDEFSET_AVHEIGHT:avatarHeight);
+
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_SENDBUTTON, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SHOWSENDBTN));
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_CHARCOUNT, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_CHARCOUNT));
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_CTRLSUPPORT, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_CTRLSUPPORT));
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_DELTEMP, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_DELTEMP));
+ msgTimeout = GetDlgItemInt(hwndDlg, IDC_SECONDS, NULL, TRUE) >= SRMSGSET_MSGTIMEOUT_MIN / 1000 ? GetDlgItemInt(hwndDlg, IDC_SECONDS, NULL, TRUE) * 1000 : SRMSGDEFSET_MSGTIMEOUT;
+ DBWriteContactSettingDword(NULL, SRMMMOD, SRMSGSET_MSGTIMEOUT, msgTimeout);
+ ReloadGlobals();
+ WindowList_Broadcast(g_dat->hMessageWindowList, DM_OPTIONSAPPLIED, 0, 0);
+ return TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ break;
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK DlgProcLogOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static HBRUSH hBkgColourBrush;
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ switch (DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_LOADHISTORY, SRMSGDEFSET_LOADHISTORY)) {
+ case LOADHISTORY_UNREAD:
+ CheckDlgButton(hwndDlg, IDC_LOADUNREAD, BST_CHECKED);
+ break;
+ case LOADHISTORY_COUNT:
+ CheckDlgButton(hwndDlg, IDC_LOADCOUNT, BST_CHECKED);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_LOADCOUNTN), TRUE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_LOADCOUNTSPIN), TRUE);
+ break;
+ case LOADHISTORY_TIME:
+ CheckDlgButton(hwndDlg, IDC_LOADTIME, BST_CHECKED);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_LOADTIMEN), TRUE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_LOADTIMESPIN), TRUE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_STMINSOLD), TRUE);
+ break;
+ }
+ SendDlgItemMessage(hwndDlg, IDC_LOADCOUNTSPIN, UDM_SETRANGE, 0, MAKELONG(100, 0));
+ SendDlgItemMessage(hwndDlg, IDC_LOADCOUNTSPIN, UDM_SETPOS, 0, DBGetContactSettingWord(NULL, SRMMMOD, SRMSGSET_LOADCOUNT, SRMSGDEFSET_LOADCOUNT));
+ SendDlgItemMessage(hwndDlg, IDC_LOADTIMESPIN, UDM_SETRANGE, 0, MAKELONG(12 * 60, 0));
+ SendDlgItemMessage(hwndDlg, IDC_LOADTIMESPIN, UDM_SETPOS, 0, DBGetContactSettingWord(NULL, SRMMMOD, SRMSGSET_LOADTIME, SRMSGDEFSET_LOADTIME));
+
+ CheckDlgButton(hwndDlg, IDC_SHOWLOGICONS, DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWLOGICONS, SRMSGDEFSET_SHOWLOGICONS));
+ CheckDlgButton(hwndDlg, IDC_SHOWNAMES, !DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_HIDENAMES, SRMSGDEFSET_HIDENAMES));
+ CheckDlgButton(hwndDlg, IDC_SHOWTIMES, DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWTIME, SRMSGDEFSET_SHOWTIME));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SHOWSECS), IsDlgButtonChecked(hwndDlg, IDC_SHOWTIMES));
+ CheckDlgButton(hwndDlg, IDC_SHOWSECS, DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWSECS, SRMSGDEFSET_SHOWSECS));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SHOWDATES), IsDlgButtonChecked(hwndDlg, IDC_SHOWTIMES));
+ CheckDlgButton(hwndDlg, IDC_SHOWDATES, DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWDATE, SRMSGDEFSET_SHOWDATE));
+ CheckDlgButton(hwndDlg, IDC_SHOWSTATUSCHANGES, DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWSTATUSCH, SRMSGDEFSET_SHOWSTATUSCH));
+ SendDlgItemMessage(hwndDlg, IDC_BKGCOLOUR, CPM_SETCOLOUR, 0, DBGetContactSettingDword(NULL, SRMMMOD, SRMSGSET_BKGCOLOUR, SRMSGDEFSET_BKGCOLOUR));
+ SendDlgItemMessage(hwndDlg, IDC_BKGCOLOUR, CPM_SETDEFAULTCOLOUR, 0, SRMSGDEFSET_BKGCOLOUR);
+
+ hBkgColourBrush = CreateSolidBrush(SendDlgItemMessage(hwndDlg, IDC_BKGCOLOUR, CPM_GETCOLOUR, 0, 0));
+
+ { int i;
+ LOGFONT lf;
+ for (i = 0; i < SIZEOF(fontOptionsList); i++) {
+ LoadMsgDlgFont(i, &lf, &fontOptionsList[i].colour);
+ lstrcpy(fontOptionsList[i].szFace, lf.lfFaceName);
+ fontOptionsList[i].size = (char) lf.lfHeight;
+ fontOptionsList[i].style = (lf.lfWeight >= FW_BOLD ? FONTF_BOLD : 0) | (lf.lfItalic ? FONTF_ITALIC : 0);
+ fontOptionsList[i].charset = lf.lfCharSet;
+ //I *think* some OSs will fail LB_ADDSTRING if lParam==0
+ SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_ADDSTRING, 0, i + 1);
+ }
+ SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_SETSEL, TRUE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_FONTCOLOUR, CPM_SETCOLOUR, 0, fontOptionsList[0].colour);
+ SendDlgItemMessage(hwndDlg, IDC_FONTCOLOUR, CPM_SETDEFAULTCOLOUR, 0, fontOptionsList[0].defColour);
+ }
+ return TRUE;
+ case WM_CTLCOLORLISTBOX:
+ SetBkColor((HDC) wParam, SendDlgItemMessage(hwndDlg, IDC_BKGCOLOUR, CPM_GETCOLOUR, 0, 0));
+ return (BOOL) hBkgColourBrush;
+ case WM_MEASUREITEM:
+ {
+ MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *) lParam;
+ HFONT hFont, hoFont;
+ HDC hdc;
+ SIZE fontSize;
+ int iItem = mis->itemData - 1;
+ hFont = CreateFont(fontOptionsList[iItem].size, 0, 0, 0,
+ fontOptionsList[iItem].style & FONTF_BOLD ? FW_BOLD : FW_NORMAL,
+ fontOptionsList[iItem].style & FONTF_ITALIC ? 1 : 0, 0, 0, fontOptionsList[iItem].charset, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fontOptionsList[iItem].szFace);
+ hdc = GetDC(GetDlgItem(hwndDlg, mis->CtlID));
+ hoFont = (HFONT) SelectObject(hdc, hFont);
+ GetTextExtentPoint32(hdc, fontOptionsList[iItem].szDescr, lstrlen(fontOptionsList[iItem].szDescr), &fontSize);
+ SelectObject(hdc, hoFont);
+ ReleaseDC(GetDlgItem(hwndDlg, mis->CtlID), hdc);
+ DeleteObject(hFont);
+ mis->itemWidth = fontSize.cx;
+ mis->itemHeight = fontSize.cy;
+ return TRUE;
+ }
+ case WM_DRAWITEM:
+ {
+ DRAWITEMSTRUCT* dis = (DRAWITEMSTRUCT *) lParam;
+ HFONT hFont, hoFont;
+ TCHAR* pszText;
+ int iItem = dis->itemData - 1;
+ hFont = CreateFont(fontOptionsList[iItem].size, 0, 0, 0,
+ fontOptionsList[iItem].style & FONTF_BOLD ? FW_BOLD : FW_NORMAL,
+ fontOptionsList[iItem].style & FONTF_ITALIC ? 1 : 0, 0, 0, fontOptionsList[iItem].charset, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fontOptionsList[iItem].szFace);
+ hoFont = (HFONT) SelectObject(dis->hDC, hFont);
+ SetBkMode(dis->hDC, TRANSPARENT);
+ FillRect(dis->hDC, &dis->rcItem, hBkgColourBrush);
+ if (dis->itemState & ODS_SELECTED)
+ FrameRect(dis->hDC, &dis->rcItem, GetSysColorBrush(COLOR_HIGHLIGHT));
+ SetTextColor(dis->hDC, fontOptionsList[iItem].colour);
+ pszText = TranslateTS(fontOptionsList[iItem].szDescr);
+ TextOut(dis->hDC, dis->rcItem.left, dis->rcItem.top, pszText, lstrlen(pszText));
+ SelectObject(dis->hDC, hoFont);
+ DeleteObject(hFont);
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_LOADUNREAD:
+ case IDC_LOADCOUNT:
+ case IDC_LOADTIME:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_LOADCOUNTN), IsDlgButtonChecked(hwndDlg, IDC_LOADCOUNT));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_LOADCOUNTSPIN), IsDlgButtonChecked(hwndDlg, IDC_LOADCOUNT));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_LOADTIMEN), IsDlgButtonChecked(hwndDlg, IDC_LOADTIME));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_LOADTIMESPIN), IsDlgButtonChecked(hwndDlg, IDC_LOADTIME));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_STMINSOLD), IsDlgButtonChecked(hwndDlg, IDC_LOADTIME));
+ break;
+ case IDC_SHOWTIMES:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SHOWSECS), IsDlgButtonChecked(hwndDlg, IDC_SHOWTIMES));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SHOWDATES), IsDlgButtonChecked(hwndDlg, IDC_SHOWTIMES));
+ break;
+ case IDC_BKGCOLOUR:
+ DeleteObject(hBkgColourBrush);
+ hBkgColourBrush = CreateSolidBrush(SendDlgItemMessage(hwndDlg, IDC_BKGCOLOUR, CPM_GETCOLOUR, 0, 0));
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_FONTLIST), NULL, TRUE);
+ break;
+ case IDC_FONTLIST:
+ if (HIWORD(wParam) == LBN_SELCHANGE) {
+ if (SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETSELCOUNT, 0, 0) > 1) {
+ SendDlgItemMessage(hwndDlg, IDC_FONTCOLOUR, CPM_SETCOLOUR, 0, GetSysColor(COLOR_3DFACE));
+ SendDlgItemMessage(hwndDlg, IDC_FONTCOLOUR, CPM_SETDEFAULTCOLOUR, 0, GetSysColor(COLOR_WINDOWTEXT));
+ }
+ else {
+ int i = SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETITEMDATA,
+ SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETCURSEL, 0, 0), 0) - 1;
+ SendDlgItemMessage(hwndDlg, IDC_FONTCOLOUR, CPM_SETCOLOUR, 0, fontOptionsList[i].colour);
+ SendDlgItemMessage(hwndDlg, IDC_FONTCOLOUR, CPM_SETDEFAULTCOLOUR, 0, fontOptionsList[i].defColour);
+ }
+ }
+ if (HIWORD(wParam) != LBN_DBLCLK)
+ return TRUE;
+ //fall through
+ case IDC_CHOOSEFONT:
+ {
+ CHOOSEFONT cf = { 0 };
+ LOGFONT lf = { 0 };
+ int i = SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETITEMDATA, SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETCURSEL, 0, 0),
+ 0) - 1;
+ lf.lfHeight = fontOptionsList[i].size;
+ lf.lfWeight = fontOptionsList[i].style & FONTF_BOLD ? FW_BOLD : FW_NORMAL;
+ lf.lfItalic = fontOptionsList[i].style & FONTF_ITALIC ? 1 : 0;
+ lf.lfCharSet = fontOptionsList[i].charset;
+ lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
+ lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf.lfQuality = DEFAULT_QUALITY;
+ lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ lstrcpy(lf.lfFaceName, fontOptionsList[i].szFace);
+ cf.lStructSize = sizeof(cf);
+ cf.hwndOwner = hwndDlg;
+ cf.lpLogFont = &lf;
+ cf.Flags = CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
+ if (ChooseFont(&cf)) {
+ int selItems[ SIZEOF(fontOptionsList) ];
+ int sel, selCount;
+
+ selCount = SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETSELITEMS, SIZEOF(fontOptionsList), (LPARAM) selItems);
+ for (sel = 0; sel < selCount; sel++) {
+ i = SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETITEMDATA, selItems[sel], 0) - 1;
+ fontOptionsList[i].size = (char) lf.lfHeight;
+ fontOptionsList[i].style = (lf.lfWeight >= FW_BOLD ? FONTF_BOLD : 0) | (lf.lfItalic ? FONTF_ITALIC : 0);
+ fontOptionsList[i].charset = lf.lfCharSet;
+ lstrcpy(fontOptionsList[i].szFace, lf.lfFaceName);
+ {
+ MEASUREITEMSTRUCT mis = { 0 };
+ mis.CtlID = IDC_FONTLIST;
+ mis.itemData = i + 1;
+ SendMessage(hwndDlg, WM_MEASUREITEM, 0, (LPARAM) & mis);
+ SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_SETITEMHEIGHT, selItems[sel], mis.itemHeight);
+ }
+ }
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_FONTLIST), NULL, TRUE);
+ break;
+ }
+ return TRUE;
+ }
+ case IDC_FONTCOLOUR:
+ {
+ int selItems[ SIZEOF(fontOptionsList) ];
+ int sel, selCount, i;
+
+ selCount = SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETSELITEMS, SIZEOF(fontOptionsList), (LPARAM) selItems);
+ for (sel = 0; sel < selCount; sel++) {
+ i = SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETITEMDATA, selItems[sel], 0) - 1;
+ fontOptionsList[i].colour = SendDlgItemMessage(hwndDlg, IDC_FONTCOLOUR, CPM_GETCOLOUR, 0, 0);
+ }
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_FONTLIST), NULL, FALSE);
+ break;
+ }
+ case IDC_LOADCOUNTN:
+ case IDC_LOADTIMEN:
+ if (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus())
+ return TRUE;
+ break;
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch (((LPNMHDR) lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR) lParam)->code) {
+ case PSN_APPLY:
+ if (IsDlgButtonChecked(hwndDlg, IDC_LOADCOUNT))
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_LOADHISTORY, LOADHISTORY_COUNT);
+ else if (IsDlgButtonChecked(hwndDlg, IDC_LOADTIME))
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_LOADHISTORY, LOADHISTORY_TIME);
+ else
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_LOADHISTORY, LOADHISTORY_UNREAD);
+ DBWriteContactSettingWord(NULL, SRMMMOD, SRMSGSET_LOADCOUNT, (WORD) SendDlgItemMessage(hwndDlg, IDC_LOADCOUNTSPIN, UDM_GETPOS, 0, 0));
+ DBWriteContactSettingWord(NULL, SRMMMOD, SRMSGSET_LOADTIME, (WORD) SendDlgItemMessage(hwndDlg, IDC_LOADTIMESPIN, UDM_GETPOS, 0, 0));
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWLOGICONS, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SHOWLOGICONS));
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_HIDENAMES, (BYTE) ! IsDlgButtonChecked(hwndDlg, IDC_SHOWNAMES));
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWTIME, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SHOWTIMES));
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWSECS, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SHOWSECS));
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWDATE, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SHOWDATES));
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWSTATUSCH, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SHOWSTATUSCHANGES));
+ DBWriteContactSettingDword(NULL, SRMMMOD, SRMSGSET_BKGCOLOUR, SendDlgItemMessage(hwndDlg, IDC_BKGCOLOUR, CPM_GETCOLOUR, 0, 0));
+
+ {
+ int i;
+ char str[32];
+ for (i = 0; i < SIZEOF(fontOptionsList); i++) {
+ wsprintfA(str, "SRMFont%d", i);
+ DBWriteContactSettingTString(NULL, SRMMMOD, str, fontOptionsList[i].szFace);
+ wsprintfA(str, "SRMFont%dSize", i);
+ DBWriteContactSettingByte(NULL, SRMMMOD, str, fontOptionsList[i].size);
+ wsprintfA(str, "SRMFont%dSty", i);
+ DBWriteContactSettingByte(NULL, SRMMMOD, str, fontOptionsList[i].style);
+ wsprintfA(str, "SRMFont%dSet", i);
+ DBWriteContactSettingByte(NULL, SRMMMOD, str, fontOptionsList[i].charset);
+ wsprintfA(str, "SRMFont%dCol", i);
+ DBWriteContactSettingDword(NULL, SRMMMOD, str, fontOptionsList[i].colour);
+ }
+ }
+
+ FreeMsgLogIcons();
+ LoadMsgLogIcons();
+ ReloadGlobals();
+ WindowList_Broadcast(g_dat->hMessageWindowList, DM_OPTIONSAPPLIED, 0, 0);
+ return TRUE;
+ }
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ DeleteObject(hBkgColourBrush);
+ break;
+ }
+ return FALSE;
+}
+
+static ResetCList(HWND hwndDlg)
+{
+ int i;
+
+ if (CallService(MS_CLUI_GETCAPS, 0, 0) & CLUIF_DISABLEGROUPS && !DBGetContactSettingByte(NULL, "CList", "UseGroups", SETTING_USEGROUPS_DEFAULT))
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETUSEGROUPS, (WPARAM) FALSE, 0);
+ else
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETUSEGROUPS, (WPARAM) TRUE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETHIDEEMPTYGROUPS, 1, 0);
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETGREYOUTFLAGS, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETLEFTMARGIN, 2, 0);
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETBKBITMAP, 0, (LPARAM) (HBITMAP) NULL);
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETBKCOLOR, GetSysColor(COLOR_WINDOW), 0);
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETINDENT, 10, 0);
+ for (i = 0; i <= FONTID_MAX; i++)
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETTEXTCOLOR, i, GetSysColor(COLOR_WINDOWTEXT));
+}
+
+static void RebuildList(HWND hwndDlg, HANDLE hItemNew, HANDLE hItemUnknown)
+{
+ HANDLE hContact, hItem;
+ BYTE defType = DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_TYPINGNEW, SRMSGDEFSET_TYPINGNEW);
+
+ if (hItemNew && defType) {
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETCHECKMARK, (WPARAM) hItemNew, 1);
+ }
+ if (hItemUnknown && DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_TYPINGUNKNOWN, SRMSGDEFSET_TYPINGUNKNOWN)) {
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETCHECKMARK, (WPARAM) hItemUnknown, 1);
+ }
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ do {
+ hItem = (HANDLE) SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_FINDCONTACT, (WPARAM) hContact, 0);
+ if (hItem && DBGetContactSettingByte(hContact, SRMMMOD, SRMSGSET_TYPING, defType)) {
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETCHECKMARK, (WPARAM) hItem, 1);
+ }
+ } while (hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0));
+}
+
+static void SaveList(HWND hwndDlg, HANDLE hItemNew, HANDLE hItemUnknown)
+{
+ HANDLE hContact, hItem;
+
+ if (hItemNew) {
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_TYPINGNEW, (BYTE) (SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_GETCHECKMARK, (WPARAM) hItemNew, 0) ? 1 : 0));
+ }
+ if (hItemUnknown) {
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_TYPINGUNKNOWN, (BYTE) (SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_GETCHECKMARK, (WPARAM) hItemUnknown, 0) ? 1 : 0));
+ }
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ do {
+ hItem = (HANDLE) SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_FINDCONTACT, (WPARAM) hContact, 0);
+ if (hItem) {
+ DBWriteContactSettingByte(hContact, SRMMMOD, SRMSGSET_TYPING, (BYTE) (SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_GETCHECKMARK, (WPARAM) hItem, 0) ? 1 : 0));
+ }
+ } while (hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0));
+}
+
+static BOOL CALLBACK DlgProcTypeOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static HANDLE hItemNew, hItemUnknown;
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ {
+ CLCINFOITEM cii = { 0 };
+ cii.cbSize = sizeof(cii);
+ cii.flags = CLCIIF_GROUPFONT | CLCIIF_CHECKBOX;
+ cii.pszText = TranslateT("** New contacts **");
+ hItemNew = (HANDLE) SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_ADDINFOITEM, 0, (LPARAM) & cii);
+ cii.pszText = TranslateT("** Unknown contacts **");
+ hItemUnknown = (HANDLE) SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_ADDINFOITEM, 0, (LPARAM) & cii);
+ }
+ SetWindowLong(GetDlgItem(hwndDlg, IDC_CLIST), GWL_STYLE, GetWindowLong(GetDlgItem(hwndDlg, IDC_CLIST), GWL_STYLE) | (CLS_SHOWHIDDEN) | (CLS_NOHIDEOFFLINE));
+ ResetCList(hwndDlg);
+ RebuildList(hwndDlg, hItemNew, hItemUnknown);
+ CheckDlgButton(hwndDlg, IDC_SHOWNOTIFY, DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWTYPING, SRMSGDEFSET_SHOWTYPING));
+ CheckDlgButton(hwndDlg, IDC_TYPEWIN, DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWTYPINGWIN, SRMSGDEFSET_SHOWTYPINGWIN));
+ CheckDlgButton(hwndDlg, IDC_TYPETRAY, DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWTYPINGNOWIN, SRMSGDEFSET_SHOWTYPINGNOWIN));
+ CheckDlgButton(hwndDlg, IDC_NOTIFYTRAY, DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWTYPINGCLIST, SRMSGDEFSET_SHOWTYPINGCLIST));
+ CheckDlgButton(hwndDlg, IDC_NOTIFYBALLOON, !DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWTYPINGCLIST, SRMSGDEFSET_SHOWTYPINGCLIST));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_TYPEWIN), IsDlgButtonChecked(hwndDlg, IDC_SHOWNOTIFY));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_TYPETRAY), IsDlgButtonChecked(hwndDlg, IDC_SHOWNOTIFY));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_NOTIFYTRAY), IsDlgButtonChecked(hwndDlg, IDC_TYPETRAY));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_NOTIFYBALLOON), IsDlgButtonChecked(hwndDlg, IDC_TYPETRAY));
+ if (!ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_NOTIFYBALLOON), FALSE);
+ CheckDlgButton(hwndDlg, IDC_NOTIFYTRAY, BST_CHECKED);
+ SetWindowTextA(GetDlgItem(hwndDlg, IDC_NOTIFYBALLOON), Translate("Show balloon popup (unsupported system)"));
+ }
+ break;
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_TYPETRAY:
+ if (IsDlgButtonChecked(hwndDlg, IDC_TYPETRAY)) {
+ if (!ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_NOTIFYTRAY), TRUE);
+ }
+ else {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_NOTIFYTRAY), TRUE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_NOTIFYBALLOON), TRUE);
+ }
+ }
+ else {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_NOTIFYTRAY), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_NOTIFYBALLOON), FALSE);
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case IDC_SHOWNOTIFY:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_TYPEWIN), IsDlgButtonChecked(hwndDlg, IDC_SHOWNOTIFY));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_TYPETRAY), IsDlgButtonChecked(hwndDlg, IDC_SHOWNOTIFY));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_NOTIFYTRAY), IsDlgButtonChecked(hwndDlg, IDC_SHOWNOTIFY));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_NOTIFYBALLOON), IsDlgButtonChecked(hwndDlg, IDC_SHOWNOTIFY)
+ && ServiceExists(MS_CLIST_SYSTRAY_NOTIFY));
+ //fall-thru
+ case IDC_TYPEWIN:
+ case IDC_NOTIFYTRAY:
+ case IDC_NOTIFYBALLOON:
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ break;
+ case WM_NOTIFY:
+ switch (((NMHDR *) lParam)->idFrom) {
+ case IDC_CLIST:
+ switch (((NMHDR *) lParam)->code) {
+ case CLN_OPTIONSCHANGED:
+ ResetCList(hwndDlg);
+ break;
+ case CLN_CHECKCHANGED:
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ break;
+ case 0:
+ switch (((LPNMHDR) lParam)->code) {
+ case PSN_APPLY:
+ {
+ SaveList(hwndDlg, hItemNew, hItemUnknown);
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWTYPING, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SHOWNOTIFY));
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWTYPINGWIN, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_TYPEWIN));
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWTYPINGNOWIN, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_TYPETRAY));
+ DBWriteContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWTYPINGCLIST, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_NOTIFYTRAY));
+ ReloadGlobals();
+ WindowList_Broadcast(g_dat->hMessageWindowList, DM_OPTIONSAPPLIED, 0, 0);
+ }
+ }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static int OptInitialise(WPARAM wParam, LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+
+ odp.cbSize = sizeof(odp);
+ odp.position = 910000000;
+ odp.hInstance = g_hInst;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_MSGDLG);
+ odp.pszTitle = "Messaging";
+ odp.pszGroup = "Events";
+ odp.pfnDlgProc = DlgProcOptions;
+ odp.flags = ODPF_BOLDGROUPS;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) & odp);
+
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_MSGLOG);
+ odp.pszTitle = "Messaging Log";
+ odp.pfnDlgProc = DlgProcLogOptions;
+ odp.nIDBottomSimpleControl = IDC_STMSGLOGGROUP;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) & odp);
+
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_MSGTYPE);
+ odp.pszTitle = "Typing Notify";
+ odp.pfnDlgProc = DlgProcTypeOptions;
+ odp.nIDBottomSimpleControl = 0;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) & odp);
+ return 0;
+}
+
+int InitOptions(void)
+{
+ HookEvent(ME_OPT_INITIALISE, OptInitialise);
+ return 0;
+}
diff --git a/miranda-wine/plugins/srmm/msgs.c b/miranda-wine/plugins/srmm/msgs.c
new file mode 100644
index 0000000..a8ac9ff
--- /dev/null
+++ b/miranda-wine/plugins/srmm/msgs.c
@@ -0,0 +1,587 @@
+/*
+SRMM
+
+Copyright 2000-2005 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#pragma hdrstop
+
+static void InitREOleCallback(void);
+
+HCURSOR hCurSplitNS, hCurSplitWE, hCurHyperlinkHand;
+static HANDLE hEventDbEventAdded, hEventDbSettingChange, hEventContactDeleted;
+HANDLE *hMsgMenuItem = NULL, hHookWinEvt=NULL;
+int hMsgMenuItemCount = 0;
+
+extern HINSTANCE g_hInst;
+
+static int SRMMStatusToPf2(int status)
+{
+ switch (status) {
+ case ID_STATUS_ONLINE:
+ return PF2_ONLINE;
+ case ID_STATUS_AWAY:
+ return PF2_SHORTAWAY;
+ case ID_STATUS_DND:
+ return PF2_HEAVYDND;
+ case ID_STATUS_NA:
+ return PF2_LONGAWAY;
+ case ID_STATUS_OCCUPIED:
+ return PF2_LIGHTDND;
+ case ID_STATUS_FREECHAT:
+ return PF2_FREECHAT;
+ case ID_STATUS_INVISIBLE:
+ return PF2_INVISIBLE;
+ case ID_STATUS_ONTHEPHONE:
+ return PF2_ONTHEPHONE;
+ case ID_STATUS_OUTTOLUNCH:
+ return PF2_OUTTOLUNCH;
+ case ID_STATUS_OFFLINE:
+ return MODEF_OFFLINE;
+ }
+ return 0;
+}
+
+static int ReadMessageCommand(WPARAM wParam, LPARAM lParam)
+{
+ struct NewMessageWindowLParam newData = { 0 };
+ HWND hwndExisting;
+
+ hwndExisting = WindowList_Find(g_dat->hMessageWindowList, ((CLISTEVENT *) lParam)->hContact);
+ newData.hContact = ((CLISTEVENT *) lParam)->hContact;
+ CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_MSG), NULL, DlgProcMessage, (LPARAM) & newData);
+ return 0;
+}
+
+static int MessageEventAdded(WPARAM wParam, LPARAM lParam)
+{
+ CLISTEVENT cle;
+ DBEVENTINFO dbei;
+ HWND hwnd;
+
+ ZeroMemory(&dbei, sizeof(dbei));
+ dbei.cbSize = sizeof(dbei);
+ dbei.cbBlob = 0;
+ CallService(MS_DB_EVENT_GET, lParam, (LPARAM) & dbei);
+
+ if (dbei.flags & DBEF_SENT || dbei.eventType != EVENTTYPE_MESSAGE || dbei.flags & DBEF_READ)
+ return 0;
+
+ CallServiceSync(MS_CLIST_REMOVEEVENT, wParam, (LPARAM) 1);
+ /* does a window for the contact exist? */
+ hwnd = WindowList_Find(g_dat->hMessageWindowList, (HANDLE) wParam);
+ if (hwnd) {
+ if (GetForegroundWindow()==hwnd)
+ SkinPlaySound("RecvMsgActive");
+ else SkinPlaySound("RecvMsgInactive");
+ return 0;
+ }
+ /* new message */
+ SkinPlaySound("AlertMsg");
+ {
+ char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) wParam, 0);
+ if (szProto && (g_dat->openFlags & SRMMStatusToPf2(CallProtoService(szProto, PS_GETSTATUS, 0, 0)))) {
+ struct NewMessageWindowLParam newData = { 0 };
+ newData.hContact = (HANDLE) wParam;
+ CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_MSG), NULL, DlgProcMessage, (LPARAM) & newData);
+ return 0;
+ }
+ }
+ {
+ TCHAR toolTip[256], *contactName;
+ ZeroMemory(&cle, sizeof(cle));
+ cle.cbSize = sizeof(cle);
+ cle.hContact = (HANDLE) wParam;
+ cle.hDbEvent = (HANDLE) lParam;
+ cle.flags = CLEF_TCHAR;
+ cle.hIcon = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE);
+ cle.pszService = "SRMsg/ReadMessage";
+ contactName = (TCHAR*) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, wParam, GCDNF_TCHAR);
+ mir_sntprintf(toolTip, SIZEOF(toolTip), TranslateT("Message from %s"), contactName);
+ cle.ptszTooltip = toolTip;
+ CallService(MS_CLIST_ADDEVENT, 0, (LPARAM) & cle);
+ }
+ return 0;
+}
+
+#if defined(_UNICODE)
+static int SendMessageCommand_W(WPARAM wParam, LPARAM lParam)
+{
+ HWND hwnd;
+ struct NewMessageWindowLParam newData = { 0 };
+
+ {
+ /* does the HCONTACT's protocol support IM messages? */
+ char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (szProto) {
+ if (!CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_IMSEND)
+ return 1;
+ }
+ else {
+ /* unknown contact */
+ return 1;
+ } //if
+ }
+
+ if (hwnd = WindowList_Find(g_dat->hMessageWindowList, (HANDLE) wParam)) {
+ if (lParam) {
+ HWND hEdit;
+ hEdit = GetDlgItem(hwnd, IDC_MESSAGE);
+ SendMessage(hEdit, EM_SETSEL, -1, SendMessage(hEdit, WM_GETTEXTLENGTH, 0, 0));
+ SendMessage(hEdit, EM_REPLACESEL, FALSE, (LPARAM) (char *) lParam);
+ }
+ ShowWindow(hwnd, SW_SHOWNORMAL);
+ SetForegroundWindow(hwnd);
+ SetFocus(hwnd);
+ }
+ else {
+ newData.hContact = (HANDLE) wParam;
+ newData.szInitialText = (const char *) lParam;
+ newData.isWchar = 1;
+ CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_MSG), NULL, DlgProcMessage, (LPARAM) & newData);
+ }
+ return 0;
+}
+#endif
+
+static int SendMessageCommand(WPARAM wParam, LPARAM lParam)
+{
+ HWND hwnd;
+ struct NewMessageWindowLParam newData = { 0 };
+
+ {
+ /* does the HCONTACT's protocol support IM messages? */
+ char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (szProto) {
+ if (!CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_IMSEND)
+ return 1;
+ }
+ else {
+ /* unknown contact */
+ return 1;
+ } //if
+ }
+
+ if (hwnd = WindowList_Find(g_dat->hMessageWindowList, (HANDLE) wParam)) {
+ if (lParam) {
+ HWND hEdit;
+ hEdit = GetDlgItem(hwnd, IDC_MESSAGE);
+ SendMessage(hEdit, EM_SETSEL, -1, SendMessage(hEdit, WM_GETTEXTLENGTH, 0, 0));
+ SendMessageA(hEdit, EM_REPLACESEL, FALSE, (LPARAM) (char *) lParam);
+ }
+ ShowWindow(hwnd, SW_SHOWNORMAL);
+ SetForegroundWindow(hwnd);
+ SetFocus(hwnd);
+ }
+ else {
+ newData.hContact = (HANDLE) wParam;
+ newData.szInitialText = (const char *) lParam;
+ newData.isWchar = 0;
+ CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_MSG), NULL, DlgProcMessage, (LPARAM) & newData);
+ }
+ return 0;
+}
+
+static int TypingMessageCommand(WPARAM wParam, LPARAM lParam)
+{
+ CLISTEVENT *cle = (CLISTEVENT *) lParam;
+
+ if (!cle)
+ return 0;
+ SendMessageCommand((WPARAM) cle->hContact, 0);
+ return 0;
+}
+
+static int TypingMessage(WPARAM wParam, LPARAM lParam)
+{
+ HWND hwnd;
+ int foundWin = 0;
+
+ if (!(g_dat->flags&SMF_SHOWTYPING))
+ return 0;
+ if (hwnd = WindowList_Find(g_dat->hMessageWindowList, (HANDLE) wParam)) {
+ SendMessage(hwnd, DM_TYPING, 0, lParam);
+ foundWin = 1;
+ }
+ if ((int) lParam && !foundWin && (g_dat->flags&SMF_SHOWTYPINGTRAY)) {
+ char szTip[256];
+ mir_snprintf(szTip, SIZEOF(szTip), Translate("%s is typing a message"), (char *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, wParam, 0));
+
+ if (ServiceExists(MS_CLIST_SYSTRAY_NOTIFY) && !(g_dat->flags&SMF_SHOWTYPINGCLIST)) {
+ MIRANDASYSTRAYNOTIFY tn;
+ tn.szProto = NULL;
+ tn.cbSize = sizeof(tn);
+ tn.szInfoTitle = Translate("Typing Notification");
+ tn.szInfo = szTip;
+ tn.dwInfoFlags = NIIF_INFO;
+ tn.uTimeout = 1000 * 4;
+ CallService(MS_CLIST_SYSTRAY_NOTIFY, 0, (LPARAM) & tn);
+ }
+ else {
+ CLISTEVENT cle;
+
+ ZeroMemory(&cle, sizeof(cle));
+ cle.cbSize = sizeof(cle);
+ cle.hContact = (HANDLE) wParam;
+ cle.hDbEvent = (HANDLE) 1;
+ cle.flags = CLEF_ONLYAFEW;
+ cle.hIcon = g_dat->hIcons[SMF_ICON_TYPING];
+ cle.pszService = "SRMsg/TypingMessage";
+ cle.pszTooltip = szTip;
+ CallServiceSync(MS_CLIST_REMOVEEVENT, wParam, (LPARAM) 1);
+ CallServiceSync(MS_CLIST_ADDEVENT, wParam, (LPARAM) & cle);
+ }
+ }
+ return 0;
+}
+
+static int MessageSettingChanged(WPARAM wParam, LPARAM lParam)
+{
+ DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *) lParam;
+ char *szProto;
+
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (lstrcmpA(cws->szModule, "CList") && (szProto == NULL || lstrcmpA(cws->szModule, szProto)))
+ return 0;
+ WindowList_Broadcast(g_dat->hMessageWindowList, DM_UPDATETITLE, (WPARAM) cws, 0);
+ return 0;
+}
+
+static int ContactDeleted(WPARAM wParam, LPARAM lParam)
+{
+ HWND hwnd;
+
+ if (hwnd = WindowList_Find(g_dat->hMessageWindowList, (HANDLE) wParam)) {
+ SendMessage(hwnd, WM_CLOSE, 0, 0);
+ }
+ return 0;
+}
+
+static void RestoreUnreadMessageAlerts(void)
+{
+ CLISTEVENT cle = { 0 };
+ DBEVENTINFO dbei = { 0 };
+ char toolTip[256];
+ int windowAlreadyExists;
+ HANDLE hDbEvent, hContact;
+ int autoPopup;
+
+ dbei.cbSize = sizeof(dbei);
+ cle.cbSize = sizeof(cle);
+ cle.hIcon = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE);
+ cle.pszService = "SRMsg/ReadMessage";
+
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact) {
+ hDbEvent = (HANDLE) CallService(MS_DB_EVENT_FINDFIRSTUNREAD, (WPARAM) hContact, 0);
+ while (hDbEvent) {
+ autoPopup = 0;
+ dbei.cbBlob = 0;
+ CallService(MS_DB_EVENT_GET, (WPARAM) hDbEvent, (LPARAM) & dbei);
+ if (!(dbei.flags & (DBEF_SENT | DBEF_READ)) && dbei.eventType == EVENTTYPE_MESSAGE) {
+ windowAlreadyExists = WindowList_Find(g_dat->hMessageWindowList, hContact) != NULL;
+ if (windowAlreadyExists)
+ continue;
+ {
+ char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ if (szProto && (g_dat->openFlags & SRMMStatusToPf2(CallProtoService(szProto, PS_GETSTATUS, 0, 0)))) {
+ autoPopup = 1;
+ }
+ }
+ if (autoPopup && !windowAlreadyExists) {
+ struct NewMessageWindowLParam newData = { 0 };
+ newData.hContact = hContact;
+ CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_MSG), NULL, DlgProcMessage, (LPARAM) & newData);
+ }
+ else {
+ cle.hContact = hContact;
+ cle.hDbEvent = hDbEvent;
+ mir_snprintf(toolTip, SIZEOF(toolTip), Translate("Message from %s"), (char *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) hContact, 0));
+ cle.pszTooltip = toolTip;
+ CallService(MS_CLIST_ADDEVENT, 0, (LPARAM) & cle);
+ }
+ }
+ hDbEvent = (HANDLE) CallService(MS_DB_EVENT_FINDNEXT, (WPARAM) hDbEvent, 0);
+ }
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ }
+}
+
+static int SplitmsgModulesLoaded(WPARAM wParam, LPARAM lParam)
+{
+ CLISTMENUITEM mi;
+ PROTOCOLDESCRIPTOR **protocol;
+ int protoCount, i;
+
+ LoadMsgLogIcons();
+ ZeroMemory(&mi, sizeof(mi));
+ mi.cbSize = sizeof(mi);
+ mi.position = -2000090000;
+ mi.flags = 0;
+ mi.hIcon = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE);
+ mi.pszName = Translate("&Message");
+ mi.pszService = MS_MSG_SENDMESSAGE;
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM) & protoCount, (LPARAM) & protocol);
+ for (i = 0; i < protoCount; i++) {
+ if (protocol[i]->type != PROTOTYPE_PROTOCOL)
+ continue;
+ if (CallProtoService(protocol[i]->szName, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_IMSEND) {
+ mi.pszContactOwner = protocol[i]->szName;
+ hMsgMenuItem = realloc(hMsgMenuItem, (hMsgMenuItemCount + 1) * sizeof(HANDLE));
+ hMsgMenuItem[hMsgMenuItemCount++] = (HANDLE) CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM) & mi);
+ }
+ }
+ HookEvent(ME_CLIST_DOUBLECLICKED, SendMessageCommand);
+ RestoreUnreadMessageAlerts();
+ return 0;
+}
+
+int PreshutdownSendRecv(WPARAM wParam, LPARAM lParam)
+{
+ WindowList_BroadcastAsync(g_dat->hMessageWindowList, WM_CLOSE, 0, 0);
+ return 0;
+}
+
+int SplitmsgShutdown(void)
+{
+ DestroyCursor(hCurSplitNS);
+ DestroyCursor(hCurHyperlinkHand);
+ DestroyCursor(hCurSplitWE);
+ UnhookEvent(hEventDbEventAdded);
+ UnhookEvent(hEventDbSettingChange);
+ UnhookEvent(hEventContactDeleted);
+ FreeMsgLogIcons();
+ FreeLibrary(GetModuleHandleA("riched20"));
+ OleUninitialize();
+ if (hMsgMenuItem) {
+ free(hMsgMenuItem);
+ hMsgMenuItem = NULL;
+ hMsgMenuItemCount = 0;
+ }
+ RichUtil_Unload();
+ FreeGlobals();
+ return 0;
+}
+
+static int IconsChanged(WPARAM wParam, LPARAM lParam)
+{
+ if (hMsgMenuItem) {
+ int j;
+ CLISTMENUITEM mi;
+
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIM_ICON;
+ mi.hIcon = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE);
+
+ for (j = 0; j < hMsgMenuItemCount; j++) {
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) hMsgMenuItem[j], (LPARAM) & mi);
+ }
+ }
+ FreeMsgLogIcons();
+ LoadMsgLogIcons();
+ WindowList_Broadcast(g_dat->hMessageWindowList, DM_REMAKELOG, 0, 0);
+ // change all the icons
+ WindowList_Broadcast(g_dat->hMessageWindowList, DM_UPDATEWINICON, 0, 0);
+ return 0;
+}
+
+static int GetWindowAPI(WPARAM wParam, LPARAM lParam)
+{
+ return PLUGIN_MAKE_VERSION(0,0,0,3);
+}
+
+static int GetWindowClass(WPARAM wParam, LPARAM lParam)
+{
+ char *szBuf = (char*)wParam;
+ int size = (int)lParam;
+ mir_snprintf(szBuf, size, SRMMMOD);
+ return 0;
+}
+
+static int GetWindowData(WPARAM wParam, LPARAM lParam)
+{
+ MessageWindowInputData *mwid = (MessageWindowInputData*)wParam;
+ MessageWindowData *mwd = (MessageWindowData*)lParam;
+ HWND hwnd;
+
+ if (mwid==NULL||mwd==NULL) return 1;
+ if (mwid->cbSize!=sizeof(MessageWindowInputData)||mwd->cbSize!=sizeof(MessageWindowData)) return 1;
+ if (mwid->hContact==NULL) return 1;
+ if (mwid->uFlags!=MSG_WINDOW_UFLAG_MSG_BOTH) return 1;
+ hwnd = WindowList_Find(g_dat->hMessageWindowList, mwid->hContact);
+ mwd->uFlags = MSG_WINDOW_UFLAG_MSG_BOTH;
+ mwd->hwndWindow = hwnd;
+ mwd->local = 0;
+ mwd->uState = SendMessage(hwnd, DM_GETWINDOWSTATE, 0, 0);
+ return 0;
+}
+
+int LoadSendRecvMessageModule(void)
+{
+ if (LoadLibraryA("riched20.dll") == NULL) {
+ if (IDYES !=
+ MessageBoxA(0,
+ Translate
+ ("Miranda could not load the built-in message module, riched20.dll is missing. If you are using Windows 95 or WINE please make sure you have riched20.dll installed. Press 'Yes' to continue loading Miranda."),
+ Translate("Information"), MB_YESNO | MB_ICONINFORMATION))
+ return 1;
+ return 0;
+ }
+ InitGlobals();
+ RichUtil_Load();
+ OleInitialize(NULL);
+ InitREOleCallback();
+ InitOptions();
+ hEventDbEventAdded = HookEvent(ME_DB_EVENT_ADDED, MessageEventAdded);
+ hEventDbSettingChange = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, MessageSettingChanged);
+ hEventContactDeleted = HookEvent(ME_DB_CONTACT_DELETED, ContactDeleted);
+ HookEvent(ME_SYSTEM_MODULESLOADED, SplitmsgModulesLoaded);
+ HookEvent(ME_SKIN_ICONSCHANGED, IconsChanged);
+ HookEvent(ME_PROTO_CONTACTISTYPING, TypingMessage);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN, PreshutdownSendRecv);
+ CreateServiceFunction(MS_MSG_SENDMESSAGE, SendMessageCommand);
+#if defined(_UNICODE)
+ CreateServiceFunction(MS_MSG_SENDMESSAGE "W", SendMessageCommand_W);
+#endif
+ CreateServiceFunction(MS_MSG_GETWINDOWAPI, GetWindowAPI);
+ CreateServiceFunction(MS_MSG_GETWINDOWCLASS, GetWindowClass);
+ CreateServiceFunction(MS_MSG_GETWINDOWDATA, GetWindowData);
+ CreateServiceFunction("SRMsg/ReadMessage", ReadMessageCommand);
+ CreateServiceFunction("SRMsg/TypingMessage", TypingMessageCommand);
+ hHookWinEvt=CreateHookableEvent(ME_MSG_WINDOWEVENT);
+ SkinAddNewSoundEx("RecvMsgActive", Translate("Messages"), Translate("Incoming (Focused Window)"));
+ SkinAddNewSoundEx("RecvMsgInactive", Translate("Messages"), Translate("Incoming (Unfocused Window)"));
+ SkinAddNewSoundEx("AlertMsg", Translate("Messages"), Translate("Incoming (New Session)"));
+ SkinAddNewSoundEx("SendMsg", Translate("Messages"), Translate("Outgoing"));
+ hCurSplitNS = LoadCursor(NULL, IDC_SIZENS);
+ hCurSplitWE = LoadCursor(NULL, IDC_SIZEWE);
+ hCurHyperlinkHand = LoadCursor(NULL, IDC_HAND);
+ if (hCurHyperlinkHand == NULL)
+ hCurHyperlinkHand = LoadCursor(g_hInst, MAKEINTRESOURCE(IDC_HYPERLINKHAND));
+ return 0;
+}
+
+static IRichEditOleCallbackVtbl reOleCallbackVtbl;
+struct CREOleCallback reOleCallback;
+
+static STDMETHODIMP_(ULONG) CREOleCallback_QueryInterface(struct CREOleCallback *lpThis, REFIID riid, LPVOID * ppvObj)
+{
+ if (IsEqualIID(riid, &IID_IRichEditOleCallback)) {
+ *ppvObj = lpThis;
+ lpThis->lpVtbl->AddRef((IRichEditOleCallback *) lpThis);
+ return S_OK;
+ }
+ *ppvObj = NULL;
+ return E_NOINTERFACE;
+}
+
+static STDMETHODIMP_(ULONG) CREOleCallback_AddRef(struct CREOleCallback *lpThis)
+{
+ if (lpThis->refCount == 0) {
+ if (S_OK != StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE | STGM_DELETEONRELEASE, 0, &lpThis->pictStg))
+ lpThis->pictStg = NULL;
+ lpThis->nextStgId = 0;
+ }
+ return ++lpThis->refCount;
+}
+
+static STDMETHODIMP_(ULONG) CREOleCallback_Release(struct CREOleCallback *lpThis)
+{
+ if (--lpThis->refCount == 0) {
+ if (lpThis->pictStg)
+ lpThis->pictStg->lpVtbl->Release(lpThis->pictStg);
+ }
+ return lpThis->refCount;
+}
+
+static STDMETHODIMP_(HRESULT) CREOleCallback_ContextSensitiveHelp(struct CREOleCallback *lpThis, BOOL fEnterMode)
+{
+ return S_OK;
+}
+
+static STDMETHODIMP_(HRESULT) CREOleCallback_DeleteObject(struct CREOleCallback *lpThis, LPOLEOBJECT lpoleobj)
+{
+ return S_OK;
+}
+
+static STDMETHODIMP_(HRESULT) CREOleCallback_GetClipboardData(struct CREOleCallback *lpThis, CHARRANGE * lpchrg, DWORD reco, LPDATAOBJECT * lplpdataobj)
+{
+ return E_NOTIMPL;
+}
+
+static STDMETHODIMP_(HRESULT) CREOleCallback_GetContextMenu(struct CREOleCallback *lpThis, WORD seltype, LPOLEOBJECT lpoleobj, CHARRANGE * lpchrg, HMENU * lphmenu)
+{
+ return E_INVALIDARG;
+}
+
+static STDMETHODIMP_(HRESULT) CREOleCallback_GetDragDropEffect(struct CREOleCallback *lpThis, BOOL fDrag, DWORD grfKeyState, LPDWORD pdwEffect)
+{
+ return S_OK;
+}
+
+static STDMETHODIMP_(HRESULT) CREOleCallback_GetInPlaceContext(struct CREOleCallback *lpThis, LPOLEINPLACEFRAME * lplpFrame, LPOLEINPLACEUIWINDOW * lplpDoc, LPOLEINPLACEFRAMEINFO lpFrameInfo)
+{
+ return E_INVALIDARG;
+}
+
+static STDMETHODIMP_(HRESULT) CREOleCallback_GetNewStorage(struct CREOleCallback *lpThis, LPSTORAGE * lplpstg)
+{
+ WCHAR szwName[64];
+ char szName[64];
+ wsprintfA(szName, "s%u", lpThis->nextStgId);
+ MultiByteToWideChar(CP_ACP, 0, szName, -1, szwName, SIZEOF(szwName));
+ if (lpThis->pictStg == NULL)
+ return STG_E_MEDIUMFULL;
+ return lpThis->pictStg->lpVtbl->CreateStorage(lpThis->pictStg, szwName, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, 0, 0, lplpstg);
+}
+
+static STDMETHODIMP_(HRESULT) CREOleCallback_QueryAcceptData(struct CREOleCallback *lpThis, LPDATAOBJECT lpdataobj, CLIPFORMAT * lpcfFormat, DWORD reco, BOOL fReally, HGLOBAL hMetaPict)
+{
+ return S_OK;
+}
+
+static STDMETHODIMP_(HRESULT) CREOleCallback_QueryInsertObject(struct CREOleCallback *lpThis, LPCLSID lpclsid, LPSTORAGE lpstg, LONG cp)
+{
+ return S_OK;
+}
+
+static STDMETHODIMP_(HRESULT) CREOleCallback_ShowContainerUI(struct CREOleCallback *lpThis, BOOL fShow)
+{
+ return S_OK;
+}
+
+static void InitREOleCallback(void)
+{
+ reOleCallback.lpVtbl = &reOleCallbackVtbl;
+ reOleCallback.lpVtbl->AddRef = (ULONG(__stdcall *) (IRichEditOleCallback *)) CREOleCallback_AddRef;
+ reOleCallback.lpVtbl->Release = (ULONG(__stdcall *) (IRichEditOleCallback *)) CREOleCallback_Release;
+ reOleCallback.lpVtbl->QueryInterface = (ULONG(__stdcall *) (IRichEditOleCallback *, REFIID, PVOID *)) CREOleCallback_QueryInterface;
+ reOleCallback.lpVtbl->ContextSensitiveHelp = (HRESULT(__stdcall *) (IRichEditOleCallback *, BOOL)) CREOleCallback_ContextSensitiveHelp;
+ reOleCallback.lpVtbl->DeleteObject = (HRESULT(__stdcall *) (IRichEditOleCallback *, LPOLEOBJECT)) CREOleCallback_DeleteObject;
+ reOleCallback.lpVtbl->GetClipboardData = (HRESULT(__stdcall *) (IRichEditOleCallback *, CHARRANGE *, DWORD, LPDATAOBJECT *)) CREOleCallback_GetClipboardData;
+ reOleCallback.lpVtbl->GetContextMenu = (HRESULT(__stdcall *) (IRichEditOleCallback *, WORD, LPOLEOBJECT, CHARRANGE *, HMENU *)) CREOleCallback_GetContextMenu;
+ reOleCallback.lpVtbl->GetDragDropEffect = (HRESULT(__stdcall *) (IRichEditOleCallback *, BOOL, DWORD, LPDWORD)) CREOleCallback_GetDragDropEffect;
+ reOleCallback.lpVtbl->GetInPlaceContext = (HRESULT(__stdcall *) (IRichEditOleCallback *, LPOLEINPLACEFRAME *, LPOLEINPLACEUIWINDOW *, LPOLEINPLACEFRAMEINFO))
+ CREOleCallback_GetInPlaceContext;
+ reOleCallback.lpVtbl->GetNewStorage = (HRESULT(__stdcall *) (IRichEditOleCallback *, LPSTORAGE *)) CREOleCallback_GetNewStorage;
+ reOleCallback.lpVtbl->QueryAcceptData = (HRESULT(__stdcall *) (IRichEditOleCallback *, LPDATAOBJECT, CLIPFORMAT *, DWORD, BOOL, HGLOBAL)) CREOleCallback_QueryAcceptData;
+ reOleCallback.lpVtbl->QueryInsertObject = (HRESULT(__stdcall *) (IRichEditOleCallback *, LPCLSID, LPSTORAGE, LONG)) CREOleCallback_QueryInsertObject;
+ reOleCallback.lpVtbl->ShowContainerUI = (HRESULT(__stdcall *) (IRichEditOleCallback *, BOOL)) CREOleCallback_ShowContainerUI;
+ reOleCallback.refCount = 0;
+}
diff --git a/miranda-wine/plugins/srmm/msgs.h b/miranda-wine/plugins/srmm/msgs.h
new file mode 100644
index 0000000..538f8b5
--- /dev/null
+++ b/miranda-wine/plugins/srmm/msgs.h
@@ -0,0 +1,211 @@
+/*
+SRMM
+
+Copyright 2000-2005 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 SRMM_MSGS_H
+#define SRMM_MSGS_H
+
+#include <richedit.h>
+#include <richole.h>
+#define MSGERROR_CANCEL 0
+#define MSGERROR_RETRY 1
+
+struct NewMessageWindowLParam
+{
+ HANDLE hContact;
+ const char *szInitialText;
+ int isWchar;
+};
+
+struct MessageWindowData
+{
+ HANDLE hContact;
+ HANDLE hDbEventFirst, hDbEventLast;
+ HANDLE hSendId;
+ int sendCount;
+ HBRUSH hBkgBrush;
+ int splitterPos, originalSplitterPos;
+ char *sendBuffer;
+ SIZE minEditBoxSize;
+ RECT minEditInit;
+ int lineHeight;
+ int windowWasCascaded;
+ int nFlash;
+ int nFlashMax;
+ int nLabelRight;
+ int nTypeSecs;
+ int nTypeMode;
+ int avatarWidth;
+ int avatarHeight;
+ int limitAvatarH;
+ HBITMAP avatarPic;
+ DWORD nLastTyping;
+ int showTyping;
+ HWND hwndStatus;
+ DWORD lastMessage;
+ char *szProto;
+ WORD wStatus;
+ WORD wOldStatus;
+ TCmdList *cmdList;
+ TCmdList *cmdListCurrent;
+ int bIsRtl, bIsFirstAppend, bIsAutoRTL;
+ int lastEventType;
+};
+
+#define HM_EVENTSENT (WM_USER+10)
+#define DM_REMAKELOG (WM_USER+11)
+#define HM_DBEVENTADDED (WM_USER+12)
+#define DM_CASCADENEWWINDOW (WM_USER+13)
+#define DM_OPTIONSAPPLIED (WM_USER+14)
+#define DM_SPLITTERMOVED (WM_USER+15)
+#define DM_UPDATETITLE (WM_USER+16)
+#define DM_APPENDTOLOG (WM_USER+17)
+#define DM_ERRORDECIDED (WM_USER+18)
+#define DM_SCROLLLOGTOBOTTOM (WM_USER+19)
+#define DM_TYPING (WM_USER+20)
+#define DM_UPDATEWINICON (WM_USER+21)
+#define DM_UPDATELASTMESSAGE (WM_USER+22)
+#define DM_USERNAMETOCLIP (WM_USER+23)
+#define DM_AVATARSIZECHANGE (WM_USER+24)
+#define DM_AVATARCALCSIZE (WM_USER+25)
+#define DM_GETAVATAR (WM_USER+26)
+#define DM_UPDATESIZEBAR (WM_USER+27)
+#define HM_AVATARACK (WM_USER+28)
+#define HM_ACKEVENT (WM_USER+29)
+#define DM_GETWINDOWSTATE (WM_USER+30)
+
+#define EVENTTYPE_STATUSCHANGE 25368
+
+struct CREOleCallback
+{
+ IRichEditOleCallbackVtbl *lpVtbl;
+ unsigned refCount;
+ IStorage *pictStg;
+ int nextStgId;
+};
+
+BOOL CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+int InitOptions(void);
+BOOL CALLBACK ErrorDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+int DbEventIsShown(DBEVENTINFO * dbei, struct MessageWindowData *dat);
+void StreamInEvents(HWND hwndDlg, HANDLE hDbEventFirst, int count, int fAppend);
+void LoadMsgLogIcons(void);
+void FreeMsgLogIcons(void);
+
+#define MSGFONTID_MYMSG 0
+#define MSGFONTID_YOURMSG 1
+#define MSGFONTID_MYNAME 2
+#define MSGFONTID_MYTIME 3
+#define MSGFONTID_MYCOLON 4
+#define MSGFONTID_YOURNAME 5
+#define MSGFONTID_YOURTIME 6
+#define MSGFONTID_YOURCOLON 7
+#define MSGFONTID_MESSAGEAREA 8
+#define MSGFONTID_NOTICE 9
+
+void LoadMsgDlgFont(int i, LOGFONT* lf, COLORREF* colour);
+extern const int msgDlgFontCount;
+
+#define LOADHISTORY_UNREAD 0
+#define LOADHISTORY_COUNT 1
+#define LOADHISTORY_TIME 2
+
+#define SRMMMOD "SRMM"
+
+#define SRMSGSET_POPFLAGS "PopupFlags"
+#define SRMSGDEFSET_POPFLAGS 0
+#define SRMSGSET_SHOWBUTTONLINE "ShowButtonLine"
+#define SRMSGDEFSET_SHOWBUTTONLINE 1
+#define SRMSGSET_SHOWINFOLINE "ShowInfoLine"
+#define SRMSGDEFSET_SHOWINFOLINE 1
+#define SRMSGSET_AUTOMIN "AutoMin"
+#define SRMSGDEFSET_AUTOMIN 0
+#define SRMSGSET_AUTOCLOSE "AutoClose"
+#define SRMSGDEFSET_AUTOCLOSE 0
+#define SRMSGSET_SAVEPERCONTACT "SavePerContact"
+#define SRMSGDEFSET_SAVEPERCONTACT 0
+#define SRMSGSET_CASCADE "Cascade"
+#define SRMSGDEFSET_CASCADE 1
+#define SRMSGSET_SENDONENTER "SendOnEnter"
+#define SRMSGDEFSET_SENDONENTER 1
+#define SRMSGSET_SENDONDBLENTER "SendOnDblEnter"
+#define SRMSGDEFSET_SENDONDBLENTER 0
+#define SRMSGSET_STATUSICON "UseStatusWinIcon"
+#define SRMSGDEFSET_STATUSICON 0
+#define SRMSGSET_SENDBUTTON "UseSendButton"
+#define SRMSGDEFSET_SENDBUTTON 0
+#define SRMSGSET_CHARCOUNT "ShowCharCount"
+#define SRMSGDEFSET_CHARCOUNT 0
+#define SRMSGSET_CTRLSUPPORT "SupportCtrlUpDn"
+#define SRMSGDEFSET_CTRLSUPPORT 1
+#define SRMSGSET_DELTEMP "DeleteTempCont"
+#define SRMSGDEFSET_DELTEMP 0
+#define SRMSGSET_MSGTIMEOUT "MessageTimeout"
+#define SRMSGDEFSET_MSGTIMEOUT 10000
+#define SRMSGSET_MSGTIMEOUT_MIN 4000 // minimum value (4 seconds)
+#define SRMSGSET_FLASHCOUNT "FlashMax"
+#define SRMSGDEFSET_FLASHCOUNT 5
+
+#define SRMSGSET_LOADHISTORY "LoadHistory"
+#define SRMSGDEFSET_LOADHISTORY LOADHISTORY_UNREAD
+#define SRMSGSET_LOADCOUNT "LoadCount"
+#define SRMSGDEFSET_LOADCOUNT 10
+#define SRMSGSET_LOADTIME "LoadTime"
+#define SRMSGDEFSET_LOADTIME 10
+
+#define SRMSGSET_SHOWLOGICONS "ShowLogIcon"
+#define SRMSGDEFSET_SHOWLOGICONS 1
+#define SRMSGSET_HIDENAMES "HideNames"
+#define SRMSGDEFSET_HIDENAMES 1
+#define SRMSGSET_SHOWTIME "ShowTime"
+#define SRMSGDEFSET_SHOWTIME 1
+#define SRMSGSET_SHOWSECS "ShowSeconds"
+#define SRMSGDEFSET_SHOWSECS 1
+#define SRMSGSET_SHOWDATE "ShowDate"
+#define SRMSGDEFSET_SHOWDATE 0
+#define SRMSGSET_SHOWSTATUSCH "ShowStatusChanges"
+#define SRMSGDEFSET_SHOWSTATUSCH 1
+#define SRMSGSET_BKGCOLOUR "BkgColour"
+#define SRMSGDEFSET_BKGCOLOUR GetSysColor(COLOR_WINDOW)
+
+#define SRMSGSET_TYPING "SupportTyping"
+#define SRMSGSET_TYPINGNEW "DefaultTyping"
+#define SRMSGDEFSET_TYPINGNEW 1
+#define SRMSGSET_TYPINGUNKNOWN "UnknownTyping"
+#define SRMSGDEFSET_TYPINGUNKNOWN 0
+#define SRMSGSET_SHOWTYPING "ShowTyping"
+#define SRMSGDEFSET_SHOWTYPING 1
+#define SRMSGSET_SHOWTYPINGWIN "ShowTypingWin"
+#define SRMSGDEFSET_SHOWTYPINGWIN 1
+#define SRMSGSET_SHOWTYPINGNOWIN "ShowTypingTray"
+#define SRMSGDEFSET_SHOWTYPINGNOWIN 0
+#define SRMSGSET_SHOWTYPINGCLIST "ShowTypingClist"
+#define SRMSGDEFSET_SHOWTYPINGCLIST 1
+
+
+#define SRMSGSET_AVATARENABLE "AvatarEnable"
+#define SRMSGDEFSET_AVATARENABLE 1
+#define SRMSGSET_LIMITAVHEIGHT "AvatarLimitHeight"
+#define SRMSGDEFSET_LIMITAVHEIGHT 1
+#define SRMSGSET_AVHEIGHT "AvatarHeight"
+#define SRMSGDEFSET_AVHEIGHT 60
+#define SRMSGSET_AVATAR "Avatar"
+
+#endif
diff --git a/miranda-wine/plugins/srmm/msgtimedout.c b/miranda-wine/plugins/srmm/msgtimedout.c
new file mode 100644
index 0000000..5539ff0
--- /dev/null
+++ b/miranda-wine/plugins/srmm/msgtimedout.c
@@ -0,0 +1,71 @@
+/*
+SRMM
+
+Copyright 2000-2005 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#pragma hdrstop
+#include "msgs.h"
+
+BOOL CALLBACK ErrorDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ char* pszError = ( char* )GetWindowLong(hwndDlg, GWL_USERDATA);
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ RECT rc, rcParent;
+
+ SetWindowLong(hwndDlg, GWL_USERDATA, (LONG) pszError);
+
+ TranslateDialogDefault(hwndDlg);
+
+ if (lParam) {
+ pszError = (char *) lParam;
+ if (!pszError||!strlen(pszError))
+ pszError = strdup(Translate("An unknown error has occured."));
+ SetDlgItemTextA(hwndDlg, IDC_ERRORTEXT, pszError);
+ }
+
+ GetWindowRect(hwndDlg, &rc);
+ GetWindowRect(GetParent(hwndDlg), &rcParent);
+ SetWindowPos(hwndDlg, 0, (rcParent.left + rcParent.right - (rc.right - rc.left)) / 2, (rcParent.top + rcParent.bottom - (rc.bottom - rc.top)) / 2, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDOK:
+ if (pszError)
+ free(pszError);
+ SendMessage(GetParent(hwndDlg), DM_ERRORDECIDED, MSGERROR_RETRY, 0);
+ DestroyWindow(hwndDlg);
+ break;
+ case IDCANCEL:
+ if (pszError)
+ free(pszError);
+ SendMessage(GetParent(hwndDlg), DM_ERRORDECIDED, MSGERROR_CANCEL, 0);
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
diff --git a/miranda-wine/plugins/srmm/res/add.ico b/miranda-wine/plugins/srmm/res/add.ico
new file mode 100644
index 0000000..2efc4dc
--- /dev/null
+++ b/miranda-wine/plugins/srmm/res/add.ico
Binary files differ
diff --git a/miranda-wine/plugins/srmm/res/clock.ico b/miranda-wine/plugins/srmm/res/clock.ico
new file mode 100644
index 0000000..83b8abf
--- /dev/null
+++ b/miranda-wine/plugins/srmm/res/clock.ico
Binary files differ
diff --git a/miranda-wine/plugins/srmm/res/details.ico b/miranda-wine/plugins/srmm/res/details.ico
new file mode 100644
index 0000000..a2c16ae
--- /dev/null
+++ b/miranda-wine/plugins/srmm/res/details.ico
Binary files differ
diff --git a/miranda-wine/plugins/srmm/res/downarrow.ico b/miranda-wine/plugins/srmm/res/downarrow.ico
new file mode 100644
index 0000000..76a473c
--- /dev/null
+++ b/miranda-wine/plugins/srmm/res/downarrow.ico
Binary files differ
diff --git a/miranda-wine/plugins/srmm/res/history.ico b/miranda-wine/plugins/srmm/res/history.ico
new file mode 100644
index 0000000..2749b50
--- /dev/null
+++ b/miranda-wine/plugins/srmm/res/history.ico
Binary files differ
diff --git a/miranda-wine/plugins/srmm/res/incoming.ico b/miranda-wine/plugins/srmm/res/incoming.ico
new file mode 100644
index 0000000..fabbf97
--- /dev/null
+++ b/miranda-wine/plugins/srmm/res/incoming.ico
Binary files differ
diff --git a/miranda-wine/plugins/srmm/res/notice.ico b/miranda-wine/plugins/srmm/res/notice.ico
new file mode 100644
index 0000000..23527a9
--- /dev/null
+++ b/miranda-wine/plugins/srmm/res/notice.ico
Binary files differ
diff --git a/miranda-wine/plugins/srmm/res/outgoing.ico b/miranda-wine/plugins/srmm/res/outgoing.ico
new file mode 100644
index 0000000..f772ab3
--- /dev/null
+++ b/miranda-wine/plugins/srmm/res/outgoing.ico
Binary files differ
diff --git a/miranda-wine/plugins/srmm/res/typing.ico b/miranda-wine/plugins/srmm/res/typing.ico
new file mode 100644
index 0000000..6dd597e
--- /dev/null
+++ b/miranda-wine/plugins/srmm/res/typing.ico
Binary files differ
diff --git a/miranda-wine/plugins/srmm/resource.h b/miranda-wine/plugins/srmm/resource.h
new file mode 100644
index 0000000..d1e7ce3
--- /dev/null
+++ b/miranda-wine/plugins/srmm/resource.h
@@ -0,0 +1,93 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by resource.rc
+//
+#define IDD_MSGSENDERROR 102
+#define IDI_USERDETAILS 160
+#define IDI_HISTORY 174
+#define IDR_CONTEXT 180
+#define IDC_DROP 183
+#define IDI_ADDCONTACT 210
+#define IDC_HYPERLINKHAND 214
+#define IDC_DROPUSER 215
+#define IDD_OPT_MSGDLG 243
+#define IDD_MSG 244
+#define IDD_OPT_MSGLOG 245
+#define IDI_DOWNARROW 264
+#define IDI_TYPING 268
+#define IDD_OPT_MSGTYPE 275
+#define IDI_INCOMING 276
+#define IDI_OUTGOING 277
+#define IDI_NOTICE 282
+#define IDC_LOG 1001
+#define IDC_MESSAGE 1002
+#define IDC_AUTOCLOSE 1004
+#define IDC_AUTOMIN 1005
+#define IDC_NAME 1009
+#define IDC_SPLITTER 1017
+#define IDC_SHOWNAMES 1024
+#define IDC_SHOWSENDBTN 1029
+#define IDC_SHOWLOGICONS 1032
+#define IDC_SHOWTIMES 1033
+#define IDC_SHOWDATES 1034
+#define IDC_CLIST 1035
+#define IDC_SHOWSTATUSCHANGES 1035
+#define IDC_SAVEPERCONTACT 1037
+#define IDC_LOADCOUNTN 1039
+#define IDC_LOADCOUNTSPIN 1040
+#define IDC_SHOWINFOLINE 1041
+#define IDC_SHOWBUTTONLINE 1042
+#define IDC_LOADUNREAD 1043
+#define IDC_SENDONENTER 1043
+#define IDC_LOADCOUNT 1044
+#define IDC_SENDONDBLENTER 1044
+#define IDC_LOADTIMEN 1045
+#define IDC_LOADTIMESPIN 1046
+#define IDC_LOADTIME 1047
+#define IDC_FONTLIST 1048
+#define IDC_CHOOSEFONT 1049
+#define IDC_STMINSOLD 1051
+#define IDC_DETAILS 1069
+#define IDC_ADD 1070
+#define IDC_USERMENU 1071
+#define IDC_HISTORY 1080
+#define IDC_BKGCOLOUR 1269
+#define IDC_FONTCOLOUR 1282
+#define IDC_STMSGLOGGROUP 1442
+#define IDC_PROTOCOL 1580
+#define IDC_ERRORTEXT 1596
+#define IDC_SHOWNOTIFY 1600
+#define IDC_STATUSWIN 1601
+#define IDC_TYPEWIN 1602
+#define IDC_CHARCOUNT 1603
+#define IDC_TYPETRAY 1603
+#define IDC_CASCADE 1604
+#define IDC_SECONDS 1605
+#define IDC_NOTIFYTRAY 1606
+#define IDC_NOTIFYBALLOON 1607
+#define IDC_CTRLSUPPORT 1608
+#define IDC_DELTEMP 1609
+#define IDC_AVATAR 1610
+#define IDC_AVATARSUPPORT 1611
+#define IDC_LIMITAVATARH 1612
+#define IDC_AVATARHEIGHT 1613
+#define IDC_SHOWSECS 1614
+#define IDC_POPLIST 1616
+#define IDM_COPY 40001
+#define IDM_COPYALL 40011
+#define IDM_SELECTALL 40012
+#define IDM_CLEAR 40013
+#define IDM_OPENNEW 40014
+#define IDM_OPENEXISTING 40015
+#define IDM_COPYLINK 40016
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 286
+#define _APS_NEXT_COMMAND_VALUE 40019
+#define _APS_NEXT_CONTROL_VALUE 1617
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/miranda-wine/plugins/srmm/resource.rc b/miranda-wine/plugins/srmm/resource.rc
new file mode 100644
index 0000000..3dfc7e8
--- /dev/null
+++ b/miranda-wine/plugins/srmm/resource.rc
@@ -0,0 +1,356 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include <windows.h>
+#include <winres.h>
+#include "../../include/statusmodes.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
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_OPT_MSGDLG DIALOGEX 0, 0, 312, 234
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Message Window Options",IDC_STATIC,2,0,310,231
+ CONTROL "Close the message window on send",IDC_AUTOCLOSE,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,8,58,212,10
+ CONTROL "Minimize the message window on send",IDC_AUTOMIN,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,8,70,221,10
+ CONTROL "Use the contact's status icon as the window icon",
+ IDC_STATUSWIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,82,
+ 273,10
+ CONTROL "Save the window size and location individually for each contact",
+ IDC_SAVEPERCONTACT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 8,94,300,10
+ CONTROL "Cascade new windows",IDC_CASCADE,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,8,106,136,10
+ CONTROL "Show 'Send' button",IDC_SHOWSENDBTN,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,8,174,135,10
+ CONTROL "Show username on top row",IDC_SHOWINFOLINE,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,8,187,138,10
+ CONTROL "Show toolbar buttons on top row",IDC_SHOWBUTTONLINE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,200,137,10
+ CONTROL "Send message on double 'Enter'",IDC_SENDONDBLENTER,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,148,174,137,10
+ CONTROL "Send message on 'Enter'",IDC_SENDONENTER,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,148,187,137,10
+ CONTROL "Show character count",IDC_CHARCOUNT,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,148,200,133,10
+ LTEXT "Show warning when message has not been received after",
+ IDC_STATIC,8,216,211,8
+ EDITTEXT IDC_SECONDS,223,214,25,12,ES_AUTOHSCROLL
+ LTEXT "seconds.",IDC_STATIC,253,216,44,8
+ CONTROL "Support control up/down in message area to show previously sent messages",
+ IDC_CTRLSUPPORT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,
+ 118,298,10
+ CONTROL "Delete temporary contacts when closing message window",
+ IDC_DELTEMP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,130,
+ 287,10
+ CONTROL "Enable avatar support in the message window",
+ IDC_AVATARSUPPORT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 8,143,279,10
+ CONTROL "Limit avatar height to ",IDC_LIMITAVATARH,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,22,157,106,10
+ EDITTEXT IDC_AVATARHEIGHT,148,156,28,13,ES_AUTOHSCROLL
+ LTEXT "pixels.",IDC_STATIC,181,158,35,8
+ CONTROL "Tree1",IDC_POPLIST,"SysTreeView32",TVS_DISABLEDRAGDROP |
+ TVS_NOTOOLTIPS | TVS_NONEVENHEIGHT | WS_BORDER |
+ WS_TABSTOP,163,14,98,42
+ LTEXT "Automatically popup window when:",IDC_STATIC,10,15,141,
+ 13
+END
+
+IDD_MSGSENDERROR DIALOGEX 0, 0, 187, 97
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP |
+ WS_VISIBLE | WS_CAPTION | WS_SYSMENU | DS_SETFONT
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Send Error"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "An error has occured. The protocol reported the following error:",
+ IDC_STATIC,5,5,177,28
+ DEFPUSHBUTTON "Try again",IDOK,22,78,63,14
+ PUSHBUTTON "Cancel",IDCANCEL,104,78,61,14
+ EDITTEXT IDC_ERRORTEXT,5,37,177,35,ES_MULTILINE | ES_READONLY |
+ WS_VSCROLL
+END
+
+IDD_MSG DIALOGEX 0, 0, 184, 78
+STYLE DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CLIPCHILDREN |
+ WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | DS_SETFONT
+EXSTYLE WS_EX_ACCEPTFILES
+CAPTION "Message Session"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ EDITTEXT IDC_MESSAGE,1,49,141,13,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_WANTRETURN | WS_VSCROLL,WS_EX_ACCEPTFILES
+ DEFPUSHBUTTON "&Send",IDOK,143,48,39,15
+ PUSHBUTTON "Close",IDCANCEL,129,0,54,15,NOT WS_VISIBLE
+ CONTROL "",IDC_PROTOCOL,"Button",BS_OWNERDRAW,2,5,12,12
+ CONTROL "",IDC_NAME,"MButtonClass",WS_TABSTOP,15,2,95,14,
+ 0x18000000L
+ CONTROL "",IDC_ADD,"MButtonClass",WS_TABSTOP,110,2,16,14,
+ 0x18000000L
+ CONTROL "",IDC_USERMENU,"MButtonClass",WS_TABSTOP,128,2,16,14,
+ 0x18000000L
+ CONTROL "&D",IDC_DETAILS,"MButtonClass",WS_TABSTOP,146,2,16,14,
+ 0x18000000L
+ CONTROL "&H",IDC_HISTORY,"MButtonClass",WS_TABSTOP,164,2,16,14,
+ 0x18000000L
+ CONTROL "",IDC_LOG,"RichEdit20A",WS_VSCROLL | WS_TABSTOP | 0x844,
+ 1,18,181,26,WS_EX_CLIENTEDGE
+ CONTROL "",IDC_SPLITTER,"Static",SS_ENHMETAFILE,0,45,183,2
+ CONTROL "",IDC_AVATAR,"Button",BS_OWNERDRAW | NOT WS_VISIBLE,1,
+ 50,1,13
+END
+
+IDD_OPT_MSGLOG DIALOGEX 0, 0, 306, 229
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Message Window Event Log",IDC_STMSGLOGGROUP,0,0,158,158
+ CONTROL "Show icons",IDC_SHOWLOGICONS,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,10,12,146,10
+ CONTROL "Show names",IDC_SHOWNAMES,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,10,28,146,10
+ CONTROL "Show timestamp",IDC_SHOWTIMES,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,10,44,146,10
+ CONTROL "Show dates",IDC_SHOWDATES,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,21,75,135,10
+ GROUPBOX "Fonts",IDC_STATIC,163,0,143,158
+ LTEXT "Background colour:",IDC_STATIC,169,16,81,8
+ CONTROL "",IDC_BKGCOLOUR,"ColourPicker",WS_TABSTOP,261,14,39,12
+ LISTBOX IDC_FONTLIST,169,31,131,82,LBS_OWNERDRAWVARIABLE |
+ LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL |
+ WS_TABSTOP
+ CONTROL "",IDC_FONTCOLOUR,"ColourPicker",WS_TABSTOP,169,117,57,
+ 14
+ PUSHBUTTON "Choose font...",IDC_CHOOSEFONT,243,117,57,14
+ GROUPBOX "Load History Events",IDC_STATIC,0,163,306,66
+ CONTROL "Load unread events only",IDC_LOADUNREAD,"Button",
+ BS_AUTORADIOBUTTON | WS_TABSTOP,10,177,138,10
+ CONTROL "Load number of previous events",IDC_LOADCOUNT,"Button",
+ BS_AUTORADIOBUTTON,10,193,138,10
+ EDITTEXT IDC_LOADCOUNTN,148,192,33,12,ES_RIGHT | ES_NUMBER |
+ WS_DISABLED
+ CONTROL "Spin1",IDC_LOADCOUNTSPIN,"msctls_updown32",
+ UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY |
+ UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK |
+ WS_DISABLED,170,191,10,14
+ CONTROL "Load previous events less than",IDC_LOADTIME,"Button",
+ BS_AUTORADIOBUTTON,10,209,138,10
+ EDITTEXT IDC_LOADTIMEN,148,208,33,12,ES_RIGHT | ES_NUMBER |
+ WS_DISABLED
+ CONTROL "Spin1",IDC_LOADTIMESPIN,"msctls_updown32",
+ UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY |
+ UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK |
+ WS_DISABLED,170,207,10,14
+ LTEXT "minutes old",IDC_STMINSOLD,185,210,90,8,WS_DISABLED
+ CTEXT "Select multiple fonts by dragging or by using the control key",
+ IDC_STATIC,169,135,131,16
+ CONTROL "Show status changes",IDC_SHOWSTATUSCHANGES,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,10,92,146,10
+ CONTROL "Show seconds",IDC_SHOWSECS,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,21,59,127,10
+END
+
+IDD_OPT_MSGTYPE DIALOGEX 0, 0, 283, 252
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Typing Notification Options",IDC_STATIC,7,7,269,238
+ CONTROL "",IDC_CLIST,"CListControl",WS_TABSTOP | 0x348,18,42,248,
+ 131,WS_EX_CLIENTEDGE
+ LTEXT "Send typing notifications to the following users when you are typing a message to them:",
+ IDC_STATIC,19,18,245,19
+ CONTROL "Show typing notifications when a user is typing a message",
+ IDC_SHOWNOTIFY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,18,
+ 178,233,13
+ CONTROL "Update inactive message window icons when a user is typing",
+ IDC_TYPEWIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,29,193,
+ 230,10
+ CONTROL "Show typing notification when no message dialog is open",
+ IDC_TYPETRAY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,29,
+ 206,230,10
+ CONTROL "Flash in the system tray and in the contact list",
+ IDC_NOTIFYTRAY,"Button",BS_AUTORADIOBUTTON,44,219,206,10
+ CONTROL "Show balloon popup",IDC_NOTIFYBALLOON,"Button",
+ BS_AUTORADIOBUTTON,44,231,206,10
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_OPT_MSGDLG, DIALOG
+ BEGIN
+ VERTGUIDE, 10
+ VERTGUIDE, 22
+ VERTGUIDE, 51
+ VERTGUIDE, 148
+ VERTGUIDE, 300
+ VERTGUIDE, 310
+ BOTTOMMARGIN, 231
+ END
+
+ IDD_MSGSENDERROR, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 182
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 92
+ END
+
+ IDD_MSG, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 179
+ TOPMARGIN, 5
+ HORZGUIDE, 16
+ HORZGUIDE, 53
+ END
+
+ IDD_OPT_MSGLOG, DIALOG
+ BEGIN
+ VERTGUIDE, 10
+ VERTGUIDE, 148
+ VERTGUIDE, 156
+ VERTGUIDE, 169
+ VERTGUIDE, 300
+ HORZGUIDE, 183
+ HORZGUIDE, 199
+ END
+
+ IDD_OPT_MSGTYPE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 276
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 245
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include <windows.h>\r\n"
+ "#include <winres.h>\r\n"
+ "#include ""../../include/statusmodes.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_USERDETAILS ICON DISCARDABLE "res/Details.ico"
+IDI_ADDCONTACT ICON DISCARDABLE "res\\add.ico"
+IDI_HISTORY ICON DISCARDABLE "res/History.ico"
+IDI_DOWNARROW ICON DISCARDABLE "res/Downarrow.ico"
+IDI_TYPING ICON DISCARDABLE "res/Typing.ico"
+IDI_OUTGOING ICON DISCARDABLE "res\\outgoing.ico"
+IDI_INCOMING ICON DISCARDABLE "res\\incoming.ico"
+IDI_NOTICE ICON DISCARDABLE "res\\notice.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Cursor
+//
+
+IDC_HYPERLINKHAND CURSOR DISCARDABLE "../../src/res/hyperlin.cur"
+IDC_DROP CURSOR DISCARDABLE "../../src/res/dragcopy.cur"
+IDC_DROPUSER CURSOR DISCARDABLE "../../src/res/dropuser.cur"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_CONTEXT MENU DISCARDABLE
+BEGIN
+ POPUP "Log"
+ BEGIN
+ MENUITEM "C&lear Log", IDM_CLEAR
+ MENUITEM SEPARATOR
+ MENUITEM "&Copy", IDM_COPY
+ MENUITEM "Co&py All", IDM_COPYALL
+ MENUITEM SEPARATOR
+ MENUITEM "Select &All", IDM_SELECTALL
+ END
+ POPUP "LogLink"
+ BEGIN
+ MENUITEM "Open in &new window", IDM_OPENNEW
+ MENUITEM "&Open in existing window", IDM_OPENEXISTING
+ MENUITEM "&Copy link", IDM_COPYLINK
+ END
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/miranda-wine/plugins/srmm/richutil.c b/miranda-wine/plugins/srmm/richutil.c
new file mode 100644
index 0000000..d803af8
--- /dev/null
+++ b/miranda-wine/plugins/srmm/richutil.c
@@ -0,0 +1,234 @@
+/*
+SRMM
+
+Copyright 2000-2005 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "richutil.h"
+
+/*
+ To initialize this library, call:
+ RichUtil_Load();
+ Before the application exits, call:
+ RichUtil_Unload();
+
+ Then to use the library (it draws the xp border around it), you need
+ to make sure you control has the WS_EX_CLIENTEDGE flag. Then you just
+ subclass it with:
+ RichUtil_SubClass(hwndEdit);
+
+ If no xptheme is present, the window isn't subclassed the SubClass function
+ just returns. And if WS_EX_CLIENTEDGE isn't present, the subclass does nothing.
+ Otherwise it removes the border and draws it by itself.
+*/
+
+static struct LIST_INTERFACE li;
+static SortedList sListInt;
+
+static int RichUtil_CmpVal(void *p1, void *p2) {
+ TRichUtil *tp1 = (TRichUtil*)p1;
+ TRichUtil *tp2 = (TRichUtil*)p2;
+ if (tp1->hwnd==tp2->hwnd)
+ return 0;
+ return (int)((int)tp1->hwnd-(int)tp2->hwnd);
+}
+
+// UxTheme Stuff
+static HMODULE mTheme = 0;
+static HANDLE (WINAPI *MyOpenThemeData)(HWND,LPCWSTR) = 0;
+static HRESULT (WINAPI *MyCloseThemeData)(HANDLE) = 0;
+static BOOL (WINAPI *MyIsThemeActive)() = 0;
+static HRESULT (WINAPI *MyDrawThemeBackground)(HANDLE,HDC,int,int,const RECT*,const RECT *) = 0;
+static HRESULT (WINAPI *MyGetThemeBackgroundContentRect)(HANDLE,HDC,int,int,const RECT *,RECT *) = 0;
+static HRESULT (WINAPI *MyDrawThemeParentBackground)(HWND,HDC,RECT*) = 0;
+static BOOL (WINAPI *MyIsThemeBackgroundPartiallyTransparent)(HANDLE,int,int) = 0;
+
+static CRITICAL_SECTION csRich;
+
+static LRESULT CALLBACK RichUtil_Proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+static RichUtil_ClearUglyBorder(TRichUtil *ru);
+
+void RichUtil_Load() {
+ li.cbSize = sizeof(li);
+ CallService(MS_SYSTEM_GET_LI,0,(LPARAM)&li);
+ ZeroMemory(&sListInt, sizeof(sListInt));
+ sListInt.increment = 10;
+ sListInt.sortFunc = RichUtil_CmpVal;
+ mTheme = RIsWinVerXPPlus()?LoadLibraryA("uxtheme.dll"):0;
+ InitializeCriticalSection(&csRich);
+ if (!mTheme) return;
+ MyOpenThemeData = (HANDLE (WINAPI *)(HWND, LPCWSTR))GetProcAddress(mTheme, "OpenThemeData");
+ MyCloseThemeData = (HRESULT (WINAPI *)(HANDLE))GetProcAddress(mTheme, "CloseThemeData");
+ MyIsThemeActive = (BOOL (WINAPI *)())GetProcAddress(mTheme, "IsThemeActive");
+ MyDrawThemeBackground = (HRESULT (WINAPI *)(HANDLE, HDC, int, int, const RECT*, const RECT *))GetProcAddress(mTheme, "DrawThemeBackground");
+ MyGetThemeBackgroundContentRect = (HRESULT (WINAPI *)(HANDLE, HDC, int, int, const RECT *, RECT *))GetProcAddress(mTheme, "GetThemeBackgroundContentRect");
+ MyDrawThemeParentBackground = (HRESULT (WINAPI *)(HWND, HDC, RECT*))GetProcAddress(mTheme, "DrawThemeParentBackground");
+ MyIsThemeBackgroundPartiallyTransparent = (BOOL (WINAPI *)(HANDLE, int, int))GetProcAddress(mTheme, "IsThemeBackgroundPartiallyTransparent");
+ if (!MyOpenThemeData||
+ !MyCloseThemeData||
+ !MyIsThemeActive||
+ !MyDrawThemeBackground||
+ !MyGetThemeBackgroundContentRect||
+ !MyDrawThemeParentBackground||
+ !MyIsThemeBackgroundPartiallyTransparent) {
+ FreeLibrary(mTheme);
+ mTheme=NULL;
+ }
+}
+
+void RichUtil_Unload() {
+ li.List_Destroy(&sListInt);
+ DeleteCriticalSection(&csRich);
+ if (mTheme) {
+ FreeLibrary(mTheme);
+ }
+}
+
+int RichUtil_SubClass(HWND hwndEdit) {
+ if (IsWindow(hwndEdit)) {
+ int idx;
+
+ TRichUtil *ru = (TRichUtil*)malloc(sizeof(TRichUtil));
+
+ ZeroMemory(ru, sizeof(TRichUtil));
+ ru->hwnd = hwndEdit;
+ ru->hasUglyBorder = 0;
+ EnterCriticalSection(&csRich);
+ if (!li.List_GetIndex(&sListInt, ru, &idx))
+ li.List_Insert(&sListInt, ru, idx);
+ LeaveCriticalSection(&csRich);
+ SetWindowLong(ru->hwnd, GWL_USERDATA, (LONG)ru); // Ugly hack
+ ru->origProc = (WNDPROC)SetWindowLong(ru->hwnd, GWL_WNDPROC, (LONG)&RichUtil_Proc);
+ RichUtil_ClearUglyBorder(ru);
+ return 1;
+ }
+ return 0;
+}
+
+static LRESULT CALLBACK RichUtil_Proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+ TRichUtil *ru = 0, tru;
+ int idx;
+
+ EnterCriticalSection(&csRich);
+ tru.hwnd = hwnd;
+ if (li.List_GetIndex(&sListInt, &tru, &idx))
+ ru = (TRichUtil*)sListInt.items[idx];
+ LeaveCriticalSection(&csRich);
+ switch(msg) {
+ case WM_THEMECHANGED:
+ case WM_STYLECHANGED:
+ {
+ RichUtil_ClearUglyBorder(ru);
+ break;
+ }
+ case WM_NCPAINT:
+ {
+ LRESULT ret = CallWindowProc(ru->origProc, hwnd, msg, wParam, lParam);
+ if (ru->hasUglyBorder&&MyIsThemeActive()) {
+ HANDLE hTheme = MyOpenThemeData(ru->hwnd, L"EDIT");
+
+ if (hTheme) {
+ RECT rcBorder;
+ RECT rcClient;
+ int nState;
+ HDC hdc = GetWindowDC(ru->hwnd);
+
+ GetWindowRect(hwnd, &rcBorder);
+ rcBorder.right -= rcBorder.left; rcBorder.bottom -= rcBorder.top;
+ rcBorder.left = rcBorder.top = 0;
+ CopyRect(&rcClient, &rcBorder);
+ rcClient.left += ru->rect.left;
+ rcClient.top += ru->rect.top;
+ rcClient.right -= ru->rect.right;
+ rcClient.bottom -= ru->rect.bottom;
+ ExcludeClipRect(hdc, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
+ if(MyIsThemeBackgroundPartiallyTransparent(hTheme, EP_EDITTEXT, ETS_NORMAL))
+ MyDrawThemeParentBackground(hwnd, hdc, &rcBorder);
+ if(!IsWindowEnabled(hwnd))
+ nState = ETS_DISABLED;
+ else if(SendMessage(hwnd, EM_GETOPTIONS, 0, 0) & ECO_READONLY)
+ nState = ETS_READONLY;
+ else nState = ETS_NORMAL;
+ MyDrawThemeBackground(hTheme, hdc, EP_EDITTEXT, nState, &rcBorder, NULL);
+ MyCloseThemeData(hTheme);
+ ReleaseDC(hwnd, hdc);
+ return 0;
+ }
+ }
+ return ret;
+ }
+ case WM_NCCALCSIZE:
+ {
+ LRESULT ret = CallWindowProc(ru->origProc, hwnd, msg, wParam, lParam);
+ NCCALCSIZE_PARAMS *ncsParam = (NCCALCSIZE_PARAMS*)lParam;
+
+ if (ru->hasUglyBorder&&MyIsThemeActive()) {
+ HANDLE hTheme = MyOpenThemeData(hwnd, L"EDIT");
+
+ if (hTheme) {
+ RECT rcClient;
+ HDC hdc = GetDC(GetParent(hwnd));
+
+ ZeroMemory(&rcClient, sizeof(RECT));
+ if(MyGetThemeBackgroundContentRect(hTheme, hdc, EP_EDITTEXT, ETS_NORMAL, &ncsParam->rgrc[0], &rcClient) == S_OK) {
+ ru->rect.left = rcClient.left-ncsParam->rgrc[0].left;
+ ru->rect.top = rcClient.top-ncsParam->rgrc[0].top;
+ ru->rect.right = ncsParam->rgrc[0].right-rcClient.right;
+ ru->rect.bottom = ncsParam->rgrc[0].bottom-rcClient.bottom;
+ CopyRect(&ncsParam->rgrc[0], &rcClient);
+ MyCloseThemeData(hTheme);
+ ReleaseDC(GetParent(hwnd), hdc);
+ return WVR_REDRAW;
+ }
+ ReleaseDC(GetParent(hwnd), hdc);
+ MyCloseThemeData(hTheme);
+ }
+ }
+ return ret;
+ }
+ case WM_ENABLE:
+ RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE|RDW_NOCHILDREN|RDW_UPDATENOW|RDW_FRAME);
+ break;
+ case WM_DESTROY:
+ {
+ LRESULT ret = CallWindowProc(ru->origProc, hwnd, msg, wParam, lParam);
+
+ if(IsWindow(hwnd)) {
+ if((WNDPROC)GetWindowLong(hwnd, GWL_WNDPROC) == &RichUtil_Proc)
+ SetWindowLong(hwnd, GWL_WNDPROC, (LONG)ru->origProc);
+ }
+ EnterCriticalSection(&csRich);
+ li.List_Remove(&sListInt, idx);
+ LeaveCriticalSection(&csRich);
+ if (ru) free(ru);
+ return ret;
+ }
+ }
+ return CallWindowProc(ru->origProc, hwnd, msg, wParam, lParam);
+}
+
+static RichUtil_ClearUglyBorder(TRichUtil *ru) {
+ if (mTheme&&MyIsThemeActive()&&GetWindowLong(ru->hwnd, GWL_EXSTYLE)&WS_EX_CLIENTEDGE) {
+ ru->hasUglyBorder = 1;
+ SetWindowLong(ru->hwnd, GWL_EXSTYLE, GetWindowLong(ru->hwnd, GWL_EXSTYLE)^WS_EX_CLIENTEDGE);
+ }
+ // Redraw window since the style may have changed
+ SetWindowPos(ru->hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_FRAMECHANGED);
+ RedrawWindow(ru->hwnd, NULL, NULL, RDW_INVALIDATE|RDW_NOCHILDREN|RDW_UPDATENOW|RDW_FRAME);
+}
diff --git a/miranda-wine/plugins/srmm/richutil.h b/miranda-wine/plugins/srmm/richutil.h
new file mode 100644
index 0000000..dff6a53
--- /dev/null
+++ b/miranda-wine/plugins/srmm/richutil.h
@@ -0,0 +1,55 @@
+/*
+SRMM
+
+Copyright 2000-2005 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 SRMM_RICHUTIL_H
+#define SRMM_RICHUTIL_H
+
+#define RWinVerMajor() LOBYTE(LOWORD(GetVersion()))
+#define RIsWinVerXPPlus() (RWinVerMajor()>=5 && LOWORD(GetVersion())!=5)
+
+#ifndef WM_THEMECHANGED
+#define WM_THEMECHANGED 0x031A
+#endif
+#ifndef EP_EDITTEXT
+#define EP_EDITTEXT 1
+#endif
+#ifndef ETS_NORMAL
+#define ETS_NORMAL 1
+#endif
+#ifndef ETS_DISABLED
+#define ETS_DISABLED 4
+#endif
+#ifndef ETS_READONLY
+#define ETS_READONLY 6
+#endif
+
+typedef struct {
+ HWND hwnd;
+ RECT rect;
+ int hasUglyBorder;
+ WNDPROC origProc;
+} TRichUtil;
+
+void RichUtil_Load();
+void RichUtil_Unload();
+int RichUtil_SubClass(HWND hwndEdit);
+
+#endif
diff --git a/miranda-wine/plugins/srmm/srmm.c b/miranda-wine/plugins/srmm/srmm.c
new file mode 100644
index 0000000..f416ef6
--- /dev/null
+++ b/miranda-wine/plugins/srmm/srmm.c
@@ -0,0 +1,71 @@
+/*
+SRMM
+
+Copyright 2000-2005 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+int LoadSendRecvMessageModule(void);
+int SplitmsgShutdown(void);
+
+PLUGINLINK *pluginLink;
+HINSTANCE g_hInst;
+
+PLUGININFO pluginInfo = {
+ sizeof(PLUGININFO),
+#ifdef _UNICODE
+ "Send/Receive Messages (Unicode)",
+#else
+ "Send/Receive Messages",
+#endif
+ PLUGIN_MAKE_VERSION(3, 0, 0, 0),
+ "Send and receive instant messages",
+ "Miranda IM Development Team",
+ "rainwater@miranda-im.org",
+ "Copyright 2000-2006 Miranda IM project",
+ "http://www.miranda-im.org",
+ 0,
+ DEFMOD_SRMESSAGE // replace internal version (if any)
+};
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ g_hInst = hinstDLL;
+ return TRUE;
+}
+
+__declspec(dllexport)
+ PLUGININFO *MirandaPluginInfo(DWORD mirandaVersion)
+{
+ if (mirandaVersion < PLUGIN_MAKE_VERSION(0, 4, 0, 0))
+ return NULL;
+ return &pluginInfo;
+}
+
+int __declspec(dllexport) Load(PLUGINLINK * link)
+{
+ pluginLink = link;
+ return LoadSendRecvMessageModule();
+}
+
+int __declspec(dllexport) Unload(void)
+{
+ return SplitmsgShutdown();
+}
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
diff --git a/miranda-wine/src/core/commonheaders.c b/miranda-wine/src/core/commonheaders.c
new file mode 100644
index 0000000..95b2201
--- /dev/null
+++ b/miranda-wine/src/core/commonheaders.c
@@ -0,0 +1,2 @@
+#include "commonheaders.h"
+
diff --git a/miranda-wine/src/core/commonheaders.h b/miranda-wine/src/core/commonheaders.h
new file mode 100644
index 0000000..a08783f
--- /dev/null
+++ b/miranda-wine/src/core/commonheaders.h
@@ -0,0 +1,84 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 defined( UNICODE ) && !defined( _UNICODE )
+# define _UNICODE
+#endif
+
+#include <tchar.h>
+#include <malloc.h>
+
+#define _ALPHA_BASE_ 1 // defined for CVS builds
+#define _ALPHA_FUSE_ 1 // defined for fuse powered core
+
+#ifdef _DEBUG
+# define _CRTDBG_MAP_ALLOC
+# include <stdlib.h>
+# include <crtdbg.h>
+#endif
+
+#define _WIN32_WINNT 0x0501
+#define _WIN32_IE 0x0500
+#include <windows.h>
+#include <commctrl.h>
+#include <stdio.h>
+#include <time.h>
+#include <stddef.h>
+#include <process.h>
+#include <io.h>
+#include <string.h>
+#include <direct.h>
+#include "../resource.h"
+#include <win2k.h>
+#include "modules.h"
+#include "miranda.h"
+#include "forkthread.h"
+#include <m_system.h>
+#include <newpluginapi.h>
+#include <m_database.h>
+#include <m_clc.h>
+#include <m_clui.h>
+#include <m_langpack.h>
+#include <m_clist.h>
+#include <m_clistint.h>
+#include <m_netlib.h>
+#include <m_button.h>
+#include <m_protosvc.h>
+#include <m_protomod.h>
+#include <m_protocols.h>
+#include <m_plugins.h>
+#include <m_options.h>
+#include <m_utils.h>
+#include <m_skin.h>
+#include <m_contacts.h>
+#include <m_message.h>
+#include <m_userinfo.h>
+#include <m_history.h>
+#include <m_addcontact.h>
+#include <m_findadd.h>
+#include <m_file.h>
+#include <m_email.h>
+#include <m_awaymsg.h>
+#include <m_idle.h>
+#include <m_ignore.h>
+#include <m_utils.h>
diff --git a/miranda-wine/src/core/forkthread.h b/miranda-wine/src/core/forkthread.h
new file mode 100644
index 0000000..154584f
--- /dev/null
+++ b/miranda-wine/src/core/forkthread.h
@@ -0,0 +1,64 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/*
+
+Purpose:
+
+ A safe version of _beginthread()
+
+Description:
+
+ 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 unsure
+ that Miranda will wait for all created threads to return as well.
+
+Cavets:
+
+ The function must be reimplemented across MT plugins, since thread
+ creation depends on CRT which can not be shared.
+
+*/
+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/src/core/memory.c b/miranda-wine/src/core/memory.c
new file mode 100644
index 0000000..7c55939
--- /dev/null
+++ b/miranda-wine/src/core/memory.c
@@ -0,0 +1,167 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+#define BLOCK_ALLOCED 0xABBABABA
+#define BLOCK_FREED 0xDEADBEEF
+
+static int CheckBlock( void* blk )
+{
+ int result = FALSE;
+ char* p = ( char* )blk - sizeof(DWORD)*2;
+ DWORD size, *b, *e;
+
+ __try
+ {
+ size = *( DWORD* )p;
+ b = ( DWORD* )&p[ sizeof( DWORD ) ];
+ e = ( DWORD* )&p[ sizeof( DWORD )*2 + size ];
+
+ if ( *b != BLOCK_ALLOCED || *e != BLOCK_ALLOCED )
+ {
+ if ( *b == BLOCK_FREED && *e == BLOCK_FREED )
+ OutputDebugStringA( "memory block is already deleted\n" );
+ else
+ OutputDebugStringA( "memory block is corrupted\n" );
+ #if defined( _DEBUG )
+ DebugBreak();
+ #endif
+ }
+ else result = TRUE;
+ }
+ __except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ OutputDebugStringA( "access violation during checking memory block\n" );
+ #if defined( _DEBUG )
+ DebugBreak();
+ #endif
+ }
+
+ return result;
+}
+
+/******************************************************************************/
+
+void* mir_alloc( size_t size )
+{
+ if ( size == 0 )
+ return NULL;
+ {
+ char* p = (char*)malloc( size + sizeof(DWORD)*3 );
+ if ( p == NULL ) {
+ OutputDebugStringA( "memory overflow\n" );
+ #if defined( _DEBUG )
+ DebugBreak();
+ #endif
+ return NULL;
+ }
+
+ *( DWORD* )p = ( DWORD )size;
+ *( DWORD* )&p[ sizeof(DWORD) ] = BLOCK_ALLOCED;
+ *( DWORD* )&p[ size + sizeof(DWORD)*2 ] = BLOCK_ALLOCED;
+ return p + sizeof( DWORD )*2;
+} }
+
+/******************************************************************************/
+
+void* mir_calloc( size_t size )
+{
+ void* p = mir_alloc( size );
+ if ( p != NULL )
+ memset( p, 0, size );
+ return p;
+}
+
+/******************************************************************************/
+
+void* mir_realloc( void* ptr, size_t size )
+{
+ char* p;
+
+ if ( ptr != NULL ) {
+ if ( !CheckBlock( ptr ))
+ return NULL;
+ p = ( char* )ptr - sizeof(DWORD)*2;
+ }
+ else p = NULL;
+
+ p = ( char* )realloc( p, size + sizeof(DWORD)*3 );
+ if ( p == NULL ) {
+ OutputDebugStringA( "memory overflow\n" );
+ #if defined( _DEBUG )
+ DebugBreak();
+ #endif
+ return NULL;
+ }
+
+ *( DWORD* )p = ( DWORD )size;
+ *( DWORD* )&p[ sizeof(DWORD) ] = BLOCK_ALLOCED;
+ *( DWORD* )&p[ size + sizeof(DWORD)*2 ] = BLOCK_ALLOCED;
+ return p + sizeof( DWORD )*2;
+}
+
+/******************************************************************************/
+
+void mir_free( void* ptr )
+{
+ char* p;
+ DWORD size;
+
+ if ( ptr == NULL )
+ return;
+ if ( !CheckBlock( ptr ))
+ return;
+
+ p = ( char* )ptr - sizeof(DWORD)*2;
+ size = *( DWORD* )p;
+ *( DWORD* )&p[ sizeof(DWORD) ] = BLOCK_FREED;
+ *( DWORD* )&p[ size + sizeof(DWORD)*2 ] = BLOCK_FREED;
+ free( p );
+}
+
+/******************************************************************************/
+
+char* mir_strdup( const char* str )
+{
+ if ( str != NULL ) {
+ char* p = mir_alloc( strlen( str )+1 );
+ if ( p )
+ strcpy( p, str );
+ return p;
+ }
+ return NULL;
+}
+
+/******************************************************************************/
+
+WCHAR* mir_wstrdup( const WCHAR* str )
+{
+ if ( str != NULL ) {
+ WCHAR* p = mir_alloc( sizeof( WCHAR )*( wcslen( str )+1 ));
+ if ( p )
+ wcscpy( p, str );
+ return p;
+ }
+ return NULL;
+}
diff --git a/miranda-wine/src/core/miranda.c b/miranda-wine/src/core/miranda.c
new file mode 100644
index 0000000..f003ecf
--- /dev/null
+++ b/miranda-wine/src/core/miranda.c
@@ -0,0 +1,565 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "../modules/database/dblists.h"
+
+int InitialiseModularEngine(void);
+void DestroyingModularEngine(void);
+void DestroyModularEngine(void);
+int UnloadNewPluginsModule(void);
+
+HINSTANCE GetInstByAddress( void* codePtr );
+
+DWORD (WINAPI *MyMsgWaitForMultipleObjectsEx)(DWORD,CONST HANDLE*,DWORD,DWORD,DWORD);
+static DWORD MsgWaitForMultipleObjectsExWorkaround(DWORD nCount, const HANDLE *pHandles,
+ DWORD dwMsecs, DWORD dwWakeMask, DWORD dwFlags);
+
+static HANDLE hOkToExitEvent,hModulesLoadedEvent;
+HANDLE hShutdownEvent,hPreShutdownEvent;
+static HANDLE hWaitObjects[MAXIMUM_WAIT_OBJECTS-1];
+static char *pszWaitServices[MAXIMUM_WAIT_OBJECTS-1];
+static int waitObjectCount=0;
+HANDLE hStackMutex,hMirandaShutdown,hThreadQueueEmpty;
+
+struct THREAD_WAIT_ENTRY {
+ DWORD dwThreadId; // valid if hThread isn't signalled
+ HANDLE hThread;
+ HINSTANCE hOwner;
+};
+
+struct THREAD_WAIT_ENTRY *WaitingThreads=NULL;
+int WaitingThreadsCount=0;
+
+struct FORK_ARG {
+ HANDLE hEvent;
+ void (__cdecl *threadcode)(void*);
+ unsigned (__stdcall *threadcodeex)(void*);
+ void *arg;
+};
+
+void __cdecl forkthread_r(void * arg)
+{
+ struct FORK_ARG * fa = (struct FORK_ARG *) arg;
+ void (*callercode)(void*)=fa->threadcode;
+ void * cookie=fa->arg;
+ CallService(MS_SYSTEM_THREAD_PUSH,0,0);
+ SetEvent(fa->hEvent);
+ __try {
+ callercode(cookie);
+ } __finally {
+ 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);
+ } //if
+ CloseHandle(fa.hEvent);
+ return rc;
+}
+
+unsigned __stdcall forkthreadex_r(void * arg)
+{
+ struct FORK_ARG *fa=(struct FORK_ARG *)arg;
+ unsigned (__stdcall * threadcode) (void *)=fa->threadcodeex;
+ void *cookie=fa->arg;
+ unsigned long rc;
+
+ CallService(MS_SYSTEM_THREAD_PUSH,0,0);
+ SetEvent(fa->hEvent);
+ __try {
+ rc=threadcode(cookie);
+ } __finally {
+ 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,(void *)&fa,0,thraddr);
+ if (rc) {
+ WaitForSingleObject(fa.hEvent,INFINITE);
+ }
+ CloseHandle(fa.hEvent);
+ return rc;
+}
+
+static void __stdcall DummyAPCFunc(DWORD dwArg)
+{
+ /* called in the context of thread that cleared it's APC queue */
+ return;
+}
+
+static int MirandaWaitForMutex(HANDLE hEvent)
+{
+ for (;;) {
+ // will get WAIT_IO_COMPLETE for QueueUserAPC() which isnt a result
+ DWORD rc=MsgWaitForMultipleObjectsExWorkaround(1, &hEvent, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE);
+ if ( rc == WAIT_OBJECT_0 + 1 ) {
+ MSG msg;
+ while ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) {
+ if ( IsDialogMessage(msg.hwnd, &msg) ) continue;
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ } else if ( rc==WAIT_OBJECT_0 ) {
+ // got object
+ return 1;
+ } else if ( rc==WAIT_ABANDONED_0 || rc == WAIT_FAILED ) return 0;
+ }
+}
+
+VOID CALLBACK KillAllThreads(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
+{
+ if ( MirandaWaitForMutex( hStackMutex )) {
+ int j;
+ for ( j=0; j < WaitingThreadsCount; j++ ) {
+ char szModuleName[ MAX_PATH ];
+ GetModuleFileNameA( WaitingThreads[j].hOwner, szModuleName, sizeof(szModuleName));
+ Netlib_Logf( NULL, "Thread %08x was abnormally terminated because module '%s' didn't released it",
+ WaitingThreads[j].hThread, szModuleName );
+ TerminateThread( WaitingThreads[j].hThread, 9999 );
+ }
+
+ ReleaseMutex(hStackMutex);
+ SetEvent(hThreadQueueEmpty);
+} }
+
+static void UnwindThreadWait(void)
+{
+ // acquire the list and wake up any alertable threads
+ if ( MirandaWaitForMutex(hStackMutex) ) {
+ int j;
+ for (j=0;j<WaitingThreadsCount;j++)
+ QueueUserAPC(DummyAPCFunc,WaitingThreads[j].hThread, 0);
+ ReleaseMutex(hStackMutex);
+ }
+
+ // give all unclosed threads 5 seconds to close
+ SetTimer( NULL, 0, 5000, KillAllThreads );
+
+ // wait til the thread list is empty
+ MirandaWaitForMutex(hThreadQueueEmpty);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+typedef LONG (WINAPI *pNtQIT)(HANDLE, LONG, PVOID, ULONG, PULONG);
+#define ThreadQuerySetWin32StartAddress 9
+
+void* GetCurrentThreadEntryPoint()
+{
+ LONG ntStatus;
+ HANDLE hDupHandle, hCurrentProcess;
+ DWORD dwStartAddress;
+
+ pNtQIT NtQueryInformationThread = (pNtQIT)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "NtQueryInformationThread" );
+ if(NtQueryInformationThread == NULL) return 0;
+
+ hCurrentProcess = GetCurrentProcess();
+ if(!DuplicateHandle(hCurrentProcess, GetCurrentThread(), hCurrentProcess, &hDupHandle, THREAD_QUERY_INFORMATION, FALSE, 0)){
+ SetLastError(ERROR_ACCESS_DENIED);
+ return NULL;
+ }
+ ntStatus = NtQueryInformationThread(hDupHandle, ThreadQuerySetWin32StartAddress, &dwStartAddress, sizeof(DWORD), NULL);
+ CloseHandle(hDupHandle);
+
+ if(ntStatus != ERROR_SUCCESS) return 0;
+ return ( void* )dwStartAddress;
+}
+
+int UnwindThreadPush(WPARAM wParam,LPARAM lParam)
+{
+ ResetEvent(hThreadQueueEmpty); // thread list is not empty
+ if (WaitForSingleObject(hStackMutex,INFINITE)==WAIT_OBJECT_0)
+ {
+ HANDLE hThread=0;
+ DuplicateHandle(GetCurrentProcess(),GetCurrentThread(),GetCurrentProcess(),&hThread,THREAD_SET_CONTEXT,FALSE,0);
+ WaitingThreads=mir_realloc(WaitingThreads,sizeof(struct THREAD_WAIT_ENTRY)*(WaitingThreadsCount+1));
+ WaitingThreads[WaitingThreadsCount].hThread=hThread;
+ WaitingThreads[WaitingThreadsCount].dwThreadId=GetCurrentThreadId();
+ WaitingThreads[WaitingThreadsCount].hOwner=GetInstByAddress( GetCurrentThreadEntryPoint() );
+ WaitingThreadsCount++;
+#ifdef _DEBUG
+ {
+ char szBuf[64];
+ mir_snprintf(szBuf,SIZEOF(szBuf),"*** pushing thread (%x)\n",GetCurrentThreadId());
+ OutputDebugStringA(szBuf);
+ }
+#endif
+ ReleaseMutex(hStackMutex);
+ } //if
+ return 0;
+}
+
+int UnwindThreadPop(WPARAM wParam,LPARAM lParam)
+{
+ if (WaitForSingleObject(hStackMutex,INFINITE)==WAIT_OBJECT_0)
+ {
+ DWORD dwThreadId=GetCurrentThreadId();
+ int j;
+ for (j=0;j<WaitingThreadsCount;j++) {
+ if (WaitingThreads[j].dwThreadId == dwThreadId) {
+ CloseHandle(WaitingThreads[j].hThread);
+ WaitingThreadsCount--;
+ if (j<WaitingThreadsCount) memmove(&WaitingThreads[j],&WaitingThreads[j+1],(WaitingThreadsCount-j) * sizeof(struct THREAD_WAIT_ENTRY));
+ if (!WaitingThreadsCount)
+ {
+ mir_free(WaitingThreads);
+ WaitingThreads=NULL;
+ WaitingThreadsCount=0;
+ ReleaseMutex(hStackMutex);
+ SetEvent(hThreadQueueEmpty); // thread list is empty now
+ return 0;
+ } else {
+ WaitingThreads=mir_realloc(WaitingThreads,sizeof(struct THREAD_WAIT_ENTRY)*WaitingThreadsCount);
+ } //if
+ ReleaseMutex(hStackMutex);
+ return 0;
+ } //if
+ } //for
+ ReleaseMutex(hStackMutex);
+ } //if
+ return 1;
+}
+
+int MirandaIsTerminated(WPARAM wParam,LPARAM lParam)
+{
+ return WaitForSingleObject(hMirandaShutdown,0)==WAIT_OBJECT_0;
+}
+
+static void __cdecl compactHeapsThread(void *dummy)
+{
+ while (!Miranda_Terminated())
+ {
+ HANDLE hHeaps[256];
+ DWORD hc;
+ SleepEx((1000*60)*5,TRUE); // every 5 minutes
+ hc=GetProcessHeaps(255,(PHANDLE)&hHeaps);
+ if (hc != 0 && hc < 256) {
+ DWORD j;
+ for (j=0;j<hc;j++) HeapCompact(hHeaps[j],0);
+ }
+ } //while
+}
+
+static void InsertRegistryKey(void)
+{
+ if(DBGetContactSettingByte(NULL,"_Sys","CreateRegKey",1)) {
+ HKEY hKey;
+ DWORD dw;
+ if(RegCreateKeyExA(HKEY_LOCAL_MACHINE,"SOFTWARE\\Miranda",0,NULL,0,KEY_CREATE_SUB_KEY|KEY_SET_VALUE,NULL,&hKey,&dw)==ERROR_SUCCESS) {
+ char str[MAX_PATH],*str2;
+ GetModuleFileNameA(NULL,str,SIZEOF(str));
+ str2=strrchr(str,'\\');
+ if(str2!=NULL) *str2=0;
+ RegSetValueExA(hKey,"Install_Dir",0,REG_SZ,(PBYTE)str,lstrlenA(str)+1);
+ RegCloseKey(hKey);
+ }
+ }
+}
+
+DWORD CALLBACK APCWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (msg==WM_NULL) SleepEx(0,TRUE);
+ return DefWindowProc(hwnd,msg,wParam,lParam);
+}
+
+HWND hAPCWindow=NULL;
+void (*SetIdleCallback) (void)=NULL;
+
+static int SystemSetIdleCallback(WPARAM wParam, LPARAM lParam)
+{
+ if (lParam && SetIdleCallback==NULL) {
+ SetIdleCallback=(void (*)(void))lParam;
+ return 1;
+ }
+ return 0;
+}
+
+static DWORD dwEventTime=0;
+void checkIdle(MSG * msg)
+{
+ switch(msg->message) {
+ case WM_MOUSEACTIVATE:
+ case WM_MOUSEMOVE:
+ case WM_CHAR:
+ {
+ dwEventTime = GetTickCount();
+ }
+ }
+}
+
+static int SystemGetIdle(WPARAM wParam, LPARAM lParam)
+{
+ if ( lParam ) *(DWORD*)lParam = dwEventTime;
+ return 0;
+}
+
+static DWORD MsgWaitForMultipleObjectsExWorkaround(DWORD nCount, const HANDLE *pHandles,
+ DWORD dwMsecs, DWORD dwWakeMask, DWORD dwFlags)
+{
+ DWORD rc;
+ if ( MyMsgWaitForMultipleObjectsEx != NULL )
+ return MyMsgWaitForMultipleObjectsEx(nCount, pHandles, dwMsecs, dwWakeMask, dwFlags);
+ rc=MsgWaitForMultipleObjects(nCount, pHandles, FALSE, 50, QS_ALLINPUT);
+ if ( rc == WAIT_TIMEOUT ) rc=WaitForMultipleObjectsEx(nCount, pHandles, FALSE, 20, TRUE);
+ return rc;
+}
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
+{
+ DWORD myPid=0;
+ int messageloop=1;
+
+#ifdef _DEBUG
+ _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
+#endif
+
+ if (InitialiseModularEngine())
+ {
+ NotifyEventHooks(hShutdownEvent,0,0);
+ UnloadNewPluginsModule();
+ DestroyModularEngine();
+ return 1;
+ }
+ InsertRegistryKey();
+ NotifyEventHooks(hModulesLoadedEvent,0,0);
+ MyMsgWaitForMultipleObjectsEx=(DWORD (WINAPI *)(DWORD,CONST HANDLE*,DWORD,DWORD,DWORD))GetProcAddress(GetModuleHandleA("user32"),"MsgWaitForMultipleObjectsEx");
+ forkthread(compactHeapsThread,0,NULL);
+ CreateServiceFunction(MS_SYSTEM_SETIDLECALLBACK,SystemSetIdleCallback);
+ CreateServiceFunction(MS_SYSTEM_GETIDLE, SystemGetIdle);
+ dwEventTime=GetTickCount();
+ myPid=GetCurrentProcessId();
+ for(;messageloop;) {
+ MSG msg;
+ DWORD rc;
+ BOOL dying=FALSE;
+ rc=MsgWaitForMultipleObjectsExWorkaround(waitObjectCount, hWaitObjects, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE);
+ if ( rc >= WAIT_OBJECT_0 && rc < WAIT_OBJECT_0 + waitObjectCount) {
+ rc -= WAIT_OBJECT_0;
+ CallService(pszWaitServices[rc], (WPARAM) hWaitObjects[rc], 0);
+ }
+ //
+ while ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) {
+ if ( msg.message != WM_QUIT ) {
+ HWND h=GetForegroundWindow();
+ DWORD pid = 0;
+ checkIdle(&msg);
+ if ( h != NULL && GetWindowThreadProcessId(h,&pid) && pid==myPid
+ && GetClassLong(h, GCW_ATOM)==32770 ) {
+ if ( IsDialogMessage(h, &msg) ) continue;
+ }
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ if ( SetIdleCallback != NULL )
+ SetIdleCallback();
+ } else if ( !dying ) {
+ dying++;
+ SetEvent(hMirandaShutdown);
+ NotifyEventHooks(hPreShutdownEvent, 0, 0);
+ DestroyingModularEngine();
+ // this spins and processes the msg loop, objects and APC.
+ UnwindThreadWait();
+ NotifyEventHooks(hShutdownEvent, 0, 0);
+ // if the hooks generated any messages, it'll get processed before the second WM_QUIT
+ PostQuitMessage(0);
+ } else if ( dying ) {
+ messageloop=0;
+ }
+ } // while
+ }
+ UnloadNewPluginsModule();
+ DestroyModularEngine();
+ CloseHandle(hStackMutex);
+ CloseHandle(hMirandaShutdown);
+ CloseHandle(hThreadQueueEmpty);
+ DestroyWindow(hAPCWindow);
+ return 0;
+}
+
+static int SystemShutdownProc(WPARAM wParam,LPARAM lParam)
+{
+ return 0;
+}
+
+static int OkToExit(WPARAM wParam,LPARAM lParam)
+{
+ return NotifyEventHooks(hOkToExitEvent,0,0)==0;
+}
+
+static int GetMirandaVersion(WPARAM wParam,LPARAM lParam)
+{
+ char filename[MAX_PATH];
+ DWORD unused;
+ DWORD verInfoSize;
+ UINT blockSize;
+ PVOID pVerInfo;
+ VS_FIXEDFILEINFO *vsffi;
+ DWORD ver;
+
+ GetModuleFileNameA(NULL,filename,SIZEOF(filename));
+ verInfoSize=GetFileVersionInfoSizeA(filename,&unused);
+ pVerInfo=mir_alloc(verInfoSize);
+ GetFileVersionInfoA(filename,0,verInfoSize,pVerInfo);
+ VerQueryValueA(pVerInfo,"\\",(PVOID*)&vsffi,&blockSize);
+ ver=(((vsffi->dwProductVersionMS>>16)&0xFF)<<24)|
+ ((vsffi->dwProductVersionMS&0xFF)<<16)|
+ (((vsffi->dwProductVersionLS>>16)&0xFF)<<8)|
+ (vsffi->dwProductVersionLS&0xFF);
+ mir_free(pVerInfo);
+ return (int)ver;
+}
+
+static int GetMirandaVersionText(WPARAM wParam,LPARAM lParam)
+{
+ char filename[MAX_PATH],*productVersion;
+ DWORD unused;
+ DWORD verInfoSize;
+ UINT blockSize;
+ PVOID pVerInfo;
+
+ GetModuleFileNameA(NULL,filename,SIZEOF(filename));
+ verInfoSize=GetFileVersionInfoSizeA(filename,&unused);
+ pVerInfo=mir_alloc(verInfoSize);
+ GetFileVersionInfoA(filename,0,verInfoSize,pVerInfo);
+ VerQueryValueA(pVerInfo,"\\StringFileInfo\\000004b0\\ProductVersion",(void*)&productVersion,&blockSize);
+ #if defined( _UNICODE )
+ mir_snprintf(( char* )lParam, wParam, "%s Unicode", productVersion );
+ #else
+ lstrcpynA((char*)lParam,productVersion,wParam);
+ #endif
+ mir_free(pVerInfo);
+ return 0;
+}
+
+int WaitOnHandle(WPARAM wParam,LPARAM lParam)
+{
+ if(waitObjectCount>=MAXIMUM_WAIT_OBJECTS-1) return 1;
+ hWaitObjects[waitObjectCount]=(HANDLE)wParam;
+ pszWaitServices[waitObjectCount]=(char*)lParam;
+ waitObjectCount++;
+ return 0;
+}
+
+static int RemoveWait(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+
+ for(i=0;i<waitObjectCount;i++)
+ if(hWaitObjects[i]==(HANDLE)wParam) break;
+ if(i==waitObjectCount) return 1;
+ waitObjectCount--;
+ MoveMemory(&hWaitObjects[i],&hWaitObjects[i+1],sizeof(HANDLE)*(waitObjectCount-i));
+ MoveMemory(&pszWaitServices[i],&pszWaitServices[i+1],sizeof(char*)*(waitObjectCount-i));
+ return 0;
+}
+
+int GetMemoryManagerInterface(WPARAM wParam, LPARAM lParam)
+{
+ struct MM_INTERFACE *mmi = (struct MM_INTERFACE*) lParam;
+ if (mmi || mmi->cbSize == sizeof(struct MM_INTERFACE))
+ {
+ mmi->mmi_malloc = mir_alloc;
+ mmi->mmi_realloc = mir_realloc;
+ mmi->mmi_free = mir_free;
+ return 0;
+ }
+ return 1;
+}
+
+int GetListInterface(WPARAM wParam, LPARAM lParam)
+{
+ struct LIST_INTERFACE *li = (struct LIST_INTERFACE*) lParam;
+ if (li || li->cbSize == sizeof(struct LIST_INTERFACE))
+ {
+ li->List_Create = List_Create;
+ li->List_Destroy = List_Destroy;
+ li->List_Find = List_Find;
+ li->List_GetIndex = List_GetIndex;
+ li->List_Insert = List_Insert;
+ li->List_Remove = List_Remove;
+ li->List_IndexOf = List_IndexOf;
+ return 0;
+ }
+ return 1;
+}
+
+int LoadSystemModule(void)
+{
+ InitCommonControls();
+
+ hAPCWindow=CreateWindowEx(0,_T("STATIC"),NULL,0, 0,0,0,0, NULL,NULL,NULL,NULL); // lame
+ SetWindowLong(hAPCWindow,GWL_WNDPROC,(LONG)APCWndProc);
+ hStackMutex=CreateMutex(NULL,FALSE,NULL);
+ hMirandaShutdown=CreateEvent(NULL,TRUE,FALSE,NULL);
+ hThreadQueueEmpty=CreateEvent(NULL,TRUE,TRUE,NULL);
+
+ hShutdownEvent=CreateHookableEvent(ME_SYSTEM_SHUTDOWN);
+ hPreShutdownEvent=CreateHookableEvent(ME_SYSTEM_PRESHUTDOWN);
+ hModulesLoadedEvent=CreateHookableEvent(ME_SYSTEM_MODULESLOADED);
+ hOkToExitEvent=CreateHookableEvent(ME_SYSTEM_OKTOEXIT);
+
+ HookEvent(ME_SYSTEM_SHUTDOWN,SystemShutdownProc);
+
+ CreateServiceFunction(MS_SYSTEM_THREAD_PUSH,UnwindThreadPush);
+ CreateServiceFunction(MS_SYSTEM_THREAD_POP,UnwindThreadPop);
+ CreateServiceFunction(MS_SYSTEM_TERMINATED,MirandaIsTerminated);
+ CreateServiceFunction(MS_SYSTEM_OKTOEXIT,OkToExit);
+ CreateServiceFunction(MS_SYSTEM_GETVERSION,GetMirandaVersion);
+ CreateServiceFunction(MS_SYSTEM_GETVERSIONTEXT,GetMirandaVersionText);
+ CreateServiceFunction(MS_SYSTEM_WAITONHANDLE,WaitOnHandle);
+ CreateServiceFunction(MS_SYSTEM_REMOVEWAIT,RemoveWait);
+ CreateServiceFunction(MS_SYSTEM_GET_LI,GetListInterface);
+ CreateServiceFunction(MS_SYSTEM_GET_MMI,GetMemoryManagerInterface);
+ return 0;
+}
diff --git a/miranda-wine/src/core/miranda.h b/miranda-wine/src/core/miranda.h
new file mode 100644
index 0000000..af80535
--- /dev/null
+++ b/miranda-wine/src/core/miranda.h
@@ -0,0 +1,48 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/**** memory.c *************************************************************************/
+
+void* mir_alloc( size_t );
+void* mir_calloc( size_t );
+void* mir_realloc( void* ptr, size_t );
+void mir_free( void* ptr );
+char* mir_strdup( const char* str );
+WCHAR* mir_wstrdup( const WCHAR* str );
+
+#if defined( _UNICODE )
+ #define mir_tstrdup mir_wstrdup
+#else
+ #define mir_tstrdup mir_strdup
+#endif
+
+/**** utf.c ****************************************************************************/
+
+void Utf8Decode( char* str, wchar_t** ucs2 );
+
+/**** langpack.c ***********************************************************************/
+
+int LangPackGetDefaultCodePage();
+int LangPackGetDefaultLocale();
+TCHAR* LangPackPcharToTchar( const char* pszStr );
+char* LangPackTranslateString(const char *szEnglish, const int W);
diff --git a/miranda-wine/src/core/modules.c b/miranda-wine/src/core/modules.c
new file mode 100644
index 0000000..dd180fe
--- /dev/null
+++ b/miranda-wine/src/core/modules.c
@@ -0,0 +1,656 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include <m_plugins.h>
+
+typedef struct {
+ MIRANDAHOOK pfnHook;
+ HINSTANCE hOwner;
+ HWND hwnd;
+ UINT message;
+} THookSubscriber;
+
+typedef struct {
+ char name[MAXMODULELABELLENGTH];
+ DWORD hookHash;
+ int subscriberCount;
+ THookSubscriber *subscriber;
+ MIRANDAHOOK pfnHook;
+} THookList;
+
+typedef struct {
+ char name[MAXMODULELABELLENGTH];
+ DWORD nameHash;
+ HINSTANCE hOwner;
+ MIRANDASERVICE pfnService;
+} TServiceList;
+
+typedef struct {
+ int hookId;
+ HANDLE hDoneEvent;
+ WPARAM wParam;
+ LPARAM lParam;
+ int result;
+} THookToMainThreadItem;
+
+typedef struct {
+ HANDLE hDoneEvent;
+ WPARAM wParam;
+ LPARAM lParam;
+ int result;
+ const char *name;
+} TServiceToMainThreadItem;
+
+static THookList *hook;
+static TServiceList *service;
+static int hookCount,serviceCount;
+static CRITICAL_SECTION csHooks,csServices;
+static DWORD mainThreadId;
+static HANDLE hMainThread;
+static HANDLE hMissingService;
+
+HINSTANCE GetInstByAddress( void* codePtr );
+
+int LoadSystemModule(void); // core: m_system.h services
+int LoadNewPluginsModuleInfos(void); // core: preloading plugins
+int LoadNewPluginsModule(void); // core: N.O. plugins
+int LoadNetlibModule(void); // core: network
+int LoadLangPackModule(void); // core: translation
+int LoadProtocolsModule(void); // core: protocol manager
+int LoadIgnoreModule(void); // protocol filter: ignore
+
+int LoadSendRecvUrlModule(void); //send/recv
+int LoadSendRecvEMailModule(void); //send/recv
+int LoadSendRecvAuthModule(void); //send/recv
+int LoadSendRecvFileModule(void); //send/recv
+
+int LoadContactListModule(void);// ui: clist
+int LoadOptionsModule(void); // ui: options dialog
+int LoadFindAddModule(void); // ui: search/add users
+int LoadSkinModule(void); // ui: skin
+int LoadHelpModule(void); // ui: help stuff
+int LoadUserInfoModule(void); // ui: user info
+int LoadHistoryModule(void); // ui: history viewer
+int LoadAwayMsgModule(void); // ui: setting away messages
+int LoadVisibilityModule(void); // ui: visibility control
+int LoadCLUIModule(void); // ui: CList UI
+int LoadPluginOptionsModule(void); // ui: plugin viewer
+int LoadAddContactModule(void); // ui: authcontrol contacts
+int LoadIdleModule(void); // rnd: report idle information
+int LoadAutoAwayModule(void); // ui: away
+int LoadUserOnlineModule(void); // ui: online alert
+int LoadUtilsModule(void); // ui: utils (has a few window classes, like HyperLink)
+int LoadCLCModule(void); // window class: CLC control
+int LoadButtonModule(void); // window class: button class
+int LoadContactsModule(void); // random: contact
+
+static int LoadDefaultModules(void)
+{
+ int *disableDefaultModule = 0;
+
+ //load order is very important for these
+ if(LoadSystemModule()) return 1;
+ if(LoadLangPackModule()) return 1; // langpack will be a system module in the new order so this is moved 'ere
+ if(LoadUtilsModule()) return 1; //order not important for this, but no dependencies and no point in pluginising
+ if(LoadNewPluginsModuleInfos()) return 1;
+ if(LoadProtocolsModule()) return 1;
+ if(LoadSkinModule()) return 1;
+ if(LoadButtonModule()) return 1;
+ if(LoadOptionsModule()) return 1;
+ if(LoadContactsModule()) return 1;
+ if(LoadContactListModule()) return 1;
+ if(LoadAddContactModule()) return 1;
+ if(LoadNewPluginsModule()) return 1; // will call Load() on everything, clist will load first
+
+ //this info will be available at LoadNewPluginsModule()
+ disableDefaultModule=(int*)CallService(MS_PLUGINS_GETDISABLEDEFAULTARRAY,0,0);
+ if(!disableDefaultModule[DEFMOD_PROTOCOLNETLIB]) if(LoadNetlibModule()) return 1;
+ //order becomes less important below here
+ if(!disableDefaultModule[DEFMOD_UIFINDADD]) if(LoadFindAddModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_UIUSERINFO]) if(LoadUserInfoModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_SRURL]) if(LoadSendRecvUrlModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_SREMAIL]) if(LoadSendRecvEMailModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_SRAUTH]) if(LoadSendRecvAuthModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_SRFILE]) if(LoadSendRecvFileModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_UIHELP]) if(LoadHelpModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_UIHISTORY]) if(LoadHistoryModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_RNDIDLE]) if(LoadIdleModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_RNDAUTOAWAY]) if(LoadAutoAwayModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_RNDUSERONLINE]) if(LoadUserOnlineModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_SRAWAY]) if(LoadAwayMsgModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_RNDIGNORE]) if(LoadIgnoreModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_UIVISIBILITY]) if(LoadVisibilityModule()) return 1;
+ //if(!disableDefaultModule[DEFMOD_UIPLUGINOPTS]) if(LoadPluginOptionsModule()) return 1;
+ return 0;
+}
+
+int InitialiseModularEngine(void)
+{
+ hookCount=serviceCount=0;
+ hook=NULL;
+ service=NULL;
+ InitializeCriticalSection(&csHooks);
+ InitializeCriticalSection(&csServices);
+
+ mainThreadId=GetCurrentThreadId();
+ DuplicateHandle(GetCurrentProcess(),GetCurrentThread(),GetCurrentProcess(),&hMainThread,THREAD_SET_CONTEXT,FALSE,0);
+
+ hMissingService = CreateHookableEvent(ME_SYSTEM_MISSINGSERVICE);
+ return LoadDefaultModules();
+}
+
+void DestroyingModularEngine(void)
+{
+ return;
+}
+
+void DestroyModularEngine(void)
+{
+ int i;
+ for(i=0;i<hookCount;i++)
+ if(hook[i].subscriberCount) mir_free(hook[i].subscriber);
+ if(hookCount) mir_free(hook);
+ if(serviceCount) mir_free(service);
+ DeleteCriticalSection(&csHooks);
+ DeleteCriticalSection(&csServices);
+ CloseHandle(hMainThread);
+}
+
+
+#if __GNUC__
+#define NOINLINEASM
+#endif
+
+DWORD NameHashFunction(const char *szStr)
+{
+#if defined _M_IX86 && !defined _NUMEGA_BC_FINALCHECK && !defined NOINLINEASM
+ __asm { //this breaks if szStr is empty
+ xor edx,edx
+ xor eax,eax
+ mov esi,szStr
+ mov al,[esi]
+ xor cl,cl
+ lph_top: //only 4 of 9 instructions in here don't use AL, so optimal pipe use is impossible
+ xor edx,eax
+ inc esi
+ xor eax,eax
+ and cl,31
+ mov al,[esi]
+ add cl,5
+ test al,al
+ rol eax,cl //rol is u-pipe only, but pairable
+ //rol doesn't touch z-flag
+ jnz lph_top //5 clock tick loop. not bad.
+
+ xor eax,edx
+ }
+#else
+ DWORD hash=0;
+ int i;
+ int shift=0;
+ for(i=0;szStr[i];i++) {
+ hash^=szStr[i]<<shift;
+ if(shift>24) hash^=(szStr[i]>>(32-shift))&0x7F;
+ shift=(shift+5)&0x1F;
+ }
+ return hash;
+#endif
+}
+
+///////////////////////////////HOOKS
+
+static int FindHookByName(const char *name)
+{
+ int i;
+
+ for(i=0;i<hookCount;i++)
+ if(!strcmp(hook[i].name,name)) return i;
+ return -1;
+}
+
+static int FindHookByHashAndName(DWORD Hash, const char *name)
+{
+ int i;
+ for (i=0; i<hookCount; i++)
+ if (hook[i].hookHash==Hash)
+ {
+ if (!strcmp(hook[i].name, name)) return i;
+ }
+ return -1;
+}
+
+HANDLE CreateHookableEvent(const char *name)
+{
+ DWORD Hash = NameHashFunction(name);
+ HANDLE ret;
+
+ EnterCriticalSection(&csHooks);
+ //if(FindHookByName(name)!=-1) {LeaveCriticalSection(&csHooks); return NULL;}
+ if (FindHookByHashAndName(Hash, name) != -1)
+ {
+ LeaveCriticalSection(&csHooks);
+ return NULL;
+ }
+ hook=(THookList*)mir_realloc(hook,sizeof(THookList)*(hookCount+1));
+ strcpy(hook[hookCount].name,name);
+ hook[hookCount].hookHash=Hash;
+ hook[hookCount].subscriberCount=0;
+ hook[hookCount].subscriber=NULL;
+ hook[hookCount].pfnHook=NULL;
+ hookCount++;
+ ret=(HANDLE)hookCount;
+ LeaveCriticalSection(&csHooks);
+ return ret;
+}
+
+int DestroyHookableEvent(HANDLE hEvent)
+{
+ int hookId=(int)hEvent-1;
+ EnterCriticalSection(&csHooks);
+ if(hookId>=hookCount || hookId<0) {LeaveCriticalSection(&csHooks); return 1;}
+ if(hook[hookId].name[0]==0) {LeaveCriticalSection(&csHooks); return 1;}
+ hook[hookId].name[0]=0;
+ if(hook[hookId].subscriberCount) {
+ mir_free(hook[hookId].subscriber);
+ hook[hookId].subscriber=NULL;
+ hook[hookId].subscriberCount=0;
+ }
+ LeaveCriticalSection(&csHooks);
+ return 0;
+}
+
+int SetHookDefaultForHookableEvent(HANDLE hEvent, MIRANDAHOOK pfnHook)
+{
+ int hookId = (int) hEvent - 1;
+ if ( hookId < 0 || hookId >= hookCount ) return 1;
+ EnterCriticalSection(&csHooks);
+ hook[hookId].pfnHook = pfnHook;
+ LeaveCriticalSection(&csHooks);
+ return 0;
+}
+
+static int CallHookSubscribers(int hookId,WPARAM wParam,LPARAM lParam)
+{
+ int i,returnVal=0;
+
+ EnterCriticalSection(&csHooks);
+ if(hookId>=hookCount || hookId<0 || hook[hookId].name[0]==0) returnVal=-1;
+ else {
+ //NOTE: We've got the critical section while all this lot are called. That's mostly safe, though.
+ for(i=0;i<hook[hookId].subscriberCount;i++) {
+ if(hook[hookId].subscriber[i].pfnHook!=NULL) {
+ returnVal=hook[hookId].subscriber[i].pfnHook(wParam,lParam);
+ if( returnVal ) break;
+ }
+ else if(hook[hookId].subscriber[i].hwnd!=NULL) {
+ returnVal=SendMessage(hook[hookId].subscriber[i].hwnd,hook[hookId].subscriber[i].message,wParam,lParam);
+ if( returnVal ) break;
+ }//if
+ }//for
+ // check for no hooks and call the default hook if any
+ if ( hook[hookId].subscriberCount == 0 && hook[hookId].pfnHook != 0 ) returnVal = hook[hookId].pfnHook(wParam,lParam);
+ }
+ LeaveCriticalSection(&csHooks);
+ return returnVal;
+}
+
+static void CALLBACK HookToMainAPCFunc(DWORD dwParam)
+{
+ THookToMainThreadItem *item=(THookToMainThreadItem*)dwParam;
+
+ item->result=CallHookSubscribers(item->hookId,item->wParam,item->lParam);
+ SetEvent(item->hDoneEvent);
+ return;
+}
+
+int NotifyEventHooks(HANDLE hEvent,WPARAM wParam,LPARAM lParam)
+{
+ extern HWND hAPCWindow;
+
+ if(GetCurrentThreadId()!=mainThreadId) {
+ THookToMainThreadItem item;
+
+ item.hDoneEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
+ item.hookId=(int)hEvent-1;
+ item.wParam=wParam;
+ item.lParam=lParam;
+
+ QueueUserAPC(HookToMainAPCFunc,hMainThread,(DWORD)&item);
+ PostMessage(hAPCWindow,WM_NULL,0,0); // let it process APC even if we're in a common dialog
+ WaitForSingleObject(item.hDoneEvent,INFINITE);
+ CloseHandle(item.hDoneEvent);
+ return item.result;
+ }
+ else
+ return CallHookSubscribers((int)hEvent-1,wParam,lParam);
+}
+
+HANDLE HookEvent(const char *name,MIRANDAHOOK hookProc)
+{
+ int hookId;
+ HANDLE ret;
+
+ EnterCriticalSection(&csHooks);
+ hookId=FindHookByName(name);
+ if(hookId==-1) {
+#ifdef _DEBUG
+ OutputDebugStringA("Attempt to hook: \t");
+ OutputDebugStringA(name);
+ OutputDebugStringA("\n");
+#endif
+ LeaveCriticalSection(&csHooks);
+ return NULL;
+ }
+ hook[hookId].subscriber=(THookSubscriber*)mir_realloc(hook[hookId].subscriber,sizeof(THookSubscriber)*(hook[hookId].subscriberCount+1));
+ hook[hookId].subscriber[hook[hookId].subscriberCount].pfnHook = hookProc;
+ hook[hookId].subscriber[hook[hookId].subscriberCount].hOwner = GetInstByAddress(hookProc);
+ hook[hookId].subscriber[hook[hookId].subscriberCount].hwnd = NULL;
+ hook[hookId].subscriberCount++;
+
+ ret=(HANDLE)((hookId<<16)|hook[hookId].subscriberCount);
+ LeaveCriticalSection(&csHooks);
+ return ret;
+}
+
+HANDLE HookEventMessage(const char *name,HWND hwnd,UINT message)
+{
+ int hookId;
+ HANDLE ret;
+
+ EnterCriticalSection(&csHooks);
+ hookId=FindHookByName(name);
+ if(hookId==-1) {
+#ifdef _DEBUG
+ MessageBoxA(NULL,"Attempt to hook non-existant event",name,MB_OK);
+#endif
+ LeaveCriticalSection(&csHooks);
+ return NULL;
+ }
+ hook[hookId].subscriber=(THookSubscriber*)mir_realloc(hook[hookId].subscriber,sizeof(THookSubscriber)*(hook[hookId].subscriberCount+1));
+ hook[hookId].subscriber[hook[hookId].subscriberCount].pfnHook=NULL;
+ hook[hookId].subscriber[hook[hookId].subscriberCount].hwnd=hwnd;
+ hook[hookId].subscriber[hook[hookId].subscriberCount].message=message;
+ hook[hookId].subscriberCount++;
+ ret=(HANDLE)((hookId<<16)|hook[hookId].subscriberCount);
+ LeaveCriticalSection(&csHooks);
+ return ret;
+}
+
+int UnhookEvent(HANDLE hHook)
+{
+ int hookId=(int)hHook>>16;
+ int subscriberId=((int)hHook&0xFFFF)-1;
+
+ EnterCriticalSection(&csHooks);
+ if(hookId>=hookCount || hookId<0) {LeaveCriticalSection(&csHooks); return 1;}
+ if(hook[hookId].name[0]==0) {LeaveCriticalSection(&csHooks); return 1;}
+ if(subscriberId>=hook[hookId].subscriberCount || subscriberId<0) {LeaveCriticalSection(&csHooks); return 1;}
+ hook[hookId].subscriber[subscriberId].pfnHook=NULL;
+ hook[hookId].subscriber[subscriberId].hwnd=NULL;
+ while(hook[hookId].subscriberCount && hook[hookId].subscriber[hook[hookId].subscriberCount-1].pfnHook==NULL && hook[hookId].subscriber[hook[hookId].subscriberCount-1].hwnd==NULL)
+ hook[hookId].subscriberCount--;
+ if (hook[hookId].subscriberCount==0) {
+ if(hook[hookId].subscriber) mir_free(hook[hookId].subscriber);
+ hook[hookId].subscriber=NULL;
+ }
+ LeaveCriticalSection(&csHooks);
+ return 0;
+}
+
+void KillModuleEventHooks( HINSTANCE hInst )
+{
+ int i, j;
+
+ EnterCriticalSection(&csHooks);
+ for ( i = hookCount-1; i >= 0; i-- ) {
+ if ( hook[i].subscriberCount == 0 )
+ continue;
+
+ for ( j = hook[i].subscriberCount-1; j >= 0; j-- ) {
+ if ( hook[i].subscriber[j].hOwner == hInst ) {
+ char szModuleName[ MAX_PATH ];
+ GetModuleFileNameA( hook[i].subscriber[j].hOwner, szModuleName, sizeof(szModuleName));
+ Netlib_Logf( NULL, "A hook %08x for event '%s' was abnormally deleted because module '%s' didn't released it",
+ hook[i].subscriber[j].pfnHook, hook[i].name, szModuleName );
+ UnhookEvent(( HANDLE )(( i << 16 ) + j + 1 ));
+ if ( hook[i].subscriberCount == 0 )
+ break;
+ } } }
+
+ LeaveCriticalSection(&csHooks);
+}
+
+/////////////////////SERVICES
+
+static __inline TServiceList *FindServiceByHash(DWORD hash)
+{
+ int first,last,mid;
+
+ if(serviceCount==0) return NULL;
+ first=0; last=serviceCount-1;
+ if(hash>=service[last].nameHash) {
+ if(hash==service[last].nameHash) return &service[last];
+ return NULL;
+ }
+ for(;;) {
+ mid=(first+last)>>1;
+ if(hash>service[mid].nameHash) {
+ if(last-first<=1) break;
+ first=mid;
+ }
+ else if(hash<service[mid].nameHash) {
+ if(last-first<=1) break;
+ last=mid;
+ }
+ else return &service[mid];
+ }
+ return NULL;
+}
+
+static __inline TServiceList *FindServiceByName(const char *name)
+{
+ return FindServiceByHash(NameHashFunction(name));
+}
+
+/* assume critical section csServices is owned */
+static int FindHashForService(DWORD hash, int * shift)
+{
+ int i=0;
+ unsigned int mid = 0;
+ unsigned int min = 0;
+ unsigned int max = serviceCount - 1;
+ if (serviceCount==0) {
+ if (shift) *shift=0;
+ return 0;
+ }
+ if ( serviceCount > 0 && hash > service[serviceCount - 1].nameHash) {
+ if (shift) *shift = 0;
+ return serviceCount;
+ }
+ if ( serviceCount > 2 )
+ {
+ for ( ; (max - min) > 1 ; )
+ {
+ mid = ( min + max ) >> 1;
+ if ( hash > service[mid].nameHash ) min = mid;
+ else if ( hash < service[mid].nameHash ) max = mid;
+ else return -1;
+ } // for
+ i = mid - 1;
+ }
+ /* its O(N) but we might reduce it to M=(log2 N), then looking for the hash is only O(2) */
+ for(; i < serviceCount ; i++) {
+ if ( hash <= service[i].nameHash ) break;
+ }
+ return i;
+}
+
+HANDLE CreateServiceFunction(const char *name,MIRANDASERVICE serviceProc)
+{
+ DWORD hash;
+ int i;
+ int shift = 1;
+#ifdef _DEBUG
+ if (name==NULL) {
+ MessageBoxA(0,"Someone tried to create a NULL'd service, see call stack for more info","",0);
+ DebugBreak();
+ return NULL;
+ }
+#else
+ if (name==NULL) return NULL;
+#endif
+ hash=NameHashFunction(name);
+ EnterCriticalSection(&csServices);
+ i=FindHashForService(hash,&shift);
+ if (i==-1) {
+ LeaveCriticalSection(&csServices);
+ return NULL;
+ }
+ service=(TServiceList*)mir_realloc(service,sizeof(TServiceList)*(serviceCount+1));
+ if ( serviceCount > 0 && shift) MoveMemory(service+i+1,service+i,sizeof(TServiceList)*(serviceCount-i));
+ strncpy(service[i].name,name,sizeof(service[i].name));
+ service[i].nameHash = hash;
+ service[i].pfnService = serviceProc;
+ service[i].hOwner = GetInstByAddress( serviceProc );
+ serviceCount++;
+ LeaveCriticalSection(&csServices);
+ return (HANDLE)hash;
+}
+
+int DestroyServiceFunction(HANDLE hService)
+{
+ TServiceList *pService;
+ int i;
+
+ EnterCriticalSection(&csServices);
+ pService=FindServiceByHash((DWORD)hService);
+ if(pService==NULL) {LeaveCriticalSection(&csServices); return 1;}
+ i=(int)(pService-service);
+ MoveMemory(service+i,service+i+1,sizeof(TServiceList)*(--serviceCount-i));
+ LeaveCriticalSection(&csServices);
+ return 0;
+}
+
+int ServiceExists(const char *name)
+{
+ int ret;
+ EnterCriticalSection(&csServices);
+ ret=FindServiceByName(name)!=NULL;
+ LeaveCriticalSection(&csServices);
+ return ret;
+}
+
+int CallService(const char *name,WPARAM wParam,LPARAM lParam)
+{
+ TServiceList *pService;
+ MIRANDASERVICE pfnService;
+
+#ifdef _DEBUG
+ if (name==NULL) {
+ MessageBoxA(0,"Someone tried to CallService(NULL,..) see stack trace for details","",0);
+ DebugBreak();
+ return CALLSERVICE_NOTFOUND;
+ }
+#else
+ if (name==NULL) return CALLSERVICE_NOTFOUND;
+#endif
+
+ EnterCriticalSection(&csServices);
+ pService=FindServiceByName(name);
+ if(pService==NULL) {
+ LeaveCriticalSection(&csServices);
+#ifdef _DEBUG
+ //MessageBoxA(NULL,"Attempt to call non-existant service",name,MB_OK);
+ OutputDebugStringA("Missing service called: \t");
+ OutputDebugStringA(name);
+ OutputDebugStringA("\n");
+#endif
+/* { MISSING_SERVICE_PARAMS params = { name, wParam, lParam };
+ int result = NotifyEventHooks(hMissingService,0,(LPARAM)&params);
+ if (result != 0)
+ return params.lParam;
+ } */
+ return CALLSERVICE_NOTFOUND;
+ }
+ pfnService=pService->pfnService;
+ LeaveCriticalSection(&csServices);
+ return ((int (*)(WPARAM,LPARAM))pfnService)(wParam,lParam);
+}
+
+static void CALLBACK CallServiceToMainAPCFunc(DWORD dwParam)
+{
+ TServiceToMainThreadItem *item = (TServiceToMainThreadItem*) dwParam;
+ item->result = CallService(item->name, item->wParam, item->lParam);
+ SetEvent(item->hDoneEvent);
+}
+
+int CallServiceSync(const char *name, WPARAM wParam, LPARAM lParam)
+{
+
+ extern HWND hAPCWindow;
+
+ if (name==NULL) return CALLSERVICE_NOTFOUND;
+ // the service is looked up within the main thread, since the time it takes
+ // for the APC queue to clear the service being called maybe removed.
+ // even thou it may exists before the call, the critsec can't be locked between calls.
+ if (GetCurrentThreadId() != mainThreadId) {
+ TServiceToMainThreadItem item;
+ item.wParam = wParam;
+ item.lParam = lParam;
+ item.name = name;
+ item.hDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ QueueUserAPC(CallServiceToMainAPCFunc, hMainThread, (DWORD) &item);
+ PostMessage(hAPCWindow,WM_NULL,0,0); // let this get processed in its own time
+ WaitForSingleObject(item.hDoneEvent, INFINITE);
+ CloseHandle(item.hDoneEvent);
+ return item.result;
+ }
+
+ return CallService(name, wParam, lParam);
+}
+
+int CallFunctionAsync( void (__stdcall *func)(void *), void *arg)
+{
+ extern HWND hAPCWindow;
+ int r = 0;
+ r=QueueUserAPC((void (__stdcall *)(DWORD))func,hMainThread,(DWORD)arg);
+ PostMessage(hAPCWindow,WM_NULL,0,0);
+ return r;
+}
+
+void KillModuleServices( HINSTANCE hInst )
+{
+ int i;
+
+ EnterCriticalSection(&csServices);
+ for ( i = serviceCount-1; i >= 0; i-- ) {
+ if ( service[i].hOwner == hInst ) {
+ char szModuleName[ MAX_PATH ];
+ GetModuleFileNameA( service[i].hOwner, szModuleName, sizeof(szModuleName));
+ Netlib_Logf( NULL, "A service function '%s' was abnormally deleted because module '%s' didn't released it",
+ service[i].name, szModuleName );
+ DestroyServiceFunction(( HANDLE )service[i].nameHash );
+ } }
+
+ LeaveCriticalSection(&csServices);
+}
diff --git a/miranda-wine/src/core/modules.h b/miranda-wine/src/core/modules.h
new file mode 100644
index 0000000..4e488d3
--- /dev/null
+++ b/miranda-wine/src/core/modules.h
@@ -0,0 +1,184 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+//Modules Core - Richard
+#ifndef MODULES_H_
+#define MODULES_H_
+
+/* MAXMODULELABELLENGTH
+The maximum allowed length of a 'name' parameter. Very likely to change with
+restructuring modules.c for performance.
+*/
+#define MAXMODULELABELLENGTH 64
+
+typedef int (*MIRANDAHOOK)(WPARAM,LPARAM);
+typedef int (*MIRANDASERVICE)(WPARAM,LPARAM);
+
+/**************************hook functions****************************/
+/* CreateHookableEvent
+Adds an named event to the list and returns a handle referring to it, or NULL
+on failure. Will be automatically destroyed on exit, or can be removed from the
+list earlier using DestroyHookableEvent()
+Will fail if the given name has already been used
+*/
+HANDLE CreateHookableEvent(const char *name);
+
+/* DestroyHookableEvent
+Removes the event hEvent from the list of events. All modules hooked to it are
+automatically unhooked. NotifyEventHooks() will fail if called with this hEvent
+again. hEvent must have been returned by CreateHookableEvent()
+Returns 0 on success, or nonzero if hEvent is invalid
+*/
+int DestroyHookableEvent(HANDLE hEvent);
+
+/* NotifyEventHooks
+Calls every module in turn that has hooked hEvent, using the parameters wParam
+and lParam. hEvent must have been returned by CreateHookableEvent()
+Returns 0 on success
+ -1 if hEvent is invalid
+ If one of the hooks returned nonzero to indicate abort, returns that abort
+ value immediately, without calling the rest of the hooks in the chain
+
+Notes on calling NotifyEventHooks() from a thread other than that which owns
+the main Miranda window:
+It works. The call is routed to the main thread and all hook subcribers are
+called in the context of the main thread. The thread which called
+NotifyHookEvents() is paused until all the processing is complete at which
+point it returns with the correct return value.
+This procedure requires more than one wait object so naturally there are
+possibilities for deadlocks, but not many.
+Calling NotifyEventHooks() from other than the main thread will be
+considerably slower than from the main thread, but will consume only slightly
+more actual CPU time, the rest will mostly be spent waiting for the main thread
+to return to the message loop so it can be interrupted neatly.
+*/
+int NotifyEventHooks(HANDLE hEvent,WPARAM wParam,LPARAM lParam);
+
+/*
+ hEvent : a HANDLE which has been returned by CreateHookableEvent()
+ pfnHook: a function pointer (MIRANDAHOOK) which is called when there are no hooks.
+ Affect: This core service allows hooks to have a 'default' hook which is called
+ when no one has hooked the given event, this allows hook creators to add default
+ processing which is ONLY CALLED when no one else has HookEvent()'d
+ Notes: The return value from pfnHook() is returned to NotifyEventHooks()
+ Returns: 0 on success, non zero on failure
+ Version: 0.3.4+ (2004/09/15)
+*/
+int SetHookDefaultForHookableEvent(HANDLE hEvent, MIRANDAHOOK pfnHook);
+
+/* HookEvent
+Adds a new hook to the chain 'name', to be called when the hook owner calls
+NotifyEventHooks(). Returns NULL if name is not a valid event or a handle
+referring to the hook otherwise. Note that debug builds will warn with a
+MessageBoxA if a hook is attempted on an unknown event. All hooks will be
+automatically destroyed when their parent event is destroyed or the programme
+ends, but can be unhooked earlier using UnhookEvent(). hookProc() is defined as
+ int HookProc(WPARAM wParam,LPARAM lParam)
+where you can substitute your own name for HookProc. wParam and lParam are
+defined by the creator of the event when NotifyEventHooks() is called.
+The return value is 0 to continue processing the other hooks, or nonzero
+to stop immediately. This abort value is returned to the caller of
+NotifyEventHooks() and should not be -1 since that is a special return code
+for NotifyEventHooks() (see above)
+*/
+HANDLE HookEvent(const char *name,MIRANDAHOOK hookProc);
+
+/* HookEventMessage
+Works as for HookEvent(), except that when the notifier is called a message is
+sent to a window, rather than a function being called.
+Note that SendMessage() is a decidedly slow function so please limit use of
+this function to events that are not called frequently, or to hooks that are
+only installed briefly
+The window procedure is called with the message 'message' and the wParam and
+lParam given to NotifyEventHooks(). The return value of SendMessage() is used
+in the same way as the return value in HookEvent().
+*/
+HANDLE HookEventMessage(const char *name,HWND hwnd,UINT message);
+
+/* UnhookEvent
+Removes a hook from its event chain. It will no longer receive any events.
+hHook must have been returned by HookEvent() or HookEventMessage().
+Returns 0 on success or nonzero if hHook is invalid.
+*/
+int UnhookEvent(HANDLE hHook);
+
+
+/*************************service functions**************************/
+/* CreateServiceFunction
+Adds a new service function called 'name' to the global list and returns a
+handle referring to it. Service function handles are destroyed automatically
+on exit, but can be removed from the list earlier using
+DestroyServiceFunction()
+Returns NULL if name has already been used. serviceProc is defined by the
+caller as
+ int ServiceProc(WPARAM wParam,LPARAM lParam)
+where the creator publishes the meanings of wParam, lParam and the return value
+Service functions must not return CALLSERVICE_NOTFOUND since that would confuse
+callers of CallService().
+*/
+HANDLE CreateServiceFunction(const char *name,MIRANDASERVICE serviceProc);
+
+/* DestroyServiceFunction
+Removes the function associated with hService from the global service function
+list. Modules calling CallService() will fail if they try to call this
+service's name. hService must have been returned by CreateServiceFunction().
+Returns 0 on success or non-zero if hService is invalid.
+*/
+int DestroyServiceFunction(HANDLE hService);
+
+/* CallService
+Finds and calls the service function 'name' using the parameters wParam and
+lParam.
+Returns CALLSERVICE_NOTFOUND if no service function called 'name' has been
+created, or the value the service function returned otherwise.
+*/
+#define CALLSERVICE_NOTFOUND ((int)0x80000000)
+int CallService(const char *name,WPARAM wParam,LPARAM lParam);
+
+/* ServiceExists
+Finds if a service with the given name exists
+Returns nonzero if the service was found, and zero if it was not
+*/
+int ServiceExists(const char *name);
+
+/* CallServiceSync
+Calls a given service executed within the context of the main thread
+only useful to multi threaded modules calling thread unsafe services!
+*/
+int CallServiceSync(const char *name, WPARAM wParam, LPARAM lParam);
+
+/* CallFunctionAsync
+Calls a given function pointer, it doesn't go thru the core at all, it is
+just a wrapper around QueueUserAPC() and other workarounds to make APC
+work even if there are non APC message loops, this allows plugins who
+need this feature to get it without recoding it themselves.
+
+The function 'func' will always be called from the main thread in idle time even
+if it is invokved from a worker thread, 'arg' must not be on the stack.
+
+Returns nonzero on success, zero on failure
+
+added during 0.3.4+ (2004/08/14)
+*/
+int CallFunctionAsync( void (__stdcall *func)(void *), void *arg);
+
+#endif // MODULES_H_
diff --git a/miranda-wine/src/modules/addcontact/addcontact.c b/miranda-wine/src/modules/addcontact/addcontact.c
new file mode 100644
index 0000000..9c441f8
--- /dev/null
+++ b/miranda-wine/src/modules/addcontact/addcontact.c
@@ -0,0 +1,235 @@
+/*
+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.
+*/
+#include "commonheaders.h"
+
+BOOL CALLBACK AddContactDlgProc(HWND hdlg,UINT msg,WPARAM wparam,LPARAM lparam)
+{
+ ADDCONTACTSTRUCT *acs;
+
+ switch(msg)
+ {
+ case WM_INITDIALOG:
+ {
+ char idstr[4],szUin[10];
+ DBVARIANT dbv;
+ int groupId;
+ DWORD flags=0;
+
+ acs=(ADDCONTACTSTRUCT *)lparam;
+ SetWindowLong(hdlg,GWL_USERDATA,(LONG)acs);
+
+ TranslateDialogDefault(hdlg);
+ SendMessage(hdlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_ADDCONTACT)));
+ if(acs->handleType==HANDLE_EVENT)
+ {
+ DBEVENTINFO dbei;
+ DWORD dwUin;
+
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=sizeof(DWORD);
+ dbei.pBlob=(PBYTE)&dwUin;
+ CallService(MS_DB_EVENT_GET,(WPARAM)acs->handle,(LPARAM)&dbei);
+ _ltoa(dwUin,szUin,10);
+ acs->szProto = dbei.szModule;
+ }
+ { TCHAR* szName;
+ if ( acs->handleType == HANDLE_CONTACT )
+ szName = (TCHAR*)CallService( MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)acs->handle, GCDNF_TCHAR );
+ else {
+ char* p = (acs->handleType == HANDLE_EVENT) ? szUin : acs->psr->nick;
+ #if defined( _UNICODE )
+ szName =( TCHAR* )alloca( 128*sizeof( TCHAR ));
+ MultiByteToWideChar( CP_ACP, 0, p, -1, szName, 128 );
+ #else
+ szName = p;
+ #endif
+ }
+
+ if ( lstrlen( szName )) {
+ TCHAR szTitle[128];
+ mir_sntprintf( szTitle, SIZEOF(szTitle), TranslateT("Add %s"), szName );
+ SetWindowText( hdlg, szTitle );
+ }
+ else SetWindowText( hdlg, TranslateT("Add Contact"));
+ }
+
+ if ( acs->handleType == HANDLE_CONTACT && acs->handle ) {
+ if ( acs->szProto == NULL || (acs->szProto != NULL && strcmp(acs->szProto,"") == 0) )
+ acs->szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)acs->handle,0);
+ }
+
+ for(groupId=0;groupId<999;groupId++)
+ {
+ _itoa(groupId,idstr,10);
+ if(DBGetContactSettingTString(NULL,"CListGroups",idstr,&dbv)) break;
+ SendDlgItemMessage(hdlg,IDC_GROUP,CB_ADDSTRING,0,(LPARAM)(dbv.ptszVal+1));
+ DBFreeVariant(&dbv);
+ }
+ SendDlgItemMessage(hdlg,IDC_GROUP,CB_INSERTSTRING,0,(LPARAM)TranslateT("None"));
+ SendDlgItemMessage(hdlg,IDC_GROUP,CB_SETCURSEL,0,0);
+ /* acs->szProto may be NULL don't expect it */
+ if (acs->szProto) flags=CallProtoService(acs->szProto,PS_GETCAPS,PFLAGNUM_4,0);
+ else flags=0;
+ if (flags&PF4_FORCEADDED) { // force you were added requests for this protocol
+ CheckDlgButton(hdlg,IDC_ADDED,BST_CHECKED);
+ EnableWindow(GetDlgItem(hdlg,IDC_ADDED),FALSE);
+ }
+ if (flags&PF4_FORCEAUTH) { // force auth requests for this protocol
+ CheckDlgButton(hdlg,IDC_AUTH,BST_CHECKED);
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTH),FALSE);
+ }
+ if (flags&PF4_NOCUSTOMAUTH) {
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTHREQ),FALSE);
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTHGB),FALSE);
+ }
+ SetDlgItemText(hdlg,IDC_AUTHREQ,TranslateT("Please authorize my request and add me to your contact list."));
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTHREQ),IsDlgButtonChecked(hdlg,IDC_AUTH));
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTHGB),IsDlgButtonChecked(hdlg,IDC_AUTH));
+ }
+ break;
+
+ case WM_COMMAND:
+ acs=(ADDCONTACTSTRUCT *)GetWindowLong(hdlg,GWL_USERDATA);
+
+ switch(LOWORD(wparam))
+ {
+ case IDC_AUTH:
+ {
+ DWORD flags=0;
+
+ flags=CallProtoService(acs->szProto,PS_GETCAPS,PFLAGNUM_4,0);
+ if (flags&PF4_NOCUSTOMAUTH) {
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTHREQ),FALSE);
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTHGB),FALSE);
+ }
+ else {
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTHREQ),IsDlgButtonChecked(hdlg,IDC_AUTH));
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTHGB),IsDlgButtonChecked(hdlg,IDC_AUTH));
+ }
+ }
+ break;
+ case IDOK:
+ {
+ HANDLE hcontact=INVALID_HANDLE_VALUE;
+ if(acs->handleType==HANDLE_EVENT)
+ {
+ DBEVENTINFO dbei;
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=0;
+ CallService(MS_DB_EVENT_GET,(WPARAM)acs->handle,(LPARAM)&dbei);
+ hcontact=(HANDLE)CallProtoService(dbei.szModule,PS_ADDTOLISTBYEVENT,0,(LPARAM)acs->handle);
+ }
+ else if(acs->handleType==HANDLE_SEARCHRESULT)
+ hcontact=(HANDLE)CallProtoService(acs->szProto,PS_ADDTOLIST,0,(LPARAM)acs->psr);
+
+ else if(acs->handleType==HANDLE_CONTACT)
+ hcontact=acs->handle;
+
+ if ( hcontact == NULL ) break;
+
+ { TCHAR szHandle[256];
+ if ( GetDlgItemText( hdlg, IDC_MYHANDLE, szHandle, SIZEOF(szHandle)))
+ DBWriteContactSettingTString( hcontact, "CList", "MyHandle", szHandle );
+
+ GetDlgItemText( hdlg, IDC_GROUP, szHandle, SIZEOF(szHandle));
+ if ( lstrcmp( szHandle, TranslateT( "None" )))
+ DBWriteContactSettingTString( hcontact, "CList", "Group", szHandle );
+ }
+
+ if(IsDlgButtonChecked(hdlg,IDC_ADDED)) CallContactService(hcontact,PSS_ADDED,0,0);
+ if(IsDlgButtonChecked(hdlg,IDC_AUTH)) {
+ DWORD flags;
+ flags=CallProtoService(acs->szProto,PS_GETCAPS,PFLAGNUM_4,0);
+ if (flags&PF4_NOCUSTOMAUTH) CallContactService(hcontact,PSS_AUTHREQUEST,0,(LPARAM)"");
+ else {
+ char szReason[256];
+
+ GetDlgItemTextA(hdlg,IDC_AUTHREQ,szReason,256);
+ CallContactService(hcontact,PSS_AUTHREQUEST,0,(LPARAM)szReason);
+ } }
+
+ DBDeleteContactSetting(hcontact,"CList","NotOnList");
+ }
+ // fall through
+ case IDCANCEL:
+ if (GetParent(hdlg)==NULL) DestroyWindow(hdlg);
+ else EndDialog(hdlg,0);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ /* if there is no parent for the dialog, its a modeless dialog and can't be killed using EndDialog() */
+ if(GetParent(hdlg)==NULL) DestroyWindow(hdlg);
+ else EndDialog(hdlg,0);
+ break;
+
+ case WM_DESTROY:
+ acs=(ADDCONTACTSTRUCT *)GetWindowLong(hdlg,GWL_USERDATA);
+ if (acs) {
+ if (acs->psr) {
+ if (acs->psr->nick) mir_free(acs->psr->nick);
+ if (acs->psr->firstName) mir_free(acs->psr->firstName);
+ if (acs->psr->lastName) mir_free(acs->psr->lastName);
+ if (acs->psr->email) mir_free(acs->psr->email);
+ mir_free(acs->psr);
+ }
+ mir_free(acs);
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+int AddContactDialog(WPARAM wParam,LPARAM lParam)
+{
+ ADDCONTACTSTRUCT *acs;
+ if (lParam) {
+ acs=mir_alloc(sizeof(ADDCONTACTSTRUCT));
+ memmove(acs,(ADDCONTACTSTRUCT*)lParam,sizeof(ADDCONTACTSTRUCT));
+ if (acs->psr) {
+ PROTOSEARCHRESULT *psr;
+ /* bad! structures that are bigger than psr will cause crashes if they define pointers within unreachable structural space */
+ psr=mir_alloc(acs->psr->cbSize);
+ memmove(psr,acs->psr,acs->psr->cbSize);
+ if (psr->nick) psr->nick=mir_strdup(psr->nick);
+ if (psr->firstName) psr->firstName=mir_strdup(psr->firstName);
+ if (psr->lastName) psr->lastName=mir_strdup(psr->lastName);
+ if (psr->email) psr->email=mir_strdup(psr->email);
+ acs->psr=psr;
+ /* copied the passed acs structure, the psr structure with, the pointers within that */
+ } //if
+ if (wParam) {
+ DialogBoxParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_ADDCONTACT),(HWND)wParam,AddContactDlgProc,(LPARAM)acs);
+ } else {
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_ADDCONTACT),(HWND)wParam,AddContactDlgProc,(LPARAM)acs);
+ } //if
+ return 0;
+ }
+ return 1;
+}
+
+int LoadAddContactModule(void)
+{
+ CreateServiceFunction(MS_ADDCONTACT_SHOW,AddContactDialog);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/autoaway/autoaway.c b/miranda-wine/src/modules/autoaway/autoaway.c
new file mode 100644
index 0000000..5cb10ce
--- /dev/null
+++ b/miranda-wine/src/modules/autoaway/autoaway.c
@@ -0,0 +1,82 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+#define AA_MODULE "AutoAway"
+
+static void AutoAwaySetProtocol(const char * proto, unsigned status)
+{
+ char * awayMsg = (char *) CallService(MS_AWAYMSG_GETSTATUSMSG, (WPARAM) status, 0);
+ CallProtoService(proto, PS_SETSTATUS, status, 0);
+ if ( awayMsg != NULL ) {
+ if (CallProtoService(proto,PS_GETCAPS,PFLAGNUM_1,0)&PF1_MODEMSGSEND)
+ CallProtoService(proto, PS_SETAWAYMSG, status, (LPARAM) awayMsg);
+ miranda_sys_free(awayMsg);
+ }
+}
+
+static int AutoAwayEvent(WPARAM wParam, LPARAM lParam)
+{
+ PROTOCOLDESCRIPTOR **proto=0;
+ int protoCount=0;
+ int j;
+ MIRANDA_IDLE_INFO mii;
+ int status;
+
+ mii.cbSize = sizeof(mii);
+ CallService(MS_IDLE_GETIDLEINFO, 0, (LPARAM)&mii);
+ if (mii.aaStatus==0) return 0;
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM)&protoCount, (LPARAM)&proto);
+ for (j=0; j<protoCount; j++) {
+ if ( proto[j]->type == PROTOTYPE_PROTOCOL ) {
+ int statusbits = CallProtoService(proto[j]->szName, PS_GETCAPS, PFLAGNUM_2, 0);
+ int currentstatus = CallProtoService(proto[j]->szName, PS_GETSTATUS, 0, 0);
+ status = mii.aaStatus;
+ if ( !(statusbits & Proto_Status2Flag(status)) ) {
+ // the protocol doesnt support the given status
+ if ( statusbits & Proto_Status2Flag(ID_STATUS_AWAY) ) status=ID_STATUS_AWAY;
+ else {
+ // the proto doesnt support user mode or even away, bail.
+ continue;
+ }
+ }
+ if ( currentstatus >= ID_STATUS_ONLINE && currentstatus != ID_STATUS_INVISIBLE ) {
+ if ( (lParam&IDF_ISIDLE) && ( currentstatus == ID_STATUS_ONLINE || currentstatus == ID_STATUS_FREECHAT )) {
+ DBWriteContactSettingByte(NULL,AA_MODULE,proto[j]->szName,1);
+ AutoAwaySetProtocol(proto[j]->szName, status);
+ } else if ( !(lParam&IDF_ISIDLE) && DBGetContactSettingByte(NULL,AA_MODULE,proto[j]->szName,0) ) {
+ // returning from idle and this proto was set away, set it back
+ DBWriteContactSettingByte(NULL,AA_MODULE,proto[j]->szName,0);
+ if ( !mii.aaLock ) AutoAwaySetProtocol(proto[j]->szName, ID_STATUS_ONLINE);
+ } } } }
+
+ return 0;
+}
+
+int LoadAutoAwayModule(void)
+{
+ HookEvent(ME_IDLE_CHANGED, AutoAwayEvent);
+ return 0;
+}
+
+
diff --git a/miranda-wine/src/modules/button/button.c b/miranda-wine/src/modules/button/button.c
new file mode 100644
index 0000000..e5b203c
--- /dev/null
+++ b/miranda-wine/src/modules/button/button.c
@@ -0,0 +1,540 @@
+/*
+Miranda IM
+Copyright (C) 2002 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.
+*/
+#include "commonheaders.h"
+
+// TODO:
+// - Support for bitmap buttons (simple call to DrawIconEx())
+
+static LRESULT CALLBACK MButtonWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+typedef struct {
+ HWND hwnd;
+ int stateId; // button state
+ int focus; // has focus (1 or 0)
+ HFONT hFont; // font
+ HICON arrow; // uses down arrow
+ int defbutton; // default button
+ HICON hIcon;
+ HBITMAP hBitmap;
+ int pushBtn;
+ int pbState;
+ HANDLE hThemeButton;
+ HANDLE hThemeToolbar;
+ char cHot;
+ int flatBtn;
+} MButtonCtrl;
+
+
+// External theme methods and properties
+static HMODULE themeAPIHandle = NULL; // handle to uxtheme.dll
+static HANDLE (WINAPI *MyOpenThemeData)(HWND,LPCWSTR);
+static HRESULT (WINAPI *MyCloseThemeData)(HANDLE);
+static BOOL (WINAPI *MyIsThemeBackgroundPartiallyTransparent)(HANDLE,int,int);
+static HRESULT (WINAPI *MyDrawThemeParentBackground)(HWND,HDC,RECT *);
+static HRESULT (WINAPI *MyDrawThemeBackground)(HANDLE,HDC,int,int,const RECT *,const RECT *);
+static HRESULT (WINAPI *MyDrawThemeText)(HANDLE,HDC,int,int,LPCWSTR,int,DWORD,DWORD,const RECT *);
+
+static CRITICAL_SECTION csTips;
+static HWND hwndToolTips = NULL;
+
+int UnloadButtonModule(WPARAM wParam, LPARAM lParam) {
+ DeleteCriticalSection(&csTips);
+ return 0;
+}
+
+int LoadButtonModule(void) {
+ WNDCLASSEX wc;
+
+ ZeroMemory(&wc, sizeof(wc));
+ wc.cbSize = sizeof(wc);
+ wc.lpszClassName = MIRANDABUTTONCLASS;
+ wc.lpfnWndProc = MButtonWndProc;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.cbWndExtra = sizeof(MButtonCtrl*);
+ wc.hbrBackground = 0;
+ wc.style = CS_GLOBALCLASS;
+ RegisterClassEx(&wc);
+ InitializeCriticalSection(&csTips);
+ HookEvent(ME_SYSTEM_SHUTDOWN, UnloadButtonModule);
+ return 0;
+}
+
+// Used for our own cheap TrackMouseEvent
+#define BUTTON_POLLID 100
+#define BUTTON_POLLDELAY 50
+
+#define MGPROC(x) GetProcAddress(themeAPIHandle,x)
+static int ThemeSupport() {
+ if (IsWinVerXPPlus()) {
+ if (!themeAPIHandle) {
+ themeAPIHandle = GetModuleHandleA("uxtheme");
+ if (themeAPIHandle) {
+ MyOpenThemeData = (HANDLE (WINAPI *)(HWND,LPCWSTR))MGPROC("OpenThemeData");
+ MyCloseThemeData = (HRESULT (WINAPI *)(HANDLE))MGPROC("CloseThemeData");
+ MyIsThemeBackgroundPartiallyTransparent = (BOOL (WINAPI *)(HANDLE,int,int))MGPROC("IsThemeBackgroundPartiallyTransparent");
+ MyDrawThemeParentBackground = (HRESULT (WINAPI *)(HWND,HDC,RECT *))MGPROC("DrawThemeParentBackground");
+ MyDrawThemeBackground = (HRESULT (WINAPI *)(HANDLE,HDC,int,int,const RECT *,const RECT *))MGPROC("DrawThemeBackground");
+ MyDrawThemeText = (HRESULT (WINAPI *)(HANDLE,HDC,int,int,LPCWSTR,int,DWORD,DWORD,const RECT *))MGPROC("DrawThemeText");
+ }
+ }
+ // Make sure all of these methods are valid (i would hope either all or none work)
+ if (MyOpenThemeData
+ &&MyCloseThemeData
+ &&MyIsThemeBackgroundPartiallyTransparent
+ &&MyDrawThemeParentBackground
+ &&MyDrawThemeBackground
+ &&MyDrawThemeText) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void DestroyTheme(MButtonCtrl *ctl) {
+ if (ThemeSupport()) {
+ if (ctl->hThemeButton) {
+ MyCloseThemeData(ctl->hThemeButton);
+ ctl->hThemeButton = NULL;
+ }
+ if (ctl->hThemeToolbar) {
+ MyCloseThemeData(ctl->hThemeToolbar);
+ ctl->hThemeToolbar = NULL;
+ }
+ }
+}
+
+static void LoadTheme(MButtonCtrl *ctl) {
+ if (ThemeSupport()) {
+ DestroyTheme(ctl);
+ ctl->hThemeButton = MyOpenThemeData(ctl->hwnd,L"BUTTON");
+ ctl->hThemeToolbar = MyOpenThemeData(ctl->hwnd,L"TOOLBAR");
+ }
+}
+
+static int TBStateConvert2Flat(int state) {
+ switch(state) {
+ case PBS_NORMAL: return TS_NORMAL;
+ case PBS_HOT: return TS_HOT;
+ case PBS_PRESSED: return TS_PRESSED;
+ case PBS_DISABLED: return TS_DISABLED;
+ case PBS_DEFAULTED: return TS_NORMAL;
+ }
+ return TS_NORMAL;
+}
+
+static void PaintWorker(MButtonCtrl *ctl, HDC hdcPaint) {
+ if (hdcPaint) {
+ HDC hdcMem;
+ HBITMAP hbmMem;
+ HDC hOld;
+ RECT rcClient;
+
+ GetClientRect(ctl->hwnd, &rcClient);
+ hdcMem = CreateCompatibleDC(hdcPaint);
+ hbmMem = CreateCompatibleBitmap(hdcPaint, rcClient.right-rcClient.left, rcClient.bottom-rcClient.top);
+ hOld = SelectObject(hdcMem, hbmMem);
+
+ // If its a push button, check to see if it should stay pressed
+ if (ctl->pushBtn && ctl->pbState) ctl->stateId = PBS_PRESSED;
+
+ // Draw the flat button
+ if (ctl->flatBtn) {
+ if (ctl->hThemeToolbar) {
+ int state = IsWindowEnabled(ctl->hwnd)?(ctl->stateId==PBS_NORMAL&&ctl->defbutton?PBS_DEFAULTED:ctl->stateId):PBS_DISABLED;
+ if (MyIsThemeBackgroundPartiallyTransparent(ctl->hThemeToolbar, TP_BUTTON, TBStateConvert2Flat(state))) {
+ MyDrawThemeParentBackground(ctl->hwnd, hdcMem, &rcClient);
+ }
+ MyDrawThemeBackground(ctl->hThemeToolbar, hdcMem, TP_BUTTON, TBStateConvert2Flat(state), &rcClient, &rcClient);
+ }
+ else {
+ HBRUSH hbr;
+
+ if (ctl->stateId==PBS_PRESSED||ctl->stateId==PBS_HOT)
+ hbr = GetSysColorBrush(COLOR_3DLIGHT);
+ else {
+ HWND hwndParent = GetParent(ctl->hwnd);
+ HDC dc = GetDC(hwndParent);
+ HBRUSH oldBrush = GetCurrentObject( dc, OBJ_BRUSH );
+ hbr = (HBRUSH)SendMessage(hwndParent, WM_CTLCOLORDLG, (WPARAM)dc, (LPARAM)hwndParent);
+ SelectObject(dc,oldBrush);
+ ReleaseDC(hwndParent,dc);
+ }
+ if (hbr) {
+ FillRect(hdcMem, &rcClient, hbr);
+ DeleteObject(hbr);
+ }
+ if (ctl->stateId==PBS_HOT||ctl->focus) {
+ if (ctl->pbState)
+ DrawEdge(hdcMem,&rcClient, EDGE_ETCHED,BF_RECT|BF_SOFT);
+ else DrawEdge(hdcMem,&rcClient, BDR_RAISEDOUTER,BF_RECT|BF_SOFT|BF_FLAT);
+ }
+ else if (ctl->stateId==PBS_PRESSED)
+ DrawEdge(hdcMem, &rcClient, BDR_SUNKENOUTER,BF_RECT|BF_SOFT);
+ }
+ }
+ else {
+ // Draw background/border
+ if (ctl->hThemeButton) {
+ int state = IsWindowEnabled(ctl->hwnd)?(ctl->stateId==PBS_NORMAL&&ctl->defbutton?PBS_DEFAULTED:ctl->stateId):PBS_DISABLED;
+ if (MyIsThemeBackgroundPartiallyTransparent(ctl->hThemeButton, BP_PUSHBUTTON, state)) {
+ MyDrawThemeParentBackground(ctl->hwnd, hdcMem, &rcClient);
+ }
+ MyDrawThemeBackground(ctl->hThemeButton, hdcMem, BP_PUSHBUTTON, state, &rcClient, &rcClient);
+ }
+ else {
+ UINT uState = DFCS_BUTTONPUSH|((ctl->stateId==PBS_HOT)?DFCS_HOT:0)|((ctl->stateId == PBS_PRESSED)?DFCS_PUSHED:0);
+ if (ctl->defbutton&&ctl->stateId==PBS_NORMAL) uState |= DLGC_DEFPUSHBUTTON;
+ DrawFrameControl(hdcMem, &rcClient, DFC_BUTTON, uState);
+ }
+
+ // Draw focus rectangle if button has focus
+ if (ctl->focus) {
+ RECT focusRect = rcClient;
+ InflateRect(&focusRect, -3, -3);
+ DrawFocusRect(hdcMem, &focusRect);
+ }
+ }
+
+ // If we have an icon or a bitmap, ignore text and only draw the image on the button
+ if (ctl->hIcon) {
+ int ix = (rcClient.right-rcClient.left)/2 - (GetSystemMetrics(SM_CXSMICON)/2);
+ int iy = (rcClient.bottom-rcClient.top)/2 - (GetSystemMetrics(SM_CYSMICON)/2);
+ if (ctl->stateId == PBS_PRESSED) {
+ ix++;
+ iy++;
+ }
+ {
+ HIMAGELIST hImageList;
+ HICON hIconNew;
+
+ hImageList = ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON), IsWinVerXPPlus()? ILC_COLOR32 | ILC_MASK : ILC_COLOR16 | ILC_MASK, 1, 0);
+ ImageList_AddIcon(hImageList, ctl->hIcon);
+ hIconNew = ImageList_GetIcon(hImageList, 0, ILD_NORMAL);
+ DrawState(hdcMem,NULL,NULL,(LPARAM)hIconNew,0,ix,iy,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),IsWindowEnabled(ctl->hwnd)?DST_ICON|DSS_NORMAL:DST_ICON|DSS_DISABLED);
+ ImageList_RemoveAll(hImageList);
+ ImageList_Destroy(hImageList);
+ DestroyIcon(hIconNew);
+ }
+ }
+ else if (ctl->hBitmap) {
+ BITMAP bminfo;
+ int ix,iy;
+
+ GetObject(ctl->hBitmap, sizeof(bminfo), &bminfo);
+ ix = (rcClient.right-rcClient.left)/2 - (bminfo.bmWidth/2);
+ iy = (rcClient.bottom-rcClient.top)/2 - (bminfo.bmHeight/2);
+ if (ctl->stateId == PBS_PRESSED) {
+ ix++;
+ iy++;
+ }
+ DrawState(hdcMem,NULL,NULL,(LPARAM)ctl->hBitmap,0,ix,iy,bminfo.bmWidth,bminfo.bmHeight,IsWindowEnabled(ctl->hwnd)?DST_BITMAP:DST_BITMAP|DSS_DISABLED);
+ }
+ else if (GetWindowTextLength(ctl->hwnd)) {
+ // Draw the text and optinally the arrow
+ TCHAR szText[MAX_PATH];
+ SIZE sz;
+ RECT rcText;
+ HFONT hOldFont;
+
+ CopyRect(&rcText, &rcClient);
+ GetWindowText(ctl->hwnd, szText, SIZEOF(szText));
+ SetBkMode(hdcMem, TRANSPARENT);
+ hOldFont = SelectObject(hdcMem, ctl->hFont);
+ // XP w/themes doesn't used the glossy disabled text. Is it always using COLOR_GRAYTEXT? Seems so.
+ SetTextColor(hdcMem, IsWindowEnabled(ctl->hwnd)||!ctl->hThemeButton?GetSysColor(COLOR_BTNTEXT):GetSysColor(COLOR_GRAYTEXT));
+ GetTextExtentPoint32(hdcMem, szText, lstrlen(szText), &sz);
+ if (ctl->cHot) {
+ SIZE szHot;
+
+ GetTextExtentPoint32 (hdcMem, _T("&"), 1, &szHot);
+ sz.cx -= szHot.cx;
+ }
+ if (ctl->arrow) {
+ DrawState(hdcMem,NULL,NULL,(LPARAM)ctl->arrow,0,rcClient.right-rcClient.left-5-GetSystemMetrics(SM_CXSMICON)+(!ctl->hThemeButton&&ctl->stateId==PBS_PRESSED?1:0),(rcClient.bottom-rcClient.top)/2-GetSystemMetrics(SM_CYSMICON)/2+(!ctl->hThemeButton&&ctl->stateId==PBS_PRESSED?1:0),GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),IsWindowEnabled(ctl->hwnd)?DST_ICON:DST_ICON|DSS_DISABLED);
+ }
+ SelectObject(hdcMem, ctl->hFont);
+ DrawState(hdcMem,NULL,NULL,(LPARAM)szText,0,(rcText.right-rcText.left-sz.cx)/2+(!ctl->hThemeButton&&ctl->stateId==PBS_PRESSED?1:0),ctl->hThemeButton?(rcText.bottom-rcText.top-sz.cy)/2:(rcText.bottom-rcText.top-sz.cy)/2-(ctl->stateId==PBS_PRESSED?0:1),sz.cx,sz.cy,IsWindowEnabled(ctl->hwnd)||ctl->hThemeButton?DST_PREFIXTEXT|DSS_NORMAL:DST_PREFIXTEXT|DSS_DISABLED);
+ SelectObject(hdcMem, hOldFont);
+ }
+ BitBlt(hdcPaint, 0, 0, rcClient.right-rcClient.left, rcClient.bottom-rcClient.top, hdcMem, 0, 0, SRCCOPY);
+ SelectObject(hdcMem, hOld);
+ DeleteObject(hbmMem);
+ DeleteDC(hdcMem);
+
+ }
+}
+
+static LRESULT CALLBACK MButtonWndProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) {
+ MButtonCtrl* bct = (MButtonCtrl *)GetWindowLong(hwndDlg, 0);
+ switch(msg) {
+ case WM_NCCREATE:
+ {
+ SetWindowLong(hwndDlg, GWL_STYLE, GetWindowLong(hwndDlg, GWL_STYLE)|BS_OWNERDRAW);
+ bct = mir_alloc(sizeof(MButtonCtrl));
+ if (bct==NULL) return FALSE;
+ bct->hwnd = hwndDlg;
+ bct->stateId = PBS_NORMAL;
+ bct->focus = 0;
+ bct->hFont = GetStockObject(DEFAULT_GUI_FONT);
+ bct->arrow = NULL;
+ bct->defbutton = 0;
+ bct->hIcon = NULL;
+ bct->hBitmap = NULL;
+ bct->pushBtn = 0;
+ bct->pbState = 0;
+ bct->hThemeButton = NULL;
+ bct->hThemeToolbar = NULL;
+ bct->cHot = 0;
+ bct->flatBtn = 0;
+ LoadTheme(bct);
+ SetWindowLong(hwndDlg, 0, (LONG)bct);
+ if (((CREATESTRUCT *)lParam)->lpszName) SetWindowText(hwndDlg, ((CREATESTRUCT *)lParam)->lpszName);
+ return TRUE;
+ }
+ case WM_DESTROY:
+ {
+ if (bct) {
+ EnterCriticalSection(&csTips);
+ if (hwndToolTips) {
+ TOOLINFO ti;
+
+ ZeroMemory(&ti, sizeof(ti));
+ ti.cbSize = sizeof(ti);
+ ti.uFlags = TTF_IDISHWND;
+ ti.hwnd = bct->hwnd;
+ ti.uId = (UINT)bct->hwnd;
+ if (SendMessage(hwndToolTips, TTM_GETTOOLINFO, 0, (LPARAM)&ti)) {
+ SendMessage(hwndToolTips, TTM_DELTOOL, 0, (LPARAM)&ti);
+ }
+ if (SendMessage(hwndToolTips, TTM_GETTOOLCOUNT, 0, (LPARAM)&ti)==0) {
+ DestroyWindow(hwndToolTips);
+ hwndToolTips = NULL;
+ }
+ }
+ LeaveCriticalSection(&csTips);
+ DestroyTheme(bct);
+ mir_free(bct);
+ }
+ SetWindowLong(hwndDlg,0,(LONG)NULL);
+ break; // DONT! fall thru
+ }
+ case WM_SETTEXT:
+ {
+ bct->cHot = 0;
+ if ( lParam != 0 ) {
+ TCHAR *tmp = ( TCHAR* )lParam;
+ while (*tmp) {
+ if (*tmp=='&' && *(tmp+1)) {
+ bct->cHot = _tolower(*(tmp+1));
+ break;
+ }
+ tmp++;
+ }
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ break;
+ }
+ case WM_SYSKEYUP:
+ if (bct->stateId!=PBS_DISABLED && bct->cHot && bct->cHot == tolower((int)wParam)) {
+ if (bct->pushBtn) {
+ if (bct->pbState) bct->pbState = 0;
+ else bct->pbState = 1;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ SendMessage(GetParent(hwndDlg), WM_COMMAND, MAKELONG(GetDlgCtrlID(hwndDlg), BN_CLICKED), (LPARAM)hwndDlg);
+ return 0;
+ }
+ break;
+ case WM_THEMECHANGED: {
+ // themed changed, reload theme object
+ LoadTheme(bct);
+ InvalidateRect(bct->hwnd, NULL, TRUE); // repaint it
+ break;
+ }
+ case WM_SETFONT: // remember the font so we can use it later
+ {
+ bct->hFont = (HFONT)wParam; // maybe we should redraw?
+ break;
+ }
+ case WM_NCPAINT:
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HDC hdcPaint;
+
+ hdcPaint = BeginPaint(hwndDlg, &ps);
+ if (hdcPaint) {
+ PaintWorker(bct, hdcPaint);
+ EndPaint(hwndDlg, &ps);
+ }
+ break;
+ }
+ case BM_SETIMAGE:
+ if (wParam == IMAGE_ICON) {
+ bct->hIcon = (HICON)lParam;
+ bct->hBitmap = NULL;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ else if (wParam == IMAGE_BITMAP) {
+ bct->hBitmap = (HBITMAP)lParam;
+ bct->hIcon = NULL;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ break;
+ case BM_SETCHECK:
+ if (!bct->pushBtn) break;
+ if (wParam == BST_CHECKED) {
+ bct->pbState = 1;
+ bct->stateId = PBS_PRESSED;
+ }
+ else if (wParam == BST_UNCHECKED) {
+ bct->pbState = 0;
+ bct->stateId = PBS_NORMAL;
+ }
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case BM_GETCHECK:
+ if (bct->pushBtn) {
+ return bct->pbState?BST_CHECKED:BST_UNCHECKED;
+ }
+ return 0;
+ case BUTTONSETARROW: // turn arrow on/off
+ if (wParam) {
+ if (!bct->arrow)
+ bct->arrow = (HICON)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_DOWNARROW),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ }
+ else {
+ if (bct->arrow) {
+ DestroyIcon(bct->arrow);
+ bct->arrow = NULL;
+ }
+ }
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case BUTTONSETDEFAULT:
+ bct->defbutton = wParam?1:0;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case BUTTONSETASPUSHBTN:
+ bct->pushBtn = 1;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case BUTTONSETASFLATBTN:
+ bct->flatBtn = 1;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case BUTTONADDTOOLTIP:
+ {
+ TOOLINFOA ti;
+
+ if (!(char*)wParam) break;
+ EnterCriticalSection(&csTips);
+ if (!hwndToolTips)
+ hwndToolTips = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, _T(""), WS_POPUP, 0, 0, 0, 0, NULL, NULL, GetModuleHandle(NULL), NULL);
+
+ ZeroMemory(&ti, sizeof(ti));
+ ti.cbSize = sizeof(ti);
+ ti.uFlags = TTF_IDISHWND;
+ ti.hwnd = bct->hwnd;
+ ti.uId = (UINT)bct->hwnd;
+ if (SendMessage(hwndToolTips, TTM_GETTOOLINFO, 0, (LPARAM)&ti)) {
+ SendMessage(hwndToolTips, TTM_DELTOOL, 0, (LPARAM)&ti);
+ }
+ ti.uFlags = TTF_IDISHWND|TTF_SUBCLASS;
+ ti.uId = (UINT)bct->hwnd;
+ ti.lpszText=(char*)wParam;
+ SendMessageA( hwndToolTips, TTM_ADDTOOLA, 0, (LPARAM)&ti);
+ LeaveCriticalSection(&csTips);
+ break;
+ }
+ case WM_SETFOCUS: // set keybord focus and redraw
+ bct->focus = 1;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case WM_KILLFOCUS: // kill focus and redraw
+ bct->focus = 0;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case WM_WINDOWPOSCHANGED:
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case WM_ENABLE: // windows tells us to enable/disable
+ {
+ bct->stateId = wParam?PBS_NORMAL:PBS_DISABLED;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ }
+ case WM_MOUSELEAVE: // faked by the WM_TIMER
+ {
+ if (bct->stateId!=PBS_DISABLED) { // don't change states if disabled
+ bct->stateId = PBS_NORMAL;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ break;
+ }
+ case WM_LBUTTONDOWN:
+ {
+ if (bct->stateId!=PBS_DISABLED) { // don't change states if disabled
+ bct->stateId = PBS_PRESSED;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ break;
+ }
+ case WM_LBUTTONUP:
+ {
+ if (bct->pushBtn) {
+ if (bct->pbState) bct->pbState = 0;
+ else bct->pbState = 1;
+ }
+ if (bct->stateId!=PBS_DISABLED) { // don't change states if disabled
+ if (msg==WM_LBUTTONUP) bct->stateId = PBS_HOT;
+ else bct->stateId = PBS_NORMAL;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ // Tell your daddy you got clicked.
+ SendMessage(GetParent(hwndDlg), WM_COMMAND, MAKELONG(GetDlgCtrlID(hwndDlg), BN_CLICKED), (LPARAM)hwndDlg);
+ break;
+ }
+ case WM_MOUSEMOVE:
+ if (bct->stateId == PBS_NORMAL) {
+ bct->stateId = PBS_HOT;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ // Call timer, used to start cheesy TrackMouseEvent faker
+ SetTimer(hwndDlg,BUTTON_POLLID,BUTTON_POLLDELAY,NULL);
+ break;
+ case WM_TIMER: // use a timer to check if they have did a mouseout
+ {
+ if (wParam==BUTTON_POLLID) {
+ RECT rc;
+ POINT pt;
+ GetWindowRect(hwndDlg,&rc);
+ GetCursorPos(&pt);
+ if(!PtInRect(&rc,pt)) { // mouse must be gone, trigger mouse leave
+ PostMessage(hwndDlg,WM_MOUSELEAVE,0,0L);
+ KillTimer(hwndDlg,BUTTON_POLLID);
+ }
+ }
+ break;
+ }
+ case WM_ERASEBKGND:
+ return 1;
+ }
+ return DefWindowProc(hwndDlg, msg, wParam, lParam);
+}
diff --git a/miranda-wine/src/modules/clist/Docking.c b/miranda-wine/src/modules/clist/Docking.c
new file mode 100644
index 0000000..f0a75de
--- /dev/null
+++ b/miranda-wine/src/modules/clist/Docking.c
@@ -0,0 +1,293 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "clc.h"
+
+#define WM_DOCKCALLBACK (WM_USER+121)
+#define WM_CREATEDOCKED (WM_USER+122)
+#define EDGESENSITIVITY 3
+
+#define DOCKED_NONE 0
+#define DOCKED_LEFT 1
+#define DOCKED_RIGHT 2
+static int docked;
+
+typedef HMONITOR WINAPI MyMonitorFromPoint(POINT, DWORD);
+typedef BOOL WINAPI MyGetMonitorInfo(HMONITOR, LPMONITORINFO);
+
+static void Docking_GetMonitorRectFromPoint(POINT pt, RECT * rc)
+{
+ HMODULE hUserInstance = GetModuleHandleA("user32");
+
+ MyMonitorFromPoint *LPMyMonitorFromPoint = (MyMonitorFromPoint *) GetProcAddress(hUserInstance, "MonitorFromPoint");
+ if (LPMyMonitorFromPoint) {
+ MONITORINFO monitorInfo;
+ HMONITOR hMonitor = LPMyMonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST); // always returns a valid value
+ monitorInfo.cbSize = sizeof(MONITORINFO);
+
+ if ((MyGetMonitorInfo *) GetProcAddress(hUserInstance, "GetMonitorInfoA") (hMonitor, &monitorInfo)) {
+ CopyMemory(rc, &monitorInfo.rcMonitor, sizeof(RECT));
+ return;
+ }
+ }
+
+ // "generic" win95/NT support, also serves as failsafe
+ rc->left = 0;
+ rc->top = 0;
+ rc->bottom = GetSystemMetrics(SM_CYSCREEN);
+ rc->right = GetSystemMetrics(SM_CXSCREEN);
+}
+
+static void Docking_GetMonitorRectFromWindow(HWND hWnd, RECT * rc)
+{
+ POINT ptWindow;
+ GetWindowRect(hWnd, rc);
+ ptWindow.x = rc->left;
+ ptWindow.y = rc->top;
+ Docking_GetMonitorRectFromPoint(ptWindow, rc);
+}
+
+static void Docking_AdjustPosition(HWND hwnd, RECT * rcDisplay, RECT * rc)
+{
+ APPBARDATA abd;
+
+ ZeroMemory(&abd, sizeof(abd));
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = hwnd;
+ abd.uEdge = docked == DOCKED_LEFT ? ABE_LEFT : ABE_RIGHT;
+ abd.rc = *rc;
+ abd.rc.top = rcDisplay->top;
+ abd.rc.bottom = rcDisplay->bottom;
+ if (docked == DOCKED_LEFT) {
+ abd.rc.right = rcDisplay->left + abd.rc.right - abd.rc.left;
+ abd.rc.left = rcDisplay->left;
+ }
+ else {
+ abd.rc.left = rcDisplay->right - (abd.rc.right - abd.rc.left);
+ abd.rc.right = rcDisplay->right;
+
+ }
+ SHAppBarMessage(ABM_SETPOS, &abd);
+ *rc = abd.rc;
+}
+
+int Docking_IsDocked(WPARAM wParam, LPARAM lParam)
+{
+ return docked;
+}
+
+int fnDocking_ProcessWindowMessage(WPARAM wParam, LPARAM lParam)
+{
+ APPBARDATA abd;
+ static int draggingTitle;
+ MSG *msg = (MSG *) wParam;
+
+ if (msg->message == WM_DESTROY)
+ DBWriteContactSettingByte(NULL, "CList", "Docked", (BYTE) docked);
+ if (!docked && msg->message != WM_CREATE && msg->message != WM_MOVING && msg->message != WM_CREATEDOCKED && msg->message != WM_MOVE)
+ return 0;
+ switch (msg->message) {
+ case WM_CREATE:
+ //if(GetSystemMetrics(SM_CMONITORS)>1) return 0;
+ if (DBGetContactSettingByte(NULL, "CList", "Docked", 0))
+ PostMessage(msg->hwnd, WM_CREATEDOCKED, 0, 0);
+ draggingTitle = 0;
+ return 0;
+ case WM_CREATEDOCKED:
+ //we need to post a message just after creation to let main message function do some work
+ docked = (int) (char) DBGetContactSettingByte(NULL, "CList", "Docked", 0);
+ if (IsWindowVisible(msg->hwnd) && !IsIconic(msg->hwnd)) {
+ RECT rc, rcMonitor;
+ ZeroMemory(&abd, sizeof(abd));
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = msg->hwnd;
+ abd.lParam = 0;
+ abd.uCallbackMessage = WM_DOCKCALLBACK;
+ SHAppBarMessage(ABM_NEW, &abd);
+ GetWindowRect(msg->hwnd, &rc);
+ Docking_GetMonitorRectFromWindow(msg->hwnd, &rcMonitor);
+ Docking_AdjustPosition(msg->hwnd, &rcMonitor, &rc);
+ MoveWindow(msg->hwnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);
+ }
+ break;
+ case WM_ACTIVATE:
+ ZeroMemory(&abd, sizeof(abd));
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = msg->hwnd;
+ SHAppBarMessage(ABM_ACTIVATE, &abd);
+ return 0;
+ case WM_WINDOWPOSCHANGED:
+ ZeroMemory(&abd, sizeof(abd));
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = msg->hwnd;
+ SHAppBarMessage(ABM_WINDOWPOSCHANGED, &abd);
+ return 0;
+ case WM_MOVING:
+ {
+ RECT rcMonitor;
+ POINT ptCursor;
+
+ // stop early
+ if (GetAsyncKeyState(VK_CONTROL) & 0x8000)
+ return 0;
+
+ // GetMessagePos() is no good, position is always unsigned
+ GetCursorPos(&ptCursor);
+ Docking_GetMonitorRectFromPoint(ptCursor, &rcMonitor);
+
+ if ((ptCursor.x < rcMonitor.left + EDGESENSITIVITY) || (ptCursor.x >= rcMonitor.right - EDGESENSITIVITY)) {
+ ZeroMemory(&abd, sizeof(abd));
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = msg->hwnd;
+ abd.lParam = 0;
+ abd.uCallbackMessage = WM_DOCKCALLBACK;
+ SHAppBarMessage(ABM_NEW, &abd);
+ if (ptCursor.x < rcMonitor.left + EDGESENSITIVITY)
+ docked = DOCKED_LEFT;
+ else
+ docked = DOCKED_RIGHT;
+ PostMessage(msg->hwnd, WM_LBUTTONUP, 0, MAKELPARAM(ptCursor.x, ptCursor.y));
+ GetWindowRect(msg->hwnd, (LPRECT) msg->lParam);
+ Docking_AdjustPosition(msg->hwnd, (LPRECT) & rcMonitor, (LPRECT) msg->lParam);
+ PostMessage(msg->hwnd, WM_SIZE, 0, 0);
+ return TRUE;
+ }
+ return 0;
+ }
+ case WM_MOVE:
+ {
+ if (docked) {
+ RECT rc, rcMonitor;
+ Docking_GetMonitorRectFromWindow(msg->hwnd, &rcMonitor);
+ GetWindowRect(msg->hwnd, &rc);
+ Docking_AdjustPosition(msg->hwnd, &rcMonitor, &rc);
+ MoveWindow(msg->hwnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);
+ return 1;
+ }
+ return 0;
+ }
+ case WM_SIZING:
+ {
+ RECT rcMonitor;
+ Docking_GetMonitorRectFromWindow(msg->hwnd, &rcMonitor);
+ Docking_AdjustPosition(msg->hwnd, &rcMonitor, (LPRECT) msg->lParam);
+ *((LRESULT *) lParam) = TRUE;
+ return TRUE;
+ }
+ case WM_SHOWWINDOW:
+ if (msg->lParam)
+ return 0;
+ if ((msg->wParam && docked < 0) || (!msg->wParam && docked > 0))
+ docked = -docked;
+ ZeroMemory(&abd, sizeof(abd));
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = msg->hwnd;
+ if (msg->wParam) {
+ RECT rc, rcMonitor;
+ Docking_GetMonitorRectFromWindow(msg->hwnd, &rcMonitor);
+ abd.lParam = 0;
+ abd.uCallbackMessage = WM_DOCKCALLBACK;
+ SHAppBarMessage(ABM_NEW, &abd);
+ GetWindowRect(msg->hwnd, &rc);
+ Docking_AdjustPosition(msg->hwnd, &rcMonitor, &rc);
+ MoveWindow(msg->hwnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, FALSE);
+ }
+ else {
+ SHAppBarMessage(ABM_REMOVE, &abd);
+ }
+ return 0;
+ case WM_NCHITTEST:
+ {
+ LONG result;
+ result = DefWindowProc(msg->hwnd, WM_NCHITTEST, msg->wParam, msg->lParam);
+ if (result == HTSIZE || result == HTTOP || result == HTTOPLEFT || result == HTTOPRIGHT ||
+ result == HTBOTTOM || result == HTBOTTOMRIGHT || result == HTBOTTOMLEFT) {
+ *((LRESULT *) lParam) = HTCLIENT;
+ return TRUE;
+ }
+ if (docked == DOCKED_LEFT && result == HTLEFT) {
+ *((LRESULT *) lParam) = HTCLIENT;
+ return TRUE;
+ }
+ if (docked == DOCKED_RIGHT && result == HTRIGHT) {
+ *((LRESULT *) lParam) = HTCLIENT;
+ return TRUE;
+ }
+ return 0;
+ }
+ case WM_SYSCOMMAND:
+ if ((msg->wParam & 0xFFF0) != SC_MOVE)
+ return 0;
+ SetActiveWindow(msg->hwnd);
+ SetCapture(msg->hwnd);
+ draggingTitle = 1;
+ *((LRESULT *) lParam) = 0;
+ return TRUE;
+ case WM_MOUSEMOVE:
+ if (!draggingTitle)
+ return 0;
+ {
+ RECT rc;
+ POINT pt;
+ GetClientRect(msg->hwnd, &rc);
+ if (((docked == DOCKED_LEFT || docked == -DOCKED_LEFT) && (short) LOWORD(msg->lParam) > rc.right) ||
+ ((docked == DOCKED_RIGHT || docked == -DOCKED_RIGHT) && (short) LOWORD(msg->lParam) < 0)) {
+ ReleaseCapture();
+ draggingTitle = 0;
+ ZeroMemory(&abd, sizeof(abd));
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = msg->hwnd;
+ SHAppBarMessage(ABM_REMOVE, &abd);
+ docked = 0;
+ GetCursorPos(&pt);
+ PostMessage(msg->hwnd, WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(pt.x, pt.y));
+ SetWindowPos(msg->hwnd, 0, pt.x - rc.right / 2, pt.y - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYSMCAPTION) / 2,
+ DBGetContactSettingDword(NULL, "CList", "Width", 0), DBGetContactSettingDword(NULL, "CList", "Height", 0),
+ SWP_NOZORDER);
+ }
+ return 1;
+ }
+ case WM_LBUTTONUP:
+ if (draggingTitle) {
+ ReleaseCapture();
+ draggingTitle = 0;
+ }
+ return 0;
+ case WM_DOCKCALLBACK:
+ switch (msg->wParam) {
+ case ABN_WINDOWARRANGE:
+ ShowWindow(msg->hwnd, msg->lParam ? SW_HIDE : SW_SHOW);
+ break;
+ }
+ return TRUE;
+ case WM_DESTROY:
+ if (docked > 0) {
+ ZeroMemory(&abd, sizeof(abd));
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = msg->hwnd;
+ SHAppBarMessage(ABM_REMOVE, &abd);
+ }
+ return 0;
+ }
+ return 0;
+}
diff --git a/miranda-wine/src/modules/clist/clc.c b/miranda-wine/src/modules/clist/clc.c
new file mode 100644
index 0000000..1689ea1
--- /dev/null
+++ b/miranda-wine/src/modules/clist/clc.c
@@ -0,0 +1,1321 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "clc.h"
+#include "../database/dblists.h"
+
+#define NEWSTR_ALLOCA(A) (A==NULL)?NULL:strcpy((char*)alloca(strlen(A)+1),A)
+
+void Utf8Decode( char* str, wchar_t** ucs2 );
+
+static HANDLE hClcWindowList;
+static HANDLE hShowInfoTipEvent;
+HANDLE hHideInfoTipEvent;
+static HANDLE hAckHook;
+static HANDLE hClcSettingsChanged;
+
+int g_IconWidth, g_IconHeight;
+
+void FreeDisplayNameCache(void);
+
+void fnClcBroadcast( int msg, WPARAM wParam, LPARAM lParam )
+{
+ WindowList_Broadcast(hClcWindowList, msg, wParam, lParam);
+}
+
+void fnClcOptionsChanged(void)
+{
+ cli.pfnClcBroadcast( INTM_RELOADOPTIONS, 0, 0);
+}
+
+HMENU fnBuildGroupPopupMenu( struct ClcGroup* group )
+{
+ static HMENU result = NULL;
+
+ if ( result == NULL ) {
+ result = GetSubMenu(LoadMenu(cli.hInst, MAKEINTRESOURCE(IDR_CONTEXT)), 2);
+ CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) result, 0);
+ }
+ CheckMenuItem(result, POPUP_GROUPHIDEOFFLINE, group->hideOffline ? MF_CHECKED : MF_UNCHECKED);
+ return result;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// standard CLC services
+
+static int ClcSettingChanged(WPARAM wParam, LPARAM lParam)
+{
+ char *szProto;
+ DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *) lParam;
+ if ( (HANDLE)wParam != NULL && !strcmp(cws->szModule, "CList")) {
+ if (!strcmp(cws->szSetting, "MyHandle")) {
+ cli.pfnInvalidateDisplayNameCacheEntry((HANDLE) wParam);
+ cli.pfnClcBroadcast( INTM_NAMECHANGED, wParam, lParam);
+ }
+ else if (!strcmp(cws->szSetting, "Group"))
+ cli.pfnClcBroadcast( INTM_GROUPCHANGED, wParam, lParam);
+ else if (!strcmp(cws->szSetting, "Hidden"))
+ cli.pfnClcBroadcast( INTM_HIDDENCHANGED, wParam, lParam);
+ else if (!strcmp(cws->szSetting, "NotOnList"))
+ cli.pfnClcBroadcast( INTM_NOTONLISTCHANGED, wParam, lParam);
+ else if (!strcmp(cws->szSetting, "Status"))
+ cli.pfnClcBroadcast( INTM_INVALIDATE, 0, 0);
+ else if (!strcmp(cws->szSetting, "NameOrder"))
+ cli.pfnClcBroadcast( INTM_NAMEORDERCHANGED, 0, 0);
+ }
+ else if (!strcmp(cws->szModule, "CListGroups")) {
+ cli.pfnClcBroadcast( INTM_GROUPSCHANGED, wParam, lParam);
+ }
+ else {
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (szProto != NULL && (HANDLE) wParam != NULL) {
+ char *id = NULL;
+ if (!strcmp(cws->szModule, "Protocol") && !strcmp(cws->szSetting, "p")) {
+ cli.pfnClcBroadcast( INTM_PROTOCHANGED, wParam, lParam);
+ }
+ // something is being written to a protocol module
+ if (!strcmp(szProto, cws->szModule)) {
+ // was a unique setting key written?
+ id = (char *) CallProtoService(szProto, PS_GETCAPS, PFLAG_UNIQUEIDSETTING, 0);
+ if ((int) id != CALLSERVICE_NOTFOUND && id != NULL && !strcmp(id, cws->szSetting)) {
+ cli.pfnClcBroadcast( INTM_PROTOCHANGED, wParam, lParam);
+ }
+ }
+ }
+ if (szProto == NULL || strcmp(szProto, cws->szModule))
+ return 0;
+ if (!strcmp(cws->szSetting, "Nick") || !strcmp(cws->szSetting, "FirstName") || !strcmp(cws->szSetting, "e-mail")
+ || !strcmp(cws->szSetting, "LastName") || !strcmp(cws->szSetting, "UIN"))
+ cli.pfnClcBroadcast( INTM_NAMECHANGED, wParam, lParam);
+ else if (!strcmp(cws->szSetting, "ApparentMode"))
+ cli.pfnClcBroadcast( INTM_APPARENTMODECHANGED, wParam, lParam);
+ else if (!strcmp(cws->szSetting, "IdleTS"))
+ cli.pfnClcBroadcast( INTM_IDLECHANGED, wParam, lParam);
+ }
+ return 0;
+}
+
+static int ClcModulesLoaded(WPARAM wParam, LPARAM lParam)
+{
+ PROTOCOLDESCRIPTOR **proto;
+ int protoCount, i;
+
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM) & protoCount, (LPARAM) & proto);
+ for (i = 0; i < protoCount; i++) {
+ if (proto[i]->type != PROTOTYPE_PROTOCOL)
+ continue;
+ cli.clcProto = (ClcProtoStatus *) mir_realloc(cli.clcProto, sizeof(ClcProtoStatus) * (cli.hClcProtoCount + 1));
+ cli.clcProto[cli.hClcProtoCount].szProto = proto[i]->szName;
+ cli.clcProto[cli.hClcProtoCount].dwStatus = ID_STATUS_OFFLINE;
+ cli.hClcProtoCount++;
+ }
+ return 0;
+}
+
+static int ClcProtoAck(WPARAM wParam, LPARAM lParam)
+{
+ ACKDATA *ack = (ACKDATA *) lParam;
+ int i;
+
+ if (ack->type == ACKTYPE_STATUS) {
+ WindowList_BroadcastAsync(hClcWindowList,INTM_INVALIDATE,0,0);
+ if (ack->result == ACKRESULT_SUCCESS) {
+ for (i = 0; i < cli.hClcProtoCount; i++) {
+ if (!lstrcmpA(cli.clcProto[i].szProto, ack->szModule)) {
+ cli.clcProto[i].dwStatus = (WORD) ack->lParam;
+ break;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static int ClcContactAdded(WPARAM wParam, LPARAM lParam)
+{
+ WindowList_BroadcastAsync(hClcWindowList,INTM_CONTACTADDED,wParam,lParam);
+ return 0;
+}
+
+static int ClcContactDeleted(WPARAM wParam, LPARAM lParam)
+{
+ WindowList_BroadcastAsync(hClcWindowList,INTM_CONTACTDELETED,wParam,lParam);
+ return 0;
+}
+
+static int ClcContactIconChanged(WPARAM wParam, LPARAM lParam)
+{
+ WindowList_BroadcastAsync(hClcWindowList,INTM_ICONCHANGED,wParam,lParam);
+ return 0;
+}
+
+static int ClcIconsChanged(WPARAM wParam, LPARAM lParam)
+{
+ WindowList_BroadcastAsync(hClcWindowList,INTM_INVALIDATE,0,0);
+ return 0;
+}
+
+static int SetInfoTipHoverTime(WPARAM wParam, LPARAM lParam)
+{
+ DBWriteContactSettingWord(NULL, "CLC", "InfoTipHoverTime", (WORD) wParam);
+ cli.pfnClcBroadcast( INTM_SETINFOTIPHOVERTIME, wParam, 0);
+ return 0;
+}
+
+static int GetInfoTipHoverTime(WPARAM wParam, LPARAM lParam)
+{
+ return DBGetContactSettingWord(NULL, "CLC", "InfoTipHoverTime", 750);
+}
+
+static int ClcShutdown(WPARAM wParam, LPARAM lParam)
+{
+ UnhookEvent(hAckHook);
+ UnhookEvent(hClcSettingsChanged);
+ if (cli.clcProto) mir_free(cli.clcProto);
+ FreeFileDropping();
+ FreeDisplayNameCache();
+ return 0;
+}
+
+static void SortClcByTimer( HWND hwnd )
+{
+ KillTimer( hwnd, TIMERID_DELAYEDRESORTCLC );
+ SetTimer( hwnd, TIMERID_DELAYEDRESORTCLC, 200, NULL );
+}
+
+int LoadCLCModule(void)
+{
+ g_IconWidth = GetSystemMetrics(SM_CXSMICON);
+ g_IconHeight = GetSystemMetrics(SM_CYSMICON);
+
+ hClcWindowList = (HANDLE) CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0);
+ hShowInfoTipEvent = CreateHookableEvent(ME_CLC_SHOWINFOTIP);
+ hHideInfoTipEvent = CreateHookableEvent(ME_CLC_HIDEINFOTIP);
+ CreateServiceFunction(MS_CLC_SETINFOTIPHOVERTIME, SetInfoTipHoverTime);
+ CreateServiceFunction(MS_CLC_GETINFOTIPHOVERTIME, GetInfoTipHoverTime);
+
+ InitFileDropping();
+
+ HookEvent(ME_SYSTEM_MODULESLOADED, ClcModulesLoaded);
+ hClcSettingsChanged = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, ClcSettingChanged);
+ HookEvent(ME_DB_CONTACT_ADDED, ClcContactAdded);
+ HookEvent(ME_DB_CONTACT_DELETED, ClcContactDeleted);
+ HookEvent(ME_CLIST_CONTACTICONCHANGED, ClcContactIconChanged);
+ HookEvent(ME_SKIN_ICONSCHANGED, ClcIconsChanged);
+ hAckHook = (HANDLE) HookEvent(ME_PROTO_ACK, ClcProtoAck);
+ HookEvent(ME_SYSTEM_SHUTDOWN, ClcShutdown);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// default contact list control window procedure
+
+LRESULT CALLBACK fnContactListControlWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct ClcData *dat;
+
+ dat = (struct ClcData *) GetWindowLong(hwnd, 0);
+ if (msg >= CLM_FIRST && msg < CLM_LAST)
+ return cli.pfnProcessExternalMessages(hwnd, dat, msg, wParam, lParam);
+
+ switch (msg) {
+ case WM_CREATE:
+ WindowList_Add(hClcWindowList, hwnd, NULL);
+ cli.pfnRegisterFileDropping(hwnd);
+ if ( dat == NULL ) {
+ dat = (struct ClcData *) mir_calloc(sizeof(struct ClcData));
+ SetWindowLong(hwnd, 0, (LONG) dat);
+ }
+ {
+ int i;
+ for (i = 0; i <= FONTID_MAX; i++)
+ dat->fontInfo[i].changed = 1;
+ }
+ dat->selection = -1;
+ dat->iconXSpace = 20;
+ dat->checkboxSize = 13;
+ dat->dragAutoScrollHeight = 30;
+ dat->iDragItem = -1;
+ dat->iInsertionMark = -1;
+ dat->insertionMarkHitHeight = 5;
+ dat->iHotTrack = -1;
+ dat->infoTipTimeout = DBGetContactSettingWord(NULL, "CLC", "InfoTipHoverTime", 750);
+ dat->extraColumnSpacing = 20;
+ dat->list.cl.increment = 30;
+ dat->needsResort = 1;
+ cli.pfnLoadClcOptions(hwnd, dat);
+ if (!IsWindowVisible(hwnd))
+ SetTimer(hwnd,TIMERID_REBUILDAFTER,10,NULL);
+ else
+ cli.pfnRebuildEntireList(hwnd,dat);
+ {
+ NMCLISTCONTROL nm;
+ nm.hdr.code = CLN_LISTREBUILT;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+ }
+ break;
+ case INTM_SCROLLBARCHANGED:
+ if (GetWindowLong(hwnd, GWL_STYLE) & CLS_CONTACTLIST) {
+ if (dat->noVScrollbar)
+ ShowScrollBar(hwnd, SB_VERT, FALSE);
+ else
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ }
+ break;
+
+ case INTM_RELOADOPTIONS:
+ cli.pfnLoadClcOptions(hwnd, dat);
+ cli.pfnSaveStateAndRebuildList(hwnd, dat);
+ break;
+ case WM_THEMECHANGED:
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+ case WM_SIZE:
+ cli.pfnEndRename(hwnd, dat, 1);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ { //creating imagelist containing blue line for highlight
+ HBITMAP hBmp, hBmpMask, hoBmp, hoMaskBmp;
+ HDC hdc,hdcMem;
+ RECT rc;
+ int depth;
+ HBRUSH hBrush;
+
+ GetClientRect(hwnd, &rc);
+ if (rc.right == 0)
+ break;
+ rc.bottom = dat->rowHeight;
+ hdc = GetDC(hwnd);
+ depth = GetDeviceCaps(hdc, BITSPIXEL);
+ if (depth < 16)
+ depth = 16;
+ hBmp = CreateBitmap(rc.right, rc.bottom, 1, depth, NULL);
+ hBmpMask = CreateBitmap(rc.right, rc.bottom, 1, 1, NULL);
+ hdcMem = CreateCompatibleDC(hdc);
+ hoBmp = (HBITMAP) SelectObject(hdcMem, hBmp);
+ hBrush = CreateSolidBrush(dat->useWindowsColours ? GetSysColor(COLOR_HIGHLIGHT) : dat->selBkColour);
+ FillRect(hdcMem, &rc, hBrush);
+ DeleteObject(hBrush);
+
+ hoMaskBmp = SelectObject(hdcMem, hBmpMask);
+ FillRect(hdcMem, &rc, GetStockObject(BLACK_BRUSH));
+ SelectObject(hdcMem, hoMaskBmp);
+ SelectObject(hdcMem, hoBmp);
+ DeleteDC(hdcMem);
+ ReleaseDC(hwnd, hdc);
+ if (dat->himlHighlight)
+ ImageList_Destroy(dat->himlHighlight);
+ dat->himlHighlight = ImageList_Create(rc.right, rc.bottom, (IsWinVerXPPlus()? ILC_COLOR32 : ILC_COLOR16) | ILC_MASK, 1, 1);
+ ImageList_Add(dat->himlHighlight, hBmp, hBmpMask);
+ DeleteObject(hBmpMask);
+ DeleteObject(hBmp);
+ }
+ break;
+
+ case WM_SYSCOLORCHANGE:
+ SendMessage(hwnd, WM_SIZE, 0, 0);
+ break;
+
+ case WM_GETDLGCODE:
+ if (lParam) {
+ MSG *msg = (MSG *) lParam;
+ if (msg->message == WM_KEYDOWN) {
+ if (msg->wParam == VK_TAB)
+ return 0;
+ if (msg->wParam == VK_ESCAPE && dat->hwndRenameEdit == NULL && dat->szQuickSearch[0] == 0)
+ return 0;
+ }
+ if (msg->message == WM_CHAR) {
+ if (msg->wParam == '\t')
+ return 0;
+ if (msg->wParam == 27 && dat->hwndRenameEdit == NULL && dat->szQuickSearch[0] == 0)
+ return 0;
+ }
+ }
+ return DLGC_WANTMESSAGE;
+
+ case WM_KILLFOCUS:
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ case WM_SETFOCUS:
+ case WM_ENABLE:
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case WM_GETFONT:
+ return (LRESULT) dat->fontInfo[FONTID_CONTACTS].hFont;
+
+ case INTM_GROUPSCHANGED:
+ {
+ DBCONTACTWRITESETTING *dbcws = (DBCONTACTWRITESETTING *) lParam;
+ if (dbcws->value.type == DBVT_ASCIIZ || dbcws->value.type == DBVT_UTF8) {
+ int groupId = atoi(dbcws->szSetting) + 1;
+ struct ClcContact *contact;
+ struct ClcGroup *group;
+ TCHAR szFullName[512];
+ int i, nameLen, eq;
+ //check name of group and ignore message if just being expanded/collapsed
+ if (cli.pfnFindItem(hwnd, dat, (HANDLE) (groupId | HCONTACT_ISGROUP), &contact, &group, NULL)) {
+ lstrcpy(szFullName, contact->szText);
+ while (group->parent) {
+ for (i = 0; i < group->parent->cl.count; i++)
+ if (group->parent->cl.items[i]->group == group)
+ break;
+ if (i == group->parent->cl.count) {
+ szFullName[0] = '\0';
+ break;
+ }
+ group = group->parent;
+ nameLen = lstrlen(group->cl.items[i]->szText);
+ if (lstrlen(szFullName) + 1 + nameLen > SIZEOF(szFullName)) {
+ szFullName[0] = '\0';
+ break;
+ }
+ memmove(szFullName + 1 + nameLen, szFullName, sizeof( TCHAR )*( lstrlen(szFullName) + 1));
+ memcpy(szFullName, group->cl.items[i]->szText, sizeof( TCHAR )*nameLen);
+ szFullName[nameLen] = '\\';
+ }
+
+ if ( dbcws->value.type == DBVT_ASCIIZ )
+ #if defined( UNICODE )
+ { WCHAR* wszGrpName = a2u(dbcws->value.pszVal+1);
+ eq = !lstrcmp( szFullName, wszGrpName );
+ mir_free( wszGrpName );
+ }
+ #else
+ eq = !lstrcmp( szFullName, dbcws->value.pszVal+1 );
+ #endif
+ else {
+ char* szGrpName = NEWSTR_ALLOCA(dbcws->value.pszVal+1);
+ #if defined( UNICODE )
+ WCHAR* wszGrpName;
+ Utf8Decode(szGrpName, &wszGrpName );
+ eq = !lstrcmp( szFullName, wszGrpName );
+ mir_free( wszGrpName );
+
+ #else
+ Utf8Decode(szGrpName, NULL);
+ eq = !lstrcmp( szFullName, szGrpName );
+ #endif
+ }
+ if ( eq && (contact->group->hideOffline != 0) == ((dbcws->value.pszVal[0] & GROUPF_HIDEOFFLINE) != 0))
+ break; //only expanded has changed: no action reqd
+ }
+ }
+ cli.pfnSaveStateAndRebuildList(hwnd, dat);
+ break;
+ }
+ case INTM_NAMEORDERCHANGED:
+ PostMessage(hwnd, CLM_AUTOREBUILD, 0, 0);
+ break;
+
+ case INTM_CONTACTADDED:
+ cli.pfnAddContactToTree(hwnd, dat, (HANDLE) wParam, 1, 1);
+ cli.pfnNotifyNewContact(hwnd, (HANDLE) wParam);
+ SortClcByTimer(hwnd);
+ break;
+
+ case INTM_CONTACTDELETED:
+ cli.pfnDeleteItemFromTree(hwnd, (HANDLE) wParam);
+ SortClcByTimer(hwnd);
+ break;
+
+ case INTM_HIDDENCHANGED:
+ {
+ DBCONTACTWRITESETTING *dbcws = (DBCONTACTWRITESETTING *) lParam;
+ if (GetWindowLong(hwnd, GWL_STYLE) & CLS_SHOWHIDDEN)
+ break;
+ if (dbcws->value.type == DBVT_DELETED || dbcws->value.bVal == 0) {
+ if (cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, NULL, NULL, NULL))
+ break;
+ cli.pfnAddContactToTree(hwnd, dat, (HANDLE) wParam, 1, 1);
+ cli.pfnNotifyNewContact(hwnd, (HANDLE) wParam);
+ }
+ else cli.pfnDeleteItemFromTree(hwnd, (HANDLE) wParam);
+
+ dat->needsResort = 1;
+ SortClcByTimer(hwnd);
+ break;
+ }
+ case INTM_GROUPCHANGED:
+ {
+ struct ClcContact *contact;
+ BYTE iExtraImage[MAXEXTRACOLUMNS];
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ memset(iExtraImage, 0xFF, SIZEOF(iExtraImage));
+ else
+ CopyMemory(iExtraImage, contact->iExtraImage, SIZEOF(iExtraImage));
+ cli.pfnDeleteItemFromTree(hwnd, (HANDLE) wParam);
+ if (GetWindowLong(hwnd, GWL_STYLE) & CLS_SHOWHIDDEN || !DBGetContactSettingByte((HANDLE) wParam, "CList", "Hidden", 0)) {
+ NMCLISTCONTROL nm;
+ cli.pfnAddContactToTree(hwnd, dat, (HANDLE) wParam, 1, 1);
+ if (cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ CopyMemory(contact->iExtraImage, iExtraImage, SIZEOF(iExtraImage));
+ nm.hdr.code = CLN_CONTACTMOVED;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = (HANDLE) wParam;
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+ dat->needsResort = 1;
+ }
+ SetTimer(hwnd,TIMERID_REBUILDAFTER,1,NULL);
+ break;
+ }
+ case INTM_ICONCHANGED:
+ {
+ struct ClcContact *contact = NULL;
+ struct ClcGroup *group = NULL;
+ int recalcScrollBar = 0, shouldShow;
+ WORD status;
+ char *szProto;
+
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (szProto == NULL)
+ status = ID_STATUS_OFFLINE;
+ else
+ status = DBGetContactSettingWord((HANDLE) wParam, szProto, "Status", ID_STATUS_OFFLINE);
+
+ shouldShow = (GetWindowLong(hwnd, GWL_STYLE) & CLS_SHOWHIDDEN || !DBGetContactSettingByte((HANDLE) wParam, "CList", "Hidden", 0))
+ && (!cli.pfnIsHiddenMode(dat, status)
+ || CallService(MS_CLIST_GETCONTACTICON, wParam, 0) != lParam); //this means an offline msg is flashing, so the contact should be shown
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, &group, NULL)) {
+ if (shouldShow) {
+ cli.pfnAddContactToTree(hwnd, dat, (HANDLE) wParam, 0, 0);
+ recalcScrollBar = 1;
+ cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL);
+ if (contact) {
+ contact->iImage = (WORD) lParam;
+ cli.pfnNotifyNewContact(hwnd, (HANDLE) wParam);
+ dat->needsResort = 1;
+ } }
+ }
+ else { //item in list already
+ DWORD style = GetWindowLong(hwnd, GWL_STYLE);
+ if (contact->iImage == (WORD) lParam)
+ break;
+ if (!shouldShow && !(style & CLS_NOHIDEOFFLINE) && (style & CLS_HIDEOFFLINE || group->hideOffline)) {
+ HANDLE hSelItem;
+ struct ClcContact *selcontact;
+ struct ClcGroup *selgroup;
+ if (cli.pfnGetRowByIndex(dat, dat->selection, &selcontact, NULL) == -1)
+ hSelItem = NULL;
+ else
+ hSelItem = cli.pfnContactToHItem(selcontact);
+ cli.pfnRemoveItemFromGroup(hwnd, group, contact, 0);
+ if (hSelItem)
+ if (cli.pfnFindItem(hwnd, dat, hSelItem, &selcontact, &selgroup, NULL))
+ dat->selection = cli.pfnGetRowsPriorTo(&dat->list, selgroup, List_IndexOf(( SortedList* )&selgroup->cl, selcontact));
+
+ recalcScrollBar = 1;
+ }
+ else {
+ contact->iImage = (WORD) lParam;
+ if (!cli.pfnIsHiddenMode(dat, status))
+ contact->flags |= CONTACTF_ONLINE;
+ else
+ contact->flags &= ~CONTACTF_ONLINE;
+ }
+ dat->needsResort = 1;
+ }
+ SortClcByTimer(hwnd);
+ break;
+ }
+ case INTM_NAMECHANGED:
+ {
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+
+ lstrcpyn(contact->szText, cli.pfnGetContactDisplayName((HANDLE)wParam,0), SIZEOF(contact->szText));
+ dat->needsResort = 1;
+ SortClcByTimer(hwnd);
+ break;
+ }
+ case INTM_PROTOCHANGED:
+ {
+ struct ClcContact *contact = NULL;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+ contact->proto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ cli.pfnInvalidateDisplayNameCacheEntry((HANDLE)wParam);
+ lstrcpyn(contact->szText, cli.pfnGetContactDisplayName((HANDLE)wParam,0), SIZEOF(contact->szText));
+ SortClcByTimer(hwnd);
+ break;
+ }
+ case INTM_NOTONLISTCHANGED:
+ {
+ DBCONTACTWRITESETTING *dbcws = (DBCONTACTWRITESETTING *) lParam;
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+ if (contact->type != CLCIT_CONTACT)
+ break;
+ if (dbcws->value.type == DBVT_DELETED || dbcws->value.bVal == 0)
+ contact->flags &= ~CONTACTF_NOTONLIST;
+ else
+ contact->flags |= CONTACTF_NOTONLIST;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+ }
+ case INTM_INVALIDATE:
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case INTM_APPARENTMODECHANGED:
+ {
+ WORD apparentMode;
+ char *szProto;
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (szProto == NULL)
+ break;
+ apparentMode = DBGetContactSettingWord((HANDLE) wParam, szProto, "ApparentMode", 0);
+ contact->flags &= ~(CONTACTF_INVISTO | CONTACTF_VISTO);
+ if (apparentMode == ID_STATUS_OFFLINE)
+ contact->flags |= CONTACTF_INVISTO;
+ else if (apparentMode == ID_STATUS_ONLINE)
+ contact->flags |= CONTACTF_VISTO;
+ else if (apparentMode)
+ contact->flags |= CONTACTF_VISTO | CONTACTF_INVISTO;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+ }
+ case INTM_SETINFOTIPHOVERTIME:
+ dat->infoTipTimeout = wParam;
+ break;
+
+ case INTM_IDLECHANGED:
+ {
+ char *szProto;
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (szProto == NULL)
+ break;
+ contact->flags &= ~CONTACTF_IDLE;
+ if (DBGetContactSettingDword((HANDLE) wParam, szProto, "IdleTS", 0)) {
+ contact->flags |= CONTACTF_IDLE;
+ }
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+ }
+ case WM_PRINTCLIENT:
+ cli.pfnPaintClc(hwnd, dat, (HDC) wParam, NULL);
+ break;
+
+ case WM_NCPAINT:
+ if (wParam == 1)
+ break;
+ {
+ POINT ptTopLeft = { 0, 0 };
+ HRGN hClientRgn;
+ ClientToScreen(hwnd, &ptTopLeft);
+ hClientRgn = CreateRectRgn(0, 0, 1, 1);
+ CombineRgn(hClientRgn, (HRGN) wParam, NULL, RGN_COPY);
+ OffsetRgn(hClientRgn, -ptTopLeft.x, -ptTopLeft.y);
+ InvalidateRgn(hwnd, hClientRgn, FALSE);
+ DeleteObject(hClientRgn);
+ UpdateWindow(hwnd);
+ }
+ break;
+
+ case WM_PAINT:
+ {
+ HDC hdc;
+ PAINTSTRUCT ps;
+ hdc = BeginPaint(hwnd, &ps);
+ /* we get so many cli.pfnInvalidateRect()'s that there is no point painting,
+ Windows in theory shouldn't queue up WM_PAINTs in this case but it does so
+ we'll just ignore them */
+ if (IsWindowVisible(hwnd))
+ cli.pfnPaintClc(hwnd, dat, hdc, &ps.rcPaint);
+ EndPaint(hwnd, &ps);
+ break;
+ }
+ case WM_VSCROLL:
+ {
+ int desty;
+ RECT clRect;
+ int noSmooth = 0;
+
+ cli.pfnEndRename(hwnd, dat, 1);
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ desty = dat->yScroll;
+ GetClientRect(hwnd, &clRect);
+ switch (LOWORD(wParam)) {
+ case SB_LINEUP: desty -= dat->rowHeight; break;
+ case SB_LINEDOWN: desty += dat->rowHeight; break;
+ case SB_PAGEUP: desty -= clRect.bottom - dat->rowHeight; break;
+ case SB_PAGEDOWN: desty += clRect.bottom - dat->rowHeight; break;
+ case SB_BOTTOM: desty = 0x7FFFFFFF; break;
+ case SB_TOP: desty = 0; break;
+ case SB_THUMBTRACK: desty = HIWORD(wParam); noSmooth = 1; break; //noone has more than 4000 contacts, right?
+ default: return 0;
+ }
+ cli.pfnScrollTo(hwnd, dat, desty, noSmooth);
+ break;
+ }
+ case WM_MOUSEWHEEL:
+ {
+ UINT scrollLines;
+ cli.pfnEndRename(hwnd, dat, 1);
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &scrollLines, FALSE))
+ scrollLines = 3;
+ cli.pfnScrollTo(hwnd, dat, dat->yScroll - (short) HIWORD(wParam) * dat->rowHeight * (signed) scrollLines / WHEEL_DELTA, 0);
+ return 0;
+ }
+ case WM_KEYDOWN:
+ {
+ int selMoved = 0;
+ int changeGroupExpand = 0;
+ int pageSize;
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ if (CallService(MS_CLIST_MENUPROCESSHOTKEY, wParam, MPCF_CONTACTMENU))
+ break;
+ {
+ RECT clRect;
+ GetClientRect(hwnd, &clRect);
+ pageSize = clRect.bottom / dat->rowHeight;
+ }
+ switch (wParam) {
+ case VK_DOWN: dat->selection++; selMoved = 1; break;
+ case VK_UP: dat->selection--; selMoved = 1; break;
+ case VK_PRIOR: dat->selection -= pageSize; selMoved = 1; break;
+ case VK_NEXT: dat->selection += pageSize; selMoved = 1; break;
+ case VK_HOME: dat->selection = 0; selMoved = 1; break;
+ case VK_END: dat->selection = cli.pfnGetGroupContentsCount(&dat->list, 1) - 1; selMoved = 1; break;
+ case VK_LEFT: changeGroupExpand = 1; break;
+ case VK_RIGHT: changeGroupExpand = 2; break;
+ case VK_RETURN: cli.pfnDoSelectionDefaultAction(hwnd, dat); return 0;
+ case VK_F2: cli.pfnBeginRenameSelection(hwnd, dat); return 0;
+ case VK_DELETE: cli.pfnDeleteFromContactList(hwnd, dat); return 0;
+ default:
+ {
+ NMKEY nmkey;
+ nmkey.hdr.hwndFrom = hwnd;
+ nmkey.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nmkey.hdr.code = NM_KEYDOWN;
+ nmkey.nVKey = wParam;
+ nmkey.uFlags = HIWORD(lParam);
+ if (SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nmkey))
+ return 0;
+ }
+ }
+ if (changeGroupExpand) {
+ int hit;
+ struct ClcContact *contact;
+ struct ClcGroup *group;
+ dat->szQuickSearch[0] = 0;
+ hit = cli.pfnGetRowByIndex(dat, dat->selection, &contact, &group);
+ if (hit != -1) {
+ if (changeGroupExpand == 1 && contact->type == CLCIT_CONTACT) {
+ if (group == &dat->list)
+ return 0;
+ dat->selection = cli.pfnGetRowsPriorTo(&dat->list, group, -1);
+ selMoved = 1;
+ }
+ else {
+ if (contact->type == CLCIT_GROUP)
+ cli.pfnSetGroupExpand(hwnd, dat, contact->group, changeGroupExpand == 2);
+ return 0;
+ }
+ }
+ else
+ return 0;
+ }
+ if (selMoved) {
+ dat->szQuickSearch[0] = 0;
+ if (dat->selection >= cli.pfnGetGroupContentsCount(&dat->list, 1))
+ dat->selection = cli.pfnGetGroupContentsCount(&dat->list, 1) - 1;
+ if (dat->selection < 0)
+ dat->selection = 0;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ cli.pfnEnsureVisible(hwnd, dat, dat->selection, 0);
+ UpdateWindow(hwnd);
+ return 0;
+ }
+ break;
+ }
+ case WM_CHAR:
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ if (wParam == 27) //escape
+ dat->szQuickSearch[0] = 0;
+ else if (wParam == '\b' && dat->szQuickSearch[0])
+ dat->szQuickSearch[lstrlen(dat->szQuickSearch) - 1] = '\0';
+ else if (wParam < ' ')
+ break;
+ else if (wParam == ' ' && dat->szQuickSearch[0] == '\0' && GetWindowLong(hwnd, GWL_STYLE) & CLS_CHECKBOXES) {
+ struct ClcContact *contact;
+ NMCLISTCONTROL nm;
+ if (cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL) == -1)
+ break;
+ if (contact->type != CLCIT_CONTACT)
+ break;
+ contact->flags ^= CONTACTF_CHECKED;
+ if (contact->type == CLCIT_GROUP)
+ cli.pfnSetGroupChildCheckboxes(contact->group, contact->flags & CONTACTF_CHECKED);
+ cli.pfnRecalculateGroupCheckboxes(hwnd, dat);
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ nm.hdr.code = CLN_CHECKCHANGED;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = cli.pfnContactToItemHandle(contact, &nm.flags);
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+ }
+ else {
+ TCHAR szNew[2];
+ szNew[0] = (TCHAR) wParam;
+ szNew[1] = '\0';
+ if (lstrlen(dat->szQuickSearch) >= SIZEOF(dat->szQuickSearch) - 1) {
+ MessageBeep(MB_OK);
+ break;
+ }
+ _tcscat(dat->szQuickSearch, szNew);
+ }
+ if (dat->szQuickSearch[0]) {
+ int index;
+ index = cli.pfnFindRowByText(hwnd, dat, dat->szQuickSearch, 1);
+ if (index != -1)
+ dat->selection = index;
+ else {
+ MessageBeep(MB_OK);
+ dat->szQuickSearch[ lstrlen(dat->szQuickSearch) - 1] = '\0';
+ }
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ cli.pfnEnsureVisible(hwnd, dat, dat->selection, 0);
+ }
+ else
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case WM_SYSKEYDOWN:
+ cli.pfnEndRename(hwnd, dat, 1);
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ dat->iHotTrack = -1;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ ReleaseCapture();
+ if (wParam == VK_F10 && GetKeyState(VK_SHIFT) & 0x8000)
+ break;
+ SendMessage(GetParent(hwnd), msg, wParam, lParam);
+ return 0;
+
+ case WM_TIMER:
+ switch( wParam ) {
+ case TIMERID_RENAME:
+ cli.pfnBeginRenameSelection(hwnd, dat);
+ break;
+ case TIMERID_DRAGAUTOSCROLL:
+ cli.pfnScrollTo(hwnd, dat, dat->yScroll + dat->dragAutoScrolling * dat->rowHeight * 2, 0);
+ break;
+ case TIMERID_INFOTIP:
+ { CLCINFOTIP it;
+ struct ClcContact *contact;
+ int hit;
+ RECT clRect;
+ POINT ptClientOffset = { 0 };
+
+ KillTimer(hwnd, wParam);
+ GetCursorPos(&it.ptCursor);
+ ScreenToClient(hwnd, &it.ptCursor);
+ if (it.ptCursor.x != dat->ptInfoTip.x || it.ptCursor.y != dat->ptInfoTip.y)
+ break;
+ GetClientRect(hwnd, &clRect);
+ it.rcItem.left = 0;
+ it.rcItem.right = clRect.right;
+ hit = cli.pfnHitTest(hwnd, dat, it.ptCursor.x, it.ptCursor.y, &contact, NULL, NULL);
+ if (hit == -1)
+ break;
+ if (contact->type != CLCIT_GROUP && contact->type != CLCIT_CONTACT)
+ break;
+ ClientToScreen(hwnd, &it.ptCursor);
+ ClientToScreen(hwnd, &ptClientOffset);
+ it.isTreeFocused = GetFocus() == hwnd;
+ it.rcItem.top = cli.pfnGetRowTopY(dat, hit) - dat->yScroll;
+ it.rcItem.bottom = it.rcItem.top + cli.pfnGetRowHeight(dat, hit);
+ OffsetRect(&it.rcItem, ptClientOffset.x, ptClientOffset.y);
+ it.isGroup = contact->type == CLCIT_GROUP;
+ it.hItem = contact->type == CLCIT_GROUP ? (HANDLE) contact->groupId : contact->hContact;
+ it.cbSize = sizeof(it);
+ dat->hInfoTipItem = cli.pfnContactToHItem(contact);
+ NotifyEventHooks(hShowInfoTipEvent, 0, (LPARAM) & it);
+ break;
+ }
+ case TIMERID_REBUILDAFTER:
+ KillTimer(hwnd,TIMERID_REBUILDAFTER);
+ cli.pfnInvalidateRect(hwnd,NULL,FALSE);
+ cli.pfnSaveStateAndRebuildList(hwnd,dat);
+ break;
+
+ case TIMERID_DELAYEDRESORTCLC:
+ KillTimer(hwnd,TIMERID_DELAYEDRESORTCLC);
+ cli.pfnInvalidateRect(hwnd,NULL,FALSE);
+ cli.pfnSortCLC(hwnd,dat,1);
+ cli.pfnRecalcScrollBar(hwnd,dat);
+ break;
+ }
+ break;
+
+ case WM_MBUTTONDOWN:
+ case WM_LBUTTONDOWN:
+ {
+ struct ClcContact *contact;
+ struct ClcGroup *group;
+ int hit;
+ DWORD hitFlags;
+
+ if (GetFocus() != hwnd)
+ SetFocus(hwnd);
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ cli.pfnEndRename(hwnd, dat, 1);
+ dat->ptDragStart.x = (short) LOWORD(lParam);
+ dat->ptDragStart.y = (short) HIWORD(lParam);
+ dat->szQuickSearch[0] = 0;
+ hit = cli.pfnHitTest(hwnd, dat, (short) LOWORD(lParam), (short) HIWORD(lParam), &contact, &group, &hitFlags);
+ if (hit != -1) {
+ if (hit == dat->selection && hitFlags & CLCHT_ONITEMLABEL && dat->exStyle & CLS_EX_EDITLABELS) {
+ SetCapture(hwnd);
+ dat->iDragItem = dat->selection;
+ dat->dragStage = DRAGSTAGE_NOTMOVED | DRAGSTAGEF_MAYBERENAME;
+ dat->dragAutoScrolling = 0;
+ break;
+ } }
+
+ if (hit != -1 && contact->type == CLCIT_GROUP)
+ if (hitFlags & CLCHT_ONITEMICON) {
+ struct ClcGroup *selgroup;
+ struct ClcContact *selcontact;
+ dat->selection = cli.pfnGetRowByIndex(dat, dat->selection, &selcontact, &selgroup);
+ cli.pfnSetGroupExpand(hwnd, dat, contact->group, -1);
+ if (dat->selection != -1) {
+ dat->selection =
+ cli.pfnGetRowsPriorTo(&dat->list, selgroup, List_IndexOf((SortedList*)&selgroup->cl,selcontact));
+ if (dat->selection == -1)
+ dat->selection = cli.pfnGetRowsPriorTo(&dat->list, contact->group, -1);
+ }
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ UpdateWindow(hwnd);
+ break;
+ }
+ if (hit != -1 && hitFlags & CLCHT_ONITEMCHECK) {
+ NMCLISTCONTROL nm;
+ contact->flags ^= CONTACTF_CHECKED;
+ if (contact->type == CLCIT_GROUP)
+ cli.pfnSetGroupChildCheckboxes(contact->group, contact->flags & CONTACTF_CHECKED);
+ cli.pfnRecalculateGroupCheckboxes(hwnd, dat);
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ nm.hdr.code = CLN_CHECKCHANGED;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = cli.pfnContactToItemHandle(contact, &nm.flags);
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+ }
+ if (!(hitFlags & (CLCHT_ONITEMICON | CLCHT_ONITEMLABEL | CLCHT_ONITEMCHECK))) {
+ NMCLISTCONTROL nm;
+ nm.hdr.code = NM_CLICK;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ if (hit == -1)
+ nm.hItem = NULL;
+ else
+ nm.hItem = cli.pfnContactToItemHandle(contact, &nm.flags);
+ nm.iColumn = hitFlags & CLCHT_ONITEMEXTRA ? HIBYTE(HIWORD(hitFlags)) : -1;
+ nm.pt = dat->ptDragStart;
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+ }
+ if (hitFlags & (CLCHT_ONITEMCHECK | CLCHT_ONITEMEXTRA))
+ break;
+ dat->selection = hit;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ if (dat->selection != -1)
+ cli.pfnEnsureVisible(hwnd, dat, hit, 0);
+ UpdateWindow(hwnd);
+ if (dat->selection != -1 && (contact->type == CLCIT_CONTACT || contact->type == CLCIT_GROUP)
+ && !(hitFlags & (CLCHT_ONITEMEXTRA | CLCHT_ONITEMCHECK))) {
+ SetCapture(hwnd);
+ dat->iDragItem = dat->selection;
+ dat->dragStage = DRAGSTAGE_NOTMOVED;
+ dat->dragAutoScrolling = 0;
+ }
+ break;
+ }
+ case WM_MOUSEMOVE:
+ if (dat->iDragItem == -1) {
+ int iOldHotTrack = dat->iHotTrack;
+ if (dat->hwndRenameEdit != NULL)
+ break;
+ if (GetKeyState(VK_MENU) & 0x8000 || GetKeyState(VK_F10) & 0x8000)
+ break;
+ dat->iHotTrack = cli.pfnHitTest(hwnd, dat, (short) LOWORD(lParam), (short) HIWORD(lParam), NULL, NULL, NULL);
+ if (iOldHotTrack != dat->iHotTrack) {
+ if (iOldHotTrack == -1)
+ SetCapture(hwnd);
+ else if (dat->iHotTrack == -1)
+ ReleaseCapture();
+ if (dat->exStyle & CLS_EX_TRACKSELECT) {
+ cli.pfnInvalidateItem(hwnd, dat, iOldHotTrack);
+ cli.pfnInvalidateItem(hwnd, dat, dat->iHotTrack);
+ }
+ cli.pfnHideInfoTip(hwnd, dat);
+ }
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ if (wParam == 0 && dat->hInfoTipItem == NULL) {
+ dat->ptInfoTip.x = (short) LOWORD(lParam);
+ dat->ptInfoTip.y = (short) HIWORD(lParam);
+ SetTimer(hwnd, TIMERID_INFOTIP, dat->infoTipTimeout, NULL);
+ }
+ break;
+ }
+ if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_NOTMOVED && !(dat->exStyle & CLS_EX_DISABLEDRAGDROP)) {
+ if (abs((short) LOWORD(lParam) - dat->ptDragStart.x) >= GetSystemMetrics(SM_CXDRAG)
+ || abs((short) HIWORD(lParam) - dat->ptDragStart.y) >= GetSystemMetrics(SM_CYDRAG))
+ dat->dragStage = (dat->dragStage & ~DRAGSTAGEM_STAGE) | DRAGSTAGE_ACTIVE;
+ }
+ if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_ACTIVE) {
+ HCURSOR hNewCursor;
+ RECT clRect;
+ POINT pt;
+ int target;
+
+ GetClientRect(hwnd, &clRect);
+ pt.x = (short) LOWORD(lParam);
+ pt.y = (short) HIWORD(lParam);
+ hNewCursor = LoadCursor(NULL, IDC_NO);
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ if (dat->dragAutoScrolling) {
+ KillTimer(hwnd, TIMERID_DRAGAUTOSCROLL);
+ dat->dragAutoScrolling = 0;
+ }
+ target = cli.pfnGetDropTargetInformation(hwnd, dat, pt);
+ if (dat->dragStage & DRAGSTAGEF_OUTSIDE && target != DROPTARGET_OUTSIDE) {
+ NMCLISTCONTROL nm;
+ struct ClcContact *contact;
+ cli.pfnGetRowByIndex(dat, dat->iDragItem, &contact, NULL);
+ nm.hdr.code = CLN_DRAGSTOP;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = cli.pfnContactToItemHandle(contact, &nm.flags);
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+ dat->dragStage &= ~DRAGSTAGEF_OUTSIDE;
+ }
+ switch (target) {
+ case DROPTARGET_ONSELF:
+ case DROPTARGET_ONCONTACT:
+ break;
+ case DROPTARGET_ONGROUP:
+ hNewCursor = LoadCursor(cli.hInst, MAKEINTRESOURCE(IDC_DROPUSER));
+ break;
+ case DROPTARGET_INSERTION:
+ hNewCursor = LoadCursor(cli.hInst, MAKEINTRESOURCE(IDC_DROPUSER));
+ break;
+ case DROPTARGET_OUTSIDE:
+ {
+ NMCLISTCONTROL nm;
+ struct ClcContact *contact;
+
+ if (pt.x >= 0 && pt.x < clRect.right
+ && ((pt.y < 0 && pt.y > -dat->dragAutoScrollHeight)
+ || (pt.y >= clRect.bottom && pt.y < clRect.bottom + dat->dragAutoScrollHeight))) {
+ if (!dat->dragAutoScrolling) {
+ if (pt.y < 0)
+ dat->dragAutoScrolling = -1;
+ else
+ dat->dragAutoScrolling = 1;
+ SetTimer(hwnd, TIMERID_DRAGAUTOSCROLL, dat->scrollTime, NULL);
+ }
+ SendMessage(hwnd, WM_TIMER, TIMERID_DRAGAUTOSCROLL, 0);
+ }
+
+ dat->dragStage |= DRAGSTAGEF_OUTSIDE;
+ cli.pfnGetRowByIndex(dat, dat->iDragItem, &contact, NULL);
+ nm.hdr.code = CLN_DRAGGING;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = cli.pfnContactToItemHandle(contact, &nm.flags);
+ nm.pt = pt;
+ if (SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm))
+ return 0;
+ break;
+ }
+ default:
+ {
+ struct ClcGroup *group;
+ cli.pfnGetRowByIndex(dat, dat->iDragItem, NULL, &group);
+ if (group->parent)
+ hNewCursor = LoadCursor(cli.hInst, MAKEINTRESOURCE(IDC_DROPUSER));
+ break;
+ }
+ }
+ SetCursor(hNewCursor);
+ }
+ break;
+
+ case WM_LBUTTONUP:
+ if (dat->iDragItem == -1)
+ break;
+ SetCursor((HCURSOR) GetClassLong(hwnd, GCL_HCURSOR));
+ if (dat->exStyle & CLS_EX_TRACKSELECT) {
+ dat->iHotTrack = cli.pfnHitTest(hwnd, dat, (short) LOWORD(lParam), (short) HIWORD(lParam), NULL, NULL, NULL);
+ if (dat->iHotTrack == -1)
+ ReleaseCapture();
+ }
+ else ReleaseCapture();
+ KillTimer(hwnd, TIMERID_DRAGAUTOSCROLL);
+ if (dat->dragStage == (DRAGSTAGE_NOTMOVED | DRAGSTAGEF_MAYBERENAME))
+ SetTimer(hwnd, TIMERID_RENAME, GetDoubleClickTime(), NULL);
+ else if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_ACTIVE) {
+ POINT pt;
+ int target;
+
+ pt.x = (short) LOWORD(lParam);
+ pt.y = (short) HIWORD(lParam);
+ target = cli.pfnGetDropTargetInformation(hwnd, dat, pt);
+ switch (target) {
+ case DROPTARGET_ONSELF:
+ break;
+ case DROPTARGET_ONCONTACT:
+ break;
+ case DROPTARGET_ONGROUP:
+ {
+ struct ClcContact *contact;
+ TCHAR *szGroup;
+ cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL);
+ szGroup = cli.pfnGetGroupName(contact->groupId, NULL);
+ cli.pfnGetRowByIndex(dat, dat->iDragItem, &contact, NULL);
+ if (contact->type == CLCIT_CONTACT) //dropee is a contact
+ DBWriteContactSettingTString(contact->hContact, "CList", "Group", szGroup);
+ else if (contact->type == CLCIT_GROUP) { //dropee is a group
+ TCHAR szNewName[120];
+ mir_sntprintf(szNewName, SIZEOF(szNewName), _T("%s\\%s"), szGroup, contact->szText);
+ cli.pfnRenameGroup( contact->groupId, szNewName );
+ }
+ break;
+ }
+ case DROPTARGET_INSERTION:
+ {
+ struct ClcContact *contact, *destcontact;
+ struct ClcGroup *destgroup;
+ cli.pfnGetRowByIndex(dat, dat->iDragItem, &contact, NULL);
+ if (cli.pfnGetRowByIndex(dat, dat->iInsertionMark, &destcontact, &destgroup) == -1 || destgroup != contact->group->parent)
+ CallService(MS_CLIST_GROUPMOVEBEFORE, contact->groupId, 0);
+ else {
+ if (destcontact->type == CLCIT_GROUP)
+ destgroup = destcontact->group;
+ else
+ destgroup = destgroup;
+ CallService(MS_CLIST_GROUPMOVEBEFORE, contact->groupId, destgroup->groupId);
+ }
+ break;
+ }
+ case DROPTARGET_OUTSIDE:
+ {
+ NMCLISTCONTROL nm;
+ struct ClcContact *contact;
+ cli.pfnGetRowByIndex(dat, dat->iDragItem, &contact, NULL);
+ nm.hdr.code = CLN_DROPPED;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = cli.pfnContactToItemHandle(contact, &nm.flags);
+ nm.pt = pt;
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+ break;
+ }
+ default:
+ {
+ struct ClcGroup *group;
+ struct ClcContact *contact;
+ cli.pfnGetRowByIndex(dat, dat->iDragItem, &contact, &group);
+ if (group->parent) { //move to root
+ if (contact->type == CLCIT_CONTACT) //dropee is a contact
+ DBDeleteContactSetting(contact->hContact, "CList", "Group");
+ else if (contact->type == CLCIT_GROUP) { //dropee is a group
+ TCHAR szNewName[120];
+ lstrcpyn(szNewName, contact->szText, SIZEOF(szNewName));
+ cli.pfnRenameGroup( contact->groupId, szNewName );
+ } } } } }
+
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ dat->iDragItem = -1;
+ dat->iInsertionMark = -1;
+ break;
+
+ case WM_LBUTTONDBLCLK:
+ {
+ struct ClcContact *contact;
+ DWORD hitFlags;
+ ReleaseCapture();
+ dat->iHotTrack = -1;
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_RENAME);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ dat->szQuickSearch[0] = 0;
+ dat->selection = cli.pfnHitTest(hwnd, dat, (short) LOWORD(lParam), (short) HIWORD(lParam), &contact, NULL, &hitFlags);
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ if (dat->selection != -1)
+ cli.pfnEnsureVisible(hwnd, dat, dat->selection, 0);
+ if (!(hitFlags & (CLCHT_ONITEMICON | CLCHT_ONITEMLABEL)))
+ break;
+ UpdateWindow(hwnd);
+ cli.pfnDoSelectionDefaultAction(hwnd, dat);
+ break;
+ }
+ case WM_CONTEXTMENU:
+ {
+ struct ClcContact *contact;
+ HMENU hMenu = NULL;
+ POINT pt;
+ DWORD hitFlags;
+
+ cli.pfnEndRename(hwnd, dat, 1);
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_RENAME);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ if (GetFocus() != hwnd)
+ SetFocus(hwnd);
+ dat->iHotTrack = -1;
+ dat->szQuickSearch[0] = 0;
+ pt.x = (short) LOWORD(lParam);
+ pt.y = (short) HIWORD(lParam);
+ if (pt.x == -1 && pt.y == -1) {
+ dat->selection = cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL);
+ if (dat->selection != -1)
+ cli.pfnEnsureVisible(hwnd, dat, dat->selection, 0);
+ pt.x = dat->iconXSpace + 15;
+ pt.y = cli.pfnGetRowTopY(dat, dat->selection) - dat->yScroll + (int)(cli.pfnGetRowHeight(dat, dat->selection) * .7);
+ hitFlags = dat->selection == -1 ? CLCHT_NOWHERE : CLCHT_ONITEMLABEL;
+ }
+ else {
+ ScreenToClient(hwnd, &pt);
+ dat->selection = cli.pfnHitTest(hwnd, dat, pt.x, pt.y, &contact, NULL, &hitFlags);
+ }
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ if (dat->selection != -1)
+ cli.pfnEnsureVisible(hwnd, dat, dat->selection, 0);
+ UpdateWindow(hwnd);
+
+ if (dat->selection != -1 && hitFlags & (CLCHT_ONITEMICON | CLCHT_ONITEMCHECK | CLCHT_ONITEMLABEL)) {
+ if (contact->type == CLCIT_GROUP) {
+ hMenu = cli.pfnBuildGroupPopupMenu(contact->group);
+ ClientToScreen(hwnd, &pt);
+ TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
+ return 0;
+ }
+ else if (contact->type == CLCIT_CONTACT)
+ hMenu = (HMENU) CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM) contact->hContact, 0);
+ }
+ else {
+ //call parent for new group/hide offline menu
+ SendMessage(GetParent(hwnd), WM_CONTEXTMENU, wParam, lParam);
+ }
+ if (hMenu != NULL) {
+ ClientToScreen(hwnd, &pt);
+ TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
+ DestroyMenu(hMenu);
+ }
+ return 0;
+ }
+ case WM_MEASUREITEM:
+ return CallService(MS_CLIST_MENUMEASUREITEM, wParam, lParam);
+
+ case WM_DRAWITEM:
+ return CallService(MS_CLIST_MENUDRAWITEM, wParam, lParam);
+
+ case WM_COMMAND:
+ {
+ struct ClcContact *contact;
+ int hit = cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL);
+ if (hit == -1)
+ break;
+ if (contact->type == CLCIT_CONTACT)
+ if (CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_CONTACTMENU), (LPARAM) contact->hContact))
+ break;
+ switch (LOWORD(wParam)) {
+ case POPUP_NEWSUBGROUP:
+ if (contact->type != CLCIT_GROUP)
+ break;
+ SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~CLS_HIDEEMPTYGROUPS);
+ CallService(MS_CLIST_GROUPCREATE, contact->groupId, 0);
+ break;
+ case POPUP_RENAMEGROUP:
+ cli.pfnBeginRenameSelection(hwnd, dat);
+ break;
+ case POPUP_DELETEGROUP:
+ if (contact->type != CLCIT_GROUP)
+ break;
+ CallService(MS_CLIST_GROUPDELETE, contact->groupId, 0);
+ break;
+ case POPUP_GROUPHIDEOFFLINE:
+ if (contact->type != CLCIT_GROUP)
+ break;
+ CallService(MS_CLIST_GROUPSETFLAGS, contact->groupId,
+ MAKELPARAM(contact->group->hideOffline ? 0 : GROUPF_HIDEOFFLINE, GROUPF_HIDEOFFLINE));
+ break;
+ }
+ break;
+ }
+ case WM_DESTROY:
+ cli.pfnHideInfoTip(hwnd, dat);
+ {
+ int i;
+ for (i = 0; i <= FONTID_MAX; i++)
+ if (!dat->fontInfo[i].changed)
+ DeleteObject(dat->fontInfo[i].hFont);
+ }
+ if (dat->himlHighlight)
+ ImageList_Destroy(dat->himlHighlight);
+ if (dat->hwndRenameEdit)
+ DestroyWindow(dat->hwndRenameEdit);
+ if (!dat->bkChanged && dat->hBmpBackground)
+ DeleteObject(dat->hBmpBackground);
+ cli.pfnFreeGroup(&dat->list);
+ mir_free(dat);
+ cli.pfnUnregisterFileDropping(hwnd);
+ WindowList_Remove(hClcWindowList, hwnd);
+ }
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+}
diff --git a/miranda-wine/src/modules/clist/clc.h b/miranda-wine/src/modules/clist/clc.h
new file mode 100644
index 0000000..4c9b80d
--- /dev/null
+++ b/miranda-wine/src/modules/clist/clc.h
@@ -0,0 +1,154 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+struct ClcContact {
+ BYTE type;
+ BYTE flags;
+ union {
+ struct {
+ WORD iImage;
+ HANDLE hContact;
+ };
+ struct {
+ WORD groupId;
+ struct ClcGroup *group;
+ };
+ };
+ BYTE iExtraImage[MAXEXTRACOLUMNS];
+ TCHAR szText[120-MAXEXTRACOLUMNS];
+ char * proto; // MS_PROTO_GETBASEPROTO
+};
+
+struct ClcData {
+ struct ClcGroup list;
+ int rowHeight;
+ int yScroll;
+ int selection;
+ struct ClcFontInfo fontInfo[FONTID_MAX + 1];
+ int scrollTime;
+ HIMAGELIST himlHighlight;
+ int groupIndent;
+ TCHAR szQuickSearch[128];
+ int iconXSpace;
+ HWND hwndRenameEdit;
+ COLORREF bkColour, selBkColour, selTextColour, hotTextColour, quickSearchColour;
+ int iDragItem, iInsertionMark;
+ int dragStage;
+ POINT ptDragStart;
+ int dragAutoScrolling;
+ int dragAutoScrollHeight;
+ int leftMargin;
+ int insertionMarkHitHeight;
+ HBITMAP hBmpBackground;
+ int backgroundBmpUse, bkChanged;
+ int iHotTrack;
+ int gammaCorrection;
+ DWORD greyoutFlags; //see m_clc.h
+ DWORD offlineModes;
+ DWORD exStyle;
+ POINT ptInfoTip;
+ int infoTipTimeout;
+ HANDLE hInfoTipItem;
+ HIMAGELIST himlExtraColumns;
+ int extraColumnsCount;
+ int extraColumnSpacing;
+ int checkboxSize;
+ int showSelAlways;
+ int showIdle;
+ int noVScrollbar;
+ int useWindowsColours;
+ int needsResort;
+};
+
+//clc.c
+extern int g_IconWidth, g_IconHeight;
+
+//clcidents.c
+int GetRowsPriorTo(struct ClcGroup *group,struct ClcGroup *subgroup,int contactIndex);
+int FindItem(HWND hwnd,struct ClcData *dat,HANDLE hItem,struct ClcContact **contact,struct ClcGroup **subgroup,int *isVisible);
+int GetRowByIndex(struct ClcData *dat,int testindex,struct ClcContact **contact,struct ClcGroup **subgroup);
+HANDLE ContactToHItem(struct ClcContact *contact);
+HANDLE ContactToItemHandle(struct ClcContact *contact,DWORD *nmFlags);
+
+//clcitems.c
+struct ClcGroup *AddGroup(HWND hwnd,struct ClcData *dat,const TCHAR *szName,DWORD flags,int groupId,int calcTotalMembers);
+void FreeGroup(struct ClcGroup *group);
+int AddInfoItemToGroup(struct ClcGroup *group,int flags,const TCHAR *pszText);
+void RebuildEntireList(HWND hwnd,struct ClcData *dat);
+struct ClcGroup *RemoveItemFromGroup(HWND hwnd,struct ClcGroup *group,struct ClcContact *contact,int updateTotalCount);
+void DeleteItemFromTree(HWND hwnd,HANDLE hItem);
+void AddContactToTree(HWND hwnd,struct ClcData *dat,HANDLE hContact,int updateTotalCount,int checkHideOffline);
+void SortCLC(HWND hwnd,struct ClcData *dat,int useInsertionSort);
+int GetGroupContentsCount(struct ClcGroup *group,int visibleOnly);
+void SaveStateAndRebuildList(HWND hwnd,struct ClcData *dat);
+
+//clcmsgs.c
+LRESULT ProcessExternalMessages(HWND hwnd,struct ClcData *dat,UINT msg,WPARAM wParam,LPARAM lParam);
+
+//clcutils.c
+void EnsureVisible(HWND hwnd,struct ClcData *dat,int iItem,int partialOk);
+void RecalcScrollBar(HWND hwnd,struct ClcData *dat);
+void SetGroupExpand(HWND hwnd,struct ClcData *dat,struct ClcGroup *group,int newState);
+void DoSelectionDefaultAction(HWND hwnd,struct ClcData *dat);
+int FindRowByText(HWND hwnd,struct ClcData *dat,const TCHAR *text,int prefixOk);
+void EndRename(HWND hwnd,struct ClcData *dat,int save);
+void DeleteFromContactList(HWND hwnd,struct ClcData *dat);
+void BeginRenameSelection(HWND hwnd,struct ClcData *dat);
+char *GetGroupCountsText(struct ClcData *dat,struct ClcContact *contact);
+int HitTest(HWND hwnd,struct ClcData *dat,int testx,int testy,struct ClcContact **contact,struct ClcGroup **group,DWORD *flags);
+void ScrollTo(HWND hwnd,struct ClcData *dat,int desty,int noSmooth);
+
+int GetDropTargetInformation(HWND hwnd,struct ClcData *dat,POINT pt);
+int ClcStatusToPf2(int status);
+int IsHiddenMode(struct ClcData *dat,int status);
+void HideInfoTip(HWND hwnd,struct ClcData *dat);
+void NotifyNewContact(HWND hwnd,HANDLE hContact);
+void LoadClcOptions(HWND hwnd,struct ClcData *dat);
+void RecalculateGroupCheckboxes(HWND hwnd,struct ClcData *dat);
+void SetGroupChildCheckboxes(struct ClcGroup *group,int checked);
+void InvalidateItem(HWND hwnd,struct ClcData *dat,int iItem);
+
+int fnGetRowBottomY(struct ClcData *dat, int item);
+int fnGetRowHeight(struct ClcData *dat, int item);
+int fnGetRowTopY(struct ClcData *dat, int item);
+int fnGetRowTotalHeight(struct ClcData *dat);
+int fnRowHitTest(struct ClcData *dat, int y);
+
+//clcpaint.c
+void PaintClc(HWND hwnd,struct ClcData *dat,HDC hdc,RECT *rcPaint);
+
+//clcopts.c
+int ClcOptInit(WPARAM wParam,LPARAM lParam);
+DWORD GetDefaultExStyle(void);
+void GetFontSetting(int i,LOGFONTA *lf,COLORREF *colour);
+
+//clistsettings.c
+TCHAR* GetContactDisplayNameW( HANDLE hContact, int mode );
+char* u2a( wchar_t* src );
+wchar_t* a2u( char* src );
+
+//clcfiledrop.c
+void InitFileDropping(void);
+void FreeFileDropping(void);
+void RegisterFileDropping(HWND hwnd);
+void UnregisterFileDropping(HWND hwnd);
diff --git a/miranda-wine/src/modules/clist/clcfiledrop.c b/miranda-wine/src/modules/clist/clcfiledrop.c
new file mode 100644
index 0000000..bc8701d
--- /dev/null
+++ b/miranda-wine/src/modules/clist/clcfiledrop.c
@@ -0,0 +1,295 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "clc.h"
+#include <shlobj.h>
+
+static IDropTargetVtbl dropTargetVtbl;
+
+struct CDropTarget
+{
+ IDropTargetVtbl *lpVtbl;
+ unsigned refCount;
+ IDropTargetHelper *pDropTargetHelper;
+}
+static dropTarget;
+
+static HWND hwndCurrentDrag = NULL;
+static int originalSelection;
+
+static STDMETHODIMP_(ULONG) CDropTarget_QueryInterface(struct CDropTarget *lpThis, REFIID riid, LPVOID * ppvObj)
+{
+ if (IsEqualIID(riid, &IID_IDropTarget)) {
+ *ppvObj = lpThis;
+ lpThis->lpVtbl->AddRef((IDropTarget *) lpThis);
+ return S_OK;
+ }
+ *ppvObj = NULL;
+ return E_NOINTERFACE;
+}
+
+static STDMETHODIMP_(ULONG) CDropTarget_AddRef(struct CDropTarget *lpThis)
+{
+ return ++lpThis->refCount;
+}
+
+static STDMETHODIMP_(ULONG) CDropTarget_Release(struct CDropTarget *lpThis)
+{
+ if (lpThis->refCount == 1) {
+ if (lpThis->pDropTargetHelper)
+ lpThis->pDropTargetHelper->lpVtbl->Release(lpThis->pDropTargetHelper);
+ }
+ return --lpThis->refCount;
+}
+
+static HANDLE HContactFromPoint(HWND hwnd, struct ClcData *dat, int x, int y, int *hitLine)
+{
+ int hit;
+ struct ClcContact *contact;
+ DWORD hitFlags;
+ char *szProto;
+ DWORD protoCaps;
+
+ hit = cli.pfnHitTest(hwnd, dat, x, y, &contact, NULL, &hitFlags);
+ if (hit == -1 || !(hitFlags & (CLCHT_ONITEMLABEL | CLCHT_ONITEMICON)) || contact->type != CLCIT_CONTACT)
+ return NULL;
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) contact->hContact, 0);
+ if (szProto == NULL)
+ return NULL;
+ protoCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0);
+ if (!(protoCaps & PF1_FILESEND))
+ return NULL;
+ if (ID_STATUS_OFFLINE == DBGetContactSettingWord(contact->hContact, szProto, "Status", ID_STATUS_OFFLINE))
+ return NULL;
+ if (hitLine)
+ *hitLine = hit;
+ return contact->hContact;
+}
+
+static STDMETHODIMP_(HRESULT) CDropTarget_DragOver(struct CDropTarget *lpThis, DWORD fKeyState, POINTL pt, DWORD * pdwEffect)
+{
+ POINT shortPt;
+ struct ClcData *dat;
+ RECT clRect;
+ int hit;
+ HANDLE hContact;
+
+ if (lpThis->pDropTargetHelper && hwndCurrentDrag)
+ lpThis->pDropTargetHelper->lpVtbl->DragOver(lpThis->pDropTargetHelper, (POINT *) & pt, *pdwEffect);
+
+ *pdwEffect = 0;
+ if (hwndCurrentDrag == NULL) {
+ *pdwEffect = DROPEFFECT_NONE;
+ return S_OK;
+ }
+ CallService(MS_CLIST_PAUSEAUTOHIDE, 0, 0);
+ dat = (struct ClcData *) GetWindowLong(hwndCurrentDrag, 0);
+ shortPt.x = pt.x;
+ shortPt.y = pt.y;
+ ScreenToClient(hwndCurrentDrag, &shortPt);
+ GetClientRect(hwndCurrentDrag, &clRect);
+
+ if (shortPt.y < dat->dragAutoScrollHeight || shortPt.y >= clRect.bottom - dat->dragAutoScrollHeight) {
+ *pdwEffect |= DROPEFFECT_SCROLL;
+ cli.pfnScrollTo(hwndCurrentDrag, dat, dat->yScroll + (shortPt.y < dat->dragAutoScrollHeight ? -1 : 1) * dat->rowHeight * 2, 0);
+ }
+ hContact = HContactFromPoint(hwndCurrentDrag, dat, shortPt.x, shortPt.y, &hit);
+ if (hContact == NULL) {
+ hit = -1;
+ *pdwEffect |= DROPEFFECT_NONE;
+ }
+ else
+ *pdwEffect |= DROPEFFECT_COPY;
+
+ if (dat->selection != hit) {
+ dat->selection = hit;
+ cli.pfnInvalidateRect(hwndCurrentDrag, NULL, FALSE);
+ lpThis->pDropTargetHelper->lpVtbl->Show(lpThis->pDropTargetHelper, FALSE);
+ UpdateWindow(hwndCurrentDrag);
+ lpThis->pDropTargetHelper->lpVtbl->Show(lpThis->pDropTargetHelper, TRUE);
+ }
+
+ return S_OK;
+}
+
+static STDMETHODIMP_(HRESULT) CDropTarget_DragEnter(struct CDropTarget *lpThis, IDataObject * pData, DWORD fKeyState, POINTL pt, DWORD * pdwEffect)
+{
+ HWND hwnd;
+ TCHAR szWindowClass[64];
+ POINT shortPt;
+
+ shortPt.x = pt.x;
+ shortPt.y = pt.y;
+ hwnd = WindowFromPoint(shortPt);
+ GetClassName(hwnd, szWindowClass, SIZEOF(szWindowClass));
+ if (!lstrcmp(szWindowClass, CLISTCONTROL_CLASS)) {
+ struct ClcData *dat;
+ hwndCurrentDrag = hwnd;
+ dat = (struct ClcData *) GetWindowLong(hwndCurrentDrag, 0);
+ originalSelection = dat->selection;
+ dat->showSelAlways = 1;
+ }
+ if (lpThis->pDropTargetHelper && hwndCurrentDrag)
+ lpThis->pDropTargetHelper->lpVtbl->DragEnter(lpThis->pDropTargetHelper, hwndCurrentDrag, pData, (POINT *) & pt, *pdwEffect);
+ return CDropTarget_DragOver(lpThis, fKeyState, pt, pdwEffect);
+}
+
+static STDMETHODIMP_(HRESULT) CDropTarget_DragLeave(struct CDropTarget *lpThis)
+{
+ if (hwndCurrentDrag) {
+ struct ClcData *dat;
+ if (lpThis->pDropTargetHelper)
+ lpThis->pDropTargetHelper->lpVtbl->DragLeave(lpThis->pDropTargetHelper);
+ dat = (struct ClcData *) GetWindowLong(hwndCurrentDrag, 0);
+ dat->showSelAlways = 0;
+ dat->selection = originalSelection;
+ cli.pfnInvalidateRect(hwndCurrentDrag, NULL, FALSE);
+ }
+ hwndCurrentDrag = NULL;
+ return S_OK;
+}
+
+static void AddToFileList(char ***pppFiles, int *totalCount, const char *szFilename)
+{
+ *pppFiles = (char **) mir_realloc(*pppFiles, (++*totalCount + 1) * sizeof(char *));
+ (*pppFiles)[*totalCount] = NULL;
+ (*pppFiles)[*totalCount - 1] = mir_strdup(szFilename);
+ if (GetFileAttributesA(szFilename) & FILE_ATTRIBUTE_DIRECTORY) {
+ WIN32_FIND_DATAA fd;
+ HANDLE hFind;
+ char szPath[MAX_PATH];
+ lstrcpyA(szPath, szFilename);
+ lstrcatA(szPath, "\\*");
+ if (hFind = FindFirstFileA(szPath, &fd)) {
+ do {
+ if (!lstrcmpA(fd.cFileName, ".") || !lstrcmpA(fd.cFileName, ".."))
+ continue;
+ lstrcpyA(szPath, szFilename);
+ lstrcatA(szPath, "\\");
+ lstrcatA(szPath, fd.cFileName);
+ AddToFileList(pppFiles, totalCount, szPath);
+ } while (FindNextFileA(hFind, &fd));
+ FindClose(hFind);
+ }
+ }
+}
+
+static STDMETHODIMP_(HRESULT) CDropTarget_Drop(struct CDropTarget *lpThis, IDataObject * pData, DWORD fKeyState, POINTL pt, DWORD * pdwEffect)
+{
+ FORMATETC fe = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
+ STGMEDIUM stg;
+ HDROP hDrop;
+ POINT shortPt;
+ struct ClcData *dat;
+ HANDLE hContact;
+
+ if (lpThis->pDropTargetHelper && hwndCurrentDrag)
+ lpThis->pDropTargetHelper->lpVtbl->Drop(lpThis->pDropTargetHelper, pData, (POINT *) & pt, *pdwEffect);
+
+ *pdwEffect = DROPEFFECT_NONE;
+ if (hwndCurrentDrag == NULL || S_OK != pData->lpVtbl->GetData(pData, &fe, &stg))
+ return S_OK;
+ hDrop = (HDROP) stg.hGlobal;
+ dat = (struct ClcData *) GetWindowLong(hwndCurrentDrag, 0);
+
+ shortPt.x = pt.x;
+ shortPt.y = pt.y;
+ ScreenToClient(hwndCurrentDrag, &shortPt);
+ hContact = HContactFromPoint(hwndCurrentDrag, dat, shortPt.x, shortPt.y, NULL);
+ if (hContact != NULL) {
+ char **ppFiles = NULL;
+ char szFilename[MAX_PATH];
+ int fileCount, totalCount = 0, i;
+
+ fileCount = DragQueryFile(hDrop, -1, NULL, 0);
+ ppFiles = NULL;
+ for (i = 0; i < fileCount; i++) {
+ DragQueryFileA(hDrop, i, szFilename, SIZEOF(szFilename));
+ AddToFileList(&ppFiles, &totalCount, szFilename);
+ }
+
+ if (!CallService(MS_CLIST_CONTACTFILESDROPPED, (WPARAM) hContact, (LPARAM) ppFiles))
+ *pdwEffect = DROPEFFECT_COPY;
+
+ for (i = 0; ppFiles[i]; i++)
+ mir_free(ppFiles[i]);
+ mir_free(ppFiles);
+ }
+
+ if (stg.pUnkForRelease)
+ stg.pUnkForRelease->lpVtbl->Release(stg.pUnkForRelease);
+ else
+ GlobalFree(stg.hGlobal);
+
+ CDropTarget_DragLeave(lpThis);
+ return S_OK;
+}
+
+static VOID CALLBACK CreateDropTargetHelperTimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
+{
+ /* macro defines needed CLSID and IID declarations since
+ they have to be referenced */
+#ifndef CLSID_DragDropHelper
+#define MDEF_CLSID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ const CLSID name \
+ = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
+
+ MDEF_CLSID(IID_IDropTargetHelper, 0x4657278b, 0x411b, 0x11d2, 0x83, 0x9a, 0x0, 0xc0, 0x4f, 0xd9, 0x18, 0xd0);
+ MDEF_CLSID(CLSID_DragDropHelper, 0x4657278a, 0x411b, 0x11d2, 0x83, 0x9a, 0x0, 0xc0, 0x4f, 0xd9, 0x18, 0xd0);
+#endif
+ KillTimer(hwnd, idEvent);
+ //This is a ludicrously slow function (~200ms) so we delay load it a bit.
+ if (S_OK != CoCreateInstance(&CLSID_DragDropHelper, NULL, CLSCTX_INPROC_SERVER, &IID_IDropTargetHelper, &dropTarget.pDropTargetHelper))
+ dropTarget.pDropTargetHelper = NULL;
+}
+
+void InitFileDropping(void)
+{
+ OleInitialize(NULL);
+ dropTarget.lpVtbl = &dropTargetVtbl;
+ dropTarget.lpVtbl->AddRef = (ULONG(__stdcall *) (IDropTarget *)) CDropTarget_AddRef;
+ dropTarget.lpVtbl->Release = (ULONG(__stdcall *) (IDropTarget *)) CDropTarget_Release;
+ dropTarget.lpVtbl->QueryInterface = (ULONG(__stdcall *) (IDropTarget *, REFIID, PVOID *)) CDropTarget_QueryInterface;
+ dropTarget.lpVtbl->DragEnter = (HRESULT(__stdcall *) (IDropTarget *, IDataObject *, DWORD, POINTL, PDWORD)) CDropTarget_DragEnter;
+ dropTarget.lpVtbl->DragOver = (HRESULT(__stdcall *) (IDropTarget *, DWORD, POINTL, PDWORD)) CDropTarget_DragOver;
+ dropTarget.lpVtbl->DragLeave = (HRESULT(__stdcall *) (IDropTarget *)) CDropTarget_DragLeave;
+ dropTarget.lpVtbl->Drop = (HRESULT(__stdcall *) (IDropTarget *, IDataObject *, DWORD, POINTL, PDWORD)) CDropTarget_Drop;
+ dropTarget.refCount = 0;
+ dropTarget.pDropTargetHelper = NULL;
+ SetTimer(NULL, 1, 1000, CreateDropTargetHelperTimerProc);
+}
+
+void FreeFileDropping(void)
+{
+ OleUninitialize();
+}
+
+void fnRegisterFileDropping(HWND hwnd)
+{
+ RegisterDragDrop(hwnd, (IDropTarget *) & dropTarget);
+}
+
+void fnUnregisterFileDropping(HWND hwnd)
+{
+ RevokeDragDrop(hwnd);
+}
diff --git a/miranda-wine/src/modules/clist/clcidents.c b/miranda-wine/src/modules/clist/clcidents.c
new file mode 100644
index 0000000..66baeed
--- /dev/null
+++ b/miranda-wine/src/modules/clist/clcidents.c
@@ -0,0 +1,201 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "clc.h"
+
+/* the CLC uses 3 different ways to identify elements in its list, this file
+contains routines to convert between them.
+
+1) struct ClcContact/struct ClcGroup pair. Only ever used within the duration
+ of a single operation, but used at some point in nearly everything
+2) index integer. The 0-based number of the item from the top. Only visible
+ items are counted (ie not closed groups). Used for saving selection and drag
+ highlight
+3) hItem handle. Either the hContact or (hGroup|HCONTACT_ISGROUP). Used
+ exclusively externally
+
+1->2: GetRowsPriorTo()
+1->3: ContactToHItem()
+3->1: FindItem()
+2->1: GetRowByIndex()
+*/
+
+int fnGetRowsPriorTo(struct ClcGroup *group, struct ClcGroup *subgroup, int contactIndex)
+{
+ int count = 0;
+
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ group->scanIndex++;
+ continue;
+ }
+ if (group == subgroup && contactIndex == group->scanIndex)
+ return count;
+ count++;
+ if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ if (group->cl.items[group->scanIndex]->group == subgroup && contactIndex == -1)
+ return count - 1;
+ if (group->cl.items[group->scanIndex]->group->expanded) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ continue;
+ }
+ }
+ group->scanIndex++;
+ }
+ return -1;
+}
+
+int fnFindItem(HWND hwnd, struct ClcData *dat, HANDLE hItem, struct ClcContact **contact, struct ClcGroup **subgroup, int *isVisible)
+{
+ int index = 0;
+ int nowVisible = 1;
+ struct ClcGroup *group = &dat->list;
+
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ struct ClcGroup *tgroup;
+ group = group->parent;
+ if (group == NULL)
+ break;
+ nowVisible = 1;
+ for (tgroup = group; tgroup; tgroup = tgroup->parent)
+ if (!group->expanded) {
+ nowVisible = 0;
+ break;
+ }
+ group->scanIndex++;
+ continue;
+ }
+ if (nowVisible)
+ index++;
+ if ((IsHContactGroup(hItem) && group->cl.items[group->scanIndex]->type == CLCIT_GROUP
+ && ((unsigned) hItem & ~HCONTACT_ISGROUP) == group->cl.items[group->scanIndex]->groupId) || (IsHContactContact(hItem)
+ && group->cl.items[group->scanIndex]->type == CLCIT_CONTACT
+ && group->cl.items[group->scanIndex]->hContact == hItem) || (IsHContactInfo(hItem)
+ && group->cl.items[group->scanIndex]->type == CLCIT_INFO
+ && group->cl.items[group->scanIndex]->hContact == (HANDLE) ((unsigned)hItem & ~HCONTACT_ISINFO)))
+ {
+ if (isVisible) {
+ if (!nowVisible)
+ *isVisible = 0;
+ else {
+ int posY = cli.pfnGetRowTopY(dat, index+1);
+ if (posY < dat->yScroll)
+ *isVisible = 0;
+ else {
+ RECT clRect;
+ GetClientRect(hwnd, &clRect);
+ if (posY >= dat->yScroll + clRect.bottom)
+ *isVisible = 0;
+ else
+ *isVisible = 1;
+ }
+ }
+ }
+ if (contact)
+ *contact = group->cl.items[group->scanIndex];
+ if (subgroup)
+ *subgroup = group;
+ return 1;
+ }
+ if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ nowVisible &= group->expanded;
+ continue;
+ }
+ group->scanIndex++;
+ }
+ return 0;
+}
+
+int fnGetRowByIndex(struct ClcData *dat, int testindex, struct ClcContact **contact, struct ClcGroup **subgroup)
+{
+ int index = 0;
+ struct ClcGroup *group = &dat->list;
+
+ if (testindex<0)
+ return (-1);
+
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ group->scanIndex++;
+ continue;
+ }
+ if (testindex == index) {
+ if (contact)
+ *contact = group->cl.items[group->scanIndex];
+ if (subgroup)
+ *subgroup = group;
+ return index;
+ }
+ index++;
+ if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP && group->cl.items[group->scanIndex]->group->expanded) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ continue;
+ }
+ group->scanIndex++;
+ }
+ return -1;
+}
+
+HANDLE fnContactToHItem(struct ClcContact * contact)
+{
+ switch (contact->type) {
+ case CLCIT_CONTACT:
+ return contact->hContact;
+ case CLCIT_GROUP:
+ return (HANDLE) (contact->groupId | HCONTACT_ISGROUP);
+ case CLCIT_INFO:
+ return (HANDLE) ((DWORD) contact->hContact | HCONTACT_ISINFO);
+ }
+ return NULL;
+}
+
+HANDLE fnContactToItemHandle(struct ClcContact * contact, DWORD * nmFlags)
+{
+ switch (contact->type) {
+ case CLCIT_CONTACT:
+ return contact->hContact;
+ case CLCIT_GROUP:
+ if (nmFlags)
+ *nmFlags |= CLNF_ISGROUP;
+ return (HANDLE) contact->groupId;
+ case CLCIT_INFO:
+ if (nmFlags)
+ *nmFlags |= CLNF_ISINFO;
+ return (HANDLE) ((DWORD) contact->hContact | HCONTACT_ISINFO);
+ }
+ return NULL;
+}
diff --git a/miranda-wine/src/modules/clist/clcitems.c b/miranda-wine/src/modules/clist/clcitems.c
new file mode 100644
index 0000000..b25df7f
--- /dev/null
+++ b/miranda-wine/src/modules/clist/clcitems.c
@@ -0,0 +1,721 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "clc.h"
+#include "../database/dblists.h"
+
+//routines for managing adding/removal of items in the list, including sorting
+
+int fnAddItemToGroup(struct ClcGroup *group, int iAboveItem)
+{
+ struct ClcContact* newItem = cli.pfnCreateClcContact();
+ newItem->type = CLCIT_DIVIDER;
+ newItem->flags = 0;
+ newItem->szText[0] = '\0';
+ memset( newItem->iExtraImage, 0xFF, SIZEOF(newItem->iExtraImage));
+
+ List_Insert(( SortedList* )&group->cl, newItem, iAboveItem );
+ return iAboveItem;
+}
+
+struct ClcGroup* fnAddGroup(HWND hwnd, struct ClcData *dat, const TCHAR *szName, DWORD flags, int groupId, int calcTotalMembers)
+{
+ TCHAR *pBackslash, *pNextField, szThisField[ SIZEOF(dat->list.cl.items[0]->szText) ];
+ struct ClcGroup *group = &dat->list;
+ int i, compareResult;
+
+ dat->needsResort = 1;
+ if (!(GetWindowLong(hwnd, GWL_STYLE) & CLS_USEGROUPS))
+ return &dat->list;
+
+ pNextField = ( TCHAR* )szName;
+ do {
+ pBackslash = _tcschr(pNextField, '\\');
+ if (pBackslash == NULL) {
+ lstrcpyn(szThisField, pNextField, SIZEOF(szThisField));
+ pNextField = NULL;
+ }
+ else {
+ lstrcpyn(szThisField, pNextField, min( SIZEOF(szThisField), pBackslash - pNextField + 1 ));
+ pNextField = pBackslash + 1;
+ }
+ compareResult = 1;
+ for (i = 0; i < group->cl.count; i++) {
+ if (group->cl.items[i]->type == CLCIT_CONTACT)
+ break;
+ if (group->cl.items[i]->type != CLCIT_GROUP)
+ continue;
+ compareResult = lstrcmp(szThisField, group->cl.items[i]->szText);
+ if (compareResult == 0) {
+ if (pNextField == NULL && flags != (DWORD) - 1) {
+ group->cl.items[i]->groupId = (WORD) groupId;
+ group = group->cl.items[i]->group;
+ group->expanded = (flags & GROUPF_EXPANDED) != 0;
+ group->hideOffline = (flags & GROUPF_HIDEOFFLINE) != 0;
+ group->groupId = groupId;
+ }
+ else
+ group = group->cl.items[i]->group;
+ break;
+ }
+ if (pNextField == NULL && group->cl.items[i]->groupId == 0)
+ break;
+ if (groupId && group->cl.items[i]->groupId > groupId)
+ break;
+ }
+ if (compareResult) {
+ if (groupId == 0)
+ return NULL;
+ i = cli.pfnAddItemToGroup(group, i);
+ group->cl.items[i]->type = CLCIT_GROUP;
+ lstrcpyn(group->cl.items[i]->szText, szThisField, SIZEOF( group->cl.items[i]->szText ));
+ group->cl.items[i]->groupId = (WORD) (pNextField ? 0 : groupId);
+ group->cl.items[i]->group = (struct ClcGroup *) mir_alloc(sizeof(struct ClcGroup));
+ group->cl.items[i]->group->parent = group;
+ group = group->cl.items[i]->group;
+ memset( &group->cl, 0, sizeof( group->cl ));
+ group->cl.increment = 10;
+ if (flags == (DWORD) - 1 || pNextField != NULL) {
+ group->expanded = 0;
+ group->hideOffline = 0;
+ }
+ else {
+ group->expanded = (flags & GROUPF_EXPANDED) != 0;
+ group->hideOffline = (flags & GROUPF_HIDEOFFLINE) != 0;
+ }
+ group->groupId = pNextField ? 0 : groupId;
+ group->totalMembers = 0;
+ if (flags != (DWORD) - 1 && pNextField == NULL && calcTotalMembers) {
+ DWORD style = GetWindowLong(hwnd, GWL_STYLE);
+ HANDLE hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact) {
+ ClcCacheEntryBase* cache = cli.pfnGetCacheEntry( hContact );
+ if ( !lstrcmp( cache->group, szName) && (style & CLS_SHOWHIDDEN || !cache->isHidden ))
+ group->totalMembers++;
+
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ }
+ }
+ }
+ } while (pNextField);
+ return group;
+}
+
+void fnFreeContact(struct ClcContact* p)
+{
+ if (p->type == CLCIT_GROUP) {
+ cli.pfnFreeGroup(p->group);
+ mir_free(p->group);
+} }
+
+void fnFreeGroup(struct ClcGroup *group)
+{
+ int i;
+ for (i = 0; i < group->cl.count; i++) {
+ cli.pfnFreeContact(group->cl.items[i]);
+ mir_free(group->cl.items[i]);
+ }
+ if (group->cl.items)
+ mir_free(group->cl.items);
+ group->cl.limit = group->cl.count = 0;
+ group->cl.items = NULL;
+}
+
+static int iInfoItemUniqueHandle = 0;
+int fnAddInfoItemToGroup(struct ClcGroup *group, int flags, const TCHAR *pszText)
+{
+ int i = 0;
+
+ if (flags & CLCIIF_BELOWCONTACTS)
+ i = group->cl.count;
+ else if (flags & CLCIIF_BELOWGROUPS) {
+ for (; i < group->cl.count; i++)
+ if (group->cl.items[i]->type == CLCIT_CONTACT)
+ break;
+ }
+ else
+ for (; i < group->cl.count; i++)
+ if (group->cl.items[i]->type != CLCIT_INFO)
+ break;
+ i = cli.pfnAddItemToGroup(group, i);
+ iInfoItemUniqueHandle = (iInfoItemUniqueHandle + 1) & 0xFFFF;
+ if (iInfoItemUniqueHandle == 0)
+ ++iInfoItemUniqueHandle;
+ group->cl.items[i]->type = CLCIT_INFO;
+ group->cl.items[i]->flags = (BYTE) flags;
+ group->cl.items[i]->hContact = (HANDLE)++ iInfoItemUniqueHandle;
+ lstrcpyn(group->cl.items[i]->szText, pszText, SIZEOF( group->cl.items[i]->szText ));
+ return i;
+}
+
+int fnAddContactToGroup(struct ClcData *dat, struct ClcGroup *group, HANDLE hContact)
+{
+ char *szProto;
+ WORD apparentMode;
+ DWORD idleMode;
+
+ int i, index = -1;
+
+ dat->needsResort = 1;
+ for (i = group->cl.count - 1; i >= 0; i--) {
+ if (group->cl.items[i]->hContact == hContact )
+ return i;
+
+ if ( index == -1 )
+ if (group->cl.items[i]->type != CLCIT_INFO || !(group->cl.items[i]->flags & CLCIIF_BELOWCONTACTS))
+ index = i;
+ }
+
+ i = cli.pfnAddItemToGroup(group, index + 1);
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ group->cl.items[i]->type = CLCIT_CONTACT;
+ group->cl.items[i]->iImage = CallService(MS_CLIST_GETCONTACTICON, (WPARAM) hContact, 0);
+ group->cl.items[i]->hContact = hContact;
+ group->cl.items[i]->proto = szProto;
+ if (szProto != NULL && !cli.pfnIsHiddenMode(dat, DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE)))
+ group->cl.items[i]->flags |= CONTACTF_ONLINE;
+ apparentMode = szProto != NULL ? DBGetContactSettingWord(hContact, szProto, "ApparentMode", 0) : 0;
+ if (apparentMode == ID_STATUS_OFFLINE)
+ group->cl.items[i]->flags |= CONTACTF_INVISTO;
+ else if (apparentMode == ID_STATUS_ONLINE)
+ group->cl.items[i]->flags |= CONTACTF_VISTO;
+ else if (apparentMode)
+ group->cl.items[i]->flags |= CONTACTF_VISTO | CONTACTF_INVISTO;
+ if (DBGetContactSettingByte(hContact, "CList", "NotOnList", 0))
+ group->cl.items[i]->flags |= CONTACTF_NOTONLIST;
+ idleMode = szProto != NULL ? DBGetContactSettingDword(hContact, szProto, "IdleTS", 0) : 0;
+ if (idleMode)
+ group->cl.items[i]->flags |= CONTACTF_IDLE;
+ lstrcpyn(group->cl.items[i]->szText, cli.pfnGetContactDisplayName(hContact,0), SIZEOF(group->cl.items[i]->szText));
+
+ { ClcCacheEntryBase* p = cli.pfnGetCacheEntry(hContact);
+ if ( p != NULL ) {
+ if ( p->group ) mir_free( p->group );
+ p->group = NULL;
+ } }
+
+ return i;
+}
+
+void fnAddContactToTree(HWND hwnd, struct ClcData *dat, HANDLE hContact, int updateTotalCount, int checkHideOffline)
+{
+ struct ClcGroup *group;
+ DBVARIANT dbv;
+ DWORD style = GetWindowLong(hwnd, GWL_STYLE);
+ WORD status;
+ char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+
+ dat->needsResort = 1;
+ if (style & CLS_NOHIDEOFFLINE)
+ checkHideOffline = 0;
+ if (checkHideOffline) {
+ if (szProto == NULL)
+ status = ID_STATUS_OFFLINE;
+ else
+ status = DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE);
+ }
+
+ if ( DBGetContactSettingTString(hContact, "CList", "Group", &dbv))
+ group = &dat->list;
+ else {
+ group = cli.pfnAddGroup(hwnd, dat, dbv.ptszVal, (DWORD) - 1, 0, 0);
+ if (group == NULL) {
+ int i, len;
+ DWORD groupFlags;
+ TCHAR *szGroupName;
+ if (!(style & CLS_HIDEEMPTYGROUPS)) {
+ mir_free(dbv.pszVal);
+ return;
+ }
+ if (checkHideOffline && cli.pfnIsHiddenMode(dat, status)) {
+ for (i = 1;; i++) {
+ szGroupName = cli.pfnGetGroupName(i, &groupFlags);
+ if (szGroupName == NULL) {
+ mir_free(dbv.pszVal);
+ return;
+ } //never happens
+ if (!lstrcmp(szGroupName, dbv.ptszVal))
+ break;
+ }
+ if (groupFlags & GROUPF_HIDEOFFLINE) {
+ mir_free(dbv.pszVal);
+ return;
+ }
+ }
+ for (i = 1;; i++) {
+ szGroupName = cli.pfnGetGroupName(i, &groupFlags);
+ if (szGroupName == NULL) {
+ mir_free(dbv.pszVal);
+ return;
+ } //never happens
+ if (!lstrcmp(szGroupName, dbv.ptszVal))
+ break;
+ len = lstrlen(szGroupName);
+ if (!_tcsncmp(szGroupName, dbv.ptszVal, len) && dbv.ptszVal[len] == '\\')
+ cli.pfnAddGroup(hwnd, dat, szGroupName, groupFlags, i, 1);
+ }
+ group = cli.pfnAddGroup(hwnd, dat, dbv.ptszVal, groupFlags, i, 1);
+ }
+ mir_free(dbv.pszVal);
+ }
+ if (checkHideOffline) {
+ if (cli.pfnIsHiddenMode(dat, status) && (style & CLS_HIDEOFFLINE || group->hideOffline)) {
+ if (updateTotalCount)
+ group->totalMembers++;
+ return;
+ }
+ }
+ cli.pfnAddContactToGroup(dat, group, hContact);
+ if (updateTotalCount)
+ group->totalMembers++;
+}
+
+struct ClcGroup* fnRemoveItemFromGroup(HWND hwnd, struct ClcGroup *group, struct ClcContact *contact, int updateTotalCount)
+{
+ int iContact;
+ if (( iContact = List_IndexOf(( SortedList* )&group->cl, contact )) == -1 )
+ return group;
+
+ if (updateTotalCount && contact->type == CLCIT_CONTACT)
+ group->totalMembers--;
+
+ { ClcCacheEntryBase* p = cli.pfnGetCacheEntry(contact->hContact);
+ if ( p != NULL ) {
+ if ( p->group ) mir_free( p->group );
+ p->group = NULL;
+ } }
+
+ cli.pfnFreeContact( group->cl.items[iContact] );
+ mir_free( group->cl.items[iContact] );
+ List_Remove(( SortedList* )&group->cl, iContact );
+
+ if ((GetWindowLong(hwnd, GWL_STYLE) & CLS_HIDEEMPTYGROUPS) && group->cl.count == 0) {
+ int i;
+ if (group->parent == NULL)
+ return group;
+ for (i = 0; i < group->parent->cl.count; i++)
+ if (group->parent->cl.items[i]->type == CLCIT_GROUP && group->parent->cl.items[i]->groupId == group->groupId)
+ break;
+ if (i == group->parent->cl.count)
+ return group; //never happens
+ return cli.pfnRemoveItemFromGroup(hwnd, group->parent, group->parent->cl.items[i], 0);
+ }
+ return group;
+}
+
+void fnDeleteItemFromTree(HWND hwnd, HANDLE hItem)
+{
+ struct ClcContact *contact;
+ struct ClcGroup *group;
+ struct ClcData *dat = (struct ClcData *) GetWindowLong(hwnd, 0);
+
+ dat->needsResort = 1;
+ if (!cli.pfnFindItem(hwnd, dat, hItem, &contact, &group, NULL)) {
+ DBVARIANT dbv;
+ int i, nameOffset;
+ if (!IsHContactContact(hItem))
+ return;
+ if (DBGetContactSettingTString(hItem, "CList", "Group", &dbv))
+ return;
+
+ //decrease member counts of all parent groups too
+ group = &dat->list;
+ nameOffset = 0;
+ for (i = 0;; i++) {
+ if (group->scanIndex == group->cl.count)
+ break;
+ if (group->cl.items[i]->type == CLCIT_GROUP) {
+ int len = lstrlen(group->cl.items[i]->szText);
+ if (!_tcsncmp(group->cl.items[i]->szText, dbv.ptszVal + nameOffset, len) &&
+ (dbv.ptszVal[nameOffset + len] == '\\' || dbv.ptszVal[nameOffset + len] == '\0')) {
+ group->totalMembers--;
+ if (dbv.ptszVal[nameOffset + len] == '\0')
+ break;
+ }
+ }
+ }
+ mir_free(dbv.ptszVal);
+ }
+ else
+ cli.pfnRemoveItemFromGroup(hwnd, group, contact, 1);
+}
+
+void fnRebuildEntireList(HWND hwnd, struct ClcData *dat)
+{
+ char *szProto;
+ DWORD style = GetWindowLong(hwnd, GWL_STYLE);
+ HANDLE hContact;
+ struct ClcGroup *group;
+ DBVARIANT dbv;
+
+ dat->list.expanded = 1;
+ dat->list.hideOffline = DBGetContactSettingByte(NULL, "CLC", "HideOfflineRoot", 0);
+ dat->list.cl.count = dat->list.cl.limit = 0;
+ dat->selection = -1;
+ {
+ int i;
+ TCHAR *szGroupName;
+ DWORD groupFlags;
+
+ for (i = 1;; i++) {
+ szGroupName = cli.pfnGetGroupName(i, &groupFlags);
+ if (szGroupName == NULL)
+ break;
+ cli.pfnAddGroup(hwnd, dat, szGroupName, groupFlags, i, 0);
+ }
+ }
+
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact) {
+ if (style & CLS_SHOWHIDDEN || !DBGetContactSettingByte(hContact, "CList", "Hidden", 0)) {
+ if (DBGetContactSettingTString(hContact, "CList", "Group", &dbv))
+ group = &dat->list;
+ else {
+ group = cli.pfnAddGroup(hwnd, dat, dbv.ptszVal, (DWORD) - 1, 0, 0);
+ mir_free(dbv.ptszVal);
+ }
+
+ if (group != NULL) {
+ group->totalMembers++;
+ if (!(style & CLS_NOHIDEOFFLINE) && (style & CLS_HIDEOFFLINE || group->hideOffline)) {
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ if (szProto == NULL) {
+ if (!cli.pfnIsHiddenMode(dat, ID_STATUS_OFFLINE))
+ cli.pfnAddContactToGroup(dat, group, hContact);
+ }
+ else if (!cli.pfnIsHiddenMode(dat, DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE)))
+ cli.pfnAddContactToGroup(dat, group, hContact);
+ }
+ else cli.pfnAddContactToGroup(dat, group, hContact);
+ }
+ }
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ }
+
+ if (style & CLS_HIDEEMPTYGROUPS) {
+ group = &dat->list;
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ if (group->cl.items[group->scanIndex]->group->cl.count == 0) {
+ group = cli.pfnRemoveItemFromGroup(hwnd, group, group->cl.items[group->scanIndex], 0);
+ }
+ else {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ }
+ continue;
+ }
+ group->scanIndex++;
+ }
+ }
+
+ cli.pfnSortCLC(hwnd, dat, 0);
+}
+
+int fnGetGroupContentsCount(struct ClcGroup *group, int visibleOnly)
+{
+ int count = group->cl.count;
+ struct ClcGroup *topgroup = group;
+
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ if (group == topgroup)
+ break;
+ group = group->parent;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP && (!visibleOnly || group->cl.items[group->scanIndex]->group->expanded)) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ count += group->cl.count;
+ continue;
+ }
+ group->scanIndex++;
+ }
+ return count;
+}
+
+static int __cdecl GroupSortProc(const struct ClcContact **contact1, const struct ClcContact **contact2)
+{
+ return lstrcmpi(contact1[0]->szText, contact2[0]->szText);
+}
+
+static int __cdecl ContactSortProc(const struct ClcContact **contact1, const struct ClcContact **contact2)
+{
+ int result = cli.pfnCompareContacts( contact1[0], contact2[0] );
+ if (result)
+ return result;
+ //nothing to distinguish them, so make sure they stay in the same order
+ return (int) contact2[0]->hContact - (int) contact1[0]->hContact;
+}
+
+static void InsertionSort(struct ClcContact **pContactArray, int nArray, int (*CompareProc) (const void *, const void *))
+{
+ int i, j;
+ struct ClcContact* testElement;
+
+ for (i = 1; i < nArray; i++) {
+ if (CompareProc(&pContactArray[i - 1], &pContactArray[i]) > 0) {
+ testElement = pContactArray[i];
+ for (j = i - 2; j >= 0; j--)
+ if (CompareProc(&pContactArray[j], &testElement) <= 0)
+ break;
+ j++;
+ memmove(&pContactArray[j + 1], &pContactArray[j], sizeof(void*) * (i - j));
+ pContactArray[j] = testElement;
+} } }
+
+static void SortGroup(struct ClcData *dat, struct ClcGroup *group, int useInsertionSort)
+{
+ int i, sortCount;
+
+ for (i = group->cl.count - 1; i >= 0; i--) {
+ if (group->cl.items[i]->type == CLCIT_DIVIDER) {
+ mir_free( group->cl.items[i] );
+ List_Remove(( SortedList* )&group->cl, i );
+ } }
+
+ for (i = 0; i < group->cl.count; i++)
+ if (group->cl.items[i]->type != CLCIT_INFO)
+ break;
+ if (i > group->cl.count - 2)
+ return;
+ if (group->cl.items[i]->type == CLCIT_GROUP) {
+ if (dat->exStyle & CLS_EX_SORTGROUPSALPHA) {
+ for (sortCount = 0; i + sortCount < group->cl.count; sortCount++)
+ if (group->cl.items[i + sortCount]->type != CLCIT_GROUP)
+ break;
+ qsort(group->cl.items + i, sortCount, sizeof(void*), GroupSortProc);
+ i = i + sortCount;
+ }
+ for (; i < group->cl.count; i++)
+ if (group->cl.items[i]->type == CLCIT_CONTACT)
+ break;
+ if (group->cl.count - i < 2)
+ return;
+ }
+ for (sortCount = 0; i + sortCount < group->cl.count; sortCount++)
+ if (group->cl.items[i + sortCount]->type != CLCIT_CONTACT)
+ break;
+ if (useInsertionSort)
+ InsertionSort(group->cl.items + i, sortCount, ContactSortProc);
+ else
+ qsort(group->cl.items + i, sortCount, sizeof(void*), ContactSortProc);
+ if (dat->exStyle & CLS_EX_DIVIDERONOFF) {
+ int prevContactOnline = 0;
+ for (i = 0; i < group->cl.count; i++) {
+ if (group->cl.items[i]->type != CLCIT_CONTACT)
+ continue;
+ if (group->cl.items[i]->flags & CONTACTF_ONLINE)
+ prevContactOnline = 1;
+ else {
+ if (prevContactOnline) {
+ i = cli.pfnAddItemToGroup(group, i);
+ group->cl.items[i]->type = CLCIT_DIVIDER;
+ lstrcpy(group->cl.items[i]->szText, TranslateT("Offline"));
+ }
+ break;
+} } } }
+
+void fnSortCLC(HWND hwnd, struct ClcData *dat, int useInsertionSort)
+{
+ struct ClcContact *selcontact;
+ struct ClcGroup *group = &dat->list, *selgroup;
+ int dividers = dat->exStyle & CLS_EX_DIVIDERONOFF;
+ HANDLE hSelItem;
+
+ if ( dat->needsResort ) {
+ if (cli.pfnGetRowByIndex(dat, dat->selection, &selcontact, NULL) == -1)
+ hSelItem = NULL;
+ else
+ hSelItem = cli.pfnContactToHItem(selcontact);
+ group->scanIndex = 0;
+ SortGroup(dat, group, useInsertionSort);
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ SortGroup(dat, group, useInsertionSort);
+ continue;
+ }
+ group->scanIndex++;
+ }
+ if (hSelItem)
+ if (cli.pfnFindItem(hwnd, dat, hSelItem, &selcontact, &selgroup, NULL))
+ dat->selection = cli.pfnGetRowsPriorTo(&dat->list, selgroup, List_IndexOf((SortedList*)&selgroup->cl,selcontact));
+
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ }
+ dat->needsResort = 0;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+}
+
+struct SavedContactState_t
+{
+ HANDLE hContact;
+ BYTE iExtraImage[MAXEXTRACOLUMNS];
+ int checked;
+};
+
+struct SavedGroupState_t
+{
+ int groupId, expanded;
+};
+
+struct SavedInfoState_t
+{
+ int parentId;
+ struct ClcContact contact;
+};
+
+void fnSaveStateAndRebuildList(HWND hwnd, struct ClcData *dat)
+{
+ NMCLISTCONTROL nm;
+ int i, j;
+ struct SavedGroupState_t *savedGroup = NULL;
+ int savedGroupCount = 0, savedGroupAlloced = 0;
+ struct SavedContactState_t *savedContact = NULL;
+ int savedContactCount = 0, savedContactAlloced = 0;
+ struct SavedInfoState_t *savedInfo = NULL;
+ int savedInfoCount = 0, savedInfoAlloced = 0;
+ struct ClcGroup *group;
+ struct ClcContact *contact;
+
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ cli.pfnEndRename(hwnd, dat, 1);
+
+ dat->needsResort = 1;
+ group = &dat->list;
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ if (++savedGroupCount > savedGroupAlloced) {
+ savedGroupAlloced += 8;
+ savedGroup = (struct SavedGroupState_t *) mir_realloc(savedGroup, sizeof(struct SavedGroupState_t) * savedGroupAlloced);
+ }
+ savedGroup[savedGroupCount - 1].groupId = group->groupId;
+ savedGroup[savedGroupCount - 1].expanded = group->expanded;
+ continue;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT) {
+ if (++savedContactCount > savedContactAlloced) {
+ savedContactAlloced += 16;
+ savedContact = (struct SavedContactState_t *) mir_realloc(savedContact, sizeof(struct SavedContactState_t) * savedContactAlloced);
+ }
+ savedContact[savedContactCount - 1].hContact = group->cl.items[group->scanIndex]->hContact;
+ CopyMemory(savedContact[savedContactCount - 1].iExtraImage, group->cl.items[group->scanIndex]->iExtraImage,
+ sizeof(group->cl.items[group->scanIndex]->iExtraImage));
+ savedContact[savedContactCount - 1].checked = group->cl.items[group->scanIndex]->flags & CONTACTF_CHECKED;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_INFO) {
+ if (++savedInfoCount > savedInfoAlloced) {
+ savedInfoAlloced += 4;
+ savedInfo = (struct SavedInfoState_t *) mir_realloc(savedInfo, sizeof(struct SavedInfoState_t) * savedInfoAlloced);
+ }
+ if (group->parent == NULL)
+ savedInfo[savedInfoCount - 1].parentId = -1;
+ else
+ savedInfo[savedInfoCount - 1].parentId = group->groupId;
+ savedInfo[savedInfoCount - 1].contact = *group->cl.items[group->scanIndex];
+ }
+ group->scanIndex++;
+ }
+
+ cli.pfnFreeGroup(&dat->list);
+ cli.pfnRebuildEntireList(hwnd, dat);
+
+ group = &dat->list;
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ for (i = 0; i < savedGroupCount; i++)
+ if (savedGroup[i].groupId == group->groupId) {
+ group->expanded = savedGroup[i].expanded;
+ break;
+ }
+ continue;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT) {
+ for (i = 0; i < savedContactCount; i++)
+ if (savedContact[i].hContact == group->cl.items[group->scanIndex]->hContact) {
+ CopyMemory(group->cl.items[group->scanIndex]->iExtraImage, savedContact[i].iExtraImage,
+ SIZEOF(group->cl.items[group->scanIndex]->iExtraImage));
+ if (savedContact[i].checked)
+ group->cl.items[group->scanIndex]->flags |= CONTACTF_CHECKED;
+ break;
+ }
+ }
+ group->scanIndex++;
+ }
+ if (savedGroup)
+ mir_free(savedGroup);
+ if (savedContact)
+ mir_free(savedContact);
+ for (i = 0; i < savedInfoCount; i++) {
+ if (savedInfo[i].parentId == -1)
+ group = &dat->list;
+ else {
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) (savedInfo[i].parentId | HCONTACT_ISGROUP), &contact, NULL, NULL))
+ continue;
+ group = contact->group;
+ }
+ j = cli.pfnAddInfoItemToGroup(group, savedInfo[i].contact.flags, _T(""));
+ *group->cl.items[j] = savedInfo[i].contact;
+ }
+ if (savedInfo)
+ mir_free(savedInfo);
+ cli.pfnRecalculateGroupCheckboxes(hwnd, dat);
+
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ nm.hdr.code = CLN_LISTREBUILT;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+}
diff --git a/miranda-wine/src/modules/clist/clcmsgs.c b/miranda-wine/src/modules/clist/clcmsgs.c
new file mode 100644
index 0000000..c481715
--- /dev/null
+++ b/miranda-wine/src/modules/clist/clcmsgs.c
@@ -0,0 +1,462 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "clc.h"
+#include "../database/dblists.h"
+
+//processing of all the CLM_ messages incoming
+
+LRESULT fnProcessExternalMessages(HWND hwnd, struct ClcData *dat, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case CLM_ADDCONTACT:
+ cli.pfnAddContactToTree(hwnd, dat, (HANDLE) wParam, 1, 0);
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ cli.pfnSortCLC(hwnd, dat, 1);
+ break;
+
+ case CLM_ADDGROUP:
+ {
+ DWORD groupFlags;
+ TCHAR *szName = cli.pfnGetGroupName(wParam, &groupFlags);
+ if (szName == NULL)
+ break;
+ cli.pfnAddGroup(hwnd, dat, szName, groupFlags, wParam, 0);
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ break;
+ }
+
+ case CLM_ADDINFOITEMA:
+ case CLM_ADDINFOITEMW:
+ {
+ int i;
+ struct ClcContact *groupContact;
+ struct ClcGroup *group;
+ CLCINFOITEM *cii = (CLCINFOITEM *) lParam;
+ if (cii==NULL || cii->cbSize != sizeof(CLCINFOITEM))
+ return (LRESULT) (HANDLE) NULL;
+ if (cii->hParentGroup == NULL)
+ group = &dat->list;
+ else {
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) ((DWORD) cii->hParentGroup | HCONTACT_ISGROUP), &groupContact, NULL, NULL))
+ return (LRESULT) (HANDLE) NULL;
+ group = groupContact->group;
+ }
+#if defined( _UNICODE )
+ if ( msg == CLM_ADDINFOITEMA )
+ { WCHAR* wszText = a2u(( char* )cii->pszText );
+ i = cli.pfnAddInfoItemToGroup(group, cii->flags, wszText);
+ mir_free( wszText );
+ }
+ else i = cli.pfnAddInfoItemToGroup(group, cii->flags, cii->pszText);
+#else
+ i = cli.pfnAddInfoItemToGroup(group, cii->flags, cii->pszText);
+#endif
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ return (LRESULT) group->cl.items[i]->hContact | HCONTACT_ISINFO;
+ }
+
+ case CLM_AUTOREBUILD:
+ KillTimer(hwnd,TIMERID_REBUILDAFTER);
+ cli.pfnSaveStateAndRebuildList(hwnd, dat);
+ break;
+
+ case CLM_DELETEITEM:
+ cli.pfnDeleteItemFromTree(hwnd, (HANDLE) wParam);
+ cli.pfnSortCLC(hwnd, dat, 1);
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ break;
+
+ case CLM_EDITLABEL:
+ SendMessage(hwnd, CLM_SELECTITEM, wParam, 0);
+ cli.pfnBeginRenameSelection(hwnd, dat);
+ break;
+
+ case CLM_ENDEDITLABELNOW:
+ cli.pfnEndRename(hwnd, dat, wParam);
+ break;
+
+ case CLM_ENSUREVISIBLE:
+ {
+ struct ClcContact *contact;
+ struct ClcGroup *group, *tgroup;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, &group, NULL))
+ break;
+ for (tgroup = group; tgroup; tgroup = tgroup->parent)
+ cli.pfnSetGroupExpand(hwnd, dat, tgroup, 1);
+ cli.pfnEnsureVisible(hwnd, dat, cli.pfnGetRowsPriorTo(&dat->list, group, List_IndexOf((SortedList*)&group->cl,contact)), 0);
+ break;
+ }
+
+ case CLM_EXPAND:
+ {
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+ if (contact->type != CLCIT_GROUP)
+ break;
+ cli.pfnSetGroupExpand(hwnd, dat, contact->group, lParam);
+ break;
+ }
+
+ case CLM_FINDCONTACT:
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, NULL, NULL, NULL))
+ return (LRESULT) (HANDLE) NULL;
+ return wParam;
+
+ case CLM_FINDGROUP:
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) (wParam | HCONTACT_ISGROUP), NULL, NULL, NULL))
+ return (LRESULT) (HANDLE) NULL;
+ return wParam | HCONTACT_ISGROUP;
+
+ case CLM_GETBKCOLOR:
+ return dat->bkColour;
+
+ case CLM_GETCHECKMARK:
+ {
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ return 0;
+ return (contact->flags & CONTACTF_CHECKED) != 0;
+ }
+
+ case CLM_GETCOUNT:
+ return cli.pfnGetGroupContentsCount(&dat->list, 0);
+
+ case CLM_GETEDITCONTROL:
+ return (LRESULT) dat->hwndRenameEdit;
+
+ case CLM_GETEXPAND:
+ {
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ return CLE_INVALID;
+ if (contact->type != CLCIT_GROUP)
+ return CLE_INVALID;
+ return contact->group->expanded;
+ }
+
+ case CLM_GETEXTRACOLUMNS:
+ return dat->extraColumnsCount;
+
+ case CLM_GETEXTRAIMAGE:
+ {
+ struct ClcContact *contact;
+ if (LOWORD(lParam) >= dat->extraColumnsCount)
+ return 0xFF;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ return 0xFF;
+ return contact->iExtraImage[LOWORD(lParam)];
+ }
+
+ case CLM_GETEXTRAIMAGELIST:
+ return (LRESULT) dat->himlExtraColumns;
+
+ case CLM_GETFONT:
+ if (wParam < 0 || wParam > FONTID_MAX)
+ return 0;
+ return (LRESULT) dat->fontInfo[wParam].hFont;
+
+ case CLM_GETHIDEOFFLINEROOT:
+ return DBGetContactSettingByte(NULL, "CLC", "HideOfflineRoot", 0);
+
+ case CLM_GETINDENT:
+ return dat->groupIndent;
+
+ case CLM_GETISEARCHSTRING:
+ lstrcpy(( TCHAR* ) lParam, dat->szQuickSearch);
+ return lstrlen(dat->szQuickSearch);
+
+ case CLM_GETITEMTEXT:
+ {
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ return 0;
+ lstrcpy(( TCHAR* ) lParam, contact->szText);
+ return lstrlen(contact->szText);
+ }
+
+ case CLM_GETITEMTYPE:
+ {
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ return CLCIT_INVALID;
+ return contact->type;
+ }
+
+ case CLM_GETLEFTMARGIN:
+ return dat->leftMargin;
+
+ case CLM_GETNEXTITEM:
+ {
+ struct ClcContact *contact;
+ struct ClcGroup *group;
+ int i;
+
+ if (wParam != CLGN_ROOT) {
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) lParam, &contact, &group, NULL))
+ return (LRESULT) (HANDLE) NULL;
+ i = List_IndexOf((SortedList*)&group->cl,contact);
+ }
+ switch (wParam) {
+ case CLGN_ROOT:
+ if (dat->list.cl.count)
+ return (LRESULT) cli.pfnContactToHItem(dat->list.cl.items[0]);
+ else
+ return (LRESULT) (HANDLE) NULL;
+ case CLGN_CHILD:
+ if (contact->type != CLCIT_GROUP)
+ return (LRESULT) (HANDLE) NULL;
+ group = contact->group;
+ if (group->cl.count == 0)
+ return (LRESULT) (HANDLE) NULL;
+ return (LRESULT) cli.pfnContactToHItem(group->cl.items[0]);
+ case CLGN_PARENT:
+ return group->groupId | HCONTACT_ISGROUP;
+ case CLGN_NEXT:
+ if (i >= group->cl.count)
+ return (LRESULT) (HANDLE) NULL;
+ return (LRESULT) cli.pfnContactToHItem(group->cl.items[i + 1]);
+ case CLGN_PREVIOUS:
+ if (i <= 0)
+ return (LRESULT) (HANDLE) NULL;
+ return (LRESULT) cli.pfnContactToHItem(group->cl.items[i - 1]);
+ case CLGN_NEXTCONTACT:
+ for (i++; i < group->cl.count; i++)
+ if (group->cl.items[i]->type == CLCIT_CONTACT)
+ break;
+ if (i >= group->cl.count)
+ return (LRESULT) (HANDLE) NULL;
+ return (LRESULT) cli.pfnContactToHItem(group->cl.items[i]);
+ case CLGN_PREVIOUSCONTACT:
+ if (i >= group->cl.count)
+ return (LRESULT) (HANDLE) NULL;
+ for (i--; i >= 0; i--)
+ if (group->cl.items[i]->type == CLCIT_CONTACT)
+ break;
+ if (i < 0)
+ return (LRESULT) (HANDLE) NULL;
+ return (LRESULT) cli.pfnContactToHItem(group->cl.items[i]);
+ case CLGN_NEXTGROUP:
+ for (i++; i < group->cl.count; i++)
+ if (group->cl.items[i]->type == CLCIT_GROUP)
+ break;
+ if (i >= group->cl.count)
+ return (LRESULT) (HANDLE) NULL;
+ return (LRESULT) cli.pfnContactToHItem(group->cl.items[i]);
+ case CLGN_PREVIOUSGROUP:
+ if (i >= group->cl.count)
+ return (LRESULT) (HANDLE) NULL;
+ for (i--; i >= 0; i--)
+ if (group->cl.items[i]->type == CLCIT_GROUP)
+ break;
+ if (i < 0)
+ return (LRESULT) (HANDLE) NULL;
+ return (LRESULT) cli.pfnContactToHItem(group->cl.items[i]);
+ }
+ return (LRESULT) (HANDLE) NULL;
+ }
+
+ case CLM_GETSCROLLTIME:
+ return dat->scrollTime;
+
+ case CLM_GETSELECTION:
+ {
+ struct ClcContact *contact;
+ if (cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL) == -1)
+ return (LRESULT) (HANDLE) NULL;
+ return (LRESULT) cli.pfnContactToHItem(contact);
+ }
+
+ case CLM_GETTEXTCOLOR:
+ if (wParam < 0 || wParam > FONTID_MAX)
+ return 0;
+ return (LRESULT) dat->fontInfo[wParam].colour;
+
+ case CLM_HITTEST:
+ {
+ struct ClcContact *contact;
+ DWORD hitFlags;
+ int hit;
+ hit = cli.pfnHitTest(hwnd, dat, (short) LOWORD(lParam), (short) HIWORD(lParam), &contact, NULL, &hitFlags);
+ if (wParam)
+ *(PDWORD) wParam = hitFlags;
+ if (hit == -1)
+ return (LRESULT) (HANDLE) NULL;
+ return (LRESULT) cli.pfnContactToHItem(contact);
+ }
+
+ case CLM_SELECTITEM:
+ {
+ struct ClcContact *contact;
+ struct ClcGroup *group, *tgroup;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, &group, NULL))
+ break;
+ for (tgroup = group; tgroup; tgroup = tgroup->parent)
+ cli.pfnSetGroupExpand(hwnd, dat, tgroup, 1);
+ dat->selection = cli.pfnGetRowsPriorTo(&dat->list, group, List_IndexOf((SortedList*)&group->cl,contact));
+ cli.pfnEnsureVisible(hwnd, dat, dat->selection, 0);
+ break;
+ }
+
+ case CLM_SETBKBITMAP:
+ if (!dat->bkChanged && dat->hBmpBackground) {
+ DeleteObject(dat->hBmpBackground);
+ dat->hBmpBackground = NULL;
+ }
+ dat->hBmpBackground = (HBITMAP) lParam;
+ dat->backgroundBmpUse = wParam;
+ dat->bkChanged = 1;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case CLM_SETBKCOLOR:
+ if (!dat->bkChanged && dat->hBmpBackground) {
+ DeleteObject(dat->hBmpBackground);
+ dat->hBmpBackground = NULL;
+ }
+ dat->bkColour = wParam;
+ dat->bkChanged = 1;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case CLM_SETCHECKMARK:
+ {
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ return 0;
+ if (lParam)
+ contact->flags |= CONTACTF_CHECKED;
+ else
+ contact->flags &= ~CONTACTF_CHECKED;
+ cli.pfnRecalculateGroupCheckboxes(hwnd, dat);
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+ }
+
+ case CLM_SETEXTRACOLUMNS:
+ if (wParam > MAXEXTRACOLUMNS)
+ return 0;
+ dat->extraColumnsCount = wParam;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case CLM_SETEXTRAIMAGE:
+ {
+ struct ClcContact *contact;
+ if (LOWORD(lParam) >= dat->extraColumnsCount)
+ return 0;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ return 0;
+ contact->iExtraImage[LOWORD(lParam)] = (BYTE) HIWORD(lParam);
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+ }
+
+ case CLM_SETEXTRAIMAGELIST:
+ dat->himlExtraColumns = (HIMAGELIST) lParam;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case CLM_SETFONT:
+ if (HIWORD(lParam) < 0 || HIWORD(lParam) > FONTID_MAX)
+ return 0;
+ dat->fontInfo[HIWORD(lParam)].hFont = (HFONT) wParam;
+ dat->fontInfo[HIWORD(lParam)].changed = 1;
+ {
+ SIZE fontSize;
+ HDC hdc = GetDC(hwnd);
+ SelectObject(hdc, (HFONT) wParam);
+ GetTextExtentPoint32A(hdc, "x", 1, &fontSize);
+ dat->fontInfo[HIWORD(lParam)].fontHeight = fontSize.cy;
+ if (dat->rowHeight < fontSize.cy + 2)
+ dat->rowHeight = fontSize.cy + 2;
+ ReleaseDC(hwnd, hdc);
+ }
+ if (LOWORD(lParam))
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case CLM_SETGREYOUTFLAGS:
+ dat->greyoutFlags = wParam;
+ break;
+
+ case CLM_SETHIDEEMPTYGROUPS:
+ if (wParam)
+ SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | CLS_HIDEEMPTYGROUPS);
+ else
+ SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~CLS_HIDEEMPTYGROUPS);
+ SendMessage(hwnd, CLM_AUTOREBUILD, 0, 0);
+ break;
+
+ case CLM_SETHIDEOFFLINEROOT:
+ DBWriteContactSettingByte(NULL, "CLC", "HideOfflineRoot", (BYTE) wParam);
+ SendMessage(hwnd, CLM_AUTOREBUILD, 0, 0);
+ break;
+
+ case CLM_SETINDENT:
+ dat->groupIndent = wParam;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case CLM_SETITEMTEXT:
+ {
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+ lstrcpyn(contact->szText, ( TCHAR* )lParam, SIZEOF( contact->szText ));
+ cli.pfnSortCLC(hwnd, dat, 1);
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+ }
+
+ case CLM_SETLEFTMARGIN:
+ dat->leftMargin = wParam;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case CLM_SETOFFLINEMODES:
+ dat->offlineModes = wParam;
+ SendMessage(hwnd, CLM_AUTOREBUILD, 0, 0);
+ break;
+
+ case CLM_SETSCROLLTIME:
+ dat->scrollTime = wParam;
+ break;
+
+ case CLM_SETTEXTCOLOR:
+ if (wParam < 0 || wParam > FONTID_MAX)
+ break;
+ dat->fontInfo[wParam].colour = lParam;
+ break;
+
+ case CLM_SETUSEGROUPS:
+ if (wParam)
+ SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | CLS_USEGROUPS);
+ else
+ SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~CLS_USEGROUPS);
+ SendMessage(hwnd, CLM_AUTOREBUILD, 0, 0);
+ break;
+ }
+ return 0;
+}
diff --git a/miranda-wine/src/modules/clist/clcutils.c b/miranda-wine/src/modules/clist/clcutils.c
new file mode 100644
index 0000000..b296e8b
--- /dev/null
+++ b/miranda-wine/src/modules/clist/clcutils.c
@@ -0,0 +1,865 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "clc.h"
+
+//loads of stuff that didn't really fit anywhere else
+
+extern HANDLE hHideInfoTipEvent;
+
+char* fnGetGroupCountsText(struct ClcData *dat, struct ClcContact *contact)
+{
+ static char szName[32];
+ int onlineCount, totalCount;
+ struct ClcGroup *group, *topgroup;
+
+ if (contact->type != CLCIT_GROUP || !(dat->exStyle & CLS_EX_SHOWGROUPCOUNTS))
+ return "";
+
+ group = topgroup = contact->group;
+ onlineCount = 0;
+ totalCount = group->totalMembers;
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ if (group == topgroup)
+ break;
+ group = group->parent;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ totalCount += group->totalMembers;
+ continue;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT)
+ if (group->cl.items[group->scanIndex]->flags & CONTACTF_ONLINE)
+ onlineCount++;
+ group->scanIndex++;
+ }
+ if (onlineCount == 0 && dat->exStyle & CLS_EX_HIDECOUNTSWHENEMPTY)
+ return "";
+ mir_snprintf(szName, SIZEOF(szName), "(%u/%u)", onlineCount, totalCount);
+ return szName;
+}
+
+int fnHitTest(HWND hwnd, struct ClcData *dat, int testx, int testy, struct ClcContact **contact, struct ClcGroup **group, DWORD * flags)
+{
+ struct ClcContact *hitcontact;
+ struct ClcGroup *hitgroup;
+ int hit, indent, width, i;
+ int checkboxWidth;
+ SIZE textSize;
+ HDC hdc;
+ RECT clRect;
+ HFONT hFont;
+ DWORD style = GetWindowLong(hwnd, GWL_STYLE);
+
+ if (flags)
+ *flags = 0;
+ GetClientRect(hwnd, &clRect);
+ if (testx < 0 || testy < 0 || testy >= clRect.bottom || testx >= clRect.right) {
+ if (flags) {
+ if (testx < 0)
+ *flags |= CLCHT_TOLEFT;
+ else if (testx >= clRect.right)
+ *flags |= CLCHT_TORIGHT;
+ if (testy < 0)
+ *flags |= CLCHT_ABOVE;
+ else if (testy >= clRect.bottom)
+ *flags |= CLCHT_BELOW;
+ }
+ return -1;
+ }
+ if (testx < dat->leftMargin) {
+ if (flags)
+ *flags |= CLCHT_INLEFTMARGIN | CLCHT_NOWHERE;
+ return -1;
+ }
+ hit = cli.pfnRowHitTest(dat, dat->yScroll + testy);
+ if ( hit != -1 )
+ hit = cli.pfnGetRowByIndex(dat, hit, &hitcontact, &hitgroup);
+ if (hit == -1) {
+ if (flags)
+ *flags |= CLCHT_NOWHERE | CLCHT_BELOWITEMS;
+ return -1;
+ }
+ if (contact)
+ *contact = hitcontact;
+ if (group)
+ *group = hitgroup;
+ for (indent = 0; hitgroup->parent; indent++, hitgroup = hitgroup->parent);
+ if (testx < dat->leftMargin + indent * dat->groupIndent) {
+ if (flags)
+ *flags |= CLCHT_ONITEMINDENT;
+ return hit;
+ }
+ checkboxWidth = 0;
+ if (style & CLS_CHECKBOXES && hitcontact->type == CLCIT_CONTACT)
+ checkboxWidth = dat->checkboxSize + 2;
+ if (style & CLS_GROUPCHECKBOXES && hitcontact->type == CLCIT_GROUP)
+ checkboxWidth = dat->checkboxSize + 2;
+ if (hitcontact->type == CLCIT_INFO && hitcontact->flags & CLCIIF_CHECKBOX)
+ checkboxWidth = dat->checkboxSize + 2;
+ if (testx < dat->leftMargin + indent * dat->groupIndent + checkboxWidth) {
+ if (flags)
+ *flags |= CLCHT_ONITEMCHECK;
+ return hit;
+ }
+ if (testx < dat->leftMargin + indent * dat->groupIndent + checkboxWidth + dat->iconXSpace) {
+ if (flags)
+ *flags |= CLCHT_ONITEMICON;
+ return hit;
+ }
+
+ for (i = 0; i < dat->extraColumnsCount; i++) {
+ if (hitcontact->iExtraImage[i] == 0xFF)
+ continue;
+ if (testx >= clRect.right - dat->extraColumnSpacing * (dat->extraColumnsCount - i) &&
+ testx < clRect.right - dat->extraColumnSpacing * (dat->extraColumnsCount - i) + g_IconWidth ) {
+ if (flags)
+ *flags |= CLCHT_ONITEMEXTRA | (i << 24);
+ return hit;
+ }
+ }
+ hdc = GetDC(hwnd);
+ if (hitcontact->type == CLCIT_GROUP)
+ hFont = SelectObject(hdc, dat->fontInfo[FONTID_GROUPS].hFont);
+ else
+ hFont = SelectObject(hdc, dat->fontInfo[FONTID_CONTACTS].hFont);
+ GetTextExtentPoint32(hdc, hitcontact->szText, lstrlen(hitcontact->szText), &textSize);
+ width = textSize.cx;
+ if (hitcontact->type == CLCIT_GROUP) {
+ char *szCounts;
+ szCounts = cli.pfnGetGroupCountsText(dat, hitcontact);
+ if (szCounts[0]) {
+ GetTextExtentPoint32A(hdc, " ", 1, &textSize);
+ width += textSize.cx;
+ SelectObject(hdc, dat->fontInfo[FONTID_GROUPCOUNTS].hFont);
+ GetTextExtentPoint32A(hdc, szCounts, lstrlenA(szCounts), &textSize);
+ width += textSize.cx;
+ }
+ }
+ SelectObject(hdc, hFont);
+ ReleaseDC(hwnd, hdc);
+ if (testx < dat->leftMargin + indent * dat->groupIndent + checkboxWidth + dat->iconXSpace + width + 4) {
+ if (flags)
+ *flags |= CLCHT_ONITEMLABEL;
+ return hit;
+ }
+ if (flags)
+ *flags |= CLCHT_NOWHERE;
+ return -1;
+}
+
+void fnScrollTo(HWND hwnd, struct ClcData *dat, int desty, int noSmooth)
+{
+ DWORD startTick, nowTick;
+ int oldy = dat->yScroll;
+ RECT clRect, rcInvalidate;
+ int maxy, previousy;
+
+ if (dat->iHotTrack != -1 && dat->yScroll != desty) {
+ cli.pfnInvalidateItem(hwnd, dat, dat->iHotTrack);
+ dat->iHotTrack = -1;
+ ReleaseCapture();
+ }
+ GetClientRect(hwnd, &clRect);
+ rcInvalidate = clRect;
+ maxy = cli.pfnGetRowTotalHeight(dat) - clRect.bottom;
+ if (desty > maxy)
+ desty = maxy;
+ if (desty < 0)
+ desty = 0;
+ if (abs(desty - dat->yScroll) < 4)
+ noSmooth = 1;
+ if (!noSmooth && dat->exStyle & CLS_EX_NOSMOOTHSCROLLING)
+ noSmooth = 1;
+ previousy = dat->yScroll;
+ if (!noSmooth) {
+ startTick = GetTickCount();
+ for (;;) {
+ nowTick = GetTickCount();
+ if (nowTick >= startTick + dat->scrollTime)
+ break;
+ dat->yScroll = oldy + (desty - oldy) * (int) (nowTick - startTick) / dat->scrollTime;
+ if (dat->backgroundBmpUse & CLBF_SCROLL || dat->hBmpBackground == NULL)
+ ScrollWindowEx(hwnd, 0, previousy - dat->yScroll, NULL, NULL, NULL, NULL, SW_INVALIDATE);
+ else
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ previousy = dat->yScroll;
+ SetScrollPos(hwnd, SB_VERT, dat->yScroll, TRUE);
+ UpdateWindow(hwnd);
+ }
+ }
+ dat->yScroll = desty;
+ if (dat->backgroundBmpUse & CLBF_SCROLL || dat->hBmpBackground == NULL)
+ ScrollWindowEx(hwnd, 0, previousy - dat->yScroll, NULL, NULL, NULL, NULL, SW_INVALIDATE);
+ else
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ SetScrollPos(hwnd, SB_VERT, dat->yScroll, TRUE);
+}
+
+void fnEnsureVisible(HWND hwnd, struct ClcData *dat, int iItem, int partialOk)
+{
+ int itemy, itemh = cli.pfnGetRowHeight(dat, iItem), newY;
+ int moved = 0;
+ RECT clRect;
+
+ GetClientRect(hwnd, &clRect);
+ itemy = cli.pfnGetRowTopY(dat, iItem);
+ if (partialOk) {
+ if (itemy + itemh - 1 < dat->yScroll) {
+ newY = itemy;
+ moved = 1;
+ }
+ else if (itemy >= dat->yScroll + clRect.bottom) {
+ newY = itemy - clRect.bottom + itemh;
+ moved = 1;
+ }
+ }
+ else {
+ if (itemy < dat->yScroll) {
+ newY = itemy;
+ moved = 1;
+ }
+ else if (itemy >= dat->yScroll + clRect.bottom - itemh) {
+ newY = itemy - clRect.bottom + itemh;
+ moved = 1;
+ }
+ }
+ if (moved)
+ cli.pfnScrollTo(hwnd, dat, newY, 0);
+}
+
+void fnRecalcScrollBar(HWND hwnd, struct ClcData *dat)
+{
+ SCROLLINFO si = { 0 };
+ RECT clRect;
+ NMCLISTCONTROL nm;
+
+ GetClientRect(hwnd, &clRect);
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_ALL;
+ si.nMin = 0;
+ si.nMax = cli.pfnGetRowTotalHeight(dat)-1;
+ si.nPage = clRect.bottom;
+ si.nPos = dat->yScroll;
+
+ if (GetWindowLong(hwnd, GWL_STYLE) & CLS_CONTACTLIST) {
+ if (dat->noVScrollbar == 0)
+ SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
+ }
+ else SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
+
+ cli.pfnScrollTo(hwnd, dat, dat->yScroll, 1);
+ nm.hdr.code = CLN_LISTSIZECHANGE;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.pt.y = si.nMax;
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+}
+
+void fnSetGroupExpand(HWND hwnd, struct ClcData *dat, struct ClcGroup *group, int newState)
+{
+ int contentCount;
+ int groupy;
+ int newY, posY;
+ RECT clRect;
+ NMCLISTCONTROL nm;
+
+ if (newState == -1)
+ group->expanded ^= 1;
+ else {
+ if (group->expanded == (newState != 0))
+ return;
+ group->expanded = newState != 0;
+ }
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ contentCount = cli.pfnGetGroupContentsCount(group, 1);
+ groupy = cli.pfnGetRowsPriorTo(&dat->list, group, -1);
+ if (dat->selection > groupy && dat->selection < groupy + contentCount)
+ dat->selection = groupy;
+ GetClientRect(hwnd, &clRect);
+ newY = dat->yScroll;
+ posY = cli.pfnGetRowBottomY(dat, groupy + contentCount);
+ if (posY >= newY + clRect.bottom)
+ newY = posY - clRect.bottom;
+ posY = cli.pfnGetRowTopY(dat, groupy);
+ if (newY > posY)
+ newY = posY;
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ cli.pfnScrollTo(hwnd, dat, newY, 0);
+ nm.hdr.code = CLN_EXPANDED;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.hItem = (HANDLE) group->groupId;
+ nm.action = group->expanded;
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+}
+
+void fnDoSelectionDefaultAction(HWND hwnd, struct ClcData *dat)
+{
+ struct ClcContact *contact;
+
+ if (dat->selection == -1)
+ return;
+ dat->szQuickSearch[0] = 0;
+ if (cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL) == -1)
+ return;
+ if (contact->type == CLCIT_GROUP)
+ cli.pfnSetGroupExpand(hwnd, dat, contact->group, -1);
+ if (contact->type == CLCIT_CONTACT)
+ CallService(MS_CLIST_CONTACTDOUBLECLICKED, (WPARAM) contact->hContact, 0);
+}
+
+int fnFindRowByText(HWND hwnd, struct ClcData *dat, const TCHAR *text, int prefixOk)
+{
+ struct ClcGroup *group = &dat->list;
+ int testlen = lstrlen(text);
+
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ group->scanIndex++;
+ continue;
+ }
+ if (group->cl.items[group->scanIndex]->type != CLCIT_DIVIDER) {
+ if ((prefixOk && !_tcsnicmp(text, group->cl.items[group->scanIndex]->szText, testlen)) ||
+ (!prefixOk && !lstrcmpi(text, group->cl.items[group->scanIndex]->szText))) {
+ struct ClcGroup *contactGroup = group;
+ int contactScanIndex = group->scanIndex;
+ for (; group; group = group->parent)
+ cli.pfnSetGroupExpand(hwnd, dat, group, 1);
+ return cli.pfnGetRowsPriorTo(&dat->list, contactGroup, contactScanIndex);
+ }
+ if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ if (!(dat->exStyle & CLS_EX_QUICKSEARCHVISONLY) || group->cl.items[group->scanIndex]->group->expanded) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ continue;
+ }
+ }
+ }
+ group->scanIndex++;
+ }
+ return -1;
+}
+
+void fnEndRename(HWND hwnd, struct ClcData *dat, int save)
+{
+ HWND hwndEdit = dat->hwndRenameEdit;
+
+ if (dat->hwndRenameEdit == NULL)
+ return;
+ dat->hwndRenameEdit = NULL;
+ if (save) {
+ TCHAR text[120];
+ struct ClcContact *contact;
+ GetWindowText(hwndEdit, text, SIZEOF(text));
+ if (cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL) != -1) {
+ if (lstrcmp(contact->szText, text)) {
+ if (contact->type == CLCIT_GROUP && !_tcsstr(text, _T("\\"))) {
+ TCHAR szFullName[256];
+ if (contact->group->parent && contact->group->parent->parent)
+ mir_sntprintf( szFullName, SIZEOF(szFullName), _T("%s\\%s"),
+ cli.pfnGetGroupName(contact->group->parent->groupId, NULL), text);
+ else
+ lstrcpyn( szFullName, text, SIZEOF( szFullName ));
+ cli.pfnRenameGroup( contact->groupId, szFullName );
+ }
+ else if (contact->type == CLCIT_CONTACT) {
+ TCHAR* otherName = cli.pfnGetContactDisplayName(contact->hContact, GCDNF_NOMYHANDLE);
+ cli.pfnInvalidateDisplayNameCacheEntry(contact->hContact);
+ if (text[0] == '\0') {
+ DBDeleteContactSetting(contact->hContact, "CList", "MyHandle");
+ }
+ else {
+ if (!lstrcmp(otherName, text))
+ DBDeleteContactSetting(contact->hContact, "CList", "MyHandle");
+ else
+ DBWriteContactSettingTString(contact->hContact, "CList", "MyHandle", text);
+ }
+ if (otherName)
+ mir_free(otherName);
+ }
+ }
+ }
+ }
+ DestroyWindow(hwndEdit);
+}
+
+void fnDeleteFromContactList(HWND hwnd, struct ClcData *dat)
+{
+ struct ClcContact *contact;
+ if (dat->selection == -1)
+ return;
+ dat->szQuickSearch[0] = 0;
+ if (cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL) == -1)
+ return;
+ switch (contact->type) {
+ case CLCIT_GROUP:
+ CallService(MS_CLIST_GROUPDELETE, (WPARAM) (HANDLE) contact->groupId, 0);
+ break;
+ case CLCIT_CONTACT:
+ CallService("CList/DeleteContactCommand", (WPARAM) (HANDLE)
+ contact->hContact, (LPARAM) hwnd);
+ break;
+ }
+}
+
+static WNDPROC OldRenameEditWndProc;
+static LRESULT CALLBACK RenameEditSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_KEYDOWN:
+ switch (wParam) {
+ case VK_RETURN:
+ cli.pfnEndRename(GetParent(hwnd), (struct ClcData *) GetWindowLong(GetParent(hwnd), 0), 1);
+ return 0;
+ case VK_ESCAPE:
+ cli.pfnEndRename(GetParent(hwnd), (struct ClcData *) GetWindowLong(GetParent(hwnd), 0), 0);
+ return 0;
+ }
+ break;
+ case WM_GETDLGCODE:
+ if (lParam) {
+ MSG *msg = (MSG *) lParam;
+ if (msg->message == WM_KEYDOWN && msg->wParam == VK_TAB)
+ return 0;
+ if (msg->message == WM_CHAR && msg->wParam == '\t')
+ return 0;
+ }
+ return DLGC_WANTMESSAGE;
+ case WM_KILLFOCUS:
+ cli.pfnEndRename(GetParent(hwnd), (struct ClcData *) GetWindowLong(GetParent(hwnd), 0), 1);
+ return 0;
+ }
+ return CallWindowProc(OldRenameEditWndProc, hwnd, msg, wParam, lParam);
+}
+
+void fnBeginRenameSelection(HWND hwnd, struct ClcData *dat)
+{
+ struct ClcContact *contact;
+ struct ClcGroup *group;
+ RECT clRect;
+ POINT pt;
+ int h;
+
+ KillTimer(hwnd, TIMERID_RENAME);
+ ReleaseCapture();
+ dat->iHotTrack = -1;
+ dat->selection = cli.pfnGetRowByIndex(dat, dat->selection, &contact, &group);
+ if (dat->selection == -1)
+ return;
+ if (contact->type != CLCIT_CONTACT && contact->type != CLCIT_GROUP)
+ return;
+ GetClientRect(hwnd, &clRect);
+ cli.pfnCalcEipPosition( dat, contact, group, &pt );
+ h = cli.pfnGetRowHeight(dat, dat->selection);
+ dat->hwndRenameEdit = CreateWindow( _T("EDIT"), contact->szText, WS_CHILD | WS_BORDER | ES_AUTOHSCROLL, pt.x, pt.y, clRect.right - pt.x, h, hwnd, NULL, cli.hInst, NULL);
+ OldRenameEditWndProc = (WNDPROC) SetWindowLong(dat->hwndRenameEdit, GWL_WNDPROC, (LONG) RenameEditSubclassProc);
+ SendMessage(dat->hwndRenameEdit, WM_SETFONT, (WPARAM) (contact->type == CLCIT_GROUP ? dat->fontInfo[FONTID_GROUPS].hFont : dat->fontInfo[FONTID_CONTACTS].hFont), 0);
+ SendMessage(dat->hwndRenameEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN | EC_USEFONTINFO, 0);
+ SendMessage(dat->hwndRenameEdit, EM_SETSEL, 0, (LPARAM) (-1));
+ ShowWindow(dat->hwndRenameEdit, SW_SHOW);
+ SetFocus(dat->hwndRenameEdit);
+}
+
+void fnCalcEipPosition( struct ClcData *dat, struct ClcContact *contact, struct ClcGroup *group, POINT *result)
+{
+ int indent;
+ for (indent = 0; group->parent; indent++, group = group->parent);
+ result->x = indent * dat->groupIndent + dat->iconXSpace - 2;
+ result->y = cli.pfnGetRowTopY(dat, dat->selection) - dat->yScroll;
+}
+
+int fnGetDropTargetInformation(HWND hwnd, struct ClcData *dat, POINT pt)
+{
+ RECT clRect;
+ int hit;
+ struct ClcContact *contact, *movecontact;
+ struct ClcGroup *group, *movegroup;
+ DWORD hitFlags;
+
+ GetClientRect(hwnd, &clRect);
+ dat->selection = dat->iDragItem;
+ dat->iInsertionMark = -1;
+ if (!PtInRect(&clRect, pt))
+ return DROPTARGET_OUTSIDE;
+
+ hit = cli.pfnHitTest(hwnd, dat, pt.x, pt.y, &contact, &group, &hitFlags);
+ cli.pfnGetRowByIndex(dat, dat->iDragItem, &movecontact, &movegroup);
+ if (hit == dat->iDragItem)
+ return DROPTARGET_ONSELF;
+ if (hit == -1 || hitFlags & CLCHT_ONITEMEXTRA)
+ return DROPTARGET_ONNOTHING;
+
+ if (movecontact->type == CLCIT_GROUP) {
+ struct ClcContact *bottomcontact = NULL, *topcontact = NULL;
+ struct ClcGroup *topgroup = NULL;
+ int topItem = -1, bottomItem;
+ int ok = 0;
+ if (pt.y + dat->yScroll < cli.pfnGetRowTopY(dat, hit) + dat->insertionMarkHitHeight) {
+ //could be insertion mark (above)
+ topItem = hit - 1;
+ bottomItem = hit;
+ bottomcontact = contact;
+ topItem = cli.pfnGetRowByIndex(dat, topItem, &topcontact, &topgroup);
+ ok = 1;
+ }
+ if (pt.y + dat->yScroll >= cli.pfnGetRowBottomY(dat, hit+1) - dat->insertionMarkHitHeight) {
+ //could be insertion mark (below)
+ topItem = hit;
+ bottomItem = hit + 1;
+ topcontact = contact;
+ topgroup = group;
+ bottomItem = cli.pfnGetRowByIndex(dat, bottomItem, &bottomcontact, NULL);
+ ok = 1;
+ }
+ if (ok) {
+ ok = 0;
+ if (bottomItem == -1 || bottomcontact->type != CLCIT_GROUP) { //need to special-case moving to end
+ if (topItem != dat->iDragItem) {
+ for (; topgroup; topgroup = topgroup->parent) {
+ if (topgroup == movecontact->group)
+ break;
+ if (topgroup == movecontact->group->parent) {
+ ok = 1;
+ break;
+ }
+ }
+ if (ok)
+ bottomItem = topItem + 1;
+ }
+ }
+ else if (bottomItem != dat->iDragItem && bottomcontact->type == CLCIT_GROUP && bottomcontact->group->parent == movecontact->group->parent) {
+ if (bottomcontact != movecontact + 1)
+ ok = 1;
+ }
+ if (ok) {
+ dat->iInsertionMark = bottomItem;
+ dat->selection = -1;
+ return DROPTARGET_INSERTION;
+ }
+ }
+ }
+ if (contact->type == CLCIT_GROUP) {
+ if (dat->iInsertionMark == -1) {
+ if (movecontact->type == CLCIT_GROUP) { //check not moving onto its own subgroup
+ for (; group; group = group->parent)
+ if (group == movecontact->group)
+ return DROPTARGET_ONSELF;
+ }
+ dat->selection = hit;
+ return DROPTARGET_ONGROUP;
+ }
+ }
+ return DROPTARGET_ONCONTACT;
+}
+
+int fnClcStatusToPf2(int status)
+{
+ switch(status) {
+ case ID_STATUS_ONLINE: return PF2_ONLINE;
+ case ID_STATUS_AWAY: return PF2_SHORTAWAY;
+ case ID_STATUS_DND: return PF2_HEAVYDND;
+ case ID_STATUS_NA: return PF2_LONGAWAY;
+ case ID_STATUS_OCCUPIED: return PF2_LIGHTDND;
+ case ID_STATUS_FREECHAT: return PF2_FREECHAT;
+ case ID_STATUS_INVISIBLE: return PF2_INVISIBLE;
+ case ID_STATUS_ONTHEPHONE: return PF2_ONTHEPHONE;
+ case ID_STATUS_OUTTOLUNCH: return PF2_OUTTOLUNCH;
+ case ID_STATUS_OFFLINE: return MODEF_OFFLINE;
+ }
+ return 0;
+}
+
+int fnIsHiddenMode(struct ClcData *dat, int status)
+{
+ return dat->offlineModes & cli.pfnClcStatusToPf2(status);
+}
+
+void fnHideInfoTip(HWND hwnd, struct ClcData *dat)
+{
+ CLCINFOTIP it = { 0 };
+
+ if (dat->hInfoTipItem == NULL)
+ return;
+ it.isGroup = IsHContactGroup(dat->hInfoTipItem);
+ it.hItem = (HANDLE) ((unsigned) dat->hInfoTipItem & ~HCONTACT_ISGROUP);
+ it.cbSize = sizeof(it);
+ dat->hInfoTipItem = NULL;
+ NotifyEventHooks(hHideInfoTipEvent, 0, (LPARAM) & it);
+}
+
+void fnNotifyNewContact(HWND hwnd, HANDLE hContact)
+{
+ NMCLISTCONTROL nm;
+ nm.hdr.code = CLN_NEWCONTACT;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = hContact;
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+}
+
+DWORD fnGetDefaultExStyle(void)
+{
+ BOOL param;
+ DWORD ret = CLCDEFAULT_EXSTYLE;
+ if (SystemParametersInfo(SPI_GETLISTBOXSMOOTHSCROLLING, 0, &param, FALSE) && !param)
+ ret |= CLS_EX_NOSMOOTHSCROLLING;
+ if (SystemParametersInfo(SPI_GETHOTTRACKING, 0, &param, FALSE) && !param)
+ ret &= ~CLS_EX_TRACKSELECT;
+ return ret;
+}
+
+#define DBFONTF_BOLD 1
+#define DBFONTF_ITALIC 2
+#define DBFONTF_UNDERLINE 4
+
+void fnGetDefaultFontSetting(int i, LOGFONT* lf, COLORREF* colour)
+{
+ SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), lf, FALSE);
+ *colour = GetSysColor(COLOR_WINDOWTEXT);
+ lf->lfHeight = 8;
+ switch (i) {
+ case FONTID_GROUPS:
+ lf->lfWeight = FW_BOLD;
+ break;
+ case FONTID_GROUPCOUNTS:
+ *colour = GetSysColor(COLOR_3DSHADOW);
+ break;
+ case FONTID_OFFINVIS:
+ case FONTID_INVIS:
+ lf->lfItalic = !lf->lfItalic;
+ break;
+ case FONTID_DIVIDERS:
+ break;
+ case FONTID_NOTONLIST:
+ *colour = GetSysColor(COLOR_3DSHADOW);
+ break;
+} }
+
+void fnGetFontSetting(int i, LOGFONT* lf, COLORREF* colour)
+{
+ DBVARIANT dbv;
+ char idstr[10];
+ BYTE style;
+
+ cli.pfnGetDefaultFontSetting(i, lf, colour);
+ wsprintfA(idstr, "Font%dName", i);
+ if ( !DBGetContactSettingTString(NULL, "CLC", idstr, &dbv )) {
+ lstrcpy(lf->lfFaceName, dbv.ptszVal);
+ mir_free(dbv.pszVal);
+ }
+ wsprintfA(idstr, "Font%dCol", i);
+ *colour = DBGetContactSettingDword(NULL, "CLC", idstr, *colour);
+ wsprintfA(idstr, "Font%dSize", i);
+ lf->lfHeight = (char) DBGetContactSettingByte(NULL, "CLC", idstr, lf->lfHeight);
+ wsprintfA(idstr, "Font%dSty", i);
+ style = (BYTE) DBGetContactSettingByte(NULL, "CLC", idstr, (lf->lfWeight == FW_NORMAL ? 0 : DBFONTF_BOLD) | (lf->lfItalic ? DBFONTF_ITALIC : 0) | (lf->lfUnderline ? DBFONTF_UNDERLINE : 0));
+ lf->lfWidth = lf->lfEscapement = lf->lfOrientation = 0;
+ lf->lfWeight = style & DBFONTF_BOLD ? FW_BOLD : FW_NORMAL;
+ lf->lfItalic = (style & DBFONTF_ITALIC) != 0;
+ lf->lfUnderline = (style & DBFONTF_UNDERLINE) != 0;
+ lf->lfStrikeOut = 0;
+ wsprintfA(idstr, "Font%dSet", i);
+ lf->lfCharSet = DBGetContactSettingByte(NULL, "CLC", idstr, lf->lfCharSet);
+ lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
+ lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf->lfQuality = DEFAULT_QUALITY;
+ lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+}
+
+void fnLoadClcOptions(HWND hwnd, struct ClcData *dat)
+{
+ dat->rowHeight = DBGetContactSettingByte(NULL, "CLC", "RowHeight", CLCDEFAULT_ROWHEIGHT);
+ {
+ int i;
+ LOGFONT lf;
+ SIZE fontSize;
+ HDC hdc = GetDC(hwnd);
+ HFONT hFont = GetCurrentObject(hdc, OBJ_FONT);
+ HFONT holdfont;
+
+ for (i = 0; i <= FONTID_MAX; i++) {
+ if (!dat->fontInfo[i].changed)
+ DeleteObject(dat->fontInfo[i].hFont);
+ cli.pfnGetFontSetting(i, &lf, &dat->fontInfo[i].colour);
+ {
+ LONG height;
+ HDC hdc = GetDC(NULL);
+ height = lf.lfHeight;
+ lf.lfHeight = -MulDiv(lf.lfHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72);
+ ReleaseDC(NULL, hdc);
+ dat->fontInfo[i].hFont = CreateFontIndirect(&lf);
+ lf.lfHeight = height;
+ }
+ dat->fontInfo[i].changed = 0;
+ holdfont = SelectObject(hdc,dat->fontInfo[i].hFont);
+ GetTextExtentPoint32(hdc, _T("x"), 1, &fontSize);
+ dat->fontInfo[i].fontHeight = fontSize.cy;
+ if (holdfont) SelectObject(hdc, holdfont);
+ }
+ SelectObject(hdc,hFont);
+ ReleaseDC(hwnd, hdc);
+ }
+ dat->leftMargin = DBGetContactSettingByte(NULL, "CLC", "LeftMargin", CLCDEFAULT_LEFTMARGIN);
+ dat->exStyle = DBGetContactSettingDword(NULL, "CLC", "ExStyle", cli.pfnGetDefaultExStyle());
+ dat->scrollTime = DBGetContactSettingWord(NULL, "CLC", "ScrollTime", CLCDEFAULT_SCROLLTIME);
+ dat->groupIndent = DBGetContactSettingByte(NULL, "CLC", "GroupIndent", CLCDEFAULT_GROUPINDENT);
+ dat->gammaCorrection = DBGetContactSettingByte(NULL, "CLC", "GammaCorrect", CLCDEFAULT_GAMMACORRECT);
+ dat->showIdle = DBGetContactSettingByte(NULL, "CLC", "ShowIdle", CLCDEFAULT_SHOWIDLE);
+ dat->noVScrollbar = DBGetContactSettingByte(NULL, "CLC", "NoVScrollBar", 0);
+ SendMessage(hwnd, INTM_SCROLLBARCHANGED, 0, 0);
+ if (!dat->bkChanged) {
+ DBVARIANT dbv;
+ dat->bkColour = DBGetContactSettingDword(NULL, "CLC", "BkColour", CLCDEFAULT_BKCOLOUR);
+ if (dat->hBmpBackground) {
+ DeleteObject(dat->hBmpBackground);
+ dat->hBmpBackground = NULL;
+ }
+ if (DBGetContactSettingByte(NULL, "CLC", "UseBitmap", CLCDEFAULT_USEBITMAP)) {
+ if (!DBGetContactSetting(NULL, "CLC", "BkBitmap", &dbv)) {
+ dat->hBmpBackground = (HBITMAP) CallService(MS_UTILS_LOADBITMAP, 0, (LPARAM) dbv.pszVal);
+ mir_free(dbv.pszVal);
+ }
+ }
+ dat->backgroundBmpUse = DBGetContactSettingWord(NULL, "CLC", "BkBmpUse", CLCDEFAULT_BKBMPUSE);
+ }
+ dat->greyoutFlags = DBGetContactSettingDword(NULL, "CLC", "GreyoutFlags", CLCDEFAULT_GREYOUTFLAGS);
+ dat->offlineModes = DBGetContactSettingDword(NULL, "CLC", "OfflineModes", CLCDEFAULT_OFFLINEMODES);
+ dat->selBkColour = DBGetContactSettingDword(NULL, "CLC", "SelBkColour", CLCDEFAULT_SELBKCOLOUR);
+ dat->selTextColour = DBGetContactSettingDword(NULL, "CLC", "SelTextColour", CLCDEFAULT_SELTEXTCOLOUR);
+ dat->hotTextColour = DBGetContactSettingDword(NULL, "CLC", "HotTextColour", CLCDEFAULT_HOTTEXTCOLOUR);
+ dat->quickSearchColour = DBGetContactSettingDword(NULL, "CLC", "QuickSearchColour", CLCDEFAULT_QUICKSEARCHCOLOUR);
+ dat->useWindowsColours = DBGetContactSettingByte(NULL, "CLC", "UseWinColours", CLCDEFAULT_USEWINDOWSCOLOURS);
+ {
+ NMHDR hdr;
+ hdr.code = CLN_OPTIONSCHANGED;
+ hdr.hwndFrom = hwnd;
+ hdr.idFrom = GetDlgCtrlID(hwnd);
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & hdr);
+ }
+ SendMessage(hwnd, WM_SIZE, 0, 0);
+}
+
+#define GSIF_HASMEMBERS 0x80000000
+#define GSIF_ALLCHECKED 0x40000000
+#define GSIF_INDEXMASK 0x3FFFFFFF
+void fnRecalculateGroupCheckboxes(HWND hwnd, struct ClcData *dat)
+{
+ struct ClcGroup *group;
+ int check;
+
+ group = &dat->list;
+ group->scanIndex = GSIF_ALLCHECKED;
+ for (;;) {
+ if ((group->scanIndex & GSIF_INDEXMASK) == group->cl.count) {
+ check = (group->scanIndex & (GSIF_HASMEMBERS | GSIF_ALLCHECKED)) == (GSIF_HASMEMBERS | GSIF_ALLCHECKED);
+ group = group->parent;
+ if (group == NULL)
+ break;
+ if (check)
+ group->cl.items[(group->scanIndex & GSIF_INDEXMASK)]->flags |= CONTACTF_CHECKED;
+ else {
+ group->cl.items[(group->scanIndex & GSIF_INDEXMASK)]->flags &= ~CONTACTF_CHECKED;
+ group->scanIndex &= ~GSIF_ALLCHECKED;
+ }
+ }
+ else if (group->cl.items[(group->scanIndex & GSIF_INDEXMASK)]->type == CLCIT_GROUP) {
+ group = group->cl.items[(group->scanIndex & GSIF_INDEXMASK)]->group;
+ group->scanIndex = GSIF_ALLCHECKED;
+ continue;
+ }
+ else if (group->cl.items[(group->scanIndex & GSIF_INDEXMASK)]->type == CLCIT_CONTACT) {
+ group->scanIndex |= GSIF_HASMEMBERS;
+ if (!(group->cl.items[(group->scanIndex & GSIF_INDEXMASK)]->flags & CONTACTF_CHECKED))
+ group->scanIndex &= ~GSIF_ALLCHECKED;
+ }
+ group->scanIndex++;
+ }
+}
+
+void fnSetGroupChildCheckboxes(struct ClcGroup *group, int checked)
+{
+ int i;
+
+ for (i = 0; i < group->cl.count; i++) {
+ if (group->cl.items[i]->type == CLCIT_GROUP) {
+ cli.pfnSetGroupChildCheckboxes(group->cl.items[i]->group, checked);
+ if (checked)
+ group->cl.items[i]->flags |= CONTACTF_CHECKED;
+ else
+ group->cl.items[i]->flags &= ~CONTACTF_CHECKED;
+ }
+ else if (group->cl.items[i]->type == CLCIT_CONTACT) {
+ if (checked)
+ group->cl.items[i]->flags |= CONTACTF_CHECKED;
+ else
+ group->cl.items[i]->flags &= ~CONTACTF_CHECKED;
+ }
+ }
+}
+
+void fnInvalidateItem(HWND hwnd, struct ClcData *dat, int iItem)
+{
+ RECT rc;
+ if ( iItem == -1 )
+ return;
+
+ GetClientRect(hwnd, &rc);
+ rc.top = cli.pfnGetRowTopY(dat, iItem) - dat->yScroll;
+ rc.bottom = rc.top + cli.pfnGetRowHeight(dat, iItem);
+ cli.pfnInvalidateRect(hwnd, &rc, FALSE);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// row coord functions
+
+int fnGetRowTopY(struct ClcData *dat, int item)
+{ return item * dat->rowHeight;
+}
+
+int fnGetRowBottomY(struct ClcData *dat, int item)
+{ return (item+1) * dat->rowHeight;
+}
+
+int fnGetRowTotalHeight(struct ClcData *dat)
+{ return dat->rowHeight * cli.pfnGetGroupContentsCount(&dat->list, 1);
+}
+
+int fnGetRowHeight(struct ClcData *dat, int item)
+{ return dat->rowHeight;
+}
+
+int fnRowHitTest(struct ClcData *dat, int y)
+{ if (!dat->rowHeight)
+ return y;
+ return y / dat->rowHeight;
+} \ No newline at end of file
diff --git a/miranda-wine/src/modules/clist/clistcore.c b/miranda-wine/src/modules/clist/clistcore.c
new file mode 100644
index 0000000..13bce39
--- /dev/null
+++ b/miranda-wine/src/modules/clist/clistcore.c
@@ -0,0 +1,315 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "clc.h"
+
+CLIST_INTERFACE cli = { 0 };
+
+int LoadContactListModule2( void );
+int LoadCLCModule( void );
+
+/* clc.c */
+void fnClcOptionsChanged( void );
+void fnClcBroadcast( int msg, WPARAM wParam, LPARAM lParam );
+HMENU fnBuildGroupPopupMenu( struct ClcGroup* group );
+
+LRESULT CALLBACK fnContactListControlWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+/* clcfiledrop.c */
+void fnRegisterFileDropping ( HWND hwnd );
+void fnUnregisterFileDropping ( HWND hwnd );
+
+/* clcidents.c */
+int fnGetRowsPriorTo( struct ClcGroup *group, struct ClcGroup *subgroup, int contactIndex );
+int fnFindItem( HWND hwnd, struct ClcData *dat, HANDLE hItem, struct ClcContact **contact, struct ClcGroup **subgroup, int *isVisible );
+int fnGetRowByIndex( struct ClcData *dat, int testindex, struct ClcContact **contact, struct ClcGroup **subgroup );
+HANDLE fnContactToHItem( struct ClcContact* contact );
+HANDLE fnContactToItemHandle( struct ClcContact * contact, DWORD * nmFlags );
+
+/* clcitems.c */
+struct ClcGroup* fnAddGroup( HWND hwnd, struct ClcData *dat, const TCHAR *szName, DWORD flags, int groupId, int calcTotalMembers );
+struct ClcGroup* fnRemoveItemFromGroup(HWND hwnd, struct ClcGroup *group, struct ClcContact *contact, int updateTotalCount);
+
+void fnFreeContact( struct ClcContact *p );
+void fnFreeGroup( struct ClcGroup *group );
+int fnAddInfoItemToGroup(struct ClcGroup *group, int flags, const TCHAR *pszText);
+int fnAddItemToGroup( struct ClcGroup *group,int iAboveItem );
+void fnAddContactToTree( HWND hwnd, struct ClcData *dat, HANDLE hContact, int updateTotalCount, int checkHideOffline);
+int fnAddContactToGroup( struct ClcData *dat, struct ClcGroup *group, HANDLE hContact);
+void fnDeleteItemFromTree( HWND hwnd, HANDLE hItem );
+void fnRebuildEntireList( HWND hwnd, struct ClcData *dat );
+int fnGetGroupContentsCount( struct ClcGroup *group, int visibleOnly );
+void fnSortCLC( HWND hwnd, struct ClcData *dat, int useInsertionSort );
+void fnSaveStateAndRebuildList(HWND hwnd, struct ClcData *dat);
+
+/* clcmsgs.c */
+LRESULT fnProcessExternalMessages(HWND hwnd, struct ClcData *dat, UINT msg, WPARAM wParam, LPARAM lParam );
+
+/* clcpaint.c */
+void fnPaintClc( HWND hwnd, struct ClcData *dat, HDC hdc, RECT * rcPaint ) {}
+
+/* clcutils.c */
+char* fnGetGroupCountsText(struct ClcData *dat, struct ClcContact *contact );
+int fnHitTest( HWND hwnd, struct ClcData *dat, int testx, int testy, struct ClcContact **contact, struct ClcGroup **group, DWORD * flags );
+void fnScrollTo( HWND hwnd, struct ClcData *dat, int desty, int noSmooth );
+void fnEnsureVisible(HWND hwnd, struct ClcData *dat, int iItem, int partialOk );
+void fnRecalcScrollBar( HWND hwnd, struct ClcData *dat );
+void fnSetGroupExpand( HWND hwnd, struct ClcData *dat, struct ClcGroup *group, int newState );
+void fnDoSelectionDefaultAction( HWND hwnd, struct ClcData *dat );
+int fnFindRowByText(HWND hwnd, struct ClcData *dat, const TCHAR *text, int prefixOk );
+void fnEndRename(HWND hwnd, struct ClcData *dat, int save );
+void fnDeleteFromContactList( HWND hwnd, struct ClcData *dat );
+void fnBeginRenameSelection( HWND hwnd, struct ClcData *dat );
+void fnCalcEipPosition( struct ClcData *dat, struct ClcContact *contact, struct ClcGroup *group, POINT *result);
+int fnGetDropTargetInformation( HWND hwnd, struct ClcData *dat, POINT pt );
+int fnClcStatusToPf2( int status );
+int fnIsHiddenMode( struct ClcData *dat, int status );
+void fnHideInfoTip( HWND hwnd, struct ClcData *dat );
+void fnNotifyNewContact( HWND hwnd, HANDLE hContact );
+DWORD fnGetDefaultExStyle( void );
+void fnGetSetting( int i, LOGFONT* lf, COLORREF* colour );
+void fnGetDefaultFontSetting(int i, LOGFONT* lf, COLORREF* colour);
+void fnGetFontSetting( int i, LOGFONT* lf, COLORREF* colour );
+void fnLoadClcOptions( HWND hwnd, struct ClcData *dat );
+void fnRecalculateGroupCheckboxes( HWND hwnd, struct ClcData *dat );
+void fnSetGroupChildCheckboxes( struct ClcGroup *group, int checked );
+void fnInvalidateItem( HWND hwnd, struct ClcData *dat, int iItem );
+
+/* clistevents.c */
+struct CListEvent* fnAddEvent( CLISTEVENT *cle );
+CLISTEVENT* fnGetEvent( HANDLE hContact, int idx );
+
+struct CListEvent* fnCreateEvent( void );
+void fnFreeEvent( struct CListEvent* p );
+
+int fnEventsProcessContactDoubleClick( HANDLE hContact );
+int fnEventsProcessTrayDoubleClick( void );
+int fnGetImlIconIndex(HICON hIcon);
+int fnRemoveEvent( HANDLE hContact, HANDLE dbEvent );
+
+/* clistmod.c */
+int fnIconFromStatusMode(const char *szProto, int status, HANDLE hContact);
+int fnShowHide( WPARAM wParam, LPARAM lParam );
+TCHAR* fnGetStatusModeDescription( int wParam, int lParam);
+int fnGetWindowVisibleState(HWND hWnd, int iStepX, int iStepY);
+
+/* clistsettings.c */
+TCHAR* fnGetContactDisplayName( HANDLE hContact, int mode );
+void fnGetDefaultFontSetting( int i, LOGFONT* lf, COLORREF * colour);
+void fnInvalidateDisplayNameCacheEntry( HANDLE hContact );
+
+ClcCacheEntryBase* fnGetCacheEntry( HANDLE hContact );
+ClcCacheEntryBase* fnCreateCacheItem ( HANDLE hContact );
+void fnCheckCacheItem( ClcCacheEntryBase* p );
+void fnFreeCacheItem( ClcCacheEntryBase* p );
+
+/* clisttray.c */
+int fnCListTrayNotify(MIRANDASYSTRAYNOTIFY *msn);
+void fnTrayIconUpdateWithImageList ( int iImage, const TCHAR *szNewTip, char *szPreferredProto );
+void fnTrayIconUpdateBase ( const char *szChangedProto );
+void fnTrayIconSetToBase ( char *szPreferredProto );
+void fnTrayIconIconsChanged ( void );
+int fnTrayIconPauseAutoHide ( WPARAM wParam, LPARAM lParam );
+int fnTrayIconProcessMessage ( WPARAM wParam, LPARAM lParam );
+
+/* clui.c */
+LRESULT CALLBACK fnContactListWndProc ( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
+void fnLoadCluiGlobalOpts( void );
+int fnCluiProtocolStatusChanged(int,const char*);
+void fnDrawMenuItem(DRAWITEMSTRUCT *dis, HICON hIcon, HICON eventIcon);
+
+/* contact.c */
+void fnChangeContactIcon ( HANDLE hContact, int iIcon, int add );
+void fnLoadContactTree ( void );
+int fnCompareContacts ( const struct ClcContact *contact1, const struct ClcContact *contact2);
+void fnSortContacts ( void );
+int fnSetHideOffline ( WPARAM wParam, LPARAM lParam );
+
+/* docking.c */
+int fnDocking_ProcessWindowMessage ( WPARAM wParam, LPARAM lParam );
+
+/* group.c */
+TCHAR* fnGetGroupName ( int idx, DWORD* pdwFlags );
+int fnRenameGroup ( int groupID, TCHAR* newName );
+
+/* keyboard.c */
+int fnHotKeysRegister ( HWND hwnd );
+void fnHotKeysUnregister ( HWND hwnd );
+int fnHotKeysProcess ( HWND hwnd, WPARAM wParam, LPARAM lParam );
+int fnHotkeysProcessMessage ( WPARAM wParam, LPARAM lParam );
+
+static int interfaceInited = 0;
+
+static struct ClcContact* fnCreateClcContact( void )
+{
+ return ( struct ClcContact* )mir_calloc( sizeof( struct ClcContact ));
+}
+
+static BOOL fnInvalidateRect( HWND hwnd, CONST RECT* lpRect,BOOL bErase )
+{
+ return InvalidateRect( hwnd, lpRect, bErase );
+}
+
+static void fnOnCreateClc( void )
+{
+}
+
+static int srvRetrieveInterface( WPARAM wParam, LPARAM lParam )
+{
+ int rc;
+
+ if ( interfaceInited == 0 ) {
+ cli.version = 3;
+
+ cli.pfnClcOptionsChanged = fnClcOptionsChanged;
+ cli.pfnClcBroadcast = fnClcBroadcast;
+ cli.pfnContactListControlWndProc = fnContactListControlWndProc;
+ cli.pfnBuildGroupPopupMenu = fnBuildGroupPopupMenu;
+
+ cli.pfnRegisterFileDropping = fnRegisterFileDropping;
+ cli.pfnUnregisterFileDropping = fnUnregisterFileDropping;
+
+ cli.pfnGetRowsPriorTo = fnGetRowsPriorTo;
+ cli.pfnFindItem = fnFindItem;
+ cli.pfnGetRowByIndex = fnGetRowByIndex;
+ cli.pfnContactToHItem = fnContactToHItem;
+ cli.pfnContactToItemHandle = fnContactToItemHandle;
+
+ cli.pfnAddGroup = fnAddGroup;
+ cli.pfnAddItemToGroup = fnAddItemToGroup;
+ cli.pfnCreateClcContact = fnCreateClcContact;
+ cli.pfnRemoveItemFromGroup = fnRemoveItemFromGroup;
+ cli.pfnFreeContact = fnFreeContact;
+ cli.pfnFreeGroup = fnFreeGroup;
+ cli.pfnAddInfoItemToGroup = fnAddInfoItemToGroup;
+ cli.pfnAddContactToGroup = fnAddContactToGroup;
+ cli.pfnAddContactToTree = fnAddContactToTree;
+ cli.pfnDeleteItemFromTree = fnDeleteItemFromTree;
+ cli.pfnRebuildEntireList = fnRebuildEntireList;
+ cli.pfnGetGroupContentsCount = fnGetGroupContentsCount;
+ cli.pfnSortCLC = fnSortCLC;
+ cli.pfnSaveStateAndRebuildList = fnSaveStateAndRebuildList;
+
+ cli.pfnProcessExternalMessages = fnProcessExternalMessages;
+
+ cli.pfnPaintClc = fnPaintClc;
+
+ cli.pfnGetGroupCountsText = fnGetGroupCountsText;
+ cli.pfnHitTest = fnHitTest;
+ cli.pfnScrollTo = fnScrollTo;
+ cli.pfnEnsureVisible = fnEnsureVisible;
+ cli.pfnRecalcScrollBar = fnRecalcScrollBar;
+ cli.pfnSetGroupExpand = fnSetGroupExpand;
+ cli.pfnDoSelectionDefaultAction = fnDoSelectionDefaultAction;
+ cli.pfnFindRowByText = fnFindRowByText;
+ cli.pfnEndRename = fnEndRename;
+ cli.pfnDeleteFromContactList = fnDeleteFromContactList;
+ cli.pfnBeginRenameSelection = fnBeginRenameSelection;
+ cli.pfnCalcEipPosition = fnCalcEipPosition;
+ cli.pfnGetDropTargetInformation = fnGetDropTargetInformation;
+ cli.pfnClcStatusToPf2 = fnClcStatusToPf2;
+ cli.pfnIsHiddenMode = fnIsHiddenMode;
+ cli.pfnHideInfoTip = fnHideInfoTip;
+ cli.pfnNotifyNewContact = fnNotifyNewContact;
+ cli.pfnGetDefaultExStyle = fnGetDefaultExStyle;
+ cli.pfnGetDefaultFontSetting = fnGetDefaultFontSetting;
+ cli.pfnGetFontSetting = fnGetFontSetting;
+ cli.pfnLoadClcOptions = fnLoadClcOptions;
+ cli.pfnRecalculateGroupCheckboxes = fnRecalculateGroupCheckboxes;
+ cli.pfnSetGroupChildCheckboxes = fnSetGroupChildCheckboxes;
+ cli.pfnInvalidateItem = fnInvalidateItem;
+ cli.pfnGetRowBottomY = fnGetRowBottomY;
+ cli.pfnGetRowHeight = fnGetRowHeight;
+ cli.pfnGetRowTopY = fnGetRowTopY;
+ cli.pfnGetRowTotalHeight = fnGetRowTotalHeight;
+ cli.pfnRowHitTest = fnRowHitTest;
+
+ cli.pfnAddEvent = fnAddEvent;
+ cli.pfnCreateEvent = fnCreateEvent;
+ cli.pfnEventsProcessContactDoubleClick = fnEventsProcessContactDoubleClick;
+ cli.pfnEventsProcessTrayDoubleClick = fnEventsProcessTrayDoubleClick;
+ cli.pfnFreeEvent = fnFreeEvent;
+ cli.pfnGetEvent = fnGetEvent;
+ cli.pfnGetImlIconIndex = fnGetImlIconIndex;
+ cli.pfnRemoveEvent = fnRemoveEvent;
+
+ cli.pfnGetContactDisplayName = fnGetContactDisplayName;
+ cli.pfnInvalidateDisplayNameCacheEntry = fnInvalidateDisplayNameCacheEntry;
+ cli.pfnCreateCacheItem = fnCreateCacheItem;
+ cli.pfnCheckCacheItem = fnCheckCacheItem;
+ cli.pfnFreeCacheItem = fnFreeCacheItem;
+ cli.pfnGetCacheEntry = fnGetCacheEntry;
+
+ cli.pfnTrayIconUpdateWithImageList = fnTrayIconUpdateWithImageList;
+ cli.pfnTrayIconUpdateBase = fnTrayIconUpdateBase;
+ cli.pfnTrayIconSetToBase = fnTrayIconSetToBase;
+ cli.pfnTrayIconIconsChanged = fnTrayIconIconsChanged;
+ cli.pfnTrayIconPauseAutoHide = fnTrayIconPauseAutoHide;
+ cli.pfnTrayIconProcessMessage = fnTrayIconProcessMessage;
+ cli.pfnCListTrayNotify = fnCListTrayNotify;
+
+ cli.pfnContactListWndProc = fnContactListWndProc;
+ cli.pfnLoadCluiGlobalOpts = fnLoadCluiGlobalOpts;
+ cli.pfnCluiProtocolStatusChanged = fnCluiProtocolStatusChanged;
+ cli.pfnDrawMenuItem = fnDrawMenuItem;
+ cli.pfnInvalidateRect = fnInvalidateRect;
+ cli.pfnOnCreateClc = fnOnCreateClc;
+
+ cli.pfnChangeContactIcon = fnChangeContactIcon;
+ cli.pfnLoadContactTree = fnLoadContactTree;
+ cli.pfnCompareContacts = fnCompareContacts;
+ cli.pfnSortContacts = fnSortContacts;
+ cli.pfnSetHideOffline = fnSetHideOffline;
+
+ cli.pfnDocking_ProcessWindowMessage = fnDocking_ProcessWindowMessage;
+
+ cli.pfnGetWindowVisibleState = fnGetWindowVisibleState;
+ cli.pfnIconFromStatusMode = fnIconFromStatusMode;
+ cli.pfnShowHide = fnShowHide;
+ cli.pfnGetStatusModeDescription = fnGetStatusModeDescription;
+
+ cli.pfnGetGroupName = fnGetGroupName;
+ cli.pfnRenameGroup = fnRenameGroup;
+
+ cli.pfnHotKeysRegister = fnHotKeysRegister;
+ cli.pfnHotKeysUnregister = fnHotKeysUnregister;
+ cli.pfnHotKeysProcess = fnHotKeysProcess;
+ cli.pfnHotkeysProcessMessage = fnHotkeysProcessMessage;
+
+ cli.hInst = ( HMODULE )lParam;
+
+ rc = LoadContactListModule2();
+ if (rc == 0)
+ rc = LoadCLCModule();
+ interfaceInited = 1;
+ }
+
+ return ( int )( LPARAM )&cli;
+}
+
+int LoadContactListModule()
+{
+ CreateServiceFunction( MS_CLIST_RETRIEVE_INTERFACE, srvRetrieveInterface );
+ return 0;
+} \ No newline at end of file
diff --git a/miranda-wine/src/modules/clist/clistevents.c b/miranda-wine/src/modules/clist/clistevents.c
new file mode 100644
index 0000000..f455d85
--- /dev/null
+++ b/miranda-wine/src/modules/clist/clistevents.c
@@ -0,0 +1,308 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "clc.h"
+#include "../database/dblists.h"
+
+struct CListEvent
+{
+ int imlIconIndex;
+ int flashesDone;
+ CLISTEVENT cle;
+};
+
+struct CListImlIcon
+{
+ int index;
+ HICON hIcon;
+};
+static struct CListImlIcon *imlIcon;
+static int imlIconCount;
+
+extern HIMAGELIST hCListImages;
+
+static UINT flashTimerId;
+static int iconsOn;
+static int disableTrayFlash;
+static int disableIconFlash;
+
+int fnGetImlIconIndex(HICON hIcon)
+{
+ int i;
+
+ for (i = 0; i < imlIconCount; i++) {
+ if (imlIcon[i].hIcon == hIcon)
+ return imlIcon[i].index;
+ }
+ imlIcon = (struct CListImlIcon *) mir_realloc(imlIcon, sizeof(struct CListImlIcon) * (imlIconCount + 1));
+ imlIconCount++;
+ imlIcon[i].hIcon = hIcon;
+ imlIcon[i].index = ImageList_AddIcon(hCListImages, hIcon);
+ return imlIcon[i].index;
+}
+
+static VOID CALLBACK IconFlashTimer(HWND hwnd, UINT message, UINT idEvent, DWORD dwTime)
+{
+ int i, j;
+
+ if (cli.events.count) {
+ char *szProto;
+ if (cli.events.items[0]->cle.hContact == NULL)
+ szProto = NULL;
+ else
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) cli.events.items[0]->cle.hContact, 0);
+ cli.pfnTrayIconUpdateWithImageList((iconsOn || disableTrayFlash) ? cli.events.items[0]->imlIconIndex : 0, cli.events.items[0]->cle.ptszTooltip, szProto);
+ }
+ for (i = 0; i < cli.events.count; i++) {
+ for (j = 0; j < i; j++)
+ if (cli.events.items[j]->cle.hContact == cli.events.items[i]->cle.hContact)
+ break;
+ if (j < i)
+ continue;
+ cli.pfnChangeContactIcon(cli.events.items[i]->cle.hContact, iconsOn || disableIconFlash ? cli.events.items[i]->imlIconIndex : 0, 0);
+ if (cli.events.items[i]->cle.flags & CLEF_ONLYAFEW) {
+ if (0 == --cli.events.items[i]->flashesDone)
+ cli.pfnRemoveEvent( cli.events.items[i]->cle.hContact, cli.events.items[i]->cle.hDbEvent);
+ } }
+
+ iconsOn = !iconsOn;
+}
+
+struct CListEvent* fnAddEvent( CLISTEVENT *cle )
+{
+ int i;
+ struct CListEvent* p;
+
+ if (cle==NULL || cle->cbSize != sizeof(CLISTEVENT))
+ return NULL;
+
+ if (cle->flags & CLEF_URGENT) {
+ for (i = 0; i < cli.events.count; i++)
+ if (!(cli.events.items[i]->cle.flags & CLEF_URGENT))
+ break;
+ }
+ else i = cli.events.count;
+
+ if (( p = ( struct CListEvent* )cli.pfnCreateEvent()) == NULL )
+ return NULL;
+
+ List_Insert(( SortedList* )&cli.events, p, i );
+ p->cle = *cle;
+ p->imlIconIndex = fnGetImlIconIndex(cli.events.items[i]->cle.hIcon);
+ p->flashesDone = 12;
+ p->cle.pszService = mir_strdup(cli.events.items[i]->cle.pszService);
+ #if defined( _UNICODE )
+ if (p->cle.flags & CLEF_UNICODE)
+ p->cle.ptszTooltip = mir_tstrdup((TCHAR*)p->cle.ptszTooltip);
+ else
+ p->cle.ptszTooltip = a2u((char*)p->cle.pszTooltip); //if no flag defined it handled as unicode
+ #else
+ p->cle.ptszTooltip = mir_tstrdup(p->cle.ptszTooltip);
+ #endif
+
+ if (cli.events.count == 1) {
+ char *szProto;
+ if (cle->hContact == NULL)
+ szProto = NULL;
+ else
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)cle->hContact, 0);
+ iconsOn = 1;
+ flashTimerId = SetTimer(NULL, 0, DBGetContactSettingWord(NULL, "CList", "IconFlashTime", 550), IconFlashTimer);
+ cli.pfnTrayIconUpdateWithImageList( p->imlIconIndex, p->cle.ptszTooltip, szProto);
+ }
+ cli.pfnChangeContactIcon(cle->hContact, p->imlIconIndex, 1);
+ cli.pfnSortContacts();
+ return p;
+}
+
+// Removes an event from the contact list's queue
+// Returns 0 if the event was successfully removed, or nonzero if the event was not found
+int fnRemoveEvent( HANDLE hContact, HANDLE dbEvent )
+{
+ int i;
+ char *szProto;
+
+ // Find the event that should be removed
+ for (i = 0; i < cli.events.count; i++)
+ if ((cli.events.items[i]->cle.hContact == hContact) && (cli.events.items[i]->cle.hDbEvent == dbEvent))
+ break;
+
+ // Event was not found
+ if (i == cli.events.count)
+ return 1;
+
+ // Update contact's icon
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ cli.pfnChangeContactIcon(cli.events.items[i]->cle.hContact,
+ cli.pfnIconFromStatusMode(szProto,
+ szProto == NULL ? ID_STATUS_OFFLINE : DBGetContactSettingWord(cli.events.items[i]->cle.hContact, szProto, "Status",
+ ID_STATUS_OFFLINE), cli.events.items[i]->cle.hContact), 0);
+
+ // Free any memory allocated to the event
+ cli.pfnFreeEvent( cli.events.items[i] );
+ List_Remove(( SortedList* )&cli.events, i );
+
+ if (cli.events.count == 0) {
+ KillTimer(NULL, flashTimerId);
+ cli.pfnTrayIconSetToBase( hContact == NULL ? NULL : szProto);
+ }
+ else {
+ if (cli.events.items[0]->cle.hContact == NULL)
+ szProto = NULL;
+ else
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) cli.events.items[0]->cle.hContact, 0);
+ cli.pfnTrayIconUpdateWithImageList(iconsOn ? cli.events.items[0]->imlIconIndex : 0, cli.events.items[0]->cle.ptszTooltip, szProto);
+ }
+
+ return 0;
+}
+
+CLISTEVENT* fnGetEvent( HANDLE hContact, int idx )
+{
+ int i;
+
+ if ( hContact == INVALID_HANDLE_VALUE) {
+ if (idx >= cli.events.count)
+ return NULL;
+ return &cli.events.items[idx]->cle;
+ }
+
+ for (i = 0; i < cli.events.count; i++)
+ if (cli.events.items[i]->cle.hContact == hContact)
+ if (idx-- == 0)
+ return &cli.events.items[i]->cle;
+ return NULL;
+}
+
+int fnEventsProcessContactDoubleClick(HANDLE hContact)
+{
+ int i;
+ HANDLE hDbEvent;
+
+ for (i = 0; i < cli.events.count; i++) {
+ if (cli.events.items[i]->cle.hContact == hContact) {
+ hDbEvent = cli.events.items[i]->cle.hDbEvent;
+ CallService(cli.events.items[i]->cle.pszService, (WPARAM) (HWND) NULL, (LPARAM) & cli.events.items[i]->cle);
+ cli.pfnRemoveEvent(hContact, hDbEvent);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int fnEventsProcessTrayDoubleClick(void)
+{
+ if (cli.events.count) {
+ HANDLE hContact, hDbEvent;
+ hContact = cli.events.items[0]->cle.hContact;
+ hDbEvent = cli.events.items[0]->cle.hDbEvent;
+ CallService(cli.events.items[0]->cle.pszService, (WPARAM) NULL, (LPARAM) & cli.events.items[0]->cle);
+ cli.pfnRemoveEvent(hContact, hDbEvent);
+ return 0;
+ }
+ return 1;
+}
+
+static int RemoveEventsForContact(WPARAM wParam, LPARAM lParam)
+{
+ int j, hit;
+
+ /*
+ the for(;;) loop is used here since the cli.events.count can not be relied upon to take us
+ thru the cli.events.items[] array without suffering from shortsightedness about how many unseen
+ events remain, e.g. three events, we remove the first, we're left with 2, the event
+ loop exits at 2 and we never see the real new 2.
+ */
+
+ for (; cli.events.count > 0;) {
+ for (hit = 0, j = 0; j < cli.events.count; j++) {
+ if (cli.events.items[j]->cle.hContact == (HANDLE) wParam) {
+ cli.pfnRemoveEvent((HANDLE)wParam, cli.events.items[j]->cle.hDbEvent);
+ hit = 1;
+ }
+ }
+ if (j == cli.events.count && hit == 0)
+ return 0; /* got to the end of the array and didnt remove anything */
+ }
+
+ return 0;
+}
+
+static int CListEventSettingsChanged(WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hContact = (HANDLE) wParam;
+ DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *) lParam;
+ if (hContact == NULL && cws && cws->szModule && cws->szSetting && strcmp(cws->szModule, "CList") == 0) {
+ if (strcmp(cws->szSetting, "DisableTrayFlash") == 0)
+ disableTrayFlash = (int) cws->value.bVal;
+ else if (strcmp(cws->szSetting, "NoIconBlink") == 0)
+ disableIconFlash = (int) cws->value.bVal;
+ }
+ return 0;
+}
+
+/***************************************************************************************/
+
+int AddEventStub(WPARAM wParam, LPARAM lParam) { return cli.pfnAddEvent((CLISTEVENT*)lParam ) == NULL; }
+int RemoveEventStub(WPARAM wParam, LPARAM lParam) { return cli.pfnRemoveEvent((HANDLE)wParam,(HANDLE)lParam ); }
+int GetEventStub(WPARAM wParam, LPARAM lParam) { return (int)cli.pfnGetEvent((HANDLE)wParam,lParam); }
+
+int InitCListEvents(void)
+{
+ memset( &cli.events, 0, sizeof(cli.events));
+ cli.events.increment = 10;
+
+ disableTrayFlash = DBGetContactSettingByte(NULL, "CList", "DisableTrayFlash", 0);
+ disableIconFlash = DBGetContactSettingByte(NULL, "CList", "NoIconBlink", 0);
+ CreateServiceFunction(MS_CLIST_ADDEVENT, AddEventStub);
+ CreateServiceFunction(MS_CLIST_REMOVEEVENT, RemoveEventStub);
+ CreateServiceFunction(MS_CLIST_GETEVENT, GetEventStub);
+ HookEvent(ME_DB_CONTACT_DELETED, RemoveEventsForContact);
+ HookEvent(ME_DB_CONTACT_SETTINGCHANGED, CListEventSettingsChanged);
+ return 0;
+}
+
+struct CListEvent* fnCreateEvent( void )
+{
+ return (struct CListEvent*)mir_calloc( sizeof(struct CListEvent));
+}
+
+void fnFreeEvent( struct CListEvent* p )
+{
+ if ( p->cle.pszService )
+ mir_free( p->cle.pszService );
+ if ( p->cle.pszTooltip )
+ mir_free( p->cle.pszTooltip );
+ mir_free( p );
+}
+
+void UninitCListEvents(void)
+{
+ int i;
+ for (i = 0; i < cli.events.count; i++)
+ cli.pfnFreeEvent(( struct CListEvent* )cli.events.items[i] );
+ mir_free( cli.events.items );
+
+ if ( imlIcon != NULL )
+ mir_free( imlIcon );
+}
diff --git a/miranda-wine/src/modules/clist/clistmod.c b/miranda-wine/src/modules/clist/clistmod.c
new file mode 100644
index 0000000..9e4d6b0
--- /dev/null
+++ b/miranda-wine/src/modules/clist/clistmod.c
@@ -0,0 +1,526 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "clc.h"
+
+int AddMainMenuItem(WPARAM wParam, LPARAM lParam);
+int AddContactMenuItem(WPARAM wParam, LPARAM lParam);
+int ContactChangeGroup(WPARAM wParam, LPARAM lParam);
+int InitCListEvents(void);
+void UninitCListEvents(void);
+int ContactSettingChanged(WPARAM wParam, LPARAM lParam);
+int ContactAdded(WPARAM wParam, LPARAM lParam);
+int ContactDeleted(WPARAM wParam, LPARAM lParam);
+int GetContactDisplayName(WPARAM wParam, LPARAM lParam);
+int InvalidateDisplayName(WPARAM wParam, LPARAM lParam);
+int InitGroupServices(void);
+int Docking_IsDocked(WPARAM wParam, LPARAM lParam);
+int MenuProcessCommand(WPARAM wParam, LPARAM lParam);
+void InitDisplayNameCache(void);
+void FreeDisplayNameCache(void);
+void InitTray(void);
+void LoadCLUIModule();
+
+HANDLE hContactDoubleClicked, hContactIconChangedEvent;
+HIMAGELIST hCListImages;
+BOOL(WINAPI * MySetProcessWorkingSetSize) (HANDLE, SIZE_T, SIZE_T);
+extern BYTE nameOrder[];
+static int statusModeList[] = { ID_STATUS_OFFLINE, ID_STATUS_ONLINE, ID_STATUS_AWAY, ID_STATUS_NA, ID_STATUS_OCCUPIED, ID_STATUS_DND, ID_STATUS_FREECHAT, ID_STATUS_INVISIBLE, ID_STATUS_ONTHEPHONE, ID_STATUS_OUTTOLUNCH };
+static int skinIconStatusList[] = { SKINICON_STATUS_OFFLINE, SKINICON_STATUS_ONLINE, SKINICON_STATUS_AWAY, SKINICON_STATUS_NA, SKINICON_STATUS_OCCUPIED, SKINICON_STATUS_DND, SKINICON_STATUS_FREE4CHAT, SKINICON_STATUS_INVISIBLE, SKINICON_STATUS_ONTHEPHONE, SKINICON_STATUS_OUTTOLUNCH };
+struct ProtoIconIndex
+{
+ char *szProto;
+ int iIconBase;
+}
+static *protoIconIndex;
+static int protoIconIndexCount;
+static HANDLE hProtoAckHook;
+static HANDLE hContactSettingChanged;
+
+TCHAR* fnGetStatusModeDescription( int mode, int flags )
+{
+ static TCHAR szMode[64];
+ TCHAR* descr;
+ int noPrefixReqd = 0;
+ switch (mode) {
+ case ID_STATUS_OFFLINE:
+ descr = TranslateT("Offline");
+ noPrefixReqd = 1;
+ break;
+ case ID_STATUS_CONNECTING:
+ descr = TranslateT("Connecting");
+ noPrefixReqd = 1;
+ break;
+ case ID_STATUS_ONLINE:
+ descr = TranslateT("Online");
+ noPrefixReqd = 1;
+ break;
+ case ID_STATUS_AWAY:
+ descr = TranslateT("Away");
+ break;
+ case ID_STATUS_DND:
+ descr = TranslateT("DND");
+ break;
+ case ID_STATUS_NA:
+ descr = TranslateT("NA");
+ break;
+ case ID_STATUS_OCCUPIED:
+ descr = TranslateT("Occupied");
+ break;
+ case ID_STATUS_FREECHAT:
+ descr = TranslateT("Free for chat");
+ break;
+ case ID_STATUS_INVISIBLE:
+ descr = TranslateT("Invisible");
+ break;
+ case ID_STATUS_OUTTOLUNCH:
+ descr = TranslateT("Out to lunch");
+ break;
+ case ID_STATUS_ONTHEPHONE:
+ descr = TranslateT("On the phone");
+ break;
+ case ID_STATUS_IDLE:
+ descr = TranslateT("Idle");
+ break;
+ default:
+ if (mode > ID_STATUS_CONNECTING && mode < ID_STATUS_CONNECTING + MAX_CONNECT_RETRIES) {
+ mir_sntprintf(szMode, SIZEOF(szMode), TranslateT("Connecting (attempt %d)"), mode - ID_STATUS_CONNECTING + 1);
+ return szMode;
+ }
+ return NULL;
+ }
+ if (noPrefixReqd || !(flags & GSMDF_PREFIXONLINE))
+ return descr;
+
+ lstrcpy(szMode, TranslateT("Online"));
+ lstrcat(szMode, _T(": "));
+ lstrcat(szMode, descr);
+ return szMode;
+}
+
+static int GetStatusModeDescription(WPARAM wParam, LPARAM lParam)
+{
+ #ifdef UNICODE
+ if ( !( lParam & GCMDF_TCHAR ))
+ {
+ static char szMode[64]={0};
+ TCHAR* buf1 = (TCHAR*)cli.pfnGetStatusModeDescription(wParam,lParam);
+ char *buf2=u2a(buf1);
+ _snprintf(szMode,sizeof(szMode),"%s",buf2);
+ mir_free(buf2);
+ return (int)szMode;
+ }
+ #endif
+
+ return (int)cli.pfnGetStatusModeDescription(wParam,lParam);
+}
+
+static int ProtocolAck(WPARAM wParam, LPARAM lParam)
+{
+ ACKDATA *ack = (ACKDATA *) lParam;
+
+ if (ack->type != ACKTYPE_STATUS)
+ return 0;
+ CallService(MS_CLUI_PROTOCOLSTATUSCHANGED, ack->lParam, (LPARAM) ack->szModule);
+
+ if ((int) ack->hProcess < ID_STATUS_ONLINE && ack->lParam >= ID_STATUS_ONLINE) {
+ DWORD caps;
+ caps = (DWORD) CallProtoService(ack->szModule, PS_GETCAPS, PFLAGNUM_1, 0);
+ if (caps & PF1_SERVERCLIST) {
+ HANDLE hContact;
+ char *szProto;
+
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact) {
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ if (szProto != NULL && !strcmp(szProto, ack->szModule))
+ if (DBGetContactSettingByte(hContact, "CList", "Delete", 0))
+ CallService(MS_DB_CONTACT_DELETE, (WPARAM) hContact, 0);
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ }
+ }
+ }
+
+ cli.pfnTrayIconUpdateBase(ack->szModule);
+ return 0;
+}
+
+int fnIconFromStatusMode(const char *szProto, int status)
+{
+ int index, i;
+
+ for (index = 0; index < SIZEOF(statusModeList); index++)
+ if (status == statusModeList[index])
+ break;
+ if (index == SIZEOF(statusModeList))
+ index = 0;
+ if (szProto == NULL)
+ return index + 1;
+ for (i = 0; i < protoIconIndexCount; i++) {
+ if (strcmp(szProto, protoIconIndex[i].szProto))
+ continue;
+ return protoIconIndex[i].iIconBase + index;
+ }
+ return 1;
+}
+
+static int GetContactIcon(WPARAM wParam, LPARAM lParam)
+{
+ char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ HANDLE hContact = (HANDLE)wParam;
+
+ return cli.pfnIconFromStatusMode(szProto,
+ szProto == NULL ? ID_STATUS_OFFLINE : DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE), hContact);
+}
+
+static int ContactListShutdownProc(WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hContact, hNext;
+
+ //remove transitory contacts
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact != NULL) {
+ hNext = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ if (DBGetContactSettingByte(hContact, "CList", "NotOnList", 0))
+ CallService(MS_DB_CONTACT_DELETE, (WPARAM) hContact, 0);
+ hContact = hNext;
+ }
+ ImageList_Destroy(hCListImages);
+ UnhookEvent(hProtoAckHook);
+ UninitCListEvents();
+ mir_free(protoIconIndex);
+ DestroyHookableEvent(hContactDoubleClicked);
+ UnhookEvent(hContactSettingChanged);
+ return 0;
+}
+
+static int ContactListModulesLoaded(WPARAM wParam, LPARAM lParam)
+{
+ int i, protoCount, j, iImg;
+ PROTOCOLDESCRIPTOR **protoList;
+
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM) & protoCount, (LPARAM) & protoList);
+ protoIconIndexCount = 0;
+ protoIconIndex = NULL;
+ for (i = 0; i < protoCount; i++) {
+ if (protoList[i]->type != PROTOTYPE_PROTOCOL)
+ continue;
+ protoIconIndex = (struct ProtoIconIndex *) mir_realloc(protoIconIndex, sizeof(struct ProtoIconIndex) * (protoIconIndexCount + 1));
+ protoIconIndex[protoIconIndexCount].szProto = protoList[i]->szName;
+ for (j = 0; j < SIZEOF(statusModeList); j++) {
+ iImg = ImageList_AddIcon(hCListImages, LoadSkinnedProtoIcon(protoList[i]->szName, statusModeList[j]));
+ if (j == 0)
+ protoIconIndex[protoIconIndexCount].iIconBase = iImg;
+ }
+ protoIconIndexCount++;
+ }
+ cli.pfnLoadContactTree();
+
+ if ( !ServiceExists( MS_DB_CONTACT_GETSETTING_STR )) {
+ MessageBox( NULL, TranslateT( "This plugin requires db3x plugin version 0.5.1.0 or later" ), _T("CList"), MB_OK );
+ return 1;
+ }
+
+ LoadCLUIModule();
+ return 0;
+}
+
+static int ContactDoubleClicked(WPARAM wParam, LPARAM lParam)
+{
+ // Check and an event from the CList queue for this hContact
+ if (cli.pfnEventsProcessContactDoubleClick((HANDLE) wParam))
+ NotifyEventHooks(hContactDoubleClicked, wParam, 0);
+
+ return 0;
+}
+
+static int GetIconsImageList(WPARAM wParam, LPARAM lParam)
+{
+ return (int) hCListImages;
+}
+
+static int ContactFilesDropped(WPARAM wParam, LPARAM lParam)
+{
+ CallService(MS_FILE_SENDSPECIFICFILES, wParam, lParam);
+ return 0;
+}
+
+static int CListIconsChanged(WPARAM wParam, LPARAM lParam)
+{
+ int i, j;
+
+ for (i = 0; i < SIZEOF(statusModeList); i++)
+ ImageList_ReplaceIcon(hCListImages, i + 1, LoadSkinnedIcon(skinIconStatusList[i]));
+ ImageList_ReplaceIcon(hCListImages, IMAGE_GROUPOPEN, LoadSkinnedIcon(SKINICON_OTHER_GROUPOPEN));
+ ImageList_ReplaceIcon(hCListImages, IMAGE_GROUPSHUT, LoadSkinnedIcon(SKINICON_OTHER_GROUPSHUT));
+ for (i = 0; i < protoIconIndexCount; i++)
+ for (j = 0; j < SIZEOF(statusModeList); j++)
+ ImageList_ReplaceIcon(hCListImages, protoIconIndex[i].iIconBase + j, LoadSkinnedProtoIcon(protoIconIndex[i].szProto, statusModeList[j]));
+ cli.pfnTrayIconIconsChanged();
+ cli.pfnInvalidateRect((HWND) CallService(MS_CLUI_GETHWND, 0, 0), NULL, TRUE);
+ return 0;
+}
+
+/*
+Begin of Hrk's code for bug
+*/
+#define GWVS_HIDDEN 1
+#define GWVS_VISIBLE 2
+#define GWVS_COVERED 3
+#define GWVS_PARTIALLY_COVERED 4
+
+int fnGetWindowVisibleState(HWND hWnd, int iStepX, int iStepY)
+{
+ RECT rc = { 0 };
+ POINT pt = { 0 };
+ register int i = 0, j = 0, width = 0, height = 0, iCountedDots = 0, iNotCoveredDots = 0;
+ BOOL bPartiallyCovered = FALSE;
+ HWND hAux = 0;
+
+ if (hWnd == NULL) {
+ SetLastError(0x00000006); //Wrong handle
+ return -1;
+ }
+ //Some defaults now. The routine is designed for thin and tall windows.
+ if (iStepX <= 0)
+ iStepX = 4;
+ if (iStepY <= 0)
+ iStepY = 16;
+
+ if (IsIconic(hWnd) || !IsWindowVisible(hWnd))
+ return GWVS_HIDDEN;
+ else {
+ GetWindowRect(hWnd, &rc);
+ width = rc.right - rc.left;
+ height = rc.bottom - rc.top;
+
+ for (i = rc.top; i < rc.bottom; i += (height / iStepY)) {
+ pt.y = i;
+ for (j = rc.left; j < rc.right; j += (width / iStepX)) {
+ pt.x = j;
+ hAux = WindowFromPoint(pt);
+ while (GetParent(hAux) != NULL)
+ hAux = GetParent(hAux);
+ if (hAux != hWnd) //There's another window!
+ bPartiallyCovered = TRUE;
+ else
+ iNotCoveredDots++; //Let's count the not covered dots.
+ iCountedDots++; //Let's keep track of how many dots we checked.
+ }
+ }
+ if (iNotCoveredDots == iCountedDots) //Every dot was not covered: the window is visible.
+ return GWVS_VISIBLE;
+ else if (iNotCoveredDots == 0) //They're all covered!
+ return GWVS_COVERED;
+ else //There are dots which are visible, but they are not as many as the ones we counted: it's partially covered.
+ return GWVS_PARTIALLY_COVERED;
+ }
+}
+
+int fnShowHide(WPARAM wParam, LPARAM lParam)
+{
+ BOOL bShow = FALSE;
+
+ int iVisibleState = cli.pfnGetWindowVisibleState(cli.hwndContactList, 0, 0);
+
+ //bShow is FALSE when we enter the switch.
+ switch (iVisibleState) {
+ case GWVS_PARTIALLY_COVERED:
+ //If we don't want to bring it to top, we can use a simple break. This goes against readability ;-) but the comment explains it.
+ if (!DBGetContactSettingByte(NULL, "CList", "BringToFront", SETTING_BRINGTOFRONT_DEFAULT))
+ break;
+ case GWVS_COVERED: //Fall through (and we're already falling)
+ case GWVS_HIDDEN:
+ bShow = TRUE;
+ break;
+ case GWVS_VISIBLE: //This is not needed, but goes for readability.
+ bShow = FALSE;
+ break;
+ case -1: //We can't get here, both cli.hwndContactList and iStepX and iStepY are right.
+ return 0;
+ }
+ if (bShow == TRUE) {
+ WINDOWPLACEMENT pl = { 0 };
+ HMONITOR(WINAPI * MyMonitorFromWindow) (HWND, DWORD);
+ RECT rcScreen, rcWindow;
+ int offScreen = 0;
+
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &rcScreen, FALSE);
+ ShowWindow(cli.hwndContactList, SW_RESTORE);
+ SetWindowPos(cli.hwndContactList, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ if (!DBGetContactSettingByte(NULL, "CList", "OnTop", SETTING_ONTOP_DEFAULT))
+ SetWindowPos(cli.hwndContactList, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
+ SetForegroundWindow(cli.hwndContactList);
+ DBWriteContactSettingByte(NULL, "CList", "State", SETTING_STATE_NORMAL);
+ //this forces the window onto the visible screen
+ MyMonitorFromWindow = (HMONITOR(WINAPI *) (HWND, DWORD)) GetProcAddress(GetModuleHandleA("USER32"), "MonitorFromWindow");
+ GetWindowRect(cli.hwndContactList, &rcWindow);
+ if (MyMonitorFromWindow) {
+ if (MyMonitorFromWindow(cli.hwndContactList, 0) == NULL) {
+ BOOL(WINAPI * MyGetMonitorInfoA) (HMONITOR, LPMONITORINFO);
+ MONITORINFO mi = { 0 };
+ HMONITOR hMonitor = MyMonitorFromWindow(cli.hwndContactList, 2);
+ MyGetMonitorInfoA = (BOOL(WINAPI *) (HMONITOR, LPMONITORINFO)) GetProcAddress(GetModuleHandleA("USER32"), "GetMonitorInfoA");
+ mi.cbSize = sizeof(mi);
+ MyGetMonitorInfoA(hMonitor, &mi);
+ rcScreen = mi.rcWork;
+ offScreen = 1;
+ }
+ }
+ else {
+ RECT rcDest;
+ if (IntersectRect(&rcDest, &rcScreen, &rcWindow) == 0)
+ offScreen = 1;
+ }
+ if (offScreen) {
+ if (rcWindow.top >= rcScreen.bottom)
+ OffsetRect(&rcWindow, 0, rcScreen.bottom - rcWindow.bottom);
+ else if (rcWindow.bottom <= rcScreen.top)
+ OffsetRect(&rcWindow, 0, rcScreen.top - rcWindow.top);
+ if (rcWindow.left >= rcScreen.right)
+ OffsetRect(&rcWindow, rcScreen.right - rcWindow.right, 0);
+ else if (rcWindow.right <= rcScreen.left)
+ OffsetRect(&rcWindow, rcScreen.left - rcWindow.left, 0);
+ SetWindowPos(cli.hwndContactList, 0, rcWindow.left, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top,
+ SWP_NOZORDER);
+ }
+ }
+ else { //It needs to be hidden
+ ShowWindow(cli.hwndContactList, SW_HIDE);
+ DBWriteContactSettingByte(NULL, "CList", "State", SETTING_STATE_HIDDEN);
+ if (MySetProcessWorkingSetSize != NULL && DBGetContactSettingByte(NULL, "CList", "DisableWorkingSet", 1))
+ MySetProcessWorkingSetSize(GetCurrentProcess(), -1, -1);
+ }
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// old evil code. hopefully it will be deleted soon, cause nobody uses it now
+
+#define SAFESTRING(a) a?a:""
+
+int GetStatusModeOrdering(int statusMode);
+extern int sortByStatus, sortByProto;
+
+static int CompareContacts( WPARAM wParam, LPARAM lParam )
+{
+ HANDLE a = (HANDLE) wParam, b = (HANDLE) lParam;
+ TCHAR namea[128], *nameb;
+ int statusa, statusb;
+ char *szProto1, *szProto2;
+ int rc;
+
+ szProto1 = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) a, 0);
+ szProto2 = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) b, 0);
+ statusa = DBGetContactSettingWord((HANDLE) a, SAFESTRING(szProto1), "Status", ID_STATUS_OFFLINE);
+ statusb = DBGetContactSettingWord((HANDLE) b, SAFESTRING(szProto2), "Status", ID_STATUS_OFFLINE);
+
+ if (sortByProto) {
+ /* deal with statuses, online contacts have to go above offline */
+ if ((statusa == ID_STATUS_OFFLINE) != (statusb == ID_STATUS_OFFLINE)) {
+ return 2 * (statusa == ID_STATUS_OFFLINE) - 1;
+ }
+ /* both are online, now check protocols */
+ rc = strcmp(SAFESTRING(szProto1), SAFESTRING(szProto2)); /* strcmp() doesn't like NULL so feed in "" as needed */
+ if (rc != 0 && (szProto1 != NULL && szProto2 != NULL))
+ return rc;
+ /* protocols are the same, order by display name */
+ }
+
+ if (sortByStatus) {
+ int ordera, orderb;
+ ordera = GetStatusModeOrdering(statusa);
+ orderb = GetStatusModeOrdering(statusb);
+ if (ordera != orderb)
+ return ordera - orderb;
+ }
+ else {
+ //one is offline: offline goes below online
+ if ((statusa == ID_STATUS_OFFLINE) != (statusb == ID_STATUS_OFFLINE)) {
+ return 2 * (statusa == ID_STATUS_OFFLINE) - 1;
+ }
+ }
+
+ nameb = cli.pfnGetContactDisplayName( a, 0);
+ _tcsncpy(namea, nameb, SIZEOF(namea));
+ namea[ SIZEOF(namea)-1 ] = 0;
+ nameb = cli.pfnGetContactDisplayName( b, 0);
+
+ //otherwise just compare names
+ return _tcsicmp(namea, nameb);
+}
+
+/***************************************************************************************/
+
+static int TrayIconProcessMessageStub( WPARAM wParam, LPARAM lParam ) { return cli.pfnTrayIconProcessMessage( wParam, lParam ); }
+static int TrayIconPauseAutoHideStub( WPARAM wParam, LPARAM lParam ) { return cli.pfnTrayIconPauseAutoHide( wParam, lParam ); }
+static int ShowHideStub( WPARAM wParam, LPARAM lParam ) { return cli.pfnShowHide( wParam, lParam ); }
+static int SetHideOfflineStub( WPARAM wParam, LPARAM lParam ) { return cli.pfnSetHideOffline( wParam, lParam ); }
+static int Docking_ProcessWindowMessageStub( WPARAM wParam, LPARAM lParam ) { return cli.pfnDocking_ProcessWindowMessage( wParam, lParam ); }
+static int HotkeysProcessMessageStub( WPARAM wParam, LPARAM lParam ) { return cli.pfnHotkeysProcessMessage( wParam, lParam ); }
+
+int LoadContactListModule2(void)
+{
+ HookEvent(ME_SYSTEM_SHUTDOWN, ContactListShutdownProc);
+ HookEvent(ME_SYSTEM_MODULESLOADED, ContactListModulesLoaded);
+ hContactSettingChanged = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, ContactSettingChanged);
+ HookEvent(ME_DB_CONTACT_ADDED, ContactAdded);
+ HookEvent(ME_DB_CONTACT_DELETED, ContactDeleted);
+ hProtoAckHook = (HANDLE) HookEvent(ME_PROTO_ACK, ProtocolAck);
+ hContactDoubleClicked = CreateHookableEvent(ME_CLIST_DOUBLECLICKED);
+ hContactIconChangedEvent = CreateHookableEvent(ME_CLIST_CONTACTICONCHANGED);
+ CreateServiceFunction(MS_CLIST_CONTACTDOUBLECLICKED, ContactDoubleClicked);
+ CreateServiceFunction(MS_CLIST_CONTACTFILESDROPPED, ContactFilesDropped);
+ CreateServiceFunction(MS_CLIST_GETSTATUSMODEDESCRIPTION, GetStatusModeDescription);
+ CreateServiceFunction(MS_CLIST_GETCONTACTDISPLAYNAME, GetContactDisplayName);
+ CreateServiceFunction(MS_CLIST_INVALIDATEDISPLAYNAME, InvalidateDisplayName);
+ CreateServiceFunction(MS_CLIST_TRAYICONPROCESSMESSAGE, TrayIconProcessMessageStub );
+ CreateServiceFunction(MS_CLIST_PAUSEAUTOHIDE, TrayIconPauseAutoHideStub);
+ CreateServiceFunction(MS_CLIST_CONTACTSCOMPARE, CompareContacts);
+ CreateServiceFunction(MS_CLIST_CONTACTCHANGEGROUP, ContactChangeGroup);
+ CreateServiceFunction(MS_CLIST_SHOWHIDE, ShowHideStub);
+ CreateServiceFunction(MS_CLIST_SETHIDEOFFLINE, SetHideOfflineStub);
+ CreateServiceFunction(MS_CLIST_DOCKINGPROCESSMESSAGE, Docking_ProcessWindowMessageStub);
+ CreateServiceFunction(MS_CLIST_DOCKINGISDOCKED, Docking_IsDocked);
+ CreateServiceFunction(MS_CLIST_HOTKEYSPROCESSMESSAGE, HotkeysProcessMessageStub);
+ CreateServiceFunction(MS_CLIST_GETCONTACTICON, GetContactIcon);
+ MySetProcessWorkingSetSize = (BOOL(WINAPI *) (HANDLE, SIZE_T, SIZE_T)) GetProcAddress(GetModuleHandleA("kernel32"), "SetProcessWorkingSetSize");
+ InitDisplayNameCache();
+ InitCListEvents();
+ InitGroupServices();
+ InitTray();
+
+ hCListImages = ImageList_Create(16, 16, ILC_MASK | (IsWinVerXPPlus()? ILC_COLOR32 : ILC_COLOR16), 13, 0);
+ HookEvent(ME_SKIN_ICONSCHANGED, CListIconsChanged);
+ CreateServiceFunction(MS_CLIST_GETICONSIMAGELIST, GetIconsImageList);
+ ImageList_AddIcon(hCListImages, LoadIcon(cli.hInst, MAKEINTRESOURCE(IDI_BLANK)));
+ {
+ int i;
+ for (i = 0; i < SIZEOF(statusModeList); i++)
+ ImageList_AddIcon(hCListImages, LoadSkinnedIcon(skinIconStatusList[i]));
+ }
+ //see IMAGE_GROUP... in clist.h if you add more images above here
+ ImageList_AddIcon(hCListImages, LoadSkinnedIcon(SKINICON_OTHER_GROUPOPEN));
+ ImageList_AddIcon(hCListImages, LoadSkinnedIcon(SKINICON_OTHER_GROUPSHUT));
+ return 0;
+}
diff --git a/miranda-wine/src/modules/clist/clistsettings.c b/miranda-wine/src/modules/clist/clistsettings.c
new file mode 100644
index 0000000..afae3aa
--- /dev/null
+++ b/miranda-wine/src/modules/clist/clistsettings.c
@@ -0,0 +1,380 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "clc.h"
+#include "../database/dblists.h"
+
+SortedList* clistCache = NULL;
+
+static int compareContacts( ClcCacheEntryBase* p1, ClcCacheEntryBase* p2 )
+{
+ return ( char* )p1->hContact - ( char* )p2->hContact;
+}
+
+void InitDisplayNameCache(void)
+{
+ clistCache = List_Create( 0, 50 );
+ clistCache->sortFunc = compareContacts;
+}
+
+void FreeDisplayNameCache(void)
+{
+ if ( clistCache != NULL ) {
+ int i;
+ for ( i = 0; i < clistCache->realCount; i++) {
+ cli.pfnFreeCacheItem(( ClcCacheEntryBase* )clistCache->items[i] );
+ mir_free( clistCache->items[i] );
+ }
+
+ List_Destroy( clistCache );
+ mir_free(clistCache);
+ clistCache = NULL;
+} }
+
+// default handlers for the cache item creation and destruction
+
+ClcCacheEntryBase* fnCreateCacheItem( HANDLE hContact )
+{
+ ClcCacheEntryBase* p = ( ClcCacheEntryBase* )mir_calloc( sizeof( ClcCacheEntryBase ));
+ if ( p == NULL )
+ return NULL;
+
+ p->hContact = hContact;
+ return p;
+}
+
+void fnCheckCacheItem( ClcCacheEntryBase* p )
+{
+ DBVARIANT dbv;
+ if ( p->group == NULL ) {
+ if ( !DBGetContactSettingTString( p->hContact, "CList", "Group", &dbv )) {
+ p->group = mir_tstrdup( dbv.ptszVal );
+ mir_free( dbv.ptszVal );
+ }
+ else p->group = mir_tstrdup( _T("") );
+ }
+
+ if ( p->isHidden == -1 )
+ p->isHidden = DBGetContactSettingByte( p->hContact, "CList", "Hidden", 0 );
+}
+
+void fnFreeCacheItem( ClcCacheEntryBase* p )
+{
+ if ( p->name ) { mir_free( p->name ); p->name = NULL; }
+ #if defined( _UNICODE )
+ if ( p->szName ) { mir_free( p->szName); p->szName = NULL; }
+ #endif
+ if ( p->group ) { mir_free( p->group ); p->group = NULL; }
+ p->isHidden = -1;
+}
+
+ClcCacheEntryBase* fnGetCacheEntry(HANDLE hContact)
+{
+ ClcCacheEntryBase* p;
+ int idx;
+ if ( !List_GetIndex( clistCache, &hContact, &idx )) {
+ if (( p = cli.pfnCreateCacheItem( hContact )) != NULL ) {
+ List_Insert( clistCache, p, idx );
+ cli.pfnInvalidateDisplayNameCacheEntry( p );
+ }
+ }
+ else p = ( ClcCacheEntryBase* )clistCache->items[idx];
+
+ cli.pfnCheckCacheItem( p );
+ return p;
+}
+
+void fnInvalidateDisplayNameCacheEntry(HANDLE hContact)
+{
+ if (hContact == INVALID_HANDLE_VALUE) {
+ FreeDisplayNameCache();
+ InitDisplayNameCache();
+ SendMessage(cli.hwndContactTree, CLM_AUTOREBUILD, 0, 0);
+ }
+ else {
+ int idx;
+ if ( List_GetIndex( clistCache, &hContact, &idx ))
+ cli.pfnFreeCacheItem(( ClcCacheEntryBase* )clistCache->items[idx] );
+} }
+
+TCHAR* fnGetContactDisplayName( HANDLE hContact, int mode )
+{
+ CONTACTINFO ci;
+ TCHAR *buffer;
+ ClcCacheEntryBase* cacheEntry = NULL;
+
+ if ( mode & GCDNF_NOCACHE )
+ mode &= ~GCDNF_NOCACHE;
+ else if ( mode != GCDNF_NOMYHANDLE) {
+ cacheEntry = cli.pfnGetCacheEntry( hContact );
+ if ( cacheEntry->name )
+ return cacheEntry->name;
+ }
+ ZeroMemory(&ci, sizeof(ci));
+ ci.cbSize = sizeof(ci);
+ ci.hContact = hContact;
+ if (ci.hContact == NULL)
+ ci.szProto = "ICQ";
+ ci.dwFlag = (mode == GCDNF_NOMYHANDLE) ? CNF_DISPLAYNC : CNF_DISPLAY;
+ #if defined( _UNICODE )
+ ci.dwFlag += CNF_UNICODE;
+ #endif
+ if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
+ if (ci.type == CNFT_ASCIIZ) {
+ if (cacheEntry == NULL) {
+ size_t len = _tcslen(ci.pszVal);
+ buffer = (TCHAR*) mir_alloc( sizeof( TCHAR )*( len+1 ));
+ memcpy( buffer, ci.pszVal, len * sizeof( TCHAR ));
+ buffer[ len ] = 0;
+ mir_free(ci.pszVal);
+ return buffer;
+ }
+ else {
+ cacheEntry->name = ci.pszVal;
+ #if defined( _UNICODE )
+ cacheEntry->szName = u2a( ci.pszVal );
+ #endif
+ return ci.pszVal;
+ } }
+
+ if (ci.type == CNFT_DWORD) {
+ if (cacheEntry == NULL) {
+ buffer = (TCHAR*) mir_alloc(15 * sizeof( TCHAR ));
+ _ltot(ci.dVal, buffer, 10 );
+ return buffer;
+ }
+ else {
+ buffer = (TCHAR*) mir_alloc(15 * sizeof( TCHAR ));
+ _ltot(ci.dVal, buffer, 10 );
+ cacheEntry->name = buffer;
+ #if defined( _UNICODE )
+ cacheEntry->szName = u2a( buffer );
+ #else
+ #endif
+ return buffer;
+ } } }
+
+ CallContactService(hContact, PSS_GETINFO, SGIF_MINIMAL, 0);
+ buffer = TranslateT("(Unknown Contact)");
+ return buffer;
+}
+
+int GetContactDisplayName(WPARAM wParam, LPARAM lParam)
+{
+ CONTACTINFO ci;
+ ClcCacheEntryBase* cacheEntry = NULL;
+ char *buffer;
+ HANDLE hContact = (HANDLE)wParam;
+
+ if ( lParam & GCDNF_UNICODE )
+ return ( int )cli.pfnGetContactDisplayName(hContact, lParam & ~GCDNF_UNICODE );
+
+ if ((int) lParam != GCDNF_NOMYHANDLE) {
+ cacheEntry = cli.pfnGetCacheEntry(hContact);
+ #if defined( _UNICODE )
+ if ( cacheEntry->szName )
+ return (int)cacheEntry->szName;
+ #else
+ if ( cacheEntry->name )
+ return (int)cacheEntry->name;
+ #endif
+ }
+ ZeroMemory(&ci, sizeof(ci));
+ ci.cbSize = sizeof(ci);
+ ci.hContact = hContact;
+ if (ci.hContact == NULL)
+ ci.szProto = "ICQ";
+ ci.dwFlag = (int) lParam == GCDNF_NOMYHANDLE ? CNF_DISPLAYNC : CNF_DISPLAY;
+ #if defined( _UNICODE )
+ ci.dwFlag += CNF_UNICODE;
+ #endif
+ if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
+ if (ci.type == CNFT_ASCIIZ) {
+ if (cacheEntry == NULL) {
+ size_t len = _tcslen(ci.pszVal);
+ #if defined( _UNICODE )
+ buffer = u2a( ci.pszVal );
+ mir_free(ci.pszVal);
+ #else
+ buffer = ci.pszVal;
+ #endif
+ return (int) buffer;
+ }
+ else {
+ cacheEntry->name = ci.pszVal;
+ #if defined( _UNICODE )
+ cacheEntry->szName = u2a( ci.pszVal );
+ return (int)cacheEntry->szName;
+ #else
+ return (int)cacheEntry->name;
+ #endif
+ }
+ }
+ if (ci.type == CNFT_DWORD) {
+ if (cacheEntry == NULL) {
+ buffer = ( char* )mir_alloc(15);
+ ltoa(ci.dVal, buffer, 10 );
+ return (int) buffer;
+ }
+ else {
+ buffer = ( char* )mir_alloc(15);
+ ltoa(ci.dVal, buffer, 10 );
+ #if defined( _UNICODE )
+ cacheEntry->szName = buffer;
+ cacheEntry->name = a2u( buffer );
+ #else
+ cacheEntry->name = buffer;
+ #endif
+ return (int) buffer;
+ } } }
+
+ CallContactService(hContact, PSS_GETINFO, SGIF_MINIMAL, 0);
+ buffer = Translate("(Unknown Contact)");
+ return (int) buffer;
+}
+
+int InvalidateDisplayName(WPARAM wParam, LPARAM lParam)
+{
+ cli.pfnInvalidateDisplayNameCacheEntry((HANDLE)wParam);
+ return 0;
+}
+
+int ContactAdded(WPARAM wParam, LPARAM lParam)
+{
+ cli.pfnChangeContactIcon((HANDLE)wParam, cli.pfnIconFromStatusMode((char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0), ID_STATUS_OFFLINE, NULL), 1);
+ cli.pfnSortContacts();
+ return 0;
+}
+
+int ContactDeleted(WPARAM wParam, LPARAM lParam)
+{
+ CallService(MS_CLUI_CONTACTDELETED, wParam, 0);
+ return 0;
+}
+
+int ContactSettingChanged(WPARAM wParam, LPARAM lParam)
+{
+ DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *) lParam;
+ DBVARIANT dbv;
+ HANDLE hContact = (HANDLE)wParam;
+
+ // Early exit
+ if ( hContact == NULL)
+ return 0;
+
+ dbv.pszVal = NULL;
+ if (!DBGetContactSetting(hContact, "Protocol", "p", &dbv)) {
+ if (!strcmp(cws->szModule, dbv.pszVal)) {
+ cli.pfnInvalidateDisplayNameCacheEntry(hContact);
+ if (!strcmp(cws->szSetting, "UIN") || !strcmp(cws->szSetting, "Nick") || !strcmp(cws->szSetting, "FirstName")
+ || !strcmp(cws->szSetting, "LastName") || !strcmp(cws->szSetting, "e-mail")) {
+ CallService(MS_CLUI_CONTACTRENAMED, wParam, 0);
+ }
+ else if (!strcmp(cws->szSetting, "Status")) {
+ if (!DBGetContactSettingByte(hContact, "CList", "Hidden", 0)) {
+ if (DBGetContactSettingByte(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT)) {
+ // User's state is changing, and we are hideOffline-ing
+ if (cws->value.wVal == ID_STATUS_OFFLINE) {
+ cli.pfnChangeContactIcon(hContact, cli.pfnIconFromStatusMode(cws->szModule, cws->value.wVal, hContact), 0);
+ CallService(MS_CLUI_CONTACTDELETED, wParam, 0);
+ mir_free(dbv.pszVal);
+ return 0;
+ }
+ cli.pfnChangeContactIcon(hContact, cli.pfnIconFromStatusMode(cws->szModule, cws->value.wVal, hContact), 1);
+ }
+ cli.pfnChangeContactIcon(hContact, cli.pfnIconFromStatusMode(cws->szModule, cws->value.wVal, hContact), 0);
+ }
+ }
+ else {
+ mir_free(dbv.pszVal);
+ return 0;
+ }
+ cli.pfnSortContacts();
+ }
+ }
+
+ if (!strcmp(cws->szModule, "CList")) {
+ if (!strcmp(cws->szSetting, "Hidden")) {
+ if (cws->value.type == DBVT_DELETED || cws->value.bVal == 0) {
+ char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ cli.pfnChangeContactIcon(hContact, cli.pfnIconFromStatusMode(szProto, szProto == NULL ? ID_STATUS_OFFLINE : DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE), hContact), 1);
+ }
+ else
+ CallService(MS_CLUI_CONTACTDELETED, wParam, 0);
+ }
+ if (!strcmp(cws->szSetting, "MyHandle")) {
+ cli.pfnInvalidateDisplayNameCacheEntry(hContact);
+ }
+ }
+
+ if (!strcmp(cws->szModule, "Protocol")) {
+ if (!strcmp(cws->szSetting, "p")) {
+ char *szProto;
+ if (cws->value.type == DBVT_DELETED)
+ szProto = NULL;
+ else
+ szProto = cws->value.pszVal;
+ cli.pfnChangeContactIcon(hContact,
+ cli.pfnIconFromStatusMode(szProto,
+ szProto == NULL ? ID_STATUS_OFFLINE : DBGetContactSettingWord(hContact, szProto, "Status",
+ ID_STATUS_OFFLINE), hContact), 0);
+ }
+ }
+
+ // Clean up
+ if (dbv.pszVal)
+ mir_free(dbv.pszVal);
+
+ return 0;
+
+}
+
+/*-----------------------------------------------------*/
+
+char* u2a( 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( 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/src/modules/clist/clisttray.c b/miranda-wine/src/modules/clist/clisttray.c
new file mode 100644
index 0000000..eca2cab
--- /dev/null
+++ b/miranda-wine/src/modules/clist/clisttray.c
@@ -0,0 +1,632 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "clc.h"
+
+#define TRAYICON_ID_BASE 100
+#define TIM_CALLBACK (WM_USER+1857)
+#define TIM_CREATE (WM_USER+1858)
+
+static VOID CALLBACK TrayCycleTimerProc(HWND hwnd, UINT message, UINT idEvent, DWORD dwTime);
+void fnTrayIconUpdateBase(const char *szChangedProto);
+
+extern HIMAGELIST hCListImages;
+extern int currentStatusMenuItem, currentDesiredStatusMode;
+extern BOOL(WINAPI * MySetProcessWorkingSetSize) (HANDLE, SIZE_T, SIZE_T);
+
+static UINT WM_TASKBARCREATED;
+static int cycleTimerId = 0, cycleStep = 0;
+static int RefreshTimerId=0; /////by FYR
+
+struct trayIconInfo_t
+{
+ int id;
+ char *szProto;
+ HICON hBaseIcon;
+ int isBase;
+};
+static struct trayIconInfo_t *trayIcon = NULL;
+static int trayIconCount;
+
+// don't move to win2k.h, need new and old versions to work on 9x/2000/XP
+#define NIF_STATE 0x00000008
+#define NIF_INFO 0x00000010
+
+typedef struct _DllVersionInfo
+{
+ DWORD cbSize;
+ DWORD dwMajorVersion; // Major version
+ DWORD dwMinorVersion; // Minor version
+ DWORD dwBuildNumber; // Build number
+ DWORD dwPlatformID; // DLLVER_PLATFORM_*
+}
+ DLLVERSIONINFO;
+
+#define DLLVER_PLATFORM_WINDOWS 0x00000001 // Windows 95
+#define DLLVER_PLATFORM_NT 0x00000002 // Windows NT
+typedef HRESULT(CALLBACK * DLLGETVERSIONPROC) (DLLVERSIONINFO *);
+
+static DLLVERSIONINFO dviShell;
+
+static TCHAR *TrayIconMakeTooltip(const TCHAR *szPrefix, const char *szProto)
+{
+ static TCHAR szTip[128];
+ char szProtoName[32];
+ TCHAR *szStatus, *szSeparator, *sztProto;
+
+ szSeparator = (IsWinVerMEPlus())? szSeparator = _T("\n") : _T(" | ");
+
+ if (szProto == NULL) {
+ PROTOCOLDESCRIPTOR **protos;
+ int count, netProtoCount, i;
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM) & count, (LPARAM) & protos);
+ for (i = 0, netProtoCount = 0; i < count; i++)
+ if (protos[i]->type == PROTOTYPE_PROTOCOL)
+ netProtoCount++;
+ if (netProtoCount == 1)
+ for (i = 0; i < count; i++)
+ if (protos[i]->type == PROTOTYPE_PROTOCOL)
+ return TrayIconMakeTooltip(szPrefix, protos[i]->szName);
+ if (szPrefix && szPrefix[0]) {
+ lstrcpyn(szTip, szPrefix, SIZEOF(szTip));
+ if (!DBGetContactSettingByte(NULL, "CList", "AlwaysStatus", SETTING_ALWAYSSTATUS_DEFAULT))
+ return szTip;
+ }
+ else
+ szTip[0] = '\0';
+ szTip[ SIZEOF(szTip) - 1] = '\0';
+ for (i = count - 1; i >= 0; i--) {
+ if (protos[i]->type != PROTOTYPE_PROTOCOL)
+ continue;
+ CallProtoService(protos[i]->szName, PS_GETNAME, SIZEOF(szProtoName), (LPARAM) szProtoName);
+ szStatus = cli.pfnGetStatusModeDescription( CallProtoService(protos[i]->szName, PS_GETSTATUS, 0, 0), 0);
+ if (szTip[0])
+ _tcsncat(szTip, szSeparator, SIZEOF(szTip) - 1 - _tcslen(szTip));
+ #if defined( _UNICODE )
+ { TCHAR* p = a2u( szProtoName );
+ _tcsncat(szTip, p, SIZEOF(szTip) - 1 - _tcslen(szTip));
+ mir_free( p );
+ }
+ #else
+ _tcsncat(szTip, szProtoName, SIZEOF(szTip) - 1 - _tcslen(szTip));
+ #endif
+ _tcsncat(szTip, _T(" "), SIZEOF(szTip) - 1 - _tcslen(szTip));
+ _tcsncat(szTip, szStatus, SIZEOF(szTip) - 1 - _tcslen(szTip));
+ }
+ }
+ else {
+ CallProtoService(szProto, PS_GETNAME, SIZEOF(szProtoName), (LPARAM) szProtoName);
+ #if defined( _UNICODE )
+ sztProto = a2u( szProtoName );
+ #else
+ sztProto = szProtoName;
+ #endif
+
+ szStatus = cli.pfnGetStatusModeDescription(CallProtoService(szProto, PS_GETSTATUS, 0, 0), 0);
+ if (szPrefix && szPrefix[0]) {
+ if (DBGetContactSettingByte(NULL, "CList", "AlwaysStatus", SETTING_ALWAYSSTATUS_DEFAULT))
+ mir_sntprintf(szTip, SIZEOF(szTip), _T("%s%s%s %s"), szPrefix, szSeparator, sztProto, szStatus);
+ else
+ lstrcpyn(szTip, szPrefix, SIZEOF(szTip));
+ }
+ else mir_sntprintf(szTip, SIZEOF(szTip), _T("%s %s"), sztProto, szStatus);
+
+ #if defined( _UNICODE )
+ mir_free(sztProto);
+ #endif
+ }
+ return szTip;
+}
+
+static int TrayIconAdd(HWND hwnd, const char *szProto, const char *szIconProto, int status)
+{
+ NOTIFYICONDATA nid = { 0 };
+ int i;
+
+ for (i = 0; i < trayIconCount; i++)
+ if (trayIcon[i].id == 0)
+ break;
+
+ trayIcon[i].id = TRAYICON_ID_BASE + i;
+ trayIcon[i].szProto = (char *) szProto;
+
+ nid.cbSize = ( dviShell.dwMajorVersion >= 5 ) ? sizeof(nid) : NOTIFYICONDATA_V1_SIZE;
+ nid.hWnd = hwnd;
+ nid.uID = trayIcon[i].id;
+ nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
+ nid.uCallbackMessage = TIM_CALLBACK;
+ trayIcon[i].hBaseIcon = ImageList_GetIcon(hCListImages, cli.pfnIconFromStatusMode(szIconProto ? szIconProto : trayIcon[i].szProto, status, NULL), ILD_NORMAL);
+ nid.hIcon = trayIcon[i].hBaseIcon;
+
+ if (dviShell.dwMajorVersion >= 5)
+ nid.uFlags |= NIF_INFO;
+
+ lstrcpyn(nid.szTip, TrayIconMakeTooltip(NULL, trayIcon[i].szProto), SIZEOF(nid.szTip));
+ Shell_NotifyIcon(NIM_ADD, &nid);
+ trayIcon[i].isBase = 1;
+ return i;
+}
+
+static void TrayIconRemove(HWND hwnd, const char *szProto)
+{
+ int i;
+ NOTIFYICONDATA nid = { 0 };
+
+ nid.cbSize = ( dviShell.dwMajorVersion >= 5 ) ? sizeof(nid) : NOTIFYICONDATA_V1_SIZE;
+ nid.hWnd = hwnd;
+ for (i = 0; i < trayIconCount; i++) {
+ if (trayIcon[i].id == 0)
+ continue;
+ if (lstrcmpA(szProto, trayIcon[i].szProto))
+ continue;
+ nid.uID = trayIcon[i].id;
+ Shell_NotifyIcon(NIM_DELETE, &nid);
+
+ DestroyIcon(trayIcon[i].hBaseIcon);
+ trayIcon[i].id = 0;
+ break;
+ }
+}
+
+static int TrayIconInit(HWND hwnd)
+{
+ int count, netProtoCount, i;
+ int averageMode = 0;
+ PROTOCOLDESCRIPTOR **protos;
+
+ if (cycleTimerId) {
+ KillTimer(NULL, cycleTimerId);
+ cycleTimerId = 0;
+ }
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM) & count, (LPARAM) & protos);
+ for (i = 0, netProtoCount = 0; i < count; i++) {
+ if (protos[i]->type != PROTOTYPE_PROTOCOL)
+ continue;
+ cycleStep = i;
+ netProtoCount++;
+ if (averageMode == 0)
+ averageMode = CallProtoService(protos[i]->szName, PS_GETSTATUS, 0, 0);
+ else if (averageMode != CallProtoService(protos[i]->szName, PS_GETSTATUS, 0, 0)) {
+ averageMode = -1;
+ break;
+ }
+ }
+ trayIconCount = count;
+ trayIcon = (struct trayIconInfo_t *) mir_alloc(sizeof(struct trayIconInfo_t) * count);
+ ZeroMemory(trayIcon, sizeof(struct trayIconInfo_t) * count);
+ if (DBGetContactSettingByte(NULL, "CList", "TrayIcon", SETTING_TRAYICON_DEFAULT) == SETTING_TRAYICON_MULTI &&
+ (averageMode <= 0 || DBGetContactSettingByte(NULL, "CList", "AlwaysMulti", SETTING_ALWAYSMULTI_DEFAULT))) {
+ int i;
+ for (i = count - 1; i >= 0; i--)
+ if (protos[i]->type == PROTOTYPE_PROTOCOL)
+ TrayIconAdd(hwnd, protos[i]->szName, NULL, CallProtoService(protos[i]->szName, PS_GETSTATUS, 0, 0));
+ }
+ else if (averageMode <= 0 && DBGetContactSettingByte(NULL, "CList", "TrayIcon", SETTING_TRAYICON_DEFAULT) == SETTING_TRAYICON_SINGLE) {
+ DBVARIANT dbv = { DBVT_DELETED };
+ char *szProto;
+ if (DBGetContactSetting(NULL, "CList", "PrimaryStatus", &dbv))
+ szProto = NULL;
+ else
+ szProto = dbv.pszVal;
+ TrayIconAdd(hwnd, NULL, szProto, szProto ? CallProtoService(szProto, PS_GETSTATUS, 0, 0) : CallService(MS_CLIST_GETSTATUSMODE, 0, 0));
+ DBFreeVariant(&dbv);
+ }
+ else
+ TrayIconAdd(hwnd, NULL, NULL, averageMode);
+ if (averageMode <= 0 && DBGetContactSettingByte(NULL, "CList", "TrayIcon", SETTING_TRAYICON_DEFAULT) == SETTING_TRAYICON_CYCLE)
+ cycleTimerId = SetTimer(NULL, 0, DBGetContactSettingWord(NULL, "CList", "CycleTime", SETTING_CYCLETIME_DEFAULT) * 1000, TrayCycleTimerProc);
+ return 0;
+}
+
+static void TrayIconDestroy(HWND hwnd)
+{
+ NOTIFYICONDATA nid = { 0 };
+ int i;
+
+ nid.cbSize = ( dviShell.dwMajorVersion >= 5 ) ? sizeof(nid) : NOTIFYICONDATA_V1_SIZE;
+ nid.hWnd = hwnd;
+ for (i = 0; i < trayIconCount; i++) {
+ if (trayIcon[i].id == 0)
+ continue;
+ nid.uID = trayIcon[i].id;
+ Shell_NotifyIcon(NIM_DELETE, &nid);
+ DestroyIcon(trayIcon[i].hBaseIcon);
+ }
+ if (trayIcon)
+ mir_free(trayIcon);
+ trayIcon = NULL;
+ trayIconCount = 0;
+}
+
+//called when Explorer crashes and the taskbar is remade
+static void TrayIconTaskbarCreated(HWND hwnd)
+{
+ TrayIconDestroy(hwnd);
+ TrayIconInit(hwnd);
+}
+
+static int TrayIconUpdate(HICON hNewIcon, const TCHAR *szNewTip, const char *szPreferredProto, int isBase)
+{
+ NOTIFYICONDATA nid = { 0 };
+ int i;
+
+ nid.cbSize = ( dviShell.dwMajorVersion >= 5 ) ? sizeof(nid) : NOTIFYICONDATA_V1_SIZE;
+ nid.hWnd = (HWND) CallService(MS_CLUI_GETHWND, 0, 0);
+ nid.uFlags = NIF_ICON | NIF_TIP;
+ nid.hIcon = hNewIcon;
+
+ for (i = 0; i < trayIconCount; i++) {
+ if (trayIcon[i].id == 0)
+ continue;
+ if (lstrcmpA(trayIcon[i].szProto, szPreferredProto))
+ continue;
+ nid.uID = trayIcon[i].id;
+ lstrcpyn(nid.szTip, TrayIconMakeTooltip(szNewTip, trayIcon[i].szProto), SIZEOF(nid.szTip));
+ Shell_NotifyIcon(NIM_MODIFY, &nid);
+
+ trayIcon[i].isBase = isBase;
+ return i;
+ }
+
+ //if there wasn't a suitable icon, change all the icons
+ for (i = 0; i < trayIconCount; i++) {
+ if (trayIcon[i].id == 0)
+ continue;
+ nid.uID = trayIcon[i].id;
+ lstrcpyn(nid.szTip, TrayIconMakeTooltip(szNewTip, trayIcon[i].szProto), SIZEOF(nid.szTip));
+ Shell_NotifyIcon(NIM_MODIFY, &nid);
+
+ trayIcon[i].isBase = isBase;
+ }
+ return -1;
+}
+
+static int TrayIconSetBaseInfo(HICON hIcon, char *szPreferredProto)
+{
+ int i;
+
+ for (i = 0; i < trayIconCount; i++) {
+ if (trayIcon[i].id == 0)
+ continue;
+ if (lstrcmpA(trayIcon[i].szProto, szPreferredProto))
+ continue;
+ DestroyIcon(trayIcon[i].hBaseIcon);
+ trayIcon[i].hBaseIcon = hIcon;
+ return i;
+ }
+ //if there wasn't a specific icon, there will only be one suitable
+ for (i = 0; i < trayIconCount; i++) {
+ if (trayIcon[i].id == 0)
+ continue;
+ DestroyIcon(trayIcon[i].hBaseIcon);
+ trayIcon[i].hBaseIcon = hIcon;
+ return i;
+ }
+ DestroyIcon(hIcon);
+ return -1;
+}
+
+void fnTrayIconUpdateWithImageList(int iImage, const TCHAR *szNewTip, char *szPreferredProto)
+{
+ HICON hIcon = ImageList_GetIcon(hCListImages, iImage, ILD_NORMAL);
+ TrayIconUpdate(hIcon, szNewTip, szPreferredProto, 0);
+ DestroyIcon(hIcon);
+}
+
+static VOID CALLBACK TrayCycleTimerProc(HWND hwnd, UINT message, UINT idEvent, DWORD dwTime)
+{
+ int count;
+ PROTOCOLDESCRIPTOR **protos;
+
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM) & count, (LPARAM) & protos);
+ for (cycleStep++;; cycleStep++) {
+ if (cycleStep >= count)
+ cycleStep = 0;
+ if (protos[cycleStep]->type == PROTOTYPE_PROTOCOL)
+ break;
+ }
+ DestroyIcon(trayIcon[0].hBaseIcon);
+ trayIcon[0].hBaseIcon =
+ ImageList_GetIcon(hCListImages,
+ cli.pfnIconFromStatusMode(protos[cycleStep]->szName, CallProtoService(protos[cycleStep]->szName, PS_GETSTATUS, 0, 0), NULL), ILD_NORMAL);
+ if (trayIcon[0].isBase)
+ TrayIconUpdate(trayIcon[0].hBaseIcon, NULL, NULL, 1);
+}
+
+void fnTrayIconUpdateBase(const char *szChangedProto)
+{
+ int i, count, netProtoCount, changed = -1;
+ PROTOCOLDESCRIPTOR **protos;
+ int averageMode = 0;
+ HWND hwnd = (HWND) CallService(MS_CLUI_GETHWND, 0, 0);
+
+ if (cycleTimerId) {
+ KillTimer(NULL, cycleTimerId);
+ cycleTimerId = 0;
+ }
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM) & count, (LPARAM) & protos);
+ for (i = 0, netProtoCount = 0; i < count; i++) {
+ if (protos[i]->type != PROTOTYPE_PROTOCOL)
+ continue;
+ netProtoCount++;
+ if (!lstrcmpA(szChangedProto, protos[i]->szName))
+ cycleStep = i;
+ if (averageMode == 0)
+ averageMode = CallProtoService(protos[i]->szName, PS_GETSTATUS, 0, 0);
+ else if (averageMode != CallProtoService(protos[i]->szName, PS_GETSTATUS, 0, 0)) {
+ averageMode = -1;
+ break;
+ }
+ }
+ if (netProtoCount > 1) {
+ if (averageMode > 0) {
+ if (DBGetContactSettingByte(NULL, "CList", "TrayIcon", SETTING_TRAYICON_DEFAULT) == SETTING_TRAYICON_MULTI) {
+ if (DBGetContactSettingByte(NULL, "CList", "AlwaysMulti", SETTING_ALWAYSMULTI_DEFAULT))
+ changed = TrayIconSetBaseInfo(ImageList_GetIcon(hCListImages, cli.pfnIconFromStatusMode(szChangedProto, averageMode, NULL), ILD_NORMAL), (char*)szChangedProto);
+ else if (trayIcon && trayIcon[0].szProto != NULL) {
+ TrayIconDestroy(hwnd);
+ TrayIconInit(hwnd);
+ }
+ else
+ changed = TrayIconSetBaseInfo(ImageList_GetIcon(hCListImages, cli.pfnIconFromStatusMode(NULL, averageMode, NULL), ILD_NORMAL), NULL);
+ }
+ else
+ changed = TrayIconSetBaseInfo(ImageList_GetIcon(hCListImages, cli.pfnIconFromStatusMode(NULL, averageMode, NULL), ILD_NORMAL), NULL);
+ }
+ else {
+ switch (DBGetContactSettingByte(NULL, "CList", "TrayIcon", SETTING_TRAYICON_DEFAULT)) {
+ case SETTING_TRAYICON_SINGLE:
+ {
+ DBVARIANT dbv = { DBVT_DELETED };
+ char *szProto;
+ if (DBGetContactSetting(NULL, "CList", "PrimaryStatus", &dbv))
+ szProto = NULL;
+ else
+ szProto = dbv.pszVal;
+ changed = TrayIconSetBaseInfo(ImageList_GetIcon(hCListImages,cli.pfnIconFromStatusMode(szProto,szProto ? CallProtoService(szProto, PS_GETSTATUS, 0,0) : CallService(MS_CLIST_GETSTATUSMODE, 0, 0), NULL),ILD_NORMAL), NULL);
+ DBFreeVariant(&dbv);
+ break;
+ }
+ case SETTING_TRAYICON_CYCLE:
+ cycleTimerId =
+ SetTimer(NULL, 0, DBGetContactSettingWord(NULL, "CList", "CycleTime", SETTING_CYCLETIME_DEFAULT) * 1000, TrayCycleTimerProc);
+ changed =
+ TrayIconSetBaseInfo(ImageList_GetIcon
+ (hCListImages, cli.pfnIconFromStatusMode(szChangedProto, CallProtoService(szChangedProto, PS_GETSTATUS, 0, 0), NULL),
+ ILD_NORMAL), NULL);
+ break;
+ case SETTING_TRAYICON_MULTI:
+ if (!trayIcon) {
+ TrayIconRemove(NULL, NULL);
+ }
+ else if (DBGetContactSettingByte(NULL, "CList", "AlwaysMulti", SETTING_ALWAYSMULTI_DEFAULT))
+ changed = TrayIconSetBaseInfo(ImageList_GetIcon(hCListImages, cli.pfnIconFromStatusMode(szChangedProto, CallProtoService(szChangedProto, PS_GETSTATUS, 0, 0), NULL), ILD_NORMAL), (char*)szChangedProto);
+ else {
+ TrayIconDestroy(hwnd);
+ TrayIconInit(hwnd);
+ }
+ break;
+ }
+ }
+ }
+ else
+ changed = TrayIconSetBaseInfo(ImageList_GetIcon(hCListImages, cli.pfnIconFromStatusMode(NULL, averageMode, NULL), ILD_NORMAL), NULL);
+ if (changed != -1 && trayIcon[changed].isBase)
+ TrayIconUpdate(trayIcon[changed].hBaseIcon, NULL, trayIcon[changed].szProto, 1);
+}
+
+void fnTrayIconSetToBase(char *szPreferredProto)
+{
+ int i;
+
+ for (i = 0; i < trayIconCount; i++) {
+ if (trayIcon[i].id == 0)
+ continue;
+ if (lstrcmpA(trayIcon[i].szProto, szPreferredProto))
+ continue;
+ TrayIconUpdate(trayIcon[i].hBaseIcon, NULL, szPreferredProto, 1);
+ return;
+ }
+ //if there wasn't a specific icon, there will only be one suitable
+ for (i = 0; i < trayIconCount; i++) {
+ if (trayIcon[i].id == 0)
+ continue;
+ TrayIconUpdate(trayIcon[i].hBaseIcon, NULL, szPreferredProto, 1);
+ return;
+ }
+}
+
+void fnTrayIconIconsChanged(void)
+{
+ HWND hwnd = (HWND) CallService(MS_CLUI_GETHWND, 0, 0);
+ TrayIconDestroy(hwnd);
+ TrayIconInit(hwnd);
+}
+
+static int autoHideTimerId;
+static VOID CALLBACK TrayIconAutoHideTimer(HWND hwnd, UINT message, UINT idEvent, DWORD dwTime)
+{
+ HWND hwndClui;
+ KillTimer(hwnd, idEvent);
+ hwndClui = (HWND) CallService(MS_CLUI_GETHWND, 0, 0);
+ if (GetActiveWindow() == hwndClui)
+ return;
+ ShowWindow(hwndClui, SW_HIDE);
+ if (MySetProcessWorkingSetSize != NULL)
+ MySetProcessWorkingSetSize(GetCurrentProcess(), -1, -1);
+}
+
+int fnTrayIconPauseAutoHide(WPARAM wParam, LPARAM lParam)
+{
+ if (DBGetContactSettingByte(NULL, "CList", "AutoHide", SETTING_AUTOHIDE_DEFAULT)) {
+ if (GetActiveWindow() != (HWND) CallService(MS_CLUI_GETHWND, 0, 0)) {
+ KillTimer(NULL, autoHideTimerId);
+ autoHideTimerId = SetTimer(NULL, 0, 1000 * DBGetContactSettingWord(NULL, "CList", "HideTime", SETTING_HIDETIME_DEFAULT), TrayIconAutoHideTimer);
+ }
+ }
+ return 0;
+}
+
+int fnTrayIconProcessMessage(WPARAM wParam, LPARAM lParam)
+{
+ MSG *msg = (MSG *) wParam;
+ switch (msg->message) {
+ case WM_CREATE: {
+ WM_TASKBARCREATED = RegisterWindowMessageA("TaskbarCreated");
+ PostMessage(msg->hwnd, TIM_CREATE, 0, 0);
+ break;
+ }
+ case TIM_CREATE:
+ TrayIconInit(msg->hwnd);
+ break;
+ case WM_ACTIVATE:
+ if (DBGetContactSettingByte(NULL, "CList", "AutoHide", SETTING_AUTOHIDE_DEFAULT)) {
+ if (LOWORD(msg->wParam) == WA_INACTIVE)
+ autoHideTimerId = SetTimer(NULL, 0, 1000 * DBGetContactSettingWord(NULL, "CList", "HideTime", SETTING_HIDETIME_DEFAULT), TrayIconAutoHideTimer);
+ else
+ KillTimer(NULL, autoHideTimerId);
+ }
+ break;
+ case WM_DESTROY:
+ TrayIconDestroy(msg->hwnd);
+ break;
+ case TIM_CALLBACK:
+ if (msg->lParam == WM_MBUTTONUP) {
+ cli.pfnShowHide(0, 0);
+ }
+ else if (msg->lParam ==
+ (DBGetContactSettingByte(NULL, "CList", "Tray1Click", SETTING_TRAY1CLICK_DEFAULT) ? WM_LBUTTONUP : WM_LBUTTONDBLCLK)) {
+ if ((GetAsyncKeyState(VK_CONTROL) & 0x8000))
+ cli.pfnShowHide(0, 0);
+ else {
+ if (cli.pfnEventsProcessTrayDoubleClick())
+ cli.pfnShowHide(0, 0);
+ }
+ }
+ else if (msg->lParam == WM_RBUTTONUP) {
+ MENUITEMINFO mi;
+ POINT pt;
+ HMENU hMainMenu = LoadMenu(cli.hInst, MAKEINTRESOURCE(IDR_CONTEXT));
+ HMENU hMenu = GetSubMenu(hMainMenu, 0);
+ CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) hMenu, 0);
+
+ ZeroMemory(&mi, sizeof(mi));
+ mi.cbSize = MENUITEMINFO_V4_SIZE;
+ mi.fMask = MIIM_SUBMENU | MIIM_TYPE;
+ mi.fType = MFT_STRING;
+ mi.hSubMenu = (HMENU) CallService(MS_CLIST_MENUGETMAIN, 0, 0);
+ mi.dwTypeData = TranslateT("&Main Menu");
+ InsertMenuItem(hMenu, 1, TRUE, &mi);
+ mi.hSubMenu = (HMENU) CallService(MS_CLIST_MENUGETSTATUS, 0, 0);
+ mi.dwTypeData = TranslateT("&Status");
+ InsertMenuItem(hMenu, 2, TRUE, &mi);
+ SetMenuDefaultItem(hMenu, ID_TRAY_HIDE, FALSE);
+
+ SetForegroundWindow(msg->hwnd);
+ SetFocus(msg->hwnd);
+ GetCursorPos(&pt);
+ TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN, pt.x, pt.y, 0, msg->hwnd, NULL);
+
+ RemoveMenu(hMenu, 1, MF_BYPOSITION);
+ RemoveMenu(hMenu, 1, MF_BYPOSITION);
+ DestroyMenu(hMainMenu);
+ }
+ *((LRESULT *) lParam) = 0;
+ return TRUE;
+ default:
+ if (msg->message == WM_TASKBARCREATED) {
+ TrayIconTaskbarCreated(msg->hwnd);
+ *((LRESULT *) lParam) = 0;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+int fnCListTrayNotify(MIRANDASYSTRAYNOTIFY *msn)
+{
+ if (msn && msn->cbSize == sizeof(MIRANDASYSTRAYNOTIFY) && msn->szInfo && msn->szInfoTitle) {
+ if (trayIcon) {
+ NOTIFYICONDATAA nid = { 0 };
+ nid.cbSize = ( dviShell.dwMajorVersion >= 5 ) ? sizeof(nid) : NOTIFYICONDATAA_V1_SIZE;
+ nid.hWnd = (HWND) CallService(MS_CLUI_GETHWND, 0, 0);
+ if (msn->szProto) {
+ int j;
+ for (j = 0; j < trayIconCount; j++) {
+ if (trayIcon[j].szProto != NULL) {
+ if (strcmp(msn->szProto, trayIcon[j].szProto) == 0) {
+ nid.uID = trayIcon[j].id;
+ j = trayIconCount;
+ continue;
+ }
+ }
+ else {
+ if (trayIcon[j].isBase) {
+ nid.uID = trayIcon[j].id;
+ j = trayIconCount;
+ continue;
+ }
+ }
+ } //for
+ }
+ else {
+ nid.uID = trayIcon[0].id;
+ }
+ nid.uFlags = NIF_INFO;
+ lstrcpynA(nid.szInfo, msn->szInfo, sizeof(nid.szInfo));
+ lstrcpynA(nid.szInfoTitle, msn->szInfoTitle, sizeof(nid.szInfoTitle));
+ nid.uTimeout = msn->uTimeout;
+ nid.dwInfoFlags = msn->dwInfoFlags;
+ return Shell_NotifyIconA(NIM_MODIFY, (void *) &nid) == 0;
+ }
+ return 2;
+ }
+ return 1;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static int pfnCListTrayNotifyStub(WPARAM wParam, LPARAM lParam )
+{ return cli.pfnCListTrayNotify(( MIRANDASYSTRAYNOTIFY* )lParam );
+}
+
+void InitTray(void)
+{
+ HINSTANCE hLib;
+
+ hLib = LoadLibraryA("shell32.dll");
+ if (hLib) {
+ DLLGETVERSIONPROC proc;
+ dviShell.cbSize = sizeof(dviShell);
+ proc = (DLLGETVERSIONPROC) GetProcAddress(hLib, "DllGetVersion");
+ if (proc) {
+ proc(&dviShell);
+ }
+ FreeLibrary(hLib);
+ }
+ if (dviShell.dwMajorVersion >= 5)
+ CreateServiceFunction(MS_CLIST_SYSTRAY_NOTIFY, pfnCListTrayNotifyStub );
+
+ return;
+}
diff --git a/miranda-wine/src/modules/clist/clui.c b/miranda-wine/src/modules/clist/clui.c
new file mode 100644
index 0000000..6437321
--- /dev/null
+++ b/miranda-wine/src/modules/clist/clui.c
@@ -0,0 +1,1042 @@
+/*
+
+ Miranda IM: the free IM client for Microsoft* Windows*
+
+ Copyright 2000-2006 Miranda ICQ/IM project,
+ all portions of this codebase are copyrighted to the people
+ listed in contributors.txt.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "clc.h"
+
+#define TM_AUTOALPHA 1
+#define MENU_MIRANDAMENU 0xFFFF1234
+
+static HMODULE hUserDll;
+static HIMAGELIST himlMirandaIcon;
+static HANDLE hContactDraggingEvent, hContactDroppedEvent, hContactDragStopEvent;
+static int transparentFocus = 1;
+UINT uMsgProcessProfile;
+
+void LoadCluiServices();
+
+BOOL(WINAPI * MySetLayeredWindowAttributes) (HWND, COLORREF, BYTE, DWORD);
+BOOL(WINAPI * MyAnimateWindow) (HWND hWnd, DWORD dwTime, DWORD dwFlags);
+
+typedef struct {
+ int showsbar;
+ int showgrip;
+ int transparent;
+ int alpha;
+} CluiOpts;
+static CluiOpts cluiopt = {0};
+
+void fnLoadCluiGlobalOpts() {
+ cluiopt.showsbar = DBGetContactSettingByte(NULL, "CLUI", "ShowSBar", 1);
+ cluiopt.showgrip = DBGetContactSettingByte(NULL, "CLUI", "ShowGrip", 1);
+ cluiopt.transparent = DBGetContactSettingByte(NULL,"CList","Transparent",SETTING_TRANSPARENT_DEFAULT);
+ cluiopt.alpha = DBGetContactSettingByte(NULL, "CList", "Alpha", SETTING_ALPHA_DEFAULT);
+}
+
+static int CluiModulesLoaded(WPARAM wParam, LPARAM lParam)
+{
+ MENUITEMINFO mii;
+ ZeroMemory(&mii, sizeof(mii));
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ mii.fMask = MIIM_SUBMENU;
+ mii.hSubMenu = (HMENU) CallService(MS_CLIST_MENUGETMAIN, 0, 0);
+ SetMenuItemInfo(cli.hMenuMain, 0, TRUE, &mii);
+ mii.hSubMenu = (HMENU) CallService(MS_CLIST_MENUGETSTATUS, 0, 0);
+ SetMenuItemInfo(cli.hMenuMain, 1, TRUE, &mii);
+ return 0;
+}
+
+// Restore protocols to the last global status.
+// Used to reconnect on restore after standby.
+static void RestoreMode(HWND hwnd)
+{
+ int nStatus = DBGetContactSettingWord(NULL, "CList", "Status", ID_STATUS_OFFLINE);
+ if (nStatus != ID_STATUS_OFFLINE)
+ PostMessage(hwnd&&IsWindow(hwnd)?hwnd:cli.hwndContactList, WM_COMMAND, nStatus, 0);
+}
+
+// Disconnect all protocols.
+// Happens on shutdown and standby.
+static void DisconnectAll()
+{
+ PROTOCOLDESCRIPTOR **ppProtoDesc;
+ int nProtoCount;
+ int nProto;
+
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM) & nProtoCount, (LPARAM) & ppProtoDesc);
+ for (nProto = 0; nProto < nProtoCount; nProto++) {
+ if (ppProtoDesc[nProto]->type == PROTOTYPE_PROTOCOL)
+ CallProtoService(ppProtoDesc[nProto]->szName, PS_SETSTATUS, ID_STATUS_OFFLINE, 0);
+ }
+}
+
+static int CluiIconsChanged(WPARAM wParam, LPARAM lParam)
+{
+ ImageList_ReplaceIcon(himlMirandaIcon, 0, LoadSkinnedIcon(SKINICON_OTHER_MIRANDA));
+ DrawMenuBar(cli.hwndContactList);
+ return 0;
+}
+
+static HANDLE hRenameMenuItem;
+
+static int MenuItem_PreBuild(WPARAM wParam, LPARAM lParam)
+{
+ TCHAR cls[128];
+ HANDLE hItem;
+ HWND hwndClist = GetFocus();
+ CLISTMENUITEM mi;
+
+ ZeroMemory(&mi, sizeof(mi));
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIM_FLAGS;
+ GetClassName(hwndClist, cls, SIZEOF(cls));
+ hwndClist = (!lstrcmp(CLISTCONTROL_CLASS, cls)) ? hwndClist : cli.hwndContactList;
+ hItem = (HANDLE) SendMessage(hwndClist, CLM_GETSELECTION, 0, 0);
+ if (!hItem) {
+ mi.flags = CMIM_FLAGS | CMIF_HIDDEN;
+ }
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) hRenameMenuItem, (LPARAM) & mi);
+ return 0;
+}
+
+static int MenuItem_RenameContact(WPARAM wParam, LPARAM lParam)
+{
+ TCHAR cls[128];
+ HANDLE hItem;
+ HWND hwndClist = GetFocus();
+ GetClassName(hwndClist, cls, SIZEOF(cls));
+ // worst case scenario, the rename is sent to the main contact list
+ hwndClist = (!lstrcmp(CLISTCONTROL_CLASS, cls)) ? hwndClist : cli.hwndContactList;
+ hItem = (HANDLE) SendMessage(hwndClist, CLM_GETSELECTION, 0, 0);
+ if (hItem) {
+ SetFocus(hwndClist);
+ SendMessage(hwndClist, CLM_EDITLABEL, (WPARAM) hItem, 0);
+ }
+ return 0;
+}
+
+static BOOL CALLBACK AskForConfirmationDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hWnd);
+ {
+ LOGFONT lf;
+ HFONT hFont;
+
+ hFont = (HFONT) SendDlgItemMessage(hWnd, IDYES, WM_GETFONT, 0, 0);
+ GetObject(hFont, sizeof(lf), &lf);
+ lf.lfWeight = FW_BOLD;
+ SendDlgItemMessage(hWnd, IDC_TOPLINE, WM_SETFONT, (WPARAM) CreateFontIndirect(&lf), 0);
+ }
+ {
+ TCHAR szFormat[256];
+ TCHAR szFinal[256];
+
+ GetDlgItemText(hWnd, IDC_TOPLINE, szFormat, SIZEOF(szFormat));
+ mir_sntprintf(szFinal, SIZEOF(szFinal), szFormat, cli.pfnGetContactDisplayName((HANDLE)lParam, 0));
+ SetDlgItemText(hWnd, IDC_TOPLINE, szFinal);
+ }
+ SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDYES:
+ if (IsDlgButtonChecked(hWnd, IDC_HIDE)) {
+ EndDialog(hWnd, IDC_HIDE);
+ break;
+ }
+ //fall through
+ case IDCANCEL:
+ case IDNO:
+ EndDialog(hWnd, LOWORD(wParam));
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ SendMessage(hWnd, WM_COMMAND, MAKEWPARAM(IDNO, BN_CLICKED), 0);
+ break;
+
+ case WM_DESTROY:
+ DeleteObject((HFONT) SendDlgItemMessage(hWnd, IDC_TOPLINE, WM_GETFONT, 0, 0));
+ break;
+ }
+
+ return FALSE;
+
+}
+
+static int MenuItem_DeleteContact(WPARAM wParam, LPARAM lParam)
+{
+ //see notes about deleting contacts on PF1_SERVERCLIST servers in m_protosvc.h
+ int action;
+
+ if (DBGetContactSettingByte(NULL, "CList", "ConfirmDelete", SETTING_CONFIRMDELETE_DEFAULT))
+ // Ask user for confirmation, and if the contact should be archived (hidden, not deleted)
+ action = DialogBoxParam(GetModuleHandle(0), MAKEINTRESOURCE(IDD_DELETECONTACT), (HWND) lParam, AskForConfirmationDlgProc, wParam);
+ else
+ action = IDYES;
+
+ switch (action) {
+
+ // Delete contact
+ case IDYES:
+ {
+ char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (szProto != NULL) {
+ // Check if protocol uses server side lists
+ DWORD caps;
+
+ caps = (DWORD) CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0);
+ if (caps & PF1_SERVERCLIST) {
+ int status;
+
+ status = CallProtoService(szProto, PS_GETSTATUS, 0, 0);
+ if (status == ID_STATUS_OFFLINE || (status >= ID_STATUS_CONNECTING && status < ID_STATUS_CONNECTING + MAX_CONNECT_RETRIES)) {
+ // Set a flag so we remember to delete the contact when the protocol goes online the next time
+ DBWriteContactSettingByte((HANDLE) wParam, "CList", "Delete", 1);
+ MessageBox( NULL,
+ TranslateT("This contact is on an instant messaging system which stores its contact list on a central server. The contact will be removed from the server and from your contact list when you next connect to that network."),
+ TranslateT("Delete Contact"), MB_OK);
+ return 0;
+ } } }
+
+ CallService(MS_DB_CONTACT_DELETE, wParam, 0);
+ }
+ break;
+
+ // Archive contact
+ case IDC_HIDE:
+ DBWriteContactSettingByte((HANDLE) wParam, "CList", "Hidden", 1);
+ break;
+ }
+
+ return 0;
+}
+
+static int MenuItem_AddContactToList(WPARAM wParam, LPARAM lParam)
+{
+ ADDCONTACTSTRUCT acs = { 0 };
+
+ acs.handle = (HANDLE) wParam;
+ acs.handleType = HANDLE_CONTACT;
+ acs.szProto = "";
+
+ CallService(MS_ADDCONTACT_SHOW, (WPARAM) NULL, (LPARAM) & acs);
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// this is the smalles available window procedure
+
+#ifndef CS_DROPSHADOW
+#define CS_DROPSHADOW 0x00020000
+#endif
+
+LRESULT CALLBACK ContactListWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT result;
+ MSG m;
+ m.hwnd=hwnd;
+ m.message=msg;
+ m.wParam=wParam;
+ m.lParam=lParam;
+ if ( cli.pfnDocking_ProcessWindowMessage(( WPARAM )&m, ( LPARAM )&result ))
+ return result;
+ if ( cli.pfnTrayIconProcessMessage(( WPARAM )&m, ( LPARAM )&result ))
+ return result;
+ if ( cli.pfnHotkeysProcessMessage(( WPARAM )&m, ( LPARAM )&result ))
+ return result;
+
+ return cli.pfnContactListWndProc( hwnd, msg, wParam, lParam );
+}
+
+int LoadCLUIModule(void)
+{
+ WNDCLASS wndclass;
+ DBVARIANT dbv;
+ TCHAR titleText[256];
+
+ uMsgProcessProfile = RegisterWindowMessageA("Miranda::ProcessProfile");
+ cli.pfnLoadCluiGlobalOpts();
+ hUserDll = LoadLibraryA("user32.dll");
+ if (hUserDll) {
+ MySetLayeredWindowAttributes = (BOOL(WINAPI *) (HWND, COLORREF, BYTE, DWORD)) GetProcAddress(hUserDll, "SetLayeredWindowAttributes");
+ MyAnimateWindow = (BOOL(WINAPI *) (HWND, DWORD, DWORD)) GetProcAddress(hUserDll, "AnimateWindow");
+ }
+ HookEvent(ME_SYSTEM_MODULESLOADED, CluiModulesLoaded);
+ HookEvent(ME_SKIN_ICONSCHANGED, CluiIconsChanged);
+
+ hContactDraggingEvent = CreateHookableEvent(ME_CLUI_CONTACTDRAGGING);
+ hContactDroppedEvent = CreateHookableEvent(ME_CLUI_CONTACTDROPPED);
+ hContactDragStopEvent = CreateHookableEvent(ME_CLUI_CONTACTDRAGSTOP);
+ LoadCluiServices();
+
+ wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_GLOBALCLASS;
+ wndclass.lpfnWndProc = cli.pfnContactListControlWndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = sizeof(void *);
+ wndclass.hInstance = cli.hInst;
+ wndclass.hIcon = NULL;
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.hbrBackground = NULL;
+ wndclass.lpszMenuName = NULL;
+ wndclass.lpszClassName = CLISTCONTROL_CLASS;
+ RegisterClass(&wndclass);
+
+ wndclass.style = CS_HREDRAW | CS_VREDRAW | (IsWinVerXPPlus() && DBGetContactSettingByte(NULL, "CList", "WindowShadow", 0) == 1 ? CS_DROPSHADOW : 0);
+ wndclass.lpfnWndProc = ContactListWndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = 0;
+ wndclass.hInstance = cli.hInst;
+ wndclass.hIcon = LoadSkinnedIcon(SKINICON_OTHER_MIRANDA);
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
+ wndclass.lpszMenuName = MAKEINTRESOURCE(IDR_CLISTMENU);
+ wndclass.lpszClassName = _T(MIRANDACLASS);
+ RegisterClass(&wndclass);
+
+ if (DBGetContactSettingTString(NULL, "CList", "TitleText", &dbv))
+ lstrcpyn(titleText, _T(MIRANDANAME), SIZEOF( titleText ));
+ else {
+ lstrcpyn(titleText, dbv.ptszVal, SIZEOF(titleText));
+ DBFreeVariant(&dbv);
+ }
+
+ cli.hwndContactList = CreateWindowEx(
+ DBGetContactSettingByte(NULL, "CList", "ToolWindow", SETTING_TOOLWINDOW_DEFAULT) ? WS_EX_TOOLWINDOW : 0,
+ _T(MIRANDACLASS),
+ titleText,
+ (DBGetContactSettingByte(NULL, "CLUI", "ShowCaption", SETTING_SHOWCAPTION_DEFAULT) ?
+ WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX : 0) | WS_POPUPWINDOW | WS_THICKFRAME | WS_CLIPCHILDREN,
+ (int) DBGetContactSettingDword(NULL, "CList", "x", 700),
+ (int) DBGetContactSettingDword(NULL, "CList", "y", 221),
+ (int) DBGetContactSettingDword(NULL, "CList", "Width", 108),
+ (int) DBGetContactSettingDword(NULL, "CList", "Height", 310),
+ NULL, NULL, cli.hInst, NULL);
+
+ if (DBGetContactSettingByte(NULL, "CList", "OnDesktop", 0)) {
+ HWND hProgMan = FindWindowA("Progman", NULL);
+ if (IsWindow(hProgMan))
+ SetParent(cli.hwndContactList, hProgMan);
+ }
+
+ cli.pfnOnCreateClc();
+
+ {
+ int state = DBGetContactSettingByte(NULL, "CList", "State", SETTING_STATE_NORMAL);
+ cli.hMenuMain = GetMenu(cli.hwndContactList);
+ if (!DBGetContactSettingByte(NULL, "CLUI", "ShowMainMenu", SETTING_SHOWMAINMENU_DEFAULT))
+ SetMenu(cli.hwndContactList, NULL);
+ if (state == SETTING_STATE_NORMAL)
+ ShowWindow(cli.hwndContactList, SW_SHOW);
+ else if (state == SETTING_STATE_MINIMIZED)
+ ShowWindow(cli.hwndContactList, SW_SHOWMINIMIZED);
+ SetWindowPos(cli.hwndContactList, DBGetContactSettingByte(NULL, "CList", "OnTop", SETTING_ONTOP_DEFAULT) ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
+ }
+ {
+ CLISTMENUITEM mi;
+ ZeroMemory(&mi, sizeof(mi));
+ mi.cbSize = sizeof(mi);
+
+ CreateServiceFunction("CList/DeleteContactCommand", MenuItem_DeleteContact);
+ mi.position = 2000070000;
+ mi.flags = 0;
+ mi.hIcon = LoadIcon(cli.hInst, MAKEINTRESOURCE(IDI_DELETE));
+ mi.pszContactOwner = NULL; //on every contact
+ mi.pszName = Translate("De&lete");
+ mi.pszService = "CList/DeleteContactCommand";
+ CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM) & mi);
+
+ CreateServiceFunction("CList/RenameContactCommand", MenuItem_RenameContact);
+ mi.position = 2000050000;
+ mi.flags = 0;
+ mi.hIcon = LoadIcon(cli.hInst, MAKEINTRESOURCE(IDI_RENAME));
+ mi.pszContactOwner = NULL; //on every contact
+ mi.pszName = Translate("&Rename");
+ mi.pszService = "CList/RenameContactCommand";
+ hRenameMenuItem = (HANDLE) CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM) & mi);
+ HookEvent(ME_CLIST_PREBUILDCONTACTMENU, MenuItem_PreBuild);
+
+ CreateServiceFunction("CList/AddToListContactCommand", MenuItem_AddContactToList);
+ mi.position = -2050000000;
+ mi.flags = CMIF_NOTONLIST;
+ mi.hIcon = LoadIcon(cli.hInst, MAKEINTRESOURCE(IDI_ADDCONTACT));
+ mi.pszName = Translate("&Add permanently to list");
+ mi.pszService = "CList/AddToListContactCommand";
+ CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM) & mi);
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// default contact list window procedure
+
+void fnDrawMenuItem(DRAWITEMSTRUCT *dis, HICON hIcon, HICON eventIcon)
+{
+ if (!IsWinVerXPPlus()) {
+ FillRect(dis->hDC, &dis->rcItem, GetSysColorBrush(COLOR_MENU));
+ if (dis->itemState & ODS_HOTLIGHT)
+ DrawEdge(dis->hDC, &dis->rcItem, BDR_RAISEDINNER, BF_RECT);
+ else if (dis->itemState & ODS_SELECTED)
+ DrawEdge(dis->hDC, &dis->rcItem, BDR_SUNKENOUTER, BF_RECT);
+ if (eventIcon != 0) {
+ DrawState(dis->hDC, NULL, NULL, (LPARAM) eventIcon, 0, 2, (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ DrawState(dis->hDC, NULL, NULL, (LPARAM) hIcon, 0, 4 + g_IconWidth, (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ }
+ else DrawState(dis->hDC, NULL, NULL, (LPARAM) hIcon, 0, (dis->rcItem.right + dis->rcItem.left - g_IconWidth) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ }
+ else {
+ HBRUSH hBr;
+ BOOL bfm = FALSE;
+ SystemParametersInfo(SPI_GETFLATMENU, 0, &bfm, 0);
+ if (bfm) {
+ /* flat menus: fill with COLOR_MENUHILIGHT and outline with COLOR_HIGHLIGHT, otherwise use COLOR_MENUBAR */
+ if (dis->itemState & ODS_SELECTED || dis->itemState & ODS_HOTLIGHT) {
+ /* selected or hot lighted, no difference */
+ hBr = GetSysColorBrush(COLOR_MENUHILIGHT);
+ FillRect(dis->hDC, &dis->rcItem, hBr);
+ DeleteObject(hBr);
+ /* draw the frame */
+ hBr = GetSysColorBrush(COLOR_HIGHLIGHT);
+ FrameRect(dis->hDC, &dis->rcItem, hBr);
+ DeleteObject(hBr);
+ } else {
+ /* flush the DC with the menu bar colour (only supported on XP) and then draw the icon */
+ hBr = GetSysColorBrush(COLOR_MENUBAR);
+ FillRect(dis->hDC, &dis->rcItem, hBr);
+ DeleteObject(hBr);
+ } //if
+ /* draw the icon */
+ if (eventIcon != 0) {
+ DrawState(dis->hDC, NULL, NULL, (LPARAM) eventIcon, 0, 2, (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ DrawState(dis->hDC, NULL, NULL, (LPARAM) hIcon, 0, 4 + g_IconWidth, (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ }
+ else DrawState(dis->hDC, NULL, NULL, (LPARAM) hIcon, 0, (dis->rcItem.right + dis->rcItem.left - g_IconWidth) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ }
+ else {
+ /* non-flat menus, flush the DC with a normal menu colour */
+ FillRect(dis->hDC, &dis->rcItem, GetSysColorBrush(COLOR_MENU));
+ if (dis->itemState & ODS_HOTLIGHT)
+ DrawEdge(dis->hDC, &dis->rcItem, BDR_RAISEDINNER, BF_RECT);
+ else if (dis->itemState & ODS_SELECTED)
+ DrawEdge(dis->hDC, &dis->rcItem, BDR_SUNKENOUTER, BF_RECT);
+
+ if (eventIcon != 0) {
+ DrawState(dis->hDC, NULL, NULL, (LPARAM) eventIcon, 0, 2, (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ DrawState(dis->hDC, NULL, NULL, (LPARAM) hIcon, 0, 4 + g_IconWidth, (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ }
+ else DrawState(dis->hDC, NULL, NULL, (LPARAM) hIcon, 0, (dis->rcItem.right + dis->rcItem.left - g_IconWidth) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ } }
+
+ DestroyIcon(hIcon);
+ return;
+}
+
+#define M_CREATECLC (WM_USER+1)
+LRESULT CALLBACK fnContactListWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (msg == uMsgProcessProfile) {
+ char profile[MAX_PATH];
+ int rc;
+ // wParam = (ATOM)hProfileAtom, lParam = 0
+ if (GlobalGetAtomNameA((ATOM) wParam, profile, SIZEOF(profile))) {
+ char path[MAX_PATH];
+ char file[MAX_PATH];
+ char p[MAX_PATH];
+ CallService(MS_DB_GETPROFILEPATH, SIZEOF(path), (LPARAM) & path);
+ CallService(MS_DB_GETPROFILENAME, SIZEOF(file), (LPARAM) & file);
+ mir_snprintf(p, SIZEOF(p), "%s\\%s", path, file);
+ rc = lstrcmpiA(profile, p) == 0;
+ ReplyMessage(rc);
+ if (rc) {
+ ShowWindow(hwnd, SW_SHOW);
+ SetForegroundWindow(hwnd);
+ SetFocus(hwnd);
+ }
+ }
+ return 0;
+ }
+
+ switch (msg) {
+ case WM_NCCREATE:
+ {
+ MENUITEMINFO mii;
+ ZeroMemory(&mii, sizeof(mii));
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ mii.fMask = MIIM_TYPE | MIIM_DATA;
+ himlMirandaIcon = ImageList_Create(g_IconWidth, g_IconHeight, ILC_COLOR32 | ILC_MASK, 1, 1);
+ ImageList_AddIcon(himlMirandaIcon, LoadSkinnedIcon(SKINICON_OTHER_MIRANDA));
+ mii.dwItemData = MENU_MIRANDAMENU;
+ mii.fType = MFT_OWNERDRAW;
+ mii.dwTypeData = NULL;
+ SetMenuItemInfo(GetMenu(hwnd), 0, TRUE, &mii);
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+ case WM_CREATE:
+ CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) GetMenu(hwnd), 0);
+ DrawMenuBar(hwnd);
+
+ //create the status wnd
+ {
+ int flags = WS_CHILD | CCS_BOTTOM;
+ flags |= cluiopt.showsbar ? WS_VISIBLE : 0;
+ flags |= cluiopt.showgrip ? SBARS_SIZEGRIP : 0;
+ cli.hwndStatus = CreateWindow(STATUSCLASSNAME, NULL, flags, 0, 0, 0, 0, hwnd, NULL, cli.hInst, NULL);
+ }
+ cli.pfnCluiProtocolStatusChanged(0, 0);
+
+ //delay creation of CLC so that it can get the status icons right the first time (needs protocol modules loaded)
+ PostMessage(hwnd, M_CREATECLC, 0, 0);
+
+ if (cluiopt.transparent) {
+ SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
+ if (MySetLayeredWindowAttributes)
+ MySetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), (BYTE) cluiopt.alpha, LWA_ALPHA);
+ }
+ transparentFocus = 1;
+
+ #ifndef _DEBUG
+ // Miranda is starting up! Restore last status mode.
+ // This is not done in debug builds because frequent
+ // reconnections will get you banned from the servers.
+ RestoreMode(hwnd);
+ #endif
+
+ return FALSE;
+
+ case M_CREATECLC:
+ cli.hwndContactTree = CreateWindow( CLISTCONTROL_CLASS, _T(""),
+ WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN
+ | CLS_CONTACTLIST
+ | (DBGetContactSettingByte(NULL, "CList", "UseGroups", SETTING_USEGROUPS_DEFAULT) ? CLS_USEGROUPS : 0)
+ | (DBGetContactSettingByte(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT) ? CLS_HIDEOFFLINE : 0)
+ | (DBGetContactSettingByte(NULL, "CList", "HideEmptyGroups", SETTING_HIDEEMPTYGROUPS_DEFAULT) ?
+ CLS_HIDEEMPTYGROUPS : 0), 0, 0, 0, 0, hwnd, NULL, cli.hInst, NULL);
+ SendMessage(hwnd, WM_SIZE, 0, 0);
+ break;
+
+ // Power management
+ case WM_POWERBROADCAST:
+ switch ((DWORD) wParam) {
+ case PBT_APMSUSPEND:
+ // Computer is suspending, disconnect all protocols
+ DisconnectAll();
+ break;
+
+ case PBT_APMRESUMESUSPEND:
+ // Computer is resuming, restore all protocols
+ RestoreMode(NULL);
+ break;
+ }
+ break;
+
+ case WM_SYSCOLORCHANGE:
+ SendMessage(cli.hwndContactTree, msg, wParam, lParam);
+ SendMessage(cli.hwndStatus, msg, wParam, lParam);
+ // XXX: only works with 4.71 with 95, IE4.
+ SendMessage(cli.hwndStatus, SB_SETBKCOLOR, 0, GetSysColor(COLOR_3DFACE));
+ break;
+
+ case WM_SIZE:
+ if (IsZoomed(hwnd))
+ ShowWindow(hwnd, SW_SHOWNORMAL);
+ {
+ RECT rect, rcStatus;
+ GetClientRect(hwnd, &rect);
+ if (cluiopt.showsbar) {
+ SetWindowPos(cli.hwndStatus, NULL, 0, rect.bottom - 20, rect.right - rect.left, 20, SWP_NOZORDER);
+ GetWindowRect(cli.hwndStatus, &rcStatus);
+ cli.pfnCluiProtocolStatusChanged(0, 0);
+ }
+ else
+ rcStatus.top = rcStatus.bottom = 0;
+ SetWindowPos(cli.hwndContactTree, NULL, 0, 0, rect.right, rect.bottom - (rcStatus.bottom - rcStatus.top), SWP_NOZORDER);
+ }
+ if (wParam == SIZE_MINIMIZED) {
+ if (DBGetContactSettingByte(NULL, "CList", "Min2Tray", SETTING_MIN2TRAY_DEFAULT)) {
+ ShowWindow(hwnd, SW_HIDE);
+ DBWriteContactSettingByte(NULL, "CList", "State", SETTING_STATE_HIDDEN);
+ }
+ else
+ DBWriteContactSettingByte(NULL, "CList", "State", SETTING_STATE_MINIMIZED);
+ }
+ // drop thru
+ case WM_MOVE:
+ if (!IsIconic(hwnd)) {
+ RECT rc;
+ GetWindowRect(hwnd, &rc);
+
+ if (!CallService(MS_CLIST_DOCKINGISDOCKED, 0, 0)) { //if docked, dont remember pos (except for width)
+ DBWriteContactSettingDword(NULL, "CList", "Height", (DWORD) (rc.bottom - rc.top));
+ DBWriteContactSettingDword(NULL, "CList", "x", (DWORD) rc.left);
+ DBWriteContactSettingDword(NULL, "CList", "y", (DWORD) rc.top);
+ }
+ DBWriteContactSettingDword(NULL, "CList", "Width", (DWORD) (rc.right - rc.left));
+ }
+ return FALSE;
+
+ case WM_SETFOCUS:
+ SetFocus(cli.hwndContactTree);
+ return 0;
+
+ case WM_ACTIVATE:
+ if (wParam == WA_INACTIVE) {
+ if ((HWND) wParam != hwnd)
+ if (cluiopt.transparent)
+ if (transparentFocus)
+ SetTimer(hwnd, TM_AUTOALPHA, 250, NULL);
+ }
+ else {
+ if (cluiopt.transparent) {
+ KillTimer(hwnd, TM_AUTOALPHA);
+ if (MySetLayeredWindowAttributes)
+ MySetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), (BYTE) cluiopt.alpha, LWA_ALPHA);
+ transparentFocus = 1;
+ }
+ }
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+
+ case WM_SETCURSOR:
+ if(cluiopt.transparent) {
+ if (!transparentFocus && GetForegroundWindow()!=hwnd && MySetLayeredWindowAttributes) {
+ MySetLayeredWindowAttributes(hwnd, RGB(0,0,0), (BYTE)cluiopt.alpha, LWA_ALPHA);
+ transparentFocus=1;
+ SetTimer(hwnd, TM_AUTOALPHA,250,NULL);
+ }
+ }
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+
+ case WM_NCHITTEST:
+ {
+ LRESULT result;
+ result = DefWindowProc(hwnd, WM_NCHITTEST, wParam, lParam);
+ if (result == HTSIZE || result == HTTOP || result == HTTOPLEFT || result == HTTOPRIGHT ||
+ result == HTBOTTOM || result == HTBOTTOMRIGHT || result == HTBOTTOMLEFT)
+ if (DBGetContactSettingByte(NULL, "CLUI", "AutoSize", 0))
+ return HTCLIENT;
+ return result;
+ }
+
+ case WM_TIMER:
+ if ((int) wParam == TM_AUTOALPHA) {
+ int inwnd;
+
+ if (GetForegroundWindow() == hwnd) {
+ KillTimer(hwnd, TM_AUTOALPHA);
+ inwnd = 1;
+ }
+ else {
+ POINT pt;
+ HWND hwndPt;
+ pt.x = (short) LOWORD(GetMessagePos());
+ pt.y = (short) HIWORD(GetMessagePos());
+ hwndPt = WindowFromPoint(pt);
+ inwnd = (hwndPt == hwnd || GetParent(hwndPt) == hwnd);
+ }
+ if (inwnd != transparentFocus && MySetLayeredWindowAttributes) { //change
+ transparentFocus = inwnd;
+ if (transparentFocus)
+ MySetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), (BYTE) cluiopt.alpha, LWA_ALPHA);
+ else
+ MySetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), (BYTE) DBGetContactSettingByte(NULL, "CList", "AutoAlpha", SETTING_AUTOALPHA_DEFAULT), LWA_ALPHA);
+ }
+ if (!transparentFocus)
+ KillTimer(hwnd, TM_AUTOALPHA);
+ }
+ return TRUE;
+
+ case WM_SHOWWINDOW:
+ {
+ static int noRecurse = 0;
+ if (lParam)
+ break;
+ if (noRecurse)
+ break;
+ if (!DBGetContactSettingByte(NULL, "CLUI", "FadeInOut", 0) || !IsWinVer2000Plus())
+ break;
+ if (GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED) {
+ DWORD thisTick, startTick;
+ int sourceAlpha, destAlpha;
+ if (wParam) {
+ sourceAlpha = 0;
+ destAlpha = (BYTE) cluiopt.alpha;
+ MySetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), 0, LWA_ALPHA);
+ noRecurse = 1;
+ ShowWindow(hwnd, SW_SHOW);
+ noRecurse = 0;
+ }
+ else {
+ sourceAlpha = (BYTE) cluiopt.alpha;
+ destAlpha = 0;
+ }
+ for (startTick = GetTickCount();;) {
+ thisTick = GetTickCount();
+ if (thisTick >= startTick + 200)
+ break;
+ MySetLayeredWindowAttributes(hwnd, RGB(0, 0, 0),
+ (BYTE) (sourceAlpha + (destAlpha - sourceAlpha) * (int) (thisTick - startTick) / 200), LWA_ALPHA);
+ }
+ MySetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), (BYTE) destAlpha, LWA_ALPHA);
+ }
+ else {
+ if (wParam)
+ SetForegroundWindow(hwnd);
+ MyAnimateWindow(hwnd, 200, AW_BLEND | (wParam ? 0 : AW_HIDE));
+ SetWindowPos(cli.hwndContactTree, 0, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
+ }
+ break;
+ }
+ case WM_MENURBUTTONUP: /* this API is so badly documented at MSDN!! */
+ {
+ UINT id = 0;
+
+ id = GetMenuItemID((HMENU) lParam, LOWORD(wParam)); /* LOWORD(wParam) contains the menu pos in its parent menu */
+ if (id != (-1))
+ SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(id, 0), 0);
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+ case WM_SYSCOMMAND:
+ if (wParam == SC_MAXIMIZE)
+ return 0;
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+
+ case WM_COMMAND:
+ if (CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_MAINMENU), (LPARAM) (HANDLE) NULL))
+ break;
+ switch (LOWORD(wParam)) {
+ case ID_TRAY_EXIT:
+ case ID_ICQ_EXIT:
+ if (CallService(MS_SYSTEM_OKTOEXIT, 0, 0))
+ DestroyWindow(hwnd);
+ break;
+ case ID_TRAY_HIDE:
+ CallService(MS_CLIST_SHOWHIDE, 0, 0);
+ break;
+ case POPUP_NEWGROUP:
+ SendMessage(cli.hwndContactTree, CLM_SETHIDEEMPTYGROUPS, 0, 0);
+ CallService(MS_CLIST_GROUPCREATE, 0, 0);
+ break;
+ case POPUP_HIDEOFFLINE:
+ CallService(MS_CLIST_SETHIDEOFFLINE, (WPARAM) (-1), 0);
+ break;
+ case POPUP_HIDEOFFLINEROOT:
+ SendMessage(cli.hwndContactTree, CLM_SETHIDEOFFLINEROOT, !SendMessage(cli.hwndContactTree, CLM_GETHIDEOFFLINEROOT, 0, 0), 0);
+ break;
+ case POPUP_HIDEEMPTYGROUPS:
+ {
+ int newVal = !(GetWindowLong(cli.hwndContactTree, GWL_STYLE) & CLS_HIDEEMPTYGROUPS);
+ DBWriteContactSettingByte(NULL, "CList", "HideEmptyGroups", (BYTE) newVal);
+ SendMessage(cli.hwndContactTree, CLM_SETHIDEEMPTYGROUPS, newVal, 0);
+ break;
+ }
+ case POPUP_DISABLEGROUPS:
+ {
+ int newVal = !(GetWindowLong(cli.hwndContactTree, GWL_STYLE) & CLS_USEGROUPS);
+ DBWriteContactSettingByte(NULL, "CList", "UseGroups", (BYTE) newVal);
+ SendMessage(cli.hwndContactTree, CLM_SETUSEGROUPS, newVal, 0);
+ break;
+ }
+ case POPUP_HIDEMIRANDA:
+ {
+ CallService(MS_CLIST_SHOWHIDE, 0, 0);
+ break;
+ } }
+ return FALSE;
+ case WM_KEYDOWN:
+ CallService(MS_CLIST_MENUPROCESSHOTKEY, wParam, MPCF_MAINMENU | MPCF_CONTACTMENU);
+ break;
+
+ case WM_GETMINMAXINFO:
+ DefWindowProc(hwnd, msg, wParam, lParam);
+ ((LPMINMAXINFO) lParam)->ptMinTrackSize.x = 16 + GetSystemMetrics(SM_CXHTHUMB);
+ ((LPMINMAXINFO) lParam)->ptMinTrackSize.y = 16;
+ return 0;
+
+ case WM_DISPLAYCHANGE:
+ SendMessage(cli.hwndContactTree, WM_SIZE, 0, 0); //forces it to send a cln_listsizechanged
+ break;
+
+ //MSG FROM CHILD CONTROL
+ case WM_NOTIFY:
+ if (((LPNMHDR) lParam)->hwndFrom == cli.hwndContactTree) {
+ switch (((LPNMHDR) lParam)->code) {
+ case CLN_EXPANDED:
+ {
+ NMCLISTCONTROL *nmc = (NMCLISTCONTROL *) lParam;
+ CallService(MS_CLIST_GROUPSETEXPANDED, (WPARAM) nmc->hItem, nmc->action);
+ return FALSE;
+ }
+ case CLN_DRAGGING:
+ {
+ NMCLISTCONTROL *nmc = (NMCLISTCONTROL *) lParam;
+ ClientToScreen(hwnd, &nmc->pt);
+ if (!(nmc->flags & CLNF_ISGROUP))
+ if (NotifyEventHooks(hContactDraggingEvent, (WPARAM) nmc->hItem, MAKELPARAM(nmc->pt.x, nmc->pt.y))) {
+ SetCursor(LoadCursor(cli.hInst, MAKEINTRESOURCE(IDC_DROPUSER)));
+ return TRUE;
+ }
+ break;
+ }
+ case CLN_DRAGSTOP:
+ {
+ NMCLISTCONTROL *nmc = (NMCLISTCONTROL *) lParam;
+ if (!(nmc->flags & CLNF_ISGROUP))
+ NotifyEventHooks(hContactDragStopEvent, (WPARAM) nmc->hItem, 0);
+ break;
+ }
+ case CLN_DROPPED:
+ {
+ NMCLISTCONTROL *nmc = (NMCLISTCONTROL *) lParam;
+ ClientToScreen(hwnd, &nmc->pt);
+ if (!(nmc->flags & CLNF_ISGROUP))
+ if (NotifyEventHooks(hContactDroppedEvent, (WPARAM) nmc->hItem, MAKELPARAM(nmc->pt.x, nmc->pt.y))) {
+ SetCursor(LoadCursor(cli.hInst, MAKEINTRESOURCE(IDC_DROPUSER)));
+ return TRUE;
+ }
+ break;
+ }
+ case NM_KEYDOWN:
+ {
+ NMKEY *nmkey = (NMKEY *) lParam;
+ return CallService(MS_CLIST_MENUPROCESSHOTKEY, nmkey->nVKey, MPCF_MAINMENU | MPCF_CONTACTMENU);
+ }
+ case CLN_LISTSIZECHANGE:
+ {
+ NMCLISTCONTROL *nmc = (NMCLISTCONTROL *) lParam;
+ RECT rcWindow, rcTree, rcWorkArea;
+ int maxHeight, newHeight;
+
+ if (!DBGetContactSettingByte(NULL, "CLUI", "AutoSize", 0))
+ break;
+ if (CallService(MS_CLIST_DOCKINGISDOCKED, 0, 0))
+ break;
+ maxHeight = DBGetContactSettingByte(NULL, "CLUI", "MaxSizeHeight", 75);
+ GetWindowRect(hwnd, &rcWindow);
+ GetWindowRect(cli.hwndContactTree, &rcTree);
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWorkArea, FALSE);
+ newHeight = max(nmc->pt.y, 9) + 1 + (rcWindow.bottom - rcWindow.top) - (rcTree.bottom - rcTree.top);
+ if (newHeight > (rcWorkArea.bottom - rcWorkArea.top) * maxHeight / 100)
+ newHeight = (rcWorkArea.bottom - rcWorkArea.top) * maxHeight / 100;
+ if (DBGetContactSettingByte(NULL, "CLUI", "AutoSizeUpward", 0)) {
+ rcWindow.top = rcWindow.bottom - newHeight;
+ if (rcWindow.top < rcWorkArea.top)
+ rcWindow.top = rcWorkArea.top;
+ }
+ else {
+ rcWindow.bottom = rcWindow.top + newHeight;
+ if (rcWindow.bottom > rcWorkArea.bottom)
+ rcWindow.bottom = rcWorkArea.bottom;
+ }
+ SetWindowPos(hwnd, 0, rcWindow.left, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top,
+ SWP_NOZORDER | SWP_NOACTIVATE);
+ break;
+ }
+ case NM_CLICK:
+ {
+ NMCLISTCONTROL *nm = (NMCLISTCONTROL *) lParam;
+ DWORD hitFlags;
+
+ if (SendMessage(cli.hwndContactTree, CLM_HITTEST, (WPARAM) & hitFlags, MAKELPARAM(nm->pt.x, nm->pt.y)))
+ break;
+ if ((hitFlags & (CLCHT_NOWHERE | CLCHT_INLEFTMARGIN | CLCHT_BELOWITEMS)) == 0)
+ break;
+ if (DBGetContactSettingByte(NULL, "CLUI", "ClientAreaDrag", SETTING_CLIENTDRAG_DEFAULT)) {
+ POINT pt;
+ pt = nm->pt;
+ ClientToScreen(cli.hwndContactTree, &pt);
+ return SendMessage(hwnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, MAKELPARAM(pt.x, pt.y));
+ }
+ break;
+ } }
+ }
+ else if (((LPNMHDR) lParam)->hwndFrom == cli.hwndStatus) {
+ if (((LPNMHDR) lParam)->code == NM_CLICK)
+ {
+ unsigned int nParts, nPanel;
+ NMMOUSE *nm = (NMMOUSE *) lParam;
+ HMENU hMenu;
+ RECT rc;
+ POINT pt;
+
+ hMenu = (HMENU) CallService(MS_CLIST_MENUGETSTATUS, 0, 0);
+ nParts = SendMessage(cli.hwndStatus, SB_GETPARTS, 0, 0);
+ if (nm->dwItemSpec == 0xFFFFFFFE) {
+ nPanel = nParts - 1;
+ SendMessage(cli.hwndStatus, SB_GETRECT, nPanel, (LPARAM) & rc);
+ if (nm->pt.x < rc.left)
+ return FALSE;
+ }
+ else nPanel = nm->dwItemSpec;
+
+ if (nParts > 1)
+ hMenu = GetSubMenu(hMenu, nPanel);
+ SendMessage(cli.hwndStatus, SB_GETRECT, nPanel, (LPARAM) & rc);
+ pt.x = rc.left;
+ pt.y = rc.top;
+ ClientToScreen(cli.hwndStatus, &pt);
+ TrackPopupMenu(hMenu, TPM_BOTTOMALIGN | TPM_LEFTALIGN, pt.x, pt.y, 0, hwnd, NULL);
+ } }
+ return FALSE;
+
+ case WM_CONTEXTMENU:
+ {
+ RECT rc;
+ POINT pt;
+
+ pt.x = (short) LOWORD(lParam);
+ pt.y = (short) HIWORD(lParam);
+ // x/y might be -1 if it was generated by a kb click
+ GetWindowRect(cli.hwndContactTree, &rc);
+ if (pt.x == -1 && pt.y == -1) {
+ // all this is done in screen-coords!
+ GetCursorPos(&pt);
+ // the mouse isnt near the window, so put it in the middle of the window
+ if (!PtInRect(&rc, pt)) {
+ pt.x = rc.left + (rc.right - rc.left) / 2;
+ pt.y = rc.top + (rc.bottom - rc.top) / 2;
+ }
+ }
+ if (PtInRect(&rc, pt)) {
+ HMENU hMenu;
+ hMenu = GetSubMenu(LoadMenu(cli.hInst, MAKEINTRESOURCE(IDR_CONTEXT)), 1);
+ CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) hMenu, 0);
+ CheckMenuItem(hMenu, POPUP_HIDEOFFLINE,
+ DBGetContactSettingByte(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT) ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu, POPUP_HIDEOFFLINEROOT, SendMessage(cli.hwndContactTree, CLM_GETHIDEOFFLINEROOT, 0, 0) ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu, POPUP_HIDEEMPTYGROUPS,
+ GetWindowLong(cli.hwndContactTree, GWL_STYLE) & CLS_HIDEEMPTYGROUPS ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu, POPUP_DISABLEGROUPS, GetWindowLong(cli.hwndContactTree, GWL_STYLE) & CLS_USEGROUPS ? MF_UNCHECKED : MF_CHECKED);
+ TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
+ DestroyMenu(hMenu);
+ return 0;
+ }
+ GetWindowRect(cli.hwndStatus, &rc);
+ if (PtInRect(&rc, pt)) {
+ HMENU hMenu;
+ if (DBGetContactSettingByte(NULL, "CLUI", "SBarRightClk", 0))
+ hMenu = (HMENU) CallService(MS_CLIST_MENUGETMAIN, 0, 0);
+ else
+ hMenu = (HMENU) CallService(MS_CLIST_MENUGETSTATUS, 0, 0);
+ TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
+ return 0;
+ } }
+ break;
+
+ case WM_MEASUREITEM:
+ if (((LPMEASUREITEMSTRUCT) lParam)->itemData == MENU_MIRANDAMENU) {
+ ((LPMEASUREITEMSTRUCT) lParam)->itemWidth = g_IconWidth * 4 / 3;
+ ((LPMEASUREITEMSTRUCT) lParam)->itemHeight = 0;
+ return TRUE;
+ }
+ return CallService(MS_CLIST_MENUMEASUREITEM, wParam, lParam);
+ case WM_DRAWITEM:
+ {
+ LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT) lParam;
+ if (dis->hwndItem == cli.hwndStatus) {
+ char *szProto = (char *) dis->itemData;
+ int status, x;
+ SIZE textSize;
+ BYTE showOpts = DBGetContactSettingByte(NULL, "CLUI", "SBarShow", 1);
+ status = CallProtoService(szProto, PS_GETSTATUS, 0, 0);
+ SetBkMode(dis->hDC, TRANSPARENT);
+ x = dis->rcItem.left;
+ if (showOpts & 1) {
+ HICON hIcon;
+ hIcon = LoadSkinnedProtoIcon(szProto, status);
+ DrawIconEx(dis->hDC, x, (dis->rcItem.top + dis->rcItem.bottom - g_IconHeight) >> 1, hIcon,
+ g_IconWidth, g_IconHeight, 0, NULL, DI_NORMAL);
+ x += g_IconWidth + 2;
+ }
+ else
+ x += 2;
+ if (showOpts & 2) {
+ char szName[64];
+ szName[0] = 0;
+ if (CallProtoService(szProto, PS_GETNAME, sizeof(szName), (LPARAM) szName)) {
+ strcpy(szName, szProto);
+ } //if
+ if (lstrlenA(szName) < SIZEOF(szName) - 1)
+ lstrcatA(szName, " ");
+ GetTextExtentPoint32A(dis->hDC, szName, lstrlenA(szName), &textSize);
+ TextOutA(dis->hDC, x, (dis->rcItem.top + dis->rcItem.bottom - textSize.cy) >> 1, szName, lstrlenA(szName));
+ x += textSize.cx;
+ }
+ if (showOpts & 4) {
+ char *szStatus = (char *) CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, status, 0);
+ if (!szStatus)
+ szStatus = "";
+ GetTextExtentPoint32A(dis->hDC, szStatus, lstrlenA(szStatus), &textSize);
+ TextOutA(dis->hDC, x, (dis->rcItem.top + dis->rcItem.bottom - textSize.cy) >> 1, szStatus, lstrlenA(szStatus));
+ }
+ }
+ else if (dis->CtlType == ODT_MENU) {
+ if (dis->itemData == MENU_MIRANDAMENU) {
+ HICON hIcon = ImageList_GetIcon(himlMirandaIcon, 0, ILD_NORMAL);
+ fnDrawMenuItem(dis, hIcon, NULL);
+ return TRUE;
+ }
+ return CallService(MS_CLIST_MENUDRAWITEM, wParam, lParam);
+ } }
+ return 0;
+
+ case WM_CLOSE:
+ if (DBGetContactSettingByte(NULL, "CList", "ToolWindow", SETTING_TOOLWINDOW_DEFAULT))
+ CallService(MS_CLIST_SHOWHIDE, 0, 0);
+ else
+ SendMessage(hwnd, WM_COMMAND, ID_ICQ_EXIT, 0);
+
+ return FALSE;
+ case WM_DESTROY:
+ if (!IsIconic(hwnd)) {
+ RECT rc;
+ GetWindowRect(hwnd, &rc);
+
+ if (!CallService(MS_CLIST_DOCKINGISDOCKED, 0, 0)) { //if docked, dont remember pos (except for width)
+ DBWriteContactSettingDword(NULL, "CList", "Height", (DWORD) (rc.bottom - rc.top));
+ DBWriteContactSettingDword(NULL, "CList", "x", (DWORD) rc.left);
+ DBWriteContactSettingDword(NULL, "CList", "y", (DWORD) rc.top);
+ }
+ DBWriteContactSettingDword(NULL, "CList", "Width", (DWORD) (rc.right - rc.left));
+ }
+
+ if ( cli.hwndStatus ) {
+ DestroyWindow( cli.hwndStatus );
+ cli.hwndStatus = NULL;
+ }
+
+ // Disconnect all protocols
+ DisconnectAll();
+
+ ShowWindow(hwnd, SW_HIDE);
+ DestroyWindow(cli.hwndContactTree);
+ ImageList_Destroy(himlMirandaIcon);
+ FreeLibrary(hUserDll);
+ PostQuitMessage(0);
+ default:
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+
+ return TRUE;
+}
diff --git a/miranda-wine/src/modules/clist/cluiservices.c b/miranda-wine/src/modules/clist/cluiservices.c
new file mode 100644
index 0000000..0b01b3e
--- /dev/null
+++ b/miranda-wine/src/modules/clist/cluiservices.c
@@ -0,0 +1,239 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "clc.h"
+
+static int GetHwnd(WPARAM wParam, LPARAM lParam)
+{
+ return (int)cli.hwndContactList;
+}
+
+static int GetHwndTree(WPARAM wParam,LPARAM lParam)
+{
+ return (int)cli.hwndContactTree;
+}
+
+static int CluiProtocolStatusChanged(WPARAM wParam, LPARAM lParam)
+{
+ cli.pfnCluiProtocolStatusChanged( wParam, (const char*)lParam );
+ return 0;
+}
+
+int SortList(WPARAM wParam, LPARAM lParam)
+{
+ //unnecessary: CLC does this automatically
+ return 0;
+}
+
+static int GroupAdded(WPARAM wParam, LPARAM lParam)
+{
+ //CLC does this automatically unless it's a new group
+ if (lParam) {
+ HANDLE hItem;
+ TCHAR szFocusClass[64];
+ HWND hwndFocus = GetFocus();
+
+ GetClassName(hwndFocus, szFocusClass, SIZEOF(szFocusClass));
+ if (!lstrcmp(szFocusClass, CLISTCONTROL_CLASS)) {
+ hItem = (HANDLE) SendMessage(hwndFocus, CLM_FINDGROUP, wParam, 0);
+ if (hItem)
+ SendMessage(hwndFocus, CLM_EDITLABEL, (WPARAM) hItem, 0);
+ }
+ }
+ return 0;
+}
+
+static int ContactSetIcon(WPARAM wParam, LPARAM lParam)
+{
+ //unnecessary: CLC does this automatically
+ return 0;
+}
+
+static int ContactDeleted(WPARAM wParam, LPARAM lParam)
+{
+ //unnecessary: CLC does this automatically
+ return 0;
+}
+
+static int ContactAdded(WPARAM wParam, LPARAM lParam)
+{
+ //unnecessary: CLC does this automatically
+ return 0;
+}
+
+static int ListBeginRebuild(WPARAM wParam, LPARAM lParam)
+{
+ //unnecessary: CLC does this automatically
+ return 0;
+}
+
+static int ListEndRebuild(WPARAM wParam, LPARAM lParam)
+{
+ int rebuild = 0;
+ //CLC does this automatically, but we need to force it if hideoffline or hideempty has changed
+ if ((DBGetContactSettingByte(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT) == 0) != ((GetWindowLong(cli.hwndContactTree, GWL_STYLE) & CLS_HIDEOFFLINE) == 0)) {
+ if (DBGetContactSettingByte(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT))
+ SetWindowLong(cli.hwndContactTree, GWL_STYLE, GetWindowLong(cli.hwndContactTree, GWL_STYLE) | CLS_HIDEOFFLINE);
+ else
+ SetWindowLong(cli.hwndContactTree, GWL_STYLE, GetWindowLong(cli.hwndContactTree, GWL_STYLE) & ~CLS_HIDEOFFLINE);
+ rebuild = 1;
+ }
+ if ((DBGetContactSettingByte(NULL, "CList", "HideEmptyGroups", SETTING_HIDEEMPTYGROUPS_DEFAULT) == 0) != ((GetWindowLong(cli.hwndContactTree, GWL_STYLE) & CLS_HIDEEMPTYGROUPS) == 0)) {
+ if (DBGetContactSettingByte(NULL, "CList", "HideEmptyGroups", SETTING_HIDEEMPTYGROUPS_DEFAULT))
+ SetWindowLong(cli.hwndContactTree, GWL_STYLE, GetWindowLong(cli.hwndContactTree, GWL_STYLE) | CLS_HIDEEMPTYGROUPS);
+ else
+ SetWindowLong(cli.hwndContactTree, GWL_STYLE, GetWindowLong(cli.hwndContactTree, GWL_STYLE) & ~CLS_HIDEEMPTYGROUPS);
+ rebuild = 1;
+ }
+ if ((DBGetContactSettingByte(NULL, "CList", "UseGroups", SETTING_USEGROUPS_DEFAULT) == 0) != ((GetWindowLong(cli.hwndContactTree, GWL_STYLE) & CLS_USEGROUPS) == 0)) {
+ if (DBGetContactSettingByte(NULL, "CList", "UseGroups", SETTING_USEGROUPS_DEFAULT))
+ SetWindowLong(cli.hwndContactTree, GWL_STYLE, GetWindowLong(cli.hwndContactTree, GWL_STYLE) | CLS_USEGROUPS);
+ else
+ SetWindowLong(cli.hwndContactTree, GWL_STYLE, GetWindowLong(cli.hwndContactTree, GWL_STYLE) & ~CLS_USEGROUPS);
+ rebuild = 1;
+ }
+ if (rebuild)
+ SendMessage(cli.hwndContactTree, CLM_AUTOREBUILD, 0, 0);
+ return 0;
+}
+
+static int ContactRenamed(WPARAM wParam, LPARAM lParam)
+{
+ //unnecessary: CLC does this automatically
+ return 0;
+}
+
+static int GetCaps(WPARAM wParam, LPARAM lParam)
+{
+ switch (wParam) {
+ case CLUICAPS_FLAGS1:
+ return CLUIF_HIDEEMPTYGROUPS | CLUIF_DISABLEGROUPS | CLUIF_HASONTOPOPTION | CLUIF_HASAUTOHIDEOPTION;
+ }
+ return 0;
+}
+
+int LoadCluiServices(void)
+{
+ CreateServiceFunction(MS_CLUI_GETHWND, GetHwnd);
+ CreateServiceFunction(MS_CLUI_GETHWNDTREE,GetHwndTree);
+ CreateServiceFunction(MS_CLUI_PROTOCOLSTATUSCHANGED, CluiProtocolStatusChanged);
+ CreateServiceFunction(MS_CLUI_GROUPADDED, GroupAdded);
+ CreateServiceFunction(MS_CLUI_CONTACTSETICON, ContactSetIcon);
+ CreateServiceFunction(MS_CLUI_CONTACTADDED, ContactAdded);
+ CreateServiceFunction(MS_CLUI_CONTACTDELETED, ContactDeleted);
+ CreateServiceFunction(MS_CLUI_CONTACTRENAMED, ContactRenamed);
+ CreateServiceFunction(MS_CLUI_LISTBEGINREBUILD, ListBeginRebuild);
+ CreateServiceFunction(MS_CLUI_LISTENDREBUILD, ListEndRebuild);
+ CreateServiceFunction(MS_CLUI_SORTLIST, SortList);
+ CreateServiceFunction(MS_CLUI_GETCAPS, GetCaps);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// default protocol status notification handler
+
+int fnCluiProtocolStatusChanged(int parStatus, const char* szProto)
+{
+ int protoCount, i;
+ PROTOCOLDESCRIPTOR **proto;
+ int *partWidths, partCount;
+ int borders[3];
+ int status;
+ int flags = 0;
+
+ SendMessage(cli.hwndStatus, SB_GETBORDERS, 0, (LPARAM) & borders);
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM) & protoCount, (LPARAM) & proto);
+ if (protoCount == 0)
+ return 0;
+ partWidths = (int *) mir_alloc(protoCount * sizeof(int));
+ if (DBGetContactSettingByte(NULL, "CLUI", "EqualSections", 0)) {
+ RECT rc;
+ int part;
+ GetClientRect(cli.hwndStatus, &rc);
+ rc.right -= borders[0] * 2 + (DBGetContactSettingByte(NULL, "CLUI", "ShowGrip", 1) ? GetSystemMetrics(SM_CXVSCROLL) : 0);
+ for (partCount = 0, i = protoCount - 1; i >= 0; i--)
+ if (proto[i]->type == PROTOTYPE_PROTOCOL && CallProtoService(proto[i]->szName, PS_GETCAPS, PFLAGNUM_2, 0) != 0)
+ partCount++;
+ for (part = 0, i = 0; i < protoCount; i++) {
+ if (proto[i]->type != PROTOTYPE_PROTOCOL)
+ continue;
+ partWidths[part] = (part + 1) * rc.right / partCount - (borders[2] >> 1);
+ part++;
+ }
+ }
+ else {
+ char *modeDescr;
+ HDC hdc;
+ SIZE textSize;
+ BYTE showOpts = DBGetContactSettingByte(NULL, "CLUI", "SBarShow", 1);
+ int x;
+ char szName[32];
+
+ hdc = GetDC(NULL);
+ SelectObject(hdc, (HFONT) SendMessage(cli.hwndStatus, WM_GETFONT, 0, 0));
+ for (partCount = 0, i = protoCount - 1; i >= 0; i--) { //count down since built in ones tend to go at the end
+ if (proto[i]->type != PROTOTYPE_PROTOCOL || CallProtoService(proto[i]->szName, PS_GETCAPS, PFLAGNUM_2, 0) == 0)
+ continue;
+ x = 2;
+ if (showOpts & 1)
+ x += g_IconWidth;
+ if (showOpts & 2) {
+ CallProtoService(proto[i]->szName, PS_GETNAME, SIZEOF(szName), (LPARAM) szName);
+ if (showOpts & 4 && lstrlenA(szName) < SIZEOF(szName) - 1)
+ lstrcatA(szName, " ");
+ GetTextExtentPoint32A(hdc, szName, lstrlenA(szName), &textSize);
+ x += textSize.cx;
+ x += GetSystemMetrics(SM_CXBORDER) * 4; // The SB panel doesnt allocate enough room
+ }
+ if (showOpts & 4) {
+ modeDescr = (char *) CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, CallProtoService(proto[i]->szName, PS_GETSTATUS, 0, 0), 0);
+ GetTextExtentPoint32A(hdc, modeDescr, lstrlenA(modeDescr), &textSize);
+ x += textSize.cx;
+ x += GetSystemMetrics(SM_CXBORDER) * 4; // The SB panel doesnt allocate enough room
+ }
+ partWidths[partCount] = (partCount ? partWidths[partCount - 1] : 0) + x + 2;
+ partCount++;
+ }
+ ReleaseDC(NULL, hdc);
+ }
+ if (partCount == 0) {
+ mir_free(partWidths);
+ return 0;
+ }
+ partWidths[partCount - 1] = -1;
+ SendMessage(cli.hwndStatus, SB_SETMINHEIGHT, g_IconHeight, 0);
+ SendMessage(cli.hwndStatus, SB_SETPARTS, partCount, (LPARAM) partWidths);
+ mir_free(partWidths);
+ flags = SBT_OWNERDRAW;
+ if (DBGetContactSettingByte(NULL, "CLUI", "SBarBevel", 1) == 0)
+ flags |= SBT_NOBORDERS;
+ for (partCount = 0, i = protoCount - 1; i >= 0; i--) { //count down since built in ones tend to go at the end
+ // okay, so it was a bug ;)
+ if (proto[i]->type != PROTOTYPE_PROTOCOL || (CallProtoService(proto[i]->szName, PS_GETCAPS, PFLAGNUM_2, 0) == 0))
+ continue;
+ status = CallProtoService(proto[i]->szName, PS_GETSTATUS, 0, 0);
+ SendMessage(cli.hwndStatus, SB_SETTEXT, partCount | flags, (LPARAM) proto[i]->szName);
+ partCount++;
+ }
+ return 0;
+}
diff --git a/miranda-wine/src/modules/clist/contact.c b/miranda-wine/src/modules/clist/contact.c
new file mode 100644
index 0000000..be14573
--- /dev/null
+++ b/miranda-wine/src/modules/clist/contact.c
@@ -0,0 +1,185 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "clc.h"
+
+extern HANDLE hContactIconChangedEvent;
+
+int sortByStatus;
+int sortByProto;
+struct {
+ int status,order;
+} statusModeOrder[]={
+ {ID_STATUS_OFFLINE,500},
+ {ID_STATUS_ONLINE,0},
+ {ID_STATUS_AWAY,200},
+ {ID_STATUS_DND,400},
+ {ID_STATUS_NA,450},
+ {ID_STATUS_OCCUPIED,100},
+ {ID_STATUS_FREECHAT,50},
+ {ID_STATUS_INVISIBLE,20},
+ {ID_STATUS_ONTHEPHONE,150},
+ {ID_STATUS_OUTTOLUNCH,425}};
+
+static int GetContactStatus(HANDLE hContact)
+{
+ char* szProto = ( char* )CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ if (szProto == NULL)
+ return ID_STATUS_OFFLINE;
+ return DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE);
+}
+
+void fnChangeContactIcon(HANDLE hContact, int iIcon, int add)
+{
+ CallService(add ? MS_CLUI_CONTACTADDED : MS_CLUI_CONTACTSETICON, (WPARAM) hContact, iIcon);
+ NotifyEventHooks(hContactIconChangedEvent, (WPARAM) hContact, iIcon);
+}
+
+int GetStatusModeOrdering(int statusMode)
+{
+ int i;
+ for (i = 0; i < SIZEOF(statusModeOrder); i++)
+ if (statusModeOrder[i].status == statusMode)
+ return statusModeOrder[i].order;
+ return 1000;
+}
+
+void fnLoadContactTree(void)
+{
+ HANDLE hContact;
+ int i, status, hideOffline;
+
+ CallService(MS_CLUI_LISTBEGINREBUILD, 0, 0);
+ for (i = 1;; i++) {
+ if ( cli.pfnGetGroupName(i, NULL) == NULL)
+ break;
+ CallService(MS_CLUI_GROUPADDED, i, 0);
+ }
+
+ hideOffline = DBGetContactSettingByte(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT);
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact != NULL) {
+ status = GetContactStatus(hContact);
+ if ((!hideOffline || status != ID_STATUS_OFFLINE) && !DBGetContactSettingByte(hContact, "CList", "Hidden", 0))
+ cli.pfnChangeContactIcon(hContact, cli.pfnIconFromStatusMode((char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0), status, hContact), 1);
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ }
+ sortByStatus = DBGetContactSettingByte(NULL, "CList", "SortByStatus", SETTING_SORTBYSTATUS_DEFAULT);
+ sortByProto = DBGetContactSettingByte(NULL, "CList", "SortByProto", SETTING_SORTBYPROTO_DEFAULT);
+ CallService(MS_CLUI_SORTLIST, 0, 0);
+ CallService(MS_CLUI_LISTENDREBUILD, 0, 0);
+}
+
+int fnCompareContacts(const struct ClcContact* c1, const struct ClcContact* c2)
+{
+ HANDLE a = c1->hContact, b = c2->hContact;
+ TCHAR namea[128], *nameb;
+ int statusa, statusb;
+ int rc;
+
+ statusa = DBGetContactSettingWord((HANDLE) a, c1->proto, "Status", ID_STATUS_OFFLINE);
+ statusb = DBGetContactSettingWord((HANDLE) b, c2->proto, "Status", ID_STATUS_OFFLINE);
+
+ if (sortByProto) {
+ /* deal with statuses, online contacts have to go above offline */
+ if ((statusa == ID_STATUS_OFFLINE) != (statusb == ID_STATUS_OFFLINE)) {
+ return 2 * (statusa == ID_STATUS_OFFLINE) - 1;
+ }
+ /* both are online, now check protocols */
+ rc = lstrcmpA( c1->proto, c2->proto);
+ if (rc != 0 && (c1->proto != NULL && c2->proto != NULL))
+ return rc;
+ /* protocols are the same, order by display name */
+ }
+
+ if (sortByStatus) {
+ int ordera, orderb;
+ ordera = GetStatusModeOrdering(statusa);
+ orderb = GetStatusModeOrdering(statusb);
+ if (ordera != orderb)
+ return ordera - orderb;
+ }
+ else {
+ //one is offline: offline goes below online
+ if ((statusa == ID_STATUS_OFFLINE) != (statusb == ID_STATUS_OFFLINE)) {
+ return 2 * (statusa == ID_STATUS_OFFLINE) - 1;
+ }
+ }
+
+ nameb = cli.pfnGetContactDisplayName( a, 0);
+ _tcsncpy(namea, nameb, SIZEOF(namea));
+ namea[ SIZEOF(namea)-1 ] = 0;
+ nameb = cli.pfnGetContactDisplayName( b, 0);
+
+ //otherwise just compare names
+ return _tcsicmp(namea, nameb);
+}
+
+static int resortTimerId = 0;
+static VOID CALLBACK SortContactsTimer(HWND hwnd, UINT message, UINT idEvent, DWORD dwTime)
+{
+ KillTimer(NULL, resortTimerId);
+ resortTimerId = 0;
+ CallService(MS_CLUI_SORTLIST, 0, 0);
+}
+
+void fnSortContacts(void)
+{
+ //avoid doing lots of resorts in quick succession
+ sortByStatus = DBGetContactSettingByte(NULL, "CList", "SortByStatus", SETTING_SORTBYSTATUS_DEFAULT);
+ sortByProto = DBGetContactSettingByte(NULL, "CList", "SortByProto", SETTING_SORTBYPROTO_DEFAULT);
+ if (resortTimerId)
+ KillTimer(NULL, resortTimerId);
+ // setting this to a higher delay causes shutdown waits.
+ resortTimerId = SetTimer(NULL, 0, 500, SortContactsTimer);
+}
+
+int ContactChangeGroup(WPARAM wParam, LPARAM lParam)
+{
+ CallService(MS_CLUI_CONTACTDELETED, wParam, 0);
+ if ((HANDLE) lParam == NULL)
+ DBDeleteContactSetting((HANDLE) wParam, "CList", "Group");
+ else
+ DBWriteContactSettingTString((HANDLE) wParam, "CList", "Group", cli.pfnGetGroupName(lParam, NULL));
+ CallService(MS_CLUI_CONTACTADDED, wParam,
+ cli.pfnIconFromStatusMode((char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0), GetContactStatus((HANDLE) wParam), (HANDLE) wParam));
+ return 0;
+}
+
+int fnSetHideOffline(WPARAM wParam, LPARAM lParam)
+{
+ switch ((int) wParam) {
+ case 0:
+ DBWriteContactSettingByte(NULL, "CList", "HideOffline", 0);
+ break;
+ case 1:
+ DBWriteContactSettingByte(NULL, "CList", "HideOffline", 1);
+ break;
+ case -1:
+ DBWriteContactSettingByte(NULL, "CList", "HideOffline",
+ (BYTE) ! DBGetContactSettingByte(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT));
+ break;
+ }
+ cli.pfnLoadContactTree();
+ return 0;
+}
diff --git a/miranda-wine/src/modules/clist/groups.c b/miranda-wine/src/modules/clist/groups.c
new file mode 100644
index 0000000..3c48e1e
--- /dev/null
+++ b/miranda-wine/src/modules/clist/groups.c
@@ -0,0 +1,514 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "clc.h"
+
+static int RenameGroup(WPARAM wParam, LPARAM lParam);
+static int MoveGroupBefore(WPARAM wParam, LPARAM lParam);
+
+static int CountGroups(void)
+{
+ DBVARIANT dbv;
+ int i;
+ char str[33];
+
+ for (i = 0;; i++) {
+ itoa(i, str, 10);
+ if (DBGetContactSetting(NULL, "CListGroups", str, &dbv))
+ break;
+ DBFreeVariant(&dbv);
+ }
+ return i;
+}
+
+static int GroupNameExists(const TCHAR *name, int skipGroup)
+{
+ char idstr[33];
+ DBVARIANT dbv;
+ int i;
+
+ for (i = 0;; i++) {
+ if (i == skipGroup)
+ continue;
+ itoa(i, idstr, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", idstr, &dbv))
+ break;
+ if (!_tcscmp(dbv.ptszVal + 1, name)) {
+ DBFreeVariant(&dbv);
+ return 1;
+ }
+ DBFreeVariant(&dbv);
+ }
+ return 0;
+}
+
+static int CreateGroup(WPARAM wParam, LPARAM lParam)
+{
+ int newId = CountGroups();
+ TCHAR newBaseName[127], newName[128];
+ char str[33];
+ int i;
+ DBVARIANT dbv;
+
+ if (wParam) {
+ itoa(wParam - 1, str, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", str, &dbv))
+ return 0;
+
+ mir_sntprintf( newBaseName, SIZEOF(newBaseName), _T("%s\\%s"), dbv.ptszVal + 1, TranslateT("New Group"));
+ mir_free(dbv.pszVal);
+ }
+ else lstrcpyn( newBaseName, TranslateT( "New Group" ), SIZEOF( newBaseName ));
+
+ itoa(newId, str, 10);
+ i = 1;
+ lstrcpyn( newName + 1, newBaseName, SIZEOF(newName) - 1);
+ while (GroupNameExists(newName + 1, -1))
+ mir_sntprintf( newName + 1, SIZEOF(newName) - 1, _T("%s (%d)"), newBaseName, ++i );
+
+ newName[0] = 1 | GROUPF_EXPANDED; //1 is required so we never get '\0'
+ DBWriteContactSettingTString(NULL, "CListGroups", str, newName);
+ CallService(MS_CLUI_GROUPADDED, newId + 1, 1);
+ return newId + 1;
+}
+
+static int GetGroupName2(WPARAM wParam, LPARAM lParam)
+{
+ char idstr[33];
+ DBVARIANT dbv;
+ static char name[128];
+
+ itoa(wParam - 1, idstr, 10);
+ if (DBGetContactSetting(NULL, "CListGroups", idstr, &dbv))
+ return (int) (char *) NULL;
+ lstrcpynA(name, dbv.pszVal + 1, SIZEOF(name));
+ if ((DWORD *) lParam != NULL)
+ *(DWORD *) lParam = dbv.pszVal[0];
+ DBFreeVariant(&dbv);
+ return (int) name;
+}
+
+TCHAR* fnGetGroupName( int idx, DWORD* pdwFlags )
+{
+ char idstr[33];
+ DBVARIANT dbv;
+ static TCHAR name[128];
+
+ itoa( idx-1, idstr, 10);
+ if (DBGetContactSettingTString( NULL, "CListGroups", idstr, &dbv ))
+ return NULL;
+
+ lstrcpyn( name, dbv.ptszVal + 1, SIZEOF( name ));
+ if ( pdwFlags != NULL )
+ *pdwFlags = dbv.ptszVal[0];
+ DBFreeVariant( &dbv );
+ return name;
+}
+
+static int GetGroupName(WPARAM wParam, LPARAM lParam)
+{
+ int ret;
+ ret = GetGroupName2(wParam, lParam);
+ if ((int *) lParam)
+ *(int *) lParam = 0 != (*(int *) lParam & GROUPF_EXPANDED);
+ return ret;
+}
+
+static int DeleteGroup(WPARAM wParam, LPARAM lParam)
+{
+ int i;
+ char str[33];
+ DBVARIANT dbv;
+ HANDLE hContact;
+ TCHAR name[256], szNewParent[256], *pszLastBackslash;
+
+ //get the name
+ itoa(wParam - 1, str, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", str, &dbv))
+ return 1;
+ if (DBGetContactSettingByte(NULL, "CList", "ConfirmDelete", SETTING_CONFIRMDELETE_DEFAULT))
+ if (MessageBox((HWND)CallService(MS_CLUI_GETHWND, 0, 0), TranslateT("Are you sure you want to delete this group? This operation can not be undone."), TranslateT("Delete Group"), MB_YESNO|MB_ICONQUESTION)==IDNO)
+ return 1;
+ lstrcpyn(name, dbv.ptszVal + 1, SIZEOF(name));
+ DBFreeVariant(&dbv);
+ SetCursor(LoadCursor(NULL, IDC_WAIT));
+ //must remove setting from all child contacts too
+ //children are demoted to the next group up, not deleted.
+ lstrcpy(szNewParent, name);
+ pszLastBackslash = _tcsrchr(szNewParent, '\\');
+ if (pszLastBackslash)
+ pszLastBackslash[0] = '\0';
+ else
+ szNewParent[0] = '\0';
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ do {
+ if (DBGetContactSettingTString(hContact, "CList", "Group", &dbv))
+ continue;
+ if (_tcscmp(dbv.ptszVal, name)) {
+ DBFreeVariant(&dbv);
+ continue;
+ }
+ DBFreeVariant(&dbv);
+ if (szNewParent[0])
+ DBWriteContactSettingTString(hContact, "CList", "Group", szNewParent);
+ else
+ DBDeleteContactSetting(hContact, "CList", "Group");
+ } while ((hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0)) != NULL);
+ //shuffle list of groups up to fill gap
+ for (i = wParam - 1;; i++) {
+ itoa(i + 1, str, 10);
+ if (DBGetContactSettingStringUtf(NULL, "CListGroups", str, &dbv))
+ break;
+ itoa(i, str, 10);
+ DBWriteContactSettingStringUtf(NULL, "CListGroups", str, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ itoa(i, str, 10);
+ DBDeleteContactSetting(NULL, "CListGroups", str);
+ //rename subgroups
+ {
+ TCHAR szNewName[256];
+ int len;
+
+ len = lstrlen(name);
+ for (i = 0;; i++) {
+ itoa(i, str, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", str, &dbv))
+ break;
+ if (!_tcsncmp(dbv.ptszVal + 1, name, len) && dbv.pszVal[len + 1] == '\\' && _tcschr(dbv.ptszVal + len + 2, '\\') == NULL) {
+ if (szNewParent[0])
+ mir_sntprintf(szNewName, SIZEOF(szNewName), _T("%s\\%s"), szNewParent, dbv.ptszVal + len + 2);
+ else
+ lstrcpyn(szNewName, dbv.ptszVal + len + 2, SIZEOF(szNewName));
+ cli.pfnRenameGroup(i + 1, szNewName);
+ }
+ DBFreeVariant(&dbv);
+ }
+ }
+ SetCursor(LoadCursor(NULL, IDC_ARROW));
+ cli.pfnLoadContactTree();
+ return 0;
+}
+
+static int RenameGroupWithMove(int groupId, const TCHAR *szName, int move)
+{
+ char idstr[33];
+ TCHAR str[256], oldName[256];
+ DBVARIANT dbv;
+ HANDLE hContact;
+
+ if (GroupNameExists(szName, groupId)) {
+ MessageBox(NULL, TranslateT("You already have a group with that name. Please enter a unique name for the group."), TranslateT("Rename Group"), MB_OK);
+ return 1;
+ }
+
+ //do the change
+ itoa(groupId, idstr, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", idstr, &dbv))
+ return 1;
+ str[0] = dbv.pszVal[0];
+ lstrcpyn(oldName, dbv.ptszVal + 1, SIZEOF(oldName));
+ DBFreeVariant(&dbv);
+ lstrcpyn(str + 1, szName, SIZEOF(str) - 1);
+ DBWriteContactSettingTString(NULL, "CListGroups", idstr, str);
+
+ //must rename setting in all child contacts too
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ do {
+ ClcCacheEntryBase* cache = cli.pfnGetCacheEntry( hContact );
+ if ( !lstrcmp(cache->group, oldName)) {
+ DBWriteContactSettingTString(hContact, "CList", "Group", szName);
+ mir_free(cache->group);
+ cache->group = 0;
+ cli.pfnCheckCacheItem(cache);
+ }
+ }
+ while ((hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0)) != NULL);
+
+ //rename subgroups
+ {
+ TCHAR szNewName[256];
+ int len, i;
+
+ len = lstrlen(oldName);
+ for (i = 0;; i++) {
+ if (i == groupId)
+ continue;
+ itoa(i, idstr, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", idstr, &dbv))
+ break;
+ if ( !_tcsncmp(dbv.ptszVal + 1, oldName, len) && dbv.ptszVal[len + 1] == '\\' && _tcschr(dbv.ptszVal + len + 2, '\\') == NULL) {
+ mir_sntprintf( szNewName, SIZEOF(szNewName), _T("%s\\%s"), szName, dbv.ptszVal + len + 2 );
+ RenameGroupWithMove(i, szNewName, 0); //luckily, child groups will never need reordering
+ }
+ DBFreeVariant(&dbv);
+ }
+ }
+
+ //finally must make sure it's after any parent items
+ if (move) {
+ TCHAR *pszLastBackslash;
+ int i;
+
+ lstrcpyn(str, szName, SIZEOF(str));
+ pszLastBackslash = _tcsrchr(str, '\\');
+ if (pszLastBackslash == NULL)
+ return 0;
+ *pszLastBackslash = '\0';
+ for (i = 0;; i++) {
+ itoa(i, idstr, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", idstr, &dbv))
+ break;
+ if (!lstrcmp(dbv.ptszVal + 1, str)) {
+ if (i < groupId)
+ break; //is OK
+ MoveGroupBefore(groupId + 1, i + 2);
+ break;
+ }
+ DBFreeVariant(&dbv);
+ }
+ }
+ return 0;
+}
+
+int fnRenameGroup( int groupID, TCHAR* newName )
+{
+ return -1 != RenameGroupWithMove( groupID-1, newName, 1);
+}
+
+static int RenameGroup(WPARAM wParam, LPARAM lParam)
+{
+ #if defined( _UNICODE )
+ WCHAR* temp = a2u(( char* )lParam );
+ int result = ( -1 != RenameGroupWithMove(wParam - 1, temp, 1));
+ mir_free( temp );
+ return result;
+ #else
+ return -1 != RenameGroupWithMove(wParam - 1, (TCHAR*) lParam, 1);
+ #endif
+}
+
+static int SetGroupExpandedState(WPARAM wParam, LPARAM lParam)
+{
+ char idstr[33];
+ DBVARIANT dbv;
+
+ itoa(wParam - 1, idstr, 10);
+ if (DBGetContactSettingStringUtf(NULL, "CListGroups", idstr, &dbv))
+ return 1;
+ if (lParam)
+ dbv.pszVal[0] |= GROUPF_EXPANDED;
+ else
+ dbv.pszVal[0] = dbv.pszVal[0] & ~GROUPF_EXPANDED;
+ DBWriteContactSettingStringUtf(NULL, "CListGroups", idstr, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ return 0;
+}
+
+static int SetGroupFlags(WPARAM wParam, LPARAM lParam)
+{
+ char idstr[33];
+ DBVARIANT dbv;
+ int flags, oldval, newval;
+
+ itoa(wParam - 1, idstr, 10);
+ if (DBGetContactSettingStringUtf(NULL, "CListGroups", idstr, &dbv))
+ return 1;
+ flags = LOWORD(lParam) & HIWORD(lParam);
+ oldval = dbv.pszVal[0];
+ newval = dbv.pszVal[0] = (dbv.pszVal[0] & ~HIWORD(lParam)) | flags;
+ DBWriteContactSettingStringUtf(NULL, "CListGroups", idstr, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ if ((oldval & GROUPF_HIDEOFFLINE) != (newval & GROUPF_HIDEOFFLINE))
+ cli.pfnLoadContactTree();
+ return 0;
+}
+
+static int MoveGroupBefore(WPARAM wParam, LPARAM lParam)
+{
+ int i, shuffleFrom, shuffleTo, shuffleDir;
+ char str[33];
+ TCHAR *szMoveName;
+ DBVARIANT dbv;
+
+ if (wParam == 0 || (LPARAM) wParam == lParam)
+ return 0;
+ itoa(wParam - 1, str, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", str, &dbv))
+ return 0;
+ szMoveName = dbv.ptszVal;
+ //shuffle list of groups up to fill gap
+ if (lParam == 0) {
+ shuffleFrom = wParam - 1;
+ shuffleTo = -1;
+ shuffleDir = -1;
+ }
+ else {
+ if ((LPARAM) wParam < lParam) {
+ shuffleFrom = wParam - 1;
+ shuffleTo = lParam - 2;
+ shuffleDir = -1;
+ }
+ else {
+ shuffleFrom = wParam - 1;
+ shuffleTo = lParam - 1;
+ shuffleDir = 1;
+ }
+ }
+ if (shuffleDir == -1) {
+ for (i = shuffleFrom; i != shuffleTo; i++) {
+ itoa(i + 1, str, 10);
+ if (DBGetContactSettingStringUtf(NULL, "CListGroups", str, &dbv)) {
+ shuffleTo = i;
+ break;
+ }
+ itoa(i, str, 10);
+ DBWriteContactSettingStringUtf(NULL, "CListGroups", str, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ }
+ else {
+ for (i = shuffleFrom; i != shuffleTo; i--) {
+ itoa(i - 1, str, 10);
+ if (DBGetContactSettingStringUtf(NULL, "CListGroups", str, &dbv)) {
+ mir_free(szMoveName);
+ return 1;
+ } //never happens
+ itoa(i, str, 10);
+ DBWriteContactSettingStringUtf(NULL, "CListGroups", str, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ }
+ itoa(shuffleTo, str, 10);
+ DBWriteContactSettingTString(NULL, "CListGroups", str, szMoveName);
+ mir_free(szMoveName);
+ return shuffleTo + 1;
+}
+
+static int BuildGroupMenu(WPARAM wParam, LPARAM lParam)
+{
+ char idstr[33];
+ DBVARIANT dbv;
+ int groupId;
+ HMENU hRootMenu, hThisMenu;
+ int nextMenuId = 100;
+ TCHAR *pBackslash, *pNextField, szThisField[128], szThisMenuItem[128];
+ int menuId, compareResult, menuItemCount;
+ MENUITEMINFO mii = { 0 };
+
+ if (DBGetContactSettingStringUtf(NULL, "CListGroups", "0", &dbv))
+ return (int) (HMENU) NULL;
+ DBFreeVariant(&dbv);
+ hRootMenu = CreateMenu();
+ for (groupId = 0;; groupId++) {
+ itoa(groupId, idstr, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", idstr, &dbv))
+ break;
+
+ pNextField = dbv.ptszVal + 1;
+ hThisMenu = hRootMenu;
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ do {
+ pBackslash = _tcschr(pNextField, '\\');
+ if (pBackslash == NULL) {
+ lstrcpyn(szThisField, pNextField, SIZEOF(szThisField));
+ pNextField = NULL;
+ }
+ else {
+ lstrcpyn(szThisField, pNextField, min( SIZEOF(szThisField), pBackslash - pNextField + 1));
+ pNextField = pBackslash + 1;
+ }
+ compareResult = 1;
+ menuItemCount = GetMenuItemCount(hThisMenu);
+ for (menuId = 0; menuId < menuItemCount; menuId++) {
+ mii.fMask = MIIM_TYPE | MIIM_SUBMENU | MIIM_DATA;
+ mii.cch = SIZEOF(szThisMenuItem);
+ mii.dwTypeData = szThisMenuItem;
+ GetMenuItemInfo(hThisMenu, menuId, TRUE, &mii);
+ compareResult = lstrcmp(szThisField, szThisMenuItem);
+ if (compareResult == 0) {
+ if (pNextField == NULL) {
+ mii.fMask = MIIM_DATA;
+ mii.dwItemData = groupId + 1;
+ SetMenuItemInfo(hThisMenu, menuId, TRUE, &mii);
+ }
+ else {
+ if (mii.hSubMenu == NULL) {
+ mii.fMask = MIIM_SUBMENU;
+ mii.hSubMenu = CreateMenu();
+ SetMenuItemInfo(hThisMenu, menuId, TRUE, &mii);
+ mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID;
+ //dwItemData doesn't change
+ mii.fType = MFT_STRING;
+ mii.dwTypeData = TranslateT("This group");
+ mii.wID = nextMenuId++;
+ InsertMenuItem(mii.hSubMenu, 0, TRUE, &mii);
+ mii.fMask = MIIM_TYPE;
+ mii.fType = MFT_SEPARATOR;
+ InsertMenuItem(mii.hSubMenu, 1, TRUE, &mii);
+ }
+ hThisMenu = mii.hSubMenu;
+ }
+ break;
+ }
+ if ((int) mii.dwItemData - 1 > groupId)
+ break;
+ }
+ if (compareResult) {
+ mii.fMask = MIIM_TYPE | MIIM_ID;
+ mii.wID = nextMenuId++;
+ mii.dwTypeData = szThisField;
+ mii.fType = MFT_STRING;
+ if (pNextField) {
+ mii.fMask |= MIIM_SUBMENU;
+ mii.hSubMenu = CreateMenu();
+ }
+ else {
+ mii.fMask |= MIIM_DATA;
+ mii.dwItemData = groupId + 1;
+ }
+ InsertMenuItem(hThisMenu, menuId, TRUE, &mii);
+ if (pNextField) {
+ hThisMenu = mii.hSubMenu;
+ }
+ }
+ } while (pNextField);
+
+ DBFreeVariant(&dbv);
+ }
+ return (int) hRootMenu;
+}
+
+int InitGroupServices(void)
+{
+ CreateServiceFunction(MS_CLIST_GROUPCREATE, CreateGroup);
+ CreateServiceFunction(MS_CLIST_GROUPDELETE, DeleteGroup);
+ CreateServiceFunction(MS_CLIST_GROUPRENAME, RenameGroup);
+ CreateServiceFunction(MS_CLIST_GROUPGETNAME, GetGroupName);
+ CreateServiceFunction(MS_CLIST_GROUPGETNAME2, GetGroupName2);
+ CreateServiceFunction(MS_CLIST_GROUPSETEXPANDED, SetGroupExpandedState);
+ CreateServiceFunction(MS_CLIST_GROUPSETFLAGS, SetGroupFlags);
+ CreateServiceFunction(MS_CLIST_GROUPMOVEBEFORE, MoveGroupBefore);
+ CreateServiceFunction(MS_CLIST_GROUPBUILDMENU, BuildGroupMenu);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/clist/keyboard.c b/miranda-wine/src/modules/clist/keyboard.c
new file mode 100644
index 0000000..d64c0b9
--- /dev/null
+++ b/miranda-wine/src/modules/clist/keyboard.c
@@ -0,0 +1,135 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "clc.h"
+
+static ATOM aHide = 0;
+static ATOM aRead = 0;
+static ATOM aSearch = 0;
+static ATOM aOpts = 0;
+
+static void WordToModAndVk(WORD w, UINT * mod, UINT * vk)
+{
+ *mod = 0;
+ if (HIBYTE(w) & HOTKEYF_CONTROL)
+ *mod |= MOD_CONTROL;
+ if (HIBYTE(w) & HOTKEYF_SHIFT)
+ *mod |= MOD_SHIFT;
+ if (HIBYTE(w) & HOTKEYF_ALT)
+ *mod |= MOD_ALT;
+ if (HIBYTE(w) & HOTKEYF_EXT)
+ *mod |= MOD_WIN;
+ *vk = LOBYTE(w);
+}
+
+int fnHotKeysRegister(HWND hwnd)
+{
+ UINT mod, vk;
+
+ if (DBGetContactSettingByte(NULL, "CList", "HKEnShowHide", 0)) {
+ if (!aHide)
+ aHide = GlobalAddAtomA("HKEnShowHide");
+ WordToModAndVk((WORD) DBGetContactSettingWord(NULL, "CList", "HKShowHide", 0), &mod, &vk);
+ RegisterHotKey(hwnd, aHide, mod, vk);
+ }
+ if (DBGetContactSettingByte(NULL, "CList", "HKEnReadMsg", 0)) {
+ if (!aRead)
+ aRead = GlobalAddAtomA("HKEnReadMsg");
+ WordToModAndVk((WORD) DBGetContactSettingWord(NULL, "CList", "HKReadMsg", 0), &mod, &vk);
+ RegisterHotKey(hwnd, aRead, mod, vk);
+ }
+ if (DBGetContactSettingByte(NULL, "CList", "HKEnNetSearch", 0)) {
+ if (!aSearch)
+ aSearch = GlobalAddAtomA("HKEnNetSearch");
+ WordToModAndVk((WORD) DBGetContactSettingWord(NULL, "CList", "HKNetSearch", 0), &mod, &vk);
+ RegisterHotKey(hwnd, aSearch, mod, vk);
+ }
+ if (DBGetContactSettingByte(NULL, "CList", "HKEnShowOptions", 0)) {
+ if (!aOpts)
+ aOpts = GlobalAddAtomA("HKEnShowOptions");
+ WordToModAndVk((WORD) DBGetContactSettingWord(NULL, "CList", "HKShowOptions", 0), &mod, &vk);
+ RegisterHotKey(hwnd, aOpts, mod, vk);
+ }
+ return 0;
+}
+
+void fnHotKeysUnregister(HWND hwnd)
+{
+ if (aHide) {
+ UnregisterHotKey(hwnd, aHide);
+ GlobalDeleteAtom(aHide);
+ }
+ if (aRead) {
+ UnregisterHotKey(hwnd, aRead);
+ GlobalDeleteAtom(aRead);
+ }
+ if (aSearch) {
+ UnregisterHotKey(hwnd, aSearch);
+ GlobalDeleteAtom(aSearch);
+ }
+ if (aOpts) {
+ UnregisterHotKey(hwnd, aOpts);
+ GlobalDeleteAtom(aOpts);
+ }
+}
+
+int fnHotKeysProcess(HWND hwnd, WPARAM wParam, LPARAM lParam)
+{
+ if (wParam == aHide)
+ cli.pfnShowHide(0, 0);
+ else if (wParam == aSearch) {
+ DBVARIANT dbv;
+ if (!DBGetContactSetting(NULL, "CList", "SearchUrl", &dbv)) {
+ CallService(MS_UTILS_OPENURL, DBGetContactSettingByte(NULL, "CList", "HKSearchNewWnd", 0), (LPARAM) dbv.pszVal);
+ DBFreeVariant( &dbv );
+ }
+ }
+ else if (wParam == aRead) {
+ if (cli.pfnEventsProcessTrayDoubleClick() == 0)
+ return TRUE;
+ SetForegroundWindow(hwnd);
+ SetFocus(hwnd);
+ }
+ else if (wParam == aOpts) {
+ CallService("Options/OptionsCommand", 0, 0);
+ }
+ return TRUE;
+}
+
+int fnHotkeysProcessMessage(WPARAM wParam, LPARAM lParam)
+{
+ MSG *msg = (MSG *) wParam;
+ switch (msg->message) {
+ case WM_CREATE:
+ cli.pfnHotKeysRegister(msg->hwnd);
+ break;
+ case WM_HOTKEY:
+ *((LRESULT *) lParam) = cli.pfnHotKeysProcess(msg->hwnd, msg->wParam, msg->lParam);
+ return TRUE;
+ case WM_DESTROY:
+ cli.pfnHotKeysUnregister(msg->hwnd);
+ break;
+ }
+
+ return FALSE;
+}
diff --git a/miranda-wine/src/modules/contacts/contacts.c b/miranda-wine/src/modules/contacts/contacts.c
new file mode 100644
index 0000000..bd703a0
--- /dev/null
+++ b/miranda-wine/src/modules/contacts/contacts.c
@@ -0,0 +1,478 @@
+/*
+Miranda IM
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "commonheaders.h"
+
+#define NAMEORDERCOUNT 8
+static TCHAR* nameOrderDescr[ NAMEORDERCOUNT ] =
+{
+ _T( "My custom name (not moveable)" ),
+ _T( "Nick" ),
+ _T( "FirstName" ),
+ _T( "E-mail" ),
+ _T( "LastName" ),
+ _T( "Username" ),
+ _T( "FirstName LastName" ),
+ _T( "'(Unknown Contact)' (not moveable)" )
+};
+
+BYTE nameOrder[NAMEORDERCOUNT];
+
+static int GetDatabaseString( CONTACTINFO *ci, const char* setting, DBVARIANT* dbv )
+{
+ if ( ci->dwFlag & CNF_UNICODE )
+ return DBGetContactSettingWString(ci->hContact,ci->szProto,setting,dbv);
+
+ return DBGetContactSetting(ci->hContact,ci->szProto,setting,dbv);
+}
+
+static int ProcessDatabaseValueDefault(CONTACTINFO *ci, const char* setting)
+{
+ DBVARIANT dbv;
+ if ( GetDatabaseString( ci, setting, &dbv ))
+ return 1;
+
+ switch (dbv.type) {
+ case DBVT_ASCIIZ:
+ case DBVT_WCHAR:
+ ci->type = CNFT_ASCIIZ;
+ ci->pszVal = dbv.ptszVal;
+ return 0;
+ case DBVT_BYTE:
+ ci->type = CNFT_BYTE;
+ ci->bVal = dbv.bVal;
+ return 0;
+ case DBVT_WORD:
+ ci->type = CNFT_WORD;
+ ci->wVal = dbv.wVal;
+ return 0;
+ case DBVT_DWORD:
+ ci->type = CNFT_DWORD;
+ ci->dVal = dbv.dVal;
+ return 0;
+ }
+
+ DBFreeVariant( &dbv );
+ return 1;
+}
+
+static int GetContactInfo(WPARAM wParam, LPARAM lParam) {
+ DBVARIANT dbv;
+ CONTACTINFO *ci = (CONTACTINFO*)lParam;
+
+ if (ci==NULL) return 1;
+ if (ci->szProto==NULL) ci->szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)ci->hContact,0);
+ if (ci->szProto==NULL) return 1;
+ ci->type = 0;
+ switch(ci->dwFlag & 0x7F) {
+ case CNF_FIRSTNAME: return ProcessDatabaseValueDefault( ci, "FirstName" );
+ case CNF_LASTNAME: return ProcessDatabaseValueDefault( ci, "LastName" );
+ case CNF_NICK: return ProcessDatabaseValueDefault( ci, "Nick" );
+ case CNF_EMAIL: return ProcessDatabaseValueDefault( ci, "e-mail" );
+ case CNF_CITY: return ProcessDatabaseValueDefault( ci, "City" );
+ case CNF_STATE: return ProcessDatabaseValueDefault( ci, "State" );
+ case CNF_PHONE: return ProcessDatabaseValueDefault( ci, "Phone" );
+ case CNF_HOMEPAGE: return ProcessDatabaseValueDefault( ci, "Homepage" );
+ case CNF_ABOUT: return ProcessDatabaseValueDefault( ci, "About" );
+ case CNF_AGE: return ProcessDatabaseValueDefault( ci, "Age" );
+ case CNF_GENDER: return ProcessDatabaseValueDefault( ci, "Gender" );
+ case CNF_FAX: return ProcessDatabaseValueDefault( ci, "Fax" );
+ case CNF_CELLULAR: return ProcessDatabaseValueDefault( ci, "Cellular" );
+ case CNF_BIRTHDAY: return ProcessDatabaseValueDefault( ci, "BirthDay" );
+ case CNF_BIRTHMONTH: return ProcessDatabaseValueDefault( ci, "BirthMonth" );
+ case CNF_BIRTHYEAR: return ProcessDatabaseValueDefault( ci, "BirthYear" );
+ case CNF_STREET: return ProcessDatabaseValueDefault( ci, "Street" );
+ case CNF_ZIP: return ProcessDatabaseValueDefault( ci, "ZIP" );
+ case CNF_LANGUAGE1: return ProcessDatabaseValueDefault( ci, "Language1" );
+ case CNF_LANGUAGE2: return ProcessDatabaseValueDefault( ci, "Language2" );
+ case CNF_LANGUAGE3: return ProcessDatabaseValueDefault( ci, "Language3" );
+ case CNF_CONAME: return ProcessDatabaseValueDefault( ci, "Company" );
+ case CNF_CODEPT: return ProcessDatabaseValueDefault( ci, "CompanyDepartment" );
+ case CNF_COPOSITION: return ProcessDatabaseValueDefault( ci, "CompanyPosition" );
+ case CNF_COSTREET: return ProcessDatabaseValueDefault( ci, "CompanyStreet" );
+ case CNF_COCITY: return ProcessDatabaseValueDefault( ci, "CompanyCity" );
+ case CNF_COSTATE: return ProcessDatabaseValueDefault( ci, "CompanyState" );
+ case CNF_COZIP: return ProcessDatabaseValueDefault( ci, "CompanyZIP" );
+ case CNF_COHOMEPAGE: return ProcessDatabaseValueDefault( ci, "CompanyHomepage" );
+
+ case CNF_CUSTOMNICK:
+ {
+ char* saveProto = ci->szProto; ci->szProto = "CList";
+ if ( ci->hContact != NULL && !ProcessDatabaseValueDefault( ci, "MyHandle" )) {
+ ci->szProto = saveProto;
+ return 0;
+ }
+ ci->szProto = saveProto;
+ break;
+ }
+ case CNF_COUNTRY:
+ {
+ int i,countryCount;
+ struct CountryListEntry *countries;
+ if (!DBGetContactSetting(ci->hContact,ci->szProto,"Country",&dbv)) {
+ CallService(MS_UTILS_GETCOUNTRYLIST,(WPARAM)&countryCount,(LPARAM)&countries);
+ for(i=0;i<countryCount;i++) {
+ if(countries[i].id!=dbv.wVal) continue;
+
+ if ( ci->dwFlag & CNF_UNICODE ) {
+ int cbLen = MultiByteToWideChar( CP_ACP, 0, ( LPCSTR )countries[i].szName, -1, NULL, 0 );
+ WCHAR* buf = ( WCHAR* )mir_alloc( sizeof( WCHAR )*(cbLen+1) );
+ if ( buf != NULL )
+ MultiByteToWideChar( CP_ACP, 0, ( LPCSTR )countries[i].szName, -1, buf, cbLen );
+ ci->pszVal = ( TCHAR* )buf;
+ }
+ else ci->pszVal = ( TCHAR* )mir_strdup(countries[i].szName);
+
+ ci->type = CNFT_ASCIIZ;
+ DBFreeVariant(&dbv);
+ return 0;
+ }
+ DBFreeVariant(&dbv);
+ }
+ break;
+ }
+ case CNF_FIRSTLAST:
+ if( !GetDatabaseString( ci, "FirstName", &dbv )) {
+ DBVARIANT dbv2;
+ if(!GetDatabaseString(ci,"LastName",&dbv2)) {
+ ci->type = CNFT_ASCIIZ;
+ if ( ci->dwFlag & CNF_UNICODE ) {
+ int len = wcslen(dbv.pwszVal) + wcslen(dbv2.pwszVal) + 2;
+ WCHAR* buf = ( WCHAR* )mir_alloc( sizeof( WCHAR )*len );
+ if ( buf != NULL )
+ wcscat( wcscat( wcscpy( buf, dbv.pwszVal ), L" " ), dbv2.pwszVal );
+ ci->pszVal = ( TCHAR* )buf;
+ }
+ else {
+ int len = strlen(dbv.pszVal) + strlen(dbv2.pszVal) + 2;
+ char* buf = ( char* )mir_alloc( len );
+ if ( buf != NULL )
+ strcat( strcat( strcpy( buf, dbv.pszVal ), " " ), dbv2.pszVal );
+ ci->pszVal = ( TCHAR* )buf;
+ }
+ DBFreeVariant( &dbv );
+ DBFreeVariant( &dbv2 );
+ return 0;
+ }
+ DBFreeVariant( &dbv );
+ }
+ break;
+
+ case CNF_UNIQUEID:
+ {
+ char *uid = (char*)CallProtoService(ci->szProto,PS_GETCAPS,PFLAG_UNIQUEIDSETTING,0);
+ if ((int)uid!=CALLSERVICE_NOTFOUND&&uid)
+ if (!ProcessDatabaseValueDefault(ci,uid))
+ return 0;
+
+ break;
+ }
+ case CNF_DISPLAYNC:
+ case CNF_DISPLAY:
+ {
+ int i;
+ for( i=0; i < NAMEORDERCOUNT; i++ ) {
+ switch(nameOrder[i]) {
+ case 0: // custom name
+ {
+ // make sure we aren't in CNF_DISPLAYNC mode
+ // don't get custom name for NULL contact
+ char* saveProto = ci->szProto; ci->szProto = "CList";
+ if (ci->hContact!=NULL && (ci->dwFlag&0x7F)==CNF_DISPLAY && !ProcessDatabaseValueDefault(ci,"MyHandle")) {
+ ci->szProto = saveProto;
+ return 0;
+ }
+ ci->szProto = saveProto;
+ break;
+ }
+ case 1:
+ if ( !ProcessDatabaseValueDefault( ci, "Nick" )) // nick
+ return 0;
+ break;
+ case 2:
+ if ( !ProcessDatabaseValueDefault( ci, "FirstName" )) // First Name
+ return 0;
+ break;
+ case 3:
+ if ( !ProcessDatabaseValueDefault( ci, "e-mail" )) // E-mail
+ return 0;
+ break;
+ case 4:
+ if ( !ProcessDatabaseValueDefault( ci, "LastName" )) // Last Name
+ return 0;
+ break;
+ case 5: // Unique id
+ {
+ // protocol must define a PFLAG_UNIQUEIDSETTING
+ char *uid = (char*)CallProtoService(ci->szProto,PS_GETCAPS,PFLAG_UNIQUEIDSETTING,0);
+ if ((int)uid!=CALLSERVICE_NOTFOUND&&uid) {
+ if (!GetDatabaseString(ci,uid,&dbv)) {
+ if ( dbv.type == DBVT_BYTE || dbv.type == DBVT_WORD || dbv.type == DBVT_DWORD ) {
+ long value = (dbv.type == DBVT_BYTE) ? dbv.bVal:(dbv.type==DBVT_WORD ? dbv.wVal : dbv.dVal);
+ if ( ci->dwFlag & CNF_UNICODE ) {
+ WCHAR buf[ 40 ];
+ _ltow( value, buf, 10 );
+ ci->pszVal = ( TCHAR* )mir_wstrdup( buf );
+ }
+ else {
+ char buf[ 40 ];
+ _ltoa( value, buf, 10 );
+ ci->pszVal = ( TCHAR* )mir_strdup(buf);
+ }
+ ci->type = CNFT_ASCIIZ;
+ return 0;
+ }
+ if (dbv.type==DBVT_ASCIIZ) {
+ ci->type = CNFT_ASCIIZ;
+ ci->pszVal = dbv.ptszVal;
+ return 0;
+ } } }
+ break;
+ }
+ case 6: // first + last name
+ if(!GetDatabaseString(ci,"FirstName",&dbv)) {
+ DBVARIANT dbv2;
+ if(!GetDatabaseString(ci,"LastName",&dbv2)) {
+ ci->type = CNFT_ASCIIZ;
+
+ if ( ci->dwFlag & CNF_UNICODE ) {
+ int len = wcslen(dbv.pwszVal) + wcslen(dbv2.pwszVal) + 2;
+ WCHAR* buf = ( WCHAR* )mir_alloc( sizeof( WCHAR )*len );
+ if ( buf != NULL )
+ wcscat( wcscat( wcscpy( buf, dbv.pwszVal ), L" " ), dbv2.pwszVal );
+ ci->pszVal = ( TCHAR* )buf;
+ }
+ else {
+ int len = strlen(dbv.pszVal) + strlen(dbv2.pszVal) + 2;
+ char* buf = ( char* )mir_alloc( len );
+ if ( buf != NULL )
+ strcat( strcat( strcpy( buf, dbv.pszVal ), " " ), dbv2.pszVal );
+ ci->pszVal = ( TCHAR* )buf;
+ }
+
+ DBFreeVariant( &dbv );
+ DBFreeVariant( &dbv2 );
+ return 0;
+ }
+ DBFreeVariant( &dbv );
+ }
+ break;
+
+ case 7:
+ if ( ci->dwFlag & CNF_UNICODE )
+ ci->pszVal = ( TCHAR* )mir_wstrdup( TranslateW( L"'(Unknown Contact)'" ));
+ else
+ ci->pszVal = ( TCHAR* )mir_strdup( Translate("'(Unknown Contact)'"));
+ ci->type = CNFT_ASCIIZ;
+ return 0;
+ } } }
+ break;
+
+ case CNF_TIMEZONE: {
+ char str[80];
+ DBVARIANT dbv;
+
+ if (!DBGetContactSetting(ci->hContact,ci->szProto,"Timezone",&dbv)) {
+ sprintf(str,dbv.cVal?"GMT%+d:%02d":"GMT",-dbv.cVal/2,(dbv.cVal&1)*30);
+ if ( ci->dwFlag & CNF_UNICODE ) {
+ int cbLen = MultiByteToWideChar( CP_ACP, 0, ( LPCSTR )str, -1, NULL, 0 );
+ WCHAR* buf = ( WCHAR* )mir_alloc( sizeof( WCHAR )*(cbLen+1) );
+ if ( buf != NULL )
+ MultiByteToWideChar( CP_ACP, 0, ( LPCSTR )str, -1, buf, cbLen );
+ ci->pszVal = ( TCHAR* )buf;
+ }
+ else ci->pszVal = ( TCHAR* )mir_strdup(str);
+ ci->type = CNFT_ASCIIZ;
+ return 0;
+ }
+ break;
+ }
+ case CNF_MYNOTES: {
+ char* saveProto = ci->szProto; ci->szProto = "UserInfo";
+ if (!ProcessDatabaseValueDefault(ci,"MyNotes")) {
+ ci->szProto = saveProto;
+ return 0;
+ }
+ ci->szProto = saveProto;
+ break;
+ } }
+
+ return 1;
+}
+
+struct ContactOptionsData {
+ int dragging;
+ HTREEITEM hDragItem;
+};
+
+static BOOL CALLBACK ContactOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{ struct ContactOptionsData *dat;
+
+ dat=(struct ContactOptionsData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ { TranslateDialogDefault(hwndDlg);
+ dat=(struct ContactOptionsData*)mir_alloc(sizeof(struct ContactOptionsData));
+ SetWindowLong(hwndDlg,GWL_USERDATA,(LONG)dat);
+ dat->dragging=0;
+ SetWindowLong(GetDlgItem(hwndDlg,IDC_NAMEORDER),GWL_STYLE,GetWindowLong(GetDlgItem(hwndDlg,IDC_NAMEORDER),GWL_STYLE)|TVS_NOHSCROLL);
+ { TVINSERTSTRUCT tvis;
+ int i;
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_LAST;
+ tvis.item.mask = TVIF_TEXT|TVIF_PARAM;
+ for(i=0; i < SIZEOF(nameOrderDescr); i++ ) {
+ tvis.item.lParam = nameOrder[i];
+ tvis.item.pszText = TranslateTS( nameOrderDescr[ nameOrder[i]] );
+ TreeView_InsertItem( GetDlgItem(hwndDlg,IDC_NAMEORDER), &tvis );
+ } }
+ return TRUE;
+ }
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ if (((LPNMHDR)lParam)->code == PSN_APPLY)
+ { DBCONTACTWRITESETTING cws;
+ TVITEM tvi;
+ int i;
+ cws.szModule = "Contact";
+ cws.szSetting = "NameOrder";
+ cws.value.type = DBVT_BLOB;
+ cws.value.cpbVal = SIZEOF(nameOrderDescr);
+ cws.value.pbVal = nameOrder;
+ tvi.hItem = TreeView_GetRoot(GetDlgItem(hwndDlg,IDC_NAMEORDER));
+ i=0;
+ while( tvi.hItem != NULL ) {
+ tvi.mask = TVIF_PARAM | TVIF_HANDLE;
+ TreeView_GetItem( GetDlgItem(hwndDlg,IDC_NAMEORDER), &tvi );
+ nameOrder[i++] = (BYTE)tvi.lParam;
+ tvi.hItem = TreeView_GetNextSibling(GetDlgItem(hwndDlg,IDC_NAMEORDER),tvi.hItem);
+ }
+ CallService(MS_DB_CONTACT_WRITESETTING,(WPARAM)(HANDLE)NULL,(LPARAM)&cws);
+ CallService(MS_CLIST_INVALIDATEDISPLAYNAME,(WPARAM)INVALID_HANDLE_VALUE,0);
+ }
+ break;
+ case IDC_NAMEORDER:
+ if (((LPNMHDR)lParam)->code == TVN_BEGINDRAGA) {
+ LPNMTREEVIEWA notify = (LPNMTREEVIEWA)lParam;
+ if ( notify->itemNew.lParam==0 || notify->itemNew.lParam == SIZEOF(nameOrderDescr)-1 )
+ break;
+ SetCapture(hwndDlg);
+ dat->dragging=1;
+ dat->hDragItem=((LPNMTREEVIEW)lParam)->itemNew.hItem;
+ TreeView_SelectItem(GetDlgItem(hwndDlg,IDC_NAMEORDER),dat->hDragItem);
+ }
+ break;
+ }
+ break;
+ case WM_MOUSEMOVE:
+ if(!dat->dragging) break;
+ { TVHITTESTINFO hti;
+ hti.pt.x=(short)LOWORD(lParam);
+ hti.pt.y=(short)HIWORD(lParam);
+ ClientToScreen(hwndDlg,&hti.pt);
+ ScreenToClient(GetDlgItem(hwndDlg,IDC_NAMEORDER),&hti.pt);
+ TreeView_HitTest(GetDlgItem(hwndDlg,IDC_NAMEORDER),&hti);
+ if(hti.flags&(TVHT_ONITEM|TVHT_ONITEMRIGHT)) {
+ hti.pt.y-=TreeView_GetItemHeight(GetDlgItem(hwndDlg,IDC_NAMEORDER))/2;
+ TreeView_HitTest(GetDlgItem(hwndDlg,IDC_NAMEORDER),&hti);
+ TreeView_SetInsertMark(GetDlgItem(hwndDlg,IDC_NAMEORDER),hti.hItem,1);
+ }
+ else {
+ if(hti.flags&TVHT_ABOVE) SendDlgItemMessage(hwndDlg,IDC_NAMEORDER,WM_VSCROLL,MAKEWPARAM(SB_LINEUP,0),0);
+ if(hti.flags&TVHT_BELOW) SendDlgItemMessage(hwndDlg,IDC_NAMEORDER,WM_VSCROLL,MAKEWPARAM(SB_LINEDOWN,0),0);
+ TreeView_SetInsertMark(GetDlgItem(hwndDlg,IDC_NAMEORDER),NULL,0);
+ }
+ }
+ break;
+ case WM_LBUTTONUP:
+ if(!dat->dragging) break;
+ TreeView_SetInsertMark(GetDlgItem(hwndDlg,IDC_NAMEORDER),NULL,0);
+ dat->dragging=0;
+ ReleaseCapture();
+ { TVHITTESTINFO hti;
+ TVITEM tvi;
+ hti.pt.x=(short)LOWORD(lParam);
+ hti.pt.y=(short)HIWORD(lParam);
+ ClientToScreen(hwndDlg,&hti.pt);
+ ScreenToClient(GetDlgItem(hwndDlg,IDC_NAMEORDER),&hti.pt);
+ hti.pt.y-=TreeView_GetItemHeight(GetDlgItem(hwndDlg,IDC_NAMEORDER))/2;
+ TreeView_HitTest(GetDlgItem(hwndDlg,IDC_NAMEORDER),&hti);
+ if(dat->hDragItem==hti.hItem) break;
+ tvi.mask=TVIF_HANDLE|TVIF_PARAM;
+ tvi.hItem=hti.hItem;
+ TreeView_GetItem(GetDlgItem(hwndDlg,IDC_NAMEORDER),&tvi);
+ if(tvi.lParam == SIZEOF(nameOrderDescr)-1) break;
+ if(hti.flags&(TVHT_ONITEM|TVHT_ONITEMRIGHT)) {
+ TVINSERTSTRUCT tvis;
+ TCHAR name[128];
+ tvis.item.mask=TVIF_HANDLE|TVIF_PARAM|TVIF_TEXT|TVIF_PARAM;
+ tvis.item.stateMask=0xFFFFFFFF;
+ tvis.item.pszText=name;
+ tvis.item.cchTextMax=SIZEOF(name);
+ tvis.item.hItem=dat->hDragItem;
+ TreeView_GetItem(GetDlgItem(hwndDlg,IDC_NAMEORDER),&tvis.item);
+ TreeView_DeleteItem(GetDlgItem(hwndDlg,IDC_NAMEORDER),dat->hDragItem);
+ tvis.hParent=NULL;
+ tvis.hInsertAfter=hti.hItem;
+ TreeView_SelectItem(GetDlgItem(hwndDlg,IDC_NAMEORDER),TreeView_InsertItem(GetDlgItem(hwndDlg,IDC_NAMEORDER),&tvis));
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ }
+ break;
+ case WM_DESTROY:
+ mir_free(dat);
+ break;
+ }
+ return FALSE;
+}
+
+static int ContactOptInit(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.position = -1000000000;
+ odp.hInstance = GetModuleHandle(NULL);
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_CONTACT);
+ odp.pszGroup = "Contact List";
+ odp.pszTitle = "Contact Display";
+ odp.pfnDlgProc = ContactOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
+
+int LoadContactsModule(void) {
+ {
+ // Load the name order
+ BYTE i;
+ DBVARIANT dbv;
+
+ for(i=0; i<NAMEORDERCOUNT; i++)
+ nameOrder[i]=i;
+
+ if(!DBGetContactSetting(NULL,"Contact","NameOrder",&dbv))
+ {
+ CopyMemory(nameOrder,dbv.pbVal,dbv.cpbVal);
+ DBFreeVariant(&dbv);
+ }
+ }
+ CreateServiceFunction(MS_CONTACT_GETCONTACTINFO,GetContactInfo);
+ HookEvent(ME_OPT_INITIALISE,ContactOptInit);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/database/database.c b/miranda-wine/src/modules/database/database.c
new file mode 100644
index 0000000..ead8acd
--- /dev/null
+++ b/miranda-wine/src/modules/database/database.c
@@ -0,0 +1,377 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "profilemanager.h"
+
+
+// from the plugin loader, hate extern but the db frontend is pretty much tied
+extern PLUGINLINK pluginCoreLink;
+// contains the location of mirandaboot.ini
+extern char mirandabootini[MAX_PATH];
+
+// returns 1 if the profile path was returned, without trailing slash
+int getProfilePath(char * buf, size_t cch)
+{
+ char profiledir[MAX_PATH];
+ char exprofiledir[MAX_PATH];
+ char * p = 0;
+ // grab the base location now
+ GetModuleFileNameA(NULL, buf, cch);
+ p = strrchr(buf, '\\');
+ if ( p != 0 ) *p=0;
+ // change to this location, or "." wont expand properly
+ _chdir(buf);
+ GetPrivateProfileStringA("Database", "ProfileDir", ".", profiledir, SIZEOF(profiledir), mirandabootini);
+ // get the string containing envars and maybe relative paths
+ // get rid of the vars
+ ExpandEnvironmentStringsA(profiledir, exprofiledir, SIZEOF(exprofiledir));
+ if ( _fullpath(profiledir, exprofiledir, SIZEOF(profiledir)) != 0 ) {
+ /* XXX: really use CreateDirectory()? it only creates the last dir given a\b\c, SHCreateDirectory()
+ does what we want however thats 2000+ only */
+ DWORD dw = INVALID_FILE_ATTRIBUTES;
+ CreateDirectoryA(profiledir, NULL);
+ dw=GetFileAttributesA(profiledir);
+ if ( dw != INVALID_FILE_ATTRIBUTES && dw&FILE_ATTRIBUTE_DIRECTORY ) {
+ strncpy(buf, profiledir, cch);
+ p = strrchr(buf, '\\');
+ // if the char after '\' is null then change '\' to null
+ if ( p != 0 && *(++p)==0 ) *(--p)=0;
+ return 1;
+ }
+ }
+ // this never happens, usually C:\ is always returned
+ return 0;
+}
+
+// returns 1 if *.dat spec is matched
+int isValidProfileName(char * name)
+{
+ char * p = strrchr(name, '.');
+ if ( p ) {
+ p++;
+ if ( lstrcmpiA( p, "dat" ) == 0 ) {
+ if ( p[3] == 0 ) return 1;
+ }
+ }
+ return 0;
+}
+
+// returns 1 if a single profile (full path) is found within the profile dir
+static int getProfile1(char * szProfile, size_t cch, char * profiledir, BOOL * noProfiles)
+{
+ int rc = 1;
+ char searchspec[MAX_PATH];
+ WIN32_FIND_DATAA ffd;
+ HANDLE hFind = INVALID_HANDLE_VALUE;
+ unsigned int found=0;
+ mir_snprintf(searchspec,SIZEOF(searchspec),"%s\\*.dat", profiledir);
+ hFind = FindFirstFileA(searchspec, &ffd);
+ if ( hFind != INVALID_HANDLE_VALUE )
+ {
+ // make sure the first hit is actually a *.dat file
+ if ( !(ffd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) && isValidProfileName(ffd.cFileName) )
+ {
+ // copy the profile name early cos it might be the only one
+ mir_snprintf(szProfile, cch, "%s\\%s", profiledir, ffd.cFileName);
+ found++;
+ // this might be the only dat but there might be a few wrong things returned before another *.dat
+ while ( FindNextFileA(hFind,&ffd) ) {
+ // found another *.dat, but valid?
+ if ( !(ffd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) && isValidProfileName(ffd.cFileName) ) {
+ rc=0;
+ found++;
+ break;
+ } //if
+ } // while
+ } //if
+ FindClose(hFind);
+ }
+ if ( found == 0 && noProfiles != 0 ) {
+ *noProfiles=TRUE;
+ rc=0;
+ }
+ return rc;
+}
+
+// returns 1 if something that looks like a profile is there
+static int getProfileCmdLineArgs(char * szProfile, size_t cch)
+{
+ char *szCmdLine=GetCommandLineA();
+ char *szEndOfParam;
+ char szThisParam[1024];
+ int firstParam=1;
+
+ while(szCmdLine[0]) {
+ if(szCmdLine[0]=='"') {
+ szEndOfParam=strchr(szCmdLine+1,'"');
+ if(szEndOfParam==NULL) break;
+ lstrcpynA(szThisParam,szCmdLine+1,min( SIZEOF(szThisParam),szEndOfParam-szCmdLine));
+ szCmdLine=szEndOfParam+1;
+ }
+ else {
+ szEndOfParam=szCmdLine+strcspn(szCmdLine," \t");
+ lstrcpynA(szThisParam,szCmdLine,min( SIZEOF(szThisParam),szEndOfParam-szCmdLine+1));
+ szCmdLine=szEndOfParam;
+ }
+ while(*szCmdLine && *szCmdLine<=' ') szCmdLine++;
+ if(firstParam) {firstParam=0; continue;} //first param is executable name
+ if(szThisParam[0]=='/' || szThisParam[0]=='-') continue; //no switches supported
+ ExpandEnvironmentStringsA(szThisParam,szProfile,cch);
+ return 1;
+ }
+ return 0;
+}
+
+// returns 1 if a valid filename (incl. dat) is found, includes fully qualified path
+static int getProfileCmdLine(char * szProfile, size_t cch, char * profiledir)
+{
+ char buf[MAX_PATH];
+ HANDLE hFile;
+ int rc;
+ if ( getProfileCmdLineArgs(buf, SIZEOF(buf)) ) {
+ // have something that looks like a .dat, with or without .dat in the filename
+ if ( !isValidProfileName(buf) ) mir_snprintf(buf, SIZEOF(buf)-5,"%s.dat",buf);
+ // expand the relative to a full path , which might fail
+ if ( _fullpath(szProfile, buf, cch) != 0 ) {
+ hFile=CreateFileA(szProfile, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
+ rc=hFile != INVALID_HANDLE_VALUE;
+ CloseHandle(hFile);
+ return rc;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+// returns 1 if the profile manager should be shown
+static int showProfileManager(void)
+{
+ char Mgr[32];
+ // is control pressed?
+ if (GetAsyncKeyState(VK_CONTROL)&0x8000) return 1;
+ // wanna show it?
+ GetPrivateProfileStringA("Database", "ShowProfileMgr", "never", Mgr, SIZEOF(Mgr), mirandabootini);
+ if ( _strcmpi(Mgr,"yes") == 0 ) return 1;
+ return 0;
+}
+
+// returns 1 if a default profile should be selected instead of showing the manager.
+static int getProfileAutoRun(char * szProfile, size_t cch, char * profiledir)
+{
+ char Mgr[32];
+ char env_profile[MAX_PATH];
+ char exp_profile[MAX_PATH];
+ GetPrivateProfileStringA("Database", "ShowProfileMgr", "", Mgr, SIZEOF(Mgr), mirandabootini);
+ if ( lstrcmpiA(Mgr,"never") ) return 0;
+ GetPrivateProfileStringA("Database", "DefaultProfile", "", env_profile, SIZEOF(env_profile), mirandabootini);
+ if ( lstrlenA(env_profile) == 0 ) return 0;
+ ExpandEnvironmentStringsA(env_profile, exp_profile, SIZEOF(exp_profile));
+ mir_snprintf(szProfile, cch, "%s\\%s.dat", profiledir, exp_profile);
+ return 1;
+}
+
+
+
+// returns 1 if a profile was selected
+static int getProfile(char * szProfile, size_t cch)
+{
+ char profiledir[MAX_PATH];
+ PROFILEMANAGERDATA pd;
+ ZeroMemory(&pd,sizeof(pd));
+ getProfilePath(profiledir,SIZEOF(profiledir));
+ if ( getProfileCmdLine(szProfile, cch, profiledir) ) return 1;
+ if ( getProfileAutoRun(szProfile, cch, profiledir) ) return 1;
+ if ( !showProfileManager() && getProfile1(szProfile, cch, profiledir, &pd.noProfiles) ) return 1;
+ else {
+ pd.szProfile=szProfile;
+ pd.szProfileDir=profiledir;
+ return getProfileManager(&pd);
+ }
+}
+
+// called by the UI, return 1 on success, use link to create profile, set error if any
+int makeDatabase(char * profile, DATABASELINK * link, HWND hwndDlg)
+{
+ char buf[256];
+ int err=0;
+ // check if the file already exists
+ HANDLE hFile=CreateFileA(profile, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
+ char * file = strrchr(profile,'\\');
+ file++;
+ if ( hFile != INVALID_HANDLE_VALUE ) {
+ CloseHandle(hFile);
+ mir_snprintf(buf, SIZEOF(buf), Translate("The profile '%s' already exists. Do you want to move it to the "
+ "Recycle Bin? \n\nWARNING: The profile will be deleted if Recycle Bin is disabled.\nWARNING: A profile may contain confidential information and should be properly deleted."),file);
+ // file already exists!
+ if ( MessageBoxA(hwndDlg, buf, Translate("The profile already exists"), MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2) != IDYES ) return 0;
+ // move the file
+ {
+ char szName[MAX_PATH]; // SHFileOperation needs a "double null"
+ SHFILEOPSTRUCTA sf;
+ ZeroMemory(&sf,sizeof(sf));
+ sf.wFunc=FO_DELETE;
+ sf.pFrom=szName;
+ sf.fFlags=FOF_NOCONFIRMATION|FOF_NOERRORUI|FOF_SILENT;
+ mir_snprintf(szName, SIZEOF(szName),"%s\0",profile);
+ if ( SHFileOperationA(&sf) != 0 ) {
+ mir_snprintf(buf, SIZEOF(buf),Translate("Couldn't move '%s' to the Recycle Bin, Please select another profile name."),file);
+ MessageBoxA(0,buf,Translate("Problem moving profile"),MB_ICONINFORMATION|MB_OK);
+ return 0;
+ }
+ }
+ // now the file should be gone!
+ }
+ // ask the database to create the profile
+ if ( link->makeDatabase(profile,&err) ) {
+ mir_snprintf(buf, SIZEOF(buf),Translate("Unable to create the profile '%s', the error was %x"),file, err);
+ MessageBoxA(hwndDlg,buf,Translate("Problem creating profile"),MB_ICONERROR|MB_OK);
+ return 0;
+ }
+ // the profile has been created! woot
+ return 1;
+}
+
+// enumerate all plugins that had valid DatabasePluginInfo()
+static int FindDbPluginForProfile(char * pluginname, DATABASELINK * dblink, LPARAM lParam)
+{
+ char * szProfile = (char *) lParam;
+ if ( dblink && dblink->cbSize == sizeof(DATABASELINK) ) {
+ int err=0;
+ int rc=0;
+ // liked the profile?
+ rc=dblink->grokHeader(szProfile,&err);
+ if ( rc == 0 ) {
+ // added APIs?
+ if ( dblink->Load(szProfile, &pluginCoreLink) == 0 ) return DBPE_DONE;
+ return DBPE_HALT;
+ } else {
+ switch ( err ) {
+ case EGROKPRF_CANTREAD:
+ case EGROKPRF_UNKHEADER:
+ {
+ // just not supported.
+ return DBPE_CONT;
+ }
+ case EGROKPRF_VERNEWER:
+ case EGROKPRF_DAMAGED:
+ {
+ break;
+ }
+ }
+ return DBPE_HALT;
+ } //if
+ }
+ return DBPE_CONT;
+}
+
+typedef struct {
+ char * profile;
+ UINT msg;
+ ATOM aPath;
+ int found;
+} ENUMMIRANDAWINDOW;
+
+static BOOL CALLBACK EnumMirandaWindows(HWND hwnd, LPARAM lParam)
+{
+ TCHAR classname[256];
+ ENUMMIRANDAWINDOW * x = (ENUMMIRANDAWINDOW *)lParam;
+ DWORD res=0;
+ if ( GetClassName(hwnd,classname,SIZEOF(classname)) && lstrcmp( _T("Miranda"),classname)==0 ) {
+ if ( SendMessageTimeout(hwnd, x->msg, (WPARAM)x->aPath, 0, SMTO_ABORTIFHUNG, 100, &res) && res ) {
+ x->found++;
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static int FindMirandaForProfile(char * szProfile)
+{
+ ENUMMIRANDAWINDOW x={0};
+ x.profile=szProfile;
+ x.msg=RegisterWindowMessage( _T( "Miranda::ProcessProfile" ));
+ x.aPath=GlobalAddAtomA(szProfile);
+ EnumWindows(EnumMirandaWindows, (LPARAM)&x);
+ GlobalDeleteAtom(x.aPath);
+ return x.found;
+}
+
+int LoadDatabaseModule(void)
+{
+ int iReturn = 0;
+ char szProfile[MAX_PATH];
+ szProfile[0]=0;
+
+ // load the older basic services of the db
+ InitTime();
+
+ // find out which profile to load
+ if ( getProfile(szProfile, SIZEOF(szProfile)) )
+ {
+ int rc;
+ PLUGIN_DB_ENUM dbe;
+
+ dbe.cbSize=sizeof(PLUGIN_DB_ENUM);
+ dbe.pfnEnumCallback=( int(*) (char*,void*,LPARAM) )FindDbPluginForProfile;
+ dbe.lParam=(LPARAM)szProfile;
+
+ // find a driver to support the given profile
+ rc=CallService(MS_PLUGINS_ENUMDBPLUGINS, 0, (LPARAM)&dbe);
+ switch ( rc ) {
+ case -1: {
+ // no plugins at all
+ char buf[256];
+ char * p = strrchr(szProfile,'\\');
+ mir_snprintf(buf,SIZEOF(buf),Translate("Miranda is unable to open '%s' because you do not have any profile plugins installed.\nYou need to install dbx_3x.dll or equivalent."), p ? ++p : szProfile );
+ MessageBoxA(0,buf,Translate("No profile support installed!"),MB_OK | MB_ICONERROR);
+ break;
+ }
+ case 1: {
+ // if there were drivers but they all failed cos the file is locked, try and find the miranda which locked it
+ HANDLE hFile;
+ hFile=CreateFileA(szProfile,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
+ if ( hFile == INVALID_HANDLE_VALUE ) {
+ if ( !FindMirandaForProfile(szProfile) ) {
+ // file is locked, tried to find miranda window, but that failed too.
+ }
+ } else {
+ // file isn't locked, just no driver could open it.
+ char buf[256];
+ char * p = strrchr(szProfile,'\\');
+ mir_snprintf(buf,SIZEOF(buf),Translate("Miranda was unable to open '%s', its in an unknown format.\nThis profile might also be damaged, please run DB-tool which should be installed."), p ? ++p : szProfile);
+ MessageBoxA(0,buf,Translate("Miranda can't understand that profile"),MB_OK | MB_ICONERROR);
+ CloseHandle(hFile);
+ }
+ break;
+ }
+ }
+ iReturn = (rc != 0);
+ }
+ else
+ {
+ iReturn = 1;
+ }
+
+ return iReturn;
+}
+
diff --git a/miranda-wine/src/modules/database/dbini.c b/miranda-wine/src/modules/database/dbini.c
new file mode 100644
index 0000000..0717080
--- /dev/null
+++ b/miranda-wine/src/modules/database/dbini.c
@@ -0,0 +1,495 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "../../core/commonheaders.h"
+//#include "database.h"
+
+static HANDLE hIniChangeNotification;
+extern char mirandabootini[MAX_PATH];
+
+int GetCommandLineDbName(char *szName,int cbName)
+{
+ char *szCmdLine=GetCommandLineA();
+ char *szEndOfParam;
+ char szThisParam[1024];
+ int firstParam=1;
+
+ while(szCmdLine[0]) {
+ if(szCmdLine[0]=='"') {
+ szEndOfParam=strchr(szCmdLine+1,'"');
+ if(szEndOfParam==NULL) break;
+ lstrcpynA(szThisParam,szCmdLine+1,min(sizeof(szThisParam),szEndOfParam-szCmdLine));
+ szCmdLine=szEndOfParam+1;
+ }
+ else {
+ szEndOfParam=szCmdLine+strcspn(szCmdLine," \t");
+ lstrcpynA(szThisParam,szCmdLine,min(sizeof(szThisParam),szEndOfParam-szCmdLine+1));
+ szCmdLine=szEndOfParam;
+ }
+ while(*szCmdLine && *szCmdLine<=' ') szCmdLine++;
+ if(firstParam) {firstParam=0; continue;} //first param is executable name
+ if(szThisParam[0]=='/' || szThisParam[0]=='-') continue; //no switches supported
+ lstrcpynA(szName,szThisParam,cbName);
+ return 0;
+ }
+ return 1;
+}
+
+void GetProfileDirectory(char *szPath,int cbPath)
+{
+ char *str2;
+ char szMirandaDir[MAX_PATH],szProfileDir[MAX_PATH],szExpandedProfileDir[MAX_PATH];
+ DWORD dwAttributes;
+
+ GetModuleFileNameA(GetModuleHandle(NULL),szMirandaDir,sizeof(szMirandaDir));
+ str2=strrchr(szMirandaDir,'\\');
+ if(str2!=NULL) *str2=0;
+ GetPrivateProfileStringA("Database","ProfileDir",".",szProfileDir,sizeof(szProfileDir),mirandabootini);
+ ExpandEnvironmentStringsA(szProfileDir,szExpandedProfileDir,sizeof(szExpandedProfileDir));
+ _chdir(szMirandaDir);
+ if(!_fullpath(szPath,szExpandedProfileDir,cbPath))
+ lstrcpynA(szPath,szMirandaDir,cbPath);
+ if(szPath[lstrlenA(szPath)-1]=='\\') szPath[lstrlenA(szPath)-1]='\0';
+ if((dwAttributes=GetFileAttributesA(szPath))!=0xffffffff&&dwAttributes&FILE_ATTRIBUTE_DIRECTORY) return;
+ CreateDirectoryA(szPath,NULL);
+}
+
+int ShouldAutoCreate(void)
+{
+ char szAutoCreate[4];
+ GetPrivateProfileStringA("Database","AutoCreate","no",szAutoCreate,sizeof(szAutoCreate),mirandabootini);
+ return !lstrcmpiA(szAutoCreate,"yes");
+}
+
+int GetDefaultProfilePath(char *szPath,int cbPath,int *specified)
+{
+ char szProfileDir[MAX_PATH],szDefaultName[MAX_PATH],szExpandedDefaultName[MAX_PATH];
+ HANDLE hFind;
+ char szSearchPath[MAX_PATH],szSingleExistingPath[MAX_PATH];
+ WIN32_FIND_DATAA fd;
+
+ if(specified) *specified=1;
+ GetProfileDirectory(szProfileDir,sizeof(szProfileDir));
+ if(GetCommandLineDbName(szDefaultName,sizeof(szDefaultName))) {
+ if(specified) *specified=0;
+ GetPrivateProfileStringA("Database","DefaultProfile","",szDefaultName,sizeof(szDefaultName),mirandabootini);
+ }
+ ExpandEnvironmentStringsA(szDefaultName,szExpandedDefaultName,sizeof(szExpandedDefaultName));
+
+ _chdir(szProfileDir);
+
+ szSingleExistingPath[0]='\0';
+ lstrcpyA(szSearchPath,szProfileDir);
+ lstrcatA(szSearchPath,"\\*.dat");
+ hFind=FindFirstFileA(szSearchPath,&fd);
+ if(hFind!=INVALID_HANDLE_VALUE) {
+ if(FindNextFileA(hFind,&fd)==0)
+ if(_fullpath(szSingleExistingPath,fd.cFileName,cbPath)==NULL)
+ szSingleExistingPath[0]='\0';
+ FindClose(hFind);
+ }
+
+ if(szExpandedDefaultName[0]) {
+ lstrcatA(szExpandedDefaultName,".dat");
+ if(_fullpath(szPath,szExpandedDefaultName,cbPath)!=NULL) {
+ if(specified && !lstrcmpiA(szSingleExistingPath,szPath)) *specified=1;
+ if(!_access(szPath,0)) return 0;
+ if(ShouldAutoCreate()) {
+ HANDLE hFile;
+ if(specified && szSingleExistingPath[0]=='\0') *specified=1;
+ hFile=CreateFileA(szPath,GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_ALWAYS,0,NULL);
+ CloseHandle(hFile);
+ return 0;
+ }
+ }
+ }
+
+ if(szSingleExistingPath[0]) {
+ if(specified && szExpandedDefaultName[0]=='\0') *specified=1;
+ lstrcpynA(szPath,szSingleExistingPath,cbPath);
+ return 0;
+ }
+ return 1;
+}
+
+int ShouldShowProfileManager(void)
+{
+ char szShowValue[7];
+ char szDefaultProfile[MAX_PATH];
+ int defaultProfileSpecified;
+
+ if(GetAsyncKeyState(VK_CONTROL)&0x8000) return 1;
+ GetPrivateProfileStringA("Database","ShowProfileMgr","smart",szShowValue,sizeof(szShowValue),mirandabootini);
+ if(!lstrcmpiA(szShowValue,"always")) return 1;
+ if(!lstrcmpiA(szShowValue,"never")) {
+ return GetDefaultProfilePath(szDefaultProfile,sizeof(szDefaultProfile),NULL);
+ }
+ return GetDefaultProfilePath(szDefaultProfile,sizeof(szDefaultProfile),&defaultProfileSpecified)
+ || !defaultProfileSpecified;
+}
+
+static BOOL CALLBACK InstallIniDlgProc(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ switch(message) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SetDlgItemTextA(hwndDlg,IDC_ININAME,(char*)lParam);
+ { char szSecurity[11],*pszSecurityInfo;
+ GetPrivateProfileStringA("AutoExec","Warn","notsafe",szSecurity,sizeof(szSecurity),mirandabootini);
+ if(!lstrcmpiA(szSecurity,"all"))
+ pszSecurityInfo="Security systems to prevent malicious changes are in place and you will be warned before every change that is made.";
+ else if(!lstrcmpiA(szSecurity,"onlyunsafe"))
+ pszSecurityInfo="Security systems to prevent malicious changes are in place and you will be warned before changes that are known to be unsafe.";
+ else if(!lstrcmpiA(szSecurity,"none"))
+ pszSecurityInfo="Security systems to prevent malicious changes have been disabled. You will receive no further warnings.";
+ else pszSecurityInfo=NULL;
+ if(pszSecurityInfo) SetDlgItemTextA(hwndDlg,IDC_SECURITYINFO,ServiceExists(MS_LANGPACK_TRANSLATESTRING)?Translate(pszSecurityInfo):pszSecurityInfo);
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_VIEWINI:
+ { char szPath[MAX_PATH];
+ GetDlgItemTextA(hwndDlg,IDC_ININAME,szPath,sizeof(szPath));
+ ShellExecuteA(hwndDlg,"open",szPath,NULL,NULL,SW_SHOW);
+ break;
+ }
+ case IDOK:
+ case IDCANCEL:
+ case IDC_NOTOALL:
+ EndDialog(hwndDlg,LOWORD(wParam));
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static int IsInSpaceSeparatedList(const char *szWord,const char *szList)
+{
+ char *szItem,*szEnd;
+ int wordLen=lstrlenA(szWord);
+
+ for(szItem=(char*)szList;;) {
+ szEnd=strchr(szItem,' ');
+ if(szEnd==NULL) return !lstrcmpA(szItem,szWord);
+ if(szEnd-szItem==wordLen) {
+ if(!strncmp(szItem,szWord,wordLen)) return 1;
+ }
+ szItem=szEnd+1;
+ }
+ return 0;
+}
+
+struct warnSettingChangeInfo_t {
+ char *szIniPath;
+ char *szSection;
+ char *szSafeSections;
+ char *szUnsafeSections;
+ char *szName;
+ char *szValue;
+ int warnNoMore,cancel;
+};
+
+static BOOL CALLBACK WarnIniChangeDlgProc(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ static struct warnSettingChangeInfo_t *warnInfo;
+
+ switch(message) {
+ case WM_INITDIALOG:
+ { char szSettingName[256];
+ char *pszSecurityInfo;
+ warnInfo=(struct warnSettingChangeInfo_t*)lParam;
+ TranslateDialogDefault(hwndDlg);
+ SetDlgItemTextA(hwndDlg,IDC_ININAME,warnInfo->szIniPath);
+ lstrcpyA(szSettingName,warnInfo->szSection);
+ lstrcatA(szSettingName," / ");
+ lstrcatA(szSettingName,warnInfo->szName);
+ SetDlgItemTextA(hwndDlg,IDC_SETTINGNAME,szSettingName);
+ SetDlgItemTextA(hwndDlg,IDC_NEWVALUE,warnInfo->szValue);
+ if(IsInSpaceSeparatedList(warnInfo->szSection,warnInfo->szSafeSections))
+ pszSecurityInfo="This change is known to be safe.";
+ else if(IsInSpaceSeparatedList(warnInfo->szSection,warnInfo->szUnsafeSections))
+ pszSecurityInfo="This change is known to be potentially hazardous.";
+ else
+ pszSecurityInfo="This change is not known to be safe.";
+ SetDlgItemTextA(hwndDlg,IDC_SECURITYINFO,ServiceExists(MS_LANGPACK_TRANSLATESTRING)?Translate(pszSecurityInfo):pszSecurityInfo);
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ warnInfo->cancel=1;
+ case IDYES:
+ case IDNO:
+ warnInfo->warnNoMore=IsDlgButtonChecked(hwndDlg,IDC_WARNNOMORE);
+ EndDialog(hwndDlg,LOWORD(wParam));
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK IniImportDoneDlgProc(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ switch(message) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SetDlgItemTextA(hwndDlg,IDC_ININAME,(char*)lParam);
+ SetDlgItemTextA(hwndDlg,IDC_NEWNAME,(char*)lParam);
+ return TRUE;
+ case WM_COMMAND:
+ { char szIniPath[MAX_PATH];
+ GetDlgItemTextA(hwndDlg,IDC_ININAME,szIniPath,sizeof(szIniPath));
+ switch(LOWORD(wParam)) {
+ case IDC_DELETE:
+ DeleteFileA(szIniPath);
+ case IDC_LEAVE:
+ EndDialog(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_RECYCLE:
+ { SHFILEOPSTRUCTA shfo={0};
+ shfo.wFunc=FO_DELETE;
+ shfo.pFrom=szIniPath;
+ szIniPath[lstrlenA(szIniPath)+1]='\0';
+ shfo.fFlags=FOF_NOCONFIRMATION|FOF_NOERRORUI|FOF_SILENT;
+ SHFileOperationA(&shfo);
+ }
+ EndDialog(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_MOVE:
+ { char szNewPath[MAX_PATH];
+ GetDlgItemTextA(hwndDlg,IDC_NEWNAME,szNewPath,sizeof(szNewPath));
+ MoveFileA(szIniPath,szNewPath);
+ }
+ EndDialog(hwndDlg,LOWORD(wParam));
+ break;
+ }
+ break;
+ }
+ }
+ return FALSE;
+}
+
+static void DoAutoExec(void)
+{
+ HANDLE hFind;
+ char szMirandaDir[MAX_PATH],szUse[7],szIniPath[MAX_PATH],szFindPath[MAX_PATH],szExpandedFindPath[MAX_PATH];
+ char szLine[2048];
+ char *str2;
+ WIN32_FIND_DATAA fd;
+ FILE *fp;
+ char szSection[128];
+ int lineLength;
+ char szSafeSections[2048],szUnsafeSections[2048],szSecurity[11],szOverrideSecurityFilename[MAX_PATH];
+ int warnThisSection=0;
+
+ GetPrivateProfileStringA("AutoExec","Use","prompt",szUse,sizeof(szUse),mirandabootini);
+ if(!lstrcmpiA(szUse,"no")) return;
+ GetPrivateProfileStringA("AutoExec","Safe","CLC Icons CLUI CList SkinSounds",szSafeSections,sizeof(szSafeSections),mirandabootini);
+ GetPrivateProfileStringA("AutoExec","Unsafe","ICQ MSN",szUnsafeSections,sizeof(szUnsafeSections),mirandabootini);
+ GetPrivateProfileStringA("AutoExec","Warn","notsafe",szSecurity,sizeof(szSecurity),mirandabootini);
+ GetPrivateProfileStringA("AutoExec","OverrideSecurityFilename","",szOverrideSecurityFilename,sizeof(szOverrideSecurityFilename),mirandabootini);
+ GetModuleFileNameA(GetModuleHandle(NULL),szMirandaDir,sizeof(szMirandaDir));
+ str2=strrchr(szMirandaDir,'\\');
+ if(str2!=NULL) *str2=0;
+ _chdir(szMirandaDir);
+ GetPrivateProfileStringA("AutoExec","Glob","autoexec_*.ini",szFindPath,sizeof(szFindPath),mirandabootini);
+ ExpandEnvironmentStringsA(szFindPath,szExpandedFindPath,sizeof(szExpandedFindPath));
+ hFind=FindFirstFileA(szExpandedFindPath,&fd);
+ if(hFind==INVALID_HANDLE_VALUE) return;
+ str2=strrchr(szExpandedFindPath,'\\');
+ if(str2==NULL) str2=szExpandedFindPath;
+ else str2++;
+ *str2='\0';
+ szSection[0]='\0';
+ do {
+ lstrcpyA(szIniPath,szExpandedFindPath);
+ lstrcatA(szIniPath,fd.cFileName);
+ if(!lstrcmpiA(szUse,"prompt") && lstrcmpiA(fd.cFileName,szOverrideSecurityFilename)) {
+ int result=DialogBoxParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_INSTALLINI),NULL,InstallIniDlgProc,(LPARAM)szIniPath);
+ if(result==IDC_NOTOALL) break;
+ if(result==IDCANCEL) continue;
+ }
+ fp=fopen(szIniPath,"rt");
+ while(!feof(fp)) {
+ if(fgets(szLine,sizeof(szLine),fp)==NULL) break;
+ lineLength=lstrlenA(szLine);
+ while(lineLength && (BYTE)(szLine[lineLength-1])<=' ') szLine[--lineLength]='\0';
+ if(szLine[0]==';' || szLine[0]<=' ') continue;
+ if(szLine[0]=='[') {
+ char *szEnd=strchr(szLine+1,']');
+ if(szEnd==NULL) continue;
+ if(szLine[1]=='!')
+ szSection[0]='\0';
+ else {
+ lstrcpynA(szSection,szLine+1,min(sizeof(szSection),szEnd-szLine));
+ if(!lstrcmpiA(szSecurity,"none")) warnThisSection=0;
+ else if(!lstrcmpiA(szSecurity,"notsafe"))
+ warnThisSection=!IsInSpaceSeparatedList(szSection,szSafeSections);
+ else if(!lstrcmpiA(szSecurity,"onlyunsafe"))
+ warnThisSection=IsInSpaceSeparatedList(szSection,szUnsafeSections);
+ else warnThisSection=1;
+ if(!lstrcmpiA(fd.cFileName,szOverrideSecurityFilename)) warnThisSection=0;
+ }
+ }
+ else {
+ char *szValue;
+ char szName[128];
+ struct warnSettingChangeInfo_t warnInfo;
+
+ if(szSection[0]=='\0') continue;
+ szValue=strchr(szLine,'=');
+ if(szValue==NULL) continue;
+ lstrcpynA(szName,szLine,min(sizeof(szName),szValue-szLine+1));
+ szValue++;
+ warnInfo.szIniPath=szIniPath;
+ warnInfo.szName=szName;
+ warnInfo.szSafeSections=szSafeSections;
+ warnInfo.szSection=szSection;
+ warnInfo.szUnsafeSections=szUnsafeSections;
+ warnInfo.szValue=szValue;
+ warnInfo.warnNoMore=0;
+ warnInfo.cancel=0;
+ if(!warnThisSection || IDNO!=DialogBoxParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_WARNINICHANGE),NULL,WarnIniChangeDlgProc,(LPARAM)&warnInfo)) {
+ if(warnInfo.cancel) break;
+ if(warnInfo.warnNoMore) warnThisSection=0;
+ switch(szValue[0]) {
+ case 'b':
+ case 'B':
+ DBWriteContactSettingByte(NULL,szSection,szName,(BYTE)strtol(szValue+1,NULL,0));
+ break;
+ case 'w':
+ case 'W':
+ DBWriteContactSettingWord(NULL,szSection,szName,(WORD)strtol(szValue+1,NULL,0));
+ break;
+ case 'd':
+ case 'D':
+ DBWriteContactSettingDword(NULL,szSection,szName,(DWORD)strtoul(szValue+1,NULL,0));
+ break;
+ case 'l':
+ case 'L':
+ DBDeleteContactSetting(NULL,szSection,szName);
+ break;
+ case 's':
+ case 'S':
+ DBWriteContactSettingString(NULL,szSection,szName,szValue+1);
+ break;
+ case 'u':
+ case 'U':
+ DBWriteContactSettingStringUtf(NULL,szSection,szName,szValue+1);
+ break;
+ case 'n':
+ case 'N':
+ { PBYTE buf;
+ int len;
+ char *pszValue,*pszEnd;
+ DBCONTACTWRITESETTING cws;
+
+ buf=(PBYTE)mir_alloc(lstrlenA(szValue+1));
+ for(len=0,pszValue=szValue+1;;len++) {
+ buf[len]=(BYTE)strtol(pszValue,&pszEnd,0x10);
+ if(pszValue==pszEnd) break;
+ pszValue=pszEnd;
+ }
+ cws.szModule=szSection;
+ cws.szSetting=szName;
+ cws.value.type=DBVT_BLOB;
+ cws.value.pbVal=buf;
+ cws.value.cpbVal=len;
+ CallService(MS_DB_CONTACT_WRITESETTING,(WPARAM)(HANDLE)NULL,(LPARAM)&cws);
+ mir_free(buf);
+ }
+ break;
+ default:
+ if(ServiceExists(MS_LANGPACK_TRANSLATESTRING))
+ MessageBox(NULL,TranslateT("Invalid setting type. The first character of every value must be b, w, d, l, s or n."),TranslateT("Install Database Settings"),MB_OK);
+ else
+ MessageBoxA(NULL,"Invalid setting type. The first character of every value must be b, w, d, l, s or n.","Install Database Settings",MB_OK);
+ break;
+ }
+ }
+ }
+ }
+ fclose(fp);
+ if(!lstrcmpiA(fd.cFileName,szOverrideSecurityFilename))
+ DeleteFileA(szIniPath);
+ else {
+ char szOnCompletion[8];
+ GetPrivateProfileStringA("AutoExec","OnCompletion","recycle",szOnCompletion,sizeof(szOnCompletion),mirandabootini);
+ if(!lstrcmpiA(szOnCompletion,"delete"))
+ DeleteFileA(szIniPath);
+ else if(!lstrcmpiA(szOnCompletion,"recycle")) {
+ SHFILEOPSTRUCTA shfo={0};
+ shfo.wFunc=FO_DELETE;
+ shfo.pFrom=szIniPath;
+ szIniPath[lstrlenA(szIniPath)+1]='\0';
+ shfo.fFlags=FOF_NOCONFIRMATION|FOF_NOERRORUI|FOF_SILENT;
+ SHFileOperationA(&shfo);
+ }
+ else if(!lstrcmpiA(szOnCompletion,"rename")) {
+ char szRenamePrefix[MAX_PATH];
+ char szNewPath[MAX_PATH];
+ GetPrivateProfileStringA("AutoExec","RenamePrefix","done_",szRenamePrefix,sizeof(szRenamePrefix),mirandabootini);
+ lstrcpyA(szNewPath,szExpandedFindPath);
+ lstrcatA(szNewPath,szRenamePrefix);
+ lstrcatA(szNewPath,fd.cFileName);
+ MoveFileA(szIniPath,szNewPath);
+ }
+ else if(!lstrcmpiA(szOnCompletion,"ask"))
+ DialogBoxParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_INIIMPORTDONE),NULL,IniImportDoneDlgProc,(LPARAM)szIniPath);
+ }
+ } while(FindNextFileA(hFind,&fd));
+ FindClose(hFind);
+}
+
+static int CheckIniImportNow(WPARAM wParam,LPARAM lParam)
+{
+ DoAutoExec();
+ FindNextChangeNotification(hIniChangeNotification);
+ return 0;
+}
+
+int InitIni(void)
+{
+ char szMirandaDir[MAX_PATH];
+ char *str2;
+
+ DoAutoExec();
+ GetModuleFileNameA(GetModuleHandle(NULL),szMirandaDir,sizeof(szMirandaDir));
+ str2=strrchr(szMirandaDir,'\\');
+ if(str2!=NULL) *str2=0;
+ hIniChangeNotification=FindFirstChangeNotificationA(szMirandaDir,0,FILE_NOTIFY_CHANGE_FILE_NAME);
+ if(hIniChangeNotification!=INVALID_HANDLE_VALUE) {
+ CreateServiceFunction("DB/Ini/CheckImportNow",CheckIniImportNow);
+ CallService(MS_SYSTEM_WAITONHANDLE,(WPARAM)hIniChangeNotification,(LPARAM)"DB/Ini/CheckImportNow");
+ }
+ return 0;
+}
+
+void UninitIni(void)
+{
+ CallService(MS_SYSTEM_REMOVEWAIT,(WPARAM)hIniChangeNotification,0);
+ FindCloseChangeNotification(hIniChangeNotification);
+} \ No newline at end of file
diff --git a/miranda-wine/src/modules/database/dblists.c b/miranda-wine/src/modules/database/dblists.c
new file mode 100644
index 0000000..ab656ff
--- /dev/null
+++ b/miranda-wine/src/modules/database/dblists.c
@@ -0,0 +1,149 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "dblists.h"
+
+/* a simple sorted list implementation */
+
+SortedList* List_Create( int p_limit, int p_increment )
+{
+ SortedList* result = ( SortedList* )mir_calloc( sizeof( SortedList ));
+ if ( result == NULL )
+ return(NULL);
+
+ result->increment = p_increment;
+ result->limit = p_limit;
+ return(result);
+}
+
+void List_Destroy( SortedList* p_list )
+{
+ if ( p_list == NULL )
+ return;
+
+ if ( p_list->items != NULL ) {
+ mir_free( p_list->items );
+ p_list->items = NULL;
+ }
+
+ p_list->realCount = p_list->limit = 0;
+}
+
+void* List_Find( SortedList* p_list, void* p_value )
+{
+ int index;
+
+ if ( !List_GetIndex( p_list, p_value, &index ))
+ return(NULL);
+
+ return(p_list->items[ index ]);
+}
+
+int List_GetIndex( SortedList* p_list, void* p_value, int* p_index )
+{
+ if ( p_list->sortFunc != NULL )
+ {
+ int low = 0;
+ int high = p_list->realCount-1;
+
+ while( low <= high )
+ {
+ int i = ( low+high )/2;
+ int result = p_list->sortFunc( p_list->items[ i ], p_value );
+ if ( result == 0 )
+ { *p_index = i;
+ return 1;
+ }
+
+ if ( result < 0 )
+ low = i+1;
+ else
+ high = i-1;
+ }
+
+ *p_index = low;
+ }
+ return 0;
+}
+
+int List_IndexOf( SortedList* p_list, void* p_value )
+{
+ int i;
+ for ( i=0; i < p_list->realCount; i++ )
+ if ( p_list->items[i] == p_value )
+ return i;
+
+ return -1;
+}
+
+int List_Insert( SortedList* p_list, void* p_value, int p_index)
+{
+ if ( p_value == NULL || p_index > p_list->realCount )
+ return 0;
+
+ if ( p_list->realCount == p_list->limit )
+ {
+ p_list->items = ( void** )mir_realloc( p_list->items, sizeof( void* )*(p_list->realCount + p_list->increment));
+ p_list->limit += p_list->increment;
+ }
+
+ if ( p_index < p_list->realCount )
+ memmove( p_list->items+p_index+1, p_list->items+p_index, sizeof( void* )*( p_list->realCount-p_index ));
+
+ p_list->realCount++;
+
+ p_list->items[ p_index ] = p_value;
+ return 1;
+}
+
+int List_InsertPtr( SortedList* list, void* p )
+{
+ int idx;
+ List_GetIndex( list, p, &idx );
+ return List_Insert( list, p, idx );
+}
+
+int List_Remove( SortedList* p_list, int index )
+{
+ if ( index < 0 || index > p_list->realCount )
+ return(0);
+
+ p_list->realCount--;
+ if ( p_list->realCount > index )
+ {
+ memmove( p_list->items+index, p_list->items+index+1, sizeof( void* )*( p_list->realCount-index ));
+ p_list->items[ p_list->realCount ] = NULL;
+ }
+
+ return 1;
+}
+
+int List_RemovePtr( SortedList* list, void* p )
+{
+ int idx = -1;
+ if ( List_GetIndex( list, p, &idx ))
+ List_Remove( list, idx );
+
+ return idx;
+}
diff --git a/miranda-wine/src/modules/database/dblists.h b/miranda-wine/src/modules/database/dblists.h
new file mode 100644
index 0000000..c3397ab
--- /dev/null
+++ b/miranda-wine/src/modules/database/dblists.h
@@ -0,0 +1,36 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/* a simple sorted list implementation */
+
+SortedList* List_Create( int, int );
+void List_Destroy( SortedList* );
+
+void* List_Find( SortedList*, void* );
+int List_GetIndex( SortedList*, void*, int* );
+int List_Insert( SortedList*, void*, int );
+int List_Remove( SortedList*, int );
+int List_IndexOf( SortedList*, void* );
+
+int List_InsertPtr( SortedList* list, void* p );
+int List_RemovePtr( SortedList* list, void* p );
diff --git a/miranda-wine/src/modules/database/dbtime.c b/miranda-wine/src/modules/database/dbtime.c
new file mode 100644
index 0000000..b2c9eb1
--- /dev/null
+++ b/miranda-wine/src/modules/database/dbtime.c
@@ -0,0 +1,239 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+//#include "database.h"
+
+static int daysInMonth[12]={31,28,31,30,31,30,31,31,30,31,30,31};
+static int IsLeapYear(int year)
+{
+ if(year&3) return 0;
+ if(year%100) return 1;
+ if(year%400) return 0;
+ return 1;
+}
+
+static int CompareSystemTimes(SYSTEMTIME *st,SYSTEMTIME *switchDate)
+{
+ FILETIME ft1,ft2;
+
+ if(switchDate->wYear==0) { //strange day-in-month thing
+ SYSTEMTIME tempst;
+
+ //short-circuit if the months aren't the same
+ if(st->wMonth<switchDate->wMonth) return -1;
+ if(st->wMonth>switchDate->wMonth) return 1;
+
+ tempst=*switchDate;
+ tempst.wYear=st->wYear;
+ tempst.wDay=1;
+ SystemTimeToFileTime(&tempst,&ft1);
+ FileTimeToSystemTime(&ft1,&tempst); //gets the day of week of the first of the month
+ tempst.wDay=1+(7+switchDate->wDayOfWeek-tempst.wDayOfWeek)%7;
+ if(switchDate->wDay==5) { //last wDayOfWeek in month
+ if(tempst.wMonth==2) {
+ if(IsLeapYear(tempst.wYear)) daysInMonth[1]=29;
+ else daysInMonth[1]=28;
+ }
+ tempst.wDay+=7*3; //can't be less than 4 of that day in the month
+ if(tempst.wDay+7<=daysInMonth[switchDate->wMonth-1]) tempst.wDay+=7;
+ }
+ else tempst.wDay+=7*(switchDate->wDay-1); //nth of month
+ SystemTimeToFileTime(&tempst,&ft2);
+ }
+ else {
+ switchDate->wYear=st->wYear;
+ SystemTimeToFileTime(switchDate,&ft2);
+ }
+ SystemTimeToFileTime(st,&ft1);
+ return CompareFileTime(&ft1,&ft2);
+}
+
+static int TimestampToLocal(WPARAM wParam,LPARAM lParam)
+{
+ TIME_ZONE_INFORMATION tzInfo;
+ LARGE_INTEGER liFiletime;
+ FILETIME filetime;
+ SYSTEMTIME st;
+ int iReturn = 0;
+
+ GetTimeZoneInformation(&tzInfo);
+ if(tzInfo.StandardDate.wMonth==0)
+ {
+ //no daylight savings time
+ iReturn = (int)(wParam-tzInfo.Bias*60);
+ }
+ else
+ {
+ //this huge number is the difference between 1970 and 1601 in seconds
+ liFiletime.QuadPart=((__int64)11644473600+(__int64)wParam)*10000000;
+ filetime.dwHighDateTime=liFiletime.HighPart;
+ filetime.dwLowDateTime=liFiletime.LowPart;
+ FileTimeToSystemTime(&filetime,&st);
+
+ if(tzInfo.DaylightDate.wMonth<tzInfo.StandardDate.wMonth)
+ {
+ //northern hemisphere
+ if(CompareSystemTimes(&st,&tzInfo.DaylightDate)<0 ||
+ CompareSystemTimes(&st,&tzInfo.StandardDate)>0)
+ {
+ iReturn = (int)(wParam-(tzInfo.Bias+tzInfo.StandardBias)*60);
+ }
+ else
+ {
+ iReturn = (int)(wParam-(tzInfo.Bias+tzInfo.DaylightBias)*60);
+ }
+ }
+ else
+ {
+ //southern hemisphere
+ if(CompareSystemTimes(&st,&tzInfo.StandardDate)<0 ||
+ CompareSystemTimes(&st,&tzInfo.DaylightDate)>0)
+ {
+ iReturn = (int)(wParam-(tzInfo.Bias+tzInfo.DaylightBias)*60);
+ }
+ else
+ {
+ iReturn = (int)(wParam-(tzInfo.Bias+tzInfo.StandardBias)*60);
+ }
+ }
+ }
+
+ return iReturn;
+}
+
+static int TimestampToString(WPARAM wParam,LPARAM lParam)
+{
+ DBTIMETOSTRING *tts=(DBTIMETOSTRING*)lParam;
+ LARGE_INTEGER liFiletime;
+ FILETIME filetime;
+ SYSTEMTIME st;
+ char dateTimeStr[64];
+ char *pDest,*pFormat;
+ int destCharsLeft,dateTimeStrLen;
+
+ //this huge number is the difference between 1970 and 1601 in seconds
+ liFiletime.QuadPart=((__int64)11644473600+(__int64)(DWORD)TimestampToLocal(wParam,0))*10000000;
+ filetime.dwHighDateTime=liFiletime.HighPart;
+ filetime.dwLowDateTime=liFiletime.LowPart;
+ FileTimeToSystemTime(&filetime,&st);
+ destCharsLeft=tts->cbDest;
+ for(pFormat=tts->szFormat,pDest=tts->szDest;*pFormat;pFormat++) {
+ switch(*pFormat) {
+ case 't':
+ GetTimeFormatA(LOCALE_USER_DEFAULT,TIME_NOSECONDS,&st,NULL,dateTimeStr,SIZEOF(dateTimeStr));
+ break;
+ case 's':
+ GetTimeFormatA(LOCALE_USER_DEFAULT,0,&st,NULL,dateTimeStr,SIZEOF(dateTimeStr));
+ break;
+ case 'm':
+ GetTimeFormatA(LOCALE_USER_DEFAULT,TIME_NOMINUTESORSECONDS,&st,NULL,dateTimeStr,SIZEOF(dateTimeStr));
+ break;
+ case 'd':
+ GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&st,NULL,dateTimeStr,SIZEOF(dateTimeStr));
+ break;
+ case 'D':
+ GetDateFormatA(LOCALE_USER_DEFAULT,DATE_LONGDATE,&st,NULL,dateTimeStr,SIZEOF(dateTimeStr));
+ break;
+ default:
+ if(destCharsLeft) {
+ *pDest++=*pFormat;
+ destCharsLeft--;
+ }
+ continue;
+ }
+ dateTimeStrLen=strlen(dateTimeStr);
+ if(destCharsLeft<dateTimeStrLen) dateTimeStrLen=destCharsLeft;
+ CopyMemory(pDest,dateTimeStr,dateTimeStrLen);
+ destCharsLeft-=dateTimeStrLen;
+ pDest+=dateTimeStrLen;
+ }
+ if(destCharsLeft) *pDest=0;
+ else tts->szDest[tts->cbDest-1]=0;
+ return 0;
+}
+
+#if defined( _UNICODE )
+static int TimestampToStringW(WPARAM wParam,LPARAM lParam)
+{
+ DBTIMETOSTRINGT *tts = ( DBTIMETOSTRINGT* )lParam;
+ LARGE_INTEGER liFiletime;
+ FILETIME filetime;
+ SYSTEMTIME st;
+ TCHAR dateTimeStr[64];
+ TCHAR *pDest,*pFormat;
+ int destCharsLeft, dateTimeStrLen;
+
+ //this huge number is the difference between 1970 and 1601 in seconds
+ liFiletime.QuadPart = (11644473600i64+(__int64)(DWORD)TimestampToLocal(wParam,0))*10000000;
+ filetime.dwHighDateTime = liFiletime.HighPart;
+ filetime.dwLowDateTime = liFiletime.LowPart;
+ FileTimeToSystemTime(&filetime,&st);
+ destCharsLeft = tts->cbDest;
+ for ( pFormat = tts->szFormat, pDest=tts->szDest; *pFormat; pFormat++ ) {
+ switch(*pFormat) {
+ case 't':
+ GetTimeFormat(LOCALE_USER_DEFAULT,TIME_NOSECONDS,&st,NULL,dateTimeStr,SIZEOF(dateTimeStr));
+ break;
+ case 's':
+ GetTimeFormat(LOCALE_USER_DEFAULT,0,&st,NULL,dateTimeStr,SIZEOF(dateTimeStr));
+ break;
+ case 'm':
+ GetTimeFormat(LOCALE_USER_DEFAULT,TIME_NOMINUTESORSECONDS,&st,NULL,dateTimeStr,SIZEOF(dateTimeStr));
+ break;
+ case 'd':
+ GetDateFormat(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&st,NULL,dateTimeStr,SIZEOF(dateTimeStr));
+ break;
+ case 'D':
+ GetDateFormat(LOCALE_USER_DEFAULT,DATE_LONGDATE,&st,NULL,dateTimeStr,SIZEOF(dateTimeStr));
+ break;
+ default:
+ if ( destCharsLeft ) {
+ *pDest++ = *pFormat;
+ destCharsLeft--;
+ }
+ continue;
+ }
+ dateTimeStrLen = _tcslen(dateTimeStr);
+ if (destCharsLeft < dateTimeStrLen) dateTimeStrLen = destCharsLeft;
+ CopyMemory(pDest, dateTimeStr, dateTimeStrLen*sizeof(TCHAR));
+ destCharsLeft -= dateTimeStrLen;
+ pDest += dateTimeStrLen;
+ }
+ if ( destCharsLeft ) *pDest=0;
+ else tts->szDest[ tts->cbDest-1 ] = 0;
+ return 0;
+}
+#endif
+
+int InitTime(void)
+{
+ CreateServiceFunction(MS_DB_TIME_TIMESTAMPTOLOCAL, TimestampToLocal);
+ CreateServiceFunction(MS_DB_TIME_TIMESTAMPTOSTRING, TimestampToString);
+ #if defined( _UNICODE )
+ CreateServiceFunction(MS_DB_TIME_TIMESTAMPTOSTRINGT, TimestampToStringW);
+ #else
+ CreateServiceFunction(MS_DB_TIME_TIMESTAMPTOSTRINGT, TimestampToString);
+ #endif
+ return 0;
+}
diff --git a/miranda-wine/src/modules/database/profilemanager.c b/miranda-wine/src/modules/database/profilemanager.c
new file mode 100644
index 0000000..8eeaa09
--- /dev/null
+++ b/miranda-wine/src/modules/database/profilemanager.c
@@ -0,0 +1,696 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "profilemanager.h"
+#include <sys/stat.h>
+
+#define WM_INPUTCHANGED (WM_USER + 0x3000)
+#define WM_FOCUSTEXTBOX (WM_USER + 0x3001)
+
+typedef BOOL (__cdecl *ENUMPROFILECALLBACK) (char * fullpath, char * profile, LPARAM lParam);
+
+struct DetailsPageInit {
+ int pageCount;
+ OPTIONSDIALOGPAGE *odp;
+};
+
+struct DetailsPageData {
+ DLGTEMPLATE *pTemplate;
+ HINSTANCE hInst;
+ DLGPROC dlgProc;
+ HWND hwnd;
+ int changed;
+};
+
+struct DlgProfData {
+ PROPSHEETHEADER * psh;
+ HWND hwndOK; // handle to OK button
+ PROFILEMANAGERDATA * pd;
+};
+
+struct DetailsData {
+ HINSTANCE hInstIcmp;
+ HFONT hBoldFont;
+ int pageCount;
+ int currentPage;
+ struct DetailsPageData *opd;
+ RECT rcDisplay;
+ struct DlgProfData * prof;
+};
+
+extern char mirandabootini[MAX_PATH]; // bad bad bad bad!
+static char szDefaultMirandaProfile[MAX_PATH];
+
+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 int findProfiles(char * szProfileDir, ENUMPROFILECALLBACK callback, LPARAM lParam)
+{
+ HANDLE hFind = INVALID_HANDLE_VALUE;
+ WIN32_FIND_DATAA ffd;
+ char searchspec[MAX_PATH];
+ mir_snprintf(searchspec, SIZEOF(searchspec), "%s\\*.dat", szProfileDir);
+ hFind = FindFirstFileA(searchspec, &ffd);
+ if ( hFind != INVALID_HANDLE_VALUE ) {
+ do {
+ if ( !(ffd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) && isValidProfileName(ffd.cFileName) )
+ {
+ char buf[MAX_PATH];
+ mir_snprintf(buf,SIZEOF(buf),"%s\\%s",szProfileDir, ffd.cFileName);
+ if ( !callback(buf, ffd.cFileName, lParam) ) break;
+ }
+ } while ( FindNextFileA(hFind, &ffd) );
+ FindClose(hFind);
+ return 1;
+ }
+ return 0;
+}
+
+static LRESULT CALLBACK ProfileNameValidate(HWND edit, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if ( msg==WM_CHAR ) {
+ if ( strchr(".?/\\#' ",(char)wParam&0xFF) != 0 ) return 0;
+ PostMessage(GetParent(edit),WM_INPUTCHANGED,0,0);
+ }
+ return CallWindowProc((WNDPROC)GetWindowLong(edit,GWL_USERDATA),edit,msg,wParam,lParam);
+}
+
+static int FindDbProviders(char * pluginname, DATABASELINK * dblink, LPARAM lParam)
+{
+ HWND hwndDlg = (HWND)lParam;
+ HWND hwndCombo = GetDlgItem(hwndDlg, IDC_PROFILEDRIVERS);
+ char szName[64];
+
+ if ( dblink->getFriendlyName(szName,SIZEOF(szName),1) == 0 ) {
+ // add to combo box
+ LRESULT index = SendMessageA(hwndCombo, CB_ADDSTRING, 0, (LPARAM)Translate(szName));
+ SendMessage(hwndCombo, CB_SETITEMDATA, index, (LPARAM)dblink);
+ }
+ return DBPE_CONT;
+}
+
+// returns 1 if autocreation of the profile is setup, profile has to be at least MAX_PATH!
+static int checkAutoCreateProfile(char * profile)
+{
+ char ac[MAX_PATH];
+ char env_profile[MAX_PATH];
+ GetPrivateProfileStringA("Database", "AutoCreate", "no", ac, SIZEOF(ac), mirandabootini);
+ if ( lstrcmpiA(ac,"yes") != 0 ) return 0;
+ GetPrivateProfileStringA("Database", "DefaultProfile", "", ac, SIZEOF(ac), mirandabootini);
+ ExpandEnvironmentStringsA(ac, env_profile, SIZEOF(env_profile));
+ if ( profile != NULL ) strcpy(profile, env_profile);
+ return lstrlenA(env_profile) > 0;
+}
+
+static BOOL CALLBACK DlgProfileNew(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct DlgProfData * dat = (struct DlgProfData *)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault(hwndDlg);
+ // lParam = (struct DlgProfData *)
+ SetWindowLong(hwndDlg, GWL_USERDATA, lParam);
+ dat=(struct DlgProfData *)lParam;
+ {
+ // fill in the db plugins present
+ PLUGIN_DB_ENUM dbe;
+ dbe.cbSize=sizeof(dbe);
+ dbe.pfnEnumCallback=(int(*)(char*,void*,LPARAM))FindDbProviders;
+ dbe.lParam=(LPARAM)hwndDlg;
+ if ( CallService(MS_PLUGINS_ENUMDBPLUGINS,0,(LPARAM)&dbe) == (-1) ) {
+ // no plugins?!
+ EnableWindow(GetDlgItem(hwndDlg,IDC_PROFILEDRIVERS),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_PROFILENAME),FALSE);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_NODBDRIVERS),TRUE);
+ } //if
+ // default item
+ SendDlgItemMessage(hwndDlg, IDC_PROFILEDRIVERS, CB_SETCURSEL, 0, 0);
+ }
+ // subclass the profile name box
+ {
+ HWND hwndProfile=GetDlgItem(hwndDlg, IDC_PROFILENAME);
+ WNDPROC proc = (WNDPROC)GetWindowLong(hwndProfile, GWL_WNDPROC);
+ SetWindowLong(hwndProfile,GWL_USERDATA,(LONG)proc);
+ SetWindowLong(hwndProfile,GWL_WNDPROC,(LONG)ProfileNameValidate);
+ }
+ // decide if there is a default profile name given in the INI and if it should be used
+ {
+ char profile[MAX_PATH];
+ if ( checkAutoCreateProfile((char*)&profile) ) SetDlgItemTextA(hwndDlg, IDC_PROFILENAME, profile);
+ }
+ // focus on the textbox
+ PostMessage(hwndDlg,WM_FOCUSTEXTBOX,0,0);
+ return TRUE;
+ }
+ case WM_FOCUSTEXTBOX:
+ {
+ SetFocus(GetDlgItem(hwndDlg,IDC_PROFILENAME));
+ break;
+ }
+ case WM_INPUTCHANGED: // when input in the edit box changes
+ {
+ SendMessage(GetParent(hwndDlg),PSM_CHANGED,0,0);
+ EnableWindow(dat->hwndOK, GetWindowTextLength(GetDlgItem(hwndDlg,IDC_PROFILENAME)) > 0 );
+ break;
+ }
+ case WM_SHOWWINDOW:
+ {
+ if ( wParam ) {
+ SetWindowText( dat->hwndOK, TranslateT("&Create"));
+ SendMessage(hwndDlg,WM_INPUTCHANGED,0,0);
+ }
+ break;
+ }
+ case WM_NOTIFY:
+ {
+ NMHDR * hdr = (NMHDR *)lParam;
+ if ( hdr && hdr->code == PSN_APPLY && dat && IsWindowVisible(hwndDlg) ) {
+ char szName[MAX_PATH];
+ LRESULT curSel = SendDlgItemMessage(hwndDlg,IDC_PROFILEDRIVERS,CB_GETCURSEL,0,0);
+ if ( curSel == CB_ERR ) break; // should never happen
+ GetWindowTextA(GetDlgItem(hwndDlg,IDC_PROFILENAME),szName,SIZEOF(szName));
+ if ( lstrlenA(szName) == 0 ) break;
+ mir_snprintf(dat->pd->szProfile,MAX_PATH,"%s\\%s.dat",dat->pd->szProfileDir,szName);
+ dat->pd->newProfile=1;
+ dat->pd->dblink=(DATABASELINK *)SendDlgItemMessage(hwndDlg,IDC_PROFILEDRIVERS,CB_GETITEMDATA,(WPARAM)curSel,0);
+
+ if ( makeDatabase(dat->pd->szProfile, dat->pd->dblink, hwndDlg) == 0 ) {
+ SetWindowLong(hwndDlg,DWL_MSGRESULT,PSNRET_INVALID_NOCHANGEPAGE);
+ return FALSE;
+ }
+ }
+ break;
+ }
+ }
+ return FALSE;
+}
+
+TCHAR* 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;
+}
+
+static int DetectDbProvider(char * pluginname, DATABASELINK * dblink, LPARAM lParam)
+{
+ char* fullPath = (char*)lParam;
+ int error;
+
+ if ( dblink->grokHeader( fullPath, &error ) == 0 ) {
+ dblink->getFriendlyName( fullPath, MAX_PATH, 1 );
+ //strncpy( fullPath, pluginname, MAX_PATH );
+ return DBPE_HALT;
+ }
+
+ return DBPE_CONT;
+}
+
+BOOL EnumProfilesForList(char * fullpath, char * profile, LPARAM lParam)
+{
+ HWND hwndDlg = (HWND) lParam;
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_PROFILELIST);
+ char sizeBuf[64];
+ LVITEMA item;
+ int iItem=0;
+ struct stat statbuf;
+ int bFileExists = FALSE;
+ char * p = strrchr(profile, '.');
+ strcpy(sizeBuf, "0 KB");
+ if ( p != NULL ) *p=0;
+ ZeroMemory(&item,sizeof(item));
+ item.mask = LVIF_TEXT | LVIF_IMAGE;
+ item.pszText = profile;
+ item.iItem=0;
+ item.iImage=0;
+ {
+ FILE * fp = fopen(fullpath, "r+");
+ item.iImage = fp != NULL ? 0 : 1;
+ if ( stat(fullpath, &statbuf) == 0) {
+ mir_snprintf(sizeBuf,SIZEOF(sizeBuf),"%u KB", statbuf.st_size / 1024);
+ bFileExists = TRUE;
+ }
+ if ( fp ) fclose(fp);
+ }
+ iItem=SendMessageA( hwndList, LVM_INSERTITEMA, 0, (LPARAM)&item);
+ if ( lstrcmpiA(szDefaultMirandaProfile, profile) == 0 )
+ ListView_SetItemState(hwndList, iItem, LVIS_SELECTED, LVIS_SELECTED);
+
+ item.iItem = iItem;
+ item.iSubItem = 2;
+ item.pszText = sizeBuf;
+ SendMessageA( hwndList, LVM_SETITEMTEXTA, iItem, (LPARAM)&item );
+
+ if ( bFileExists ) {
+ PLUGIN_DB_ENUM dbe;
+ char szPath[ MAX_PATH ];
+
+ LVITEM item2;
+ item2.mask = LVIF_TEXT;
+ item2.iItem = iItem;
+
+ dbe.cbSize=sizeof(dbe);
+ dbe.pfnEnumCallback=(int(*)(char*,void*,LPARAM))DetectDbProvider;
+ dbe.lParam=(LPARAM)szPath;
+ strncpy( szPath, fullpath, sizeof(szPath));
+ if (CallService(MS_PLUGINS_ENUMDBPLUGINS,0,(LPARAM)&dbe)==1) {
+ HANDLE hFile;
+
+ hFile=CreateFileA(fullpath,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
+ if (hFile == INVALID_HANDLE_VALUE) {
+ // file locked
+ item.pszText = Translate("<In Use>");
+ }
+ else {
+ CloseHandle(hFile);
+ item.pszText = szPath;
+ }
+ item.iSubItem = 1;
+ SendMessageA( hwndList, LVM_SETITEMTEXTA, iItem, (LPARAM)&item );
+ }
+
+ item2.iSubItem = 3;
+ item2.pszText = rtrim( _tctime( &statbuf.st_ctime ));
+ SendMessage( hwndList, LVM_SETITEMTEXT, iItem, (LPARAM)&item2 );
+
+ item2.iSubItem = 4;
+ item2.pszText = rtrim( _tctime( &statbuf.st_mtime ));
+ SendMessage( hwndList, LVM_SETITEMTEXT, iItem, (LPARAM)&item2 );
+ }
+ return TRUE;
+}
+
+static BOOL CALLBACK DlgProfileSelect(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct DlgProfData * dat = (struct DlgProfData *)GetWindowLong(hwndDlg, GWL_USERDATA);
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_PROFILELIST);
+ HIMAGELIST hImgList=0;
+ LVCOLUMN col;
+
+ TranslateDialogDefault(hwndDlg);
+
+ dat = (struct DlgProfData *) lParam;
+ SetWindowLong(hwndDlg,GWL_USERDATA,(LONG)dat);
+
+ // set columns
+ col.mask = LVCF_TEXT | LVCF_WIDTH;
+ col.pszText = TranslateT("Profile");
+ col.cx=122;
+ ListView_InsertColumn( hwndList, 0, &col );
+
+ col.pszText = TranslateT("Driver");
+ col.cx=100;
+ ListView_InsertColumn( hwndList, 1, &col );
+
+ col.pszText = TranslateT("Size");
+ col.cx=60;
+ ListView_InsertColumn( hwndList, 2, &col );
+
+ col.pszText = TranslateT("Created");
+ col.cx=145;
+ ListView_InsertColumn( hwndList, 3, &col );
+
+ col.pszText = TranslateT("Accessed");
+ col.cx=145;
+ ListView_InsertColumn( hwndList, 4, &col );
+
+ // icons
+ hImgList=ImageList_Create(16, 16, ILC_MASK | (IsWinVerXPPlus() ? ILC_COLOR32 : ILC_COLOR16), 1, 1);
+ ImageList_AddIcon(hImgList, LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_USERDETAILS)) );
+ ImageList_AddIcon(hImgList, LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_DELETE)) );
+ // LV will destroy the image list
+ ListView_SetImageList(hwndList, hImgList, LVSIL_SMALL);
+ // find all the profiles
+ findProfiles(dat->pd->szProfileDir, EnumProfilesForList, (LPARAM)hwndDlg);
+ PostMessage(hwndDlg,WM_FOCUSTEXTBOX,0,0);
+ return TRUE;
+ }
+ case WM_FOCUSTEXTBOX:
+ {
+ HWND hwndList=GetDlgItem(hwndDlg,IDC_PROFILELIST);
+ SetFocus(hwndList);
+ if ( lstrlenA(szDefaultMirandaProfile) == 0 || ListView_GetSelectedCount(GetDlgItem(hwndDlg,IDC_PROFILELIST)) == 0 )
+ ListView_SetItemState(hwndList, 0, LVIS_SELECTED, LVIS_SELECTED);
+ break;
+ }
+ case WM_SHOWWINDOW:
+ {
+ if ( wParam ) {
+ SetWindowText(dat->hwndOK,TranslateT("&Run"));
+ EnableWindow(dat->hwndOK, ListView_GetSelectedCount(GetDlgItem(hwndDlg,IDC_PROFILELIST))==1);
+ }
+ break;
+ }
+ case WM_NOTIFY:
+ {
+ LPNMHDR hdr = (LPNMHDR) lParam;
+ if ( hdr && hdr->code == PSN_INFOCHANGED) {
+ break;
+ }
+ if ( hdr && hdr->idFrom == IDC_PROFILELIST ) {
+ switch ( hdr->code ) {
+ case LVN_ITEMCHANGED:
+ {
+ EnableWindow(dat->hwndOK, ListView_GetSelectedCount(hdr->hwndFrom)==1);
+ }
+ case NM_DBLCLK:
+ {
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_PROFILELIST);
+ LVITEMA item;
+ char profile[MAX_PATH];
+
+ if ( dat == NULL ) break;
+ ZeroMemory(&item,sizeof(item));
+ item.mask = LVIF_TEXT;
+ item.iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED | LVNI_ALL);
+ item.pszText = profile;
+ item.cchTextMax = SIZEOF(profile);
+ if ( SendMessageA(hwndList, LVM_GETITEMA, 0, (LPARAM)&item) && dat ) {
+ mir_snprintf(dat->pd->szProfile, MAX_PATH, "%s\\%s.dat", dat->pd->szProfileDir, profile);
+ if ( hdr->code == NM_DBLCLK ) EndDialog(GetParent(hwndDlg), 1);
+ }
+ return TRUE;
+ }
+ }
+ }
+ break;
+ }
+ } //switch
+ return FALSE;
+}
+
+static BOOL CALLBACK DlgProfileManager(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct DetailsData *dat;
+
+ dat=(struct DetailsData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ struct DlgProfData * prof = (struct DlgProfData *)lParam;
+ PROPSHEETHEADER *psh = prof->psh;
+ TranslateDialogDefault(hwndDlg);
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_USERDETAILS)));
+ dat=(struct DetailsData*)mir_alloc(sizeof(struct DetailsData));
+ dat->prof = prof;
+ prof->hwndOK=GetDlgItem(hwndDlg,IDOK);
+ EnableWindow(prof->hwndOK, FALSE);
+ SetWindowLong(hwndDlg, GWL_USERDATA, (LONG)dat);
+ SetDlgItemTextA(hwndDlg,IDC_NAME,"Miranda IM Profile Manager");
+ { LOGFONT lf;
+ HFONT hNormalFont=(HFONT)SendDlgItemMessage(hwndDlg,IDC_NAME,WM_GETFONT,0,0);
+ GetObject(hNormalFont,sizeof(lf),&lf);
+ lf.lfWeight=FW_BOLD;
+ dat->hBoldFont=CreateFontIndirect(&lf);
+ SendDlgItemMessage(hwndDlg,IDC_NAME,WM_SETFONT,(WPARAM)dat->hBoldFont,0);
+ }
+ { OPTIONSDIALOGPAGE *odp;
+ int i;
+ TCITEM tci;
+
+ dat->currentPage=0;
+ dat->pageCount=psh->nPages;
+ dat->opd=(struct DetailsPageData*)mir_alloc(sizeof(struct DetailsPageData)*dat->pageCount);
+ odp=(OPTIONSDIALOGPAGE*)psh->ppsp;
+
+ tci.mask=TCIF_TEXT;
+ for(i=0;i<dat->pageCount;i++) {
+ dat->opd[i].pTemplate=(DLGTEMPLATE *)LockResource(LoadResource(odp[i].hInstance,FindResourceA(odp[i].hInstance,odp[i].pszTemplate,MAKEINTRESOURCEA(5))));
+ dat->opd[i].dlgProc=odp[i].pfnDlgProc;
+ dat->opd[i].hInst=odp[i].hInstance;
+ dat->opd[i].hwnd=NULL;
+ dat->opd[i].changed=0;
+ tci.pszText=(TCHAR*)odp[i].ptszTitle;
+ if ( dat->prof->pd->noProfiles || checkAutoCreateProfile(NULL) ) dat->currentPage=1;
+ TabCtrl_InsertItem( GetDlgItem(hwndDlg,IDC_TABS), i, &tci );
+ } }
+
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_TABS),&dat->rcDisplay);
+ TabCtrl_AdjustRect(GetDlgItem(hwndDlg,IDC_TABS),FALSE,&dat->rcDisplay);
+ {
+ POINT pt={0,0};
+ ClientToScreen(hwndDlg,&pt);
+ OffsetRect(&dat->rcDisplay,-pt.x,-pt.y);
+ }
+
+ TabCtrl_SetCurSel(GetDlgItem(hwndDlg,IDC_TABS),dat->currentPage);
+ dat->opd[dat->currentPage].hwnd=CreateDialogIndirectParam(dat->opd[dat->currentPage].hInst,dat->opd[dat->currentPage].pTemplate,hwndDlg,dat->opd[dat->currentPage].dlgProc,(LPARAM)dat->prof);
+ ThemeDialogBackground(dat->opd[dat->currentPage].hwnd);
+ SetWindowPos(dat->opd[dat->currentPage].hwnd,HWND_TOP,dat->rcDisplay.left,dat->rcDisplay.top,0,0,SWP_NOSIZE);
+ { PSHNOTIFY pshn;
+ pshn.hdr.code=PSN_INFOCHANGED;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)0;
+ SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+ ShowWindow(dat->opd[dat->currentPage].hwnd,SW_SHOW);
+ 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);
+ }
+ break;
+ case PSM_CHANGED:
+ dat->opd[dat->currentPage].changed=1;
+ return TRUE;
+ case PSM_FORCECHANGED:
+ { PSHNOTIFY pshn;
+ int i;
+
+ pshn.hdr.code=PSN_INFOCHANGED;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)0;
+ for(i=0;i<dat->pageCount;i++) {
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ if(dat->opd[i].hwnd!=NULL)
+ SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+ break;
+ }
+ case WM_NOTIFY:
+ switch(wParam) {
+ case IDC_TABS:
+ switch(((LPNMHDR)lParam)->code) {
+ case TCN_SELCHANGING:
+ { PSHNOTIFY pshn;
+ if(dat->currentPage==-1 || dat->opd[dat->currentPage].hwnd==NULL) break;
+ pshn.hdr.code=PSN_KILLACTIVE;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)0;
+ if(SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn)) {
+ SetWindowLong(hwndDlg,DWL_MSGRESULT,TRUE);
+ return TRUE;
+ }
+ break;
+ }
+ case TCN_SELCHANGE:
+ if(dat->currentPage!=-1 && dat->opd[dat->currentPage].hwnd!=NULL) ShowWindow(dat->opd[dat->currentPage].hwnd,SW_HIDE);
+ dat->currentPage=TabCtrl_GetCurSel(GetDlgItem(hwndDlg,IDC_TABS));
+ if(dat->currentPage!=-1) {
+ if(dat->opd[dat->currentPage].hwnd==NULL) {
+ PSHNOTIFY pshn;
+ dat->opd[dat->currentPage].hwnd=CreateDialogIndirectParam(dat->opd[dat->currentPage].hInst,dat->opd[dat->currentPage].pTemplate,hwndDlg,dat->opd[dat->currentPage].dlgProc,(LPARAM)dat->prof);
+ ThemeDialogBackground(dat->opd[dat->currentPage].hwnd);
+ SetWindowPos(dat->opd[dat->currentPage].hwnd,HWND_TOP,dat->rcDisplay.left,dat->rcDisplay.top,0,0,SWP_NOSIZE);
+ pshn.hdr.code=PSN_INFOCHANGED;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)0;
+ SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+ ShowWindow(dat->opd[dat->currentPage].hwnd,SW_SHOW);
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ { int i;
+ PSHNOTIFY pshn;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=0;
+ pshn.hdr.code=PSN_RESET;
+ for(i=0;i<dat->pageCount;i++) {
+ if(dat->opd[i].hwnd==NULL || !dat->opd[i].changed) continue;
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+ EndDialog(hwndDlg,0);
+ break;
+ }
+ case IDOK:
+ {
+ int i;
+ PSHNOTIFY pshn;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)0;
+ if(dat->currentPage!=-1) {
+ pshn.hdr.code=PSN_KILLACTIVE;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ if(SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn))
+ break;
+ }
+
+ pshn.hdr.code=PSN_APPLY;
+ for(i=0;i<dat->pageCount;i++) {
+ if(dat->opd[i].hwnd==NULL || !dat->opd[i].changed) continue;
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ if ( GetWindowLong(dat->opd[i].hwnd,DWL_MSGRESULT) == PSNRET_INVALID_NOCHANGEPAGE) {
+ TabCtrl_SetCurSel(GetDlgItem(hwndDlg,IDC_TABS),i);
+ if(dat->currentPage!=-1) ShowWindow(dat->opd[dat->currentPage].hwnd,SW_HIDE);
+ dat->currentPage=i;
+ ShowWindow(dat->opd[dat->currentPage].hwnd,SW_SHOW);
+ return 0;
+ }
+ }
+ EndDialog(hwndDlg,1);
+ break;
+ }
+ }
+ break;
+ case WM_DESTROY:
+ SendDlgItemMessage(hwndDlg,IDC_NAME,WM_SETFONT,SendDlgItemMessage(hwndDlg,IDC_WHITERECT,WM_GETFONT,0,0),0);
+ DeleteObject(dat->hBoldFont);
+ { int i;
+ for(i=0;i<dat->pageCount;i++)
+ if(dat->opd[i].hwnd!=NULL) DestroyWindow(dat->opd[i].hwnd);
+ }
+ mir_free(dat->opd);
+ mir_free(dat);
+ break;
+ }
+ return FALSE;
+}
+
+static int AddProfileManagerPage(struct DetailsPageInit * opi, OPTIONSDIALOGPAGE * odp)
+{
+ if(opi==NULL||odp==NULL);
+ if(odp->cbSize!=sizeof(OPTIONSDIALOGPAGE)) return 1;
+ opi->odp=(OPTIONSDIALOGPAGE*)mir_realloc(opi->odp,sizeof(OPTIONSDIALOGPAGE)*(opi->pageCount+1));
+ opi->odp[opi->pageCount].cbSize=sizeof(OPTIONSDIALOGPAGE);
+ opi->odp[opi->pageCount].hInstance=odp->hInstance;
+ opi->odp[opi->pageCount].pfnDlgProc=odp->pfnDlgProc;
+ opi->odp[opi->pageCount].position=odp->position;
+ opi->odp[opi->pageCount].ptszTitle=LangPackPcharToTchar(odp->pszTitle);
+ if((DWORD)odp->pszTemplate&0xFFFF0000) opi->odp[opi->pageCount].pszTemplate=mir_strdup(odp->pszTemplate);
+ else opi->odp[opi->pageCount].pszTemplate=odp->pszTemplate;
+ opi->odp[opi->pageCount].pszGroup=NULL;
+ opi->odp[opi->pageCount].groupPosition=odp->groupPosition;
+ opi->odp[opi->pageCount].hGroupIcon=odp->hGroupIcon;
+ opi->odp[opi->pageCount].hIcon=odp->hIcon;
+ opi->pageCount++;
+ return 0;
+}
+
+
+int getProfileManager(PROFILEMANAGERDATA * pd)
+{
+ PROPSHEETHEADER psh;
+ struct DlgProfData prof;
+ struct DetailsPageInit opi;
+ int rc=0;
+ int i;
+
+ opi.pageCount=0;
+ opi.odp=NULL;
+
+ { // remember what the default profile is, if any.
+ char defaultProfile[MAX_PATH];
+ GetPrivateProfileStringA("Database", "DefaultProfile", "", defaultProfile, SIZEOF(defaultProfile), mirandabootini);
+ ExpandEnvironmentStringsA(defaultProfile, szDefaultMirandaProfile, SIZEOF(szDefaultMirandaProfile));
+ }
+
+ {
+ OPTIONSDIALOGPAGE odp;
+ ZeroMemory(&odp,sizeof(odp));
+ odp.cbSize=sizeof(odp);
+ odp.pszTitle=Translate("My Profiles");
+ odp.pfnDlgProc=DlgProfileSelect;
+ odp.pszTemplate=MAKEINTRESOURCEA(IDD_PROFILE_SELECTION);
+ odp.hInstance=GetModuleHandle(NULL);
+ AddProfileManagerPage(&opi, &odp);
+
+ odp.pszTitle=Translate("New Profile");
+ odp.pszTemplate=MAKEINTRESOURCEA(IDD_PROFILE_NEW);
+ odp.pfnDlgProc=DlgProfileNew;
+ AddProfileManagerPage(&opi, &odp);
+ }
+
+ ZeroMemory(&psh,sizeof(psh));
+ psh.dwSize = sizeof(psh);
+ psh.dwFlags = PSH_PROPSHEETPAGE|PSH_NOAPPLYNOW;
+ psh.hwndParent = NULL;
+ psh.nPages = opi.pageCount;
+ psh.pStartPage = 0;
+ psh.ppsp = (PROPSHEETPAGE*)opi.odp;
+ prof.pd=pd;
+ prof.psh=&psh;
+ rc=DialogBoxParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_PROFILEMANAGER),NULL,DlgProfileManager,(LPARAM)&prof);
+
+ if (rc != -1)
+ {
+ for(i=0;i<opi.pageCount;i++)
+ {
+ mir_free((char*)opi.odp[i].pszTitle);
+ if(opi.odp[i].pszGroup!=NULL) mir_free(opi.odp[i].pszGroup);
+ if((DWORD)opi.odp[i].pszTemplate&0xFFFF0000) mir_free((char*)opi.odp[i].pszTemplate);
+ }
+ }
+ if ( opi.odp != NULL )
+ mir_free(opi.odp);
+
+ return rc;
+}
diff --git a/miranda-wine/src/modules/database/profilemanager.h b/miranda-wine/src/modules/database/profilemanager.h
new file mode 100644
index 0000000..5cf9191
--- /dev/null
+++ b/miranda-wine/src/modules/database/profilemanager.h
@@ -0,0 +1,37 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+typedef struct {
+ char * szProfile; // in/out
+ char * szProfileDir; // in/out
+ BOOL noProfiles; // in
+ BOOL newProfile; // out
+ DATABASELINK * dblink; // out
+} PROFILEMANAGERDATA;
+
+int InitTime(void);
+int makeDatabase(char * profile, DATABASELINK * link, HWND hwndDlg);
+int getProfileManager(PROFILEMANAGERDATA * pd);
+int getProfilePath(char * buf, size_t cch);
+int isValidProfileName(char * name);
+
diff --git a/miranda-wine/src/modules/findadd/findadd.c b/miranda-wine/src/modules/findadd/findadd.c
new file mode 100644
index 0000000..966152e
--- /dev/null
+++ b/miranda-wine/src/modules/findadd/findadd.c
@@ -0,0 +1,902 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+// TODO: Remove this
+#include <m_icq.h>
+#include "findadd.h"
+
+#define TIMERID_THROBBER 111
+
+#define HM_SEARCHACK (WM_USER+10)
+#define M_SETGROUPVISIBILITIES (WM_USER+11)
+
+static HWND hwndFindAdd=NULL;
+static HANDLE hHookModulesLoaded = 0;
+static int OnSystemModulesLoaded(WPARAM wParam,LPARAM lParam);
+
+wchar_t* a2u( char* src );
+
+void ListView_SetItemTextA( HWND hwndLV, int i, int iSubItem, char* pszText )
+{
+ LV_ITEMA _ms_lvi;
+ _ms_lvi.iSubItem = iSubItem;
+ _ms_lvi.pszText = pszText;
+ SendMessageA( hwndLV, LVM_SETITEMTEXTA, i, (LPARAM)&_ms_lvi);
+}
+
+// from msn_libstr.cpp
+static char* FindAddTrimR(char *s) {
+ char* p = s+strlen(s)-1;
+
+ while (p>=s) {
+ if (*p!=' '&&*p!='\t'&&*p!='\n'&&*p!='\r')
+ break;
+ *p--=0;
+ }
+ return s;
+}
+
+static int FindAddDlgResizer(HWND hwndDlg,LPARAM lParam,UTILRESIZECONTROL *urc)
+{
+ static int y,nextY,oldTop;
+ struct FindAddDlgData *dat;
+
+ dat=(struct FindAddDlgData*)lParam;
+ switch(urc->wId) {
+ case IDC_RESULTS:
+ return RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT;
+ case IDOK:
+ dat->minDlgHeight=nextY+urc->rcItem.bottom-urc->rcItem.top;
+ return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM;
+ case IDC_ADD:
+ case IDC_MOREOPTIONS:
+ return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM;
+ case IDC_STATUSBAR:
+ return RD_ANCHORX_WIDTH|RD_ANCHORY_BOTTOM;
+ case IDC_PROTOIDGROUP: //the resize is always processed in template order
+ nextY=y=urc->rcItem.top;
+ if(dat->showProtoId) nextY=y+urc->rcItem.bottom-urc->rcItem.top+7;
+ break;
+ case IDC_EMAILGROUP:
+ oldTop=urc->rcItem.top;
+ y=nextY;
+ if(dat->showEmail) nextY=y+urc->rcItem.bottom-urc->rcItem.top+7;
+ OffsetRect(&urc->rcItem,0,y-oldTop);
+ return RD_ANCHORX_LEFT|RD_ANCHORY_CUSTOM;
+ case IDC_NAMEGROUP:
+ oldTop=urc->rcItem.top;
+ y=nextY;
+ if(dat->showName) nextY=y+urc->rcItem.bottom-urc->rcItem.top+7;
+ OffsetRect(&urc->rcItem,0,y-oldTop);
+ return RD_ANCHORX_LEFT|RD_ANCHORY_CUSTOM;
+ case IDC_ADVANCEDGROUP:
+ oldTop=urc->rcItem.top;
+ y=nextY;
+ if(dat->showAdvanced) nextY=y+urc->rcItem.bottom-urc->rcItem.top+7;
+ OffsetRect(&urc->rcItem,0,y-oldTop);
+ return RD_ANCHORX_LEFT|RD_ANCHORY_CUSTOM;
+ case IDC_BYEMAIL:
+ case IDC_EMAIL:
+ case IDC_BYNAME:
+ case IDC_STNAMENICK:
+ case IDC_STNAMEFIRST:
+ case IDC_STNAMELAST:
+ case IDC_NAMENICK:
+ case IDC_NAMEFIRST:
+ case IDC_NAMELAST:
+ case IDC_BYADVANCED:
+ case IDC_ADVANCED:
+ OffsetRect(&urc->rcItem,0,y-oldTop);
+ return RD_ANCHORX_LEFT|RD_ANCHORY_CUSTOM;
+ }
+ return RD_ANCHORX_LEFT|RD_ANCHORY_TOP;
+}
+
+static void RenderThrobber(HDC hdc,RECT *rcItem,int *throbbing,int *pivot)
+{
+ HBRUSH hBr;
+ HDC hMemDC;
+ HBITMAP hBitmap;
+ HPEN hPen;
+ RECT rc;
+ int x,width,height,height2;
+
+ InflateRect(rcItem,-1,0);
+ width=rcItem->right-rcItem->left;
+ height=rcItem->bottom-rcItem->top;
+ height2=height/2;
+
+ if (*throbbing)
+ {
+ /* create memdc */
+ hMemDC=CreateCompatibleDC(0);
+ hBitmap=SelectObject(hMemDC, CreateCompatibleBitmap(hdc,width,height));
+ /* flush it */
+ rc.left=rc.top=0;
+ rc.right=width;
+ rc.bottom=height;
+ hBr=GetSysColorBrush(COLOR_BTNFACE);
+ FillRect(hMemDC,&rc,hBr);
+ DeleteObject(hBr);
+ /* set up the pen */
+ hPen=SelectObject(hMemDC,CreatePen(PS_SOLID,4,GetSysColor(COLOR_BTNSHADOW)));
+ /* draw everything before the pivot */
+ x=*pivot;
+ while (x>(-height))
+ {
+ MoveToEx(hMemDC,x+height2,0,NULL);
+ LineTo(hMemDC,x-height2,height);
+ x-=12;
+ } //while
+ /* draw everything after the pivot */
+ x=*pivot;
+ while (x < width+height)
+ {
+ MoveToEx(hMemDC,x+height2,0,NULL);
+ LineTo(hMemDC,x-height2,height);
+ x+=12;
+ } //while
+ /* move the pivot */
+ *pivot+=2;
+ /* reset the pivot point if it gets past the rect */
+ if (*pivot>width) *pivot=0;
+ /* put back the old pen and delete the new one */
+ DeleteObject(SelectObject(hMemDC,hPen));
+ /* cap the top and bottom */
+ hPen=SelectObject(hMemDC,CreatePen(PS_SOLID,1,GetSysColor(COLOR_BTNFACE)));
+ MoveToEx(hMemDC,0,0,NULL);
+ LineTo(hMemDC,width,0);
+ MoveToEx(hMemDC,0,height-1,NULL);
+ LineTo(hMemDC,width,height-1);
+ /* select in the old pen and delete the new pen */
+ DeleteObject(SelectObject(hMemDC,hPen));
+ /* paint to screen */
+ BitBlt(hdc,rcItem->left,rcItem->top,width,height,hMemDC,0,0,SRCCOPY);
+ /* select back in the old bitmap and delete the created one, as well as freeing the mem dc. */
+ hBitmap=SelectObject(hMemDC,hBitmap);
+ DeleteObject(hBitmap);
+ DeleteDC(hMemDC);
+ } else {
+ /* just flush the DC */
+ hBr=GetSysColorBrush(COLOR_BTNFACE);
+ FillRect(hdc,rcItem,hBr);
+ DeleteObject(hBr);
+ } //if
+}
+
+static void StartThrobber(HWND hwndDlg,struct FindAddDlgData *dat)
+{
+ dat->throbbing=1;
+ SetTimer(hwndDlg,TIMERID_THROBBER,25,NULL);
+}
+
+static void StopThrobber(HWND hwndDlg,struct FindAddDlgData *dat)
+{
+ KillTimer(hwndDlg,TIMERID_THROBBER);
+ dat->throbbing=0;
+ dat->pivot=0;
+ InvalidateRect(GetDlgItem(hwndDlg,IDC_STATUSBAR),NULL,FALSE);
+}
+
+static void ShowAdvancedSearchDlg(HWND hwndDlg,struct FindAddDlgData *dat)
+{
+ char *szProto=(char*)SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETCURSEL,0,0),0);
+ BOOL (WINAPI *MyAnimateWindow)(HWND hWnd,DWORD dwTime,DWORD dwFlags);
+
+ if(szProto==NULL) return;
+ if(dat->hwndAdvSearch==NULL) {
+ RECT rc;
+ dat->hwndAdvSearch=(HWND)CallProtoService(szProto,PS_CREATEADVSEARCHUI,0,(LPARAM)hwndDlg);
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_RESULTS),&rc);
+ SetWindowPos(dat->hwndAdvSearch,0,rc.left,rc.top,0,0,SWP_NOZORDER|SWP_NOSIZE);
+ }
+ MyAnimateWindow=(BOOL (WINAPI*)(HWND,DWORD,DWORD))GetProcAddress(GetModuleHandleA("USER32"),"AnimateWindow");
+ if(MyAnimateWindow) {
+ MyAnimateWindow(dat->hwndAdvSearch,150,AW_ACTIVATE|AW_SLIDE|AW_HOR_POSITIVE);
+ RedrawWindow(dat->hwndAdvSearch,NULL,NULL,RDW_INVALIDATE|RDW_UPDATENOW|RDW_ALLCHILDREN);
+ } else ShowWindow(dat->hwndAdvSearch,SW_SHOW);
+ CheckDlgButton(hwndDlg,IDC_ADVANCED,BST_CHECKED);
+}
+
+static void HideAdvancedSearchDlg(HWND hwndDlg,struct FindAddDlgData *dat)
+{
+ BOOL (WINAPI *MyAnimateWindow)(HWND hWnd,DWORD dwTime,DWORD dwFlags);
+
+ if(dat->hwndAdvSearch==NULL) return;
+ MyAnimateWindow=(BOOL (WINAPI*)(HWND,DWORD,DWORD))GetProcAddress(GetModuleHandleA("USER32"),"AnimateWindow");
+ if(MyAnimateWindow && IsWinVerXPPlus()) //blending is quite slow on win2k
+ MyAnimateWindow(dat->hwndAdvSearch,150,AW_HIDE|AW_BLEND);
+ else ShowWindow(dat->hwndAdvSearch,SW_HIDE);
+ CheckDlgButton(hwndDlg,IDC_ADVANCED,BST_UNCHECKED);
+}
+
+void EnableResultButtons(HWND hwndDlg,int enable)
+{
+ struct FindAddDlgData *dat;
+
+ dat=(struct FindAddDlgData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_ADD),enable);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_MOREOPTIONS),enable);
+}
+
+static void CheckSearchTypeRadioButton(HWND hwndDlg,int idControl)
+{
+ int i;
+ int controls[]={IDC_BYPROTOID,IDC_BYEMAIL,IDC_BYNAME,IDC_BYADVANCED};
+ for( i=0; i < SIZEOF(controls); i++ )
+ CheckDlgButton(hwndDlg,controls[i],idControl==controls[i]?BST_CHECKED:BST_UNCHECKED);
+}
+
+static TCHAR sttErrMsg[] = _T( "You haven't filled in the search field. Please enter a search term and try again.");
+static TCHAR sttErrTitle[] = _T( "Search" );
+
+static void SetListItemText( HWND hwndDlg, int idx, int col, char* szText )
+{
+ if ( lstrlenA( szText ))
+ ListView_SetItemTextA( GetDlgItem(hwndDlg,IDC_RESULTS), idx, col, szText );
+ else
+ ListView_SetItemText( GetDlgItem(hwndDlg,IDC_RESULTS), idx, col, TranslateT("<not specified>"));
+}
+
+static BOOL CALLBACK DlgProcFindAdd(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct FindAddDlgData *dat;
+
+ dat=(struct FindAddDlgData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ { int protoCount,i,netProtoCount;
+ PROTOCOLDESCRIPTOR **protos;
+ COMBOBOXEXITEM cbei;
+ char szProtoName[64];
+ HICON hIcon;
+
+ TranslateDialogDefault(hwndDlg);
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_FINDUSER)));
+ ListView_SetExtendedListViewStyle(GetDlgItem(hwndDlg,IDC_RESULTS),LVS_EX_FULLROWSELECT|LVS_EX_HEADERDRAGDROP);
+ dat=(struct FindAddDlgData*)mir_alloc(sizeof(struct FindAddDlgData));
+ SetWindowLong(hwndDlg,GWL_USERDATA,(LONG)dat);
+ dat->hResultHook=NULL;
+ dat->notSearchedYet=1;
+ dat->search=NULL;
+ dat->searchCount=0;
+ dat->iLastColumnSortIndex=1;
+ dat->bSortAscending=1;
+ dat->hBmpSortUp=(HBITMAP)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_SORTCOLUP),IMAGE_BITMAP,0,0,LR_LOADMAP3DCOLORS);
+ dat->hBmpSortDown=(HBITMAP)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_SORTCOLDOWN),IMAGE_BITMAP,0,0,LR_LOADMAP3DCOLORS);
+ dat->throbbing=0;
+ dat->pivot=0;
+ dat->hwndAdvSearch=NULL;
+ SendDlgItemMessage(hwndDlg,IDC_MOREOPTIONS,BUTTONSETARROW,1,0);
+
+ { LVCOLUMN lvc;
+ RECT rc;
+ LVITEM lvi;
+
+ GetClientRect(GetDlgItem(hwndDlg,IDC_RESULTS),&rc);
+ lvc.mask = LVCF_TEXT | LVCF_WIDTH;
+ lvc.pszText = TranslateT("Results");
+ lvc.cx = rc.right-1;
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_RESULTS), 0, &lvc);
+ lvi.mask=LVIF_TEXT;
+ lvi.iItem=0;
+ lvi.iSubItem=0;
+ lvi.pszText=TranslateT("There are no results to display.");
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_RESULTS), &lvi);
+ }
+
+ // Allocate a reasonable amount of space in the status bar
+ { int partWidth[3];
+ SIZE textSize;
+ HDC hdc;
+
+ hdc=GetDC(GetDlgItem(hwndDlg,IDC_STATUSBAR));
+ SelectObject(hdc,(HFONT)SendDlgItemMessage(hwndDlg,IDC_STATUSBAR,WM_GETFONT,0,0));
+ GetTextExtentPoint32(hdc,TranslateT("Searching"),lstrlen(TranslateT("Searching")),&textSize);
+ partWidth[0]=textSize.cx;
+ GetTextExtentPoint32(hdc,_T("01234567890123456789"), 20, &textSize );
+ partWidth[0]+=textSize.cx;
+ ReleaseDC(GetDlgItem(hwndDlg,IDC_STATUSBAR),hdc);
+ partWidth[1]=partWidth[0]+150;
+ partWidth[2]=-1;
+ SendDlgItemMessage(hwndDlg,IDC_STATUSBAR,SB_SETPARTS,SIZEOF(partWidth),(LPARAM)partWidth);
+ SendDlgItemMessage(hwndDlg,IDC_STATUSBAR,SB_SETTEXT,1|SBT_OWNERDRAW,0);
+ SetStatusBarSearchInfo(GetDlgItem(hwndDlg,IDC_STATUSBAR),dat);
+ }
+ {
+ char *szProto = NULL;
+ int index = 0;
+ DBVARIANT dbv={0};
+ HDC hdc;
+ SIZE textSize;
+ RECT rect;
+ int cbwidth = 0;
+ DWORD caps;
+
+ if(!DBGetContactSetting(NULL, "FindAdd", "LastSearched", &dbv))
+ szProto=(char*)dbv.pszVal;
+ CallService(MS_PROTO_ENUMPROTOCOLS,(WPARAM)&protoCount,(LPARAM)&protos);
+ for(i=0,netProtoCount=0;i<protoCount;i++) {
+ if(protos[i]->type!=PROTOTYPE_PROTOCOL) continue;
+ caps=(DWORD)CallProtoService(protos[i]->szName,PS_GETCAPS,PFLAGNUM_1,0);
+ if (caps&PF1_BASICSEARCH || caps&PF1_EXTSEARCH || caps&PF1_SEARCHBYEMAIL || caps&PF1_SEARCHBYNAME)
+ netProtoCount++;
+ }
+ dat->himlComboIcons=ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),(IsWinVerXPPlus()?ILC_COLOR32:ILC_COLOR16)|ILC_MASK,netProtoCount+1,netProtoCount+1);
+ SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CBEM_SETIMAGELIST,0,(LPARAM)dat->himlComboIcons);
+ cbei.mask=CBEIF_IMAGE|CBEIF_SELECTEDIMAGE|CBEIF_TEXT|CBEIF_LPARAM;
+ cbei.iItem=0;
+ hdc=GetDC(hwndDlg);
+ SelectObject(hdc,(HFONT)SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,WM_GETFONT,0,0));
+ if(netProtoCount>1) {
+ cbei.pszText=TranslateT("All Networks");
+ GetTextExtentPoint32(hdc,cbei.pszText,lstrlen(cbei.pszText),&textSize);
+ if (textSize.cx>cbwidth) cbwidth = textSize.cx;
+ cbei.iImage=cbei.iSelectedImage=ImageList_AddIcon(dat->himlComboIcons,LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_SEARCHALL)));
+ cbei.lParam=0;
+ SendDlgItemMessageA(hwndDlg,IDC_PROTOLIST,CBEM_INSERTITEM,0,(LPARAM)&cbei);
+ cbei.iItem++;
+ }
+ for(i=0;i<protoCount;i++) {
+ if(protos[i]->type!=PROTOTYPE_PROTOCOL) continue;
+ caps=(DWORD)CallProtoService(protos[i]->szName,PS_GETCAPS,PFLAGNUM_1,0);
+ if (!(caps&PF1_BASICSEARCH) && !(caps&PF1_EXTSEARCH) && !(caps&PF1_SEARCHBYEMAIL) && !(caps&PF1_SEARCHBYNAME))
+ continue;
+ CallProtoService(protos[i]->szName,PS_GETNAME,SIZEOF(szProtoName),(LPARAM)szProtoName);
+ #if !defined( _UNICODE )
+ cbei.pszText=(char*)szProtoName;
+ #else
+ { TCHAR wszProtoName[ 64 ];
+ MultiByteToWideChar( CP_ACP, 0, szProtoName, 64, wszProtoName, 64 );
+ cbei.pszText = wszProtoName;
+ }
+ #endif
+ GetTextExtentPoint32(hdc,cbei.pszText,lstrlen(cbei.pszText),&textSize);
+ if (textSize.cx>cbwidth) cbwidth = textSize.cx;
+ hIcon=(HICON)CallProtoService(protos[i]->szName,PS_LOADICON,PLI_PROTOCOL|PLIF_SMALL,0);
+ cbei.iImage=cbei.iSelectedImage=ImageList_AddIcon(dat->himlComboIcons,hIcon);
+ DestroyIcon(hIcon);
+ cbei.lParam=(LPARAM)protos[i]->szName;
+ SendDlgItemMessageA(hwndDlg,IDC_PROTOLIST,CBEM_INSERTITEM,0,(LPARAM)&cbei);
+ if (szProto && cbei.pszText && !lstrcmpA(szProto,szProtoName)) index=cbei.iItem;
+ cbei.iItem++;
+ }
+ cbwidth+=32;
+ SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETDROPPEDCONTROLRECT,0,(LPARAM)&rect);
+ if ((rect.right-rect.left)<cbwidth)
+ SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_SETDROPPEDWIDTH,cbwidth,0);
+ SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_SETCURSEL,index,0);
+ DBFreeVariant(&dbv); /* free string szProto was fetched with */
+ }
+ SendMessage(hwndDlg,M_SETGROUPVISIBILITIES,0,0);
+ Utils_RestoreWindowPosition(hwndDlg,NULL,"FindAdd","");
+ return TRUE;
+ }
+ case WM_SIZE:
+ { UTILRESIZEDIALOG urd={0};
+ urd.cbSize=sizeof(urd);
+ urd.hwndDlg=hwndDlg;
+ urd.hInstance=GetModuleHandle(NULL);
+ urd.lpTemplate=MAKEINTRESOURCEA(IDD_FINDADD);
+ urd.lParam=(LPARAM)dat;
+ urd.pfnResizer=FindAddDlgResizer;
+ CallService(MS_UTILS_RESIZEDIALOG,0,(LPARAM)&urd);
+ SendDlgItemMessage(hwndDlg,IDC_STATUSBAR,WM_SIZE,0,0);
+ if(dat->notSearchedYet) {
+ RECT rc;
+ GetClientRect(GetDlgItem(hwndDlg,IDC_RESULTS),&rc);
+ ListView_SetColumnWidth(GetDlgItem(hwndDlg,IDC_RESULTS),0,rc.right);
+ }
+ }
+ //fall through
+ case WM_MOVE:
+ { RECT rc;
+ if(dat->hwndAdvSearch==NULL) break;
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_RESULTS),&rc);
+ SetWindowPos(dat->hwndAdvSearch,0,rc.left,rc.top,0,0,SWP_NOZORDER|SWP_NOSIZE);
+ break;
+ }
+ case WM_GETMINMAXINFO:
+ { MINMAXINFO *mmi=(MINMAXINFO*)lParam;
+ RECT rc,rc2;
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_RESULTS),&rc);
+ GetWindowRect(hwndDlg,&rc2);
+ mmi->ptMinTrackSize.x=rc.left-rc2.left+10+GetSystemMetrics(SM_CXFRAME);
+ GetClientRect(GetDlgItem(hwndDlg,IDC_MOREOPTIONS),&rc);
+ mmi->ptMinTrackSize.x+=rc.right+5;
+ GetClientRect(GetDlgItem(hwndDlg,IDC_ADD),&rc);
+ mmi->ptMinTrackSize.x+=rc.right+5;
+ GetClientRect(GetDlgItem(hwndDlg,IDC_STATUSBAR),&rc);
+ mmi->ptMinTrackSize.y=dat->minDlgHeight+20+GetSystemMetrics(SM_CYCAPTION)+2*GetSystemMetrics(SM_CYFRAME);
+ GetClientRect(GetDlgItem(hwndDlg,IDC_STATUSBAR),&rc);
+ mmi->ptMinTrackSize.y+=rc.bottom;
+ return 0;
+ }
+ case M_SETGROUPVISIBILITIES:
+ { char *szProto;
+ int protoCount,i;
+ PROTOCOLDESCRIPTOR **protos;
+ DWORD protoCaps;
+ MINMAXINFO mmi;
+ RECT rc;
+ int checkmarkVisible;
+
+ dat->showAdvanced=dat->showEmail=dat->showName=dat->showProtoId=0;
+ szProto=(char*)SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETCURSEL,0,0),0);
+ if ( szProto == (char *)CB_ERR ) break;
+ if(szProto==NULL) {
+ CallService(MS_PROTO_ENUMPROTOCOLS,(WPARAM)&protoCount,(LPARAM)&protos);
+ for(i=0;i<protoCount;i++) {
+ if(protos[i]->type!=PROTOTYPE_PROTOCOL) continue;
+ protoCaps=(DWORD)CallProtoService(protos[i]->szName,PS_GETCAPS,PFLAGNUM_1,0);
+ if(protoCaps&PF1_SEARCHBYEMAIL) dat->showEmail=1;
+ if(protoCaps&PF1_SEARCHBYNAME) dat->showName=1;
+ }
+ }
+ else {
+ protoCaps=(DWORD)CallProtoService(szProto,PS_GETCAPS,PFLAGNUM_1,0);
+ if(protoCaps&PF1_BASICSEARCH) dat->showProtoId=1;
+ if(protoCaps&PF1_SEARCHBYEMAIL) dat->showEmail=1;
+ if(protoCaps&PF1_SEARCHBYNAME) dat->showName=1;
+ if(protoCaps&PF1_EXTSEARCHUI) dat->showAdvanced=1;
+ if(protoCaps&PF1_USERIDISEMAIL && dat->showProtoId) {dat->showProtoId=0; dat->showEmail=1;}
+ if(dat->showProtoId) {
+ char *szUniqueId;
+ szUniqueId=(char*)CallProtoService(szProto,PS_GETCAPS,PFLAG_UNIQUEIDTEXT,0);
+ if(szUniqueId) {
+ #if defined( _UNICODE )
+ TCHAR* p = a2u(szUniqueId);
+ SetDlgItemText(hwndDlg,IDC_BYPROTOID,p);
+ mir_free(p);
+ #else
+ SetDlgItemTextA(hwndDlg,IDC_BYPROTOID,szUniqueId);
+ #endif
+ }
+ else SetDlgItemText(hwndDlg,IDC_BYPROTOID,TranslateT("Handle"));
+ if(protoCaps&PF1_NUMERICUSERID) SetWindowLong(GetDlgItem(hwndDlg,IDC_PROTOID),GWL_STYLE,GetWindowLong(GetDlgItem(hwndDlg,IDC_PROTOID),GWL_STYLE)|ES_NUMBER);
+ else SetWindowLong(GetDlgItem(hwndDlg,IDC_PROTOID),GWL_STYLE,GetWindowLong(GetDlgItem(hwndDlg,IDC_PROTOID),GWL_STYLE)&~ES_NUMBER);
+ }
+ }
+#define en(id,t) ShowWindow(GetDlgItem(hwndDlg,IDC_##id),dat->show##t?SW_SHOW:SW_HIDE)
+ en(PROTOIDGROUP,ProtoId); en(BYPROTOID,ProtoId); en(PROTOID,ProtoId);
+ en(EMAILGROUP,Email); en(BYEMAIL,Email); en(EMAIL,Email);
+ en(NAMEGROUP,Name); en(BYNAME,Name);
+ en(STNAMENICK,Name); en(NAMENICK,Name);
+ en(STNAMEFIRST,Name); en(NAMEFIRST,Name);
+ en(STNAMELAST,Name); en(NAMELAST,Name);
+ en(ADVANCEDGROUP,Advanced); en(BYADVANCED,Advanced); en(ADVANCED,Advanced);
+#undef en
+ checkmarkVisible=(dat->showAdvanced && IsDlgButtonChecked(hwndDlg,IDC_BYADVANCED)) ||
+ (dat->showEmail && IsDlgButtonChecked(hwndDlg,IDC_BYEMAIL)) ||
+ (dat->showName && IsDlgButtonChecked(hwndDlg,IDC_BYNAME)) ||
+ (dat->showProtoId && IsDlgButtonChecked(hwndDlg,IDC_BYPROTOID));
+ if(!checkmarkVisible) {
+ if(dat->showProtoId) CheckSearchTypeRadioButton(hwndDlg,IDC_BYPROTOID);
+ else if(dat->showEmail) CheckSearchTypeRadioButton(hwndDlg,IDC_BYEMAIL);
+ else if(dat->showName) CheckSearchTypeRadioButton(hwndDlg,IDC_BYNAME);
+ else if(dat->showAdvanced) CheckSearchTypeRadioButton(hwndDlg,IDC_BYADVANCED);
+ }
+ SendMessage(hwndDlg,WM_SIZE,0,0);
+ SendMessage(hwndDlg,WM_GETMINMAXINFO,0,(LPARAM)&mmi);
+ GetWindowRect(hwndDlg,&rc);
+ if(rc.bottom-rc.top<mmi.ptMinTrackSize.y) SetWindowPos(hwndDlg,0,0,0,rc.right-rc.left,mmi.ptMinTrackSize.y,SWP_NOZORDER|SWP_NOMOVE);
+ break;
+ }
+ case WM_TIMER:
+ if(wParam==TIMERID_THROBBER) {
+ RECT rc;
+ HDC hdc;
+ int borders[3];
+ SendDlgItemMessage(hwndDlg,IDC_STATUSBAR,SB_GETBORDERS,0,(LPARAM)borders);
+ SendDlgItemMessage(hwndDlg,IDC_STATUSBAR,SB_GETRECT,1,(LPARAM)&rc);
+ InflateRect(&rc,-borders[2]/2,-borders[1]/2);
+ hdc=GetDC(GetDlgItem(hwndDlg,IDC_STATUSBAR));
+ RenderThrobber(hdc,&rc,&dat->throbbing,&dat->pivot);
+ ReleaseDC(GetDlgItem(hwndDlg,IDC_STATUSBAR),hdc);
+ }
+ break;
+ case WM_DRAWITEM:
+ { DRAWITEMSTRUCT *dis=(DRAWITEMSTRUCT*)lParam;
+ if(dis->CtlID==IDC_STATUSBAR && dis->itemID==1) {
+ RenderThrobber(dis->hDC,&dis->rcItem,&dat->throbbing,&dat->pivot);
+ return TRUE;
+ }
+ break;
+ }
+ case WM_NOTIFY:
+ switch(wParam)
+ {
+ case IDC_RESULTS:
+ switch(((LPNMHDR)lParam)->code) {
+ case LVN_ITEMCHANGED:
+ { int count=ListView_GetSelectedCount(GetDlgItem(hwndDlg,IDC_RESULTS));
+ if(dat->notSearchedYet) count=0;
+ EnableResultButtons(hwndDlg,count);
+ break;
+ }
+ case LVN_COLUMNCLICK:
+ {
+ LPNMLISTVIEW nmlv=(LPNMLISTVIEW)lParam;
+ HDITEM hdi;
+
+ hdi.mask=HDI_BITMAP|HDI_FORMAT;
+ hdi.fmt=HDF_LEFT|HDF_STRING;
+ Header_SetItem(ListView_GetHeader(GetDlgItem(hwndDlg,IDC_RESULTS)),dat->iLastColumnSortIndex,&hdi);
+
+ if(nmlv->iSubItem!=dat->iLastColumnSortIndex)
+ {
+ dat->bSortAscending=TRUE;
+ dat->iLastColumnSortIndex=nmlv->iSubItem;
+ }
+ else dat->bSortAscending=!dat->bSortAscending;
+
+ hdi.fmt=HDF_LEFT|HDF_BITMAP|HDF_STRING|HDF_BITMAP_ON_RIGHT;
+ hdi.hbm=dat->bSortAscending?dat->hBmpSortDown:dat->hBmpSortUp;
+ Header_SetItem(ListView_GetHeader(GetDlgItem(hwndDlg,IDC_RESULTS)),dat->iLastColumnSortIndex,&hdi);
+
+ ListView_SortItems(GetDlgItem(hwndDlg, IDC_RESULTS), SearchResultsCompareFunc, (LPARAM)dat);
+ break;
+ }
+ }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_PROTOLIST:
+ if(HIWORD(wParam)==CBN_SELCHANGE) {
+ HideAdvancedSearchDlg(hwndDlg,dat);
+ if(dat->hwndAdvSearch) {
+ DestroyWindow(dat->hwndAdvSearch);
+ dat->hwndAdvSearch=NULL;
+ }
+ SendMessage(hwndDlg,M_SETGROUPVISIBILITIES,0,0);
+ }
+ break;
+ case IDC_BYPROTOID:
+ case IDC_BYEMAIL:
+ case IDC_BYNAME:
+ HideAdvancedSearchDlg(hwndDlg,dat);
+ break;
+ case IDC_PROTOID:
+ if(HIWORD(wParam)==EN_CHANGE) {
+ HideAdvancedSearchDlg(hwndDlg,dat);
+ CheckSearchTypeRadioButton(hwndDlg,IDC_BYPROTOID);
+ }
+ break;
+ case IDC_EMAIL:
+ if(HIWORD(wParam)==EN_CHANGE) {
+ HideAdvancedSearchDlg(hwndDlg,dat);
+ CheckSearchTypeRadioButton(hwndDlg,IDC_BYEMAIL);
+ }
+ break;
+ case IDC_NAMENICK:
+ case IDC_NAMEFIRST:
+ case IDC_NAMELAST:
+ if(HIWORD(wParam)==EN_CHANGE) {
+ HideAdvancedSearchDlg(hwndDlg,dat);
+ CheckSearchTypeRadioButton(hwndDlg,IDC_BYNAME);
+ }
+ break;
+ case IDC_ADVANCED:
+ if(IsDlgButtonChecked(hwndDlg,IDC_ADVANCED))
+ ShowAdvancedSearchDlg(hwndDlg,dat);
+ else
+ HideAdvancedSearchDlg(hwndDlg,dat);
+ CheckSearchTypeRadioButton(hwndDlg,IDC_BYADVANCED);
+ break;
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ break;
+ case IDOK:
+ { char *szProto;
+
+ HideAdvancedSearchDlg(hwndDlg,dat);
+ if(dat->searchCount) { //cancel search
+ SetDlgItemText(hwndDlg,IDOK,TranslateT("&Search"));
+ if(dat->hResultHook) {UnhookEvent(dat->hResultHook); dat->hResultHook=NULL;}
+ if(dat->search) {mir_free(dat->search); dat->search=NULL;}
+ dat->searchCount=0;
+ StopThrobber(hwndDlg,dat);
+ SetStatusBarSearchInfo(GetDlgItem(hwndDlg,IDC_STATUSBAR),dat);
+ break;
+ }
+ szProto=(char*)SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETCURSEL,0,0),0);
+ if(dat->search) {mir_free(dat->search); dat->search=NULL;}
+ dat->searchCount=0;
+ dat->hResultHook=HookEventMessage(ME_PROTO_ACK,hwndDlg,HM_SEARCHACK);
+ if(IsDlgButtonChecked(hwndDlg,IDC_BYPROTOID)) {
+ char str[256];
+ GetDlgItemTextA(hwndDlg,IDC_PROTOID,str,SIZEOF(str));
+ FindAddTrimR(str);
+ if(str[0]==0)
+ MessageBox(hwndDlg,sttErrMsg,sttErrTitle,MB_OK);
+ else
+ BeginSearch(hwndDlg,dat,szProto,PS_BASICSEARCH,PF1_BASICSEARCH,str);
+ }
+ else if(IsDlgButtonChecked(hwndDlg,IDC_BYEMAIL)) {
+ char str[256];
+ GetDlgItemTextA(hwndDlg,IDC_EMAIL,str,SIZEOF(str));
+ FindAddTrimR(str);
+ if(str[0]==0)
+ MessageBox(hwndDlg,sttErrMsg,sttErrTitle,MB_OK);
+ else
+ BeginSearch(hwndDlg,dat,szProto,PS_SEARCHBYEMAIL,PF1_SEARCHBYEMAIL,str);
+ }
+ else if(IsDlgButtonChecked(hwndDlg,IDC_BYNAME)) {
+ char nick[256],first[256],last[256];
+ PROTOSEARCHBYNAME psbn;
+ GetDlgItemTextA(hwndDlg,IDC_NAMENICK,nick,SIZEOF(nick));
+ GetDlgItemTextA(hwndDlg,IDC_NAMEFIRST,first,SIZEOF(first));
+ GetDlgItemTextA(hwndDlg,IDC_NAMELAST,last,SIZEOF(last));
+ psbn.pszFirstName=first;
+ psbn.pszLastName=last;
+ psbn.pszNick=nick;
+ if(nick[0]==0 && first[0]==0 && last[0]==0)
+ MessageBox(hwndDlg,sttErrMsg,sttErrTitle,MB_OK);
+ else
+ BeginSearch(hwndDlg,dat,szProto,PS_SEARCHBYNAME,PF1_SEARCHBYNAME,&psbn);
+ }
+ else if(IsDlgButtonChecked(hwndDlg,IDC_BYADVANCED)) {
+ if(dat->hwndAdvSearch==NULL)
+ MessageBox(hwndDlg,sttErrMsg,sttErrTitle,MB_OK);
+ else
+ BeginSearch(hwndDlg,dat,szProto,PS_SEARCHBYADVANCED,PF1_EXTSEARCHUI,dat->hwndAdvSearch);
+ }
+
+ if(dat->searchCount==0) {
+ if(dat->hResultHook) {UnhookEvent(dat->hResultHook); dat->hResultHook=NULL;}
+ break;
+ }
+
+ dat->notSearchedYet=0;
+ FreeSearchResults(GetDlgItem(hwndDlg,IDC_RESULTS));
+
+ CreateResultsColumns(GetDlgItem(hwndDlg,IDC_RESULTS),dat,szProto);
+ SetStatusBarSearchInfo(GetDlgItem(hwndDlg,IDC_STATUSBAR),dat);
+ SetStatusBarResultInfo(hwndDlg,dat);
+ StartThrobber(hwndDlg,dat);
+ SetDlgItemText(hwndDlg, IDOK, TranslateT("Cancel"));
+ break;
+ }
+ case IDC_ADD:
+ { LVITEM lvi;
+ struct ListSearchResult *lsr;
+ ADDCONTACTSTRUCT acs;
+
+ if(ListView_GetSelectedCount(GetDlgItem(hwndDlg,IDC_RESULTS))!=1) break;
+ lvi.mask=LVIF_PARAM;
+ lvi.iItem=ListView_GetNextItem(GetDlgItem(hwndDlg,IDC_RESULTS),-1,LVNI_ALL|LVNI_SELECTED);
+ ListView_GetItem(GetDlgItem(hwndDlg,IDC_RESULTS),&lvi);
+ lsr=(struct ListSearchResult*)lvi.lParam;
+
+ acs.handle=NULL;
+ acs.handleType=HANDLE_SEARCHRESULT;
+ acs.szProto=lsr->szProto;
+ acs.psr=&lsr->psr;
+ CallService(MS_ADDCONTACT_SHOW,(WPARAM)hwndDlg,(LPARAM)&acs);
+ break;
+ }
+ case IDC_MOREOPTIONS:
+ { RECT rc;
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_MOREOPTIONS),&rc);
+ ShowMoreOptionsMenu(hwndDlg,rc.left,rc.bottom);
+ break;
+ }
+ }
+ break;
+ case WM_CONTEXTMENU:
+ { POINT pt;
+ LVHITTESTINFO lvhti;
+
+ pt.x=(short)LOWORD(lParam); pt.y=(short)HIWORD(lParam);
+ lvhti.pt=pt;
+ ScreenToClient(hwndDlg,&pt);
+ switch(GetDlgCtrlID(ChildWindowFromPoint(hwndDlg,pt))) {
+ case IDC_RESULTS:
+ if(dat->notSearchedYet) return TRUE;
+ ScreenToClient(GetDlgItem(hwndDlg,IDC_RESULTS),&lvhti.pt);
+ if(ListView_HitTest(GetDlgItem(hwndDlg,IDC_RESULTS),&lvhti)==-1) break;
+ ShowMoreOptionsMenu(hwndDlg,(short)LOWORD(lParam),(short)HIWORD(lParam));
+ return TRUE;
+ }
+ break;
+ }
+ case HM_SEARCHACK:
+ { ACKDATA *ack=(ACKDATA*)lParam;
+ int i;
+
+ if(ack->type!=ACKTYPE_SEARCH) break;
+ for(i=0;i<dat->searchCount;i++)
+ if(dat->search[i].hProcess==ack->hProcess && dat->search[i].hProcess != NULL && !lstrcmpA(dat->search[i].szProto,ack->szModule)) break;
+ if(i==dat->searchCount) break;
+ if(ack->result==ACKRESULT_SUCCESS) {
+ dat->searchCount--;
+ memmove(dat->search+i,dat->search+i+1,sizeof(struct ProtoSearchInfo)*(dat->searchCount-i));
+ if(dat->searchCount==0) {
+ mir_free(dat->search);
+ dat->search=NULL;
+ UnhookEvent(dat->hResultHook);
+ dat->hResultHook=NULL;
+ SetDlgItemText(hwndDlg, IDOK, TranslateT("&Search"));
+ StopThrobber(hwndDlg,dat);
+ }
+ SetStatusBarSearchInfo(GetDlgItem(hwndDlg,IDC_STATUSBAR),dat);
+ }
+ else if(ack->result==ACKRESULT_DATA) {
+ LVITEM lvi={0};
+ int i,col;
+ PROTOSEARCHRESULT *psr=(PROTOSEARCHRESULT*)ack->lParam;
+ struct ListSearchResult *lsr;
+ char *szComboProto;
+ COMBOBOXEXITEM cbei={0};
+
+ lsr=(struct ListSearchResult*)mir_alloc(offsetof(struct ListSearchResult,psr)+psr->cbSize);
+ lsr->szProto=ack->szModule;
+ CopyMemory(&lsr->psr,psr,psr->cbSize);
+ lsr->psr.email=psr->email==NULL?NULL:mir_strdup(psr->email);
+ lsr->psr.nick=psr->nick==NULL?NULL:mir_strdup(psr->nick);
+ lsr->psr.firstName=psr->firstName==NULL?NULL:mir_strdup(psr->firstName);
+ lsr->psr.lastName=psr->lastName==NULL?NULL:mir_strdup(psr->lastName);
+ lvi.mask = LVIF_PARAM|LVIF_IMAGE;
+ lvi.lParam=(LPARAM)lsr;
+ for(i=SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETCOUNT,0,0)-1;i>=0;i--) {
+ szComboProto=(char*)SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETITEMDATA,i,0);
+ if(szComboProto==NULL) continue;
+ if(!lstrcmpA(szComboProto,ack->szModule)) {
+ cbei.mask=CBEIF_IMAGE;
+ cbei.iItem=i;
+ SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CBEM_GETITEM,0,(LPARAM)&cbei);
+ lvi.iImage=cbei.iImage;
+ }
+ }
+ i=ListView_InsertItem(GetDlgItem(hwndDlg,IDC_RESULTS), &lvi);
+ col=1;
+ SetListItemText(hwndDlg, i, col++, psr->nick );
+ SetListItemText(hwndDlg, i, col++, psr->firstName );
+ SetListItemText(hwndDlg, i, col++, psr->lastName );
+ SetListItemText(hwndDlg, i, col++, psr->email );
+ if(!lstrcmpA(ack->szModule,"ICQ")) {
+ char str[15];
+ ICQSEARCHRESULT *isr=(ICQSEARCHRESULT*)psr;
+ wsprintfA(str, "%u", isr->uin);
+ ListView_SetItemTextA(GetDlgItem(hwndDlg,IDC_RESULTS),i,col++,str);
+ }
+ ListView_SortItems(GetDlgItem(hwndDlg, IDC_RESULTS), SearchResultsCompareFunc, (LPARAM)dat);
+ SetStatusBarResultInfo(hwndDlg,dat);
+ }
+ break;
+ }
+ case WM_CLOSE:
+ DestroyWindow(hwndDlg);
+ break;
+ case WM_DESTROY:
+ {
+ TCHAR *szProto;
+ int len = SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETLBTEXTLEN,SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETCURSEL,0,0),0);
+ szProto = ( TCHAR* )alloca( sizeof(TCHAR)*( len+1 ));
+ *szProto='\0';
+ SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETLBTEXT,SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETCURSEL,0,0),(LPARAM)szProto);
+ DBWriteContactSettingTString(NULL, "FindAdd", "LastSearched", szProto?szProto:_T(""));
+ }
+ SaveColumnSizes(GetDlgItem(hwndDlg,IDC_RESULTS));
+ if(dat->hResultHook!=NULL) UnhookEvent(dat->hResultHook);
+ FreeSearchResults(GetDlgItem(hwndDlg,IDC_RESULTS));
+ ImageList_Destroy(dat->himlComboIcons);
+ if(dat->search) mir_free(dat->search);
+ if(dat->hwndAdvSearch) {
+ DestroyWindow(dat->hwndAdvSearch);
+ dat->hwndAdvSearch=NULL;
+ }
+ DeleteObject(dat->hBmpSortDown);
+ DeleteObject(dat->hBmpSortUp);
+ mir_free(dat);
+ Utils_SaveWindowPosition(hwndDlg,NULL,"FindAdd","");
+ break;
+ }
+ return FALSE;
+}
+
+static int FindAddCommand(WPARAM wParam,LPARAM lParam)
+{
+ if(IsWindow(hwndFindAdd)) {
+ ShowWindow(hwndFindAdd,SW_SHOWNORMAL);
+ SetForegroundWindow(hwndFindAdd);
+ SetFocus(hwndFindAdd);
+ }
+ else {
+ INITCOMMONCONTROLSEX icce={0};
+ int netProtoCount, protoCount, i;
+ PROTOCOLDESCRIPTOR **protos;
+
+ // Make sure we have some networks to search on. This is not ideal since
+ // this check will be repeated every time the dialog is requested, but it
+ // must be done since this service can be called from other places than the menu.
+ // One alternative would be to only create the service if we have network
+ // protocols loaded but that would delay the creation until MODULE_LOADED and
+ // that is not good either...
+ CallService(MS_PROTO_ENUMPROTOCOLS,(WPARAM)&protoCount,(LPARAM)&protos);
+ for(i=0,netProtoCount=0;i<protoCount;i++)
+ if(protos[i]->type==PROTOTYPE_PROTOCOL) {
+ int protoCaps=CallProtoService(protos[i]->szName, PS_GETCAPS, PFLAGNUM_1, 0);
+ if ( protoCaps&PF1_BASICSEARCH || protoCaps&PF1_SEARCHBYEMAIL || protoCaps&PF1_SEARCHBYNAME
+ || protoCaps&PF1_EXTSEARCHUI ) netProtoCount++;
+ }
+ if (netProtoCount > 0) {
+ icce.dwSize=sizeof(icce);
+ icce.dwICC=ICC_USEREX_CLASSES;
+ InitCommonControlsEx(&icce);
+ hwndFindAdd=CreateDialog(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_FINDADD), NULL, DlgProcFindAdd);
+ }
+ }
+ return 0;
+}
+
+int FindAddPreShutdown(WPARAM wParam, LPARAM lParam)
+{
+ if (IsWindow(hwndFindAdd)) DestroyWindow(hwndFindAdd);
+ hwndFindAdd=NULL;
+ return 0;
+}
+
+int LoadFindAddModule(void)
+{
+
+ CreateServiceFunction(MS_FINDADD_FINDADD,FindAddCommand);
+ HookEvent(ME_SYSTEM_MODULESLOADED, OnSystemModulesLoaded);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN,FindAddPreShutdown);
+
+ return 0;
+}
+
+static int OnSystemModulesLoaded(WPARAM wParam,LPARAM lParam)
+{
+ CLISTMENUITEM mi;
+ int netProtoCount, protoCount, i;
+ PROTOCOLDESCRIPTOR **protos;
+
+ // Make sure we have some networks to search on.
+ CallService(MS_PROTO_ENUMPROTOCOLS,(WPARAM)&protoCount,(LPARAM)&protos);
+ for(i=0,netProtoCount=0;i<protoCount;i++)
+ if(protos[i]->type==PROTOTYPE_PROTOCOL) {
+ int protoCaps=CallProtoService(protos[i]->szName, PS_GETCAPS, PFLAGNUM_1, 0);
+ if ( protoCaps&PF1_BASICSEARCH || protoCaps&PF1_SEARCHBYEMAIL || protoCaps&PF1_SEARCHBYNAME
+ || protoCaps&PF1_EXTSEARCHUI ) netProtoCount++;
+ }
+
+ if (netProtoCount > 0) {
+ ZeroMemory(&mi, sizeof(mi));
+ mi.cbSize = sizeof(mi);
+ mi.position = 500020000;
+ mi.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_FINDUSER));
+ mi.pszName = Translate("&Find/Add Contacts...");
+ mi.pszService = MS_FINDADD_FINDADD;
+ CallService(MS_CLIST_ADDMAINMENUITEM, 0, (LPARAM)&mi);
+ }
+
+ return 0;
+
+}
+
diff --git a/miranda-wine/src/modules/findadd/findadd.h b/miranda-wine/src/modules/findadd/findadd.h
new file mode 100644
index 0000000..f8afb9c
--- /dev/null
+++ b/miranda-wine/src/modules/findadd/findadd.h
@@ -0,0 +1,57 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+struct ListSearchResult {
+ const char *szProto;
+ PROTOSEARCHRESULT psr;
+};
+
+struct ProtoSearchInfo {
+ const char *szProto;
+ HANDLE hProcess;
+};
+
+struct FindAddDlgData {
+ HANDLE hResultHook;
+ int bSortAscending;
+ int iLastColumnSortIndex;
+ HIMAGELIST himlComboIcons;
+ int showProtoId,showEmail,showName,showAdvanced;
+ int minDlgHeight;
+ int notSearchedYet;
+ struct ProtoSearchInfo *search;
+ int searchCount;
+ HBITMAP hBmpSortUp,hBmpSortDown;
+ int throbbing;
+ int pivot;
+ HWND hwndAdvSearch;
+};
+
+int CALLBACK SearchResultsCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
+void FreeSearchResults(HWND hwndResults);
+int BeginSearch(HWND hwndDlg,struct FindAddDlgData *dat,const char *szProto,const char *szSearchService,DWORD requiredCapability,void *pvSearchParams);
+void SetStatusBarSearchInfo(HWND hwndStatus,struct FindAddDlgData *dat);
+void SetStatusBarResultInfo(HWND hwndDlg,struct FindAddDlgData *dat);
+void CreateResultsColumns(HWND hwndResults,struct FindAddDlgData *dat,char *szProto);
+void EnableResultButtons(HWND hwndDlg,int enable);
+void ShowMoreOptionsMenu(HWND hwndDlg,int x,int y);
+void SaveColumnSizes(HWND hwndResults);
diff --git a/miranda-wine/src/modules/findadd/searchresults.c b/miranda-wine/src/modules/findadd/searchresults.c
new file mode 100644
index 0000000..025c90b
--- /dev/null
+++ b/miranda-wine/src/modules/findadd/searchresults.c
@@ -0,0 +1,424 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+// TODO: Remove this
+#include <m_icq.h>
+#include "findadd.h"
+
+#define COLUMNID_PROTO 0
+#define COLUMNID_NICK 1
+#define COLUMNID_FIRST 2
+#define COLUMNID_LAST 3
+#define COLUMNID_EMAIL 4
+#define COLUMNID_HANDLE 5
+
+static int handleColumnAfter=COLUMNID_EMAIL;
+
+WCHAR* a2u( const char* );
+
+void SaveColumnSizes(HWND hwndResults)
+{
+ int columnOrder[COLUMNID_HANDLE+1];
+ int columnCount;
+ char szSetting[32];
+ int i;
+ struct FindAddDlgData *dat;
+
+ dat=(struct FindAddDlgData*)GetWindowLong(GetParent(hwndResults),GWL_USERDATA);
+ columnCount=Header_GetItemCount(ListView_GetHeader(hwndResults));
+ if(columnCount<=COLUMNID_EMAIL || columnCount>COLUMNID_HANDLE+1) return;
+ ListView_GetColumnOrderArray(hwndResults,columnCount,columnOrder);
+ if(columnCount<=COLUMNID_HANDLE) {
+ if(handleColumnAfter==-1) {
+ memmove(columnOrder+1,columnOrder,sizeof(columnOrder[0])*columnCount);
+ columnOrder[0]=COLUMNID_HANDLE;
+ }
+ else {
+ for(i=0;i<columnCount;i++) {
+ if(handleColumnAfter==columnOrder[i]) {
+ memmove(columnOrder+i+2,columnOrder+i+1,sizeof(columnOrder[0])*(columnCount-i-1));
+ columnOrder[i+1]=COLUMNID_HANDLE;
+ break;
+ }
+ }
+ }
+ }
+ for(i=0;i<=COLUMNID_HANDLE;i++) {
+ wsprintfA(szSetting,"ColOrder%d",i);
+ DBWriteContactSettingByte(NULL,"FindAdd",szSetting,(BYTE)columnOrder[i]);
+ if(i>=columnCount) continue;
+ wsprintfA(szSetting,"ColWidth%d",i);
+ DBWriteContactSettingWord(NULL,"FindAdd",szSetting,(WORD)ListView_GetColumnWidth(hwndResults,i));
+ }
+ DBWriteContactSettingByte(NULL,"FindAdd","SortColumn",(BYTE)dat->iLastColumnSortIndex);
+ DBWriteContactSettingByte(NULL,"FindAdd","SortAscending",(BYTE)dat->bSortAscending);
+}
+
+static const TCHAR *szColumnNames[] = { NULL, _T("Nick"), _T("First Name"), _T("Last Name"), _T("E-mail"), NULL };
+static int defaultColumnSizes[]={0,100,100,100,200,90};
+void LoadColumnSizes(HWND hwndResults,const char *szProto)
+{
+ HDITEM hdi;
+ int columnOrder[COLUMNID_HANDLE+1];
+ int columnCount;
+ char szSetting[32];
+ int i;
+ struct FindAddDlgData *dat;
+ int colOrdersValid;
+
+ defaultColumnSizes[COLUMNID_PROTO]=GetSystemMetrics(SM_CXSMICON)+4;
+ dat=(struct FindAddDlgData*)GetWindowLong(GetParent(hwndResults),GWL_USERDATA);
+
+ if(szProto && !lstrcmpA(szProto,"ICQ"))
+ columnCount=COLUMNID_HANDLE+1;
+ else
+ columnCount=COLUMNID_EMAIL+1;
+
+ colOrdersValid=1;
+ for(i=0;i<=COLUMNID_HANDLE;i++) {
+ LVCOLUMN lvc;
+ if( i < columnCount ) {
+ int bNeedsFree = FALSE;
+ lvc.mask = LVCF_TEXT | LVCF_WIDTH;
+ if( szColumnNames[i] != NULL )
+ lvc.pszText = TranslateTS( szColumnNames[i] );
+ else if( i == COLUMNID_HANDLE ) {
+ #if defined( _UNICODE )
+ bNeedsFree = TRUE;
+ lvc.pszText = a2u((char*)CallProtoService(szProto,PS_GETCAPS,PFLAG_UNIQUEIDTEXT,0));
+ #else
+ lvc.pszText = (char*)CallProtoService(szProto,PS_GETCAPS,PFLAG_UNIQUEIDTEXT,0);
+ #endif
+ }
+ else lvc.mask &= ~LVCF_TEXT;
+ wsprintfA(szSetting,"ColWidth%d",i);
+ lvc.cx = DBGetContactSettingWord(NULL,"FindAdd",szSetting,defaultColumnSizes[i]);
+ ListView_InsertColumn( hwndResults, i, (LPARAM)&lvc );
+ #if defined( _UNICODE )
+ if ( bNeedsFree )
+ mir_free(lvc.pszText);
+ #endif
+ }
+ wsprintfA(szSetting,"ColOrder%d",i);
+ columnOrder[i]=DBGetContactSettingByte(NULL,"FindAdd",szSetting,-1);
+ if(columnOrder[i]==-1) colOrdersValid=0;
+ if(columnOrder[i]==COLUMNID_HANDLE) handleColumnAfter=i?columnOrder[i-1]:-1;
+ }
+ if(colOrdersValid) {
+ if(columnCount<=COLUMNID_HANDLE)
+ for(i=0;i<columnCount;i++)
+ if(columnOrder[i]==COLUMNID_HANDLE) {
+ memmove(columnOrder+i,columnOrder+i+1,sizeof(columnOrder[0])*(columnCount-i));
+ break;
+ }
+ ListView_SetColumnOrderArray(hwndResults,columnCount,columnOrder);
+ }
+ else handleColumnAfter=COLUMNID_EMAIL;
+
+ dat->iLastColumnSortIndex=DBGetContactSettingByte(NULL,"FindAdd","SortColumn",COLUMNID_NICK);
+ if(dat->iLastColumnSortIndex>=columnCount) dat->iLastColumnSortIndex=COLUMNID_NICK;
+ dat->bSortAscending=DBGetContactSettingByte(NULL,"FindAdd","SortAscending",TRUE);
+
+ hdi.mask=HDI_BITMAP|HDI_FORMAT;
+ hdi.fmt=HDF_LEFT|HDF_BITMAP|HDF_STRING|HDF_BITMAP_ON_RIGHT;
+ hdi.hbm=dat->bSortAscending?dat->hBmpSortDown:dat->hBmpSortUp;
+ Header_SetItem(ListView_GetHeader(hwndResults),dat->iLastColumnSortIndex,&hdi);
+}
+
+int CALLBACK SearchResultsCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+{
+ struct FindAddDlgData *dat=(struct FindAddDlgData*)lParamSort;
+ int sortMultiplier;
+ int sortCol;
+ struct ListSearchResult *lsr1=(struct ListSearchResult*)lParam1,*lsr2=(struct ListSearchResult*)lParam2;
+
+ sortMultiplier=dat->bSortAscending?1:-1;
+ sortCol=dat->iLastColumnSortIndex;
+ if ( lsr1 == NULL || lsr2 == NULL ) return 0;
+ switch(sortCol)
+ {
+ case COLUMNID_PROTO:
+ return lstrcmpA(lsr1->szProto, lsr2->szProto)*sortMultiplier;
+ case COLUMNID_NICK:
+ return lstrcmpiA(lsr1->psr.nick, lsr2->psr.nick)*sortMultiplier;
+ case COLUMNID_FIRST:
+ return lstrcmpiA(lsr1->psr.firstName, lsr2->psr.firstName)*sortMultiplier;
+ case COLUMNID_LAST:
+ return lstrcmpiA(lsr1->psr.lastName, lsr2->psr.lastName)*sortMultiplier;
+ case COLUMNID_EMAIL:
+ return lstrcmpiA(lsr1->psr.email, lsr2->psr.email)*sortMultiplier;
+ case COLUMNID_HANDLE:
+ if(!lstrcmpA(lsr1->szProto,lsr2->szProto)) {
+ if(!lstrcmpA(lsr1->szProto,"ICQ")) {
+ if(((ICQSEARCHRESULT*)&lsr1->psr)->uin<((ICQSEARCHRESULT*)&lsr2->psr)->uin) return -sortMultiplier;
+ return sortMultiplier;
+ }
+ else return 0;
+ }
+ else return lstrcmpA(lsr1->szProto, lsr2->szProto)*sortMultiplier;
+ }
+ return 0;
+}
+
+void FreeSearchResults(HWND hwndResults)
+{
+ LV_ITEM lvi;
+ struct ListSearchResult *lsr;
+ for(lvi.iItem=ListView_GetItemCount(hwndResults)-1;lvi.iItem>=0;lvi.iItem--) {
+ lvi.mask=LVIF_PARAM;
+ ListView_GetItem(hwndResults,&lvi);
+ lsr=(struct ListSearchResult*)lvi.lParam;
+ if(lsr==NULL) continue;
+ mir_free(lsr->psr.email);
+ mir_free(lsr->psr.nick);
+ mir_free(lsr->psr.firstName);
+ mir_free(lsr->psr.lastName);
+ mir_free(lsr);
+ }
+ ListView_DeleteAllItems(hwndResults);
+ EnableResultButtons(GetParent(hwndResults),0);
+}
+
+// on its own thread
+static void BeginSearchFailed(void * arg)
+{
+ TCHAR buf[128];
+ if ( arg != NULL ) {
+ TCHAR* protoName = LangPackPcharToTchar(( const char* )arg );
+ mir_sntprintf(buf,SIZEOF(buf),TranslateT("Could not start a search on '%s', there was a problem - is %s connected?"),protoName,protoName);
+ mir_free((char*)arg);
+ }
+ else lstrcpyn(buf,TranslateT("Could not search on any of the protocols, are you online?"),SIZEOF(buf));
+ MessageBox(0,buf,TranslateT("Problem with search"),MB_OK | MB_ICONERROR);
+}
+
+int BeginSearch(HWND hwndDlg,struct FindAddDlgData *dat,const char *szProto,const char *szSearchService,DWORD requiredCapability,void *pvSearchParams)
+{
+ int protoCount,i;
+ PROTOCOLDESCRIPTOR **protos;
+
+ if(szProto==NULL) {
+ int failures=0;
+ DWORD caps;
+
+ CallService(MS_PROTO_ENUMPROTOCOLS,(WPARAM)&protoCount,(LPARAM)&protos);
+ dat->searchCount=0;
+ dat->search=(struct ProtoSearchInfo*)mir_calloc(sizeof(struct ProtoSearchInfo) * protoCount);
+ for(i=0;i<protoCount;i++) {
+ if(protos[i]->type!=PROTOTYPE_PROTOCOL) continue;
+ caps=(DWORD)CallProtoService(protos[i]->szName,PS_GETCAPS,PFLAGNUM_1,0);
+ if(!(caps&requiredCapability)) continue;
+ dat->search[dat->searchCount].hProcess=(HANDLE)CallProtoService(protos[i]->szName,szSearchService,0,(LPARAM)pvSearchParams);
+ dat->search[dat->searchCount].szProto=protos[i]->szName;
+ if(dat->search[dat->searchCount].hProcess==NULL) failures++;
+ else dat->searchCount++;
+ }
+ if(failures) {
+ //infuriatingly vague error message. fixme.
+ if(dat->searchCount==0) {
+ forkthread(BeginSearchFailed,0,NULL);
+ mir_free(dat->search);
+ dat->search=NULL;
+ return 1;
+ } }
+ }
+ else {
+ dat->search=(struct ProtoSearchInfo*)mir_alloc(sizeof(struct ProtoSearchInfo));
+ dat->searchCount=1;
+ dat->search[0].hProcess=(HANDLE)CallProtoService(szProto,szSearchService,0,(LPARAM)pvSearchParams);
+ dat->search[0].szProto=szProto;
+ if(dat->search[0].hProcess==NULL) {
+ //infuriatingly vague error message. fixme.
+ forkthread(BeginSearchFailed,0,(void*)mir_strdup(szProto));
+ mir_free(dat->search);
+ dat->search=NULL;
+ dat->searchCount=0;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void SetStatusBarSearchInfo(HWND hwndStatus,struct FindAddDlgData *dat)
+{
+ TCHAR str[256];
+
+ if (dat->searchCount != 0 ) {
+ char szProtoName[64];
+ int i;
+
+ lstrcpy( str, TranslateT("Searching"));
+ for( i=0; i <dat->searchCount; i++ ) {
+ lstrcat(str, i ? _T(",") : _T( " " ));
+ CallProtoService(dat->search[i].szProto,PS_GETNAME,SIZEOF(szProtoName),(LPARAM)szProtoName);
+ #if !defined( _UNICODE )
+ lstrcatA( str, szProtoName );
+ #else
+ { TCHAR* p = a2u(szProtoName);
+ lstrcat(str, p);
+ mir_free(p);
+ }
+ #endif
+ } }
+ else lstrcpy(str, TranslateT("Idle"));
+
+ SendMessage( hwndStatus, SB_SETTEXT, 0, (LPARAM)str );
+}
+
+struct ProtoResultsSummary {
+ const char *szProto;
+ int count;
+};
+void SetStatusBarResultInfo(HWND hwndDlg,struct FindAddDlgData *dat)
+{
+ HWND hwndStatus=GetDlgItem(hwndDlg,IDC_STATUSBAR);
+ HWND hwndResults=GetDlgItem(hwndDlg,IDC_RESULTS);
+ LV_ITEM lvi;
+ struct ListSearchResult *lsr;
+ struct ProtoResultsSummary *subtotal=NULL;
+ int subtotalCount=0;
+ int i,total;
+ TCHAR str[256];
+
+ total=ListView_GetItemCount(hwndResults);
+ for(lvi.iItem=total-1;lvi.iItem>=0;lvi.iItem--) {
+ lvi.mask=LVIF_PARAM;
+ ListView_GetItem(hwndResults,&lvi);
+ lsr=(struct ListSearchResult*)lvi.lParam;
+ if(lsr==NULL) continue;
+ for(i=0;i<subtotalCount;i++) {
+ if(subtotal[i].szProto==lsr->szProto) {
+ subtotal[i].count++;
+ break;
+ }
+ }
+ if(i==subtotalCount) {
+ subtotal=(struct ProtoResultsSummary*)mir_realloc(subtotal,sizeof(struct ProtoResultsSummary)*(subtotalCount+1));
+ subtotal[subtotalCount].szProto=lsr->szProto;
+ subtotal[subtotalCount++].count=1;
+ }
+ }
+ if ( total != 0 ) {
+ char szProtoName[64];
+ TCHAR substr[64];
+ TCHAR* ptszProto;
+
+ CallProtoService( subtotal[0].szProto, PS_GETNAME, SIZEOF(szProtoName), (LPARAM)szProtoName );
+ #if defined( _UNICODE )
+ ptszProto = a2u( szProtoName );
+ #else
+ ptszProto = szProtoName;
+ #endif
+
+ if ( subtotalCount == 1 ) {
+ if(total==1) mir_sntprintf( str, SIZEOF(str), TranslateT("1 %s user found"), ptszProto );
+ else mir_sntprintf( str, SIZEOF(str), TranslateT("%d %s users found"), total, ptszProto );
+ }
+ else {
+ mir_sntprintf( str, SIZEOF(str), TranslateT("%d users found ("),total);
+ for( i=0; i < subtotalCount; i++ ) {
+ if(i) {
+ CallProtoService(subtotal[i].szProto,PS_GETNAME,SIZEOF(szProtoName),(LPARAM)szProtoName);
+ #if defined( _UNICODE )
+ mir_free( ptszProto );
+ ptszProto = a2u( szProtoName );
+ #else
+ ptszProto = szProtoName;
+ #endif
+ lstrcat( str, _T(", "));
+ }
+ mir_sntprintf( substr, SIZEOF(substr), _T("%d %s"), subtotal[i].count, ptszProto );
+ lstrcat( str, substr );
+ }
+ lstrcat( str, _T(")"));
+ }
+ mir_free(subtotal);
+ #if defined( _UNICODE )
+ mir_free( ptszProto );
+ #endif
+ }
+ else lstrcpy(str, TranslateT("No users found"));
+ SendMessage(hwndStatus, SB_SETTEXT, 2, (LPARAM)str );
+}
+
+void CreateResultsColumns(HWND hwndResults,struct FindAddDlgData *dat,char *szProto)
+{
+ SaveColumnSizes(hwndResults);
+ while(ListView_DeleteColumn(hwndResults,0));
+ ListView_SetImageList(hwndResults,dat->himlComboIcons,LVSIL_SMALL);
+ LoadColumnSizes(hwndResults,szProto);
+}
+
+void ShowMoreOptionsMenu(HWND hwndDlg,int x,int y)
+{
+ struct FindAddDlgData *dat;
+ HMENU hPopupMenu,hMenu;
+ int commandId;
+ struct ListSearchResult *lsr;
+
+ dat=(struct FindAddDlgData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+
+ { LVITEM lvi;
+ if(ListView_GetSelectedCount(GetDlgItem(hwndDlg,IDC_RESULTS))!=1) return;
+ lvi.mask=LVIF_PARAM;
+ lvi.iItem=ListView_GetNextItem(GetDlgItem(hwndDlg,IDC_RESULTS),-1,LVNI_ALL|LVNI_SELECTED);
+ ListView_GetItem(GetDlgItem(hwndDlg,IDC_RESULTS),&lvi);
+ lsr=(struct ListSearchResult*)lvi.lParam;
+ }
+
+ hMenu=LoadMenu(GetModuleHandle(NULL),MAKEINTRESOURCE(IDR_CONTEXT));
+ hPopupMenu=GetSubMenu(hMenu,4);
+ CallService(MS_LANGPACK_TRANSLATEMENU,(WPARAM)hPopupMenu,0);
+ commandId=TrackPopupMenu(hPopupMenu,TPM_RIGHTBUTTON|TPM_RETURNCMD,x,y,0,hwndDlg,NULL);
+ if(commandId) {
+ switch(commandId) {
+ case IDC_ADD:
+ { ADDCONTACTSTRUCT acs;
+
+ acs.handle=NULL;
+ acs.handleType=HANDLE_SEARCHRESULT;
+ acs.szProto=lsr->szProto;
+ acs.psr=&lsr->psr;
+ CallService(MS_ADDCONTACT_SHOW,(WPARAM)hwndDlg,(LPARAM)&acs);
+ break;
+ }
+ case IDC_DETAILS:
+ { HANDLE hContact;
+ hContact=(HANDLE)CallProtoService(lsr->szProto,PS_ADDTOLIST,PALF_TEMPORARY,(LPARAM)&lsr->psr);
+ CallService(MS_USERINFO_SHOWDIALOG,(WPARAM)hContact,0);
+ break;
+ }
+ case IDC_SENDMESSAGE:
+ { HANDLE hContact;
+ hContact=(HANDLE)CallProtoService(lsr->szProto,PS_ADDTOLIST,PALF_TEMPORARY,(LPARAM)&lsr->psr);
+ CallService(MS_MSG_SENDMESSAGE,(WPARAM)hContact,(LPARAM)(const char*)NULL);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ DestroyMenu(hPopupMenu);
+ DestroyMenu(hMenu);
+}
+
diff --git a/miranda-wine/src/modules/help/about.c b/miranda-wine/src/modules/help/about.c
new file mode 100644
index 0000000..9116d54
--- /dev/null
+++ b/miranda-wine/src/modules/help/about.c
@@ -0,0 +1,143 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+#if defined( _UNICODE )
+ #define STR_VERSION_FORMAT "%s %S"
+#else
+ #define STR_VERSION_FORMAT "%s %s"
+#endif
+
+BOOL CALLBACK DlgProcAbout(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static int iState = 0;
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ { int h;
+ LOGFONT lf;
+ HFONT hFont = (HFONT)SendDlgItemMessage(hwndDlg,IDC_MIRANDA,WM_GETFONT,0,0);
+ int iState=0;
+ GetObject(hFont,sizeof(lf),&lf);
+ h=lf.lfHeight;
+ lf.lfHeight=(int)(lf.lfHeight*1.5);
+ lf.lfWeight=FW_BOLD;
+ hFont=CreateFontIndirect(&lf);
+ SendDlgItemMessage(hwndDlg,IDC_MIRANDA,WM_SETFONT,(WPARAM)hFont,0);
+ lf.lfHeight=h;
+ hFont=CreateFontIndirect(&lf);
+ SendDlgItemMessage(hwndDlg,IDC_VERSION,WM_SETFONT,(WPARAM)hFont,0);
+ }
+ {
+ char filename[MAX_PATH],*productCopyright;
+ DWORD unused;
+ DWORD verInfoSize;
+ UINT blockSize;
+ PVOID pVerInfo;
+
+ GetModuleFileNameA(NULL,filename,SIZEOF(filename));
+ verInfoSize=GetFileVersionInfoSizeA(filename,&unused);
+ pVerInfo=mir_alloc(verInfoSize);
+ GetFileVersionInfoA(filename,0,verInfoSize,pVerInfo);
+ VerQueryValueA(pVerInfo,"\\StringFileInfo\\000004b0\\LegalCopyright",(void*)&productCopyright,&blockSize);
+ SetDlgItemTextA(hwndDlg,IDC_DEVS,productCopyright);
+ mir_free(pVerInfo);
+ }
+ { char productVersion[56];
+ TCHAR str[64];
+ CallService(MS_SYSTEM_GETVERSIONTEXT,SIZEOF(productVersion),(LPARAM)productVersion);
+ mir_sntprintf(str,SIZEOF(str),_T(STR_VERSION_FORMAT), TranslateT("Version"), productVersion);
+ SetDlgItemText(hwndDlg,IDC_VERSION,str);
+ mir_sntprintf(str,SIZEOF(str),TranslateT("Built %s %s"),_T(__DATE__),_T(__TIME__));
+ SetDlgItemText(hwndDlg,IDC_BUILDTIME,str);
+ }
+ ShowWindow(GetDlgItem(hwndDlg, IDC_CREDITSFILE), SW_HIDE);
+ { char* pszMsg = LockResource(LoadResource(GetModuleHandle(NULL),FindResource(GetModuleHandle(NULL),MAKEINTRESOURCE(IDR_CREDITS),_T("TEXT"))));
+ #if defined( _UNICODE )
+ TCHAR* ptszMsg = alloca(2000*sizeof(TCHAR));
+ MultiByteToWideChar(1252,0,pszMsg,-1,ptszMsg,2000);
+ SetDlgItemText(hwndDlg,IDC_CREDITSFILE, ptszMsg);
+ #else
+ SetDlgItemText(hwndDlg,IDC_CREDITSFILE, pszMsg);
+ #endif
+ }
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MIRANDA)));
+ return TRUE;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDOK:
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ case IDC_CONTRIBLINK:
+ {
+ if (iState) {
+ iState = 0;
+ SetDlgItemText(hwndDlg, IDC_CONTRIBLINK, TranslateT("Credits >"));
+ ShowWindow(GetDlgItem(hwndDlg, IDC_DEVS), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_BUILDTIME), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_CREDITSFILE), SW_HIDE);
+ }
+ else {
+ iState = 1;
+ SetDlgItemText(hwndDlg, IDC_CONTRIBLINK, TranslateT("< About"));
+ ShowWindow(GetDlgItem(hwndDlg, IDC_DEVS), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_BUILDTIME), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_CREDITSFILE), SW_SHOW);
+ }
+ break;
+ }
+ }
+ break;
+ case WM_CTLCOLOREDIT:
+ case WM_CTLCOLORSTATIC:
+ if((HWND)lParam==GetDlgItem(hwndDlg,IDC_WHITERECT)
+ || (HWND)lParam==GetDlgItem(hwndDlg,IDC_MIRANDA)
+ || (HWND)lParam==GetDlgItem(hwndDlg,IDC_VERSION)
+ || (HWND)lParam==GetDlgItem(hwndDlg,IDC_BUILDTIME)
+ || (HWND)lParam==GetDlgItem(hwndDlg,IDC_LOGO)
+ || (HWND)lParam==GetDlgItem(hwndDlg,IDC_CREDITSFILE)
+ || (HWND)lParam==GetDlgItem(hwndDlg,IDC_DEVS)) {
+ if((HWND)lParam==GetDlgItem(hwndDlg,IDC_MIRANDA))
+ SetTextColor((HDC)wParam,RGB(180,10,10));
+ else if((HWND)lParam==GetDlgItem(hwndDlg,IDC_VERSION))
+ SetTextColor((HDC)wParam,RGB(70,70,70));
+ else
+ SetTextColor((HDC)wParam,RGB(0,0,0));
+ SetBkColor((HDC)wParam,RGB(255,255,255));
+ return (BOOL)GetStockObject(WHITE_BRUSH);
+ }
+ break;
+ case WM_DESTROY:
+ { HFONT hFont = (HFONT)SendDlgItemMessage(hwndDlg,IDC_MIRANDA,WM_GETFONT,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_MIRANDA,WM_SETFONT,SendDlgItemMessage(hwndDlg,IDOK,WM_GETFONT,0,0),0);
+ DeleteObject(hFont);
+
+ hFont=(HFONT)SendDlgItemMessage(hwndDlg,IDC_VERSION,WM_GETFONT,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_VERSION,WM_SETFONT,SendDlgItemMessage(hwndDlg,IDOK,WM_GETFONT,0,0),0);
+ DeleteObject(hFont);
+ }
+ break;
+ }
+ return FALSE;
+}
diff --git a/miranda-wine/src/modules/help/help.c b/miranda-wine/src/modules/help/help.c
new file mode 100644
index 0000000..9646095
--- /dev/null
+++ b/miranda-wine/src/modules/help/help.c
@@ -0,0 +1,104 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+BOOL CALLBACK DlgProcAbout(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+HWND hAboutDlg=NULL;
+
+static int AboutCommand(WPARAM wParam,LPARAM lParam)
+{
+ if (IsWindow(hAboutDlg)) {
+ SetForegroundWindow(hAboutDlg);
+ SetFocus(hAboutDlg);
+ return 0;
+ }
+ hAboutDlg=CreateDialog(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_ABOUT),(HWND)wParam,DlgProcAbout);
+ return 0;
+}
+
+static int IndexCommand(WPARAM wParam,LPARAM lParam)
+{
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)"http://www.miranda-im.org/support/");
+ return 0;
+}
+
+static int WebsiteCommand(WPARAM wParam,LPARAM lParam)
+{
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)"http://www.miranda-im.org");
+ return 0;
+}
+
+static int BugCommand(WPARAM wParam,LPARAM lParam)
+{
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)"http://bugs.miranda-im.org/");
+ return 0;
+}
+
+
+int ShutdownHelpModule(WPARAM wParam, LPARAM lParam)
+{
+ if (IsWindow(hAboutDlg)) DestroyWindow(hAboutDlg);
+ hAboutDlg=NULL;
+ return 0;
+}
+
+int LoadHelpModule(void)
+{
+ CLISTMENUITEM mi;
+
+ HookEvent(ME_SYSTEM_PRESHUTDOWN,ShutdownHelpModule);
+
+ CreateServiceFunction("Help/AboutCommand",AboutCommand);
+ CreateServiceFunction("Help/IndexCommand",IndexCommand);
+ CreateServiceFunction("Help/WebsiteCommand",WebsiteCommand);
+ CreateServiceFunction("Help/BugCommand",BugCommand);
+ ZeroMemory(&mi,sizeof(mi));
+ mi.cbSize=sizeof(mi);
+ mi.hIcon=LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_MIRANDA));
+ mi.pszPopupName=Translate("&Help");
+ mi.popupPosition=2000090000;
+ mi.position=2000090000;
+ mi.pszName=Translate("&About...");
+ mi.pszService="Help/AboutCommand";
+ CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi);
+ mi.hIcon=LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_HELP));
+ mi.position=-500050000;
+ mi.pszName=Translate("&Support\tF1");
+ mi.hotKey=MAKELPARAM(0,VK_F1);
+ mi.pszService="Help/IndexCommand";
+ CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi);
+ mi.hIcon=LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_MIRANDAWEBSITE));
+ mi.position=2000050000;
+ mi.pszName=Translate("&Miranda IM Homepage");
+ mi.hotKey=0;
+ mi.pszService="Help/WebsiteCommand";
+ CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi);
+ mi.hIcon=LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_URL));
+ mi.position=2000040000;
+ mi.pszName=Translate("&Report Bug");
+ mi.hotKey=0;
+ mi.pszService="Help/BugCommand";
+ CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/history/history.c b/miranda-wine/src/modules/history/history.c
new file mode 100644
index 0000000..202b1c8
--- /dev/null
+++ b/miranda-wine/src/modules/history/history.c
@@ -0,0 +1,434 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+#define SUMMARY 0
+#define DETAIL 1
+#define DM_FINDNEXT (WM_USER+10)
+#define DM_HREBUILD (WM_USER+11)
+
+static BOOL CALLBACK DlgProcHistory(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+static BOOL CALLBACK DlgProcHistoryFind(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+static HANDLE hWindowList=0;
+
+static int UserHistoryCommand(WPARAM wParam,LPARAM lParam)
+{
+ HWND hwnd;
+
+ if(hwnd=WindowList_Find(hWindowList,(HANDLE)wParam)) {
+ SetForegroundWindow(hwnd);
+ SetFocus(hwnd);
+ return 0;
+ }
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_HISTORY),NULL,DlgProcHistory,wParam);
+ return 0;
+}
+
+static int HistoryContactDelete(WPARAM wParam,LPARAM lParam)
+{
+ HWND hwnd;
+ hwnd=WindowList_Find(hWindowList,(HANDLE)wParam);
+ if(hwnd!=NULL) DestroyWindow(hwnd);
+ return 0;
+}
+
+int PreShutdownHistoryModule(WPARAM wParam, LPARAM lParam)
+{
+ if (hWindowList) WindowList_BroadcastAsync(hWindowList,WM_DESTROY,0,0);
+ return 0;
+}
+
+int LoadHistoryModule(void)
+{
+ CLISTMENUITEM mi;
+
+ //bit of a fudge that the one service works for both global requests and
+ //the contact list's menu processing stuff
+ CreateServiceFunction(MS_HISTORY_SHOWCONTACTHISTORY,UserHistoryCommand);
+ ZeroMemory(&mi,sizeof(mi));
+ mi.cbSize=sizeof(mi);
+ mi.position=1000090000;
+ mi.flags=0;
+ mi.hIcon=LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_HISTORY));
+ mi.pszContactOwner=NULL; //all contacts
+ mi.pszName=Translate("View &History");
+ mi.pszService=MS_HISTORY_SHOWCONTACTHISTORY;
+ CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi);
+ hWindowList=(HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST,0,0);
+ HookEvent(ME_DB_CONTACT_DELETED,HistoryContactDelete);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN,PreShutdownHistoryModule);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Fills the events list
+
+static void GetMessageDescription( DBEVENTINFO *dbei, TCHAR* buf, int cbBuf )
+{
+ char* pszSrc = ( char* )dbei->pBlob;
+ #if defined( _UNICODE )
+ unsigned len = strlen(( char* )dbei->pBlob )+1;
+ if ( dbei->cbBlob != len ) {
+ int len2 = dbei->cbBlob - len;
+ if ( len2 > cbBuf )
+ len2 = cbBuf - sizeof( TCHAR );
+
+ memcpy( buf, &dbei->pBlob[ len ], len2 );
+ return;
+ }
+ #endif
+
+ #if !defined( _UNICODE )
+ strncpy( buf, ( const char* )pszSrc, cbBuf );
+ #else
+ MultiByteToWideChar( CP_ACP, 0, ( LPCSTR )pszSrc, -1, buf, cbBuf );
+ #endif
+ buf[ cbBuf-1 ] = 0;
+}
+
+static void GetUrlDescription( DBEVENTINFO *dbei, TCHAR* buf, int cbBuf )
+{
+ int len = dbei->cbBlob;
+ if ( len >= cbBuf )
+ len = cbBuf-1;
+
+ #if !defined( _UNICODE )
+ memcpy( buf, dbei->pBlob, len );
+ #else
+ MultiByteToWideChar( CP_ACP, 0, ( LPCSTR )dbei->pBlob, len, buf, cbBuf );
+ #endif
+ buf[ len ] = 0;
+
+ if ( len < cbBuf-3 )
+ _tcscat( buf, _T( "\r\n" ));
+}
+
+static void GetFileDescription( DBEVENTINFO *dbei, TCHAR* buf, int cbBuf )
+{
+ int len = dbei->cbBlob - sizeof( DWORD );
+ if ( len >= cbBuf )
+ len = cbBuf-1;
+
+ #if !defined( _UNICODE )
+ memcpy( buf, dbei->pBlob + sizeof( DWORD ), len );
+ #else
+ MultiByteToWideChar( CP_ACP, 0, ( LPCSTR )dbei->pBlob + sizeof( DWORD ), len, buf, cbBuf );
+ #endif
+ buf[ len ] = 0;
+
+ if ( len < cbBuf-3 )
+ _tcscat( buf, _T( "\r\n" ));
+}
+
+static void GetObjectDescription( DBEVENTINFO *dbei, TCHAR* str, int cbStr )
+{
+ switch( dbei->eventType ) {
+ case EVENTTYPE_MESSAGE:
+ GetMessageDescription( dbei, str, cbStr );
+ break;
+
+ case EVENTTYPE_URL:
+ GetUrlDescription( dbei, str, cbStr );
+ break;
+
+ case EVENTTYPE_FILE:
+ GetFileDescription( dbei, str, cbStr );
+ break;
+
+ default:
+ str[ 0 ] = 0;
+} }
+
+static void GetObjectSummary( DBEVENTINFO *dbei, TCHAR* str, int cbStr )
+{
+ TCHAR* pszSrc;
+
+ switch( dbei->eventType ) {
+ case EVENTTYPE_MESSAGE:
+ if ( dbei->flags & DBEF_SENT ) pszSrc = TranslateT( "Outgoing Message" );
+ else pszSrc = TranslateT( "Incoming Message" );
+ break;
+
+ case EVENTTYPE_URL:
+ if ( dbei->flags & DBEF_SENT ) pszSrc = TranslateT( "Outgoing URL" );
+ else pszSrc = TranslateT( "Incoming URL" );
+ break;
+
+ case EVENTTYPE_FILE:
+ if ( dbei->flags & DBEF_SENT ) pszSrc = TranslateT( "Outgoing File" );
+ else pszSrc = TranslateT( "Incoming File" );
+ break;
+
+ default:
+ str[ 0 ] = 0;
+ return;
+ }
+
+ _tcsncpy( str, ( const TCHAR* )pszSrc, cbStr );
+ str[ cbStr-1 ] = 0;
+}
+
+typedef struct {
+ HANDLE hContact;
+ HWND hwnd;
+} THistoryThread;
+
+static void FillHistoryThread(THistoryThread *hInfo)
+{
+ TCHAR str[200], eventText[256], strdatetime[64];
+ HANDLE hDbEvent;
+ DBEVENTINFO dbei;
+ int newBlobSize,oldBlobSize,i;
+ DBTIMETOSTRINGT dbtts;
+ HWND hwndList;
+
+ SendDlgItemMessage(hInfo->hwnd,IDC_LIST,LB_RESETCONTENT,0,0);
+ i=CallService(MS_DB_EVENT_GETCOUNT,(WPARAM)hInfo->hContact,0);
+ SendDlgItemMessage(hInfo->hwnd,IDC_LIST,LB_INITSTORAGE,i,i*40);
+
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.pBlob=NULL;
+ oldBlobSize=0;
+ hDbEvent=(HANDLE)CallService(MS_DB_EVENT_FINDLAST,(WPARAM)hInfo->hContact,0);
+ dbtts.cbDest = SIZEOF(strdatetime);
+ dbtts.szDest = strdatetime;
+ dbtts.szFormat = _T("d t");
+ hwndList=GetDlgItem(hInfo->hwnd,IDC_LIST);
+ while(hDbEvent!=NULL) {
+ if (!IsWindow(hInfo->hwnd)) break;
+ newBlobSize=CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)hDbEvent,0);
+ if(newBlobSize>oldBlobSize) {
+ dbei.pBlob=(PBYTE)mir_realloc(dbei.pBlob,newBlobSize);
+ oldBlobSize=newBlobSize;
+ }
+ dbei.cbBlob = oldBlobSize;
+ CallService( MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei );
+ GetObjectSummary(&dbei,str,SIZEOF(str));
+ if(str[0]) {
+ CallService(MS_DB_TIME_TIMESTAMPTOSTRINGT, dbei.timestamp,( LPARAM )&dbtts );
+ mir_sntprintf( eventText, SIZEOF(eventText), _T("%s: %s"), strdatetime, str );
+ i = SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)eventText );
+ SendMessage(hwndList, LB_SETITEMDATA, i, (LPARAM)hDbEvent);
+ }
+ hDbEvent=(HANDLE)CallService(MS_DB_EVENT_FINDPREV,(WPARAM)hDbEvent,0);
+ }
+ if(dbei.pBlob!=NULL) mir_free(dbei.pBlob);
+
+ SendDlgItemMessage(hInfo->hwnd,IDC_LIST,LB_SETCURSEL,0,0);
+ SendMessage(hInfo->hwnd,WM_COMMAND,MAKEWPARAM(IDC_LIST,LBN_SELCHANGE),0);
+ EnableWindow(GetDlgItem(hInfo->hwnd, IDC_LIST), TRUE);
+ mir_free(hInfo);
+}
+
+static int HistoryDlgResizer(HWND hwndDlg,LPARAM lParam,UTILRESIZECONTROL *urc) {
+ switch(urc->wId) {
+ case IDC_LIST:
+ return RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT;
+ case IDC_EDIT:
+ return RD_ANCHORX_WIDTH|RD_ANCHORY_BOTTOM;
+ case IDC_FIND:
+ case IDC_DELETEHISTORY:
+ return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM;
+ case IDOK:
+ return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM;
+ }
+ return RD_ANCHORX_LEFT|RD_ANCHORY_TOP;
+}
+
+static BOOL CALLBACK DlgProcHistory(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hContact;
+
+ hContact=(HANDLE)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ TCHAR* contactName, str[200];
+
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLong(hwndDlg,GWL_USERDATA,lParam);
+ hContact = (HANDLE)lParam;
+ WindowList_Add(hWindowList,hwndDlg,hContact);
+ Utils_RestoreWindowPosition(hwndDlg,hContact,"History","");
+ contactName=(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)hContact,GCDNF_TCHAR);
+ mir_sntprintf(str,SIZEOF(str),TranslateT("History for %s"),contactName);
+ SetWindowText(hwndDlg,str);
+ SendMessage(hwndDlg,WM_SETICON,ICON_BIG,(LPARAM)LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_HISTORY)));
+ SendMessage(hwndDlg,DM_HREBUILD,0,0);
+ return TRUE;
+ }
+ case DM_HREBUILD:
+ {
+ THistoryThread *hInfo = (THistoryThread*)mir_alloc(sizeof(THistoryThread));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_LIST), FALSE);
+ hInfo->hContact = hContact;
+ hInfo->hwnd = hwndDlg;
+ forkthread(FillHistoryThread, 0, hInfo);
+ return TRUE;
+ }
+ case WM_DESTROY:
+ {
+ Utils_SaveWindowPosition(hwndDlg,hContact,"History","");
+ WindowList_Remove(hWindowList,hwndDlg);
+ return TRUE;
+ }
+ case WM_GETMINMAXINFO:
+ {
+ ((MINMAXINFO*)lParam)->ptMinTrackSize.x=300;
+ ((MINMAXINFO*)lParam)->ptMinTrackSize.y=230;
+ }
+ case WM_SIZE:
+ {
+ UTILRESIZEDIALOG urd={0};
+ urd.cbSize=sizeof(urd);
+ urd.hwndDlg=hwndDlg;
+ urd.hInstance=GetModuleHandle(NULL);
+ urd.lpTemplate=MAKEINTRESOURCEA(IDD_HISTORY);
+ urd.lParam=(LPARAM)NULL;
+ urd.pfnResizer=HistoryDlgResizer;
+ CallService(MS_UTILS_RESIZEDIALOG,0,(LPARAM)&urd);
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ case IDC_FIND:
+ ShowWindow(CreateDialogParam(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_HISTORY_FIND), hwndDlg, DlgProcHistoryFind, (LPARAM)hwndDlg), SW_SHOW);
+ return TRUE;
+ case IDC_DELETEHISTORY:
+ {
+ HANDLE hDbevent;
+ int index;
+ index = SendDlgItemMessage(hwndDlg,IDC_LIST,LB_GETCURSEL,0,0);
+ if(index==LB_ERR) break;
+ if (MessageBox(hwndDlg,TranslateT("Are you sure you want to delete this history item?"),TranslateT("Delete History"),MB_YESNO|MB_ICONQUESTION)==IDYES) {
+ hDbevent = (HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,LB_GETITEMDATA,index,0);
+ CallService(MS_DB_EVENT_DELETE,(WPARAM)hContact,(LPARAM)hDbevent);
+ SendMessage(hwndDlg,DM_HREBUILD,0,0);
+ }
+ return TRUE;
+ }
+ case IDC_LIST:
+ if (HIWORD(wParam) == LBN_SELCHANGE)
+ { TCHAR str[8192],*contactName;
+ HANDLE hDbEvent;
+ DBEVENTINFO dbei;
+ int sel;
+ sel=SendDlgItemMessage(hwndDlg,IDC_LIST,LB_GETCURSEL,0,0);
+ if(sel==LB_ERR) { EnableWindow(GetDlgItem(hwndDlg,IDC_DELETEHISTORY),FALSE); break; }
+ EnableWindow(GetDlgItem(hwndDlg,IDC_DELETEHISTORY),TRUE);
+ contactName=(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)hContact,GCDNF_TCHAR);
+ hDbEvent=(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,LB_GETITEMDATA,sel,0);
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)hDbEvent,0);
+ dbei.pBlob=(PBYTE)mir_alloc(dbei.cbBlob);
+ CallService(MS_DB_EVENT_GET,(WPARAM)hDbEvent,(LPARAM)&dbei);
+ GetObjectDescription(&dbei,str,SIZEOF(str));
+ mir_free(dbei.pBlob);
+ if(str[0]) SetDlgItemText(hwndDlg, IDC_EDIT, str);
+ }
+ return TRUE;
+ }
+ break;
+ case DM_FINDNEXT:
+ { TCHAR str[1024];
+ HANDLE hDbEvent,hDbEventStart;
+ DBEVENTINFO dbei;
+ int newBlobSize,oldBlobSize;
+
+ int index = SendDlgItemMessage(hwndDlg,IDC_LIST,LB_GETCURSEL,0,0);
+ if ( index == LB_ERR )
+ break;
+
+ hDbEventStart=(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,LB_GETITEMDATA,index,0);
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.pBlob=NULL;
+ oldBlobSize=0;
+ for(;;) {
+ hDbEvent = (HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,LB_GETITEMDATA,++index,0);
+ if(hDbEvent == ( HANDLE )LB_ERR) {
+ index = -1;
+ continue;
+ }
+ if(hDbEvent==hDbEventStart) break;
+ newBlobSize=CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)hDbEvent,0);
+ if(newBlobSize>oldBlobSize) {
+ dbei.pBlob=(PBYTE)mir_realloc(dbei.pBlob,newBlobSize);
+ oldBlobSize=newBlobSize;
+ }
+ dbei.cbBlob=oldBlobSize;
+ CallService(MS_DB_EVENT_GET,(WPARAM)hDbEvent,(LPARAM)&dbei);
+ GetObjectDescription(&dbei,str,SIZEOF(str));
+ if(str[0]) {
+ CharUpperBuff(str,lstrlen(str));
+ if( _tcsstr(str,(const TCHAR*)lParam)!=NULL) {
+ SendDlgItemMessage(hwndDlg,IDC_LIST,LB_SETCURSEL,index,0);
+ SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_LIST,LBN_SELCHANGE),0);
+ break;
+ } } }
+
+ mir_free(dbei.pBlob);
+ break;
+ }
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK DlgProcHistoryFind(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLong(hwndDlg, GWL_USERDATA, lParam);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK://find Next
+ { HWND hwndParent;
+ TCHAR str[128];
+
+ hwndParent=(HWND)GetWindowLong(hwndDlg, GWL_USERDATA);
+ GetDlgItemText(hwndDlg, IDC_FINDWHAT, str, SIZEOF(str));
+ CharUpperBuff(str,lstrlen(str));
+ SendMessage(hwndParent,DM_FINDNEXT,0,(LPARAM)str);
+ return TRUE;
+ }
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+
+ }
+ break;
+ }
+ return FALSE;
+}
diff --git a/miranda-wine/src/modules/idle/idle.c b/miranda-wine/src/modules/idle/idle.c
new file mode 100644
index 0000000..396fab9
--- /dev/null
+++ b/miranda-wine/src/modules/idle/idle.c
@@ -0,0 +1,415 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2005 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+#define IDLEMOD "Idle"
+#define IDL_USERIDLECHECK "UserIdleCheck"
+#define IDL_IDLEMETHOD "IdleMethod"
+#define IDL_IDLETIME1ST "IdleTime1st"
+#define IDL_IDLEONSAVER "IdleOnSaver" // IDC_SCREENSAVER
+#define IDL_IDLEONLOCK "IdleOnLock" // IDC_LOCKED
+#define IDL_IDLEONTSDC "IdleOnTerminalDisconnect" //
+#define IDL_IDLEPRIVATE "IdlePrivate" // IDC_IDLEPRIVATE
+#define IDL_IDLESTATUSLOCK "IdleStatusLock" // IDC_IDLESTATUSLOCK
+#define IDL_AAENABLE "AAEnable"
+#define IDL_AASTATUS "AAStatus"
+
+#define IdleObject_IsIdle(obj) (obj->state&0x1)
+#define IdleObject_SetIdle(obj) (obj->state|=0x1)
+#define IdleObject_ClearIdle(obj) (obj->state&=~0x1)
+
+// either use meth 0,1 or figure out which one
+#define IdleObject_UseMethod0(obj) (obj->state&=~0x2)
+#define IdleObject_UseMethod1(obj) (obj->state|=0x2)
+#define IdleObject_GetMethod(obj) (obj->state&0x2)
+
+#define IdleObject_IdleCheckSaver(obj) (obj->state&0x4)
+#define IdleObject_SetSaverCheck(obj) (obj->state|=0x4)
+
+#define IdleObject_IdleCheckWorkstation(obj) (obj->state&0x8)
+#define IdleObject_SetWorkstationCheck(obj) (obj->state|=0x8)
+
+#define IdleObject_IsPrivacy(obj) (obj->state&0x10)
+#define IdleObject_SetPrivacy(obj) (obj->state|=0x10)
+
+#define IdleObject_SetStatusLock(obj) (obj->state|=0x20)
+
+#define IdleObject_IdleCheckTerminal(obj) (obj->state|=0x40)
+#define IdleObject_SetTerminalCheck(obj) (obj->state|=0x40)
+
+//#include <Wtsapi32.h>
+
+#ifndef _INC_WTSAPI
+
+#define WTS_CURRENT_SERVER_HANDLE ((HANDLE)NULL)
+#define WTS_CURRENT_SESSION ((DWORD)-1)
+
+typedef enum _WTS_CONNECTSTATE_CLASS {
+ WTSActive, // User logged on to WinStation
+ WTSConnected, // WinStation connected to client
+ WTSConnectQuery, // In the process of connecting to client
+ WTSShadow, // Shadowing another WinStation
+ WTSDisconnected, // WinStation logged on without client
+ WTSIdle, // Waiting for client to connect
+ WTSListen, // WinStation is listening for connection
+ WTSReset, // WinStation is being reset
+ WTSDown, // WinStation is down due to error
+ WTSInit, // WinStation in initialization
+} WTS_CONNECTSTATE_CLASS;
+
+
+typedef enum _WTS_INFO_CLASS {
+ WTSInitialProgram,
+ WTSApplicationName,
+ WTSWorkingDirectory,
+ WTSOEMId,
+ WTSSessionId,
+ WTSUserName,
+ WTSWinStationName,
+ WTSDomainName,
+ WTSConnectState,
+ WTSClientBuildNumber,
+ WTSClientName,
+ WTSClientDirectory,
+ WTSClientProductId,
+ WTSClientHardwareId,
+ WTSClientAddress,
+ WTSClientDisplay,
+ WTSClientProtocolType,
+} WTS_INFO_CLASS;
+
+#endif
+
+VOID (WINAPI *_WTSFreeMemory)(PVOID);
+BOOL (WINAPI *_WTSQuerySessionInformation)(HANDLE, DWORD, WTS_INFO_CLASS, PVOID, DWORD*);
+
+BOOL WTSAPI = FALSE;
+
+BOOL InitWTSAPI()
+{
+ HMODULE hDll = LoadLibraryA("wtsapi32.dll");
+ if (hDll) {
+ _WTSFreeMemory = (VOID (WINAPI *)(PVOID))GetProcAddress(hDll, "WTSFreeMemory");
+ #ifdef UNICODE
+ _WTSQuerySessionInformation = (BOOL (WINAPI *)(HANDLE, DWORD, WTS_INFO_CLASS, PVOID, DWORD*))GetProcAddress(hDll, "WTSQuerySessionInformationW");
+ #else
+ _WTSQuerySessionInformation = (BOOL (WINAPI *)(HANDLE, DWORD, WTS_INFO_CLASS, PVOID, DWORD*))GetProcAddress(hDll, "WTSQuerySessionInformationA");
+ #endif
+
+ if (_WTSFreeMemory && _WTSQuerySessionInformation) return 1;
+ }
+ return 0;
+}
+
+BOOL IsTerminalDisconnected()
+{
+ PVOID pBuffer = NULL;
+ DWORD pBytesReturned = 0;
+ BOOL result = FALSE;
+
+ if (!WTSAPI) return FALSE;
+
+ if (_WTSQuerySessionInformation(
+ WTS_CURRENT_SERVER_HANDLE,
+ WTS_CURRENT_SESSION,
+ WTSConnectState,
+ &pBuffer,
+ &pBytesReturned)
+ ) {
+
+ if (*(PDWORD)pBuffer == WTSDisconnected)
+ result = TRUE;
+
+ _WTSFreeMemory(pBuffer);
+ }
+ return result;
+}
+
+typedef struct {
+ UINT hTimer;
+ unsigned int useridlecheck;
+ unsigned int state;
+ unsigned int minutes; // user setting, number of minutes of inactivity to wait for
+ POINT mousepos;
+ unsigned int mouseidle;
+ int aastatus;
+} IdleObject;
+
+static int aa_Status[] = {ID_STATUS_AWAY, ID_STATUS_NA, ID_STATUS_OCCUPIED, ID_STATUS_DND, ID_STATUS_ONTHEPHONE, ID_STATUS_OUTTOLUNCH};
+
+static IdleObject gIdleObject;
+static HANDLE hIdleEvent;
+static BOOL (WINAPI * MyGetLastInputInfo)(PLASTINPUTINFO);
+
+void CALLBACK IdleTimer(HWND hwnd, UINT umsg, UINT idEvent, DWORD dwTime);
+static BOOL IsWorkstationLocked(void);
+static BOOL IsScreenSaverRunning(void);
+
+static void IdleObject_ReadSettings(IdleObject * obj)
+{
+ obj->useridlecheck = DBGetContactSettingByte(NULL, IDLEMOD, IDL_USERIDLECHECK, 0);
+ obj->minutes = DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLETIME1ST, 10);
+ obj->aastatus = !DBGetContactSettingByte(NULL, IDLEMOD, IDL_AAENABLE, 0) ? 0 : DBGetContactSettingWord(NULL, IDLEMOD, IDL_AASTATUS, 0);
+ if ( DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEMETHOD, 0) ) IdleObject_UseMethod1(obj);
+ else IdleObject_UseMethod0(obj);
+ if ( DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEONSAVER, 0) ) IdleObject_SetSaverCheck(obj);
+ if ( DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEONLOCK, 0 ) ) IdleObject_SetWorkstationCheck(obj);
+ if ( DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEPRIVATE, 0) ) IdleObject_SetPrivacy(obj);
+ if ( DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLESTATUSLOCK, 0) ) IdleObject_SetStatusLock(obj);
+ if ( DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEONTSDC, 0) ) IdleObject_SetTerminalCheck(obj);
+}
+
+static void IdleObject_Create(IdleObject * obj)
+{
+ ZeroMemory(obj, sizeof(IdleObject));
+ obj->hTimer=SetTimer(NULL, 0, 2000, IdleTimer);
+ IdleObject_ReadSettings(obj);
+}
+
+static void IdleObject_Destroy(IdleObject * obj)
+{
+ if (IdleObject_IsIdle(obj)) NotifyEventHooks(hIdleEvent, 0, 0);
+ IdleObject_ClearIdle(obj);
+ KillTimer(NULL, obj->hTimer);
+}
+
+static int IdleObject_IsUserIdle(IdleObject * obj)
+{
+ DWORD dwTick;
+ if ( IdleObject_GetMethod(obj) ) {
+ CallService(MS_SYSTEM_GETIDLE, 0, (DWORD)&dwTick);
+ return GetTickCount() - dwTick > (obj->minutes * 60 * 1000);
+ } else {
+ if ( MyGetLastInputInfo != NULL ) {
+ LASTINPUTINFO ii;
+ ZeroMemory(&ii,sizeof(ii));
+ ii.cbSize=sizeof(ii);
+ if ( MyGetLastInputInfo(&ii) ) return GetTickCount() - ii.dwTime > (obj->minutes * 60 * 1000);
+ } else {
+ POINT pt;
+ GetCursorPos(&pt);
+ if ( pt.x != obj->mousepos.x || pt.y != obj->mousepos.y ) {
+ obj->mousepos=pt;
+ obj->mouseidle=0;
+ } else obj->mouseidle += 2;
+ if ( obj->mouseidle ) return obj->mouseidle * 1000 >= (obj->minutes * 60 * 1000);
+ }
+ return FALSE;
+ }
+}
+
+static void IdleObject_Tick(IdleObject * obj)
+{
+ BOOL idle = ( obj->useridlecheck ? IdleObject_IsUserIdle(obj) : FALSE )
+ || ( IdleObject_IdleCheckSaver(obj) ? IsScreenSaverRunning() : FALSE )
+ || ( IdleObject_IdleCheckWorkstation(obj) ? IsWorkstationLocked() : FALSE )
+ || (IdleObject_IdleCheckTerminal(obj) ? IsTerminalDisconnected() : FALSE );
+
+ unsigned int flags = IdleObject_IsPrivacy(obj) ? IDF_PRIVACY : 0;
+
+ if ( !IdleObject_IsIdle(obj) && idle ) {
+ IdleObject_SetIdle(obj);
+ NotifyEventHooks(hIdleEvent, 0, IDF_ISIDLE | flags);
+ }
+ if ( IdleObject_IsIdle(obj) && !idle ) {
+ IdleObject_ClearIdle(obj);
+ NotifyEventHooks(hIdleEvent, 0, flags);
+ }
+}
+
+void CALLBACK IdleTimer(HWND hwnd, UINT umsg, UINT idEvent, DWORD dwTime)
+{
+ if ( gIdleObject.hTimer == idEvent ) {
+ IdleObject_Tick(&gIdleObject);
+ }
+}
+
+// delphi code here http://www.swissdelphicenter.ch/torry/printcode.php?id=2048
+static BOOL IsWorkstationLocked(void)
+{
+ BOOL rc=0;
+ HDESK hDesk = OpenDesktop( _T("default"), 0, FALSE, DESKTOP_SWITCHDESKTOP);
+ if ( hDesk != 0 ) {
+ rc = SwitchDesktop(hDesk) == FALSE;
+ CloseDesktop(hDesk);
+ }
+ return rc;
+}
+
+static BOOL IsScreenSaverRunning()
+{
+ BOOL rc = FALSE;
+ SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &rc, FALSE);
+ return rc;
+}
+
+int IdleGetStatusIndex(WORD status)
+{
+ int j;
+ for (j = 0; j < SIZEOF(aa_Status); j++ ) {
+ if (aa_Status[j]==status) return j;
+ }
+ return 0;
+}
+
+static BOOL CALLBACK IdleOptsDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ {
+ int j;
+ int method = DBGetContactSettingByte(NULL,IDLEMOD,IDL_IDLEMETHOD, 0);
+ TranslateDialogDefault(hwndDlg);
+ CheckDlgButton(hwndDlg, IDC_IDLESHORT, DBGetContactSettingByte(NULL,IDLEMOD,IDL_USERIDLECHECK,0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_IDLEONWINDOWS, method == 0 ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_IDLEONMIRANDA, method ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SCREENSAVER, DBGetContactSettingByte(NULL,IDLEMOD,IDL_IDLEONSAVER,0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_LOCKED, DBGetContactSettingByte(NULL,IDLEMOD,IDL_IDLEONLOCK,0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_IDLEPRIVATE, DBGetContactSettingByte(NULL,IDLEMOD,IDL_IDLEPRIVATE,0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_IDLESTATUSLOCK, DBGetContactSettingByte(NULL,IDLEMOD,IDL_IDLESTATUSLOCK,0) ? BST_CHECKED : BST_UNCHECKED);
+ SendDlgItemMessage(hwndDlg, IDC_IDLESPIN, UDM_SETBUDDY, (WPARAM)GetDlgItem(hwndDlg, IDC_IDLE1STTIME), 0);
+ SendDlgItemMessage(hwndDlg, IDC_IDLESPIN, UDM_SETRANGE32, 1, 60);
+ SendDlgItemMessage(hwndDlg, IDC_IDLESPIN, UDM_SETPOS, 0, MAKELONG((short) DBGetContactSettingByte(NULL,IDLEMOD,IDL_IDLETIME1ST, 10), 0));
+ SendDlgItemMessage(hwndDlg, IDC_IDLE1STTIME, EM_LIMITTEXT, (WPARAM)2, 0);
+
+ CheckDlgButton(hwndDlg, IDC_AASHORTIDLE, DBGetContactSettingByte(NULL, IDLEMOD, IDL_AAENABLE, 0) ? BST_CHECKED:BST_UNCHECKED);
+ for ( j = 0; j < SIZEOF(aa_Status); j++ ) {
+ TCHAR* szDesc = LangPackPcharToTchar(( LPCSTR )CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, (WPARAM)aa_Status[j], 0));
+ SendDlgItemMessage(hwndDlg, IDC_AASTATUS, CB_ADDSTRING, 0, (LPARAM)szDesc );
+ mir_free( szDesc );
+ }
+
+ j = IdleGetStatusIndex((WORD)(DBGetContactSettingWord(NULL, IDLEMOD, IDL_AASTATUS, 0)));
+ SendDlgItemMessage(hwndDlg, IDC_AASTATUS, CB_SETCURSEL, j, 0);
+ SendMessage(hwndDlg, WM_USER+2, 0, 0);
+ return TRUE;
+ }
+ case WM_USER+2:
+ {
+ BOOL checked = IsDlgButtonChecked(hwndDlg, IDC_IDLESHORT) == BST_CHECKED;
+ EnableWindow(GetDlgItem(hwndDlg, IDC_IDLEONWINDOWS), checked);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_IDLEONMIRANDA), checked);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_IDLE1STTIME), checked);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_AASTATUS), IsDlgButtonChecked(hwndDlg, IDC_AASHORTIDLE)==BST_CHECKED?1:0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_IDLESTATUSLOCK), IsDlgButtonChecked(hwndDlg, IDC_AASHORTIDLE)==BST_CHECKED?1:0);
+ break;
+ }
+ case WM_NOTIFY:
+ {
+ NMHDR * hdr = (NMHDR *)lParam;
+ if ( hdr && hdr->code == PSN_APPLY ) {
+ int method = IsDlgButtonChecked(hwndDlg, IDC_IDLEONWINDOWS) == BST_CHECKED;
+ int mins = SendDlgItemMessage(hwndDlg, IDC_IDLESPIN, UDM_GETPOS, 0, 0);
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLETIME1ST, (BYTE)(HIWORD(mins) == 0 ? LOWORD(mins) : 10));
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_USERIDLECHECK, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_IDLESHORT) == BST_CHECKED));
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLEMETHOD, (BYTE)(method ? 0 : 1));
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLEONSAVER, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_SCREENSAVER) == BST_CHECKED));
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLEONLOCK, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_LOCKED) == BST_CHECKED));
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLEPRIVATE, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_IDLEPRIVATE) == BST_CHECKED));
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_AAENABLE, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_AASHORTIDLE)==BST_CHECKED?1:0));
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLESTATUSLOCK, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_IDLESTATUSLOCK)==BST_CHECKED?1:0));
+ {
+ int curSel = SendDlgItemMessage(hwndDlg, IDC_AASTATUS, CB_GETCURSEL, 0, 0);
+ if ( curSel != CB_ERR ) {
+ DBWriteContactSettingWord(NULL, IDLEMOD, IDL_AASTATUS, (WORD)(aa_Status[curSel]));
+ }
+ }
+ // destroy any current idle and reset settings.
+ IdleObject_Destroy(&gIdleObject);
+ IdleObject_Create(&gIdleObject);
+ }
+ break;
+ }
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_IDLE1STTIME:
+ {
+ int min;
+ if ( (HWND)lParam != GetFocus() || HIWORD(wParam) != EN_CHANGE ) return FALSE;
+ min=GetDlgItemInt(hwndDlg, IDC_IDLE1STTIME, NULL, FALSE);
+ if ( min == 0 && GetWindowTextLength(GetDlgItem(hwndDlg, IDC_IDLE1STTIME)) )
+ SendDlgItemMessage(hwndDlg, IDC_IDLESPIN, UDM_SETPOS, 0, MAKELONG((short) 1, 0));
+ break;
+ }
+ case IDC_IDLESHORT:
+ case IDC_AASHORTIDLE:
+ SendMessage(hwndDlg, WM_USER+2, 0, 0);
+ break;
+
+ case IDC_AASTATUS:
+ if ( HIWORD(wParam) != CBN_SELCHANGE )
+ return TRUE;
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ return FALSE;
+}
+
+static int IdleOptInit(WPARAM wParam, LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.position = 100000000;
+ odp.hInstance = GetModuleHandle(NULL);
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_IDLE);
+ odp.pszGroup = "Status";
+ odp.pszTitle = "Idle";
+ odp.pfnDlgProc = IdleOptsDlgProc;
+ odp.flags = ODPF_BOLDGROUPS;
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
+
+static int IdleGetInfo(WPARAM wParam, LPARAM lParam)
+{
+ MIRANDA_IDLE_INFO *mii = (MIRANDA_IDLE_INFO*)lParam;
+
+ if (!mii || mii->cbSize!=sizeof(MIRANDA_IDLE_INFO)) return 1;
+ mii->idleTime = gIdleObject.minutes;
+ mii->privacy = gIdleObject.state&0x10;
+ mii->aaStatus = gIdleObject.aastatus;
+ mii->aaLock = gIdleObject.state&0x20;
+ return 0;
+}
+
+static int UnloadIdleModule(WPARAM wParam, LPARAM lParam)
+{
+ IdleObject_Destroy(&gIdleObject);
+ DestroyHookableEvent(hIdleEvent);
+ hIdleEvent=NULL;
+ return 0;
+}
+
+int LoadIdleModule(void)
+{
+ WTSAPI = InitWTSAPI();
+ MyGetLastInputInfo=(BOOL (WINAPI *)(LASTINPUTINFO*))GetProcAddress(GetModuleHandleA("user32"), "GetLastInputInfo");
+ hIdleEvent=CreateHookableEvent(ME_IDLE_CHANGED);
+ IdleObject_Create(&gIdleObject);
+ CreateServiceFunction(MS_IDLE_GETIDLEINFO, IdleGetInfo);
+ HookEvent(ME_SYSTEM_SHUTDOWN, UnloadIdleModule);
+ HookEvent(ME_OPT_INITIALISE, IdleOptInit);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/ignore/ignore.c b/miranda-wine/src/modules/ignore/ignore.c
new file mode 100644
index 0000000..192cb3d
--- /dev/null
+++ b/miranda-wine/src/modules/ignore/ignore.c
@@ -0,0 +1,449 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+#define IGNOREEVENT_MAX 6
+
+static const DWORD ignoreIdToPf1[IGNOREEVENT_MAX]={PF1_IMRECV,PF1_URLRECV,PF1_FILERECV,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};
+
+static DWORD GetMask(HANDLE hContact)
+{
+ DWORD mask=DBGetContactSettingDword(hContact,"Ignore","Mask1",(DWORD)(-1));
+ if(mask==(DWORD)(-1)) {
+ if(hContact==NULL) mask=0;
+ else {
+ if(DBGetContactSettingByte(hContact,"CList","Hidden",0) || DBGetContactSettingByte(hContact,"CList","NotOnList",0))
+ mask=DBGetContactSettingDword(NULL,"Ignore","Mask1",0);
+ else
+ mask=DBGetContactSettingDword(NULL,"Ignore","Default1",0);
+ }
+ }
+ return mask;
+}
+
+static void SetListGroupIcons(HWND hwndList,HANDLE hFirstItem,HANDLE hParentItem,int *groupChildCount)
+{
+ int typeOfFirst;
+ int iconOn[IGNOREEVENT_MAX]={1,1,1,1,1,1};
+ int childCount[IGNOREEVENT_MAX]={0,0,0,0,0,0},i;
+ int iImage;
+ HANDLE hItem,hChildItem;
+
+ typeOfFirst=SendMessage(hwndList,CLM_GETITEMTYPE,(WPARAM)hFirstItem,0);
+ //check groups
+ if(typeOfFirst==CLCIT_GROUP) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hFirstItem);
+ while(hItem) {
+ hChildItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_CHILD,(LPARAM)hItem);
+ if(hChildItem) SetListGroupIcons(hwndList,hChildItem,hItem,childCount);
+ for(i=0; i < SIZEOF(iconOn); i++)
+ if(iconOn[i] && SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,i)==0) iconOn[i]=0;
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hItem);
+ }
+ //check contacts
+ if(typeOfFirst==CLCIT_CONTACT) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hFirstItem);
+ while(hItem) {
+ for( i=0; i < SIZEOF(iconOn); i++ ) {
+ iImage=SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,i);
+ if(iconOn[i] && iImage==0) iconOn[i]=0;
+ if(iImage!=0xFF) childCount[i]++;
+ }
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hItem);
+ }
+ //set icons
+ for( i=0; i < SIZEOF(iconOn); i++ ) {
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hParentItem,MAKELPARAM(i,childCount[i]?(iconOn[i]?i+3:0):0xFF));
+ if(groupChildCount) groupChildCount[i]+=childCount[i];
+ }
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hParentItem,MAKELPARAM(IGNOREEVENT_MAX,1));
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hParentItem,MAKELPARAM(IGNOREEVENT_MAX+1,2));
+}
+
+static void SetAllChildIcons(HWND hwndList,HANDLE hFirstItem,int iColumn,int iImage)
+{
+ int typeOfFirst,iOldIcon;
+ HANDLE hItem,hChildItem;
+
+ typeOfFirst=SendMessage(hwndList,CLM_GETITEMTYPE,(WPARAM)hFirstItem,0);
+ //check groups
+ if(typeOfFirst==CLCIT_GROUP) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hFirstItem);
+ while(hItem) {
+ hChildItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_CHILD,(LPARAM)hItem);
+ if(hChildItem) SetAllChildIcons(hwndList,hChildItem,iColumn,iImage);
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hItem);
+ }
+ //check contacts
+ if(typeOfFirst==CLCIT_CONTACT) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hFirstItem);
+ while(hItem) {
+ iOldIcon=SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,iColumn);
+ if(iOldIcon!=0xFF && iOldIcon!=iImage) SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(iColumn,iImage));
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hItem);
+ }
+}
+
+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,4,0);
+ SendMessage(hwndList,CLM_SETINDENT,10,0);
+ SendMessage(hwndList,CLM_SETHIDEEMPTYGROUPS,1,0);
+ for(i=0;i<=FONTID_MAX;i++)
+ SendMessage(hwndList,CLM_SETTEXTCOLOR,i,GetSysColor(COLOR_WINDOWTEXT));
+}
+
+static void SetIconsForColumn(HWND hwndList,HANDLE hItem,HANDLE hItemAll,int iColumn,int iImage)
+{
+ int itemType;
+
+ itemType=SendMessage(hwndList,CLM_GETITEMTYPE,(WPARAM)hItem,0);
+ if(itemType==CLCIT_CONTACT) {
+ int oldiImage = SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,iColumn);
+ if (oldiImage!=0xFF&&oldiImage!=iImage)
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(iColumn,iImage));
+ }
+ else if(itemType==CLCIT_INFO) {
+ if(hItem==hItemAll) SetAllChildIcons(hwndList,hItem,iColumn,iImage);
+ else SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(iColumn,iImage)); //hItemUnknown
+ }
+ else if(itemType==CLCIT_GROUP) {
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_CHILD,(LPARAM)hItem);
+ if(hItem) SetAllChildIcons(hwndList,hItem,iColumn,iImage);
+ }
+}
+
+static void InitialiseItem(HWND hwndList,HANDLE hContact,HANDLE hItem,DWORD protoCaps)
+{
+ DWORD mask;
+ int i;
+
+ mask=GetMask(hContact);
+ for(i=0;i<IGNOREEVENT_MAX;i++)
+ if(ignoreIdToPf1[i]==0xFFFFFFFF || protoCaps&ignoreIdToPf1[i])
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(i,mask&(1<<i)?i+3:0));
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(IGNOREEVENT_MAX,1));
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(IGNOREEVENT_MAX+1,2));
+}
+
+static void SaveItemMask(HWND hwndList,HANDLE hContact,HANDLE hItem,const char *pszSetting)
+{
+ DWORD mask;
+ int i,iImage;
+
+ mask=0;
+ for(i=0;i<IGNOREEVENT_MAX;i++) {
+ iImage=SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(i,0));
+ if(iImage && iImage!=0xFF) mask|=1<<i;
+ }
+ DBWriteContactSettingDword(hContact,"Ignore",pszSetting,mask);
+}
+
+static void SetAllContactIcons(HWND hwndList)
+{
+ HANDLE hContact,hItem;
+ DWORD protoCaps;
+ char *szProto;
+
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ do {
+ hItem=(HANDLE)SendMessage(hwndList,CLM_FINDCONTACT,(WPARAM)hContact,0);
+ if(hItem && SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(IGNOREEVENT_MAX,0))==0xFF) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if(szProto==NULL) protoCaps=0;
+ else protoCaps=CallProtoService(szProto,PS_GETCAPS,PFLAGNUM_1,0);
+ InitialiseItem(hwndList,hContact,hItem,protoCaps);
+ if(!DBGetContactSettingByte(hContact,"CList","Hidden",0))
+ SendMessage(hwndList,CLM_SETCHECKMARK,(WPARAM)hItem,1);
+ }
+ } while(hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0));
+}
+
+static BOOL CALLBACK DlgProcIgnoreOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static HICON hIcons[IGNOREEVENT_MAX+2];
+ static HANDLE hItemAll,hItemUnknown;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ { HIMAGELIST hIml;
+ int i;
+ hIml=ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),(IsWinVerXPPlus()?ILC_COLOR32:ILC_COLOR16)|ILC_MASK,3+IGNOREEVENT_MAX,3+IGNOREEVENT_MAX);
+ ImageList_AddIcon(hIml,LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_SMALLDOT)));
+ ImageList_AddIcon(hIml,LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_FILLEDBLOB)));
+ ImageList_AddIcon(hIml,LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_EMPTYBLOB)));
+ ImageList_AddIcon(hIml,LoadSkinnedIcon(SKINICON_EVENT_MESSAGE));
+ ImageList_AddIcon(hIml,LoadSkinnedIcon(SKINICON_EVENT_URL));
+ ImageList_AddIcon(hIml,LoadSkinnedIcon(SKINICON_EVENT_FILE));
+ ImageList_AddIcon(hIml,LoadSkinnedIcon(SKINICON_OTHER_USERONLINE));
+ ImageList_AddIcon(hIml,LoadSkinnedIcon(SKINICON_OTHER_MIRANDA));
+ ImageList_AddIcon(hIml,LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_ADDCONTACT)));
+ SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_SETEXTRAIMAGELIST,0,(LPARAM)hIml);
+ for( i=0; i < SIZEOF(hIcons); i++ )
+ hIcons[i]=ImageList_GetIcon(hIml,1+i,ILD_NORMAL);
+ }
+ SendDlgItemMessage(hwndDlg,IDC_ALLICON,STM_SETICON,(WPARAM)hIcons[0],0);
+ SendDlgItemMessage(hwndDlg,IDC_NONEICON,STM_SETICON,(WPARAM)hIcons[1],0);
+ SendDlgItemMessage(hwndDlg,IDC_MSGICON,STM_SETICON,(WPARAM)hIcons[2],0);
+ SendDlgItemMessage(hwndDlg,IDC_URLICON,STM_SETICON,(WPARAM)hIcons[3],0);
+ SendDlgItemMessage(hwndDlg,IDC_FILEICON,STM_SETICON,(WPARAM)hIcons[4],0);
+ SendDlgItemMessage(hwndDlg,IDC_ONLINEICON,STM_SETICON,(WPARAM)hIcons[5],0);
+ SendDlgItemMessage(hwndDlg,IDC_AUTHICON,STM_SETICON,(WPARAM)hIcons[6],0);
+ SendDlgItemMessage(hwndDlg,IDC_ADDED,STM_SETICON,(WPARAM)hIcons[7],0);
+
+ if(!SendMessage(GetParent(hwndDlg),PSM_ISEXPERT,0,0)) {
+ SetWindowLong(GetDlgItem(hwndDlg,IDC_LIST),GWL_STYLE,GetWindowLong(GetDlgItem(hwndDlg,IDC_LIST),GWL_STYLE)&~(CLS_CHECKBOXES|CLS_GROUPCHECKBOXES|CLS_SHOWHIDDEN));
+ SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_AUTOREBUILD,0,0);
+ }
+
+ ResetListOptions(GetDlgItem(hwndDlg,IDC_LIST));
+ SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_SETEXTRACOLUMNS,IGNOREEVENT_MAX+2,0);
+
+ { CLCINFOITEM cii={0};
+ cii.cbSize=sizeof(cii);
+ cii.flags=CLCIIF_GROUPFONT;
+ cii.pszText=TranslateT("** All contacts **");
+ hItemAll=(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_ADDINFOITEM,0,(LPARAM)&cii);
+
+ cii.pszText=TranslateT("** Unknown contacts **");
+ hItemUnknown=(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_ADDINFOITEM,0,(LPARAM)&cii);
+ InitialiseItem(GetDlgItem(hwndDlg,IDC_LIST),NULL,hItemUnknown,0xFFFFFFFF);
+ }
+
+ SetAllContactIcons(GetDlgItem(hwndDlg,IDC_LIST));
+ SetListGroupIcons(GetDlgItem(hwndDlg,IDC_LIST),(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETNEXTITEM,CLGN_ROOT,0),hItemAll,NULL);
+ return TRUE;
+ case WM_SETFOCUS:
+ SetFocus(GetDlgItem(hwndDlg,IDC_LIST));
+ break;
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case IDC_LIST:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case CLN_NEWCONTACT:
+ case CLN_LISTREBUILT:
+ SetAllContactIcons(GetDlgItem(hwndDlg,IDC_LIST));
+ //fall through
+ case CLN_CONTACTMOVED:
+ SetListGroupIcons(GetDlgItem(hwndDlg,IDC_LIST),(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETNEXTITEM,CLGN_ROOT,0),hItemAll,NULL);
+ break;
+ case CLN_OPTIONSCHANGED:
+ ResetListOptions(GetDlgItem(hwndDlg,IDC_LIST));
+ break;
+ case CLN_CHECKCHANGED:
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case NM_CLICK:
+ { HANDLE hItem;
+ NMCLISTCONTROL *nm=(NMCLISTCONTROL*)lParam;
+ DWORD hitFlags;
+ int iImage;
+
+ if(nm->iColumn==-1) break;
+ hItem=(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_HITTEST,(WPARAM)&hitFlags,MAKELPARAM(nm->pt.x,nm->pt.y));
+ if(hItem==NULL) break;
+ if(!(hitFlags&CLCHT_ONITEMEXTRA)) break;
+ if(nm->iColumn==IGNOREEVENT_MAX) { //ignore all
+ for(iImage=0;iImage<IGNOREEVENT_MAX;iImage++)
+ SetIconsForColumn(GetDlgItem(hwndDlg,IDC_LIST),hItem,hItemAll,iImage,iImage+3);
+ }
+ else if(nm->iColumn==IGNOREEVENT_MAX+1) { //ignore none
+ for(iImage=0;iImage<IGNOREEVENT_MAX;iImage++)
+ SetIconsForColumn(GetDlgItem(hwndDlg,IDC_LIST),hItem,hItemAll,iImage,0);
+ }
+ else {
+ iImage=SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(nm->iColumn,0));
+ if(iImage==0) iImage=nm->iColumn+3;
+ else if(iImage!=0xFF) iImage=0;
+ SetIconsForColumn(GetDlgItem(hwndDlg,IDC_LIST),hItem,hItemAll,nm->iColumn,iImage);
+ }
+ SetListGroupIcons(GetDlgItem(hwndDlg,IDC_LIST),(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETNEXTITEM,CLGN_ROOT,0),hItemAll,NULL);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ }
+ break;
+ case 0:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case PSN_APPLY:
+ { HANDLE hContact,hItem;
+
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ do {
+ hItem=(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_FINDCONTACT,(WPARAM)hContact,0);
+ if(hItem) SaveItemMask(GetDlgItem(hwndDlg,IDC_LIST),hContact,hItem,"Mask1");
+ if(SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETCHECKMARK,(WPARAM)hItem,0))
+ DBDeleteContactSetting(hContact,"CList","Hidden");
+ else
+ DBWriteContactSettingByte(hContact,"CList","Hidden",1);
+ } while(hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0));
+ SaveItemMask(GetDlgItem(hwndDlg,IDC_LIST),NULL,hItemAll,"Default1");
+ SaveItemMask(GetDlgItem(hwndDlg,IDC_LIST),NULL,hItemUnknown,"Mask1");
+ return TRUE;
+ }
+ case PSN_EXPERTCHANGED:
+ SetWindowLong(GetDlgItem(hwndDlg,IDC_LIST),GWL_STYLE,((PSHNOTIFY*)lParam)->lParam?GetWindowLong(GetDlgItem(hwndDlg,IDC_LIST),GWL_STYLE)|CLS_CHECKBOXES|CLS_GROUPCHECKBOXES|CLS_SHOWHIDDEN:GetWindowLong(GetDlgItem(hwndDlg,IDC_LIST),GWL_STYLE)&~(CLS_CHECKBOXES|CLS_GROUPCHECKBOXES|CLS_SHOWHIDDEN));
+ SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_AUTOREBUILD,0,0);
+ break;
+ }
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ { int i;
+ HIMAGELIST hIml;
+ for( i=0; i < SIZEOF(hIcons); i++ )
+ DestroyIcon(hIcons[i]);
+ hIml=(HIMAGELIST)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETEXTRAIMAGELIST,0,0);
+ ImageList_Destroy(hIml);
+ break;
+ }
+ }
+ return FALSE;
+}
+
+static UINT expertOnlyControls[]={IDC_STCHECKMARKS};
+static int IgnoreOptInitialise(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.position = 900000000;
+ odp.hInstance = GetModuleHandle(NULL);
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_IGNORE);
+ odp.pszTitle = "Ignore";
+ odp.pszGroup = "Events";
+ odp.pfnDlgProc = DlgProcIgnoreOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.expertOnlyControls = expertOnlyControls;
+ odp.nExpertOnlyControls = SIZEOF( expertOnlyControls );
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp);
+ return 0;
+}
+
+static int IsIgnored(WPARAM wParam,LPARAM lParam)
+{
+ DWORD mask=GetMask((HANDLE)wParam);
+ if(lParam<1 || lParam>IGNOREEVENT_MAX) return 1;
+ return (mask>>(lParam-1))&1;
+}
+
+static int Ignore(WPARAM wParam,LPARAM lParam)
+{
+ DWORD mask=GetMask((HANDLE)wParam);
+ if((lParam<1 || lParam>IGNOREEVENT_MAX) && lParam!=IGNOREEVENT_ALL) return 1;
+ if(lParam==IGNOREEVENT_ALL) mask=(1<<IGNOREEVENT_MAX)-1;
+ else mask|=1<<(lParam-1);
+ DBWriteContactSettingDword((HANDLE)wParam,"Ignore","Mask1",mask);
+ return 0;
+}
+
+static int Unignore(WPARAM wParam,LPARAM lParam)
+{
+ DWORD mask=GetMask((HANDLE)wParam);
+ if((lParam<1 || lParam>IGNOREEVENT_MAX) && lParam!=IGNOREEVENT_ALL) return 1;
+ if(lParam==IGNOREEVENT_ALL) mask=0;
+ else mask&=~(1<<(lParam-1));
+ DBWriteContactSettingDword((HANDLE)wParam,"Ignore","Mask1",mask);
+ return 0;
+}
+
+static int IgnoreContactAdded(WPARAM wParam,LPARAM lParam)
+{
+ CallService(MS_PROTO_ADDTOCONTACT,wParam,(LPARAM)"Ignore");
+ return 0;
+}
+
+static int IgnoreRecvMessage(WPARAM wParam,LPARAM lParam)
+{
+ if(IsIgnored((WPARAM)((CCSDATA*)lParam)->hContact,IGNOREEVENT_MESSAGE)) return 1;
+ return CallService(MS_PROTO_CHAINRECV,wParam,lParam);
+}
+
+static int IgnoreRecvUrl(WPARAM wParam,LPARAM lParam)
+{
+ if(IsIgnored((WPARAM)((CCSDATA*)lParam)->hContact,IGNOREEVENT_URL)) return 1;
+ return CallService(MS_PROTO_CHAINRECV,wParam,lParam);
+}
+
+static int IgnoreRecvFile(WPARAM wParam,LPARAM lParam)
+{
+ if(IsIgnored((WPARAM)((CCSDATA*)lParam)->hContact,IGNOREEVENT_FILE)) return 1;
+ return CallService(MS_PROTO_CHAINRECV,wParam,lParam);
+}
+
+static int IgnoreRecvAuth(WPARAM wParam,LPARAM lParam)
+{
+ if(IsIgnored((WPARAM)((CCSDATA*)lParam)->hContact,IGNOREEVENT_AUTHORIZATION)) return 1;
+ return CallService(MS_PROTO_CHAINRECV,wParam,lParam);
+}
+
+static int IgnoreAddedNotify(WPARAM wParam,LPARAM lParam)
+{
+ DBEVENTINFO *dbei=(DBEVENTINFO*)lParam;
+ if (dbei && dbei->eventType==EVENTTYPE_ADDED && dbei->pBlob!=NULL) {
+ HANDLE hContact;
+
+ hContact=*((PHANDLE)(dbei->pBlob+sizeof(DWORD)));
+ if (CallService(MS_DB_CONTACT_IS,(WPARAM)hContact,0) && IsIgnored((WPARAM)hContact,IGNOREEVENT_YOUWEREADDED))
+ return 1;
+ }
+ return 0;
+}
+
+int LoadIgnoreModule(void)
+{
+ PROTOCOLDESCRIPTOR pd;
+ HANDLE hContact;
+
+ ZeroMemory(&pd,sizeof(pd));
+ pd.cbSize=sizeof(pd);
+ pd.szName="Ignore";
+ pd.type=PROTOTYPE_IGNORE;
+ CallService(MS_PROTO_REGISTERMODULE,0,(LPARAM)&pd);
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ while(hContact!=NULL) {
+ if(!CallService(MS_PROTO_ISPROTOONCONTACT,(WPARAM)hContact,(LPARAM)"Ignore"))
+ CallService(MS_PROTO_ADDTOCONTACT,(WPARAM)hContact,(LPARAM)"Ignore");
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0);
+ }
+ HookEvent(ME_DB_CONTACT_ADDED,IgnoreContactAdded);
+ HookEvent(ME_DB_EVENT_FILTER_ADD,IgnoreAddedNotify);
+ CreateServiceFunction("Ignore"PSR_MESSAGE,IgnoreRecvMessage);
+ CreateServiceFunction("Ignore"PSR_URL,IgnoreRecvUrl);
+ CreateServiceFunction("Ignore"PSR_FILE,IgnoreRecvFile);
+ CreateServiceFunction("Ignore"PSR_AUTH,IgnoreRecvAuth);
+ HookEvent(ME_OPT_INITIALISE,IgnoreOptInitialise);
+ CreateServiceFunction(MS_IGNORE_ISIGNORED,IsIgnored);
+ CreateServiceFunction(MS_IGNORE_IGNORE,Ignore);
+ CreateServiceFunction(MS_IGNORE_UNIGNORE,Unignore);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/langpack/langpack.c b/miranda-wine/src/modules/langpack/langpack.c
new file mode 100644
index 0000000..c816025
--- /dev/null
+++ b/miranda-wine/src/modules/langpack/langpack.c
@@ -0,0 +1,362 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+int LoadLangPackServices(void);
+
+struct LangPackEntry {
+ unsigned linePos;
+ DWORD englishHash;
+ char *english; //not currently used, the hash does everything
+ char *local;
+ wchar_t *wlocal;
+};
+
+struct LangPackStruct {
+ TCHAR filename[MAX_PATH];
+ char language[64];
+ char lastModifiedUsing[64];
+ char authors[256];
+ char authorEmail[128];
+ struct LangPackEntry *entry;
+ int entryCount;
+ LCID localeID;
+ DWORD defaultANSICp;
+} static langPack;
+
+static void TrimString(char *str)
+{
+ int len,start;
+ len=lstrlenA(str);
+ while(str[0] && (unsigned char)str[len-1]<=' ') str[--len]=0;
+ for(start=0;str[start] && (unsigned char)str[start]<=' ';start++);
+ MoveMemory(str,str+start,len-start+1);
+}
+
+static void TrimStringSimple(char *str)
+{
+ if (str[lstrlenA(str)-1] == '\n') str[lstrlenA(str)-1] = '\0';
+ if (str[lstrlenA(str)-1] == '\r') str[lstrlenA(str)-1] = '\0';
+}
+
+static int IsEmpty(char *str)
+{
+ int i = 0;
+
+ while (str[i])
+ {
+ if (str[i]!=' '&&str[i]!='\r'&&str[i]!='\n')
+ return 0;
+ i++;
+ }
+ return 1;
+}
+
+static void ConvertBackslashes(char *str)
+{
+ char *pstr;
+ for(pstr=str;*pstr;pstr=CharNextA(pstr)) {
+ if(*pstr=='\\') {
+ switch(pstr[1]) {
+case 'n': *pstr='\n'; break;
+case 't': *pstr='\t'; break;
+case 'r': *pstr='\r'; break;
+default: *pstr=pstr[1]; break;
+ }
+ MoveMemory(pstr+1,pstr+2,lstrlenA(pstr+2)+1);
+ }
+ }
+}
+
+static DWORD LangPackHash(const char *szStr)
+{
+#if defined _M_IX86 && !defined _NUMEGA_BC_FINALCHECK && !defined __GNUC__
+ __asm { //this is mediocrely optimised, but I'm sure it's good enough
+ xor edx,edx
+ mov esi,szStr
+ xor cl,cl
+lph_top:
+ xor eax,eax
+ and cl,31
+ mov al,[esi]
+ inc esi
+ test al,al
+ jz lph_end
+ rol eax,cl
+ add cl,5
+ xor edx,eax
+ jmp lph_top
+lph_end:
+ mov eax,edx
+ }
+#else
+ DWORD hash=0;
+ int i;
+ int shift=0;
+ for(i=0;szStr[i];i++) {
+ hash^=szStr[i]<<shift;
+ if(shift>24) hash^=(szStr[i]>>(32-shift))&0x7F;
+ shift=(shift+5)&0x1F;
+ }
+ return hash;
+#endif
+}
+
+static DWORD LangPackHashW(const char *szStr)
+{
+#if defined _M_IX86 && !defined _NUMEGA_BC_FINALCHECK && !defined __GNUC__
+ __asm { //this is mediocrely optimised, but I'm sure it's good enough
+ xor edx,edx
+ mov esi,szStr
+ xor cl,cl
+lph_top:
+ xor eax,eax
+ and cl,31
+ mov al,[esi]
+ inc esi
+ inc esi
+ test al,al
+ jz lph_end
+ rol eax,cl
+ add cl,5
+ xor edx,eax
+ jmp lph_top
+lph_end:
+ mov eax,edx
+ }
+#else
+ DWORD hash=0;
+ int i;
+ int shift=0;
+ for(i=0;szStr[i];i+=2) {
+ hash^=szStr[i]<<shift;
+ if(shift>24) hash^=(szStr[i]>>(32-shift))&0x7F;
+ shift=(shift+5)&0x1F;
+ }
+ return hash;
+#endif
+}
+
+static int SortLangPackHashesProc(struct LangPackEntry *arg1,struct LangPackEntry *arg2)
+{
+ if(arg1->englishHash<arg2->englishHash) return -1;
+ if(arg1->englishHash>arg2->englishHash) return 1;
+ /* both source strings of the same hash (may not be the same string thou) put
+ the one that was written first to be found first */
+ if(arg1->linePos<arg2->linePos) return -1;
+ if(arg1->linePos>arg2->linePos) return 1;
+ return 0;
+}
+
+
+static int SortLangPackHashesProc2(struct LangPackEntry *arg1,struct LangPackEntry *arg2)
+{
+ if(arg1->englishHash<arg2->englishHash) return -1;
+ if(arg1->englishHash>arg2->englishHash) return 1;
+ return 0;
+}
+
+static int LoadLangPack(const TCHAR *szLangPack)
+{
+ FILE *fp;
+ char line[4096];
+ char *pszColon;
+ char *pszLine;
+ int entriesAlloced;
+ int startOfLine=0;
+ unsigned int linePos=1;
+ USHORT langID;
+
+ lstrcpy(langPack.filename,szLangPack);
+ fp = _tfopen(szLangPack,_T("rt"));
+ if(fp==NULL) return 1;
+ fgets(line,SIZEOF(line),fp);
+ TrimString(line);
+ if(lstrcmpA(line,"Miranda Language Pack Version 1")) {fclose(fp); return 2;}
+ //headers
+ while(!feof(fp)) {
+ startOfLine=ftell(fp);
+ if(fgets(line,SIZEOF(line),fp)==NULL) break;
+ TrimString(line);
+ if(IsEmpty(line) || line[0]==';' || line[0]==0) continue;
+ if(line[0]=='[') break;
+ pszColon=strchr(line,':');
+ if(pszColon==NULL) {fclose(fp); return 3;}
+ *pszColon=0;
+ if(!lstrcmpA(line,"Language")) {mir_snprintf(langPack.language,sizeof(langPack.language),"%s",pszColon+1); TrimString(langPack.language);}
+ else if(!lstrcmpA(line,"Last-Modified-Using")) {mir_snprintf(langPack.lastModifiedUsing,sizeof(langPack.lastModifiedUsing),"%s",pszColon+1); TrimString(langPack.lastModifiedUsing);}
+ else if(!lstrcmpA(line,"Authors")) {mir_snprintf(langPack.authors,sizeof(langPack.authors),"%s",pszColon+1); TrimString(langPack.authors);}
+ else if(!lstrcmpA(line,"Author-email")) {mir_snprintf(langPack.authorEmail,sizeof(langPack.authorEmail),"%s",pszColon+1); TrimString(langPack.authorEmail);}
+ else if(!lstrcmpA(line, "Locale")) {
+ char szBuf[20], *stopped;
+
+ TrimString(pszColon + 1);
+ langID = (USHORT)strtol(pszColon + 1, &stopped, 16);
+ langPack.localeID = MAKELCID(langID, 0);
+ GetLocaleInfoA(langPack.localeID, LOCALE_IDEFAULTANSICODEPAGE, szBuf, 10);
+ szBuf[5] = 0; // codepages have max. 5 digits
+ langPack.defaultANSICp = atoi(szBuf);
+ }
+ }
+ //body
+ fseek(fp,startOfLine,SEEK_SET);
+ entriesAlloced=0;
+ while(!feof(fp)) {
+ if(fgets(line,SIZEOF(line),fp)==NULL) break;
+ if(IsEmpty(line) || line[0]==';' || line[0]==0) continue;
+ TrimStringSimple(line);
+ ConvertBackslashes(line);
+ if(line[0]=='[' && line[lstrlenA(line)-1]==']') {
+ if(langPack.entryCount && langPack.entry[langPack.entryCount-1].local==NULL) {
+ if(langPack.entry[langPack.entryCount-1].english!=NULL) mir_free(langPack.entry[langPack.entryCount-1].english);
+ langPack.entryCount--;
+ }
+ pszLine = line+1;
+ line[lstrlenA(line)-1]='\0';
+ TrimStringSimple(line);
+ if(++langPack.entryCount>entriesAlloced) {
+ entriesAlloced+=128;
+ langPack.entry=(struct LangPackEntry*)mir_realloc(langPack.entry,sizeof(struct LangPackEntry)*entriesAlloced);
+ }
+ langPack.entry[langPack.entryCount-1].english=NULL;
+ langPack.entry[langPack.entryCount-1].englishHash=LangPackHash(pszLine);
+ langPack.entry[langPack.entryCount-1].local=NULL;
+ langPack.entry[langPack.entryCount-1].wlocal = NULL;
+ langPack.entry[langPack.entryCount-1].linePos=linePos++;
+ }
+ else if(langPack.entryCount) {
+ struct LangPackEntry* E = &langPack.entry[langPack.entryCount-1];
+
+ if(E->local==NULL) {
+ E->local=mir_strdup(line);
+ {
+ int iNeeded = MultiByteToWideChar(langPack.defaultANSICp, 0, line, -1, 0, 0);
+ E->wlocal = (wchar_t *)mir_alloc((iNeeded+1) * sizeof(wchar_t));
+ MultiByteToWideChar(langPack.defaultANSICp, 0, line, -1, E->wlocal, iNeeded);
+ }
+ }
+ else {
+ E->local=(char*)mir_realloc(E->local,lstrlenA(E->local)+lstrlenA(line)+2);
+ lstrcatA(E->local,"\n");
+ lstrcatA(E->local,line);
+ {
+ int iNeeded = MultiByteToWideChar(langPack.defaultANSICp, 0, line, -1, 0, 0);
+ int iOldLen = wcslen(E->wlocal);
+ E->wlocal = (wchar_t*)mir_realloc(E->wlocal, ( sizeof(wchar_t) * ( iOldLen + iNeeded + 2)));
+ wcscat(E->wlocal, L"\n");
+ MultiByteToWideChar( langPack.defaultANSICp, 0, line, -1, E->wlocal + iOldLen+1, iNeeded);
+ }
+ }
+ }
+ }
+ qsort(langPack.entry,langPack.entryCount,sizeof(struct LangPackEntry),(int(*)(const void*,const void*))SortLangPackHashesProc);
+ fclose(fp);
+ return 0;
+}
+
+char *LangPackTranslateString(const char *szEnglish, const int W)
+{
+ struct LangPackEntry key,*entry;
+
+ if ( langPack.entryCount == 0 || szEnglish == NULL ) return (char*)szEnglish;
+
+ key.englishHash = W ? LangPackHashW(szEnglish) : LangPackHash(szEnglish);
+ entry=(struct LangPackEntry*)bsearch(&key,langPack.entry,langPack.entryCount,sizeof(struct LangPackEntry),(int(*)(const void*,const void*))SortLangPackHashesProc2);
+ if(entry==NULL) return (char*)szEnglish;
+ while(entry>langPack.entry)
+ {
+ entry--;
+ if(entry->englishHash!=key.englishHash) {
+ entry++;
+ return W ? (char *)entry->wlocal : entry->local;
+ }
+ }
+ return W ? (char *)entry->wlocal : entry->local;
+}
+
+int LangPackGetDefaultCodePage()
+{
+ return (langPack.defaultANSICp == 0) ? CP_ACP : langPack.defaultANSICp;
+}
+
+int LangPackGetDefaultLocale()
+{
+ return (langPack.localeID == 0) ? LOCALE_USER_DEFAULT : langPack.localeID;
+}
+
+TCHAR* LangPackPcharToTchar( const char* pszStr )
+{
+ if ( pszStr == NULL )
+ return NULL;
+
+ #if defined( _UNICODE )
+ { int len = strlen( pszStr );
+ TCHAR* result = ( TCHAR* )alloca(( len+1 )*sizeof( TCHAR ));
+ MultiByteToWideChar( LangPackGetDefaultCodePage(), 0, pszStr, -1, result, len );
+ result[len] = 0;
+ return mir_wstrdup( TranslateW( result ));
+ }
+ #else
+ return mir_strdup( Translate( pszStr ));
+ #endif
+}
+
+static int LangPackShutdown(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ for(i=0;i<langPack.entryCount;i++) {
+ if(langPack.entry[i].english!=NULL) mir_free(langPack.entry[i].english);
+ if(langPack.entry[i].local!=NULL) { mir_free(langPack.entry[i].local); }
+ if(langPack.entry[i].wlocal!=NULL) { mir_free(langPack.entry[i].wlocal); }
+ }
+ if(langPack.entryCount) {
+ mir_free(langPack.entry);
+ langPack.entry=0;
+ langPack.entryCount=0;
+ }
+ return 0;
+}
+
+int LoadLangPackModule(void)
+{
+ HANDLE hFind;
+ TCHAR szSearch[MAX_PATH],*str2,szLangPack[MAX_PATH];
+ WIN32_FIND_DATA fd;
+
+ ZeroMemory(&langPack,sizeof(langPack));
+ HookEvent(ME_SYSTEM_SHUTDOWN,LangPackShutdown);
+ LoadLangPackServices();
+ GetModuleFileName(GetModuleHandle(NULL),szSearch,SIZEOF(szSearch));
+ str2=_tcsrchr(szSearch,'\\');
+ if(str2!=NULL) *str2=0;
+ else str2=szSearch;
+ lstrcat( szSearch, _T("\\langpack_*.txt"));
+ hFind = FindFirstFile( szSearch, &fd );
+ if( hFind != INVALID_HANDLE_VALUE ) {
+ lstrcpy(str2+1,fd.cFileName);
+ lstrcpy(szLangPack,szSearch);
+ FindClose(hFind);
+ LoadLangPack(szLangPack);
+ }
+ return 0;
+}
diff --git a/miranda-wine/src/modules/langpack/lpservices.c b/miranda-wine/src/modules/langpack/lpservices.c
new file mode 100644
index 0000000..4ebe764
--- /dev/null
+++ b/miranda-wine/src/modules/langpack/lpservices.c
@@ -0,0 +1,128 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+#if defined( _UNICODE )
+ #define FLAGS LANG_UNICODE
+#else
+ #define FLAGS 0
+#endif
+
+static int TranslateString(WPARAM wParam,LPARAM lParam)
+{
+ return (int)LangPackTranslateString((const char *)lParam, (wParam & LANG_UNICODE) ? 1 : 0);
+}
+
+static int TranslateMenu(WPARAM wParam,LPARAM lParam)
+{
+ HMENU hMenu = ( HMENU )wParam;
+ int i;
+ MENUITEMINFO mii;
+ TCHAR str[256];
+
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ for ( i = GetMenuItemCount( hMenu )-1; i >= 0; i--) {
+ mii.fMask = MIIM_TYPE|MIIM_SUBMENU;
+ mii.dwTypeData = ( TCHAR* )str;
+ mii.cch = SIZEOF(str);
+ GetMenuItemInfo(hMenu, i, TRUE, &mii);
+
+ if ( mii.cch && mii.dwTypeData ) {
+ TCHAR* result = ( TCHAR* )LangPackTranslateString(( const char* )mii.dwTypeData, FLAGS );
+ if ( result != mii.dwTypeData ) {
+ mii.dwTypeData = result;
+ mii.fMask = MIIM_TYPE;
+ SetMenuItemInfo( hMenu, i, TRUE, &mii );
+ } }
+
+ if ( mii.hSubMenu != NULL ) TranslateMenu(( WPARAM )mii.hSubMenu, lParam);
+ }
+ return 0;
+}
+
+static void TranslateWindow( HWND hwnd, int flags )
+{
+ TCHAR title[2048];
+ GetWindowText(hwnd, title, SIZEOF( title ));
+ {
+ TCHAR* result = ( TCHAR* )LangPackTranslateString(( const char* )title, FLAGS );
+ if ( result != title )
+ SetWindowText(hwnd, result );
+} }
+
+static BOOL CALLBACK TranslateDialogEnumProc(HWND hwnd,LPARAM lParam)
+{
+ LANGPACKTRANSLATEDIALOG *lptd=(LANGPACKTRANSLATEDIALOG*)lParam;
+ TCHAR szClass[32];
+ int i,id = GetDlgCtrlID( hwnd );
+
+ if(lptd->ignoreControls != NULL)
+ for(i=0;lptd->ignoreControls[i];i++) if(lptd->ignoreControls[i]==id) return TRUE;
+
+ GetClassName(hwnd,szClass,SIZEOF(szClass));
+ if(!lstrcmpi(szClass,_T("static")) || !lstrcmpi(szClass,_T("hyperlink")) || !lstrcmpi(szClass,_T("button")) || !lstrcmpi(szClass,_T("MButtonClass")))
+ TranslateWindow(hwnd, lptd->flags);
+ else if(!lstrcmpi(szClass,_T("edit"))) {
+ if(lptd->flags&LPTDF_NOIGNOREEDIT || GetWindowLong(hwnd,GWL_STYLE)&ES_READONLY)
+ TranslateWindow(hwnd, lptd->flags);
+ }
+ return TRUE;
+}
+
+static int TranslateDialog(WPARAM wParam,LPARAM lParam)
+{
+ LANGPACKTRANSLATEDIALOG *lptd=(LANGPACKTRANSLATEDIALOG*)lParam;
+ if(lptd==NULL||lptd->cbSize!=sizeof(LANGPACKTRANSLATEDIALOG)) return 1;
+ if(!(lptd->flags&LPTDF_NOTITLE))
+ TranslateWindow( lptd->hwndDlg, wParam );
+
+ EnumChildWindows(lptd->hwndDlg,TranslateDialogEnumProc,lParam);
+ return 0;
+}
+
+static int GetDefaultCodePage(WPARAM wParam,LPARAM lParam)
+{
+ return LangPackGetDefaultCodePage();
+}
+
+static int GetDefaultLocale(WPARAM wParam,LPARAM lParam)
+{
+ return LangPackGetDefaultLocale();
+}
+
+static int PcharToTchar(WPARAM wParam,LPARAM lParam)
+{
+ return ( int )LangPackPcharToTchar((char*)lParam );
+}
+
+int LoadLangPackServices(void)
+{
+ CreateServiceFunction(MS_LANGPACK_TRANSLATESTRING,TranslateString);
+ CreateServiceFunction(MS_LANGPACK_TRANSLATEMENU,TranslateMenu);
+ CreateServiceFunction(MS_LANGPACK_TRANSLATEDIALOG,TranslateDialog);
+ CreateServiceFunction(MS_LANGPACK_GETCODEPAGE,GetDefaultCodePage);
+ CreateServiceFunction(MS_LANGPACK_GETLOCALE,GetDefaultLocale);
+ CreateServiceFunction(MS_LANGPACK_PCHARTOTCHAR,PcharToTchar);
+ return 0;
+}
+
diff --git a/miranda-wine/src/modules/netlib/netlib.c b/miranda-wine/src/modules/netlib/netlib.c
new file mode 100644
index 0000000..72a0370
--- /dev/null
+++ b/miranda-wine/src/modules/netlib/netlib.c
@@ -0,0 +1,503 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "netlib.h"
+
+struct NetlibUser **netlibUser=NULL;
+int netlibUserCount=0;
+CRITICAL_SECTION csNetlibUser;
+HANDLE hConnectionHeaderMutex;
+DWORD g_LastConnectionTick; // protected by csNetlibUser
+
+void NetlibFreeUserSettingsStruct(NETLIBUSERSETTINGS *settings)
+{
+ if(settings->szIncomingPorts) mir_free(settings->szIncomingPorts);
+ if(settings->szOutgoingPorts) mir_free(settings->szOutgoingPorts);
+ if(settings->szProxyAuthPassword) mir_free(settings->szProxyAuthPassword);
+ if(settings->szProxyAuthUser) mir_free(settings->szProxyAuthUser);
+ if(settings->szProxyServer) mir_free(settings->szProxyServer);
+}
+
+void NetlibInitializeNestedCS(struct NetlibNestedCriticalSection *nlncs)
+{
+ nlncs->dwOwningThreadId= 0;
+ nlncs->lockCount=0;
+ nlncs->hMutex=CreateMutex(NULL,FALSE,NULL);
+}
+
+void NetlibDeleteNestedCS(struct NetlibNestedCriticalSection *nlncs)
+{
+ CloseHandle(nlncs->hMutex);
+}
+
+int NetlibEnterNestedCS(struct NetlibConnection *nlc,int which)
+{
+ struct NetlibNestedCriticalSection *nlncs;
+ DWORD dwCurrentThreadId=GetCurrentThreadId();
+
+ WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
+ if(nlc==NULL || nlc->handleType!=NLH_CONNECTION) {
+ ReleaseMutex(hConnectionHeaderMutex);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ nlncs=which==NLNCS_SEND?&nlc->ncsSend:&nlc->ncsRecv;
+ if(nlncs->lockCount && (nlc->ncsRecv.dwOwningThreadId==dwCurrentThreadId || nlc->ncsSend.dwOwningThreadId==dwCurrentThreadId)) {
+ nlncs->lockCount++;
+ ReleaseMutex(hConnectionHeaderMutex);
+ return 1;
+ }
+ InterlockedIncrement(&nlc->dontCloseNow);
+ ResetEvent(nlc->hOkToCloseEvent);
+ ReleaseMutex(hConnectionHeaderMutex);
+ WaitForSingleObject(nlncs->hMutex,INFINITE);
+ nlncs->dwOwningThreadId=dwCurrentThreadId;
+ nlncs->lockCount=1;
+ if(InterlockedDecrement(&nlc->dontCloseNow)==0)
+ SetEvent(nlc->hOkToCloseEvent);
+ return 1;
+}
+
+void NetlibLeaveNestedCS(struct NetlibNestedCriticalSection *nlncs)
+{
+ if(--nlncs->lockCount==0) {
+ nlncs->dwOwningThreadId=0;
+ ReleaseMutex(nlncs->hMutex);
+ }
+}
+
+static int GetNetlibUserSettingInt(const char *szUserModule,const char *szSetting,int defValue)
+{
+ DBVARIANT dbv;
+ if(DBGetContactSetting(NULL,szUserModule,szSetting,&dbv)
+ && DBGetContactSetting(NULL,"Netlib",szSetting,&dbv))
+ return defValue;
+ if(dbv.type==DBVT_BYTE) return dbv.bVal;
+ if(dbv.type==DBVT_WORD) return dbv.wVal;
+ return dbv.dVal;
+}
+
+static char *GetNetlibUserSettingString(const char *szUserModule,const char *szSetting,int decode)
+{
+ DBVARIANT dbv;
+ if(DBGetContactSetting(NULL,szUserModule,szSetting,&dbv)
+ && DBGetContactSetting(NULL,"Netlib",szSetting,&dbv)) {
+ return NULL;
+ }
+ else {
+ char *szRet;
+ if(decode) CallService(MS_DB_CRYPT_DECODESTRING, strlen(dbv.pszVal) + 1, (LPARAM)dbv.pszVal);
+ szRet=mir_strdup(dbv.pszVal);
+ DBFreeVariant(&dbv);
+ if(szRet==NULL) SetLastError(ERROR_OUTOFMEMORY);
+ return szRet;
+ }
+}
+
+static int NetlibRegisterUser(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBUSER *nlu=(NETLIBUSER*)lParam;
+ struct NetlibUser *thisUser;
+ int i;
+
+ if(nlu==NULL || nlu->cbSize!=sizeof(NETLIBUSER) || nlu->szSettingsModule==NULL
+ || (!(nlu->flags&NUF_NOOPTIONS) && nlu->szDescriptiveName==NULL)
+ || (nlu->flags&NUF_HTTPGATEWAY && (nlu->pfnHttpGatewayInit==NULL))) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return (int)(HANDLE)NULL;
+ }
+
+ EnterCriticalSection(&csNetlibUser);
+ for(i=0;i<netlibUserCount;i++)
+ if(!lstrcmpA(netlibUser[i]->user.szSettingsModule,nlu->szSettingsModule)) {
+ LeaveCriticalSection(&csNetlibUser);
+ SetLastError(ERROR_DUP_NAME);
+ return (int)(HANDLE)NULL;
+ }
+ LeaveCriticalSection(&csNetlibUser);
+
+ thisUser=(struct NetlibUser*)mir_calloc(sizeof(struct NetlibUser));
+ thisUser->handleType=NLH_USER;
+ thisUser->user=*nlu;
+ if((thisUser->user.szSettingsModule=mir_strdup(nlu->szSettingsModule))==NULL
+ || (nlu->szDescriptiveName && (thisUser->user.szDescriptiveName=mir_strdup(nlu->szDescriptiveName))==NULL)
+ || (nlu->szHttpGatewayUserAgent && (thisUser->user.szHttpGatewayUserAgent=mir_strdup(nlu->szHttpGatewayUserAgent))==NULL)) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return (int)(HANDLE)NULL;
+ }
+ if (nlu->szHttpGatewayHello)
+ thisUser->user.szHttpGatewayHello=mir_strdup(nlu->szHttpGatewayHello);
+ else
+ thisUser->user.szHttpGatewayHello=NULL;
+
+ thisUser->settings.cbSize=sizeof(NETLIBUSERSETTINGS);
+ thisUser->settings.useProxy=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLUseProxy",0);
+ thisUser->settings.proxyType=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLProxyType",PROXYTYPE_SOCKS5);
+ if(thisUser->user.flags&NUF_NOHTTPSOPTION && thisUser->settings.proxyType==PROXYTYPE_HTTPS)
+ thisUser->settings.proxyType=PROXYTYPE_HTTP;
+ if(!(thisUser->user.flags&(NUF_HTTPCONNS|NUF_HTTPGATEWAY)) && thisUser->settings.proxyType==PROXYTYPE_HTTP) {
+ thisUser->settings.useProxy=0;
+ thisUser->settings.proxyType=PROXYTYPE_SOCKS5;
+ }
+ thisUser->settings.szProxyServer=GetNetlibUserSettingString(thisUser->user.szSettingsModule,"NLProxyServer",0);
+ thisUser->settings.wProxyPort=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLProxyPort",1080);
+ thisUser->settings.useProxyAuth=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLUseProxyAuth",0);
+ thisUser->settings.szProxyAuthUser=GetNetlibUserSettingString(thisUser->user.szSettingsModule,"NLProxyAuthUser",0);
+ thisUser->settings.szProxyAuthPassword=GetNetlibUserSettingString(thisUser->user.szSettingsModule,"NLProxyAuthPassword",1);
+ thisUser->settings.useProxyAuthNtlm=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLUseProxyAuthNtlm",0);
+ thisUser->settings.dnsThroughProxy=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLDnsThroughProxy",1);
+ thisUser->settings.specifyIncomingPorts=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLSpecifyIncomingPorts",0);
+ thisUser->settings.szIncomingPorts=GetNetlibUserSettingString(thisUser->user.szSettingsModule,"NLIncomingPorts",0);
+ thisUser->settings.specifyOutgoingPorts=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLSpecifyOutgoingPorts",0);
+ thisUser->settings.szOutgoingPorts=GetNetlibUserSettingString(thisUser->user.szSettingsModule,"NLOutgoingPorts",0);
+
+ EnterCriticalSection(&csNetlibUser);
+ netlibUser=(struct NetlibUser**)mir_realloc(netlibUser,sizeof(struct NetlibUser*)*++netlibUserCount);
+ netlibUser[netlibUserCount-1]=thisUser;
+ LeaveCriticalSection(&csNetlibUser);
+ return (int)thisUser;
+}
+
+static int NetlibGetUserSettings(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBUSERSETTINGS *nlus=(NETLIBUSERSETTINGS*)lParam;
+ struct NetlibUser *nlu=(struct NetlibUser*)wParam;
+
+ if(GetNetlibHandleType(nlu)!=NLH_USER || nlus==NULL || nlus->cbSize!=sizeof(NETLIBUSERSETTINGS)) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ *nlus=nlu->settings;
+ return 1;
+}
+
+static int NetlibSetUserSettings(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBUSERSETTINGS *nlus=(NETLIBUSERSETTINGS*)lParam;
+ struct NetlibUser *nlu=(struct NetlibUser*)wParam;
+
+ if(GetNetlibHandleType(nlu)!=NLH_USER || nlus==NULL || nlus->cbSize!=sizeof(NETLIBUSERSETTINGS)) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ NetlibFreeUserSettingsStruct(&nlu->settings);
+ NetlibSaveUserSettingsStruct(nlu->user.szSettingsModule,nlus);
+ return 1;
+}
+
+int NetlibCloseHandle(WPARAM wParam,LPARAM lParam)
+{
+ switch(GetNetlibHandleType(wParam)) {
+ case NLH_USER:
+ { struct NetlibUser *nlu=(struct NetlibUser*)wParam;
+ int i;
+ EnterCriticalSection(&csNetlibUser);
+ for(i=0;i<netlibUserCount;i++)
+ if(!lstrcmpA(netlibUser[i]->user.szSettingsModule,nlu->user.szSettingsModule)) {
+ netlibUserCount--;
+ memmove(netlibUser+i,netlibUser+i+1,(netlibUserCount-i)*sizeof(struct NetlibUser*));
+ break;
+ }
+ LeaveCriticalSection(&csNetlibUser);
+ NetlibFreeUserSettingsStruct(&nlu->settings);
+ if(nlu->user.szSettingsModule) mir_free(nlu->user.szSettingsModule);
+ if(nlu->user.szDescriptiveName) mir_free(nlu->user.szDescriptiveName);
+ if(nlu->user.szHttpGatewayHello) mir_free(nlu->user.szHttpGatewayHello);
+ if(nlu->user.szHttpGatewayUserAgent) mir_free(nlu->user.szHttpGatewayUserAgent);
+ if(nlu->szStickyHeaders) mir_free(nlu->szStickyHeaders);
+ break;
+ }
+ case NLH_CONNECTION:
+ { struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ HANDLE waitHandles[4];
+ DWORD waitResult;
+
+ WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
+ if (nlc->usingHttpGateway)
+ {
+ struct NetlibHTTPProxyPacketQueue *p = nlc->pHttpProxyPacketQueue;
+ while (p != NULL) {
+ struct NetlibHTTPProxyPacketQueue *t = p;
+
+ p = p->next;
+
+ mir_free(t->dataBuffer);
+ mir_free(t);
+ }
+ }
+ else
+ {
+ if(nlc->handleType!=NLH_CONNECTION || nlc->s==INVALID_SOCKET) {
+ ReleaseMutex(hConnectionHeaderMutex);
+ SetLastError(ERROR_INVALID_PARAMETER); //already been closed
+ return 0;
+ }
+ closesocket(nlc->s);
+ nlc->s=INVALID_SOCKET;
+ }
+ ReleaseMutex(hConnectionHeaderMutex);
+
+ waitHandles[0]=hConnectionHeaderMutex;
+ waitHandles[1]=nlc->hOkToCloseEvent;
+ waitHandles[2]=nlc->ncsRecv.hMutex;
+ waitHandles[3]=nlc->ncsSend.hMutex;
+ waitResult=WaitForMultipleObjects( SIZEOF(waitHandles),waitHandles,TRUE,INFINITE);
+ if(waitResult<WAIT_OBJECT_0 || waitResult >= WAIT_OBJECT_0 + SIZEOF(waitHandles)) {
+ ReleaseMutex(hConnectionHeaderMutex);
+ SetLastError(ERROR_INVALID_PARAMETER); //already been closed
+ return 0;
+ }
+ nlc->handleType=0;
+ if(nlc->nlhpi.szHttpPostUrl) mir_free(nlc->nlhpi.szHttpPostUrl);
+ if(nlc->nlhpi.szHttpGetUrl) mir_free(nlc->nlhpi.szHttpGetUrl);
+ if(nlc->dataBuffer) mir_free(nlc->dataBuffer);
+ if(nlc->hInstSecurityDll) FreeLibrary(nlc->hInstSecurityDll);
+ NetlibDeleteNestedCS(&nlc->ncsRecv);
+ NetlibDeleteNestedCS(&nlc->ncsSend);
+ CloseHandle(nlc->hOkToCloseEvent);
+ DeleteCriticalSection(&nlc->csHttpSequenceNums);
+ ReleaseMutex(hConnectionHeaderMutex);
+ Netlib_Logf(nlc->nlu,"(%p:%u) Connection closed",nlc,nlc->s);
+ break;
+ }
+ case NLH_BOUNDPORT:
+ return NetlibFreeBoundPort((struct NetlibBoundPort*)wParam);
+ case NLH_PACKETRECVER:
+ { struct NetlibPacketRecver *nlpr=(struct NetlibPacketRecver*)wParam;
+ mir_free(nlpr->packetRecver.buffer);
+ break;
+ }
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ mir_free((void*)wParam);
+ return 1;
+}
+
+static int NetlibGetSocket(WPARAM wParam,LPARAM lParam)
+{
+ SOCKET s;
+ if((void*)wParam==NULL) {
+ s=INVALID_SOCKET;
+ SetLastError(ERROR_INVALID_PARAMETER);
+ }
+ else {
+ WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
+ switch(GetNetlibHandleType(wParam)) {
+ case NLH_CONNECTION:
+ s=(int)((struct NetlibConnection*)wParam)->s;
+ break;
+ case NLH_BOUNDPORT:
+ s=(int)((struct NetlibBoundPort*)wParam)->s;
+ break;
+ default:
+ s=INVALID_SOCKET;
+ SetLastError(ERROR_INVALID_PARAMETER);
+ break;
+ }
+ ReleaseMutex(hConnectionHeaderMutex);
+ }
+ return s;
+}
+
+static char szHexDigits[]="0123456789ABCDEF";
+int NetlibHttpUrlEncode(WPARAM wParam,LPARAM lParam)
+{
+ unsigned char *szOutput,*szInput=(unsigned char*)lParam;
+ unsigned char *pszIn,*pszOut;
+ int outputLen;
+
+ if(szInput==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return (int)(char*)NULL;
+ }
+ for(outputLen=0,pszIn=szInput;*pszIn;pszIn++) {
+ if(isalnum(*pszIn) || *pszIn==' ') outputLen++;
+ else outputLen+=3;
+ }
+ szOutput=(unsigned char*)HeapAlloc(GetProcessHeap(),0,outputLen+1);
+ if(szOutput==NULL) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return (int)(unsigned char*)NULL;
+ }
+ for(pszOut=szOutput,pszIn=szInput;*pszIn;pszIn++) {
+ if(isalnum(*pszIn)) *pszOut++=*pszIn;
+ else if(*pszIn==' ') *pszOut++='+';
+ else {
+ *pszOut++='%';
+ *pszOut++=szHexDigits[*pszIn>>4];
+ *pszOut++=szHexDigits[*pszIn&0xF];
+ }
+ }
+ *pszOut='\0';
+ return (int)szOutput;
+}
+
+static char base64chars[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+int NetlibBase64Encode(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBBASE64 *nlb64=(NETLIBBASE64*)lParam;
+ int iIn;
+ char *pszOut;
+ PBYTE pbIn;
+
+ if(nlb64==NULL || nlb64->pszEncoded==NULL || nlb64->pbDecoded==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ if(nlb64->cchEncoded<Netlib_GetBase64EncodedBufferSize(nlb64->cbDecoded)) {
+ SetLastError(ERROR_BUFFER_OVERFLOW);
+ return 0;
+ }
+ nlb64->cchEncoded=Netlib_GetBase64EncodedBufferSize(nlb64->cbDecoded);
+ for(iIn=0,pbIn=nlb64->pbDecoded,pszOut=nlb64->pszEncoded;iIn<nlb64->cbDecoded;iIn+=3,pbIn+=3,pszOut+=4) {
+ pszOut[0]=base64chars[pbIn[0]>>2];
+ if(nlb64->cbDecoded-iIn==1) {
+ pszOut[1]=base64chars[(pbIn[0]&3)<<4];
+ pszOut[2]='=';
+ pszOut[3]='=';
+ pszOut+=4;
+ break;
+ }
+ pszOut[1]=base64chars[((pbIn[0]&3)<<4)|(pbIn[1]>>4)];
+ if(nlb64->cbDecoded-iIn==2) {
+ pszOut[2]=base64chars[(pbIn[1]&0xF)<<2];
+ pszOut[3]='=';
+ pszOut+=4;
+ break;
+ }
+ pszOut[2]=base64chars[((pbIn[1]&0xF)<<2)|(pbIn[2]>>6)];
+ pszOut[3]=base64chars[pbIn[2]&0x3F];
+ }
+ pszOut[0]='\0';
+ return 1;
+}
+
+static BYTE Base64CharToInt(char c)
+{
+ if(c>='A' && c<='Z') return c-'A';
+ if(c>='a' && c<='z') return c-'a'+26;
+ if(c>='0' && c<='9') return c-'0'+52;
+ if(c=='+') return 62;
+ if(c=='/') return 63;
+ if(c=='=') return 64;
+ return 255;
+}
+
+int NetlibBase64Decode(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBBASE64 *nlb64=(NETLIBBASE64*)lParam;
+ char *pszIn;
+ PBYTE pbOut;
+ BYTE b1,b2,b3,b4;
+ int iIn;
+
+ if(nlb64==NULL || nlb64->pszEncoded==NULL || nlb64->pbDecoded==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ if(nlb64->cchEncoded&3) {
+ SetLastError(ERROR_INVALID_DATA);
+ return 0;
+ }
+ if(nlb64->cbDecoded<Netlib_GetBase64DecodedBufferSize(nlb64->cchEncoded)) {
+ SetLastError(ERROR_BUFFER_OVERFLOW);
+ return 0;
+ }
+ nlb64->cbDecoded=Netlib_GetBase64DecodedBufferSize(nlb64->cchEncoded);
+ for(iIn=0,pszIn=nlb64->pszEncoded,pbOut=nlb64->pbDecoded;iIn<nlb64->cchEncoded;iIn+=4,pszIn+=4,pbOut+=3) {
+ b1=Base64CharToInt(pszIn[0]);
+ b2=Base64CharToInt(pszIn[1]);
+ b3=Base64CharToInt(pszIn[2]);
+ b4=Base64CharToInt(pszIn[3]);
+ if(b1==255 || b1==64 || b2==255 || b2==64 || b3==255 || b4==255) {
+ SetLastError(ERROR_INVALID_DATA);
+ return 0;
+ }
+ pbOut[0]=(b1<<2)|(b2>>4);
+ if(b3==64) {nlb64->cbDecoded-=2; break;}
+ pbOut[1]=(b2<<4)|(b3>>2);
+ if(b4==64) {nlb64->cbDecoded--; break;}
+ pbOut[2]=b4|(b3<<6);
+ }
+ return 1;
+}
+
+static int NetlibShutdown(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+
+ NetlibLogShutdown();
+ for(i=netlibUserCount;i>0;i--)
+ NetlibCloseHandle((WPARAM)netlibUser[i-1],0);
+ if(netlibUser) mir_free(netlibUser);
+ CloseHandle(hConnectionHeaderMutex);
+ DeleteCriticalSection(&csNetlibUser);
+ WSACleanup();
+ return 0;
+}
+
+static int NetlibModulesLoaded(WPARAM wParam, LPARAM lParam)
+{
+ HookEvent(ME_SYSTEM_SHUTDOWN,NetlibShutdown); // get shutdown hook _after_ all the other plugins
+ return 0;
+}
+
+int LoadNetlibModule(void)
+{
+ WSADATA wsadata;
+
+ //HookEvent(ME_SYSTEM_SHUTDOWN,NetlibShutdown); // hooked later to be called last after plugins
+ HookEvent(ME_SYSTEM_MODULESLOADED, NetlibModulesLoaded);
+ HookEvent(ME_OPT_INITIALISE,NetlibOptInitialise);
+ WSAStartup(MAKEWORD(1,1), &wsadata);
+ InitializeCriticalSection(&csNetlibUser);
+ hConnectionHeaderMutex=CreateMutex(NULL,FALSE,NULL);
+ g_LastConnectionTick=GetTickCount();
+ NetlibLogInit();
+ CreateServiceFunction(MS_NETLIB_REGISTERUSER,NetlibRegisterUser);
+ CreateServiceFunction(MS_NETLIB_GETUSERSETTINGS,NetlibGetUserSettings);
+ CreateServiceFunction(MS_NETLIB_SETUSERSETTINGS,NetlibSetUserSettings);
+ CreateServiceFunction(MS_NETLIB_CLOSEHANDLE,NetlibCloseHandle);
+ CreateServiceFunction(MS_NETLIB_BINDPORT,NetlibBindPort);
+ CreateServiceFunction(MS_NETLIB_OPENCONNECTION,NetlibOpenConnection);
+ CreateServiceFunction(MS_NETLIB_SETHTTPPROXYINFO,NetlibHttpGatewaySetInfo);
+ CreateServiceFunction(MS_NETLIB_SETSTICKYHEADERS,NetlibHttpSetSticky);
+ CreateServiceFunction(MS_NETLIB_GETSOCKET,NetlibGetSocket);
+ CreateServiceFunction(MS_NETLIB_URLENCODE,NetlibHttpUrlEncode);
+ CreateServiceFunction(MS_NETLIB_BASE64ENCODE,NetlibBase64Encode);
+ CreateServiceFunction(MS_NETLIB_BASE64DECODE,NetlibBase64Decode);
+ CreateServiceFunction(MS_NETLIB_SENDHTTPREQUEST,NetlibHttpSendRequest);
+ CreateServiceFunction(MS_NETLIB_RECVHTTPHEADERS,NetlibHttpRecvHeaders);
+ CreateServiceFunction(MS_NETLIB_FREEHTTPREQUESTSTRUCT,NetlibHttpFreeRequestStruct);
+ CreateServiceFunction(MS_NETLIB_HTTPTRANSACTION,NetlibHttpTransaction);
+ CreateServiceFunction(MS_NETLIB_SEND,NetlibSend);
+ CreateServiceFunction(MS_NETLIB_RECV,NetlibRecv);
+ CreateServiceFunction(MS_NETLIB_SELECT,NetlibSelect);
+ CreateServiceFunction(MS_NETLIB_SELECTEX,NetlibSelectEx);
+ CreateServiceFunction(MS_NETLIB_CREATEPACKETRECVER,NetlibPacketRecverCreate);
+ CreateServiceFunction(MS_NETLIB_GETMOREPACKETS,NetlibPacketRecverGetMore);
+ CreateServiceFunction(MS_NETLIB_SETPOLLINGTIMEOUT,NetlibHttpSetPollingTimeout);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/netlib/netlib.h b/miranda-wine/src/modules/netlib/netlib.h
new file mode 100644
index 0000000..8314397
--- /dev/null
+++ b/miranda-wine/src/modules/netlib/netlib.h
@@ -0,0 +1,157 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 GetNetlibHandleType(h) (h?*(int*)h:NLH_INVALID)
+#define NLH_INVALID 0
+#define NLH_USER 'USER'
+#define NLH_CONNECTION 'CONN'
+#define NLH_BOUNDPORT 'BIND'
+#define NLH_PACKETRECVER 'PCKT'
+
+struct NetlibUser {
+ int handleType;
+ NETLIBUSER user;
+ NETLIBUSERSETTINGS settings;
+ char * szStickyHeaders;
+};
+
+struct NetlibNestedCriticalSection {
+ HANDLE hMutex;
+ DWORD dwOwningThreadId;
+ int lockCount;
+};
+
+struct NetlibHTTPProxyPacketQueue {
+ struct NetlibHTTPProxyPacketQueue *next;
+ PBYTE dataBuffer;
+ int dataBufferLen;
+};
+
+struct NetlibConnection {
+ int handleType;
+ SOCKET s;
+ int usingHttpGateway;
+ struct NetlibUser *nlu;
+ SOCKADDR_IN sinProxy;
+ NETLIBHTTPPROXYINFO nlhpi;
+ PBYTE dataBuffer;
+ int dataBufferLen;
+ DWORD dwLastGetSentTime;
+ CRITICAL_SECTION csHttpSequenceNums;
+ HANDLE hOkToCloseEvent;
+ LONG dontCloseNow;
+ struct NetlibNestedCriticalSection ncsSend,ncsRecv;
+ HINSTANCE hInstSecurityDll;
+ struct NetlibHTTPProxyPacketQueue * pHttpProxyPacketQueue;
+ int pollingTimeout;
+};
+
+struct NetlibBoundPort {
+ int handleType;
+ SOCKET s;
+ WORD wPort;
+ WORD wExPort;
+ struct NetlibUser *nlu;
+ NETLIBNEWCONNECTIONPROC_V2 pfnNewConnectionV2;
+ HANDLE hThread;
+ void *pExtra;
+};
+
+struct NetlibPacketRecver {
+ int handleType;
+ struct NetlibConnection *nlc;
+ NETLIBPACKETRECVER packetRecver;
+};
+
+//netlib.c
+void NetlibFreeUserSettingsStruct(NETLIBUSERSETTINGS *settings);
+int NetlibCloseHandle(WPARAM wParam,LPARAM lParam);
+void NetlibInitializeNestedCS(struct NetlibNestedCriticalSection *nlncs);
+void NetlibDeleteNestedCS(struct NetlibNestedCriticalSection *nlncs);
+#define NLNCS_SEND 0
+#define NLNCS_RECV 1
+int NetlibEnterNestedCS(struct NetlibConnection *nlc,int which);
+void NetlibLeaveNestedCS(struct NetlibNestedCriticalSection *nlncs);
+int NetlibBase64Encode(WPARAM wParam,LPARAM lParam);
+int NetlibBase64Decode(WPARAM wParam,LPARAM lParam);
+int NetlibHttpUrlEncode(WPARAM wParam,LPARAM lParam);
+
+//netlibbind.c
+int NetlibFreeBoundPort(struct NetlibBoundPort *nlbp);
+int NetlibBindPort(WPARAM wParam,LPARAM lParam);
+int StringToPortsMask(const char *szPorts,BYTE *mask);
+
+//netlibhttp.c
+int NetlibHttpSendRequest(WPARAM wParam,LPARAM lParam);
+int NetlibHttpRecvHeaders(WPARAM wParam,LPARAM lParam);
+int NetlibHttpFreeRequestStruct(WPARAM wParam,LPARAM lParam);
+int NetlibHttpTransaction(WPARAM wParam,LPARAM lParam);
+void NetlibHttpSetLastErrorUsingHttpResult(int result);
+
+//netlibhttpproxy.c
+int NetlibInitHttpConnection(struct NetlibConnection *nlc,struct NetlibUser *nlu,NETLIBOPENCONNECTION *nloc);
+int NetlibHttpGatewaySetInfo(WPARAM wParam,LPARAM lParam);
+int NetlibHttpSetPollingTimeout(WPARAM wParam,LPARAM lParam);
+int NetlibHttpGatewayRecv(struct NetlibConnection *nlc,char *buf,int len,int flags);
+int NetlibHttpGatewayPost(struct NetlibConnection *nlc,const char *buf,int len,int flags);
+int NetlibHttpSetSticky(WPARAM wParam, LPARAM lParam);
+
+//netliblog.c
+void NetlibLogShowOptions(void);
+void NetlibDumpData(struct NetlibConnection *nlc,PBYTE buf,int len,int sent,int flags);
+void NetlibLogInit(void);
+void NetlibLogShutdown(void);
+
+//netlibopenconn.c
+DWORD DnsLookup(struct NetlibUser *nlu,const char *szHost);
+int WaitUntilReadable(SOCKET s,DWORD dwTimeout);
+int NetlibOpenConnection(WPARAM wParam,LPARAM lParam);
+
+//netlibopts.c
+int NetlibOptInitialise(WPARAM wParam,LPARAM lParam);
+void NetlibSaveUserSettingsStruct(const char *szSettingsModule,NETLIBUSERSETTINGS *settings);
+
+//netlibpktrecver.c
+int NetlibPacketRecverCreate(WPARAM wParam,LPARAM lParam);
+int NetlibPacketRecverGetMore(WPARAM wParam,LPARAM lParam);
+
+//netlibsock.c
+int NetlibSend(WPARAM wParam,LPARAM lParam);
+int NetlibRecv(WPARAM wParam,LPARAM lParam);
+int NetlibSelect(WPARAM wParam,LPARAM lParam);
+int NetlibSelectEx(WPARAM wParam,LPARAM lParam);
+
+//netlibupnp.c
+BOOL NetlibUPnPAddPortMapping(WORD intport, char *proto,
+ WORD *extport, DWORD *extip, BOOL search);
+void NetlibUPnPDeletePortMapping(WORD extport, char* proto);
+
+static __inline int NLSend(struct NetlibConnection *nlc,const char *buf,int len,int flags) {
+ NETLIBBUFFER nlb={(char*)buf,len,flags};
+ return NetlibSend((WPARAM)nlc,(LPARAM)&nlb);
+}
+static __inline int NLRecv(struct NetlibConnection *nlc,char *buf,int len,int flags) {
+ NETLIBBUFFER nlb={buf,len,flags};
+ return NetlibRecv((WPARAM)nlc,(LPARAM)&nlb);
+}
+
diff --git a/miranda-wine/src/modules/netlib/netlibbind.c b/miranda-wine/src/modules/netlib/netlibbind.c
new file mode 100644
index 0000000..383159f
--- /dev/null
+++ b/miranda-wine/src/modules/netlib/netlibbind.c
@@ -0,0 +1,247 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "netlib.h"
+
+//mask must be 8192 bytes, returns number of bits set
+#define PortInMask(mask,p) ((mask)[((p)&0xFFFF)>>3]&(1<<((p)&7)))
+int StringToPortsMask(const char *szPorts,BYTE *mask)
+{
+ const char *psz;
+ char *pszEnd;
+ int portMin,portMax,port;
+ int bitCount=0;
+
+ ZeroMemory(mask,8192);
+ for(psz=szPorts;*psz;) {
+ while(*psz==' ' && *psz==',') psz++;
+ portMin=strtol(psz,&pszEnd,0);
+ if(pszEnd==psz) break;
+ while(*pszEnd==' ') pszEnd++;
+ if(*pszEnd=='-') {
+ psz=pszEnd+1;
+ portMax=strtol(psz,&pszEnd,0);
+ if(pszEnd==psz) portMax=65535;
+ if(portMin>portMax) {
+ port=portMin;
+ portMin=portMax;
+ portMax=port;
+ }
+ }
+ else portMax=portMin;
+ if(portMax>=1) {
+ if(portMin<=0) portMin=1;
+ for(port=portMin;port<=portMax;port++) {
+ if(port>65535) break;
+ if((port&7)==0 && portMax-port>=7) {mask[port>>3]=0xFF; port+=7; bitCount+=8;}
+ else {mask[port>>3]|=1<<(port&7); bitCount++;}
+ }
+ }
+ psz=pszEnd;
+ }
+ return bitCount;
+}
+
+int NetlibFreeBoundPort(struct NetlibBoundPort *nlbp)
+{
+ closesocket(nlbp->s);
+ WaitForSingleObject(nlbp->hThread,INFINITE);
+ CloseHandle(nlbp->hThread);
+ NetlibUPnPDeletePortMapping(nlbp->wExPort, "TCP");
+ mir_free(nlbp);
+ return 1;
+}
+
+static DWORD __stdcall NetlibBindAcceptThread(struct NetlibBoundPort *nlbp)
+{
+ SOCKET s;
+ SOCKADDR_IN sin;
+ int sinLen;
+ struct NetlibConnection *nlc;
+
+ srand((unsigned int)time(NULL));
+ Netlib_Logf(nlbp->nlu,"(%d) Port %u opened for incoming connections",nlbp->s,nlbp->wPort);
+ for(;;) {
+ sinLen=sizeof(sin);
+ s=accept(nlbp->s,(struct sockaddr*)&sin,&sinLen);
+ if(s==INVALID_SOCKET) break;
+ Netlib_Logf(nlbp->nlu,"New incoming connection on port %u from %s (%d)",nlbp->wPort, inet_ntoa(sin.sin_addr),s);
+ nlc=(struct NetlibConnection*)mir_alloc(sizeof(struct NetlibConnection));
+ memset(nlc,0,sizeof(struct NetlibConnection));
+ nlc->handleType=NLH_CONNECTION;
+ nlc->nlu=nlbp->nlu;
+ nlc->s=s;
+ InitializeCriticalSection(&nlc->csHttpSequenceNums);
+ nlc->hOkToCloseEvent=CreateEvent(NULL,TRUE,TRUE,NULL);
+ nlc->dontCloseNow=0;
+ NetlibInitializeNestedCS(&nlc->ncsSend);
+ NetlibInitializeNestedCS(&nlc->ncsRecv);
+ nlbp->pfnNewConnectionV2((HANDLE)nlc,ntohl(sin.sin_addr.S_un.S_addr), nlbp->pExtra);
+ }
+ return 0;
+}
+
+int NetlibBindPort(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBBIND *nlb=(NETLIBBIND*)lParam;
+ struct NetlibUser *nlu=(struct NetlibUser*)wParam;
+ struct NetlibBoundPort *nlbp;
+ SOCKADDR_IN sin;
+ int foundPort=0;
+ DWORD dwThreadId;
+
+ if(GetNetlibHandleType(nlu)!=NLH_USER || !(nlu->user.flags&NUF_INCOMING) || nlb==NULL || nlb->pfnNewConnection==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return (int)(HANDLE)NULL;
+ }
+ if ( nlb->cbSize != sizeof(NETLIBBIND) &&
+ nlb->cbSize != NETLIBBIND_SIZEOF_V2 &&
+ nlb->cbSize != NETLIBBIND_SIZEOF_V1 )
+ {
+ return (int)(HANDLE)NULL;
+ }
+ nlbp=(struct NetlibBoundPort*)mir_alloc(sizeof(struct NetlibBoundPort));
+ nlbp->handleType=NLH_BOUNDPORT;
+ nlbp->nlu=nlu;
+ nlbp->pfnNewConnectionV2=nlb->pfnNewConnectionV2;
+ nlbp->s=socket(AF_INET,SOCK_STREAM,0);
+ nlbp->pExtra= (nlb->cbSize == sizeof(NETLIBBIND)) ? nlb->pExtra : NULL;
+ if(nlbp->s==INVALID_SOCKET) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"socket",WSAGetLastError());
+ mir_free(nlbp);
+ return (int)(HANDLE)NULL;
+ }
+ sin.sin_family=AF_INET;
+ sin.sin_addr.s_addr=htonl(INADDR_ANY);
+ sin.sin_port=0;
+ /* if the netlib user wanted a free port given in the range, then
+ they better have given wPort==0, let's hope so */
+ if(nlu->settings.specifyIncomingPorts && nlb->wPort==0) {
+ int startPort,portNum,i,j;
+ BYTE portsMask[8192];
+ int portsCount;
+
+ portsCount=StringToPortsMask(nlu->settings.szIncomingPorts,portsMask);
+ if(portsCount==0) {
+ closesocket(nlbp->s);
+ mir_free(nlbp);
+ SetLastError(WSAEADDRINUSE);
+ return (int)(HANDLE)NULL;
+ }
+ startPort=rand()%portsCount;
+ for(i=0;i<8192;i++) {
+ if(portsMask[i]==0) continue;
+ if(portsMask[i]==0xFF && startPort>=8) {startPort-=8; continue;}
+ for(j=0;j<8;j++)
+ if(portsMask[i]&(1<<j))
+ if(startPort--==0) {
+ portNum=(i<<3)+j;
+ break;
+ }
+ if(startPort==-1) break;
+ }
+ if(i==8192) return (int)(HANDLE)NULL; //can't happen
+ startPort=portNum;
+ do
+ {
+ sin.sin_port=htons((WORD)portNum);
+ if(bind(nlbp->s,(SOCKADDR *)&sin,sizeof(sin))==0) {
+ foundPort=1;
+ break;
+ }
+ for(portNum++;!PortInMask(portsMask,portNum);portNum++)
+ if(portNum==65535) portNum=0;
+ } while(portNum!=startPort);
+ }
+ else {
+ /* if ->wPort==0 then they'll get any free port, otherwise they'll
+ be asking for whatever was in nlb->wPort*/
+ if (nlb->wPort!=0) {
+ Netlib_Logf(nlu,"%s %d: trying to bind port %d, this 'feature' can be abused, please be sure you want to allow it.",__FILE__,__LINE__,nlb->wPort);
+ sin.sin_port=htons(nlb->wPort);
+ }
+ if(bind(nlbp->s,(SOCKADDR *)&sin,sizeof(sin))==0) foundPort=1;
+ }
+ if(!foundPort) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"bind",WSAGetLastError());
+ closesocket(nlbp->s);
+ mir_free(nlbp);
+ return (int)(HANDLE)NULL;
+ }
+
+ if(listen(nlbp->s,5)) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"listen",WSAGetLastError());
+ closesocket(nlbp->s);
+ mir_free(nlbp);
+ return (int)(HANDLE)NULL;
+ }
+
+ { int len;
+ DWORD extIP;
+
+ ZeroMemory(&sin,sizeof(sin));
+ len=sizeof(sin);
+ if(getsockname(nlbp->s,(SOCKADDR *)&sin,&len)) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"getsockname",WSAGetLastError());
+ closesocket(nlbp->s);
+ mir_free(nlbp);
+ return (int)(HANDLE)NULL;
+ }
+ nlb->wPort=ntohs(sin.sin_port);
+ nlbp->wPort=nlb->wPort;
+ nlb->dwInternalIP=ntohl(sin.sin_addr.S_un.S_addr);
+
+ if (nlb->dwInternalIP == 0)
+ {
+ char hostname[64];
+ struct hostent *he;
+
+ gethostname(hostname,SIZEOF(hostname));
+ he=gethostbyname(hostname);
+ if(he->h_addr_list[0])
+ nlb->dwInternalIP=ntohl(*(PDWORD)he->h_addr_list[0]);
+ }
+ if (NetlibUPnPAddPortMapping(nlb->wPort, "TCP", &nlbp->wExPort,
+ &extIP, nlb->cbSize > NETLIBBIND_SIZEOF_V2))
+ {
+ if (nlb->cbSize > NETLIBBIND_SIZEOF_V2)
+ {
+ nlb->wExPort = nlbp->wExPort;
+ nlb->dwExternalIP = extIP;
+ }
+ }
+ else
+ {
+ nlbp->wExPort = 0;
+ if (nlb->cbSize > NETLIBBIND_SIZEOF_V2)
+ {
+ nlb->wExPort = nlb->wPort;
+ nlb->dwExternalIP = nlb->dwInternalIP;
+ }
+ }
+
+ }
+ nlbp->hThread=(HANDLE)forkthreadex(NULL,0,NetlibBindAcceptThread,nlbp,0,&dwThreadId);
+ return (int)nlbp;
+}
+
diff --git a/miranda-wine/src/modules/netlib/netlibhttp.c b/miranda-wine/src/modules/netlib/netlibhttp.c
new file mode 100644
index 0000000..5e47116
--- /dev/null
+++ b/miranda-wine/src/modules/netlib/netlibhttp.c
@@ -0,0 +1,729 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#define SECURITY_WIN32
+#include <security.h>
+#include "netlib.h"
+
+// Old versions of ssapi.h defines "FreeCredentialHandle()", but the
+// function has since then been redefined to "FreeCredentialsHandle()"
+#ifndef FreeCredentialsHandle
+#define FreeCredentialsHandle FreeCredentialHandle
+#endif
+
+#define HTTPRECVHEADERSTIMEOUT 60000 //in ms
+
+struct ResizableCharBuffer {
+ char *sz;
+ int iEnd,cbAlloced;
+};
+
+static void AppendToCharBuffer(struct ResizableCharBuffer *rcb,const char *fmt,...)
+{
+ va_list va;
+ int charsDone;
+
+ if(rcb->cbAlloced==0) {
+ rcb->cbAlloced=512;
+ rcb->sz=(char*)mir_alloc(rcb->cbAlloced);
+ }
+ va_start(va,fmt);
+ for(;;) {
+ charsDone=mir_vsnprintf(rcb->sz+rcb->iEnd,rcb->cbAlloced-rcb->iEnd,fmt,va);
+ if(charsDone>=0) break;
+ rcb->cbAlloced+=512;
+ rcb->sz=(char*)mir_realloc(rcb->sz,rcb->cbAlloced);
+ }
+ va_end(va);
+ rcb->iEnd+=charsDone;
+}
+
+
+static PSecurityFunctionTableA pSecurityFunctions=NULL;
+static PSecPkgInfoA ntlmSecurityPackageInfo=NULL;
+static CtxtHandle hNtlmClientContext;
+static CredHandle hNtlmClientCredential;
+//mir_free() the return value
+static void NtlmDestroy(void)
+{
+ if (pSecurityFunctions)
+ {
+ pSecurityFunctions->DeleteSecurityContext(&hNtlmClientContext);
+ pSecurityFunctions->FreeCredentialsHandle(&hNtlmClientCredential);
+ } //if
+ if(ntlmSecurityPackageInfo) pSecurityFunctions->FreeContextBuffer(ntlmSecurityPackageInfo);
+ ntlmSecurityPackageInfo=NULL;
+}
+
+static char *NtlmInitialiseAndGetDomainPacket(HINSTANCE hInstSecurityDll)
+{
+ PSecurityFunctionTableA (*MyInitSecurityInterface)(VOID);
+ SECURITY_STATUS securityStatus;
+ SecBufferDesc outputBufferDescriptor;
+ SecBuffer outputSecurityToken;
+ TimeStamp tokenExpiration;
+ ULONG contextAttributes;
+ NETLIBBASE64 nlb64;
+
+ MyInitSecurityInterface=(PSecurityFunctionTableA (*)(VOID))GetProcAddress(hInstSecurityDll,"InitSecurityInterfaceA");
+ if(MyInitSecurityInterface==NULL) {NtlmDestroy(); return NULL;}
+ pSecurityFunctions=MyInitSecurityInterface();
+ if(pSecurityFunctions==NULL) {NtlmDestroy(); return NULL;}
+
+ securityStatus=pSecurityFunctions->QuerySecurityPackageInfoA("NTLM",&ntlmSecurityPackageInfo);
+ if(securityStatus!=SEC_E_OK) {NtlmDestroy(); return NULL;}
+ securityStatus=pSecurityFunctions->AcquireCredentialsHandleA(NULL,"NTLM",SECPKG_CRED_OUTBOUND,NULL,NULL,NULL,NULL,&hNtlmClientCredential,&tokenExpiration);
+ if(securityStatus!=SEC_E_OK) {NtlmDestroy(); return NULL;}
+
+ outputBufferDescriptor.cBuffers=1;
+ outputBufferDescriptor.pBuffers=&outputSecurityToken;
+ outputBufferDescriptor.ulVersion=SECBUFFER_VERSION;
+ outputSecurityToken.BufferType=SECBUFFER_TOKEN;
+ outputSecurityToken.cbBuffer=ntlmSecurityPackageInfo->cbMaxToken;
+ outputSecurityToken.pvBuffer=mir_alloc(outputSecurityToken.cbBuffer);
+ if(outputSecurityToken.pvBuffer==NULL) {NtlmDestroy(); SetLastError(ERROR_OUTOFMEMORY); return NULL;}
+ securityStatus=pSecurityFunctions->InitializeSecurityContextA(&hNtlmClientCredential,NULL,NULL,0,0,SECURITY_NATIVE_DREP,NULL,0,&hNtlmClientContext,&outputBufferDescriptor,&contextAttributes,&tokenExpiration);
+ if(securityStatus!=SEC_I_CONTINUE_NEEDED) {mir_free(outputSecurityToken.pvBuffer); NtlmDestroy(); return NULL;}
+
+ nlb64.cbDecoded=outputSecurityToken.cbBuffer;
+ nlb64.pbDecoded=outputSecurityToken.pvBuffer;
+ nlb64.cchEncoded=Netlib_GetBase64EncodedBufferSize(nlb64.cbDecoded);
+ nlb64.pszEncoded=(char*)mir_alloc(nlb64.cchEncoded);
+ if(nlb64.pszEncoded==NULL) {mir_free(outputSecurityToken.pvBuffer); NtlmDestroy(); SetLastError(ERROR_OUTOFMEMORY); return NULL;}
+ if(!NetlibBase64Encode(0,(LPARAM)&nlb64))
+ {mir_free(nlb64.pszEncoded); mir_free(outputSecurityToken.pvBuffer); NtlmDestroy(); return NULL;}
+ mir_free(outputSecurityToken.pvBuffer);
+ return nlb64.pszEncoded;
+}
+
+//mir_free() the result value
+static char *NtlmCreateResponseFromChallenge(char *szChallenge)
+{
+ SECURITY_STATUS securityStatus;
+ SecBufferDesc outputBufferDescriptor,inputBufferDescriptor;
+ SecBuffer outputSecurityToken,inputSecurityToken;
+ TimeStamp tokenExpiration;
+ ULONG contextAttributes;
+ NETLIBBASE64 nlb64;
+
+ nlb64.cchEncoded=lstrlenA(szChallenge);
+ nlb64.pszEncoded=szChallenge;
+ nlb64.cbDecoded=Netlib_GetBase64DecodedBufferSize(nlb64.cchEncoded);
+ nlb64.pbDecoded=(PBYTE)mir_alloc(nlb64.cbDecoded);
+ if(nlb64.pbDecoded==NULL) {SetLastError(ERROR_OUTOFMEMORY); return NULL;}
+ if(!NetlibBase64Decode(0,(LPARAM)&nlb64))
+ {mir_free(nlb64.pbDecoded); return NULL;}
+
+ inputBufferDescriptor.cBuffers=1;
+ inputBufferDescriptor.pBuffers=&inputSecurityToken;
+ inputBufferDescriptor.ulVersion=SECBUFFER_VERSION;
+ inputSecurityToken.BufferType=SECBUFFER_TOKEN;
+ inputSecurityToken.cbBuffer=nlb64.cbDecoded;
+ inputSecurityToken.pvBuffer=nlb64.pbDecoded;
+ outputBufferDescriptor.cBuffers=1;
+ outputBufferDescriptor.pBuffers=&outputSecurityToken;
+ outputBufferDescriptor.ulVersion=SECBUFFER_VERSION;
+ outputSecurityToken.BufferType=SECBUFFER_TOKEN;
+ outputSecurityToken.cbBuffer=ntlmSecurityPackageInfo->cbMaxToken;
+ outputSecurityToken.pvBuffer=mir_alloc(outputSecurityToken.cbBuffer);
+ if(outputSecurityToken.pvBuffer==NULL) {mir_free(nlb64.pbDecoded); SetLastError(ERROR_OUTOFMEMORY); return NULL;}
+ securityStatus=pSecurityFunctions->InitializeSecurityContextA(&hNtlmClientCredential,&hNtlmClientContext,NULL,0,0,SECURITY_NATIVE_DREP,&inputBufferDescriptor,0,&hNtlmClientContext,&outputBufferDescriptor,&contextAttributes,&tokenExpiration);
+ mir_free(nlb64.pbDecoded);
+ if(securityStatus!=SEC_E_OK) {mir_free(outputSecurityToken.pvBuffer); return NULL;}
+
+ nlb64.cbDecoded=outputSecurityToken.cbBuffer;
+ nlb64.pbDecoded=outputSecurityToken.pvBuffer;
+ nlb64.cchEncoded=Netlib_GetBase64EncodedBufferSize(nlb64.cbDecoded);
+ nlb64.pszEncoded=(char*)mir_alloc(nlb64.cchEncoded);
+ if(nlb64.pszEncoded==NULL) {mir_free(outputSecurityToken.pvBuffer); SetLastError(ERROR_OUTOFMEMORY); return NULL;}
+ if(!NetlibBase64Encode(0,(LPARAM)&nlb64))
+ {mir_free(nlb64.pszEncoded); mir_free(outputSecurityToken.pvBuffer); return NULL;}
+ mir_free(outputSecurityToken.pvBuffer);
+ return nlb64.pszEncoded;
+}
+
+static int RecvWithTimeoutTime(struct NetlibConnection *nlc,DWORD dwTimeoutTime,char *buf,int len,int flags)
+{
+ DWORD dwTimeNow;
+
+ dwTimeNow=GetTickCount();
+ if(dwTimeNow>=dwTimeoutTime
+ || !WaitUntilReadable(nlc->s,dwTimeoutTime-dwTimeNow)) {
+ if(dwTimeNow>=dwTimeoutTime) SetLastError(ERROR_TIMEOUT);
+ return SOCKET_ERROR;
+ }
+ return NLRecv(nlc,buf,len,flags);
+}
+
+static int HttpPeekFirstResponseLine(struct NetlibConnection *nlc,DWORD dwTimeoutTime,DWORD recvFlags,int *resultCode,char **ppszResultDescr,int *length)
+{
+ int bytesPeeked=0;
+ char buffer[1024];
+ char *peol;
+
+ for(;;) {
+ bytesPeeked=RecvWithTimeoutTime(nlc,dwTimeoutTime,buffer,SIZEOF(buffer)-1,MSG_PEEK|recvFlags);
+ if(bytesPeeked==0 || bytesPeeked==SOCKET_ERROR) {
+ if(bytesPeeked==0) SetLastError(ERROR_HANDLE_EOF);
+ return 0;
+ }
+ buffer[bytesPeeked]='\0';
+ peol=strchr(buffer,'\n');
+ if(peol==NULL) {
+ if(lstrlenA(buffer)<bytesPeeked) {
+ SetLastError(ERROR_BAD_FORMAT);
+ return 0;
+ }
+ if(bytesPeeked==SIZEOF(buffer)-1) {
+ SetLastError(ERROR_BUFFER_OVERFLOW);
+ return 0;
+ }
+ Sleep(10);
+ continue;
+ }
+ if(peol==buffer || *--peol!='\r') {
+ SetLastError(ERROR_BAD_FORMAT);
+ return 0;
+ }
+ *peol='\0';
+ {
+ char *pResultCode,*pResultDescr,*pHttpMajor,*pHttpMinor;
+ int tokenLen;
+ int httpMajorVer,httpMinorVer;
+ if(peol==buffer
+ || _strnicmp(buffer,"http/",5)
+ || (httpMajorVer=strtol(pHttpMajor=buffer+5,&pHttpMinor,10))<0
+ || pHttpMajor==pHttpMinor
+ || httpMajorVer>1
+ || *pHttpMinor++!='.'
+ || (httpMinorVer=strtol(pHttpMinor,&pResultCode,10))<0
+ || pResultCode==pHttpMinor
+ || (tokenLen=strspn(pResultCode," \t"))==0
+ || (*resultCode=strtol(pResultCode+=tokenLen,&pResultDescr,10))==0
+ || pResultDescr==pResultCode
+ || (tokenLen=strspn(pResultDescr," \t"))==0
+ || *(pResultDescr+=tokenLen)=='\0') {
+ SetLastError(peol==buffer?ERROR_BAD_FORMAT:ERROR_INVALID_DATA);
+ return 0;
+ }
+ if(ppszResultDescr) *ppszResultDescr=mir_strdup(pResultDescr);
+ if(length) *length=peol-buffer+2;
+ }
+ return 1;
+ }
+}
+
+static int SendHttpRequestAndData(struct NetlibConnection *nlc,struct ResizableCharBuffer *httpRequest,NETLIBHTTPREQUEST *nlhr,int sendContentLengthHeader)
+{
+ int bytesSent;
+
+ if((nlhr->requestType==REQUEST_POST)) {
+ if(sendContentLengthHeader)
+ AppendToCharBuffer(httpRequest,"Content-Length: %d\r\n\r\n",nlhr->dataLength);
+ else
+ AppendToCharBuffer(httpRequest,"\r\n");
+ bytesSent=NLSend(nlc,httpRequest->sz,httpRequest->iEnd,MSG_DUMPASTEXT|(nlhr->flags&(NLHRF_NODUMP|NLHRF_NODUMPHEADERS)?MSG_NODUMP:(nlhr->flags&NLHRF_DUMPPROXY?MSG_DUMPPROXY:0)));
+ mir_free(httpRequest->sz);
+ if (nlhr->dataLength) {
+ int sendResult;
+
+ if(bytesSent==SOCKET_ERROR
+ || SOCKET_ERROR==(sendResult=NLSend(nlc,nlhr->pData,nlhr->dataLength,(nlhr->flags&NLHRF_DUMPASTEXT?MSG_DUMPASTEXT:0)|(nlhr->flags&NLHRF_NODUMP?MSG_NODUMP:(nlhr->flags&NLHRF_DUMPPROXY?MSG_DUMPPROXY:0))))) {
+ return SOCKET_ERROR;
+ }
+ bytesSent+=sendResult;
+ }
+ }
+ else {
+ AppendToCharBuffer(httpRequest,"\r\n");
+ bytesSent=NLSend(nlc,httpRequest->sz,httpRequest->iEnd,MSG_DUMPASTEXT|(nlhr->flags&(NLHRF_NODUMP|NLHRF_NODUMPHEADERS)?MSG_NODUMP:(nlhr->flags&NLHRF_DUMPPROXY?MSG_DUMPPROXY:0)));
+ mir_free(httpRequest->sz);
+ }
+ return bytesSent;
+}
+
+int NetlibHttpSendRequest(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ NETLIBHTTPREQUEST *nlhr=(NETLIBHTTPREQUEST*)lParam;
+ struct ResizableCharBuffer httpRequest={0};
+ char *pszRequest,*szHost,*pszUrl;
+ char *pszProxyAuthorizationHeader;
+ int i,doneHostHeader,doneContentLengthHeader,doneProxyAuthHeader,usingNtlmAuthentication;
+ int useProxyHttpAuth,bytesSent;
+
+ if(nlhr==NULL || nlhr->cbSize!=sizeof(NETLIBHTTPREQUEST) || nlhr->szUrl==NULL || nlhr->szUrl[0]=='\0') {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+ switch(nlhr->requestType) {
+ case REQUEST_GET: pszRequest="GET"; break;
+ case REQUEST_POST: pszRequest="POST"; break;
+ case REQUEST_CONNECT: pszRequest="CONNECT"; break;
+ case REQUEST_HEAD:pszRequest="HEAD"; break;
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+
+ if(!NetlibEnterNestedCS(nlc,NLNCS_SEND)) return SOCKET_ERROR;
+
+ //first line: "GET /index.html HTTP/1.0\r\n"
+ szHost=NULL;
+ if(nlhr->flags&(NLHRF_SMARTREMOVEHOST|NLHRF_REMOVEHOST|NLHRF_GENERATEHOST)){
+ char *ppath,*phost;
+ phost=strstr(nlhr->szUrl,"://");
+ if(phost==NULL) phost=nlhr->szUrl;
+ else phost+=3;
+ ppath=strchr(phost,'/');
+ if(ppath==NULL) ppath=phost+lstrlenA(phost);
+ if(nlhr->flags&NLHRF_GENERATEHOST) {
+ szHost=(char*)mir_alloc(ppath-phost+1);
+ lstrcpynA(szHost,phost,ppath-phost+1);
+ }
+ if(nlhr->flags&NLHRF_REMOVEHOST
+ || (nlhr->flags&NLHRF_SMARTREMOVEHOST
+ && (!nlc->nlu->settings.useProxy
+ || !(nlc->nlu->settings.proxyType==PROXYTYPE_HTTP || nlc->nlu->settings.proxyType==PROXYTYPE_HTTPS)))) {
+ pszUrl=ppath;
+ }
+ else pszUrl=nlhr->szUrl;
+ }
+ else pszUrl=nlhr->szUrl;
+ AppendToCharBuffer(&httpRequest, "%s %s HTTP/1.%d\r\n", pszRequest, pszUrl, (nlhr->flags & NLHRF_HTTP11) != 0);
+
+ //if (nlhr->dataLength > 0)
+ // AppendToCharBuffer(&httpRequest,"Content-Length: %d\r\n",nlhr->dataLength);
+
+ //proxy auth initialization
+ useProxyHttpAuth=nlhr->flags&NLHRF_SMARTAUTHHEADER && nlc->nlu->settings.useProxy && nlc->nlu->settings.useProxyAuth && (nlc->nlu->settings.proxyType==PROXYTYPE_HTTP || nlc->nlu->settings.proxyType==PROXYTYPE_HTTPS);
+ usingNtlmAuthentication=0;
+ if(useProxyHttpAuth) {
+ if(nlc->nlu->settings.useProxyAuthNtlm) {
+ char *pszNtlmAuth;
+ pszNtlmAuth=NtlmInitialiseAndGetDomainPacket(nlc->hInstSecurityDll);
+ if(pszNtlmAuth==NULL) {useProxyHttpAuth=0; pszProxyAuthorizationHeader=NULL;}
+ else {
+ pszProxyAuthorizationHeader=(char*)mir_alloc(lstrlenA(pszNtlmAuth)+6);
+ lstrcpyA(pszProxyAuthorizationHeader,"NTLM ");
+ lstrcatA(pszProxyAuthorizationHeader,pszNtlmAuth);
+ mir_free(pszNtlmAuth);
+ usingNtlmAuthentication=1;
+ }
+ }
+ else {
+ NETLIBBASE64 nlb64;
+ char szAuth[512];
+ mir_snprintf(szAuth,SIZEOF(szAuth),"%s:%s",nlc->nlu->settings.szProxyAuthUser,nlc->nlu->settings.szProxyAuthPassword);
+ nlb64.cbDecoded=lstrlenA(szAuth);
+ nlb64.pbDecoded=szAuth;
+ nlb64.cchEncoded=Netlib_GetBase64EncodedBufferSize(nlb64.cbDecoded);
+ nlb64.pszEncoded=(char*)mir_alloc(nlb64.cchEncoded);
+ NetlibBase64Encode(0,(LPARAM)&nlb64);
+ pszProxyAuthorizationHeader=(char*)mir_alloc(lstrlenA(nlb64.pszEncoded)+7);
+ lstrcpyA(pszProxyAuthorizationHeader,"Basic ");
+ lstrcatA(pszProxyAuthorizationHeader,nlb64.pszEncoded);
+ mir_free(nlb64.pszEncoded);
+ }
+ }
+ else pszProxyAuthorizationHeader=NULL;
+
+ //HTTP headers
+ doneHostHeader=doneContentLengthHeader=doneProxyAuthHeader=0;
+ for(i=0;i<nlhr->headersCount;i++) {
+ if(!lstrcmpiA(nlhr->headers[i].szName,"Host")) doneHostHeader=1;
+ else if(!lstrcmpiA(nlhr->headers[i].szName,"Content-Length")) doneContentLengthHeader=1;
+ else if(!lstrcmpiA(nlhr->headers[i].szName,"Proxy-Authorization")) doneProxyAuthHeader=1;
+ else if(!lstrcmpiA(nlhr->headers[i].szName,"Connection") && usingNtlmAuthentication) continue;
+ if(nlhr->headers[i].szValue==NULL) continue;
+ AppendToCharBuffer(&httpRequest,"%s: %s\r\n",nlhr->headers[i].szName,nlhr->headers[i].szValue);
+ }
+ if(szHost && !doneHostHeader) AppendToCharBuffer(&httpRequest,"%s: %s\r\n","Host",szHost);
+ if(pszProxyAuthorizationHeader) {
+ if(!doneProxyAuthHeader) AppendToCharBuffer(&httpRequest,"%s: %s\r\n","Proxy-Authorization",pszProxyAuthorizationHeader);
+ mir_free(pszProxyAuthorizationHeader);
+ if(usingNtlmAuthentication) AppendToCharBuffer(&httpRequest,"%s: %s\r\n","Connection","Keep-Alive");
+ }
+
+ // Add Sticky Headers
+ if (nlc->nlu->szStickyHeaders != NULL) {
+ AppendToCharBuffer(&httpRequest,"%s\r\n", nlc->nlu->szStickyHeaders);
+ }
+
+ //send it
+ bytesSent=SendHttpRequestAndData(nlc,&httpRequest,nlhr,!doneContentLengthHeader);
+ if(bytesSent==SOCKET_ERROR) {
+ if(usingNtlmAuthentication) NtlmDestroy();
+ if(szHost) mir_free(szHost);
+ NetlibLeaveNestedCS(&nlc->ncsSend);
+ return SOCKET_ERROR;
+ }
+
+ //ntlm reply
+ if(usingNtlmAuthentication) {
+ int resultCode=0;
+
+ if(!HttpPeekFirstResponseLine(nlc,GetTickCount()+5000,MSG_PEEK|MSG_DUMPASTEXT|(nlhr->flags&(NLHRF_NODUMP|NLHRF_NODUMPHEADERS)?MSG_NODUMP:(nlhr->flags&NLHRF_DUMPPROXY?MSG_DUMPPROXY:0)),&resultCode,NULL,NULL)
+ || ((resultCode<200 || resultCode>=300) && resultCode!=407)) {
+ NtlmDestroy();
+ if(szHost) mir_free(szHost);
+ NetlibLeaveNestedCS(&nlc->ncsSend);
+ if(resultCode) NetlibHttpSetLastErrorUsingHttpResult(resultCode);
+ return SOCKET_ERROR;
+ }
+ if(resultCode==407) { //proxy auth required
+ NETLIBHTTPREQUEST *nlhrReply;
+ int i,error,contentLength=0;
+
+ nlhrReply=(NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc,nlhr->flags&(NLHRF_NODUMP|NLHRF_NODUMPHEADERS)?MSG_NODUMP:(nlhr->flags&NLHRF_DUMPPROXY?MSG_DUMPPROXY:0));
+ if(nlhrReply==NULL) {
+ NtlmDestroy();
+ if(szHost) mir_free(szHost);
+ NetlibLeaveNestedCS(&nlc->ncsSend);
+ if(resultCode) NetlibHttpSetLastErrorUsingHttpResult(resultCode);
+ return SOCKET_ERROR;
+ }
+ pszProxyAuthorizationHeader=NULL;
+ error=ERROR_SUCCESS;
+ for(i=0;i<nlhrReply->headersCount;i++) {
+ if(!lstrcmpiA(nlhrReply->headers[i].szName,"Proxy-Authenticate")) {
+ if(!_strnicmp(nlhrReply->headers[i].szValue,"NTLM ",5))
+ pszProxyAuthorizationHeader=NtlmCreateResponseFromChallenge(nlhrReply->headers[i].szValue+5);
+ else error=ERROR_ACCESS_DENIED;
+ }
+ else if(!lstrcmpiA(nlhrReply->headers[i].szName,"Content-Length"))
+ contentLength=atoi(nlhrReply->headers[i].szValue);
+ }
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ NtlmDestroy();
+ if(pszProxyAuthorizationHeader==NULL) {
+ if(error!=ERROR_SUCCESS) SetLastError(error);
+ if(szHost) mir_free(szHost);
+ NetlibLeaveNestedCS(&nlc->ncsSend);
+ return SOCKET_ERROR;
+ }
+
+ //receive content and throw away
+ { BYTE trashBuf[512];
+ int recvResult;
+
+ while(contentLength) {
+ recvResult=NLRecv(nlc,trashBuf,SIZEOF(trashBuf),nlhr->flags&NLHRF_NODUMP?MSG_NODUMP:MSG_DUMPASTEXT|MSG_DUMPPROXY);
+ if(recvResult==0 || recvResult==SOCKET_ERROR) {
+ if(recvResult==0) SetLastError(ERROR_HANDLE_EOF);
+ if(szHost) mir_free(szHost);
+ NetlibLeaveNestedCS(&nlc->ncsSend);
+ return SOCKET_ERROR;
+ }
+ contentLength-=recvResult;
+ }
+ }
+
+ httpRequest.cbAlloced=httpRequest.iEnd=0;
+ httpRequest.sz=NULL;
+ AppendToCharBuffer(&httpRequest,"%s %s HTTP/1.0\r\n",pszRequest,pszUrl);
+
+ //HTTP headers
+ doneHostHeader=doneContentLengthHeader=0;
+ for(i=0;i<nlhr->headersCount;i++) {
+ if(!lstrcmpiA(nlhr->headers[i].szName,"Host")) doneHostHeader=1;
+ else if(!lstrcmpiA(nlhr->headers[i].szName,"Content-Length")) doneContentLengthHeader=1;
+ if(nlhr->headers[i].szValue==NULL) continue;
+ AppendToCharBuffer(&httpRequest,"%s: %s\r\n",nlhr->headers[i].szName,nlhr->headers[i].szValue);
+ }
+ if(szHost) {
+ if(!doneHostHeader) AppendToCharBuffer(&httpRequest,"%s: %s\r\n","Host",szHost);
+ mir_free(szHost); szHost=NULL;
+ }
+ AppendToCharBuffer(&httpRequest,"%s: NTLM %s\r\n","Proxy-Authorization",pszProxyAuthorizationHeader);
+
+ //send it
+ bytesSent=SendHttpRequestAndData(nlc,&httpRequest,nlhr,!doneContentLengthHeader);
+ if(bytesSent==SOCKET_ERROR) {
+ NetlibLeaveNestedCS(&nlc->ncsSend);
+ return SOCKET_ERROR;
+ }
+ }
+ else NtlmDestroy();
+ }
+
+ //clean up
+ if(szHost) mir_free(szHost);
+ NetlibLeaveNestedCS(&nlc->ncsSend);
+ return bytesSent;
+}
+
+int NetlibHttpFreeRequestStruct(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBHTTPREQUEST *nlhr=(NETLIBHTTPREQUEST*)lParam;
+
+ if(nlhr==NULL || nlhr->cbSize!=sizeof(NETLIBHTTPREQUEST) || nlhr->requestType!=REQUEST_RESPONSE) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ if(nlhr->headers) {
+ int i;
+ for(i=0;i<nlhr->headersCount;i++) {
+ if(nlhr->headers[i].szName) mir_free(nlhr->headers[i].szName);
+ if(nlhr->headers[i].szValue) mir_free(nlhr->headers[i].szValue);
+ }
+ mir_free(nlhr->headers);
+ }
+ if(nlhr->pData) mir_free(nlhr->pData);
+ if(nlhr->szResultDescr) mir_free(nlhr->szResultDescr);
+ if(nlhr->szUrl) mir_free(nlhr->szUrl);
+ mir_free(nlhr);
+ return 1;
+}
+
+int NetlibHttpRecvHeaders(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ NETLIBHTTPREQUEST *nlhr;
+ char buffer[4096];
+ int bytesPeeked;
+ DWORD dwRequestTimeoutTime;
+ char *peol,*pbuffer;
+ int headersDone=0,firstLineLength;
+
+ if(!NetlibEnterNestedCS(nlc,NLNCS_RECV))
+ return (int)(NETLIBHTTPREQUEST*)NULL;
+ dwRequestTimeoutTime=GetTickCount()+HTTPRECVHEADERSTIMEOUT;
+ nlhr=(NETLIBHTTPREQUEST*)mir_calloc(sizeof(NETLIBHTTPREQUEST));
+ nlhr->cbSize=sizeof(NETLIBHTTPREQUEST);
+ nlhr->nlc=nlc;
+ nlhr->requestType=REQUEST_RESPONSE;
+ if(!HttpPeekFirstResponseLine(nlc,dwRequestTimeoutTime,lParam|MSG_PEEK,&nlhr->resultCode,&nlhr->szResultDescr,&firstLineLength)) {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhr);
+ return (int)(NETLIBHTTPREQUEST*)NULL;
+ }
+ bytesPeeked=NLRecv(nlc,buffer,firstLineLength,lParam|MSG_DUMPASTEXT);
+ if(bytesPeeked<firstLineLength) {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhr);
+ if(bytesPeeked!=SOCKET_ERROR) SetLastError(ERROR_HANDLE_EOF);
+ return (int)(NETLIBHTTPREQUEST*)NULL;
+ }
+ for(;;) {
+ bytesPeeked=RecvWithTimeoutTime(nlc,dwRequestTimeoutTime,buffer,SIZEOF(buffer)-1,MSG_PEEK|lParam);
+ if(bytesPeeked==0 || bytesPeeked==SOCKET_ERROR) {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhr);
+ if(bytesPeeked==0) SetLastError(ERROR_HANDLE_EOF);
+ return (int)(NETLIBHTTPREQUEST*)NULL;
+ }
+ buffer[bytesPeeked]='\0';
+ for(pbuffer=buffer;;) {
+ peol=strchr(pbuffer,'\n');
+ if(peol==NULL) {
+ if(lstrlenA(buffer)<bytesPeeked) {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhr);
+ SetLastError(ERROR_BAD_FORMAT);
+ return (int)(NETLIBHTTPREQUEST*)NULL;
+ }
+ if((bytesPeeked == SIZEOF(buffer)-1 && pbuffer==buffer) //buffer overflow
+ || (pbuffer!=buffer && NLRecv(nlc,buffer,pbuffer-buffer,lParam|MSG_DUMPASTEXT)==SOCKET_ERROR)) { //error removing read bytes from buffer
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhr);
+ if(pbuffer==buffer) SetLastError(ERROR_BUFFER_OVERFLOW);
+ return (int)(NETLIBHTTPREQUEST*)NULL;
+ }
+ Sleep(100);
+ break;
+ }
+ if(peol==pbuffer || *--peol!='\r') {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhr);
+ SetLastError(ERROR_BAD_FORMAT);
+ return (int)(NETLIBHTTPREQUEST*)NULL;
+ }
+ *peol='\0';
+ {
+ char *pColon;
+ int len;
+ if(peol==pbuffer) { //blank line: end of headers
+ if(NLRecv(nlc,buffer,peol+2-buffer,lParam|MSG_DUMPASTEXT)==SOCKET_ERROR) {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhr);
+ return (int)(NETLIBHTTPREQUEST*)NULL;
+ }
+ headersDone=1;
+ break;
+ }
+ pColon=strchr(pbuffer,':');
+ if(pColon==NULL) {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhr);
+ SetLastError(ERROR_INVALID_DATA);
+ return (int)(NETLIBHTTPREQUEST*)NULL;
+ }
+ nlhr->headersCount++;
+ nlhr->headers=(NETLIBHTTPHEADER*)mir_realloc(nlhr->headers,sizeof(NETLIBHTTPHEADER)*nlhr->headersCount);
+ nlhr->headers[nlhr->headersCount-1].szName=(char*)mir_alloc(pColon-pbuffer+1);
+ lstrcpynA(nlhr->headers[nlhr->headersCount-1].szName,pbuffer,pColon-pbuffer+1);
+ len=lstrlenA(nlhr->headers[nlhr->headersCount-1].szName);
+ while(len && (nlhr->headers[nlhr->headersCount-1].szName[len-1]==' ' || nlhr->headers[nlhr->headersCount-1].szName[len-1]=='\t'))
+ nlhr->headers[nlhr->headersCount-1].szName[--len]='\0';
+ pColon++;
+ while(*pColon==' ' || *pColon=='\t') pColon++;
+ nlhr->headers[nlhr->headersCount-1].szValue=mir_strdup(pColon);
+ }
+ pbuffer=peol+2;
+ }
+ if(headersDone) break;
+ }
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ return (int)nlhr;
+}
+
+int NetlibHttpTransaction(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibUser *nlu=(struct NetlibUser*)wParam;
+ NETLIBHTTPREQUEST *nlhr=(NETLIBHTTPREQUEST*)lParam,*nlhrReply;
+ HANDLE hConnection;
+
+ if(GetNetlibHandleType(nlu)!=NLH_USER || !(nlu->user.flags&NUF_OUTGOING) || nlhr==NULL || nlhr->cbSize!=sizeof(NETLIBHTTPREQUEST) || nlhr->szUrl==NULL || nlhr->szUrl[0]=='\0') {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return (int)(HANDLE)NULL;
+ }
+
+ {
+ NETLIBOPENCONNECTION nloc={0};
+ char szHost[128];
+ char *ppath,*phost,*pcolon;
+
+ phost=strstr(nlhr->szUrl,"://");
+ if(phost==NULL) phost=nlhr->szUrl;
+ else phost+=3;
+ lstrcpynA(szHost,phost,SIZEOF(szHost));
+ ppath=strchr(szHost,'/');
+ if(ppath) *ppath='\0';
+ nloc.cbSize=sizeof(nloc);
+ nloc.szHost=szHost;
+ pcolon=strrchr(szHost,':');
+ if(pcolon) {
+ *pcolon='\0';
+ nloc.wPort=(WORD)strtol(pcolon+1,NULL,10);
+ }
+ else nloc.wPort=80;
+ nloc.flags=NLOCF_HTTP;
+ hConnection=(HANDLE)NetlibOpenConnection((WPARAM)nlu,(LPARAM)&nloc);
+ if(hConnection==NULL) return (int)(HANDLE)NULL;
+ }
+
+ {
+ NETLIBHTTPREQUEST nlhrSend;
+ int i,doneUserAgentHeader=0;
+ char szUserAgent[64];
+
+ nlhrSend=*nlhr;
+ nlhrSend.flags&=~NLHRF_REMOVEHOST;
+ nlhrSend.flags|=NLHRF_GENERATEHOST|NLHRF_SMARTREMOVEHOST|NLHRF_SMARTAUTHHEADER;
+ for(i=0;i<nlhr->headersCount;i++) {
+ if(!lstrcmpiA(nlhr->headers[i].szName,"User-Agent"))
+ doneUserAgentHeader=1;
+ }
+ if(!doneUserAgentHeader) {
+ char *pspace,szMirandaVer[32];
+
+ nlhrSend.headersCount++;
+ nlhrSend.headers=(NETLIBHTTPHEADER*)mir_alloc(sizeof(NETLIBHTTPHEADER)*nlhrSend.headersCount);
+ CopyMemory(nlhrSend.headers,nlhr->headers,sizeof(NETLIBHTTPHEADER)*nlhr->headersCount);
+ nlhrSend.headers[nlhrSend.headersCount-1].szName="User-Agent";
+ nlhrSend.headers[nlhrSend.headersCount-1].szValue=szUserAgent;
+ CallService(MS_SYSTEM_GETVERSIONTEXT,SIZEOF(szMirandaVer),(LPARAM)szMirandaVer);
+ pspace=strchr(szMirandaVer,' ');
+ if(pspace) {
+ *pspace++='\0';
+ mir_snprintf(szUserAgent,SIZEOF(szUserAgent),"Miranda/%s (%s)",szMirandaVer,pspace);
+ }
+ else mir_snprintf(szUserAgent,SIZEOF(szUserAgent),"Miranda/%s",szMirandaVer);
+ }
+ if(NetlibHttpSendRequest((WPARAM)hConnection,(LPARAM)&nlhrSend)==SOCKET_ERROR) {
+ if(!doneUserAgentHeader) mir_free(nlhrSend.headers);
+ NetlibCloseHandle((WPARAM)hConnection,0);
+ return (int)(HANDLE)NULL;
+ }
+ if(!doneUserAgentHeader) mir_free(nlhrSend.headers);
+ }
+
+ {
+ nlhrReply=(NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)hConnection,0);
+ if(nlhrReply==NULL) {
+ NetlibCloseHandle((WPARAM)hConnection,0);
+ return (int)(HANDLE)NULL;
+ } }
+
+ if (nlhr->requestType != REQUEST_HEAD){
+ int recvResult;
+ int dataBufferAlloced=0;
+
+ for(;;) {
+ if(dataBufferAlloced-nlhrReply->dataLength<1024) {
+ dataBufferAlloced+=2048;
+ nlhrReply->pData=(PBYTE)mir_realloc(nlhrReply->pData,dataBufferAlloced);
+ if(nlhrReply->pData==NULL) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ NetlibCloseHandle((WPARAM)hConnection,0);
+ return (int)(HANDLE)NULL;
+ }
+ }
+ recvResult=NLRecv((struct NetlibConnection*)hConnection,nlhrReply->pData+nlhrReply->dataLength,dataBufferAlloced-nlhrReply->dataLength-1,(nlhr->flags&NLHRF_DUMPASTEXT?MSG_DUMPASTEXT:0)|(nlhr->flags&NLHRF_NODUMP?MSG_NODUMP:(nlhr->flags&NLHRF_DUMPPROXY?MSG_DUMPPROXY:0)));
+ if(recvResult==0) break;
+ if(recvResult==SOCKET_ERROR) {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ NetlibCloseHandle((WPARAM)hConnection,0);
+ return (int)(HANDLE)NULL;
+ }
+ nlhrReply->dataLength+=recvResult;
+ //TODO: Keep-alive replies are measured by content-length, not by when the connection closes
+ }
+ nlhrReply->pData[nlhrReply->dataLength]='\0';
+ }
+
+ NetlibCloseHandle((WPARAM)hConnection,0);
+ return (int)nlhrReply;
+}
+
+void NetlibHttpSetLastErrorUsingHttpResult(int result)
+{
+ if(result>=200 && result<300) {
+ SetLastError(ERROR_SUCCESS);
+ return;
+ }
+ switch(result) {
+ case 400: SetLastError(ERROR_BAD_FORMAT); break;
+ case 401:
+ case 402:
+ case 403:
+ case 407: SetLastError(ERROR_ACCESS_DENIED); break;
+ case 404: SetLastError(ERROR_FILE_NOT_FOUND); break;
+ case 405:
+ case 406: SetLastError(ERROR_INVALID_FUNCTION); break;
+ case 408: SetLastError(ERROR_TIMEOUT); break;
+ default: SetLastError(ERROR_GEN_FAILURE); break;
+ }
+}
diff --git a/miranda-wine/src/modules/netlib/netlibhttpproxy.c b/miranda-wine/src/modules/netlib/netlibhttpproxy.c
new file mode 100644
index 0000000..f3fc82e
--- /dev/null
+++ b/miranda-wine/src/modules/netlib/netlibhttpproxy.c
@@ -0,0 +1,610 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "netlib.h"
+
+#define HTTPGETTIMEOUT 55000 //in ms. http GETs through most proxies will give up after a while so the request needs to be re-sent
+
+static int HttpGatewaySendGet(struct NetlibConnection *nlc)
+{
+ NETLIBHTTPREQUEST nlhrSend={0};
+ NETLIBHTTPHEADER httpHeaders[3];
+ char szUrl[512];
+ struct NetlibConnection nlcSend;
+
+ nlc->s=socket(AF_INET,SOCK_STREAM,0);
+ if(nlc->s==INVALID_SOCKET) {
+ Netlib_Logf(nlc->nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"socket",WSAGetLastError());
+ return 0;
+ }
+
+ if(connect(nlc->s,(SOCKADDR *)&nlc->sinProxy,sizeof(nlc->sinProxy))==SOCKET_ERROR) {
+ Netlib_Logf(nlc->nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"connect",WSAGetLastError());
+ return 0;
+ }
+
+ nlhrSend.cbSize=sizeof(nlhrSend);
+ nlhrSend.nlc=nlc;
+
+ /*
+ * Gena01 - one small change here, just in case there is a timeout or a problem and we died while
+ * receiving
+ */
+ nlhrSend.requestType=(nlc->nlhpi.szHttpGetUrl == NULL) ? REQUEST_POST : REQUEST_GET;
+ nlhrSend.flags=NLHRF_GENERATEHOST|NLHRF_DUMPPROXY|NLHRF_SMARTAUTHHEADER;
+ if (nlc->nlhpi.flags & NLHPIF_HTTP11) nlhrSend.flags |= NLHRF_HTTP11;
+
+ /*
+ * Gena01 - fixing a possible crash, can't use GET Sequence if there is no GET URL
+ */
+ if ((nlc->nlhpi.flags&NLHPIF_USEGETSEQUENCE) && (nlc->nlhpi.szHttpGetUrl != NULL)) {
+ EnterCriticalSection(&nlc->csHttpSequenceNums);
+
+ mir_snprintf(szUrl,SIZEOF(szUrl),"%s%u",nlc->nlhpi.szHttpGetUrl,nlc->nlhpi.firstGetSequence);
+ nlc->nlhpi.firstGetSequence++;
+ if(nlc->nlhpi.flags&NLHPIF_GETPOSTSAMESEQUENCE) nlc->nlhpi.firstPostSequence++;
+ LeaveCriticalSection(&nlc->csHttpSequenceNums);
+ nlhrSend.szUrl=szUrl;
+ }
+ else nlhrSend.szUrl=(nlc->nlhpi.szHttpGetUrl == NULL) ? nlc->nlhpi.szHttpPostUrl : nlc->nlhpi.szHttpGetUrl;
+ nlhrSend.headers=httpHeaders;
+ nlhrSend.headersCount= 3;
+ httpHeaders[0].szName="User-Agent";
+ httpHeaders[0].szValue=nlc->nlu->user.szHttpGatewayUserAgent;
+ httpHeaders[1].szName="Cache-Control";
+ httpHeaders[1].szValue="no-store, no-cache";
+ httpHeaders[2].szName="Pragma";
+ httpHeaders[2].szValue="no-cache";
+
+ nlcSend=*nlc;
+ nlcSend.usingHttpGateway=0;
+
+ if (nlc->nlhpi.szHttpGetUrl != NULL) {
+
+ Netlib_Logf(nlc->nlu,"%s %d: Sending data.[ICQ GET] ",__FILE__,__LINE__);
+ if(NetlibHttpSendRequest((WPARAM)&nlcSend,(LPARAM)&nlhrSend)==SOCKET_ERROR) {
+ nlc->usingHttpGateway=1;
+ return 0;
+ }
+ nlc->dwLastGetSentTime=GetTickCount();
+ return 1;
+ }
+
+ /*
+ * Gena01 - small addition here, if we doing a POST then insert our packet here
+ */
+ if (nlc->pHttpProxyPacketQueue != NULL) {
+ struct NetlibHTTPProxyPacketQueue *p = nlc->pHttpProxyPacketQueue;
+
+ nlc->pHttpProxyPacketQueue = nlc->pHttpProxyPacketQueue->next;
+
+ nlhrSend.dataLength=p->dataBufferLen;
+ nlhrSend.pData=(char*)p->dataBuffer;
+
+ mir_free(p);
+ }
+
+ if(NetlibHttpSendRequest((WPARAM)&nlcSend,(LPARAM)&nlhrSend)==SOCKET_ERROR) {
+ struct NetlibHTTPProxyPacketQueue *p = nlc->pHttpProxyPacketQueue;
+
+ mir_free(nlhrSend.pData);
+
+ nlc->usingHttpGateway=1;
+
+ /*
+ * Gena01 - we need to drop ALL pending packets. Connection died!
+ */
+ while (p != NULL) {
+ struct NetlibHTTPProxyPacketQueue *t = p;
+
+ p = p->next;
+
+ mir_free(t->dataBuffer);
+ mir_free(t);
+ }
+
+ nlc->pHttpProxyPacketQueue = NULL; /* empty Queue */
+
+ return 0;
+ }
+ mir_free(nlhrSend.pData);
+ nlc->dwLastGetSentTime=GetTickCount();
+ return 1;
+}
+
+/*
+ * Gena01 - this is the old POST method, I renamed it and left it intact for ICQ support. it's called
+ * when we have both GET and POST URLs specified.
+ */
+int NetlibHttpGatewayOLDPost(struct NetlibConnection *nlc,const char *buf,int len,int flags)
+{
+ NETLIBHTTPREQUEST nlhrSend={0},*nlhrReply;
+ NETLIBHTTPHEADER httpHeaders[4];
+ char szUrl[512];
+ struct NetlibConnection nlcSend={0};
+
+ nlcSend.handleType=NLH_CONNECTION;
+ nlcSend.nlu=nlc->nlu;
+ nlcSend.hInstSecurityDll=nlc->hInstSecurityDll;
+ nlcSend.s=socket(AF_INET,SOCK_STREAM,0);
+ if(nlcSend.s==INVALID_SOCKET) {
+ Netlib_Logf(nlc->nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"socket",WSAGetLastError());
+ return SOCKET_ERROR;
+ }
+ nlcSend.hOkToCloseEvent=CreateEvent(NULL,TRUE,TRUE,NULL);
+ nlcSend.dontCloseNow=0;
+ NetlibInitializeNestedCS(&nlcSend.ncsRecv);
+ NetlibInitializeNestedCS(&nlcSend.ncsSend);
+
+ if(connect(nlcSend.s,(SOCKADDR *)&nlc->sinProxy,sizeof(nlc->sinProxy))==SOCKET_ERROR) {
+ Netlib_Logf(nlc->nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"connect",WSAGetLastError());
+ NetlibDeleteNestedCS(&nlcSend.ncsRecv);
+ NetlibDeleteNestedCS(&nlcSend.ncsSend);
+ CloseHandle(nlcSend.hOkToCloseEvent);
+ closesocket(nlcSend.s);
+ return SOCKET_ERROR;
+ }
+
+ nlhrSend.cbSize=sizeof(nlhrSend);
+ nlhrSend.nlc=nlc;
+ nlhrSend.requestType=REQUEST_POST;
+ nlhrSend.flags=NLHRF_GENERATEHOST|NLHRF_DUMPPROXY|NLHRF_SMARTAUTHHEADER;
+ if(flags&MSG_NODUMP) nlhrSend.flags|=NLHRF_NODUMP;
+ if(nlc->nlhpi.flags&NLHPIF_USEPOSTSEQUENCE) {
+ EnterCriticalSection(&nlc->csHttpSequenceNums);
+ mir_snprintf(szUrl,SIZEOF(szUrl),"%s%u",nlc->nlhpi.szHttpPostUrl,nlc->nlhpi.firstPostSequence);
+ nlc->nlhpi.firstPostSequence++;
+ if(nlc->nlhpi.flags&NLHPIF_GETPOSTSAMESEQUENCE) nlc->nlhpi.firstGetSequence++;
+ LeaveCriticalSection(&nlc->csHttpSequenceNums);
+ nlhrSend.szUrl=szUrl;
+ }
+ else nlhrSend.szUrl=nlc->nlhpi.szHttpPostUrl;
+ nlhrSend.headers=httpHeaders;
+ nlhrSend.headersCount=3;
+ httpHeaders[0].szName="User-Agent";
+ httpHeaders[0].szValue=nlc->nlu->user.szHttpGatewayUserAgent;
+ httpHeaders[1].szName="Cache-Control";
+ httpHeaders[1].szValue="no-store, no-cache";
+ httpHeaders[2].szName="Connection";
+ httpHeaders[2].szValue="close";
+ httpHeaders[3].szName="Pragma";
+ httpHeaders[3].szValue="no-cache";
+ nlhrSend.dataLength=len;
+ nlhrSend.pData=(char*)buf;
+ if(NetlibHttpSendRequest((WPARAM)&nlcSend,(LPARAM)&nlhrSend)==SOCKET_ERROR) {
+ NetlibDeleteNestedCS(&nlcSend.ncsRecv);
+ NetlibDeleteNestedCS(&nlcSend.ncsSend);
+ CloseHandle(nlcSend.hOkToCloseEvent);
+ closesocket(nlcSend.s);
+ return SOCKET_ERROR;
+ }
+
+ nlhrReply=(NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)&nlcSend,flags&MSG_NODUMP?MSG_NODUMP:MSG_DUMPPROXY);
+ if(nlhrReply==NULL
+ || nlhrReply->resultCode<200 || nlhrReply->resultCode>=300) {
+ NetlibDeleteNestedCS(&nlcSend.ncsRecv);
+ NetlibDeleteNestedCS(&nlcSend.ncsSend);
+ CloseHandle(nlcSend.hOkToCloseEvent);
+ closesocket(nlcSend.s);
+ if(nlhrReply) {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ NetlibHttpSetLastErrorUsingHttpResult(nlhrReply->resultCode);
+ }
+ return SOCKET_ERROR;
+ }
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+
+ NetlibDeleteNestedCS(&nlcSend.ncsRecv);
+ NetlibDeleteNestedCS(&nlcSend.ncsSend);
+ CloseHandle(nlcSend.hOkToCloseEvent);
+ closesocket(nlcSend.s);
+ return len;
+}
+
+int NetlibHttpGatewayPost(struct NetlibConnection *nlc,const char *buf,int len,int flags)
+{
+ struct NetlibHTTPProxyPacketQueue *p;
+
+ if (nlc->nlhpi.szHttpGetUrl != NULL)
+ return NetlibHttpGatewayOLDPost(nlc, buf, len, flags);
+
+ /*
+ * Gena01 - many changes here, do compare against the other version.
+ *
+ * Change #1: simplify to use similar code to GET
+ * Change #2: we need to allow to parse POST reply if szHttpGetUrl is NULL
+ * Change #3: Keep connection open if we need to.
+ *
+ * Impact: NONE! Since currently miranda doesn't allow szHttpGetUrl to be NULL, it will not connect
+ * with the new plugins that use this code.
+ */
+
+ p = mir_alloc(sizeof(struct NetlibHTTPProxyPacketQueue));
+ p->dataBuffer = mir_alloc(len);
+ memcpy(p->dataBuffer, buf, len);
+ p->dataBufferLen = len;
+ p->next = NULL;
+
+ /*
+ * Now check to see where to insert this in our queue
+ */
+ if (nlc->pHttpProxyPacketQueue == NULL) {
+ nlc->pHttpProxyPacketQueue = p;
+ } else {
+ struct NetlibHTTPProxyPacketQueue *t = nlc->pHttpProxyPacketQueue;
+
+ while (t->next != NULL)
+ t = t->next;
+
+ t->next = p;
+ }
+
+
+ /*
+ * Gena01 - fake a Send!! tell 'em all is ok. We catch errors in Recv.
+ */
+ return len;
+}
+
+#define NETLIBHTTP_RETRYCOUNT 3
+#define NETLIBHTTP_RETRYTIMEOUT 5000
+
+int NetlibHttpGatewayRecv(struct NetlibConnection *nlc,char *buf,int len,int flags)
+{
+ DWORD dwTimeNow;
+ int timedout;
+ NETLIBHTTPREQUEST *nlhrReply;
+ PBYTE dataBuffer;
+ int contentLength,i,bytesRecved;
+ int recvResult;
+ int retryCount;
+
+ /*
+ * Gena01 - we need to send packet here, since we didn't do it before.
+ */
+ if ((nlc->nlhpi.szHttpGetUrl == NULL) && (nlc->s == INVALID_SOCKET) && nlc->dataBuffer == NULL ) {
+
+ if ( nlc->pollingTimeout == 0 )
+ nlc->pollingTimeout = 30;
+
+ /* We Need to sleep/wait for the data to send before we do receive */
+ for ( retryCount = 0; retryCount < nlc->pollingTimeout; retryCount++ )
+ {
+ if ( nlc->pHttpProxyPacketQueue != NULL )
+ break;
+
+ if ( SleepEx( 1000, TRUE ))
+ return SOCKET_ERROR;
+ }
+
+/* if ( retryCount == nlc->pollingTimeout )
+ { SetLastError( ERROR_TIMEOUT );
+ return SOCKET_ERROR;
+ }
+*/
+ if ( nlc->pHttpProxyPacketQueue == 0 && nlc->nlu->user.pfnHttpGatewayWrapSend != NULL )
+ nlc->nlu->user.pfnHttpGatewayWrapSend((HANDLE)nlc,"",0,MSG_NOHTTPGATEWAYWRAP,NetlibSend);
+
+ if(!HttpGatewaySendGet(nlc)) {
+ return SOCKET_ERROR;
+ }
+ }
+ /********************/
+ if(nlc->dataBuffer) {
+ if(nlc->dataBufferLen<=len) {
+ contentLength=nlc->dataBufferLen;
+ CopyMemory(buf,nlc->dataBuffer,nlc->dataBufferLen);
+ if(!(flags&MSG_PEEK)) {
+ mir_free(nlc->dataBuffer);
+ nlc->dataBuffer=NULL;
+ nlc->dataBufferLen=0;
+ }
+ return contentLength;
+ }
+ CopyMemory(buf,nlc->dataBuffer,len);
+ if(!(flags&MSG_PEEK)) {
+ nlc->dataBufferLen-=len;
+ MoveMemory(nlc->dataBuffer,nlc->dataBuffer+len,nlc->dataBufferLen);
+ nlc->dataBuffer=(PBYTE)mir_realloc(nlc->dataBuffer,nlc->dataBufferLen);
+ }
+ return len;
+ }
+ for( retryCount = 0;;) {
+ timedout=0;
+ dwTimeNow=GetTickCount();
+ if(dwTimeNow>=nlc->dwLastGetSentTime+HTTPGETTIMEOUT) timedout=1;
+ else if(!WaitUntilReadable(nlc->s,nlc->dwLastGetSentTime+HTTPGETTIMEOUT-dwTimeNow)) {
+ if(GetLastError()==ERROR_TIMEOUT) timedout=1;
+ else return SOCKET_ERROR;
+ }
+ if(timedout) {
+ closesocket(nlc->s);
+ nlc->s=INVALID_SOCKET;
+ if(!HttpGatewaySendGet(nlc)) return SOCKET_ERROR;
+ retryCount = 0;
+ continue;
+ }
+ nlhrReply=(NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc,flags|MSG_RAW|MSG_DUMPPROXY);
+ if(nlhrReply==NULL) return SOCKET_ERROR;
+ // ignore 1xx result codes
+ if (nlhrReply->resultCode < 200)
+ {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ continue;
+ }
+ // 0.3.1+
+ // Attempt to retry NETLIBHTTP_RETRYCOUNT times if the result code is >300
+ if (nlhrReply->resultCode >= 300)
+ {
+ if (retryCount < NETLIBHTTP_RETRYCOUNT) {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ Netlib_Logf(nlc->nlu, "Error received from proxy, retrying");
+ retryCount++;
+ closesocket(nlc->s);
+ nlc->s = INVALID_SOCKET;
+ Sleep(NETLIBHTTP_RETRYTIMEOUT); // wait 5 seconds
+ // retry the connection
+ Netlib_Logf(nlc->nlu,"%s %d: ResultCode?? Doing GET.",__FILE__,__LINE__);
+ if(HttpGatewaySendGet(nlc))
+ continue;
+ SetLastError(ERROR_GEN_FAILURE);
+ return SOCKET_ERROR;
+ }
+ }
+ retryCount = 0;
+ contentLength=-1;
+ for(i=0;i<nlhrReply->headersCount;i++)
+ {
+ if(!lstrcmpiA(nlhrReply->headers[i].szName,"Content-Length")) {
+ contentLength=atoi(nlhrReply->headers[i].szValue);
+ break;
+ }
+ }
+
+ /*
+ if(contentLength<0) {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ SetLastError(ERROR_INVALID_DATA);
+ return SOCKET_ERROR;
+ }*/
+ if(contentLength==0 && nlc->nlu->user.szHttpGatewayHello != NULL)
+ {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ continue;
+ }
+
+
+ if (contentLength < 0) {
+ /* create initial buffer */
+ contentLength = 2048;
+
+ dataBuffer=(PBYTE)mir_alloc(contentLength);
+
+ /* error and exit */
+ if(dataBuffer==NULL) {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return SOCKET_ERROR;
+ }
+
+ /* now we need to get the bytes and add them to our buffer */
+ bytesRecved = 0;
+
+ do {
+ recvResult=NLRecv(nlc,dataBuffer+bytesRecved,contentLength-bytesRecved,MSG_RAW|MSG_DUMPPROXY);
+ if(recvResult==SOCKET_ERROR) {
+ mir_free(dataBuffer);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ if(recvResult==0) SetLastError(ERROR_HANDLE_EOF);
+ return SOCKET_ERROR;
+ }
+ bytesRecved+=recvResult;
+ } while (recvResult > 0);
+ contentLength = bytesRecved;
+ } else {
+ if(contentLength > 0) {
+ dataBuffer=(PBYTE)mir_alloc(contentLength);
+ if(dataBuffer==NULL) {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return SOCKET_ERROR;
+ }
+ for(bytesRecved=0;bytesRecved<contentLength;) {
+ recvResult=NLRecv(nlc,dataBuffer+bytesRecved,contentLength-bytesRecved,MSG_RAW|MSG_DUMPPROXY);
+ if(recvResult==0 || recvResult==SOCKET_ERROR) {
+ mir_free(dataBuffer);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ if(recvResult==0) SetLastError(ERROR_HANDLE_EOF);
+ return SOCKET_ERROR;
+ }
+ bytesRecved+=recvResult;
+ } }
+ else dataBuffer = NULL;
+ }
+
+ closesocket(nlc->s);
+ nlc->s=INVALID_SOCKET;
+
+ /*
+ * Gena01 - ok, ICQ does it here so that when we enter this function again we have reply
+ * pending. This is quite clever, since GET always gets replies from ICQ server
+ *
+ */
+ if (nlc->nlhpi.szHttpGetUrl != NULL) {
+ Netlib_Logf(nlc->nlu,"%s %d: Doing GET, Again????",__FILE__,__LINE__);
+
+ if(!HttpGatewaySendGet(nlc)) {
+ mir_free(dataBuffer);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ return SOCKET_ERROR;
+ }
+ }
+
+ if(nlc->nlu->user.pfnHttpGatewayUnwrapRecv && !(flags&MSG_NOHTTPGATEWAYWRAP)) {
+ PBYTE newBuffer;
+ newBuffer=nlc->nlu->user.pfnHttpGatewayUnwrapRecv(nlhrReply,dataBuffer,contentLength,&contentLength,mir_realloc);
+ if(newBuffer==NULL) {
+ mir_free(dataBuffer);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ return SOCKET_ERROR;
+ }
+ dataBuffer=newBuffer;
+ }
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ if(contentLength>0) break;
+ if((contentLength==0)&&(nlc->nlhpi.szHttpGetUrl==NULL))
+ break;
+ mir_free(dataBuffer);
+ }
+ if(contentLength<=len) {
+ if(flags&MSG_PEEK) {
+ nlc->dataBuffer=dataBuffer;
+ nlc->dataBufferLen=contentLength;
+ }
+ CopyMemory(buf,dataBuffer,contentLength);
+ if(!(flags&MSG_PEEK)) mir_free(dataBuffer);
+ return contentLength;
+ }
+ CopyMemory(buf,dataBuffer,len);
+ if(!(flags&MSG_PEEK)) {
+ MoveMemory(dataBuffer,dataBuffer+len,contentLength-len);
+ dataBuffer=(PBYTE)mir_realloc(dataBuffer,contentLength-len);
+ nlc->dataBufferLen=contentLength-len;
+ }
+ else nlc->dataBufferLen=contentLength;
+ nlc->dataBuffer=dataBuffer;
+
+ Netlib_Logf(nlc->nlu,"%s %d: NetlibHTTPGatewayRecv EXIT!",__FILE__,__LINE__);
+ return len;
+}
+
+int NetlibInitHttpConnection(struct NetlibConnection *nlc,struct NetlibUser *nlu,NETLIBOPENCONNECTION *nloc)
+{
+ NETLIBHTTPREQUEST nlhrSend={0},*nlhrReply=NULL;
+ NETLIBHTTPHEADER httpHeaders[3];
+
+ nlc->nlhpi.firstGetSequence=nlc->nlhpi.firstPostSequence=1;
+
+ /*
+ * Gena01 - ok we set nlhrReply to be null, also if the szHttpGatewayHello is NULL, then
+ * we don't send any requests/replies. We do have a socket open though. Could we
+ * re-use it maybe?
+ */
+ if (nlu->user.szHttpGatewayHello != NULL) {
+ nlhrSend.cbSize=sizeof(nlhrSend);
+ nlhrSend.nlc=nlc;
+ nlhrSend.requestType=REQUEST_GET;
+ nlhrSend.flags=NLHRF_GENERATEHOST|NLHRF_DUMPPROXY|NLHRF_SMARTAUTHHEADER;
+ if (nlc->nlhpi.flags & NLHPIF_HTTP11) nlhrSend.flags |= NLHRF_HTTP11;
+
+ nlhrSend.szUrl=nlu->user.szHttpGatewayHello;
+ nlhrSend.headers=httpHeaders;
+ nlhrSend.headersCount=3;
+ httpHeaders[0].szName="User-Agent";
+ httpHeaders[0].szValue=nlu->user.szHttpGatewayUserAgent;
+ httpHeaders[1].szName="Cache-Control";
+ httpHeaders[1].szValue="no-store, no-cache";
+ httpHeaders[2].szName="Pragma";
+ httpHeaders[2].szValue="no-cache";
+ if(NetlibHttpSendRequest((WPARAM)nlc,(LPARAM)&nlhrSend)==SOCKET_ERROR)
+ return 0;
+
+ nlhrReply=(NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc,MSG_DUMPPROXY);
+ if(nlhrReply==NULL) return 0;
+
+ if(nlhrReply->resultCode<200 || nlhrReply->resultCode>=300) {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ NetlibHttpSetLastErrorUsingHttpResult(nlhrReply->resultCode);
+ return 0;
+ }
+ }
+ if(!nlu->user.pfnHttpGatewayInit(nlc,nloc,nlhrReply)) {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ return 0;
+ }
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+
+ /*
+ * Gena01 - Ok, we should be able to use just POST. Needed for Yahoo, NO GET requests
+ */
+ if(nlc->nlhpi.szHttpPostUrl==NULL) {
+ SetLastError(ERROR_BAD_FORMAT);
+ return 0;
+ }
+ closesocket(nlc->s);
+ nlc->s=INVALID_SOCKET;
+
+ nlc->usingHttpGateway=1;
+
+ /* don't send anything if only using POST? */
+ if(nlc->nlhpi.szHttpGetUrl!= NULL)
+ if(!HttpGatewaySendGet(nlc))
+ return 0;
+
+ //now properly connected
+ if(nlu->user.pfnHttpGatewayBegin)
+ if(!nlu->user.pfnHttpGatewayBegin(nlc,nloc))
+ return 0;
+ return 1;
+}
+
+int NetlibHttpGatewaySetInfo(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBHTTPPROXYINFO *nlhpi=(NETLIBHTTPPROXYINFO*)lParam;
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+
+ if(GetNetlibHandleType(nlc)!=NLH_CONNECTION || nlhpi==NULL || nlhpi->cbSize!=sizeof(NETLIBHTTPPROXYINFO) || nlhpi->szHttpPostUrl==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ if(nlc->nlhpi.szHttpGetUrl) mir_free(nlc->nlhpi.szHttpGetUrl);
+ if(nlc->nlhpi.szHttpPostUrl) mir_free(nlc->nlhpi.szHttpPostUrl);
+ nlc->nlhpi=*nlhpi;
+
+ if (nlc->nlhpi.szHttpGetUrl)
+ nlc->nlhpi.szHttpGetUrl=mir_strdup(nlc->nlhpi.szHttpGetUrl);
+
+ nlc->nlhpi.szHttpPostUrl=mir_strdup(nlc->nlhpi.szHttpPostUrl);
+ return 1;
+}
+
+int NetlibHttpSetSticky(WPARAM wParam, LPARAM lParam)
+{
+ struct NetlibUser * nu = (struct NetlibUser*)wParam;
+ if (GetNetlibHandleType(nu)!=NLH_USER) return ERROR_INVALID_PARAMETER;
+ if (nu->szStickyHeaders) { mir_free(nu->szStickyHeaders); nu->szStickyHeaders=NULL; }
+ if (lParam) {
+ nu->szStickyHeaders=mir_strdup((char*)lParam); // pointer is ours
+ }
+ return 0;
+}
+
+int NetlibHttpSetPollingTimeout(WPARAM wParam, LPARAM lParam)
+{
+ int oldTimeout;
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ if (GetNetlibHandleType(nlc)!=NLH_CONNECTION) return -1;
+ oldTimeout = nlc->pollingTimeout;
+ nlc->pollingTimeout = lParam;
+ return oldTimeout;
+}
diff --git a/miranda-wine/src/modules/netlib/netliblog.c b/miranda-wine/src/modules/netlib/netliblog.c
new file mode 100644
index 0000000..9d07f29
--- /dev/null
+++ b/miranda-wine/src/modules/netlib/netliblog.c
@@ -0,0 +1,440 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "netlib.h"
+
+#define MS_NETLIB_LOGWIN "Netlib/Log/Win"
+
+extern HANDLE hConnectionHeaderMutex;
+
+#define TIMEFORMAT_NONE 0
+#define TIMEFORMAT_HHMMSS 1
+#define TIMEFORMAT_MILLISECONDS 2
+#define TIMEFORMAT_MICROSECONDS 3
+struct {
+ HWND hwndOpts;
+ int toOutputDebugString;
+ int toFile;
+ TCHAR* szFile;
+ int timeFormat;
+ int showUser;
+ int dumpSent,dumpRecv,dumpProxy;
+ int textDumps,autoDetectText;
+ CRITICAL_SECTION cs;
+} logOptions;
+static __int64 mirandaStartTime,perfCounterFreq;
+
+static const TCHAR* szTimeFormats[] =
+{
+ _T( "No times" ),
+ _T( "Standard hh:mm:ss times" ),
+ _T( "Times in milliseconds" ),
+ _T( "Times in microseconds" )
+};
+
+static BOOL CALLBACK LogOptionsDlgProc(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ switch(message) {
+ case WM_INITDIALOG:
+ logOptions.hwndOpts=hwndDlg;
+ TranslateDialogDefault(hwndDlg);
+ CheckDlgButton(hwndDlg,IDC_DUMPRECV,logOptions.dumpRecv?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_DUMPSENT,logOptions.dumpSent?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_DUMPPROXY,logOptions.dumpProxy?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_TEXTDUMPS,logOptions.textDumps?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_AUTODETECTTEXT,logOptions.autoDetectText?BST_CHECKED:BST_UNCHECKED);
+ { int i;
+ for( i=0; i < SIZEOF(szTimeFormats); i++ )
+ SendDlgItemMessage(hwndDlg,IDC_TIMEFORMAT,CB_ADDSTRING,0,(LPARAM)TranslateTS( szTimeFormats[i] ));
+ }
+ SendDlgItemMessage(hwndDlg,IDC_TIMEFORMAT,CB_SETCURSEL,logOptions.timeFormat,0);
+ CheckDlgButton(hwndDlg,IDC_SHOWNAMES,logOptions.showUser?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_TOOUTPUTDEBUGSTRING,logOptions.toOutputDebugString?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_TOFILE,logOptions.toFile?BST_CHECKED:BST_UNCHECKED);
+ SetDlgItemText(hwndDlg,IDC_FILENAME,logOptions.szFile);
+ CheckDlgButton(hwndDlg,IDC_SHOWTHISDLGATSTART,DBGetContactSettingByte(NULL,"Netlib","ShowLogOptsAtStart",0)?BST_CHECKED:BST_UNCHECKED);
+ { DBVARIANT dbv;
+ if(!DBGetContactSetting(NULL,"Netlib","RunAtStart",&dbv)) {
+ SetDlgItemTextA(hwndDlg,IDC_RUNATSTART,dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_DUMPRECV:
+ logOptions.dumpRecv=IsDlgButtonChecked(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_DUMPSENT:
+ logOptions.dumpSent=IsDlgButtonChecked(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_DUMPPROXY:
+ logOptions.dumpProxy=IsDlgButtonChecked(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_TEXTDUMPS:
+ logOptions.textDumps=IsDlgButtonChecked(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_AUTODETECTTEXT:
+ logOptions.autoDetectText=IsDlgButtonChecked(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_TIMEFORMAT:
+ logOptions.timeFormat=SendDlgItemMessage(hwndDlg,IDC_TIMEFORMAT,CB_GETCURSEL,0,0);
+ break;
+ case IDC_SHOWNAMES:
+ logOptions.showUser=IsDlgButtonChecked(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_TOOUTPUTDEBUGSTRING:
+ logOptions.toOutputDebugString=IsDlgButtonChecked(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_TOFILE:
+ logOptions.toFile=IsDlgButtonChecked(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_FILENAME:
+ if(HIWORD(wParam)!=EN_CHANGE) break;
+ if((HWND)lParam==GetFocus()) {
+ CheckDlgButton(hwndDlg,IDC_TOFILE,BST_CHECKED);
+ logOptions.toFile=0;
+ }
+ EnterCriticalSection(&logOptions.cs);
+ if(logOptions.szFile) mir_free(logOptions.szFile);
+ { int len;
+ len=GetWindowTextLength((HWND)lParam);
+ logOptions.szFile = ( TCHAR* )mir_alloc( sizeof( TCHAR )*( len+1 ));
+ GetWindowText((HWND)lParam, logOptions.szFile, len+1 );
+ }
+ LeaveCriticalSection(&logOptions.cs);
+ break;
+ case IDC_FILENAMEBROWSE:
+ case IDC_RUNATSTARTBROWSE:
+ { TCHAR str[MAX_PATH+2];
+ OPENFILENAME ofn={0};
+ TCHAR filter[512],*pfilter;
+
+ GetWindowText(GetWindow((HWND)lParam,GW_HWNDPREV),str,SIZEOF(str));
+ ofn.lStructSize=OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner=hwndDlg;
+ ofn.Flags=OFN_HIDEREADONLY;
+ if (LOWORD(wParam)==IDC_FILENAMEBROWSE) {
+ ofn.lpstrTitle=TranslateT("Select where log file will be created");
+ } else {
+ ofn.Flags|=OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST;
+ ofn.lpstrTitle=TranslateT("Select program to be run");
+ }
+ _tcscpy(filter,TranslateT("All Files"));
+ _tcscat(filter,_T(" (*)"));
+ pfilter=filter+lstrlen(filter)+1;
+ _tcscpy(pfilter,_T("*"));
+ pfilter=pfilter+lstrlen(pfilter)+1;
+ *pfilter='\0';
+ ofn.lpstrFilter=filter;
+ ofn.lpstrFile=str;
+ ofn.nMaxFile=SIZEOF(str)-2;
+ ofn.nMaxFileTitle=MAX_PATH;
+ if (LOWORD(wParam)==IDC_FILENAMEBROWSE) {
+ if(!GetSaveFileName(&ofn)) return 1;
+ } else {
+ if(!GetOpenFileName(&ofn)) return 1;
+ }
+ if(LOWORD(wParam)==IDC_RUNATSTARTBROWSE && _tcschr(str,' ')!=NULL) {
+ MoveMemory(str+1,str,SIZEOF(str)-2);
+ str[0]='"';
+ lstrcat(str,_T("\""));
+ }
+ SetWindowText(GetWindow((HWND)lParam,GW_HWNDPREV),str);
+ break;
+ }
+ case IDC_SHOWTHISDLGATSTART:
+ DBWriteContactSettingByte(NULL,"Netlib","ShowLogOptsAtStart",(BYTE)IsDlgButtonChecked(hwndDlg,LOWORD(wParam)));
+ break;
+ case IDC_RUNATSTART:
+ if(HIWORD(wParam)!=EN_CHANGE) break;
+ { int len;
+ char *str;
+ len=GetWindowTextLength((HWND)lParam);
+ str=(char*)mir_alloc(len+1);
+ GetWindowTextA((HWND)lParam,str,len+1);
+ DBWriteContactSettingString(NULL,"Netlib","RunAtStart",str);
+ mir_free(str);
+ }
+ break;
+ case IDC_RUNNOW:
+ { int len;
+ char *str;
+ STARTUPINFOA si={0};
+ PROCESS_INFORMATION pi;
+ len=GetWindowTextLength(GetDlgItem(hwndDlg,IDC_RUNATSTART));
+ str=(char*)mir_alloc(len+1);
+ GetDlgItemTextA(hwndDlg,IDC_RUNATSTART,str,len+1);
+ si.cb=sizeof(si);
+ if(str[0]) CreateProcessA(NULL,str,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
+ }
+ break;
+ case IDC_SAVE:
+ DBWriteContactSettingByte(NULL,"Netlib","DumpRecv",(BYTE)logOptions.dumpRecv);
+ DBWriteContactSettingByte(NULL,"Netlib","DumpSent",(BYTE)logOptions.dumpSent);
+ DBWriteContactSettingByte(NULL,"Netlib","DumpProxy",(BYTE)logOptions.dumpProxy);
+ DBWriteContactSettingByte(NULL,"Netlib","TextDumps",(BYTE)logOptions.textDumps);
+ DBWriteContactSettingByte(NULL,"Netlib","AutoDetectText",(BYTE)logOptions.autoDetectText);
+ DBWriteContactSettingByte(NULL,"Netlib","TimeFormat",(BYTE)logOptions.timeFormat);
+ DBWriteContactSettingByte(NULL,"Netlib","ShowUser",(BYTE)logOptions.showUser);
+ DBWriteContactSettingByte(NULL,"Netlib","ToOutputDebugString",(BYTE)logOptions.toOutputDebugString);
+ DBWriteContactSettingByte(NULL,"Netlib","ToFile",(BYTE)logOptions.toFile);
+ DBWriteContactSettingTString(NULL,"Netlib","File", logOptions.szFile ? logOptions.szFile: _T(""));
+ break;
+ case IDOK:
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ DestroyWindow(hwndDlg);
+ break;
+ case WM_DESTROY:
+ logOptions.hwndOpts=NULL;
+ break;
+ }
+ return FALSE;
+}
+
+void NetlibLogShowOptions(void)
+{
+ if(logOptions.hwndOpts==NULL)
+ logOptions.hwndOpts=CreateDialog(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_NETLIBLOGOPTS),NULL,LogOptionsDlgProc);
+ SetForegroundWindow(logOptions.hwndOpts);
+}
+
+static void CreateDirectoryTree( TCHAR* szDir)
+{
+ DWORD dwAttributes;
+ TCHAR* pszLastBackslash,szTestDir[MAX_PATH];
+
+ lstrcpyn(szTestDir, szDir, SIZEOF(szTestDir));
+ if ((dwAttributes = GetFileAttributes(szTestDir))!=0xffffffff && dwAttributes&FILE_ATTRIBUTE_DIRECTORY) return;
+ pszLastBackslash = _tcsrchr( szTestDir, '\\' );
+ if ( pszLastBackslash == NULL ) return;
+ *pszLastBackslash = '\0';
+ CreateDirectoryTree( szTestDir );
+ CreateDirectory( szTestDir, NULL );
+}
+
+static int NetlibLog(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibUser *nlu=(struct NetlibUser*)wParam;
+ struct NetlibUser nludummy;
+ const char *pszMsg=(const char*)lParam;
+ char *szLine;
+ char szTime[32];
+ LARGE_INTEGER liTimeNow;
+ DWORD dwOriginalLastError;
+
+ if( (nlu != NULL && GetNetlibHandleType(nlu)!=NLH_USER) || pszMsg==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ if (nlu==NULL) { /* if the Netlib user handle is NULL, just pretend its not */
+ nlu=&nludummy;
+ nlu->user.szSettingsModule="(NULL)";
+ }
+ dwOriginalLastError=GetLastError();
+ QueryPerformanceCounter(&liTimeNow);
+ liTimeNow.QuadPart-=mirandaStartTime;
+ switch(logOptions.timeFormat) {
+ case TIMEFORMAT_HHMMSS:
+ GetTimeFormatA(LOCALE_USER_DEFAULT,TIME_FORCE24HOURFORMAT|TIME_NOTIMEMARKER,NULL,NULL,szTime,SIZEOF(szTime)-1);
+ break;
+ case TIMEFORMAT_MILLISECONDS:
+ mir_snprintf(szTime,SIZEOF(szTime)-1,"%I64u.%03I64u",liTimeNow.QuadPart/perfCounterFreq,1000*(liTimeNow.QuadPart%perfCounterFreq)/perfCounterFreq);
+ break;
+ case TIMEFORMAT_MICROSECONDS:
+ mir_snprintf(szTime,SIZEOF(szTime)-1,"%I64u.%06I64u",liTimeNow.QuadPart/perfCounterFreq,1000000*(liTimeNow.QuadPart%perfCounterFreq)/perfCounterFreq);
+ break;
+ default:
+ szTime[0]='\0';
+ break;
+ }
+ EnterCriticalSection(&logOptions.cs);
+ if(logOptions.showUser) lstrcatA(szTime," ");
+ szLine=(char*)alloca(lstrlenA(pszMsg)+lstrlenA(nlu->user.szSettingsModule)+5+lstrlenA(szTime));
+ if(logOptions.timeFormat || logOptions.showUser)
+ sprintf(szLine,"[%s%s] %s\n",szTime,logOptions.showUser?nlu->user.szSettingsModule:"",pszMsg);
+ else
+ sprintf(szLine,"%s\n",pszMsg);
+ if(logOptions.toOutputDebugString) OutputDebugStringA(szLine);
+ if(logOptions.toFile && logOptions.szFile[0]) {
+ FILE *fp;
+ fp = _tfopen(logOptions.szFile, _T("at"));
+ if(!fp) {
+ CreateDirectoryTree(logOptions.szFile);
+ fp = _tfopen(logOptions.szFile, _T("at"));
+ }
+ if(fp) {
+ fputs(szLine,fp);
+ fclose(fp);
+ }
+ }
+ LeaveCriticalSection(&logOptions.cs);
+ SetLastError(dwOriginalLastError);
+ return 1;
+}
+
+void NetlibDumpData(struct NetlibConnection *nlc,PBYTE buf,int len,int sent,int flags)
+{
+ int isText=1;
+ char szTitleLine[128];
+ char *szBuf;
+ int titleLineLen;
+ struct NetlibUser *nlu;
+
+ // This section checks a number of conditions and aborts
+ // the dump if the data should not be written to the log
+
+ // Check packet flags
+ if ((flags&MSG_PEEK) || (flags&MSG_NODUMP))
+ return;
+
+ // Check user's log settings
+ if (!(logOptions.toOutputDebugString ||
+ (logOptions.toFile && logOptions.szFile[0])))
+ return;
+ if ((sent && !logOptions.dumpSent) ||
+ (!sent && !logOptions.dumpRecv))
+ return;
+ if ((flags&MSG_DUMPPROXY) && !logOptions.dumpProxy)
+ return;
+
+
+ if (!logOptions.textDumps)
+ isText = 0;
+ else if (!(flags&MSG_DUMPASTEXT)) {
+ if (logOptions.autoDetectText) {
+ int i;
+ for(i = 0; i<len; i++)
+ if ((buf[i]<' ' && buf[i]!='\t' && buf[i]!='\r' && buf[i]!='\n') || buf[i]>=0x80)
+ {
+ isText = 0;
+ break;
+ }
+ }
+ else
+ isText = 0;
+ }
+
+ WaitForSingleObject(hConnectionHeaderMutex, INFINITE);
+ nlu = nlc ? nlc->nlu : NULL;
+ titleLineLen = mir_snprintf(szTitleLine,SIZEOF(szTitleLine), "(%p:%u) Data %s%s\n", nlc, nlc?nlc->s:0, sent?"sent":"received", flags & MSG_DUMPPROXY?" (proxy)":"");
+ ReleaseMutex(hConnectionHeaderMutex);
+
+ // Text data
+ if (isText)
+ {
+ szBuf = (char*)alloca(titleLineLen + len + 1);
+ CopyMemory(szBuf, szTitleLine, titleLineLen);
+ CopyMemory(szBuf + titleLineLen, (const char*)buf, len);
+ szBuf[titleLineLen + len] = '\0';
+ }
+ // Binary data
+ else
+ {
+ int line, col, colsInLine;
+ char *pszBuf;
+
+ szBuf = (char*)alloca(titleLineLen + ((len+16)>>4) * 76 + 1);
+ CopyMemory(szBuf, szTitleLine, titleLineLen);
+ pszBuf = szBuf + titleLineLen;
+ for (line = 0; ; line += 16)
+ {
+ colsInLine = min(16, len - line);
+ pszBuf += wsprintfA(pszBuf, "%08X: ", line);
+ // Dump data as hex
+ for (col = 0; col < colsInLine; col++)
+ pszBuf += wsprintfA(pszBuf, "%02X%c", buf[line + col], ((col&3)==3 && col != 15)?'-':' ');
+ // Fill out last line with blanks
+ for ( ; col<16; col++)
+ {
+ lstrcpyA(pszBuf, " ");
+ pszBuf += 3;
+ }
+ *pszBuf++ = ' ';
+ for (col = 0; col < colsInLine; col++)
+ *pszBuf++ = buf[line+col]<' '?'.':(char)buf[line+col];
+ if (len-line<=16)
+ break;
+ *pszBuf++ = '\n'; // End each line with a break
+ }
+ *pszBuf = '\0';
+ }
+
+ NetlibLog((WPARAM)nlu,(LPARAM)szBuf);
+
+}
+
+void NetlibLogInit(void)
+{
+ DBVARIANT dbv;
+ LARGE_INTEGER li;
+
+ CreateServiceFunction(MS_NETLIB_LOG,NetlibLog);
+ QueryPerformanceFrequency(&li);
+ perfCounterFreq=li.QuadPart;
+ QueryPerformanceCounter(&li);
+ mirandaStartTime=li.QuadPart;
+ InitializeCriticalSection(&logOptions.cs);
+ logOptions.dumpRecv=DBGetContactSettingByte(NULL,"Netlib","DumpRecv",1);
+ logOptions.dumpSent=DBGetContactSettingByte(NULL,"Netlib","DumpSent",1);
+ logOptions.dumpProxy=DBGetContactSettingByte(NULL,"Netlib","DumpProxy",0);
+ logOptions.textDumps=DBGetContactSettingByte(NULL,"Netlib","TextDumps",1);
+ logOptions.autoDetectText=DBGetContactSettingByte(NULL,"Netlib","AutoDetectText",1);
+ logOptions.timeFormat=DBGetContactSettingByte(NULL,"Netlib","TimeFormat",TIMEFORMAT_HHMMSS);
+ logOptions.showUser=DBGetContactSettingByte(NULL,"Netlib","ShowUser",1);
+ logOptions.toOutputDebugString=DBGetContactSettingByte(NULL,"Netlib","ToOutputDebugString",0);
+ logOptions.toFile=DBGetContactSettingByte(NULL,"Netlib","ToFile",0);
+
+ if(!DBGetContactSettingTString(NULL, "Netlib", "File", &dbv)) {
+ logOptions.szFile = mir_tstrdup(dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ }
+ if(logOptions.toFile && logOptions.szFile[0]) {
+ FILE *fp;
+ fp = _tfopen(logOptions.szFile, _T("wt"));
+ if(fp) fclose(fp);
+ }
+ if(DBGetContactSettingByte(NULL,"Netlib","ShowLogOptsAtStart",0))
+ NetlibLogShowOptions();
+ if(!DBGetContactSetting(NULL,"Netlib","RunAtStart",&dbv)) {
+ STARTUPINFOA si={0};
+ PROCESS_INFORMATION pi;
+ si.cb=sizeof(si);
+ if(dbv.pszVal[0]) CreateProcessA(NULL,dbv.pszVal,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
+ DBFreeVariant(&dbv);
+ }
+}
+
+void NetlibLogShutdown(void)
+{
+ if(IsWindow(logOptions.hwndOpts)) DestroyWindow(logOptions.hwndOpts);
+ DeleteCriticalSection(&logOptions.cs);
+ if(logOptions.szFile) mir_free(logOptions.szFile);
+}
+
diff --git a/miranda-wine/src/modules/netlib/netlibopenconn.c b/miranda-wine/src/modules/netlib/netlibopenconn.c
new file mode 100644
index 0000000..6d19e1c
--- /dev/null
+++ b/miranda-wine/src/modules/netlib/netlibopenconn.c
@@ -0,0 +1,569 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "netlib.h"
+
+extern CRITICAL_SECTION csNetlibUser;
+extern DWORD g_LastConnectionTick; // protected by csNetlibUser
+
+//returns in network byte order
+DWORD DnsLookup(struct NetlibUser *nlu,const char *szHost)
+{
+ DWORD ip;
+ HOSTENT *host;
+
+ ip=inet_addr(szHost);
+ if(ip!=INADDR_NONE) return ip;
+ host=gethostbyname(szHost);
+ if(host) return *(u_long *)host->h_addr_list[0];
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"gethostbyname",WSAGetLastError());
+ return 0;
+}
+
+int WaitUntilReadable(SOCKET s,DWORD dwTimeout)
+{
+ fd_set readfd;
+ TIMEVAL tv;
+
+ tv.tv_sec=dwTimeout/1000;
+ tv.tv_usec=(dwTimeout%1000)*1000;
+ FD_ZERO(&readfd);
+ FD_SET(s,&readfd);
+ switch(select(0,&readfd,0,0,&tv)) {
+ case 0:
+ SetLastError(ERROR_TIMEOUT);
+ case SOCKET_ERROR:
+ return 0;
+ }
+ return 1;
+}
+
+static int WaitUntilWritable(SOCKET s,DWORD dwTimeout)
+{
+ fd_set writefd;
+ TIMEVAL tv;
+
+ tv.tv_sec=dwTimeout/1000;
+ tv.tv_usec=(dwTimeout%1000)*1000;
+ FD_ZERO(&writefd);
+ FD_SET(s,&writefd);
+ switch(select(0,0,&writefd,0,&tv)) {
+ case 0:
+ SetLastError(ERROR_TIMEOUT);
+ case SOCKET_ERROR:
+ return 0;
+ }
+ return 1;
+}
+
+static int NetlibInitSocks4Connection(struct NetlibConnection *nlc,struct NetlibUser *nlu,NETLIBOPENCONNECTION *nloc)
+{ //http://www.socks.nec.com/protocol/socks4.protocol and http://www.socks.nec.com/protocol/socks4a.protocol
+ PBYTE pInit;
+ int nUserLen,nHostLen,len;
+ BYTE reply[8];
+
+ nUserLen=lstrlenA(nlu->settings.szProxyAuthUser);
+ nHostLen=lstrlenA(nloc->szHost);
+ pInit=(PBYTE)mir_alloc(10+nUserLen+nHostLen);
+ pInit[0]=4; //SOCKS4
+ pInit[1]=1; //connect
+ *(PWORD)(pInit+2)=htons(nloc->wPort);
+ if(nlu->settings.szProxyAuthUser==NULL) pInit[8]=0;
+ else lstrcpyA(pInit+8,nlu->settings.szProxyAuthUser);
+ if(nlu->settings.dnsThroughProxy) {
+ if((*(PDWORD)(pInit+4)=inet_addr(nloc->szHost))==INADDR_NONE) {
+ *(PDWORD)(pInit+4)=0x01000000;
+ lstrcpyA(pInit+9+nUserLen,nloc->szHost);
+ len=10+nUserLen+nHostLen;
+ }
+ else len=9+nUserLen;
+ }
+ else {
+ *(PDWORD)(pInit+4)=DnsLookup(nlu,nloc->szHost);
+ if(*(PDWORD)(pInit+4)==0) {
+ mir_free(pInit);
+ return 0;
+ }
+ len=9+nUserLen;
+ }
+ if(NLSend(nlc,pInit,len,MSG_DUMPPROXY)==SOCKET_ERROR) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLSend",GetLastError());
+ mir_free(pInit);
+ return 0;
+ }
+ mir_free(pInit);
+
+ if(!WaitUntilReadable(nlc->s,30000)) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"WaitUntilReadable",GetLastError());
+ return 0;
+ }
+
+ len=NLRecv(nlc,reply,SIZEOF(reply),MSG_DUMPPROXY);
+ if(len < sizeof(reply) || reply[1]!=90) {
+ if(len != SOCKET_ERROR) {
+ if (len < SIZEOF(reply)) SetLastError(ERROR_BAD_FORMAT);
+ else switch(reply[1]) {
+ case 91: SetLastError(ERROR_ACCESS_DENIED); break;
+ case 92: SetLastError(ERROR_CONNECTION_UNAVAIL); break;
+ case 93: SetLastError(ERROR_INVALID_ACCESS); break;
+ default: SetLastError(ERROR_INVALID_DATA); break;
+ }
+ }
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLRecv",GetLastError());
+ return 0;
+ }
+ //connected
+ return 1;
+}
+
+static int NetlibInitSocks5Connection(struct NetlibConnection *nlc,struct NetlibUser *nlu,NETLIBOPENCONNECTION *nloc)
+{ //rfc1928
+ int len;
+ BYTE buf[256];
+
+ buf[0]=5; //yep, socks5
+ buf[1]=1; //one auth method
+ buf[2]=nlu->settings.useProxyAuth?2:0;
+ if(NLSend(nlc,buf,3,MSG_DUMPPROXY)==SOCKET_ERROR) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLSend",GetLastError());
+ return 0;
+ }
+
+ if(!WaitUntilReadable(nlc->s,10000)) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"WaitUntilReadable",GetLastError());
+ return 0;
+ }
+
+ len=NLRecv(nlc,buf,2,MSG_DUMPPROXY); //confirmation of auth method
+ if(len<2 || (buf[1]!=0 && buf[1]!=2)) {
+ if(len!=SOCKET_ERROR) {
+ if(len<2) SetLastError(ERROR_BAD_FORMAT);
+ else SetLastError(ERROR_INVALID_ID_AUTHORITY);
+ }
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLRecv",GetLastError());
+ return 0;
+ }
+
+ if(buf[1]==2) { //rfc1929
+ int nUserLen,nPassLen;
+ PBYTE pAuthBuf;
+
+ nUserLen=lstrlenA(nlu->settings.szProxyAuthUser);
+ nPassLen=lstrlenA(nlu->settings.szProxyAuthPassword);
+ pAuthBuf=(PBYTE)mir_alloc(3+nUserLen+nPassLen);
+ pAuthBuf[0]=1; //auth version
+ pAuthBuf[1]=nUserLen;
+ memcpy(pAuthBuf+2,nlu->settings.szProxyAuthUser,nUserLen);
+ pAuthBuf[2+nUserLen]=nPassLen;
+ memcpy(pAuthBuf+3+nUserLen,nlu->settings.szProxyAuthPassword,nPassLen);
+ if(NLSend(nlc,pAuthBuf,3+nUserLen+nPassLen,MSG_DUMPPROXY)==SOCKET_ERROR) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLSend",GetLastError());
+ mir_free(pAuthBuf);
+ return 0;
+ }
+ mir_free(pAuthBuf);
+
+ if(!WaitUntilReadable(nlc->s,10000)) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"WaitUntilReadable",GetLastError());
+ return 0;
+ }
+
+ len=NLRecv(nlc,buf,SIZEOF(buf),MSG_DUMPPROXY);
+ if(len<2 || buf[1]) {
+ if(len!=SOCKET_ERROR) {
+ if(len<2) SetLastError(ERROR_BAD_FORMAT);
+ else SetLastError(ERROR_ACCESS_DENIED);
+ }
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLRecv",GetLastError());
+ return 0;
+ }
+ }
+
+ { PBYTE pInit;
+ int nHostLen;
+ DWORD hostIP;
+
+ if(nlu->settings.dnsThroughProxy) {
+ if((hostIP=inet_addr(nloc->szHost))==INADDR_NONE)
+ nHostLen=lstrlenA(nloc->szHost)+1;
+ else nHostLen=4;
+ }
+ else {
+ if((hostIP=DnsLookup(nlu,nloc->szHost))==0)
+ return 0;
+ nHostLen=4;
+ }
+ pInit=(PBYTE)mir_alloc(6+nHostLen);
+ pInit[0]=5; //SOCKS5
+ pInit[1]=1; //connect
+ pInit[2]=0; //reserved
+ if(hostIP==INADDR_NONE) { //DNS lookup through proxy
+ pInit[3]=3;
+ pInit[4]=nHostLen-1;
+ memcpy(pInit+5,nloc->szHost,nHostLen-1);
+ }
+ else {
+ pInit[3]=1;
+ *(PDWORD)(pInit+4)=hostIP;
+ }
+ *(PWORD)(pInit+4+nHostLen)=htons(nloc->wPort);
+ if(NLSend(nlc,pInit,6+nHostLen,MSG_DUMPPROXY)==SOCKET_ERROR) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLSend",GetLastError());
+ mir_free(pInit);
+ return 0;
+ }
+ mir_free(pInit);
+ }
+
+ if(!WaitUntilReadable(nlc->s,30000)) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"WaitUntilReadable",GetLastError());
+ return 0;
+ }
+
+ len=NLRecv(nlc,buf,SIZEOF(buf),MSG_DUMPPROXY);
+ if(len<7 || buf[0]!=5 || buf[1]) {
+ if(len!=SOCKET_ERROR) {
+ if(len<7 || buf[0]!=5) SetLastError(ERROR_BAD_FORMAT);
+ else switch(buf[1]) {
+ case 1: SetLastError(ERROR_GEN_FAILURE); break;
+ case 2: SetLastError(ERROR_ACCESS_DENIED); break;
+ case 3: SetLastError(WSAENETUNREACH); break;
+ case 4: SetLastError(WSAEHOSTUNREACH); break;
+ case 5: SetLastError(WSAECONNREFUSED); break;
+ case 6: SetLastError(WSAETIMEDOUT); break;
+ case 7: SetLastError(ERROR_CALL_NOT_IMPLEMENTED); break;
+ case 8: SetLastError(ERROR_INVALID_ADDRESS); break;
+ default: SetLastError(ERROR_INVALID_DATA); break;
+ }
+ }
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLRecv",GetLastError());
+ return 0;
+ }
+ //connected
+ return 1;
+}
+
+static int NetlibInitHttpsConnection(struct NetlibConnection *nlc,struct NetlibUser *nlu,NETLIBOPENCONNECTION *nloc)
+{ //rfc2817
+ NETLIBHTTPHEADER httpHeaders[3];
+ NETLIBHTTPREQUEST nlhrSend={0},*nlhrReply;
+ char szUrl[512];
+
+ memset(httpHeaders,0,sizeof(httpHeaders));
+
+ nlhrSend.cbSize=sizeof(nlhrSend);
+ nlhrSend.requestType=REQUEST_CONNECT;
+ nlhrSend.flags=NLHRF_DUMPPROXY|NLHRF_SMARTAUTHHEADER|NLHRF_HTTP11;
+ if(nlu->settings.dnsThroughProxy) {
+ mir_snprintf(szUrl,SIZEOF(szUrl),"%s:%u",nloc->szHost,nloc->wPort);
+ if(inet_addr(nloc->szHost)==INADDR_NONE) {
+ httpHeaders[0].szName="Host";
+ httpHeaders[0].szValue=szUrl;
+ nlhrSend.headersCount++;
+ }
+ }
+ else {
+ struct in_addr addr;
+ DWORD ip=DnsLookup(nlu,nloc->szHost);
+ if(ip==0) return 0;
+ addr.S_un.S_addr=ip;
+ mir_snprintf(szUrl,SIZEOF(szUrl),"%s:%u",inet_ntoa(addr),nloc->wPort);
+ }
+ nlhrSend.szUrl=szUrl;
+ nlhrSend.headers=httpHeaders;
+ nlhrSend.headersCount=0;
+ if(NetlibHttpSendRequest((WPARAM)nlc,(LPARAM)&nlhrSend)==SOCKET_ERROR)
+ return 0;
+ nlhrReply=(NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc,MSG_DUMPPROXY);
+ if(nlhrReply==NULL) return 0;
+ if(nlhrReply->resultCode<200 || nlhrReply->resultCode>=300) {
+ NetlibHttpSetLastErrorUsingHttpResult(nlhrReply->resultCode);
+ Netlib_Logf(nlu,"%s %d: %s request failed (%u %s)",__FILE__,__LINE__,nlu->settings.proxyType==PROXYTYPE_HTTP?"HTTP":"HTTPS",nlhrReply->resultCode,nlhrReply->szResultDescr);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ return 0;
+ }
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ //connected
+ return 1;
+}
+
+static void FreePartiallyInitedConnection(struct NetlibConnection *nlc)
+{
+ DWORD dwOriginalLastError=GetLastError();
+
+ if(nlc->s!=INVALID_SOCKET) closesocket(nlc->s);
+ if(nlc->nlhpi.szHttpPostUrl) mir_free(nlc->nlhpi.szHttpPostUrl);
+ if(nlc->nlhpi.szHttpGetUrl) mir_free(nlc->nlhpi.szHttpGetUrl);
+ if(nlc->hInstSecurityDll) FreeLibrary(nlc->hInstSecurityDll);
+ NetlibDeleteNestedCS(&nlc->ncsSend);
+ NetlibDeleteNestedCS(&nlc->ncsRecv);
+ CloseHandle(nlc->hOkToCloseEvent);
+ DeleteCriticalSection(&nlc->csHttpSequenceNums);
+ mir_free(nlc);
+ SetLastError(dwOriginalLastError);
+}
+
+#define PortInMask(mask,p) ((mask)[((p)&0xFFFF)>>3]&(1<<((p)&7)))
+
+static int my_connect(SOCKET s, const struct sockaddr * name, int namelen, NETLIBOPENCONNECTION * nloc)
+{
+ int rc=0;
+ unsigned int dwTimeout=( nloc->cbSize==sizeof(NETLIBOPENCONNECTION) && nloc->flags&NLOCF_V2 ) ? nloc->timeout : 0;
+ u_long notblocking=1;
+ TIMEVAL tv;
+ DWORD lasterr = 0;
+ int waitdiff;
+ // if dwTimeout is zero then its an old style connection or new with a 0 timeout, select() will error quicker anyway
+ if ( dwTimeout == 0 )
+ dwTimeout += 60;
+ // return the socket to non blocking
+ if ( ioctlsocket(s, FIONBIO, &notblocking) != 0 ) {
+ return SOCKET_ERROR;
+ }
+ // this is for XP SP2 where there is a default connection attempt limit of 10/second
+ EnterCriticalSection(&csNetlibUser);
+ waitdiff=GetTickCount() - g_LastConnectionTick;
+ g_LastConnectionTick=GetTickCount();
+ LeaveCriticalSection(&csNetlibUser);
+ if ( waitdiff < 1000 ) {
+ // last connection was less than 1 second ago, wait 1.2 seconds
+ SleepEx(1200,TRUE);
+ }
+ // might of died in between the wait
+ if ( Miranda_Terminated() ) {
+ rc=SOCKET_ERROR;
+ lasterr=ERROR_TIMEOUT;
+ goto unblock;
+ }
+ // try a connect
+ if ( connect(s, name, namelen) == 0 ) {
+ goto unblock;
+ }
+ // didn't work, was it cos of nonblocking?
+ if ( WSAGetLastError() != WSAEWOULDBLOCK ) {
+ rc=SOCKET_ERROR;
+ lasterr=WSAGetLastError();
+ goto unblock;
+ }
+ // setup select()
+ tv.tv_sec=1;
+ tv.tv_usec=0;
+ for (;;) {
+ fd_set r, w, e;
+ FD_ZERO(&r); FD_ZERO(&w); FD_ZERO(&e);
+ FD_SET(s, &r);
+ FD_SET(s, &w);
+ FD_SET(s, &e);
+ if ( (rc=select(0, &r, &w, &e, &tv)) == SOCKET_ERROR ) {
+ break;
+ }
+ if ( rc > 0 ) {
+ if ( FD_ISSET(s, &r) ) {
+ // connection was closed
+ rc=SOCKET_ERROR;
+ lasterr=WSAECONNRESET;
+ }
+ if ( FD_ISSET(s, &w) ) {
+ // connection was successful
+ rc=0;
+ }
+ if ( FD_ISSET(s, &e) ) {
+ // connection failed.
+ int len=sizeof(lasterr);
+ rc=SOCKET_ERROR;
+ getsockopt(s,SOL_SOCKET,SO_ERROR,(char*)&lasterr,&len);
+ }
+ goto unblock;
+ } else if ( Miranda_Terminated() ) {
+ rc=SOCKET_ERROR;
+ lasterr=ERROR_TIMEOUT;
+ goto unblock;
+ } else if ( nloc->cbSize==sizeof(NETLIBOPENCONNECTION) && nloc->flags&NLOCF_V2 && nloc->waitcallback != NULL
+ && nloc->waitcallback(&dwTimeout) == 0) {
+ rc=SOCKET_ERROR;
+ lasterr=ERROR_TIMEOUT;
+ goto unblock;
+ }
+ if ( --dwTimeout == 0 ) {
+ rc=SOCKET_ERROR;
+ lasterr=ERROR_TIMEOUT;
+ goto unblock;
+ }
+ }
+unblock:
+ notblocking=0;
+ ioctlsocket(s, FIONBIO, &notblocking);
+ SetLastError(lasterr);
+ return rc;
+}
+
+int NetlibOpenConnection(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBOPENCONNECTION *nloc=(NETLIBOPENCONNECTION*)lParam;
+ struct NetlibUser *nlu=(struct NetlibUser*)wParam;
+ struct NetlibConnection *nlc;
+ SOCKADDR_IN sin;
+
+ if(GetNetlibHandleType(nlu)!=NLH_USER || !(nlu->user.flags&NUF_OUTGOING) || nloc==NULL
+ || !(nloc->cbSize==NETLIBOPENCONNECTION_V1_SIZE||nloc->cbSize==sizeof(NETLIBOPENCONNECTION)) || nloc->szHost==NULL || nloc->wPort==0) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return (int)(HANDLE)NULL;
+ }
+ nlc=(struct NetlibConnection*)mir_calloc(sizeof(struct NetlibConnection));
+ nlc->handleType=NLH_CONNECTION;
+ nlc->nlu=nlu;
+ nlc->s=socket(AF_INET,SOCK_STREAM,0);
+ if(nlc->s==INVALID_SOCKET) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"socket",WSAGetLastError());
+ mir_free(nlc);
+ return (int)(HANDLE)NULL;
+ }
+ if (nlu->settings.specifyOutgoingPorts && nlu->settings.szOutgoingPorts)
+ {
+ BYTE portsMask[0x2000];
+ int startPort,portNum,i,j,portsCount;
+
+ sin.sin_family=AF_INET;
+ sin.sin_addr.s_addr=htonl(INADDR_ANY);
+ sin.sin_port=0;
+
+ portsCount=StringToPortsMask(nlu->settings.szOutgoingPorts,portsMask);
+ if (portsCount) {
+ startPort=rand() % portsCount;
+ for (i=0;i<0x02000;i++) {
+ if(portsMask[i]==0) continue;
+ if(portsMask[i]==0xFF && startPort>=8) {startPort-=8; continue;}
+ for(j=0;j<8;j++)
+ if(portsMask[i]&(1<<j))
+ if(startPort--==0) {
+ portNum=(i<<3)+j;
+ break;
+ }
+ if(startPort==-1) break;
+ } //for
+ if (i!=0x2000) {
+ startPort=portNum;
+ do {
+ sin.sin_port=htons((WORD)portNum);
+ if(bind(nlc->s,(SOCKADDR*)&sin,sizeof(sin))==0) break;
+ for(portNum++;!PortInMask(portsMask,portNum);portNum++)
+ if(portNum==0xFFFF) portNum=0;
+ } while (portNum!=startPort);
+ } //if
+ } //if
+ }
+ InitializeCriticalSection(&nlc->csHttpSequenceNums);
+ nlc->hOkToCloseEvent=CreateEvent(NULL,TRUE,TRUE,NULL);
+ nlc->dontCloseNow=0;
+ NetlibInitializeNestedCS(&nlc->ncsSend);
+ NetlibInitializeNestedCS(&nlc->ncsRecv);
+ if(nlu->settings.useProxy && (nlu->settings.proxyType==PROXYTYPE_HTTP || nlu->settings.proxyType==PROXYTYPE_HTTPS) && nlu->settings.useProxyAuth && nlu->settings.useProxyAuthNtlm)
+ nlc->hInstSecurityDll=LoadLibraryA("security.dll");
+
+ nlc->sinProxy.sin_family=AF_INET;
+ if(nlu->settings.useProxy) {
+ nlc->sinProxy.sin_port=htons((short)nlu->settings.wProxyPort);
+ nlc->sinProxy.sin_addr.S_un.S_addr=DnsLookup(nlu,nlu->settings.szProxyServer);
+ }
+ else {
+ nlc->sinProxy.sin_port=htons((short)nloc->wPort);
+ nlc->sinProxy.sin_addr.S_un.S_addr=DnsLookup(nlu,nloc->szHost);
+ }
+ if(nlc->sinProxy.sin_addr.S_un.S_addr==0
+ || my_connect(nlc->s,(SOCKADDR *)&nlc->sinProxy,sizeof(nlc->sinProxy), nloc)==SOCKET_ERROR) {
+ if(nlc->sinProxy.sin_addr.S_un.S_addr)
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"connect",WSAGetLastError());
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+
+ if(nlu->settings.useProxy
+ && !(nloc->flags&NLOCF_HTTP
+ && (nlu->settings.proxyType==PROXYTYPE_HTTP || nlu->settings.proxyType==PROXYTYPE_HTTPS)))
+ {
+ if(!WaitUntilWritable(nlc->s,30000)) {
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+
+ switch(nlu->settings.proxyType) {
+ case PROXYTYPE_SOCKS4:
+ if(!NetlibInitSocks4Connection(nlc,nlu,nloc)) {
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+ break;
+
+ case PROXYTYPE_SOCKS5:
+ if(!NetlibInitSocks5Connection(nlc,nlu,nloc)) {
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+ break;
+
+ case PROXYTYPE_HTTPS:
+ if(!NetlibInitHttpsConnection(nlc,nlu,nloc)) {
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+ break;
+
+ case PROXYTYPE_HTTP:
+ if(!(nlu->user.flags&NUF_HTTPGATEWAY)) {
+ //NLOCF_HTTP not specified and no HTTP gateway available: try HTTPS
+ if(!NetlibInitHttpsConnection(nlc,nlu,nloc)) {
+ //can't do HTTPS: try direct
+ if(nlc->s!=INVALID_SOCKET) closesocket(nlc->s);
+
+ nlc->s=socket(AF_INET,SOCK_STREAM,0);
+ if(nlc->s==INVALID_SOCKET) {
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+ nlc->sinProxy.sin_family=AF_INET;
+ nlc->sinProxy.sin_port=htons((short)nloc->wPort);
+ nlc->sinProxy.sin_addr.S_un.S_addr=DnsLookup(nlu,nloc->szHost);
+ if(nlc->sinProxy.sin_addr.S_un.S_addr==0
+ || my_connect(nlc->s,(SOCKADDR *)&nlc->sinProxy,sizeof(nlc->sinProxy), nloc)==SOCKET_ERROR) {
+ if(nlc->sinProxy.sin_addr.S_un.S_addr)
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"connect",WSAGetLastError());
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+ }
+ }
+ else if(!NetlibInitHttpConnection(nlc,nlu,nloc)) {
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+ break;
+
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+ }
+ Netlib_Logf(nlu,"(%d) Connected to %s:%d",nlc->s,nloc->szHost,nloc->wPort);
+ return (int)nlc;
+}
diff --git a/miranda-wine/src/modules/netlib/netlibopts.c b/miranda-wine/src/modules/netlib/netlibopts.c
new file mode 100644
index 0000000..918b940
--- /dev/null
+++ b/miranda-wine/src/modules/netlib/netlibopts.c
@@ -0,0 +1,516 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "netlib.h"
+
+extern struct NetlibUser **netlibUser;
+extern int netlibUserCount;
+extern CRITICAL_SECTION csNetlibUser;
+
+struct NetlibTempSettings {
+ DWORD flags;
+ char *szSettingsModule;
+ NETLIBUSERSETTINGS settings;
+} static *tempSettings;
+static int tempSettingsCount;
+
+static const UINT outgoingConnectionsControls[]={
+ IDC_STATIC12,
+ IDC_USEPROXY,
+ IDC_STATIC21,IDC_PROXYTYPE,
+ IDC_STATIC22,IDC_PROXYHOST,IDC_STATIC23,IDC_PROXYPORT,IDC_STOFTENPORT,
+ IDC_PROXYAUTH,
+ IDC_STATIC31,IDC_PROXYUSER,IDC_STATIC32,IDC_PROXYPASS,
+ IDC_PROXYAUTHNTLM,
+ IDC_PROXYDNS,
+ IDC_SPECIFYPORTSO,
+ IDC_STATIC53,IDC_PORTSRANGEO,
+ IDC_STATIC54};
+static const UINT useProxyControls[]={
+ IDC_STATIC21,IDC_PROXYTYPE,
+ IDC_STATIC22,IDC_PROXYHOST,IDC_STATIC23,IDC_PROXYPORT,IDC_STOFTENPORT,
+ IDC_PROXYAUTH,
+ IDC_STATIC31,IDC_PROXYUSER,IDC_STATIC32,IDC_PROXYPASS,
+ IDC_PROXYAUTHNTLM,
+ IDC_PROXYDNS};
+static const UINT specifyOPortsControls[]={
+ IDC_STATIC53,IDC_PORTSRANGEO,
+ IDC_STATIC54
+};
+static const UINT incomingConnectionsControls[]={
+ IDC_STATIC43,
+ IDC_SPECIFYPORTS,
+ IDC_STATIC51,IDC_PORTSRANGE,
+ IDC_STATIC52};
+static const UINT specifyPortsControls[]={
+ IDC_STATIC51,IDC_PORTSRANGE,
+ IDC_STATIC52};
+static const TCHAR* szProxyTypes[]={_T("<mixed>"),_T("SOCKS4"),_T("SOCKS5"),_T("HTTP"),_T("HTTPS")};
+static const WORD oftenProxyPorts[]={1080,1080,1080,8080,8080};
+
+#define M_REFRESHALL (WM_USER+100)
+#define M_REFRESHENABLING (WM_USER+101)
+
+static void ShowMultipleControls(HWND hwndDlg,const UINT *controls,int cControls,int state)
+{
+ int i;
+ for(i=0;i<cControls;i++) ShowWindow(GetDlgItem(hwndDlg,controls[i]),state);
+}
+
+static void EnableMultipleControls(HWND hwndDlg,const UINT *controls,int cControls,int state)
+{
+ int i;
+ for(i=0;i<cControls;i++) EnableWindow(GetDlgItem(hwndDlg,controls[i]),state);
+}
+
+static void AddProxyTypeItem(HWND hwndDlg,int type,int selectType)
+{
+ int i;
+ i=SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_ADDSTRING,0,(LPARAM)(type==0?TranslateTS(szProxyTypes[type]):szProxyTypes[type]));
+ SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_SETITEMDATA,i,type);
+ if(type==selectType) SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_SETCURSEL,i,0);
+}
+
+static void CopySettingsStruct(NETLIBUSERSETTINGS *dest,NETLIBUSERSETTINGS *source)
+{
+ *dest=*source;
+ if(dest->szIncomingPorts) dest->szIncomingPorts=mir_strdup(dest->szIncomingPorts);
+ if(dest->szOutgoingPorts) dest->szOutgoingPorts=mir_strdup(dest->szOutgoingPorts);
+ if(dest->szProxyAuthPassword) dest->szProxyAuthPassword=mir_strdup(dest->szProxyAuthPassword);
+ if(dest->szProxyAuthUser) dest->szProxyAuthUser=mir_strdup(dest->szProxyAuthUser);
+ if(dest->szProxyServer) dest->szProxyServer=mir_strdup(dest->szProxyServer);
+}
+
+static void CombineSettingsStrings(char **dest,char **source)
+{
+ if(*dest!=NULL && (*source==NULL || lstrcmpiA(*dest,*source))) {mir_free(*dest); *dest=NULL;}
+}
+
+static void CombineSettingsStructs(NETLIBUSERSETTINGS *dest,DWORD *destFlags,NETLIBUSERSETTINGS *source,DWORD sourceFlags)
+{
+ if(sourceFlags&NUF_OUTGOING) {
+ if(*destFlags&NUF_OUTGOING) {
+ if(dest->useProxy!=source->useProxy) dest->useProxy=2;
+ if(dest->proxyType!=source->proxyType) dest->proxyType=0;
+ CombineSettingsStrings(&dest->szProxyServer,&source->szProxyServer);
+ if(dest->wProxyPort!=source->wProxyPort) dest->wProxyPort=0;
+ if(dest->useProxyAuth!=source->useProxyAuth) dest->useProxyAuth=2;
+ CombineSettingsStrings(&dest->szProxyAuthUser,&source->szProxyAuthUser);
+ CombineSettingsStrings(&dest->szProxyAuthPassword,&source->szProxyAuthPassword);
+ if(dest->useProxyAuthNtlm!=source->useProxyAuthNtlm) dest->useProxyAuthNtlm=2;
+ if(dest->dnsThroughProxy!=source->dnsThroughProxy) dest->dnsThroughProxy=2;
+ if(dest->specifyOutgoingPorts!=source->specifyOutgoingPorts) dest->specifyOutgoingPorts=2;
+ CombineSettingsStrings(&dest->szOutgoingPorts,&source->szOutgoingPorts);
+ }
+ else {
+ dest->useProxy=source->useProxy;
+ dest->proxyType=source->proxyType;
+ dest->szProxyServer=source->szProxyServer;
+ if(dest->szProxyServer) dest->szProxyServer=mir_strdup(dest->szProxyServer);
+ dest->wProxyPort=source->wProxyPort;
+ dest->useProxyAuth=source->useProxyAuth;
+ dest->szProxyAuthUser=source->szProxyAuthUser;
+ if(dest->szProxyAuthUser) dest->szProxyAuthUser=mir_strdup(dest->szProxyAuthUser);
+ dest->szProxyAuthPassword=source->szProxyAuthPassword;
+ if(dest->szProxyAuthPassword) dest->szProxyAuthPassword=mir_strdup(dest->szProxyAuthPassword);
+ dest->useProxyAuthNtlm=source->useProxyAuthNtlm;
+ dest->dnsThroughProxy=source->dnsThroughProxy;
+ dest->specifyOutgoingPorts=source->specifyOutgoingPorts;
+ dest->szOutgoingPorts=source->szOutgoingPorts;
+ if(dest->szOutgoingPorts) dest->szOutgoingPorts=mir_strdup(dest->szOutgoingPorts);
+ }
+ }
+ if(sourceFlags&NUF_INCOMING) {
+ if(*destFlags&NUF_INCOMING) {
+ if(dest->specifyIncomingPorts!=source->specifyIncomingPorts) dest->specifyIncomingPorts=2;
+ CombineSettingsStrings(&dest->szIncomingPorts,&source->szIncomingPorts);
+ }
+ else {
+ dest->specifyIncomingPorts=source->specifyIncomingPorts;
+ dest->szIncomingPorts=source->szIncomingPorts;
+ if(dest->szIncomingPorts) dest->szIncomingPorts=mir_strdup(dest->szIncomingPorts);
+ }
+ }
+ if((*destFlags&NUF_NOHTTPSOPTION)!=(sourceFlags&NUF_NOHTTPSOPTION))
+ *destFlags=(*destFlags|sourceFlags)&~NUF_NOHTTPSOPTION;
+ else *destFlags|=sourceFlags;
+}
+
+static void ChangeSettingIntByCheckbox(HWND hwndDlg,UINT ctrlId,int iUser,int memberOffset)
+{
+ int newValue,i;
+
+ newValue=IsDlgButtonChecked(hwndDlg,ctrlId)!=BST_CHECKED;
+ CheckDlgButton(hwndDlg,ctrlId,newValue?BST_CHECKED:BST_UNCHECKED);
+ if(iUser==-1) {
+ for(i=0;i<tempSettingsCount;i++)
+ if(!(tempSettings[i].flags&NUF_NOOPTIONS))
+ *(int*)(((PBYTE)&tempSettings[i].settings)+memberOffset)=newValue;
+ }
+ else *(int*)(((PBYTE)&tempSettings[iUser].settings)+memberOffset)=newValue;
+ SendMessage(hwndDlg,M_REFRESHENABLING,0,0);
+}
+
+static void ChangeSettingStringByEdit(HWND hwndDlg,UINT ctrlId,int iUser,int memberOffset)
+{
+ int i,newValueLen;
+ char *szNewValue,**ppszNew;
+
+ newValueLen=GetWindowTextLength(GetDlgItem(hwndDlg,ctrlId));
+ szNewValue=(char*)mir_alloc(newValueLen+1);
+ GetDlgItemTextA(hwndDlg,ctrlId,szNewValue,newValueLen+1);
+ if(iUser==-1) {
+ for(i=0;i<tempSettingsCount;i++)
+ if(!(tempSettings[i].flags&NUF_NOOPTIONS)) {
+ ppszNew=(char**)(((PBYTE)&tempSettings[i].settings)+memberOffset);
+ if(*ppszNew) mir_free(*ppszNew);
+ *ppszNew=mir_strdup(szNewValue);
+ }
+ mir_free(szNewValue);
+ }
+ else {
+ ppszNew=(char**)(((PBYTE)&tempSettings[iUser].settings)+memberOffset);
+ if(*ppszNew) mir_free(*ppszNew);
+ *ppszNew=szNewValue;
+ }
+}
+
+static void WriteSettingsStructToDb(const char *szSettingsModule,NETLIBUSERSETTINGS *settings,DWORD flags)
+{
+ if(flags&NUF_OUTGOING) {
+ char szEncodedPassword[512];
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLUseProxy",(BYTE)settings->useProxy);
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLProxyType",(BYTE)settings->proxyType);
+ DBWriteContactSettingString(NULL,szSettingsModule,"NLProxyServer",settings->szProxyServer?settings->szProxyServer:"");
+ DBWriteContactSettingWord(NULL,szSettingsModule,"NLProxyPort",(WORD)settings->wProxyPort);
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLUseProxyAuth",(BYTE)settings->useProxyAuth);
+ DBWriteContactSettingString(NULL,szSettingsModule,"NLProxyAuthUser",settings->szProxyAuthUser?settings->szProxyAuthUser:"");
+ lstrcpynA(szEncodedPassword,settings->szProxyAuthPassword?settings->szProxyAuthPassword:"",SIZEOF(szEncodedPassword));
+ CallService(MS_DB_CRYPT_ENCODESTRING,SIZEOF(szEncodedPassword),(LPARAM)szEncodedPassword);
+ DBWriteContactSettingString(NULL,szSettingsModule,"NLProxyAuthPassword",szEncodedPassword);
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLUseProxyAuthNtlm",(BYTE)settings->useProxyAuthNtlm);
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLDnsThroughProxy",(BYTE)settings->dnsThroughProxy);
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLSpecifyOutgoingPorts",(BYTE)settings->specifyOutgoingPorts);
+ DBWriteContactSettingString(NULL,szSettingsModule,"NLOutgoingPorts",settings->szOutgoingPorts?settings->szOutgoingPorts:"");
+ }
+ if(flags&NUF_INCOMING) {
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLSpecifyIncomingPorts",(BYTE)settings->specifyIncomingPorts);
+ DBWriteContactSettingString(NULL,szSettingsModule,"NLIncomingPorts",settings->szIncomingPorts?settings->szIncomingPorts:"");
+ }
+}
+
+void NetlibSaveUserSettingsStruct(const char *szSettingsModule,NETLIBUSERSETTINGS *settings)
+{
+ int iUser,i;
+ NETLIBUSERSETTINGS combinedSettings={0};
+ DWORD flags;
+
+ EnterCriticalSection(&csNetlibUser);
+ for(iUser=0;iUser<netlibUserCount;iUser++)
+ if(!lstrcmpA(szSettingsModule,netlibUser[iUser]->user.szSettingsModule)) break;
+ if(iUser==netlibUserCount) {
+ LeaveCriticalSection(&csNetlibUser);
+ return;
+ }
+ NetlibFreeUserSettingsStruct(&netlibUser[iUser]->settings);
+ CopySettingsStruct(&netlibUser[iUser]->settings,settings);
+ WriteSettingsStructToDb(netlibUser[iUser]->user.szSettingsModule,&netlibUser[iUser]->settings,netlibUser[iUser]->user.flags);
+ combinedSettings.cbSize=sizeof(combinedSettings);
+ for(i=0,flags=0;i<netlibUserCount;i++) {
+ if(netlibUser[iUser]->user.flags&NUF_NOOPTIONS) continue;
+ CombineSettingsStructs(&combinedSettings,&flags,&netlibUser[iUser]->settings,netlibUser[iUser]->user.flags);
+ }
+ if(combinedSettings.useProxy==2) combinedSettings.useProxy=0;
+ if(combinedSettings.proxyType==0) combinedSettings.proxyType=PROXYTYPE_SOCKS5;
+ if(combinedSettings.useProxyAuth==2) combinedSettings.useProxyAuth=0;
+ if(combinedSettings.useProxyAuthNtlm==2) combinedSettings.useProxyAuthNtlm=0;
+ if(combinedSettings.dnsThroughProxy==2) combinedSettings.dnsThroughProxy=1;
+ if(combinedSettings.specifyIncomingPorts==2) combinedSettings.specifyIncomingPorts=0;
+ WriteSettingsStructToDb("Netlib",&combinedSettings,flags);
+ NetlibFreeUserSettingsStruct(&combinedSettings);
+ LeaveCriticalSection(&csNetlibUser);
+}
+
+static BOOL CALLBACK DlgProcNetlibOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ { int iUser,iItem;
+
+ TranslateDialogDefault(hwndDlg);
+ iItem=SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_ADDSTRING,0,(LPARAM)TranslateT("<All connections>"));
+ SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_SETITEMDATA,iItem,(LPARAM)-1);
+ SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_SETCURSEL,iItem,0);
+ EnterCriticalSection(&csNetlibUser);
+ tempSettingsCount=netlibUserCount;
+ tempSettings=(struct NetlibTempSettings*)mir_alloc(sizeof(struct NetlibTempSettings)*tempSettingsCount);
+ for(iUser=0;iUser<netlibUserCount;iUser++) {
+ tempSettings[iUser].flags=netlibUser[iUser]->user.flags;
+ tempSettings[iUser].szSettingsModule=mir_strdup(netlibUser[iUser]->user.szSettingsModule);
+ CopySettingsStruct(&tempSettings[iUser].settings,&netlibUser[iUser]->settings);
+ if(netlibUser[iUser]->user.flags&NUF_NOOPTIONS) continue;
+ iItem=SendDlgItemMessageA(hwndDlg,IDC_NETLIBUSERS,CB_ADDSTRING,0,(LPARAM)netlibUser[iUser]->user.szDescriptiveName);
+ SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_SETITEMDATA,iItem,iUser);
+ }
+ LeaveCriticalSection(&csNetlibUser);
+ SendMessage(hwndDlg,M_REFRESHALL,0,0);
+ return TRUE;
+ }
+ case M_REFRESHALL:
+ { int iUser=SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_GETCURSEL,0,0),0);
+ NETLIBUSERSETTINGS settings={0};
+ DWORD flags;
+
+ if(iUser==-1) {
+ int i;
+ settings.cbSize=sizeof(settings);
+ for(i=0,flags=0;i<tempSettingsCount;i++) {
+ if(tempSettings[i].flags&NUF_NOOPTIONS) continue;
+ CombineSettingsStructs(&settings,&flags,&tempSettings[i].settings,tempSettings[i].flags);
+ }
+ }
+ else {
+ NetlibFreeUserSettingsStruct(&settings);
+ CopySettingsStruct(&settings,&tempSettings[iUser].settings);
+ flags=tempSettings[iUser].flags;
+ }
+ ShowMultipleControls(hwndDlg,outgoingConnectionsControls,SIZEOF(outgoingConnectionsControls),flags&NUF_OUTGOING?SW_SHOW:SW_HIDE);
+ CheckDlgButton(hwndDlg,IDC_USEPROXY,settings.useProxy);
+ SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_RESETCONTENT,0,0);
+ if(settings.proxyType==0) AddProxyTypeItem(hwndDlg,0,settings.proxyType);
+ AddProxyTypeItem(hwndDlg,PROXYTYPE_SOCKS4,settings.proxyType);
+ AddProxyTypeItem(hwndDlg,PROXYTYPE_SOCKS5,settings.proxyType);
+ if(flags&(NUF_HTTPCONNS|NUF_HTTPGATEWAY)) AddProxyTypeItem(hwndDlg,PROXYTYPE_HTTP,settings.proxyType);
+ if(!(flags&NUF_NOHTTPSOPTION)) AddProxyTypeItem(hwndDlg,PROXYTYPE_HTTPS,settings.proxyType);
+ SetDlgItemTextA(hwndDlg,IDC_PROXYHOST,settings.szProxyServer?settings.szProxyServer:"");
+ if(settings.wProxyPort) SetDlgItemInt(hwndDlg,IDC_PROXYPORT,settings.wProxyPort,FALSE);
+ else SetDlgItemTextA(hwndDlg,IDC_PROXYPORT,"");
+ CheckDlgButton(hwndDlg,IDC_PROXYAUTH,settings.useProxyAuth);
+ SetDlgItemTextA(hwndDlg,IDC_PROXYUSER,settings.szProxyAuthUser?settings.szProxyAuthUser:"");
+ SetDlgItemTextA(hwndDlg,IDC_PROXYPASS,settings.szProxyAuthPassword?settings.szProxyAuthPassword:"");
+ CheckDlgButton(hwndDlg,IDC_PROXYDNS,settings.dnsThroughProxy);
+ CheckDlgButton(hwndDlg,IDC_PROXYAUTHNTLM,settings.useProxyAuthNtlm);
+
+ ShowMultipleControls(hwndDlg,incomingConnectionsControls,SIZEOF(incomingConnectionsControls),flags&NUF_INCOMING?SW_SHOW:SW_HIDE);
+ CheckDlgButton(hwndDlg,IDC_SPECIFYPORTS,settings.specifyIncomingPorts);
+ SetDlgItemTextA(hwndDlg,IDC_PORTSRANGE,settings.szIncomingPorts?settings.szIncomingPorts:"");
+
+ CheckDlgButton(hwndDlg,IDC_SPECIFYPORTSO,settings.specifyOutgoingPorts);
+ SetDlgItemTextA(hwndDlg,IDC_PORTSRANGEO,settings.szOutgoingPorts?settings.szOutgoingPorts:"");
+
+ NetlibFreeUserSettingsStruct(&settings);
+ SendMessage(hwndDlg,M_REFRESHENABLING,0,0);
+ break;
+ }
+ case M_REFRESHENABLING:
+ { int selectedProxyType;
+ TCHAR str[80];
+
+ selectedProxyType=SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_GETCURSEL,0,0),0);
+ wsprintf(str,TranslateT("(often %d)"),oftenProxyPorts[selectedProxyType]);
+ SetDlgItemText(hwndDlg,IDC_STOFTENPORT,str);
+ if(IsDlgButtonChecked(hwndDlg,IDC_USEPROXY)!=BST_UNCHECKED) {
+ int enableAuth=0,enableUser=0,enablePass=0,enableNtlm=0;
+ EnableMultipleControls(hwndDlg,useProxyControls,SIZEOF(useProxyControls),TRUE);
+ if(selectedProxyType==0) {
+ int i;
+ for(i=0;i<tempSettingsCount;i++) {
+ if(tempSettings[i].flags&NUF_NOOPTIONS || !(tempSettings[i].flags&NUF_OUTGOING) || !tempSettings[i].settings.useProxy) continue;
+ if(tempSettings[i].settings.proxyType==PROXYTYPE_SOCKS4) enableUser=1;
+ else {
+ enableAuth=1;
+ if(tempSettings[i].settings.useProxyAuth) {
+ if(tempSettings[i].settings.proxyType==PROXYTYPE_HTTP || tempSettings[i].settings.proxyType==PROXYTYPE_HTTPS) {
+ enableNtlm=1;
+ if(!tempSettings[i].settings.useProxyAuthNtlm) enableUser=enablePass=1;
+ }
+ else enableUser=enablePass=1;
+ }
+ }
+ }
+ }
+ else {
+ if(selectedProxyType==PROXYTYPE_SOCKS4) enableUser=1;
+ else {
+ enableAuth=1;
+ if(IsDlgButtonChecked(hwndDlg,IDC_PROXYAUTH)!=BST_UNCHECKED) {
+ if(selectedProxyType==PROXYTYPE_HTTP || selectedProxyType==PROXYTYPE_HTTPS) {
+ enableNtlm=1;
+ if(IsDlgButtonChecked(hwndDlg,IDC_PROXYAUTHNTLM)!=BST_CHECKED) enableUser=enablePass=1;
+ }
+ else enableUser=enablePass=1;
+ }
+ }
+ }
+ EnableWindow(GetDlgItem(hwndDlg,IDC_PROXYAUTH),enableAuth);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_STATIC31),enableUser);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_PROXYUSER),enableUser);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_STATIC32),enablePass);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_PROXYPASS),enablePass);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_PROXYAUTHNTLM),enableNtlm);
+ }
+ else EnableMultipleControls(hwndDlg,useProxyControls,SIZEOF(useProxyControls),FALSE);
+ EnableMultipleControls(hwndDlg,specifyPortsControls,SIZEOF(specifyPortsControls),IsDlgButtonChecked(hwndDlg,IDC_SPECIFYPORTS)!=BST_UNCHECKED);
+ EnableMultipleControls(hwndDlg,specifyOPortsControls,SIZEOF(specifyOPortsControls),IsDlgButtonChecked(hwndDlg,IDC_SPECIFYPORTSO)!=BST_UNCHECKED);
+ break;
+ }
+ case WM_COMMAND:
+ { int iUser=SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_GETCURSEL,0,0),0);
+ switch(LOWORD(wParam)) {
+ case IDC_NETLIBUSERS:
+ if(HIWORD(wParam)==CBN_SELCHANGE) SendMessage(hwndDlg,M_REFRESHALL,0,0);
+ return 0;
+ case IDC_LOGOPTIONS:
+ NetlibLogShowOptions();
+ return 0;
+ case IDC_PROXYTYPE:
+ if(HIWORD(wParam)!=CBN_SELCHANGE) return 0;
+ { int newValue,i;
+ newValue=SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_GETCURSEL,0,0),0);
+ if(iUser==-1) {
+ if(newValue==0) return 0;
+ for(i=0;i<tempSettingsCount;i++) {
+ if(tempSettings[i].flags&NUF_NOOPTIONS) continue;
+ if(newValue==PROXYTYPE_HTTP && !(tempSettings[i].flags&(NUF_HTTPCONNS|NUF_HTTPGATEWAY)))
+ tempSettings[i].settings.proxyType=PROXYTYPE_HTTPS;
+ else if(newValue==PROXYTYPE_HTTPS && tempSettings[i].flags&NUF_NOHTTPSOPTION)
+ tempSettings[i].settings.proxyType=PROXYTYPE_HTTP;
+ else tempSettings[i].settings.proxyType=newValue;
+ }
+ SendMessage(hwndDlg,M_REFRESHALL,0,0);
+ }
+ else {
+ tempSettings[iUser].settings.proxyType=newValue;
+ SendMessage(hwndDlg,M_REFRESHENABLING,0,0);
+ }
+ }
+ break;
+ case IDC_USEPROXY:
+ ChangeSettingIntByCheckbox(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,useProxy));
+ break;
+ case IDC_PROXYAUTH:
+ ChangeSettingIntByCheckbox(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,useProxyAuth));
+ break;
+ case IDC_PROXYAUTHNTLM:
+ ChangeSettingIntByCheckbox(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,useProxyAuthNtlm));
+ break;
+ case IDC_PROXYDNS:
+ ChangeSettingIntByCheckbox(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,dnsThroughProxy));
+ break;
+ case IDC_SPECIFYPORTS:
+ ChangeSettingIntByCheckbox(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,specifyIncomingPorts));
+ break;
+ case IDC_SPECIFYPORTSO:
+ ChangeSettingIntByCheckbox(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,specifyOutgoingPorts));
+ break;
+ case IDC_PROXYHOST:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ ChangeSettingStringByEdit(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,szProxyServer));
+ break;
+ case IDC_PROXYPORT:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ { int newValue,i;
+ newValue=GetDlgItemInt(hwndDlg,LOWORD(wParam),NULL,FALSE);
+ if(iUser==-1) {
+ for(i=0;i<tempSettingsCount;i++)
+ if(!(tempSettings[i].flags&NUF_NOOPTIONS))
+ tempSettings[i].settings.wProxyPort=newValue;
+ }
+ else tempSettings[iUser].settings.wProxyPort=newValue;
+ }
+ break;
+ case IDC_PROXYUSER:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ ChangeSettingStringByEdit(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,szProxyAuthUser));
+ break;
+ case IDC_PROXYPASS:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ ChangeSettingStringByEdit(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,szProxyAuthPassword));
+ break;
+ case IDC_PORTSRANGE:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ ChangeSettingStringByEdit(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,szIncomingPorts));
+ break;
+ case IDC_PORTSRANGEO:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ ChangeSettingStringByEdit(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,szOutgoingPorts));
+ break;
+ }
+ ShowWindow(GetDlgItem(hwndDlg,IDC_RECONNECTREQD),SW_SHOW);
+ SendMessage(GetParent(hwndDlg),PSM_CHANGED,0,0);
+ break;
+ }
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case PSN_APPLY:
+ { int iUser;
+ for(iUser=0;iUser<tempSettingsCount;iUser++)
+ NetlibSaveUserSettingsStruct(tempSettings[iUser].szSettingsModule,&tempSettings[iUser].settings);
+ return TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ { int iUser;
+ for(iUser=0;iUser<tempSettingsCount;iUser++) {
+ mir_free(tempSettings[iUser].szSettingsModule);
+ NetlibFreeUserSettingsStruct(&tempSettings[iUser].settings);
+ }
+ mir_free(tempSettings);
+ break;
+ }
+ }
+ return FALSE;
+}
+
+static UINT expertOnlyControls[]={IDC_LOGOPTIONS};
+int NetlibOptInitialise(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp={0};
+ int i,optionsCount;
+
+ EnterCriticalSection(&csNetlibUser);
+ for(i=0,optionsCount=0;i<netlibUserCount;i++)
+ if(!(netlibUser[i]->user.flags&NUF_NOOPTIONS)) optionsCount++;
+ LeaveCriticalSection(&csNetlibUser);
+ if ( optionsCount == 0 )
+ return 0;
+
+ odp.cbSize = sizeof(odp);
+ odp.position = 900000000;
+ odp.hInstance = GetModuleHandle(NULL);
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_NETLIB);
+ odp.pszTitle = "Network";
+ odp.pfnDlgProc = DlgProcNetlibOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.expertOnlyControls = expertOnlyControls;
+ odp.nExpertOnlyControls = SIZEOF( expertOnlyControls );
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
diff --git a/miranda-wine/src/modules/netlib/netlibpktrecver.c b/miranda-wine/src/modules/netlib/netlibpktrecver.c
new file mode 100644
index 0000000..7bc6eb4
--- /dev/null
+++ b/miranda-wine/src/modules/netlib/netlibpktrecver.c
@@ -0,0 +1,85 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "netlib.h"
+
+int NetlibPacketRecverCreate(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ struct NetlibPacketRecver *nlpr;
+
+ if(GetNetlibHandleType(nlc)!=NLH_CONNECTION || lParam==0) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return (int)(struct NetlibPacketRecver*)NULL;
+ }
+ nlpr=(struct NetlibPacketRecver*)mir_calloc(sizeof(struct NetlibPacketRecver));
+ if(nlpr==NULL) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return (int)(struct NetlibPacketRecver*)NULL;
+ }
+ nlpr->handleType=NLH_PACKETRECVER;
+ nlpr->nlc=nlc;
+ nlpr->packetRecver.cbSize=sizeof(nlpr->packetRecver);
+ nlpr->packetRecver.bufferSize=lParam;
+ nlpr->packetRecver.buffer=(PBYTE)mir_alloc(nlpr->packetRecver.bufferSize);
+ nlpr->packetRecver.bytesUsed=0;
+ nlpr->packetRecver.bytesAvailable=0;
+ return (int)nlpr;
+}
+
+int NetlibPacketRecverGetMore(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibPacketRecver *nlpr=(struct NetlibPacketRecver*)wParam;
+ NETLIBPACKETRECVER *nlprParam=(NETLIBPACKETRECVER*)lParam;
+ int recvResult;
+
+ if(GetNetlibHandleType(nlpr)!=NLH_PACKETRECVER || nlprParam==NULL || nlprParam->cbSize!=sizeof(NETLIBPACKETRECVER) || nlprParam->bytesUsed>nlpr->packetRecver.bytesAvailable) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+ if (Miranda_Terminated()) { /* HACK: Lame, break while loops of protocols that can't kill their while loops, (cough, ICQ, cough) */
+ SetLastError(ERROR_TIMEOUT);
+ return SOCKET_ERROR;
+ }
+ nlpr->packetRecver.dwTimeout=nlprParam->dwTimeout;
+ if(nlprParam->bytesUsed==0) {
+ if(nlpr->packetRecver.bytesAvailable==nlpr->packetRecver.bufferSize) {
+ nlpr->packetRecver.bytesAvailable=0;
+ Netlib_Logf(nlpr->nlc->nlu,"Packet recver: packet overflowed buffer, ditching");
+ }
+ }
+ else {
+ MoveMemory(nlpr->packetRecver.buffer,nlpr->packetRecver.buffer+nlprParam->bytesUsed,nlpr->packetRecver.bytesAvailable-nlprParam->bytesUsed);
+ nlpr->packetRecver.bytesAvailable-=nlprParam->bytesUsed;
+ }
+ if(nlprParam->dwTimeout!=INFINITE) {
+ if(!WaitUntilReadable(nlpr->nlc->s,nlprParam->dwTimeout)) {
+ *nlprParam=nlpr->packetRecver;
+ return SOCKET_ERROR;
+ }
+ }
+ recvResult=NLRecv(nlpr->nlc,nlpr->packetRecver.buffer+nlpr->packetRecver.bytesAvailable,nlpr->packetRecver.bufferSize-nlpr->packetRecver.bytesAvailable,0);
+ if(recvResult>0) nlpr->packetRecver.bytesAvailable+=recvResult;
+ *nlprParam=nlpr->packetRecver;
+ return recvResult;
+}
diff --git a/miranda-wine/src/modules/netlib/netlibsock.c b/miranda-wine/src/modules/netlib/netlibsock.c
new file mode 100644
index 0000000..acedd8e
--- /dev/null
+++ b/miranda-wine/src/modules/netlib/netlibsock.c
@@ -0,0 +1,166 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "netlib.h"
+
+extern CRITICAL_SECTION csNetlibCloseHandle;
+extern HANDLE hConnectionHeaderMutex;
+
+int NetlibSend(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ NETLIBBUFFER *nlb=(NETLIBBUFFER*)lParam;
+ int result;
+
+ if(nlb==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+
+ if(!NetlibEnterNestedCS(nlc,NLNCS_SEND)) return SOCKET_ERROR;
+ if(nlc->usingHttpGateway && !(nlb->flags&MSG_RAW)) {
+ if(!(nlb->flags&MSG_NOHTTPGATEWAYWRAP) && nlc->nlu->user.pfnHttpGatewayWrapSend) {
+ NetlibDumpData(nlc,nlb->buf,nlb->len,1,nlb->flags);
+ result=nlc->nlu->user.pfnHttpGatewayWrapSend((HANDLE)nlc,nlb->buf,nlb->len,nlb->flags|MSG_NOHTTPGATEWAYWRAP,NetlibSend);
+ }
+ else result=NetlibHttpGatewayPost(nlc,nlb->buf,nlb->len,nlb->flags);
+ }
+ else {
+ NetlibDumpData(nlc,nlb->buf,nlb->len,1,nlb->flags);
+ result=send(nlc->s,nlb->buf,nlb->len,nlb->flags&0xFFFF);
+ }
+ NetlibLeaveNestedCS(&nlc->ncsSend);
+ return result;
+}
+
+int NetlibRecv(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ NETLIBBUFFER *nlb=(NETLIBBUFFER*)lParam;
+ int recvResult;
+
+ if(nlb==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+ if(!NetlibEnterNestedCS(nlc,NLNCS_RECV)) return SOCKET_ERROR;
+ if(nlc->usingHttpGateway && !(nlb->flags&MSG_RAW))
+ recvResult=NetlibHttpGatewayRecv(nlc,nlb->buf,nlb->len,nlb->flags);
+ else
+ recvResult=recv(nlc->s,nlb->buf,nlb->len,nlb->flags&0xFFFF);
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ if(recvResult<=0) return recvResult;
+ NetlibDumpData(nlc,nlb->buf,recvResult,0,nlb->flags);
+ return recvResult;
+}
+
+static int ConnectionListToSocketList(HANDLE *hConns,fd_set *fd)
+{
+ struct NetlibConnection *nlcCheck;
+ int i;
+
+ FD_ZERO(fd);
+ for(i=0;hConns[i] && hConns[i]!=INVALID_HANDLE_VALUE && i<FD_SETSIZE;i++) {
+ nlcCheck=(struct NetlibConnection*)hConns[i];
+ if(nlcCheck->handleType!=NLH_CONNECTION && nlcCheck->handleType!=NLH_BOUNDPORT) {
+ SetLastError(ERROR_INVALID_DATA);
+ return 0;
+ }
+ FD_SET(nlcCheck->s,fd);
+ }
+ return 1;
+}
+
+int NetlibSelect(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBSELECT *nls=(NETLIBSELECT*)lParam;
+ fd_set readfd,writefd,exceptfd;
+ TIMEVAL tv;
+
+ if(nls==NULL || nls->cbSize!=sizeof(NETLIBSELECT)) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+ tv.tv_sec=nls->dwTimeout/1000;
+ tv.tv_usec=(nls->dwTimeout%1000)*1000;
+ WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
+ if(!ConnectionListToSocketList(nls->hReadConns,&readfd)
+ || !ConnectionListToSocketList(nls->hWriteConns,&writefd)
+ || !ConnectionListToSocketList(nls->hExceptConns,&exceptfd)) {
+ ReleaseMutex(hConnectionHeaderMutex);
+ return SOCKET_ERROR;
+ }
+ ReleaseMutex(hConnectionHeaderMutex);
+ return select(0,&readfd,&writefd,&exceptfd,nls->dwTimeout==INFINITE?NULL:&tv);
+}
+
+int NetlibSelectEx(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBSELECTEX *nls=(NETLIBSELECTEX*)lParam;
+ fd_set readfd,writefd,exceptfd;
+ TIMEVAL tv;
+ int rc=SOCKET_ERROR;
+ int j;
+ struct NetlibConnection *conn=NULL;
+
+ if(nls==NULL || nls->cbSize!=sizeof(NETLIBSELECTEX)) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+ tv.tv_sec=nls->dwTimeout/1000;
+ tv.tv_usec=(nls->dwTimeout%1000)*1000;
+ WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
+ if(!ConnectionListToSocketList(nls->hReadConns,&readfd)
+ || !ConnectionListToSocketList(nls->hWriteConns,&writefd)
+ || !ConnectionListToSocketList(nls->hExceptConns,&exceptfd)) {
+ ReleaseMutex(hConnectionHeaderMutex);
+ return SOCKET_ERROR;
+ }
+ ReleaseMutex(hConnectionHeaderMutex);
+ rc=select(0,&readfd,&writefd,&exceptfd,nls->dwTimeout==INFINITE?NULL:&tv);
+ WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
+ /* go thru each passed HCONN array and grab its socket handle, then give it to FD_ISSET()
+ to see if an event happened for that socket, if it has it will be returned as TRUE (otherwise not)
+ This happens for read/write/except */
+ for (j=0; j<FD_SETSIZE; j++) {
+ conn=(struct NetlibConnection*)nls->hReadConns[j];
+ if (conn==NULL || conn==INVALID_HANDLE_VALUE) break;
+
+ if (conn->usingHttpGateway && conn->nlhpi.szHttpGetUrl == NULL && conn->dataBuffer == NULL)
+ nls->hReadStatus[j] = (conn->pHttpProxyPacketQueue != NULL);
+ else
+ nls->hReadStatus[j] = FD_ISSET(conn->s,&readfd);
+ }
+ for (j=0; j<FD_SETSIZE; j++) {
+ conn=(struct NetlibConnection*)nls->hWriteConns[j];
+ if (conn==NULL || conn==INVALID_HANDLE_VALUE) break;
+ nls->hWriteStatus[j] = FD_ISSET(conn->s,&writefd);
+ }
+ for (j=0; j<FD_SETSIZE; j++) {
+ conn=(struct NetlibConnection*)nls->hExceptConns[j];
+ if (conn==NULL || conn==INVALID_HANDLE_VALUE) break;
+ nls->hExceptStatus[j] = FD_ISSET(conn->s,&exceptfd);
+ }
+ ReleaseMutex(hConnectionHeaderMutex);
+ return rc;
+}
diff --git a/miranda-wine/src/modules/netlib/netlibupnp.c b/miranda-wine/src/modules/netlib/netlibupnp.c
new file mode 100644
index 0000000..c91de6c
--- /dev/null
+++ b/miranda-wine/src/modules/netlib/netlibupnp.c
@@ -0,0 +1,495 @@
+/*
+UPnP plugin for Miranda IM
+Copyright (C) 2006 borkra
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/* Main file for the Weather Protocol, includes loading, unloading,
+ upgrading, support for plugin uninsaller, and anything that doesn't
+ belong to any other file.
+*/
+
+#include "commonheaders.h"
+#include "netlib.h"
+
+static char search_request_msg[] =
+ "M-SEARCH * HTTP/1.1\r\n"
+ "MX: 2\r\n"
+ "HOST: 239.255.255.250:1900\r\n"
+ "MAN: \"ssdp:discover\"\r\n"
+ "ST: urn:schemas-upnp-org:service:%s\r\n"
+ "\r\n";
+
+static char xml_get_hdr[] =
+ "GET %s HTTP/1.1\r\n"
+ "Connection: close\r\n"
+ "Host: %s:%s\r\n\r\n";
+
+static char soap_post_hdr[] =
+ "POST %s HTTP/1.1\r\n"
+ "HOST: %s:%s\r\n"
+ "CONTENT-LENGTH: %u\r\n"
+ "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n"
+ "SOAPACTION: \"%s#%s\"\r\n\r\n"
+ "%s";
+
+static char soap_post_hdr_m[] =
+ "M-POST %s URL HTTP/1.1\r\n"
+ "HOST: %s:%s\r\n"
+ "CONTENT-LENGTH: %u\r\n"
+ "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n"
+ "MAN: \"http://schemas.xmlsoap.org/soap/envelope/\"; ns=01\r\n"
+ "01-SOAPACTION: \"%s#%s\"\r\n\r\n"
+ "%s";
+
+static char search_device[] =
+ "<serviceType>%s</serviceType>";
+
+static char soap_action[] =
+ "<s:Envelope\r\n"
+ " xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"\r\n"
+ " s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n"
+ " <s:Body>\r\n"
+ " <u:%s xmlns:u=\"%s\">\r\n"
+ "%s"
+ " </u:%s>\r\n"
+ " </s:Body>\r\n"
+ "</s:Envelope>\r\n";
+
+static char add_port_mapping[] =
+ " <NewRemoteHost></NewRemoteHost>\r\n"
+ " <NewExternalPort>%i</NewExternalPort>\r\n"
+ " <NewProtocol>%s</NewProtocol>\r\n"
+ " <NewInternalPort>%i</NewInternalPort>\r\n"
+ " <NewInternalClient>%s</NewInternalClient>\r\n"
+ " <NewEnabled>1</NewEnabled>\r\n"
+ " <NewPortMappingDescription>Miranda</NewPortMappingDescription>\r\n"
+ " <NewLeaseDuration>0</NewLeaseDuration>\r\n";
+
+static char delete_port_mapping[] =
+ " <NewRemoteHost></NewRemoteHost>\r\n"
+ " <NewExternalPort>%i</NewExternalPort>\r\n"
+ " <NewProtocol>%s</NewProtocol>\r\n";
+
+static char default_http_port[] = "80";
+
+static BOOL gatewayFound = FALSE;
+static SOCKADDR_IN locIP;
+static time_t lastDiscTime = 0;
+static int expireTime = 120;
+
+static char szCtlUrl[256], szDev[256];
+
+
+static BOOL txtParseParam(char* szData, char* presearch,
+ char* start, char* finish, char* param, int size)
+{
+ char *cp, *cp1;
+ int len;
+
+ *param = 0;
+
+ if (presearch != NULL)
+ {
+ cp1 = strstr(szData, presearch);
+ if (cp1 == NULL) return FALSE;
+ }
+ else
+ cp1 = szData;
+
+ cp = strstr(cp1, start);
+ if (cp == NULL) return FALSE;
+ cp += strlen(start);
+ while (*cp == ' ') ++cp;
+
+ cp1 = strstr(cp, finish);
+ if (cp1 == NULL) return FALSE;
+ while (*(cp1-1) == ' ' && cp1 > cp) --cp1;
+
+ len = min(cp1 - cp, size);
+ strncpy(param, cp, len);
+ param[len] = 0;
+
+ return TRUE;
+}
+
+static LongLog(char* szData)
+{
+ char* buf = szData;
+ int sz = strlen(szData);
+
+ while ( sz > 1000)
+ {
+ char* nbuf = buf + 1000;
+ char t = *nbuf;
+ *nbuf = 0;
+ Netlib_Logf(NULL, buf);
+ *nbuf = t;
+ buf = nbuf;
+ sz -= 1000;
+ }
+ Netlib_Logf(NULL, buf);
+}
+
+
+static void discoverUPnP(char* szUrl, int sizeUrl)
+{
+ char* buf;
+ int buflen;
+ unsigned i, j, nip = 0;
+ char* szData = NULL;
+ unsigned* ips = NULL;
+
+ static const unsigned any = INADDR_ANY;
+ fd_set readfd;
+ TIMEVAL tv = { 1, 0 };
+
+ char hostname[256];
+ PHOSTENT he;
+
+ SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+
+ SOCKADDR_IN enetaddr;
+ enetaddr.sin_family = AF_INET;
+ enetaddr.sin_port = htons(1900);
+ enetaddr.sin_addr.s_addr = inet_addr("239.255.255.250");
+
+ FD_ZERO(&readfd);
+ FD_SET(sock, &readfd);
+
+ szUrl[0] = 0;
+
+ gethostname( hostname, sizeof( hostname ));
+ he = gethostbyname( hostname );
+
+ if (he)
+ {
+ while(he->h_addr_list[nip]) ++nip;
+
+ ips = mir_alloc(nip * sizeof(unsigned));
+
+ for (j=0; j<nip; ++j)
+ ips[j] = *(unsigned*)he->h_addr_list[j];
+ }
+
+ buf = mir_alloc(1500);
+
+ for(i = 3; --i && szUrl[0] == 0;)
+ {
+ for (j=0; j<nip; ++j)
+ {
+ if (ips)
+ setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (char *)&ips[j], sizeof(unsigned));
+
+ buflen = mir_snprintf(buf, 1500, search_request_msg, "WANIPConnection:1");
+ sendto(sock, buf, buflen, 0, (SOCKADDR*)&enetaddr, sizeof(enetaddr));
+ LongLog(buf);
+
+ buflen = mir_snprintf(buf, 1500, search_request_msg, "WANPPPConnection:1");
+ sendto(sock, buf, buflen, 0, (SOCKADDR*)&enetaddr, sizeof(enetaddr));
+ LongLog(buf);
+ }
+
+ while (select(0, &readfd, NULL, NULL, &tv) == 1)
+ {
+ buflen = recv(sock, buf, 1500, 0);
+ if (buflen != SOCKET_ERROR)
+ {
+ buf[buflen] = 0;
+ LongLog(buf);
+
+ if (txtParseParam(buf, NULL, "LOCATION:", "\r", szUrl, sizeUrl) ||
+ txtParseParam(buf, NULL, "Location:", "\r", szUrl, sizeUrl))
+ {
+ char age[30];
+ txtParseParam(szUrl, NULL, "http://", "/", szCtlUrl, sizeof(szCtlUrl));
+ txtParseParam(buf, NULL, "ST:", "\r", szDev, sizeof(szDev));
+ txtParseParam(buf, "max-age", "=", "\r", age, sizeof(age));
+ expireTime = atoi(age);
+ break;
+ }
+ }
+ }
+ }
+
+ mir_free(buf);
+ mir_free(ips);
+ setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (char *)&any, sizeof(unsigned));
+ closesocket(sock);
+}
+
+
+static int httpTransact (char* szUrl, char* szResult, int resSize, char* szActionName)
+{
+ // Parse URL
+ char *ppath, *phost, *pport, *szHost, *szPort, szRes[6];
+ int sz, res = 0;
+
+ char* szPostHdr = soap_post_hdr;
+ char* szData = mir_alloc(4096);
+ char* szReq = szActionName ? mir_strdup(szResult) : NULL;
+ szResult[0] = 0;
+
+
+ phost = strstr(szUrl,"://");
+ if (phost == NULL) phost = szUrl;
+ else phost += 3;
+
+ ppath = strchr(phost,'/');
+ if (ppath == NULL) ppath = phost + strlen(phost);
+
+ pport = strchr(phost,':');
+ if (pport == NULL) pport = ppath;
+
+ sz = pport - phost + 1;
+ szHost = _alloca(sz);
+ strncpy(szHost, phost, sz);
+ szHost[sz-1] = 0;
+
+ sz = ppath - pport;
+ if (sz > 1)
+ {
+ szPort = _alloca(sz);
+ strncpy(szPort, pport+1, sz);
+ szPort[sz-1] = 0;
+ }
+ else
+ szPort = default_http_port;
+
+ for (;;)
+ {
+ if (szActionName == NULL)
+ sz = mir_snprintf (szData, 4096,
+ xml_get_hdr, ppath, szHost, szPort);
+ else
+ {
+ char szData1[1024];
+
+ sz = mir_snprintf (szData1, sizeof(szData1),
+ soap_action, szActionName, szDev, szReq, szActionName);
+
+ sz = mir_snprintf (szData, 4096,
+ szPostHdr, ppath, szHost, szPort,
+ sz, szDev, szActionName, szData1);
+ }
+
+ {
+ static TIMEVAL tv = { 3, 0 };
+ static unsigned ttl = 4;
+ fd_set readfd;
+
+ SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+ SOCKADDR_IN enetaddr;
+ enetaddr.sin_family = AF_INET;
+ enetaddr.sin_port = htons((unsigned short)atol(szPort));
+ enetaddr.sin_addr.s_addr = inet_addr(szHost);
+
+ if (enetaddr.sin_addr.s_addr == INADDR_NONE)
+ {
+ PHOSTENT he = gethostbyname(szHost);
+ if (he)
+ enetaddr.sin_addr.s_addr = *(unsigned*)he->h_addr_list[0];
+ }
+
+ Netlib_Logf(NULL, "UPnP HTTP connection Host: %s Port: %s\n", szHost, szPort);
+
+ FD_ZERO(&readfd);
+ FD_SET(sock, &readfd);
+
+ setsockopt(sock, IPPROTO_IP, IP_TTL, (char *)&ttl, sizeof(unsigned));
+
+ if (connect(sock, (SOCKADDR*)&enetaddr, sizeof(enetaddr)) == 0)
+ {
+ if (send( sock, szData, sz, 0 ) != SOCKET_ERROR)
+ {
+ LongLog(szData);
+ sz = 0;
+ for(;;)
+ {
+ int bytesRecv;
+ char *hdrend;
+
+ if (select(0, &readfd, NULL, NULL, &tv) != 1)
+ {
+ Netlib_Logf(NULL, "UPnP select timeout");
+ break;
+ }
+
+ bytesRecv = recv( sock, &szResult[sz], resSize-sz, 0 );
+ if ( bytesRecv == 0 || bytesRecv == SOCKET_ERROR)
+ break;
+ else
+ sz += bytesRecv;
+
+ if (sz >= (resSize-1))
+ {
+ szResult[resSize-1] = 0;
+ break;
+ }
+ else
+ szResult[sz] = 0;
+
+ hdrend = strstr(szResult, "\r\n\r\n");
+ if (hdrend != NULL &&
+ (txtParseParam(szResult, NULL, "Content-Length:", "\r", szRes, sizeof(szRes)) ||
+ txtParseParam(szResult, NULL, "CONTENT-LENGTH:", "\r", szRes, sizeof(szRes))))
+ {
+ int pktsz = atol(szRes) + (hdrend - szResult + 4);
+ if (sz >= pktsz)
+ {
+ szResult[pktsz] = 0;
+ break;
+ }
+ }
+
+ }
+ LongLog(szResult);
+ }
+ else
+ Netlib_Logf(NULL, "UPnP send failed %d", WSAGetLastError());
+ }
+ else
+ Netlib_Logf(NULL, "UPnP connect failed %d", WSAGetLastError());
+
+ if (szActionName == NULL)
+ {
+ int len = sizeof(locIP);
+ getsockname(sock, (SOCKADDR*)&locIP, &len);
+ }
+
+ shutdown(sock, 2);
+ closesocket(sock);
+ }
+ txtParseParam(szResult, "HTTP", " ", " ", szRes, sizeof(szRes));
+ res = atol(szRes);
+ if (szActionName != NULL && res == 405 && szPostHdr == soap_post_hdr)
+ szPostHdr = soap_post_hdr_m;
+ else
+ break;
+ }
+
+ mir_free(szData);
+ mir_free(szReq);
+ return res;
+}
+
+
+static void findUPnPGateway(void)
+{
+ time_t curTime = time(NULL);
+
+ if ((curTime - lastDiscTime) >= expireTime)
+ {
+ char szUrl[256];
+ char* szData = mir_alloc(8192);
+
+ lastDiscTime = curTime;
+
+ discoverUPnP(szUrl, sizeof(szUrl));
+ gatewayFound = szUrl[0] != 0 && httpTransact(szUrl, szData, 8192, NULL) == 200;
+
+ if (gatewayFound)
+ {
+ char szTemp[256];
+ size_t ctlLen;
+
+ txtParseParam(szData, NULL, "<URLBase>", "</URLBase>", szTemp, sizeof(szTemp));
+ if (szTemp[0] != 0) strcpy(szCtlUrl, szTemp);
+ ctlLen = strlen(szCtlUrl);
+ if (ctlLen > 0 && szCtlUrl[ctlLen-1] == '/')
+ szCtlUrl[--ctlLen] = 0;
+
+ mir_snprintf(szTemp, sizeof(szTemp), search_device, szDev);
+ txtParseParam(szData, szTemp, "<controlURL>", "</controlURL>", szUrl, sizeof(szUrl));
+ switch (szUrl[0])
+ {
+ case 0:
+ gatewayFound = FALSE;
+ break;
+
+ case '/':
+ strncat(szCtlUrl, szUrl, sizeof(szCtlUrl) - ctlLen);
+ szCtlUrl[sizeof(szCtlUrl)-1] = 0;
+ break;
+
+ default:
+ strncpy(szCtlUrl, szUrl, sizeof(szCtlUrl));
+ szCtlUrl[sizeof(szCtlUrl)-1] = 0;
+ break;
+ }
+ }
+ Netlib_Logf(NULL, "UPnP Gateway detected %d, Control URL: %s\n", gatewayFound, szCtlUrl);
+ mir_free(szData);
+ }
+}
+
+
+BOOL NetlibUPnPAddPortMapping(WORD intport, char *proto,
+ WORD *extport, DWORD *extip, BOOL search)
+{
+ int res = 0;
+
+ findUPnPGateway();
+
+ if (gatewayFound)
+ {
+ char* szData = mir_alloc(4096);
+ char szExtIP[30];
+
+ *extport = intport - 1;
+ *extip = ntohl(locIP.sin_addr.S_un.S_addr);
+
+ do {
+ ++*extport;
+ mir_snprintf(szData, 4096, add_port_mapping,
+ *extport, proto, intport, inet_ntoa(locIP.sin_addr));
+ res = httpTransact(szCtlUrl, szData, 4096, "AddPortMapping");
+ } while (search && res == 718);
+
+ if (res == 200)
+ {
+ szData[0] = 0;
+ res = httpTransact(szCtlUrl, szData, 4096, "GetExternalIPAddress");
+ if (res == 200 && txtParseParam(szData, "<NewExternalIPAddress", ">", "<", szExtIP, sizeof(szExtIP)))
+ *extip = ntohl(inet_addr(szExtIP));
+ }
+ mir_free(szData);
+ }
+
+ return res == 200;
+}
+
+
+void NetlibUPnPDeletePortMapping(WORD extport, char* proto)
+{
+ if (extport != 0)
+ {
+// findUPnPGateway();
+
+ if (gatewayFound)
+ {
+ char* szData = mir_alloc(4096);
+
+ mir_snprintf(szData, 4096, delete_port_mapping,
+ extport, proto);
+ httpTransact(szCtlUrl, szData, 4096, "DeletePortMapping");
+
+ mir_free(szData);
+ }
+ }
+}
+
diff --git a/miranda-wine/src/modules/options/options.c b/miranda-wine/src/modules/options/options.c
new file mode 100644
index 0000000..cea7421
--- /dev/null
+++ b/miranda-wine/src/modules/options/options.c
@@ -0,0 +1,664 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+char* u2a( wchar_t* src );
+
+#define OPTIONPAGE_OLD_SIZE 40
+
+static HANDLE hOptionsInitEvent;
+static HWND hwndOptions=NULL;
+
+struct OptionsPageInit {
+ int pageCount;
+ OPTIONSDIALOGPAGE *odp;
+};
+
+struct DlgTemplateExBegin {
+ WORD dlgVer;
+ WORD signature;
+ DWORD helpID;
+ DWORD exStyle;
+ DWORD style;
+ WORD cDlgItems;
+ short x;
+ short y;
+ short cx;
+ short cy;
+};
+
+struct OptionsPageData {
+ DLGTEMPLATE *pTemplate;
+ DLGPROC dlgProc;
+ HINSTANCE hInst;
+ HTREEITEM hTreeItem;
+ HWND hwnd;
+ int changed;
+ int simpleHeight,expertHeight;
+ int simpleWidth,expertWidth;
+ int simpleBottomControlId,simpleRightControlId;
+ int nExpertOnlyControls;
+ UINT *expertOnlyControls;
+ DWORD flags;
+ TCHAR *pszTitle, *pszGroup;
+};
+
+struct OptionsDlgData {
+ int pageCount;
+ int currentPage;
+ HTREEITEM hCurrentPage;
+ struct OptionsPageData *opd;
+ RECT rcDisplay;
+ HFONT hBoldFont;
+};
+
+static HTREEITEM FindNamedTreeItemAtRoot(HWND hwndTree, const TCHAR* name)
+{
+ TVITEM tvi;
+ TCHAR str[128];
+
+ tvi.mask = TVIF_TEXT;
+ tvi.pszText = str;
+ tvi.cchTextMax = SIZEOF( str );
+ tvi.hItem = TreeView_GetRoot( hwndTree );
+ while( tvi.hItem != NULL ) {
+ SendMessage( hwndTree, TVM_GETITEM, 0, (LPARAM)&tvi );
+ if( !_tcsicmp( str,name ))
+ return tvi.hItem;
+
+ tvi.hItem = TreeView_GetNextSibling( hwndTree, tvi.hItem );
+ }
+ return NULL;
+}
+
+static BOOL CALLBACK BoldGroupTitlesEnumChildren(HWND hwnd,LPARAM lParam)
+{
+ TCHAR szClass[64];
+
+ GetClassName(hwnd,szClass,SIZEOF(szClass));
+ if(!lstrcmp(szClass,_T("Button")) && (GetWindowLong(hwnd,GWL_STYLE)&0x0F)==BS_GROUPBOX)
+ SendMessage(hwnd,WM_SETFONT,lParam,0);
+ return TRUE;
+}
+
+#define OPTSTATE_PREFIX "s_"
+
+static void SaveOptionsTreeState(HWND hdlg) {
+ TVITEMA tvi;
+ char buf[130],str[128];
+ tvi.mask = TVIF_TEXT | TVIF_STATE;
+ tvi.pszText = str;
+ tvi.cchTextMax = SIZEOF(str);
+ tvi.hItem = TreeView_GetRoot( GetDlgItem( hdlg, IDC_PAGETREE ));
+ while ( tvi.hItem != NULL ) {
+ if ( SendMessageA( GetDlgItem(hdlg,IDC_PAGETREE), TVM_GETITEMA, 0, (LPARAM)&tvi )) {
+ wsprintfA(buf,"%s%s",OPTSTATE_PREFIX,str);
+ DBWriteContactSettingByte(NULL,"Options",buf,(BYTE)((tvi.state&TVIS_EXPANDED)?1:0));
+ }
+ tvi.hItem = TreeView_GetNextSibling( GetDlgItem( hdlg, IDC_PAGETREE ), tvi.hItem );
+} }
+
+#define DM_FOCUSPAGE (WM_USER+10)
+#define DM_REBUILDPAGETREE (WM_USER+11)
+
+static BOOL CALLBACK OptionsDlgProc(HWND hdlg,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ struct OptionsDlgData* dat = (struct OptionsDlgData* )GetWindowLong( hdlg, GWL_USERDATA );
+
+ switch ( message ) {
+ case WM_INITDIALOG:
+ { HRSRC hrsrc;
+ HGLOBAL hglb;
+ PROPSHEETHEADER *psh=(PROPSHEETHEADER*)lParam;
+ OPENOPTIONSDIALOG *ood=(OPENOPTIONSDIALOG*)psh->pStartPage;
+ OPTIONSDIALOGPAGE *odp;
+ int i;
+ POINT pt;
+ RECT rc,rcDlg;
+ struct DlgTemplateExBegin *dte;
+ TCHAR *lastPage = NULL, *lastGroup = NULL;
+ DBVARIANT dbv;
+
+ Utils_RestoreWindowPositionNoSize(hdlg, NULL, "Options", "");
+ TranslateDialogDefault(hdlg);
+ SendMessage(hdlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_OPTIONS)));
+ CheckDlgButton(hdlg,IDC_EXPERT,DBGetContactSettingByte(NULL,"Options","Expert",SETTING_SHOWEXPERT_DEFAULT)?BST_CHECKED:BST_UNCHECKED);
+ EnableWindow(GetDlgItem(hdlg,IDC_APPLY),FALSE);
+ dat=(struct OptionsDlgData*)mir_alloc(sizeof(struct OptionsDlgData));
+ SetWindowLong(hdlg,GWL_USERDATA,(LONG)dat);
+ SetWindowText(hdlg,psh->pszCaption);
+ { LOGFONT lf;
+ dat->hBoldFont=(HFONT)SendDlgItemMessage(hdlg,IDC_EXPERT,WM_GETFONT,0,0);
+ GetObject(dat->hBoldFont,sizeof(lf),&lf);
+ lf.lfWeight=FW_BOLD;
+ dat->hBoldFont=CreateFontIndirect(&lf);
+ }
+ dat->pageCount = psh->nPages;
+ dat->opd = ( struct OptionsPageData* )mir_alloc( sizeof(struct OptionsPageData) * dat->pageCount );
+ odp = ( OPTIONSDIALOGPAGE* )psh->ppsp;
+
+ dat->currentPage = -1;
+ if ( ood->pszPage == NULL ) {
+ if ( !DBGetContactSettingTString( NULL, "Options", "LastPage", &dbv )) {
+ lastPage = mir_tstrdup( dbv.ptszVal );
+ DBFreeVariant( &dbv );
+ }
+ }
+ else lastPage = LangPackPcharToTchar( ood->pszPage );
+
+ if ( ood->pszGroup == NULL ) {
+ if ( !DBGetContactSettingTString( NULL, "Options", "LastGroup", &dbv )) {
+ lastGroup = mir_tstrdup( dbv.ptszVal );
+ DBFreeVariant( &dbv );
+ }
+ }
+ else lastGroup = LangPackPcharToTchar( ood->pszGroup );
+
+ for ( i=0; i < dat->pageCount; i++ ) {
+ DWORD resSize;
+ hrsrc=FindResourceA(odp[i].hInstance,odp[i].pszTemplate,MAKEINTRESOURCEA(5));
+ hglb=LoadResource(odp[i].hInstance,hrsrc);
+ resSize=SizeofResource(odp[i].hInstance,hrsrc);
+ dat->opd[i].pTemplate=mir_alloc(resSize);
+ memcpy(dat->opd[i].pTemplate,LockResource(hglb),resSize);
+ dte=(struct DlgTemplateExBegin*)dat->opd[i].pTemplate;
+ if ( dte->signature == 0xFFFF ) {
+ //this feels like an access violation, and is according to boundschecker
+ //...but it works - for now
+ //may well have to remove and sort out the original dialogs
+ dte->style&=~(WS_VISIBLE|WS_CHILD|WS_POPUP|WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|DS_MODALFRAME|DS_CENTER);
+ dte->style|=WS_CHILD;
+ }
+ else {
+ dat->opd[i].pTemplate->style&=~(WS_VISIBLE|WS_CHILD|WS_POPUP|WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|DS_MODALFRAME|DS_CENTER);
+ dat->opd[i].pTemplate->style|=WS_CHILD;
+ }
+ dat->opd[i].dlgProc=odp[i].pfnDlgProc;
+ dat->opd[i].hInst=odp[i].hInstance;
+ dat->opd[i].hwnd=NULL;
+ dat->opd[i].changed=0;
+ dat->opd[i].simpleHeight=dat->opd[i].expertHeight=0;
+ dat->opd[i].simpleBottomControlId=odp[i].nIDBottomSimpleControl;
+ dat->opd[i].simpleWidth=dat->opd[i].expertWidth=0;
+ dat->opd[i].simpleRightControlId=odp[i].nIDRightSimpleControl;
+ dat->opd[i].nExpertOnlyControls=odp[i].nExpertOnlyControls;
+ dat->opd[i].expertOnlyControls=odp[i].expertOnlyControls;
+ dat->opd[i].flags=odp[i].flags;
+ if ( odp[i].pszTitle == NULL )
+ dat->opd[i].pszTitle = NULL;
+ else if ( odp[i].flags & ODPF_UNICODE ) {
+ #if defined ( _UNICODE )
+ dat->opd[i].pszTitle = ( TCHAR* )mir_wstrdup( odp[i].ptszTitle );
+ #else
+ dat->opd[i].pszTitle = u2a(( WCHAR* )odp[i].ptszTitle );
+ #endif
+ }
+ else dat->opd[i].pszTitle = ( TCHAR* )mir_strdup( odp[i].pszTitle );
+
+ if ( odp[i].pszGroup == NULL )
+ dat->opd[i].pszGroup = NULL;
+ else if ( odp[i].flags & ODPF_UNICODE ) {
+ #if defined ( _UNICODE )
+ dat->opd[i].pszGroup = ( TCHAR* )mir_wstrdup( odp[i].ptszGroup );
+ #else
+ dat->opd[i].pszGroup = u2a(( WCHAR* )odp[i].ptszGroup );
+ #endif
+ }
+ else dat->opd[i].pszGroup = ( TCHAR* )mir_strdup( odp[i].pszGroup );
+
+ if ( !lstrcmp( lastPage, odp[i].ptszTitle ) &&
+ (( lastGroup == NULL && odp[i].ptszGroup == NULL ) || !lstrcmp( lastGroup, odp[i].ptszGroup )))
+ dat->currentPage = i;
+ }
+ mir_free( lastGroup );
+ mir_free( lastPage );
+
+ GetWindowRect(hdlg,&rcDlg);
+ pt.x=pt.y=0;
+ ClientToScreen(hdlg,&pt);
+ GetWindowRect(GetDlgItem(hdlg,IDC_PAGETREE),&rc);
+ dat->rcDisplay.left=rc.right-pt.x+(rc.left-rcDlg.left);
+ dat->rcDisplay.top=rc.top-pt.y;
+ dat->rcDisplay.right=rcDlg.right-(rc.left-rcDlg.left)-pt.x;
+ GetWindowRect(GetDlgItem(hdlg,IDOK),&rc);
+ dat->rcDisplay.bottom=rc.top-(rcDlg.bottom-rc.bottom)-pt.y;
+
+ SendMessage(hdlg,DM_REBUILDPAGETREE,0,0);
+ return TRUE;
+ }
+ case DM_REBUILDPAGETREE:
+ { int i;
+ TVINSERTSTRUCT tvis;
+ TVITEMA tvi;
+ char str[128],buf[130];
+
+ TreeView_SelectItem(GetDlgItem(hdlg,IDC_PAGETREE),NULL);
+ if ( dat->currentPage != (-1))
+ ShowWindow(dat->opd[dat->currentPage].hwnd,SW_HIDE);
+ ShowWindow(GetDlgItem(hdlg,IDC_PAGETREE),SW_HIDE); //deleteall is annoyingly visible
+ TreeView_DeleteAllItems(GetDlgItem(hdlg,IDC_PAGETREE));
+ dat->hCurrentPage = NULL;
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_SORT;
+ tvis.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
+ tvis.item.state = tvis.item.stateMask = TVIS_EXPANDED;
+ for ( i=0; i < dat->pageCount; i++ ) {
+ if (( dat->opd[i].flags & ODPF_SIMPLEONLY ) && IsDlgButtonChecked( hdlg, IDC_EXPERT )) continue;
+ if (( dat->opd[i].flags & ODPF_EXPERTONLY ) && !IsDlgButtonChecked( hdlg, IDC_EXPERT )) continue;
+ tvis.hParent = NULL;
+ if(dat->opd[i].pszGroup != NULL) {
+ tvis.hParent = FindNamedTreeItemAtRoot(GetDlgItem(hdlg,IDC_PAGETREE),dat->opd[i].pszGroup);
+ if(tvis.hParent == NULL) {
+ tvis.item.lParam = -1;
+ tvis.item.pszText = dat->opd[i].pszGroup;
+ tvis.hParent = TreeView_InsertItem( GetDlgItem(hdlg,IDC_PAGETREE), &tvis );
+ }
+ }
+ else {
+ TVITEM tvi;
+ tvi.hItem = FindNamedTreeItemAtRoot(GetDlgItem(hdlg,IDC_PAGETREE),dat->opd[i].pszTitle);
+ if( tvi.hItem != NULL ) {
+ if ( i == dat->currentPage ) dat->hCurrentPage=tvi.hItem;
+ tvi.mask = TVIF_PARAM;
+ TreeView_GetItem(GetDlgItem(hdlg,IDC_PAGETREE),&tvi);
+ if ( tvi.lParam == -1 ) {
+ tvi.lParam = i;
+ TreeView_SetItem(GetDlgItem(hdlg,IDC_PAGETREE),&tvi);
+ continue;
+ } } }
+
+ tvis.item.pszText = dat->opd[i].pszTitle;
+ tvis.item.lParam = i;
+ dat->opd[i].hTreeItem = TreeView_InsertItem( GetDlgItem(hdlg,IDC_PAGETREE), &tvis);
+ if ( i == dat->currentPage )
+ dat->hCurrentPage = dat->opd[i].hTreeItem;
+ }
+ tvi.mask = TVIF_TEXT | TVIF_STATE;
+ tvi.pszText = str;
+ tvi.cchTextMax = SIZEOF(str);
+ tvi.hItem = TreeView_GetRoot(GetDlgItem(hdlg,IDC_PAGETREE));
+ while ( tvi.hItem != NULL ) {
+ if ( SendMessageA( GetDlgItem(hdlg,IDC_PAGETREE), TVM_GETITEMA, 0, (LPARAM)&tvi )) {
+ wsprintfA(buf,"%s%s",OPTSTATE_PREFIX,str);
+ if ( !DBGetContactSettingByte( NULL, "Options", buf, 1 ))
+ TreeView_Expand( GetDlgItem(hdlg,IDC_PAGETREE), tvi.hItem, TVE_COLLAPSE );
+ }
+ tvi.hItem = TreeView_GetNextSibling( GetDlgItem( hdlg, IDC_PAGETREE ), tvi.hItem );
+ }
+ if(dat->hCurrentPage==NULL) dat->hCurrentPage=TreeView_GetRoot(GetDlgItem(hdlg,IDC_PAGETREE));
+ dat->currentPage=-1;
+ TreeView_SelectItem(GetDlgItem(hdlg,IDC_PAGETREE),dat->hCurrentPage);
+ ShowWindow(GetDlgItem(hdlg,IDC_PAGETREE),SW_SHOW);
+ break;
+ }
+ case PSM_CHANGED:
+ EnableWindow(GetDlgItem(hdlg,IDC_APPLY),TRUE);
+ if(dat->currentPage != (-1)) dat->opd[dat->currentPage].changed=1;
+ return TRUE;
+ case PSM_ISEXPERT:
+ SetWindowLong(hdlg,DWL_MSGRESULT,IsDlgButtonChecked(hdlg,IDC_EXPERT));
+ return TRUE;
+ case PSM_GETBOLDFONT:
+ SetWindowLong(hdlg,DWL_MSGRESULT,(LONG)dat->hBoldFont);
+ return TRUE;
+ case WM_NOTIFY:
+ switch(wParam) {
+ case IDC_PAGETREE:
+ switch(((LPNMHDR)lParam)->code) {
+ case TVN_ITEMEXPANDING:
+ SetWindowLong(hdlg,DWL_MSGRESULT,FALSE);
+ return TRUE;
+ case TVN_SELCHANGING:
+ { PSHNOTIFY pshn;
+ if(dat->currentPage==-1 || dat->opd[dat->currentPage].hwnd==NULL) break;
+ pshn.hdr.code=PSN_KILLACTIVE;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=0;
+ if(SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn)) {
+ SetWindowLong(hdlg,DWL_MSGRESULT,TRUE);
+ return TRUE;
+ }
+ break;
+ }
+ case TVN_SELCHANGED:
+ { TVITEM tvi;
+ ShowWindow(GetDlgItem(hdlg,IDC_STNOPAGE),SW_HIDE);
+ if(dat->currentPage!=-1 && dat->opd[dat->currentPage].hwnd!=NULL) ShowWindow(dat->opd[dat->currentPage].hwnd,SW_HIDE);
+ tvi.hItem=dat->hCurrentPage=TreeView_GetSelection(GetDlgItem(hdlg,IDC_PAGETREE));
+ if(tvi.hItem==NULL) break;
+ tvi.mask=TVIF_HANDLE|TVIF_PARAM;
+ TreeView_GetItem(GetDlgItem(hdlg,IDC_PAGETREE),&tvi);
+ dat->currentPage=tvi.lParam;
+ if ( dat->currentPage != -1 ) {
+ if ( dat->opd[dat->currentPage].hwnd == NULL ) {
+ RECT rcPage;
+ RECT rcControl,rc;
+ int w,h;
+
+ dat->opd[dat->currentPage].hwnd=CreateDialogIndirectA(dat->opd[dat->currentPage].hInst,dat->opd[dat->currentPage].pTemplate,hdlg,dat->opd[dat->currentPage].dlgProc);
+ if(dat->opd[dat->currentPage].flags&ODPF_BOLDGROUPS)
+ EnumChildWindows(dat->opd[dat->currentPage].hwnd,BoldGroupTitlesEnumChildren,(LPARAM)dat->hBoldFont);
+ GetClientRect(dat->opd[dat->currentPage].hwnd,&rcPage);
+ dat->opd[dat->currentPage].expertWidth=rcPage.right;
+ dat->opd[dat->currentPage].expertHeight=rcPage.bottom;
+ GetWindowRect(dat->opd[dat->currentPage].hwnd,&rc);
+
+ if(dat->opd[dat->currentPage].simpleBottomControlId) {
+ GetWindowRect(GetDlgItem(dat->opd[dat->currentPage].hwnd,dat->opd[dat->currentPage].simpleBottomControlId),&rcControl);
+ dat->opd[dat->currentPage].simpleHeight=rcControl.bottom-rc.top;
+ }
+ else dat->opd[dat->currentPage].simpleHeight=dat->opd[dat->currentPage].expertHeight;
+
+ if(dat->opd[dat->currentPage].simpleRightControlId) {
+ GetWindowRect(GetDlgItem(dat->opd[dat->currentPage].hwnd,dat->opd[dat->currentPage].simpleRightControlId),&rcControl);
+ dat->opd[dat->currentPage].simpleWidth=rcControl.right-rc.left;
+ }
+ else dat->opd[dat->currentPage].simpleWidth=dat->opd[dat->currentPage].expertWidth;
+
+ if(IsDlgButtonChecked(hdlg,IDC_EXPERT)) {
+ w=dat->opd[dat->currentPage].expertWidth;
+ h=dat->opd[dat->currentPage].expertHeight;
+ }
+ else {
+ int i;
+ for(i=0;i<dat->opd[dat->currentPage].nExpertOnlyControls;i++)
+ ShowWindow(GetDlgItem(dat->opd[dat->currentPage].hwnd,dat->opd[dat->currentPage].expertOnlyControls[i]),SW_HIDE);
+ w=dat->opd[dat->currentPage].simpleWidth;
+ h=dat->opd[dat->currentPage].simpleHeight;
+ }
+ SetWindowPos(dat->opd[dat->currentPage].hwnd,HWND_TOP,(dat->rcDisplay.left+dat->rcDisplay.right-w)>>1,(dat->rcDisplay.top+dat->rcDisplay.bottom-h)>>1,w,h,0);
+ }
+ ShowWindow(dat->opd[dat->currentPage].hwnd,SW_SHOW);
+ if(((LPNMTREEVIEW)lParam)->action==TVC_BYMOUSE) PostMessage(hdlg,DM_FOCUSPAGE,0,0);
+ else SetFocus(GetDlgItem(hdlg,IDC_PAGETREE));
+ }
+ else ShowWindow(GetDlgItem(hdlg,IDC_STNOPAGE),SW_SHOW);
+ break;
+ } } }
+ break;
+ case DM_FOCUSPAGE:
+ if(dat->currentPage==-1) break;
+ SetFocus(dat->opd[dat->currentPage].hwnd);
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_EXPERT:
+ { int expert=IsDlgButtonChecked(hdlg,IDC_EXPERT);
+ int i,j;
+ PSHNOTIFY pshn;
+ RECT rcPage;
+ int neww,newh;
+
+ DBWriteContactSettingByte(NULL,"Options","Expert",(BYTE)expert);
+ pshn.hdr.idFrom=0;
+ pshn.lParam=expert;
+ pshn.hdr.code=PSN_EXPERTCHANGED;
+ for(i=0;i<dat->pageCount;i++) {
+ if(dat->opd[i].hwnd==NULL) continue;
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+
+ for(j=0;j<dat->opd[i].nExpertOnlyControls;j++)
+ ShowWindow(GetDlgItem(dat->opd[i].hwnd,dat->opd[i].expertOnlyControls[j]),expert?SW_SHOW:SW_HIDE);
+
+ GetClientRect(dat->opd[i].hwnd,&rcPage);
+ if(dat->opd[i].simpleBottomControlId) newh=expert?dat->opd[i].expertHeight:dat->opd[i].simpleHeight;
+ else newh=rcPage.bottom-rcPage.top;
+ if(dat->opd[i].simpleRightControlId) neww=expert?dat->opd[i].expertWidth:dat->opd[i].simpleWidth;
+ else neww=rcPage.right-rcPage.left;
+ if(i==dat->currentPage) {
+ POINT ptStart,ptEnd,ptNow;
+ DWORD thisTick,startTick;
+ RECT rc;
+
+ ptNow.x=ptNow.y=0;
+ ClientToScreen(hdlg,&ptNow);
+ GetWindowRect(dat->opd[i].hwnd,&rc);
+ ptStart.x=rc.left-ptNow.x;
+ ptStart.y=rc.top-ptNow.y;
+ ptEnd.x=(dat->rcDisplay.left+dat->rcDisplay.right-neww)>>1;
+ ptEnd.y=(dat->rcDisplay.top+dat->rcDisplay.bottom-newh)>>1;
+ if(abs(ptEnd.x-ptStart.x)>5 || abs(ptEnd.y-ptStart.y)>5) {
+ startTick=GetTickCount();
+ SetWindowPos(dat->opd[i].hwnd,HWND_TOP,0,0,min(neww,rcPage.right),min(newh,rcPage.bottom),SWP_NOMOVE);
+ UpdateWindow(dat->opd[i].hwnd);
+ for(;;) {
+ thisTick=GetTickCount();
+ if(thisTick>startTick+100) break;
+ ptNow.x=ptStart.x+(ptEnd.x-ptStart.x)*(int)(thisTick-startTick)/100;
+ ptNow.y=ptStart.y+(ptEnd.y-ptStart.y)*(int)(thisTick-startTick)/100;
+ SetWindowPos(dat->opd[i].hwnd,0,ptNow.x,ptNow.y,0,0,SWP_NOZORDER|SWP_NOSIZE);
+ }
+ }
+ }
+ SetWindowPos(dat->opd[i].hwnd,HWND_TOP,(dat->rcDisplay.left+dat->rcDisplay.right-neww)>>1,(dat->rcDisplay.top+dat->rcDisplay.bottom-newh)>>1,neww,newh,0);
+ }
+ SaveOptionsTreeState(hdlg);
+ SendMessage(hdlg,DM_REBUILDPAGETREE,0,0);
+ break;
+ }
+ case IDCANCEL:
+ { int i;
+ PSHNOTIFY pshn;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=0;
+ pshn.hdr.code=PSN_RESET;
+ for(i=0;i<dat->pageCount;i++) {
+ if(dat->opd[i].hwnd==NULL || !dat->opd[i].changed) continue;
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+ DestroyWindow(hdlg);
+ break;
+ }
+ case IDOK:
+ case IDC_APPLY:
+ { int i;
+ PSHNOTIFY pshn;
+ EnableWindow(GetDlgItem(hdlg,IDC_APPLY),FALSE);
+ if(dat->currentPage!=(-1)) {
+ pshn.hdr.idFrom=0;
+ pshn.lParam=0;
+ pshn.hdr.code=PSN_KILLACTIVE;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ if(SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn))
+ break;
+ }
+
+ pshn.hdr.code=PSN_APPLY;
+ for(i=0;i<dat->pageCount;i++) {
+ if(dat->opd[i].hwnd==NULL || !dat->opd[i].changed) continue;
+ dat->opd[i].changed=0;
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ if(SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn)==PSNRET_INVALID_NOCHANGEPAGE) {
+ dat->hCurrentPage=dat->opd[i].hTreeItem;
+ TreeView_SelectItem(GetDlgItem(hdlg,IDC_PAGETREE),dat->hCurrentPage);
+ if(dat->currentPage!=(-1)) ShowWindow(dat->opd[dat->currentPage].hwnd,SW_HIDE);
+ dat->currentPage=i;
+ if (dat->currentPage != (-1)) ShowWindow(dat->opd[dat->currentPage].hwnd,SW_SHOW);
+ return 0;
+ } }
+
+ if ( LOWORD( wParam ) == IDOK )
+ DestroyWindow(hdlg);
+ break;
+ } }
+ break;
+ case WM_DESTROY:
+ SaveOptionsTreeState( hdlg );
+ if ( dat->currentPage != -1 ) {
+ if ( dat->opd[dat->currentPage].pszGroup )
+ DBWriteContactSettingTString( NULL, "Options", "LastGroup", dat->opd[dat->currentPage].pszGroup );
+ else DBDeleteContactSetting( NULL, "Options", "LastGroup" );
+ DBWriteContactSettingTString( NULL, "Options", "LastPage", dat->opd[dat->currentPage].pszTitle );
+ }
+ else {
+ DBDeleteContactSetting(NULL,"Options","LastGroup");
+ DBDeleteContactSetting(NULL,"Options","LastPage");
+ }
+ Utils_SaveWindowPosition(hdlg, NULL, "Options", "");
+ {
+ int i;
+ for(i=0;i<dat->pageCount;i++) {
+ if(dat->opd[i].hwnd!=NULL) DestroyWindow(dat->opd[i].hwnd);
+ if(dat->opd[i].pszGroup) mir_free(dat->opd[i].pszGroup);
+ if(dat->opd[i].pszTitle) mir_free(dat->opd[i].pszTitle);
+ if(dat->opd[i].pTemplate) mir_free(dat->opd[i].pTemplate);
+ } }
+ mir_free(dat->opd);
+ DeleteObject(dat->hBoldFont);
+ mir_free(dat);
+ hwndOptions=NULL;
+ break;
+ }
+ return FALSE;
+}
+
+static void OpenOptionsNow(const char *pszGroup,const char *pszPage)
+{
+ PROPSHEETHEADER psh;
+ struct OptionsPageInit opi;
+ int i;
+ OPENOPTIONSDIALOG ood;
+
+ if(IsWindow(hwndOptions)) {
+ ShowWindow(hwndOptions,SW_RESTORE);
+ SetForegroundWindow(hwndOptions);
+ return;
+ }
+ opi.pageCount=0;
+ opi.odp=NULL;
+ NotifyEventHooks(hOptionsInitEvent,(WPARAM)&opi,0);
+ if(opi.pageCount==0) return;
+
+ ZeroMemory(&psh,sizeof(psh));
+ psh.dwSize = sizeof(psh);
+ psh.dwFlags = PSH_PROPSHEETPAGE|PSH_NOAPPLYNOW;
+ psh.hwndParent = NULL;
+ psh.nPages = opi.pageCount;
+ ood.pszGroup=pszGroup;
+ ood.pszPage=pszPage;
+ psh.pStartPage = (LPCTSTR)&ood; //more structure misuse
+ psh.pszCaption = TranslateT("Miranda IM Options");
+ psh.ppsp = (PROPSHEETPAGE*)opi.odp; //blatent misuse of the structure, but what the hell
+ hwndOptions=CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_OPTIONS),NULL,OptionsDlgProc,(LPARAM)&psh);
+ for(i=0;i<opi.pageCount;i++) {
+ mir_free((char*)opi.odp[i].pszTitle);
+ if(opi.odp[i].pszGroup!=NULL) mir_free(opi.odp[i].pszGroup);
+ if((DWORD)opi.odp[i].pszTemplate&0xFFFF0000) mir_free((char*)opi.odp[i].pszTemplate);
+ }
+ mir_free(opi.odp);
+}
+
+static int OpenOptions(WPARAM wParam,LPARAM lParam)
+{
+ OPENOPTIONSDIALOG *ood=(OPENOPTIONSDIALOG*)lParam;
+ if(ood==NULL||ood->cbSize!=sizeof(OPENOPTIONSDIALOG)) return 1;
+ OpenOptionsNow(ood->pszGroup,ood->pszPage);
+ return 0;
+}
+
+static int OpenOptionsDialog(WPARAM wParam,LPARAM lParam)
+{
+ OpenOptionsNow(NULL,NULL);
+ return 0;
+}
+
+static int AddOptionsPage(WPARAM wParam,LPARAM lParam)
+{ OPTIONSDIALOGPAGE *odp=(OPTIONSDIALOGPAGE*)lParam, *dst;
+ struct OptionsPageInit *opi=(struct OptionsPageInit*)wParam;
+
+ if(odp==NULL||opi==NULL) return 1;
+ if(odp->cbSize!=sizeof(OPTIONSDIALOGPAGE) && odp->cbSize != OPTIONPAGE_OLD_SIZE) return 1;
+ opi->odp=(OPTIONSDIALOGPAGE*)mir_realloc(opi->odp,sizeof(OPTIONSDIALOGPAGE)*(opi->pageCount+1));
+ dst = opi->odp + opi->pageCount;
+ memset( dst, 0, sizeof( OPTIONSDIALOGPAGE ));
+ memcpy( dst, odp, odp->cbSize );
+
+ if ( odp->ptszTitle != NULL ) {
+ #if defined( _UNICODE )
+ if ( odp->flags & ODPF_UNICODE )
+ dst->ptszTitle = mir_wstrdup( TranslateW( odp->ptszTitle ));
+ else {
+ dst->ptszTitle = LangPackPcharToTchar( odp->pszTitle );
+ dst->flags |= ODPF_UNICODE;
+ }
+ #else
+ dst->pszTitle = mir_strdup( Translate( odp->pszTitle ));
+ #endif
+ }
+
+ if ( odp->pszGroup != NULL ) {
+ #if defined( _UNICODE )
+ if ( odp->flags & ODPF_UNICODE )
+ dst->ptszGroup = mir_wstrdup( TranslateW( odp->ptszGroup ));
+ else {
+ dst->ptszGroup = LangPackPcharToTchar( odp->pszGroup );
+ dst->flags |= ODPF_UNICODE;
+ }
+ #else
+ dst->pszGroup = mir_strdup( Translate( odp->pszGroup ));
+ #endif
+ }
+
+ if (( DWORD )odp->pszTemplate & 0xFFFF0000 )
+ dst->pszTemplate = mir_strdup( odp->pszTemplate );
+
+ opi->pageCount++;
+ return 0;
+}
+
+static int OptModulesLoaded(WPARAM wParam,LPARAM lParam)
+{
+ CLISTMENUITEM mi;
+
+ ZeroMemory(&mi,sizeof(mi));
+ mi.cbSize=sizeof(mi);
+ mi.flags=0;
+ mi.hIcon=LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_OPTIONS));
+ mi.position=1900000000;
+ mi.pszName=Translate("&Options...");
+ mi.pszService="Options/OptionsCommand";
+ CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi);
+ return 0;
+}
+
+int ShutdownOptionsModule(WPARAM wParam,LPARAM lParam)
+{
+ if (IsWindow(hwndOptions)) DestroyWindow(hwndOptions);
+ hwndOptions=NULL;
+ return 0;
+}
+
+int LoadOptionsModule(void)
+{
+ hwndOptions=NULL;
+ hOptionsInitEvent=CreateHookableEvent(ME_OPT_INITIALISE);
+ CreateServiceFunction(MS_OPT_ADDPAGE,AddOptionsPage);
+ CreateServiceFunction(MS_OPT_OPENOPTIONS,OpenOptions);
+ CreateServiceFunction("Options/OptionsCommand",OpenOptionsDialog);
+ HookEvent(ME_SYSTEM_MODULESLOADED,OptModulesLoaded);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN,ShutdownOptionsModule);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/plugins/newplugins.c b/miranda-wine/src/modules/plugins/newplugins.c
new file mode 100644
index 0000000..3f4ee31
--- /dev/null
+++ b/miranda-wine/src/modules/plugins/newplugins.c
@@ -0,0 +1,815 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2005 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "../database/dblists.h"
+
+// block these plugins
+#define DEFMOD_REMOVED_UIPLUGINOPTS 21
+
+// basic export prototypes
+typedef int (__cdecl * Miranda_Plugin_Load) ( PLUGINLINK * );
+typedef int (__cdecl * Miranda_Plugin_Unload) ( void );
+// version control
+typedef PLUGININFO * (__cdecl * Miranda_Plugin_Info) ( DWORD mirandaVersion );
+// prototype for databases
+typedef DATABASELINK * (__cdecl * Database_Plugin_Info) ( void * reserved );
+// prototype for clists
+typedef int (__cdecl * CList_Initialise) ( PLUGINLINK * );
+// prototype for protocol plugins?
+
+typedef struct { // can all be NULL
+ HINSTANCE hInst;
+ Miranda_Plugin_Load Load;
+ Miranda_Plugin_Unload Unload;
+ Miranda_Plugin_Info Info;
+ Database_Plugin_Info DbInfo;
+ CList_Initialise clistlink;
+ PLUGININFO * pluginInfo; // must be freed if hInst==NULL then its a copy
+ DATABASELINK * dblink; // only valid during module being in memory
+} BASIC_PLUGIN_INFO;
+
+#define PCLASS_FAILED 0x1 // not a valid plugin, or API is invalid, pluginname is valid
+#define PCLASS_BASICAPI 0x2 // has Load, Unload, MirandaPluginInfo() -> PLUGININFO seems valid, this dll is in memory.
+#define PCLASS_DB 0x4 // has DatabasePluginInfo() and is valid as can be, and PCLASS_BASICAPI has to be set too
+#define PCLASS_LAST 0x8 // this plugin should be unloaded after everything else
+#define PCLASS_OK 0x10 // plugin should be loaded, if DB means nothing
+#define PCLASS_LOADED 0x20 // Load() has been called, Unload() should be called.
+#define PCLASS_STOPPED 0x40 // wasn't loaded cos plugin name not on white list
+#define PCLASS_CLIST 0x80 // a CList implementation
+
+typedef struct pluginEntry {
+ char pluginname[64];
+ unsigned int pclass; // PCLASS_*
+ BASIC_PLUGIN_INFO bpi;
+ struct pluginEntry * nextclass;
+} pluginEntry;
+
+SortedList pluginList = { 0 }, pluginListAddr = { 0 };
+
+PLUGINLINK pluginCoreLink;
+char mirandabootini[MAX_PATH];
+static DWORD mirandaVersion;
+static pluginEntry * pluginListDb;
+static pluginEntry * pluginListUI;
+static pluginEntry * pluginList_png2dib = NULL;
+static HANDLE hPluginListHeap = NULL;
+static pluginEntry * pluginDefModList[DEFMOD_HIGHEST+1]; // do not free this memory
+static int askAboutIgnoredPlugins;
+
+int InitIni(void);
+void UninitIni(void);
+
+#define PLUGINDISABLELIST "PluginDisable"
+
+void KillModuleEventHooks( HINSTANCE );
+void KillModuleServices( HINSTANCE );
+
+int LoadDatabaseModule(void);
+void ListView_SetItemTextA( HWND hwndLV, int i, int iSubItem, char* pszText );
+
+void ListView_GetItemTextA( HWND hwndLV, int i, int iSubItem, char* pszText, size_t cchTextMax )
+{
+ LV_ITEMA ms_lvi;
+ ms_lvi.iSubItem = iSubItem;
+ ms_lvi.cchTextMax = cchTextMax;
+ ms_lvi.pszText = pszText;
+ SendMessageA( hwndLV, LVM_GETITEMTEXTA, i, (LPARAM)&ms_lvi);
+}
+
+HINSTANCE GetInstByAddress( void* codePtr )
+{
+ int idx;
+ HINSTANCE result;
+ pluginEntry p; p.bpi.hInst = codePtr;
+
+ if ( pluginListAddr.realCount == 0 )
+ return NULL;
+
+ List_GetIndex( &pluginListAddr, &p, &idx );
+ if ( idx > 0 )
+ idx--;
+
+ result = (( pluginEntry* )( pluginListAddr.items[idx] ))->bpi.hInst;
+ if ( idx == 0 && codePtr < ( void* )result )
+ return NULL;
+
+ return result;
+}
+
+// returns true if the API exports were good, otherwise, passed in data is returned
+#define CHECKAPI_NONE 0
+#define CHECKAPI_DB 1
+#define CHECKAPI_CLIST 2
+static int checkAPI(char * plugin, BASIC_PLUGIN_INFO * bpi, DWORD mirandaVersion, int checkTypeAPI, int * exports)
+{
+ HINSTANCE h = NULL;
+ // this is evil but these plugins are buggy/old and people are blaming Miranda
+ {
+ char * p = strrchr(plugin,'\\');
+ if ( p != NULL && ++p ) {
+ if ( lstrcmpiA(p,"autoloadavatars.dll")==0 || lstrcmpiA(p,"multiwindow.dll")==0 ) return 0;
+ }
+ }
+ h = LoadLibraryA(plugin);
+ if ( h == NULL ) return 0;
+ // loaded, check for exports
+ bpi->Load = (Miranda_Plugin_Load) GetProcAddress(h, "Load");
+ bpi->Unload = (Miranda_Plugin_Unload) GetProcAddress(h, "Unload");
+ bpi->Info = (Miranda_Plugin_Info) GetProcAddress(h, "MirandaPluginInfo");
+ // if they were present
+ if ( bpi->Load && bpi->Unload && bpi->Info )
+ {
+ PLUGININFO * pi = bpi->Info(mirandaVersion);
+ if ( pi && pi->cbSize==sizeof(PLUGININFO) && pi->shortName && pi->description
+ && pi->author && pi->authorEmail && pi->copyright && pi->homepage
+ && pi->replacesDefaultModule <= DEFMOD_HIGHEST
+ && pi->replacesDefaultModule != DEFMOD_REMOVED_UIPLUGINOPTS)
+ {
+ bpi->pluginInfo = pi;
+ // basic API is present
+ if ( checkTypeAPI == CHECKAPI_NONE ) {
+ bpi->hInst=h;
+ return 1;
+ }
+ // check for DB?
+ if ( checkTypeAPI == CHECKAPI_DB ) {
+ bpi->DbInfo = (Database_Plugin_Info) GetProcAddress(h, "DatabasePluginInfo");
+ if ( bpi->DbInfo ) {
+ // fetch internal database function pointers
+ bpi->dblink = bpi->DbInfo(NULL);
+ // validate returned link structure
+ if ( bpi->dblink && bpi->dblink->cbSize==sizeof(DATABASELINK) ) {
+ bpi->hInst=h;
+ return 1;
+ }
+ // had DB exports
+ if ( exports != NULL ) *exports=1;
+ } //if
+ } //if
+
+ // check clist ?
+ if ( checkTypeAPI == CHECKAPI_CLIST ) {
+ bpi->clistlink = (CList_Initialise) GetProcAddress(h, "CListInitialise");
+ #if defined( _UNICODE )
+ if ( pi->isTransient == UNICODE_AWARE )
+ #endif
+ if ( bpi->clistlink ) {
+ // nothing more can be done here, this export is a load function
+ bpi->hInst=h;
+ if ( exports != NULL ) *exports=1;
+ return 1;
+ }
+ }
+ } // if
+ if ( exports != NULL ) *exports=1;
+ } //if
+ // not found, unload
+ FreeLibrary(h);
+ return 0;
+}
+
+// returns true if the given file is <anything>.dll exactly
+static int valid_library_name(char * name)
+{
+ char * dot = strrchr(name, '.');
+ if ( dot != NULL && lstrcmpiA(dot+1,"dll") == 0) {
+ if ( dot[4] == 0 ) return 1;
+ }
+ return 0;
+}
+
+// returns true if the given file matches dbx_*.dll, which is used to LoadLibrary()
+static int validguess_db_name(char * name)
+{
+ int rc=0;
+ // this is ONLY SAFE because name -> ffd.cFileName == MAX_PATH
+ char x = name[4];
+ name[4]=0;
+ rc=lstrcmpiA(name,"dbx_") == 0;
+ name[4]=x;
+ return rc;
+}
+
+// returns true if the given file matches clist_*.dll
+static int validguess_clist_name(char * name)
+{
+ int rc=0;
+ // argh evil
+ char x = name[6];
+ name[6]=0;
+ rc=lstrcmpiA(name,"clist_") == 0;
+ name[6]=x;
+ return rc;
+}
+
+// perform any API related tasks to freeing
+static void Plugin_Uninit(pluginEntry * p)
+{
+ // if it was an installed database plugin, call its unload
+ if ( p->pclass & PCLASS_DB )
+ p->bpi.dblink->Unload( p->pclass & PCLASS_OK );
+
+ // if the basic API check had passed, call Unload if Load() was ever called
+ if ( p->pclass & PCLASS_LOADED )
+ p->bpi.Unload();
+
+ // release the library
+ if ( p->bpi.hInst != NULL ) {
+ // we need to kill all resources which belong to that DLL before calling FreeLibrary
+ KillModuleEventHooks( p->bpi.hInst );
+ KillModuleServices( p->bpi.hInst );
+
+ FreeLibrary( p->bpi.hInst );
+ ZeroMemory( &p->bpi, sizeof( p->bpi ));
+ }
+ List_RemovePtr( &pluginList, p );
+ List_RemovePtr( &pluginListAddr, p );
+}
+
+typedef BOOL (*SCAN_PLUGINS_CALLBACK) ( WIN32_FIND_DATAA * fd, char * path, WPARAM wParam, LPARAM lParam );
+
+static void enumPlugins(SCAN_PLUGINS_CALLBACK cb, WPARAM wParam, LPARAM lParam)
+{
+ char exe[MAX_PATH];
+ char search[MAX_PATH];
+ char * p = 0;
+ // get miranda's exe path
+ GetModuleFileNameA(NULL, exe, SIZEOF(exe));
+ // find the last \ and null it out, this leaves no trailing slash
+ p = strrchr(exe, '\\');
+ if ( p ) *p=0;
+ // create the search filter
+ mir_snprintf(search,SIZEOF(search),"%s\\Plugins\\*.dll", exe);
+ {
+ // FFFN will return filenames for things like dot dll+ or dot dllx
+ HANDLE hFind=INVALID_HANDLE_VALUE;
+ WIN32_FIND_DATAA ffd;
+ hFind = FindFirstFileA(search, &ffd);
+ if ( hFind != INVALID_HANDLE_VALUE ) {
+ do {
+ if ( !(ffd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) && valid_library_name(ffd.cFileName) )
+ {
+ cb(&ffd,exe,wParam,lParam);
+ } //if
+ } while ( FindNextFileA(hFind, &ffd) );
+ FindClose(hFind);
+ } //if
+ }
+}
+
+// this is called by the db module to return all DBs plugins, then when it finds the one it likes the others are unloaded
+static int PluginsEnum(WPARAM wParam, LPARAM lParam)
+{
+ PLUGIN_DB_ENUM * de = (PLUGIN_DB_ENUM *) lParam;
+ pluginEntry * x = pluginListDb;
+ if ( de == NULL || de->cbSize != sizeof(PLUGIN_DB_ENUM) || de->pfnEnumCallback == NULL ) return 1;
+ while ( x != NULL ) {
+ int rc = de->pfnEnumCallback(x->pluginname, x->bpi.dblink, de->lParam);
+ if ( rc == DBPE_DONE ) {
+ // this db has been picked, get rid of all the others
+ pluginEntry * y = pluginListDb, * n;
+ while ( y != NULL ) {
+ n = y->nextclass;
+ if ( x != y )
+ Plugin_Uninit(y);
+ y = n;
+ } // while
+ x->pclass |= PCLASS_LOADED | PCLASS_OK | PCLASS_LAST;
+ return 0;
+ }
+ else if ( rc == DBPE_HALT ) return 1;
+ x = x->nextclass;
+ } // while
+ return pluginListDb != NULL ? 1 : -1;
+}
+
+static int PluginsGetDefaultArray(WPARAM wParam, LPARAM lParam)
+{
+ return (int) &pluginDefModList;
+}
+
+// called in the first pass to create pluginEntry* structures and validate database plugins
+static BOOL scanPluginsDir (WIN32_FIND_DATAA * fd, char * path, WPARAM wParam, LPARAM lParam )
+{
+ int isdb = validguess_db_name(fd->cFileName);
+ BASIC_PLUGIN_INFO bpi;
+ pluginEntry * p = HeapAlloc(hPluginListHeap, HEAP_NO_SERIALIZE|HEAP_ZERO_MEMORY, sizeof(pluginEntry));
+ strncpy(p->pluginname, fd->cFileName, SIZEOF(p->pluginname));
+ // plugin name suggests its a db module, load it right now
+ if ( isdb ) {
+ char buf[MAX_PATH];
+ mir_snprintf(buf,SIZEOF(buf),"%s\\Plugins\\%s", path, fd->cFileName);
+ if ( checkAPI(buf, &bpi, mirandaVersion, CHECKAPI_DB, NULL) ) {
+ // db plugin is valid
+ p->pclass |= (PCLASS_DB|PCLASS_BASICAPI);
+ // copy the dblink stuff
+ p->bpi=bpi;
+ // keep a faster list.
+ if ( pluginListDb != NULL ) p->nextclass=pluginListDb;
+ pluginListDb=p;
+ }
+ else {
+ // didn't have basic APIs or DB exports - failed.
+ p->pclass |= PCLASS_FAILED;
+ }
+ }
+ else if ( validguess_clist_name(fd->cFileName) ) {
+ // keep a note of this plugin for later
+ if ( pluginListUI != NULL ) p->nextclass=pluginListUI;
+ pluginListUI=p;
+ p->pclass |= PCLASS_CLIST;
+ }
+ else if ( lstrcmpiA(fd->cFileName, "png2dib.dll") == 0)
+ pluginList_png2dib = p;
+
+ // add it to the list
+ List_InsertPtr( &pluginList, p );
+ return TRUE;
+}
+
+static void SetPluginOnWhiteList(char * pluginname, int allow)
+{
+ DBWriteContactSettingByte(NULL, PLUGINDISABLELIST, pluginname, (BYTE)(allow ? 0 : 1));
+}
+
+// returns 1 if the plugin should be enabled within this profile, filename is always lower case
+static int isPluginOnWhiteList(char * pluginname)
+{
+ int rc = DBGetContactSettingByte(NULL, PLUGINDISABLELIST, pluginname, 0);
+ if ( rc != 0 && askAboutIgnoredPlugins ) {
+ char buf[256];
+ mir_snprintf(buf,SIZEOF(buf),Translate("'%s' is disabled, re-enable?"),pluginname);
+ if ( MessageBoxA(NULL,buf,Translate("Re-enable Miranda plugin?"),MB_YESNO|MB_ICONQUESTION) == IDYES ) {
+ SetPluginOnWhiteList(pluginname, 1);
+ return 1;
+ } }
+
+ return rc == 0;
+}
+
+static pluginEntry* getCListModule(char * exe, char * slice, int useWhiteList)
+{
+ pluginEntry * p = pluginListUI;
+ BASIC_PLUGIN_INFO bpi;
+ while ( p != NULL )
+ {
+ mir_snprintf(slice, &exe[MAX_PATH] - slice, "\\Plugins\\%s", p->pluginname);
+ CharLowerA(p->pluginname);
+ if ( useWhiteList ? isPluginOnWhiteList(p->pluginname) : 1 ) {
+ if ( checkAPI(exe, &bpi, mirandaVersion, CHECKAPI_CLIST, NULL) ) {
+ p->bpi = bpi;
+ p->pclass |= PCLASS_LAST | PCLASS_OK | PCLASS_BASICAPI;
+ if ( bpi.clistlink(&pluginCoreLink) == 0 ) {
+ p->bpi=bpi;
+ p->pclass |= PCLASS_LOADED;
+ return p;
+ }
+ else Plugin_Uninit( p );
+ } //if
+ } //if
+ p = p->nextclass;
+ }
+ return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+//
+// Event hook to unload all non-core plugins
+// hooked very late, after all the internal plugins, blah
+
+static int UnloadNewPlugins(WPARAM wParam, LPARAM lParam)
+{
+ int i;
+
+ // unload everything but the special db/clist plugins
+ for ( i = pluginList.realCount-1; i >= 0; i-- ) {
+ pluginEntry* p = pluginList.items[i];
+ if ( !(p->pclass & PCLASS_LAST) && (p->pclass & PCLASS_OK))
+ Plugin_Uninit( p );
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+//
+// Plugins options page dialog
+
+static BOOL dialogListPlugins(WIN32_FIND_DATAA * fd, char * path, WPARAM wParam, LPARAM lParam)
+{
+ LVITEMA it;
+ int iRow;
+ HWND hwndList=(HWND)lParam;
+ BASIC_PLUGIN_INFO pi;
+ int exports=0;
+ char buf[MAX_PATH];
+ int isdb = 0;
+ HINSTANCE gModule=NULL;
+ mir_snprintf(buf,SIZEOF(buf),"%s\\Plugins\\%s",path,fd->cFileName);
+ CharLowerA(fd->cFileName);
+ gModule=GetModuleHandleA(buf);
+ if ( checkAPI(buf, &pi, mirandaVersion, CHECKAPI_NONE, &exports) == 0 ) {
+ // failed to load anything, but if exports were good, show some info.
+ return TRUE;
+ }
+ isdb = pi.pluginInfo->replacesDefaultModule == DEFMOD_DB;
+ ZeroMemory(&it, sizeof(it));
+ it.mask=LVIF_TEXT | LVIF_PARAM;
+ it.pszText = Translate(fd->cFileName);
+ it.lParam=(LPARAM)pi.pluginInfo->replacesDefaultModule;
+ iRow=SendMessageA( hwndList, LVM_INSERTITEMA, 0, (LPARAM)&it );
+ if ( isPluginOnWhiteList(fd->cFileName) ) ListView_SetItemState(hwndList, iRow, !isdb ? 0x2000 : 0x3000, 0xF000);
+ if ( iRow != (-1) ) {
+ ListView_SetItemTextA(hwndList, iRow, 1, pi.pluginInfo->shortName);
+ mir_snprintf(buf,SIZEOF(buf),"%d.%d.%d.%d", HIBYTE(HIWORD(pi.pluginInfo->version)), LOBYTE(HIWORD(pi.pluginInfo->version)), HIBYTE(LOWORD(pi.pluginInfo->version)), LOBYTE(LOWORD(pi.pluginInfo->version)));
+ ListView_SetItemTextA(hwndList, iRow, 2, buf);
+ ListView_SetItemText(hwndList, iRow, 3, TranslateTS( gModule != NULL ? _T("Yes"):_T("No") ));
+ ListView_SetItemTextA(hwndList, iRow, 4, pi.pluginInfo->author);
+ ListView_SetItemTextA(hwndList, iRow, 5, pi.pluginInfo->authorEmail);
+ ListView_SetItemTextA(hwndList, iRow, 6, pi.pluginInfo->description);
+ ListView_SetItemTextA(hwndList, iRow, 7, pi.pluginInfo->copyright);
+ ListView_SetItemTextA(hwndList, iRow, 8, pi.pluginInfo->homepage);
+ }
+ FreeLibrary(pi.hInst);
+ return TRUE;
+}
+
+static LRESULT CALLBACK ListView_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ WNDPROC proc=(WNDPROC)GetWindowLong(hwnd,GWL_USERDATA);
+ if ( msg == WM_WINDOWPOSCHANGING ) ShowScrollBar(hwnd,SB_HORZ,FALSE);
+ return CallWindowProc(proc,hwnd,msg,wParam,lParam);
+}
+
+static TCHAR* PluginCutCopyright(TCHAR * buf)
+{
+ /* Some plugins include (C,c)opyright, which is fine but it looks stupid in the UI */
+ TCHAR tmp[16];
+ _tcsncpy(tmp, buf, 9);
+ tmp[9]=0;
+ if ( lstrcmpi( tmp, _T("copyright")) == 0 ) return buf+10;
+ return buf;
+}
+
+static BOOL CALLBACK DlgPluginOpt(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ HWND hwndList=GetDlgItem(hwndDlg,IDC_PLUGLIST);
+ LVCOLUMN col;
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLong(hwndList,GWL_USERDATA, SetWindowLong(hwndList,GWL_WNDPROC, (LONG)ListView_WndProc));
+ col.mask=LVCF_TEXT|LVCF_WIDTH;
+ col.pszText=TranslateT("Plugin");
+ col.cx=75;
+ ListView_InsertColumn(hwndList,0,&col);
+
+ col.pszText=TranslateT("Name");
+ ListView_InsertColumn(hwndList,1,&col);
+
+ col.pszText=TranslateT("Version");
+ col.cx=60;
+ ListView_InsertColumn(hwndList,2,&col);
+
+ col.pszText=TranslateT("Running");
+ col.cx=1000;
+ ListView_InsertColumn(hwndList,3,&col);
+
+ col.pszText=TranslateT("Author");
+ ListView_InsertColumn(hwndList,4,&col);
+
+ col.pszText=TranslateT("e-mail");
+ ListView_InsertColumn(hwndList,5,&col);
+
+ col.pszText=TranslateT("Description");
+ ListView_InsertColumn(hwndList,6,&col);
+
+ col.pszText=TranslateT("Copyright");
+ ListView_InsertColumn(hwndList,7,&col);
+
+ col.pszText=TranslateT("Homepage");
+ ListView_InsertColumn(hwndList,8,&col);
+
+ // XXX: Won't work on windows 95 without IE3+ or 4.70
+ ListView_SetExtendedListViewStyleEx(hwndList, 0, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT );
+ // scan the plugin dir for plugins, cos
+ enumPlugins(dialogListPlugins,(WPARAM)hwndDlg,(LPARAM)hwndList);
+ // sort out the headers
+ ListView_SetColumnWidth(hwndList, 0, LVSCW_AUTOSIZE); // dll name
+ ListView_SetColumnWidth(hwndList, 1, LVSCW_AUTOSIZE); // short name
+ return TRUE;
+ }
+ case WM_NOTIFY:
+ {
+ NMLISTVIEW * hdr = (NMLISTVIEW *) lParam;
+ if ( hdr && hdr->hdr.code == LVN_ITEMCHANGED && hdr->uOldState != 0
+ && (hdr->uNewState == 0x1000 || hdr->uNewState == 0x2000 ) && IsWindowVisible(hdr->hdr.hwndFrom) ) {
+ HWND hwndList=GetDlgItem(hwndDlg,IDC_PLUGLIST);
+ LVITEM it;
+ int iRow;
+ ZeroMemory(&it,sizeof(it));
+ it.mask=LVIF_PARAM | LVIF_STATE;
+ it.iItem = hdr->iItem;
+ if ( ListView_GetItem(hwndList,&it) && it.lParam == DEFMOD_DB ) {
+ ListView_SetItemState(hwndList, hdr->iItem, 0x3000, 0xF000);
+ return FALSE;
+ }
+ // if enabling and replaces, find all other replaces and toggle off
+ if ( hdr->uNewState&0x2000 && it.lParam ) {
+ for ( iRow=0; iRow != (-1); ) {
+ if ( iRow != hdr->iItem ) {
+ LVITEM dt;
+ dt.mask = LVIF_PARAM;
+ dt.iItem = iRow;
+ if ( ListView_GetItem(hwndList,&dt) && dt.lParam == it.lParam ) {
+ // the lParam is unset, so when the check is unset the clist block doesnt trigger
+ LPARAM lParam = dt.lParam;
+ dt.lParam = 0;
+ ListView_SetItem(hwndList, &dt);
+ ListView_SetItemState(hwndList, iRow, 0x1000, 0xF000);
+ dt.lParam = lParam;
+ ListView_SetItem(hwndList, &dt);
+ }
+ }
+ iRow=ListView_GetNextItem(hwndList, iRow, LVNI_ALL);
+ }
+ }
+ ShowWindow(GetDlgItem(hwndDlg, IDC_RESTART), TRUE);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ if ( hdr && hdr->hdr.code == LVN_ITEMCHANGED && IsWindowVisible(hdr->hdr.hwndFrom) && hdr->iItem != -1 ) {
+ TCHAR buf[1024];
+ int sel = hdr->uNewState&LVIS_SELECTED;
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_PLUGLIST);
+ // frame/about
+ ListView_GetItemText(hwndList, hdr->iItem, 1, buf, SIZEOF(buf));
+ SetWindowText(GetDlgItem(hwndDlg,IDC_PLUGININFOFRAME),sel ? buf : _T(""));
+ // author
+ ListView_GetItemText(hwndList, hdr->iItem, 4, buf, SIZEOF(buf));
+ SetWindowText(GetDlgItem(hwndDlg,IDC_PLUGINAUTHOR), sel ? buf : _T(""));
+ // author email
+ ListView_GetItemText(hwndList, hdr->iItem, 5, buf, SIZEOF(buf));
+ SetWindowText(GetDlgItem(hwndDlg,IDC_PLUGINEMAIL), sel ? buf : _T(""));
+ // description
+ ListView_GetItemText(hwndList, hdr->iItem, 6, buf, SIZEOF(buf));
+ SetWindowText(GetDlgItem(hwndDlg,IDC_PLUGINLONGINFO), sel ? buf : _T(""));
+ // copyright
+ ListView_GetItemText(hwndList, hdr->iItem, 7, buf, SIZEOF(buf));
+ SetWindowText(GetDlgItem(hwndDlg,IDC_PLUGINCPYR), sel ? PluginCutCopyright(buf) : _T(""));
+ // homepage
+ ListView_GetItemText(hwndList, hdr->iItem, 8, buf, SIZEOF(buf));
+ SetWindowText(GetDlgItem(hwndDlg,IDC_PLUGINURL), sel ? buf : _T(""));
+ }
+ if ( hdr && hdr->hdr.code == PSN_APPLY ) {
+ HWND hwndList=GetDlgItem(hwndDlg,IDC_PLUGLIST);
+ int iRow;
+ int iState;
+ char buf[1024];
+ for (iRow=0 ; iRow != (-1) ; ) {
+ ListView_GetItemTextA(hwndList, iRow, 0, buf, SIZEOF(buf));
+ iState=ListView_GetItemState(hwndList, iRow, LVIS_STATEIMAGEMASK);
+ SetPluginOnWhiteList(buf, iState&0x2000 ? 1 : 0);
+ iRow=ListView_GetNextItem(hwndList, iRow, LVNI_ALL);
+ } }
+ break;
+ }
+ case WM_COMMAND:
+ {
+ if ( HIWORD(wParam) == STN_CLICKED ) {
+ switch (LOWORD(wParam)) {
+ case IDC_PLUGINEMAIL:
+ case IDC_PLUGINURL:
+ {
+ char buf[512];
+ char * p = &buf[7];
+ lstrcpyA(buf,"mailto:");
+ if ( GetWindowTextA(GetDlgItem(hwndDlg, LOWORD(wParam)), p, SIZEOF(buf) - 7) ) {
+ CallService(MS_UTILS_OPENURL,0,(LPARAM) (LOWORD(wParam)==IDC_PLUGINEMAIL ? buf : p) );
+ }
+ break;
+ }
+ } // switch
+ }
+ break;
+ }
+ }
+ return FALSE;
+}
+
+static int PluginOptionsInit(WPARAM wParam, LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.hInstance = GetModuleHandle(NULL);
+ odp.pfnDlgProc = DlgPluginOpt;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_PLUGINS);
+ odp.position = 1300000000;
+ odp.pszTitle = "Plugins";
+ odp.flags = ODPF_BOLDGROUPS;
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+//
+// Loads all plugins
+
+int LoadNewPluginsModule(void)
+{
+ char exe[MAX_PATH];
+ char* slice;
+ pluginEntry* p;
+ pluginEntry* clist = NULL;
+ int useWhiteList, i;
+
+ // make full path to the plugin
+ GetModuleFileNameA(NULL, exe, SIZEOF(exe));
+ slice=strrchr(exe, '\\');
+ if ( slice != NULL )
+ *slice=0;
+
+ // remember some useful options
+ askAboutIgnoredPlugins=(UINT) GetPrivateProfileIntA( "PluginLoader", "AskAboutIgnoredPlugins", 0, mirandabootini);
+
+ // if png2dib is present, load it to provide the basic core functions
+ if ( pluginList_png2dib != NULL ) {
+ BASIC_PLUGIN_INFO bpi;
+ mir_snprintf(slice,&exe[SIZEOF(exe)] - slice, "\\Plugins\\%s", pluginList_png2dib->pluginname);
+ if ( checkAPI(exe, &bpi, mirandaVersion, CHECKAPI_NONE, NULL) ) {
+ pluginList_png2dib->bpi = bpi;
+ pluginList_png2dib->pclass |= PCLASS_OK | PCLASS_BASICAPI;
+ if ( bpi.Load(&pluginCoreLink) == 0 )
+ pluginList_png2dib->pclass |= PCLASS_LOADED;
+ else
+ Plugin_Uninit( pluginList_png2dib );
+ } }
+
+ // first load the clist cos alot of plugins need that to be present at Load()
+ for ( useWhiteList = 1; useWhiteList >= 0 && clist == NULL; useWhiteList-- )
+ clist=getCListModule(exe, slice, useWhiteList);
+ /* the loop above will try and get one clist DLL to work, if all fail then just bail now */
+ if ( clist == NULL ) {
+ // result = 0, no clist_* can be found
+ if ( pluginListUI )
+ MessageBox(0, TranslateT("Unable to start any of the installed contact list plugins, I even ignored your preferences for which contact list couldn't load any."), _T(""), MB_OK | MB_ICONINFORMATION);
+ else
+ MessageBox(0, TranslateT("Can't find a contact list plugin! you need clist_classic or clist_mw.") , _T(""), MB_OK | MB_ICONINFORMATION);
+ return 1;
+ }
+
+ /* enable and disable as needed */
+ p=pluginListUI;
+ while ( p != NULL ) {
+ SetPluginOnWhiteList(p->pluginname, clist != p ? 0 : 1 );
+ p = p->nextclass;
+ }
+ /* now loop thru and load all the other plugins, do this in one pass */
+
+ for ( i=0; i < pluginList.realCount; i++ ) {
+ p = pluginList.items[i];
+ CharLowerA(p->pluginname);
+ if ( !(p->pclass&PCLASS_LOADED) && !(p->pclass&PCLASS_DB)
+ && !(p->pclass&PCLASS_CLIST) && isPluginOnWhiteList(p->pluginname) ) {
+ BASIC_PLUGIN_INFO bpi;
+ mir_snprintf(slice,&exe[SIZEOF(exe)] - slice, "\\Plugins\\%s", p->pluginname);
+ if ( checkAPI(exe, &bpi, mirandaVersion, CHECKAPI_NONE, NULL) ) {
+ int rm = bpi.pluginInfo->replacesDefaultModule;
+ p->bpi = bpi;
+ p->pclass |= PCLASS_OK | PCLASS_BASICAPI;
+
+ List_InsertPtr( &pluginListAddr, p );
+
+ if ( pluginDefModList[rm] == NULL ) {
+ if ( bpi.Load(&pluginCoreLink) == 0 ) p->pclass |= PCLASS_LOADED;
+ else {
+ Plugin_Uninit( p );
+ i--;
+ }
+ if ( rm ) pluginDefModList[rm]=p;
+ } //if
+ else {
+ SetPluginOnWhiteList( p->pluginname, 0 );
+ Plugin_Uninit( p );
+ i--;
+ }
+ }
+ else p->pclass |= PCLASS_FAILED;
+ } }
+
+ // hook shutdown after everything
+ HookEvent(ME_SYSTEM_SHUTDOWN, UnloadNewPlugins);
+ HookEvent(ME_OPT_INITIALISE, PluginOptionsInit);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+//
+// Plugins module initialization
+// called before anything real is loaded, incl. database
+
+static int sttComparePlugins( pluginEntry* p1, pluginEntry* p2 )
+{ return ( int )( p1->bpi.hInst - p2->bpi.hInst );
+}
+
+static int sttComparePluginsByName( pluginEntry* p1, pluginEntry* p2 )
+{ return lstrcmpA( p1->pluginname, p2->pluginname );
+}
+
+int LoadNewPluginsModuleInfos(void)
+{
+ pluginList.increment = 10;
+ pluginList.sortFunc = sttComparePluginsByName;
+
+ pluginListAddr.increment = 10;
+ pluginListAddr.sortFunc = sttComparePlugins;
+
+ hPluginListHeap=HeapCreate(HEAP_NO_SERIALIZE, 0, 0);
+ mirandaVersion = (DWORD)CallService(MS_SYSTEM_GETVERSION, 0, 0);
+ //
+ CreateServiceFunction(MS_PLUGINS_ENUMDBPLUGINS, PluginsEnum);
+ CreateServiceFunction(MS_PLUGINS_GETDISABLEDEFAULTARRAY, PluginsGetDefaultArray);
+ // make sure plugins can get internal core APIs
+ pluginCoreLink.CallService=CallService;
+ pluginCoreLink.ServiceExists=ServiceExists;
+ pluginCoreLink.CreateServiceFunction=CreateServiceFunction;
+ pluginCoreLink.CreateTransientServiceFunction=CreateServiceFunction;
+ pluginCoreLink.DestroyServiceFunction=DestroyServiceFunction;
+ pluginCoreLink.CreateHookableEvent=CreateHookableEvent;
+ pluginCoreLink.DestroyHookableEvent=DestroyHookableEvent;
+ pluginCoreLink.HookEvent=HookEvent;
+ pluginCoreLink.HookEventMessage=HookEventMessage;
+ pluginCoreLink.UnhookEvent=UnhookEvent;
+ pluginCoreLink.NotifyEventHooks=NotifyEventHooks;
+ pluginCoreLink.SetHookDefaultForHookableEvent=SetHookDefaultForHookableEvent;
+ pluginCoreLink.CallServiceSync=CallServiceSync;
+ pluginCoreLink.CallFunctionAsync=CallFunctionAsync;
+ // remember where the mirandaboot.ini goes
+ {
+ char exe[MAX_PATH];
+ char * slice;
+ GetModuleFileNameA(NULL, exe, SIZEOF(exe));
+ slice=strrchr(exe, '\\');
+ if ( slice != NULL ) *slice=0;
+ mir_snprintf(mirandabootini, SIZEOF(mirandabootini), "%s\\mirandaboot.ini", exe);
+ }
+ // look for all *.dll's
+ enumPlugins(scanPluginsDir, 0, 0);
+ // the database will select which db plugin to use, or fail if no profile is selected
+ if (LoadDatabaseModule()) return 1;
+ InitIni();
+ // could validate the plugin entries here but internal modules arent loaded so can't call Load() in one pass
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+//
+// Plugins module unloading
+// called at the end of module chain unloading, just modular engine left at this point
+
+int UnloadNewPluginsModule(void)
+{
+ int i;
+
+ // unload everything but the DB
+ for ( i = pluginList.realCount-1; i >= 0; i-- ) {
+ pluginEntry* p = pluginList.items[i];
+ if ( !(p->pclass & PCLASS_DB) )
+ Plugin_Uninit( p );
+ }
+
+ // unload the DB
+ for ( i = pluginList.realCount-1; i >= 0; i-- ) {
+ pluginEntry * p = pluginList.items[i];
+ Plugin_Uninit( p );
+ }
+
+ if ( hPluginListHeap ) HeapDestroy(hPluginListHeap);
+ hPluginListHeap=0;
+
+ List_Destroy( &pluginList );
+ List_Destroy( &pluginListAddr );
+ UninitIni();
+ return 0;
+}
diff --git a/miranda-wine/src/modules/protocols/protochains.c b/miranda-wine/src/modules/protocols/protochains.c
new file mode 100644
index 0000000..e36d95d
--- /dev/null
+++ b/miranda-wine/src/modules/protocols/protochains.c
@@ -0,0 +1,225 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include <m_protomod.h>
+
+int Proto_IsProtocolLoaded(WPARAM wParam,LPARAM lParam);
+
+//Protocol chain is list of integers "0".."n", with network protocol named "p"
+static int Proto_CallContactService(WPARAM wParam,LPARAM lParam)
+//note that this is ChainSend() too, due to a quirk of function definitions
+{
+ CCSDATA *ccs=(CCSDATA*)lParam;
+ int i;
+ char str[10];
+ DBVARIANT dbv;
+ int ret;
+
+ if(wParam==(WPARAM)(-1)) return 1;
+ for(i=wParam;;i++) {
+ _itoa(i,str,10);
+ if(DBGetContactSetting(ccs->hContact,"_Filter",str,&dbv)) break;
+ if((ret=CallProtoService(dbv.pszVal,ccs->szProtoService,i+1,lParam))!=CALLSERVICE_NOTFOUND) {
+ //chain was started, exit
+ mir_free(dbv.pszVal);
+ return ret;
+ }
+ mir_free(dbv.pszVal);
+ }
+ if(DBGetContactSetting(ccs->hContact,"Protocol","p",&dbv)) return 1;
+ if((ret=CallProtoService(dbv.pszVal,ccs->szProtoService,(WPARAM)(-1),lParam))!=CALLSERVICE_NOTFOUND) {
+ //chain was started, exit
+ mir_free(dbv.pszVal);
+ return ret;
+ }
+ mir_free(dbv.pszVal);
+ return 1;
+}
+
+static int CallRecvChain(WPARAM wParam,LPARAM lParam)
+{
+ CCSDATA *ccs=(CCSDATA*)lParam;
+ int i,ret;
+ char str[10];
+ DBVARIANT dbv;
+
+ if(wParam==(WPARAM)(-1)) return 1; //shouldn't happen - sanity check
+ if(wParam==0) { //begin processing by finding end of chain
+ for(;;wParam++) {
+ _itoa(wParam,str,10);
+ if(DBGetContactSetting(ccs->hContact,"_Filter",str,&dbv)) break;
+ mir_free(dbv.pszVal);
+ }
+ }
+ else wParam--;
+ for(i=wParam-1;i>=0;i--) {
+ _itoa(i,str,10);
+ if(DBGetContactSetting(ccs->hContact,"_Filter",str,&dbv)) return 1; //never happens
+ if((ret=CallProtoService(dbv.pszVal,ccs->szProtoService,i+1,lParam))!=CALLSERVICE_NOTFOUND) {
+ //chain was started, exit
+ mir_free(dbv.pszVal);
+ return ret;
+ }
+ mir_free(dbv.pszVal);
+ }
+ //end of chain, call network protocol again
+ if(DBGetContactSetting(ccs->hContact,"Protocol","p",&dbv)) return 1;
+ if((ret=CallProtoService(dbv.pszVal,ccs->szProtoService,(WPARAM)(-1),lParam))!=CALLSERVICE_NOTFOUND) {
+ mir_free(dbv.pszVal);
+ return ret;
+ }
+ mir_free(dbv.pszVal);
+ return 1;
+}
+
+static int Proto_ChainRecv(WPARAM wParam,LPARAM lParam)
+{
+ /* this will switch threads just like before */
+ return CallServiceSync(MS_PROTO_CHAINRECV "ThreadSafe",wParam,lParam);
+}
+
+#if 1
+static int Proto_GetContactBaseProto(WPARAM wParam,LPARAM lParam)
+{
+ DBVARIANT dbv;
+ PROTOCOLDESCRIPTOR *pd;
+ DBCONTACTGETSETTING dbcgs;
+ char name[32];
+
+ dbv.type=DBVT_ASCIIZ;
+ dbv.pszVal=name;
+ dbv.cchVal=SIZEOF(name);
+ dbcgs.pValue=&dbv;
+ dbcgs.szModule="Protocol";
+ dbcgs.szSetting="p";
+ if(CallService(MS_DB_CONTACT_GETSETTINGSTATIC,wParam,(LPARAM)&dbcgs)) return (int)(char*)NULL;
+ pd=(PROTOCOLDESCRIPTOR*)Proto_IsProtocolLoaded(0,(LPARAM)dbv.pszVal);
+ if(pd==NULL) return (int)(char*)NULL;
+ return (int)pd->szName;
+}
+#endif
+
+static int Proto_IsProtoOnContact(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ char str[10];
+ DBVARIANT dbv;
+
+ if(!DBGetContactSetting((HANDLE)wParam,"Protocol","p",&dbv)) {
+ if(!strcmp((char*)lParam,dbv.pszVal)) {
+ mir_free(dbv.pszVal);
+ return -1;
+ }
+ mir_free(dbv.pszVal);
+ }
+ for(i=0;;i++) {
+ _itoa(i,str,10);
+ if(DBGetContactSetting((HANDLE)wParam,"_Filter",str,&dbv)) break;
+ if(!strcmp((char*)lParam,dbv.pszVal)) {
+ mir_free(dbv.pszVal);
+ return i+1;
+ }
+ mir_free(dbv.pszVal);
+ }
+ return 0;
+}
+
+static int Proto_AddToContact(WPARAM wParam,LPARAM lParam)
+{
+ PROTOCOLDESCRIPTOR *pd,*pdCompare;
+
+ pd=(PROTOCOLDESCRIPTOR*)Proto_IsProtocolLoaded(0,lParam);
+ if(pd==NULL) return 1;
+ if ( pd->type == PROTOTYPE_PROTOCOL ) {
+ DBWriteContactSettingString((HANDLE)wParam,"Protocol","p",(char*)lParam);
+ return 0;
+ }
+ if(Proto_IsProtoOnContact(wParam,lParam)) return 1;
+ { /* v:0.3.3 + PROTO FILTERS ARE NOW KEPT IN THEIR OWN DB MODULE! */
+ int i;
+ char str[10],*lastProto;
+ DBVARIANT dbv;
+
+ for(i=0;;i++) {
+ _itoa(i,str,10);
+ if(DBGetContactSetting((HANDLE)wParam,"_Filter",str,&dbv)) break;
+ pdCompare=(PROTOCOLDESCRIPTOR*)Proto_IsProtocolLoaded(0,(LPARAM)dbv.pszVal);
+ mir_free(dbv.pszVal);
+ if(pdCompare==NULL) continue;
+ if(pd->type > pdCompare->type) break;
+ }
+ //put the new module at position i
+ lastProto=mir_strdup((char*)lParam);
+ for(;;i++) {
+ _itoa(i,str,10);
+ if(DBGetContactSetting((HANDLE)wParam,"_Filter",str,&dbv)) {
+ DBWriteContactSettingString((HANDLE)wParam,"_Filter",str,lastProto);
+ mir_free(lastProto);
+ break;
+ }
+ DBWriteContactSettingString((HANDLE)wParam,"_Filter",str,lastProto);
+ mir_free(lastProto);
+ lastProto=dbv.pszVal;
+ }
+ }
+ return 0;
+}
+
+static int Proto_RemoveFromContact(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ DBVARIANT dbv;
+ char str[10];
+
+ i=Proto_IsProtoOnContact(wParam,lParam);
+ if(!i) return 1;
+ if(i==-1)
+ DBDeleteContactSetting((HANDLE)wParam,"Protocol","p");
+ else {
+ for(i--;;i++) { //we have to decrease i, as Proto_IsOnContact returns +1 more number than read from database
+ _itoa(i+1,str,10);
+ if(0!=DBGetContactSetting((HANDLE)wParam,"_Filter",str,&dbv)) {
+ _itoa(i,str,10);
+ DBDeleteContactSetting((HANDLE)wParam,"_Filter",str);
+ break;
+ }
+ _itoa(i,str,10);
+ DBWriteContactSettingString((HANDLE)wParam,"_Filter",str,dbv.pszVal);
+ mir_free(dbv.pszVal);
+ }
+ }
+ return 0;
+}
+
+int LoadProtoChains(void)
+{
+ CreateServiceFunction(MS_PROTO_CALLCONTACTSERVICE,Proto_CallContactService);
+ CreateServiceFunction(MS_PROTO_CHAINSEND,Proto_CallContactService);
+ CreateServiceFunction(MS_PROTO_CHAINRECV,Proto_ChainRecv);
+ CreateServiceFunction(MS_PROTO_CHAINRECV "ThreadSafe",CallRecvChain);
+ CreateServiceFunction(MS_PROTO_GETCONTACTBASEPROTO,Proto_GetContactBaseProto);
+ CreateServiceFunction(MS_PROTO_ISPROTOONCONTACT,Proto_IsProtoOnContact);
+ CreateServiceFunction(MS_PROTO_ADDTOCONTACT,Proto_AddToContact);
+ CreateServiceFunction(MS_PROTO_REMOVEFROMCONTACT,Proto_RemoveFromContact);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/protocols/protocols.c b/miranda-wine/src/modules/protocols/protocols.c
new file mode 100644
index 0000000..88b5513
--- /dev/null
+++ b/miranda-wine/src/modules/protocols/protocols.c
@@ -0,0 +1,134 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+int LoadProtoChains(void);
+
+static HANDLE hAckEvent,hTypeEvent;
+static int protocolModuleCount;
+static PROTOCOLDESCRIPTOR *protocolModule;
+static PROTOCOLDESCRIPTOR **pProtocolModules;
+
+void InitContactDir(void);
+void UninitContactDir(void);
+
+static int Proto_BroadcastAck(WPARAM wParam,LPARAM lParam)
+{
+ return NotifyEventHooks(hAckEvent,wParam,lParam);
+}
+
+int Proto_IsProtocolLoaded(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ for(i=0;i<protocolModuleCount;i++)
+ if(!strcmp(protocolModule[i].szName,(char*)lParam)) return (int)&protocolModule[i];
+ return (int)(PROTOCOLDESCRIPTOR*)NULL;
+}
+
+static int Proto_EnumProtocols(WPARAM wParam,LPARAM lParam)
+{
+ *(int*)wParam=protocolModuleCount;
+ *(PROTOCOLDESCRIPTOR***)lParam=pProtocolModules;
+ return 0;
+}
+
+static int Proto_RegisterModule(WPARAM wParam,LPARAM lParam)
+{
+ PROTOCOLDESCRIPTOR *pd=(PROTOCOLDESCRIPTOR*)lParam;
+ int i;
+
+ if(pd->cbSize!=sizeof(PROTOCOLDESCRIPTOR)) return 1;
+ protocolModule=(PROTOCOLDESCRIPTOR*)mir_realloc(protocolModule,sizeof(PROTOCOLDESCRIPTOR)*(protocolModuleCount+1));
+ protocolModule[protocolModuleCount]=*pd;
+ protocolModule[protocolModuleCount++].szName=mir_strdup(pd->szName);
+ pProtocolModules=(PROTOCOLDESCRIPTOR**)mir_realloc(pProtocolModules,sizeof(PROTOCOLDESCRIPTOR*)*(protocolModuleCount+1));
+ for(i=0;i<protocolModuleCount;i++)
+ pProtocolModules[i]=&protocolModule[i];
+ return 0;
+}
+
+static int Proto_ValidTypingContact(HANDLE hContact, char *szProto) {
+ DWORD protoCaps;
+
+ if (!hContact || !szProto) return 0;
+ protoCaps=CallProtoService(szProto,PS_GETCAPS,PFLAGNUM_4,0);
+ if (!(protoCaps&PF4_SUPPORTTYPING)) return 0;
+ return 1;
+}
+
+static int Proto_SelfIsTyping(WPARAM wParam,LPARAM lParam)
+{
+ int type = (int)lParam;
+ char *szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,wParam,0);
+ if (type!=PROTOTYPE_SELFTYPING_OFF && type!=PROTOTYPE_SELFTYPING_ON) return 0;
+
+ if (!szProto) return 0;
+ if (Proto_ValidTypingContact((HANDLE)wParam, szProto)) {
+ CallProtoService(szProto, PSS_USERISTYPING, wParam, lParam);
+ }
+ return 0;
+}
+
+static int Proto_ContactIsTyping(WPARAM wParam,LPARAM lParam)
+{
+ int type = (int)lParam;
+ char *szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,wParam,0);
+
+ if (!szProto) return 0;
+ if (type<PROTOTYPE_CONTACTTYPING_OFF) return 0;
+ if (Proto_ValidTypingContact((HANDLE)wParam, szProto))
+ NotifyEventHooks(hTypeEvent, wParam, lParam);
+ return 0;
+}
+
+static int ProtoShutdown(WPARAM wParam,LPARAM lParam)
+{
+ if (hAckEvent) DestroyHookableEvent(hAckEvent);
+ hAckEvent=NULL;
+ if(protocolModule!=NULL) {
+ int i;
+ for(i=0;i<protocolModuleCount;i++)
+ mir_free(protocolModule[i].szName);
+ mir_free(protocolModule);
+ }
+ if(pProtocolModules!=NULL) mir_free(pProtocolModules);
+ protocolModuleCount=0;
+ UninitContactDir();
+ return 0;
+}
+
+int LoadProtocolsModule(void)
+{
+ HookEvent(ME_SYSTEM_SHUTDOWN,ProtoShutdown);
+ if(LoadProtoChains()) return 1;
+ hAckEvent=CreateHookableEvent(ME_PROTO_ACK);
+ hTypeEvent=CreateHookableEvent(ME_PROTO_CONTACTISTYPING);
+ CreateServiceFunction(MS_PROTO_BROADCASTACK,Proto_BroadcastAck);
+ CreateServiceFunction(MS_PROTO_ISPROTOCOLLOADED,Proto_IsProtocolLoaded);
+ CreateServiceFunction(MS_PROTO_ENUMPROTOCOLS,Proto_EnumProtocols);
+ CreateServiceFunction(MS_PROTO_REGISTERMODULE,Proto_RegisterModule);
+ CreateServiceFunction(MS_PROTO_SELFISTYPING,Proto_SelfIsTyping);
+ CreateServiceFunction(MS_PROTO_CONTACTISTYPING,Proto_ContactIsTyping);
+ InitContactDir();
+ return 0;
+}
diff --git a/miranda-wine/src/modules/protocols/protodir.c b/miranda-wine/src/modules/protocols/protodir.c
new file mode 100644
index 0000000..7a11026
--- /dev/null
+++ b/miranda-wine/src/modules/protocols/protodir.c
@@ -0,0 +1,248 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2005 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+#if 0
+
+extern HANDLE hCacheHeap;
+
+/*
+
+ the id cache has id/proto against hContact to lookup ID's fast to resolve to hContact,
+ the protoBaseCache has hContact's sorted, so can lookup hContact->proto fast, these two caches
+ share the same data, they're indexes, each entry might not have an "id" set.
+
+ There is a small cache which maintains a protocol list
+
+*/
+
+/*
+
+ The information we need to cache is not readily available, data has to be gathered at startup
+ when a new contact is created/deleted, when a new proto registers and so on.
+
+ The information we get at startup includes walking the contact chain and reading Protocol/p which
+ will give us the protocol the contact is on, all this info is stored in contactEntry's within
+ protoCache ONLY - contactCache is EMPTY at this point.
+
+ We can not fetch the id of the contact because this information is only in SOME protocol plugins,
+ this is a problem but we'll hook all proto registrations and ask each proto if it supports the
+ returning this ID name, if not - it won't even use our id <-> contact look so no biggie!
+
+*/
+
+typedef struct {
+ char * proto; // within proto cache
+ char * id; // optional
+ HANDLE hContact;
+} contactEntry;
+
+typedef struct {
+ CRITICAL_SECTION csLock;
+ SortedList contactCache; // index for id/proto -> hContact
+ SortedList protoCache; // index for hContact -> proto/id
+ SortedList protoNameCache; // index of protocol names
+} contactDir;
+
+static contactDir condir;
+
+// compare's id/proto and return's hContact's
+int contactCacheCompare(void * a, void * b)
+{
+ contactEntry * x = (contactEntry *) a;
+ contactEntry * y = (contactEntry *) b;
+ int rc=0;
+ // same protocol?
+ rc = strcmp(x->proto, y->proto);
+ if ( rc == 0 ) {
+ // same id? id's might be missing
+ if ( x->id && y->id ) rc = strcmp(x->id, y->id);
+ }
+ return rc;
+}
+
+// compares hContact's and returns associated data
+int protoCacheCompare(void * a, void * b)
+{
+ contactEntry * x = (contactEntry *) a;
+ contactEntry * y = (contactEntry *) b;
+ if ( x->hContact < y->hContact ) return -1;
+ if ( x->hContact > y->hContact ) return 1;
+ return 0;
+}
+
+// keeps a list of protocol names
+int protoNameCacheCompare(void * a, void * b)
+{
+ return strcmp( (char *)a, (char*)b );
+}
+
+// cache the protocol string so that its not allocated per contact but shared
+char * contactDir_Proto_Add(contactDir * cd, char * proto)
+{
+ int index = 0 ;
+ char * szCache = 0;
+ EnterCriticalSection(&cd->csLock);
+ if ( List_GetIndex(&cd->protoNameCache, proto, &index) ) szCache = cd->protoNameCache.items[index];
+ else {
+ szCache = HeapAlloc(hCacheHeap, HEAP_NO_SERIALIZE, strlen(proto)+1);
+ strcpy(szCache, proto);
+ List_Insert(&cd->protoNameCache, szCache, index);
+ }
+ LeaveCriticalSection(&cd->csLock);
+ return szCache;
+}
+
+// thread safe
+char * contactDir_Proto_Get(contactDir * cd, HANDLE hContact)
+{
+ char * szCache = 0;
+ int index = 0;
+ contactEntry e;
+ e.hContact=hContact;
+ e.proto="";
+ e.id="";
+ EnterCriticalSection(&cd->csLock);
+ if ( List_GetIndex(&cd->protoCache, &e, &index) ) {
+ contactEntry * p = cd->protoCache.items[index];
+ szCache = p->proto;
+ }
+ LeaveCriticalSection(&cd->csLock);
+ return szCache;
+}
+
+// thread tolerant, if updating id dont pass proto, if updating proto dont pass id
+void contactDir_Contact_Add(contactDir * cd, HANDLE hContact, char * proto, char * id)
+{
+ // if a contact is gonna exist anywhere it's going to be in the ->protoCache which has a key of hContact
+ // if id is not null then the contact should be indexed via the ->contactCache instead
+ if ( id == NULL ) {
+ int index = 0;
+ contactEntry e;
+ e.hContact=hContact;
+ e.proto = proto;
+ e.id = "";
+ EnterCriticalSection(&cd->csLock);
+ if ( List_GetIndex(&cd->protoCache, &e, &index) ) {
+ contactEntry * p = cd->protoCache.items[index];
+ // this hContact is in the cache, protcol changing?
+ p->proto = contactDir_Proto_Add(cd, proto); // just replace the old pointer
+ } else {
+ contactEntry * p = 0;
+ // this hContact isn't in the cache, add it
+ p = HeapAlloc(hCacheHeap, HEAP_NO_SERIALIZE, sizeof(contactEntry));
+ p->proto = contactDir_Proto_Add(cd, proto);
+ p->id = 0;
+ p->hContact = hContact;
+ // add it
+ List_Insert(&cd->protoCache, p, index);
+ }
+ LeaveCriticalSection(&cd->csLock);
+ } else {
+ // this contact HAS to be in ->protoCache since it was added during startup
+ // need to find the contactEntry* that should already exist for it
+ } //if
+}
+
+// only expected to be called at startup.
+void contactDir_Proto_Walk(contactDir * cd)
+{
+ HANDLE hContact;
+ char buf[128];
+ DBCONTACTGETSETTING gsProto;
+ DBVARIANT dbvProto;
+ // setup the read structure
+ gsProto.szModule="Protocol";
+ gsProto.szSetting="p";
+ gsProto.pValue = &dbvProto;
+ // this might not work
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while ( hContact ) {
+ // and how we'll get the reset
+ dbvProto.type=DBVT_ASCIIZ;
+ dbvProto.pszVal = (char *) &buf;
+ dbvProto.cchVal = SIZEOF(buf);
+ // figure out what hContact/Protocol/p is
+ if ( CallService(MS_DB_CONTACT_GETSETTINGSTATIC,(WPARAM)hContact, (LPARAM)&gsProto) == 0 ) {
+ contactDir_Contact_Add(cd, hContact, buf, NULL);
+ }
+ // find next
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0);
+ }
+}
+
+// ctor/dtor
+
+void contactDir_Init(contactDir * cd)
+{
+ InitializeCriticalSection(&cd->csLock);
+ cd->contactCache.increment=50;
+ cd->contactCache.sortFunc=contactCacheCompare;
+ cd->protoCache.increment=50;
+ cd->protoCache.sortFunc=protoCacheCompare;
+ cd->protoNameCache.increment=5;
+ cd->protoNameCache.sortFunc=protoNameCacheCompare;
+ // build a list of all hContact's and what proto's they are on
+ contactDir_Proto_Walk(cd);
+}
+
+void contactDir_Deinit(contactDir * cd)
+{
+ List_Destroy(&cd->contactCache);
+ List_Destroy(&cd->protoCache);
+ List_Destroy(&cd->protoNameCache);
+ DeleteCriticalSection(&cd->csLock);
+}
+
+static int contactDirGetProto(WPARAM wParam, LPARAM lParam)
+{
+ return (int) contactDir_Proto_Get(&condir,(HANDLE)wParam);
+}
+
+#endif
+
+void InitContactDir(void)
+{
+ return;
+ //contactDir_Init(&condir);
+ //CreateServiceFunction(MS_PROTODIR_PROTOFROMCONTACT, contactDirGetProto);
+}
+
+
+void UninitContactDir(void)
+{
+ return;
+#if 0
+ {
+ int j;
+ for ( j = 0; j< condir.protoCache.realCount; j++) {
+ char buf[128];
+ contactEntry * p = condir.protoCache.items[j];
+ mir_snprintf(buf,SIZEOF(buf)," [%s] %s @ %x \n", p->proto, p->id ? p->id : "", p->hContact);
+ OutputDebugString(buf);
+ }
+ }
+ contactDir_Deinit(&condir);
+#endif
+}
diff --git a/miranda-wine/src/modules/skin/skin.c b/miranda-wine/src/modules/skin/skin.c
new file mode 100644
index 0000000..5fea4ca
--- /dev/null
+++ b/miranda-wine/src/modules/skin/skin.c
@@ -0,0 +1,77 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+int InitSkinIcons(void);
+void UninitSkinIcons(void);
+int InitSkinSounds(void);
+void UninitSkinSounds(void);
+BOOL CALLBACK DlgProcSoundOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+BOOL CALLBACK DlgProcIconsOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+static int SkinSystemShutdown(WPARAM wParam,LPARAM lParam)
+{
+ UninitSkinSounds();
+ UninitSkinIcons();
+ return 0;
+}
+
+static UINT iconsExpertOnlyControls[]={IDC_IMPORT};
+static int SkinOptionsInit(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.position = -200000000;
+ odp.hInstance = GetModuleHandle(NULL);
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_SOUND);
+ odp.pszGroup = "Events";
+ odp.pszTitle = "Sounds";
+ odp.pfnDlgProc = DlgProcSoundOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+
+ odp.position = -180000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_ICONS);
+ odp.pszTitle = "Icons";
+ odp.pszGroup = "Contact List";
+ odp.pfnDlgProc = DlgProcIconsOpts;
+ odp.expertOnlyControls = iconsExpertOnlyControls;
+ odp.nExpertOnlyControls = SIZEOF( iconsExpertOnlyControls );
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
+
+static int SkinSystemModulesLoaded(WPARAM wParam,LPARAM lParam)
+{
+ HookEvent(ME_OPT_INITIALISE,SkinOptionsInit);
+ return 0;
+}
+
+int LoadSkinModule(void)
+{
+ HookEvent(ME_SYSTEM_MODULESLOADED,SkinSystemModulesLoaded);
+ HookEvent(ME_SYSTEM_SHUTDOWN,SkinSystemShutdown);
+ if(InitSkinIcons()) return 1;
+ if(InitSkinSounds()) return 1;
+ return 0;
+}
diff --git a/miranda-wine/src/modules/skin/skinicons.c b/miranda-wine/src/modules/skin/skinicons.c
new file mode 100644
index 0000000..706f585
--- /dev/null
+++ b/miranda-wine/src/modules/skin/skinicons.c
@@ -0,0 +1,1044 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include <io.h>
+
+/***********W*A*R*N*I*N*G*************
+
+ This is quite possibly the worst
+ code that has ever been written.
+
+************W*A*R*N*I*N*G************/
+
+BOOL CALLBACK DlgProcIconIndex(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+static HINSTANCE hMiranda;
+static HANDLE hIconsChangedEvent;
+static HICON ImportIcon(const char *szProto,int n);
+
+struct IconPreview {
+ int id;
+ char* description;
+ int main;
+};
+
+struct IconPreview static mainIcons[] =
+{
+ { SKINICON_OTHER_MIRANDA, "Miranda IM", 1 },
+ { SKINICON_EVENT_MESSAGE, "Message", 1 },
+ { SKINICON_EVENT_URL, "URL", 1 },
+ { SKINICON_EVENT_FILE, "File", 1 },
+ { SKINICON_OTHER_USERONLINE, "User Online", 1 },
+ { SKINICON_OTHER_GROUPOPEN, "Group (Open)", 1 },
+ { SKINICON_OTHER_GROUPSHUT, "Group (Closed)", 1 },
+};
+static int skinIconStatusToIdStatus[]={ID_STATUS_OFFLINE,ID_STATUS_ONLINE,ID_STATUS_AWAY,ID_STATUS_NA,ID_STATUS_OCCUPIED,ID_STATUS_DND,ID_STATUS_FREECHAT,ID_STATUS_INVISIBLE,ID_STATUS_ONTHEPHONE,ID_STATUS_OUTTOLUNCH};
+static int skinIconStatusToPf2[]={0xFFFFFFFF,PF2_ONLINE,PF2_SHORTAWAY,PF2_LONGAWAY,PF2_LIGHTDND,PF2_HEAVYDND,PF2_FREECHAT,PF2_INVISIBLE,PF2_ONTHEPHONE,PF2_OUTTOLUNCH};
+static UINT skinIconStatusToResourceId[]={IDI_OFFLINE,IDI_ONLINE,IDI_AWAY,IDI_NA,IDI_OCCUPIED,IDI_DND,IDI_FREE4CHAT,IDI_INVISIBLE,IDI_ONTHEPHONE,IDI_OUTTOLUNCH};
+static UINT eventIconToResourceId[]={IDI_RECVMSG,IDI_URL,IDI_FILE};
+static UINT otherIconToResourceId[]={IDI_MIRANDA,IDI_MIRANDA,IDI_MIRANDA,IDI_GROUPOPEN,IDI_USERONLINE,IDI_GROUPSHUT};
+
+struct ProtoIcons {
+ char *szProto;
+ HICON hIcons[ SIZEOF(skinIconStatusToIdStatus) ];
+} static *protoIcons;
+static int protoIconsCount;
+static HICON hEventIcons[3],hOtherIcons[6];
+static HICON hStatusIcons[ SIZEOF(skinIconStatusToIdStatus) ];
+
+static int IdStatusToSkinIconStatus(int idStatus)
+{
+ int i;
+ for( i=0; i < SIZEOF(skinIconStatusToIdStatus); i++ )
+ if(skinIconStatusToIdStatus[i]==idStatus) return i;
+ return SKINICON_STATUS_OFFLINE;
+}
+
+static int LoadSkinProtoIcon(WPARAM wParam,LPARAM lParam)
+{
+ char *szProto=(char*)wParam;
+ int i;
+ if (!szProto) {
+ // Only return a protocol specific icon if there is only one protocol
+ // Otherwise return the builtin hStatusIcons icon. This affects the global status menu mainly.
+ PROTOCOLDESCRIPTOR **proto;
+ DWORD protoCount,j;
+ CallService(MS_PROTO_ENUMPROTOCOLS,(WPARAM)&protoCount,(LPARAM)&proto);
+ if (protoIconsCount==1) {
+ HICON hIcon=protoIcons[0].hIcons[IdStatusToSkinIconStatus(lParam)];
+ if (hIcon) {
+ if (protoCount) {
+ for (j=0;j<protoCount;j++) {
+ if (proto[j]->type!=PROTOTYPE_PROTOCOL) continue;
+ if (!_strcmpi(proto[j]->szName,protoIcons[0].szProto)) return (int)hIcon;
+ } //for
+ } else {
+ return (int)hIcon;
+ } //if
+ } //if
+ } // if
+ return (int)hStatusIcons[IdStatusToSkinIconStatus(lParam)];
+ } //if
+
+ for(i=0;i<protoIconsCount;i++)
+ if(!strcmp(szProto,protoIcons[i].szProto))
+ return (int)protoIcons[i].hIcons[IdStatusToSkinIconStatus(lParam)];
+ {
+ int j;
+ protoIcons=(struct ProtoIcons*)mir_realloc(protoIcons,sizeof(struct ProtoIcons)*(protoIconsCount+1));
+ protoIcons[protoIconsCount].szProto=mir_strdup(szProto);
+ for( j=0; j < SIZEOF(skinIconStatusToIdStatus); j++ )
+ {
+ protoIcons[protoIconsCount].hIcons[j]=ImportIcon(szProto,j);
+ }//for
+ protoIconsCount++;
+ }
+ return (int)protoIcons[protoIconsCount-1].hIcons[IdStatusToSkinIconStatus(lParam)];
+}
+
+static int LoadSkinIcon(WPARAM wParam,LPARAM lParam)
+{
+ if(wParam<SKINICON_EVENT_MESSAGE) {
+ if(wParam>=SIZEOF(skinIconStatusToIdStatus)) return (int)(HICON)NULL;
+ return LoadSkinProtoIcon((WPARAM)(char*)NULL,skinIconStatusToIdStatus[wParam]);
+ }
+ if(wParam<SKINICON_OTHER_MIRANDA) {
+ if(wParam-SKINICON_EVENT_MESSAGE>=SIZEOF(hEventIcons)) return (int)(HICON)NULL;
+ return (int)hEventIcons[wParam-SKINICON_EVENT_MESSAGE];
+ }
+ if(wParam-SKINICON_OTHER_MIRANDA>=SIZEOF(hOtherIcons)) return (int)(HICON)NULL;
+ return (int)hOtherIcons[wParam-SKINICON_OTHER_MIRANDA];
+}
+
+static HICON ExtractIconFromPath(const char *path)
+{
+ char *comma;
+ char file[MAX_PATH],fileFull[MAX_PATH];
+ int n;
+ HICON hIcon;
+
+ if (path == NULL) return (HICON)NULL;
+
+ lstrcpynA(file,path,SIZEOF(file));
+ comma=strrchr(file,',');
+ if(comma==NULL) n=0;
+ else {n=atoi(comma+1); *comma=0;}
+ CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM)file, (LPARAM)fileFull);
+ hIcon=NULL;
+ ExtractIconExA(fileFull,n,NULL,&hIcon,1);
+ return hIcon;
+}
+
+static HICON ImportIcon(const char *szProto,int n)
+{
+ DBVARIANT dbv;
+ char szSetting[64];
+ HICON hIcon;
+
+ if(szProto==NULL && n<SKINICON_EVENT_MESSAGE) {
+ /* return 'all protocol status icon' */
+ int i;
+ for(i=0;;i++) {
+ szSetting[0]='p';
+ _itoa(i,szSetting+1,10);
+ if(DBGetContactSetting(NULL,"Icons",szSetting,&dbv)) break;
+ mir_snprintf(szSetting,SIZEOF(szSetting),"%s%d",dbv.pszVal,skinIconStatusToIdStatus[n]);
+ DBFreeVariant(&dbv);
+ if(!DBGetContactSetting(NULL,"Icons",szSetting,&dbv)) {
+ hIcon=ExtractIconFromPath(dbv.pszVal);
+ DBFreeVariant(&dbv);
+ if (hIcon)
+ return hIcon;
+ } //if
+ } //for
+ return hStatusIcons[n];
+ }//if
+
+ /* if there is a protocol, build <protocol><ID> to get a path, otherwise
+ use the index 'n' directly. */
+ if (szProto) {
+ //
+ mir_snprintf(szSetting,SIZEOF(szSetting),"%s%d",szProto,skinIconStatusToIdStatus[n]);
+ } else {
+ _itoa(n,szSetting,10);
+ } //if
+
+ if(!DBGetContactSetting(NULL,"Icons",szSetting,&dbv)) {
+ hIcon=ExtractIconFromPath(dbv.pszVal);
+ DBFreeVariant(&dbv);
+ if(hIcon!=NULL)
+ return hIcon;
+ }
+ if (szProto) {
+ char szPath[MAX_PATH], szFullPath[MAX_PATH],*str;
+ HICON hIcon;
+
+ GetModuleFileNameA(GetModuleHandle(NULL), szPath, MAX_PATH);
+ str=strrchr(szPath,'\\');
+ if(str!=NULL) *str=0;
+ mir_snprintf(szFullPath, SIZEOF(szFullPath), "%s\\Icons\\proto_%s.dll,%d", szPath, szProto, -(int)skinIconStatusToResourceId[n]);
+ hIcon=ExtractIconFromPath(szFullPath);
+ if (hIcon) return hIcon;
+ /* looking for a protocol icon and it wasn't found, use internal */
+ return hStatusIcons[n];
+ }
+ return LoadIcon(hMiranda,MAKEINTRESOURCE(n<SKINICON_OTHER_MIRANDA?eventIconToResourceId[n-SKINICON_EVENT_MESSAGE]:otherIconToResourceId[n-SKINICON_OTHER_MIRANDA]));
+}
+
+static void LoadAllIcons(void)
+{
+ DBVARIANT dbv;
+ int i,j,z;
+ char szSetting[128];
+
+ for( i=0; i < SIZEOF(hEventIcons); i++ )
+ hEventIcons[i]=ImportIcon(NULL,i+SKINICON_EVENT_MESSAGE);
+ for( i=0; i < SIZEOF(hOtherIcons); i++ )
+ hOtherIcons[i]=ImportIcon(NULL,i+SKINICON_OTHER_MIRANDA);
+ ZeroMemory(hStatusIcons,sizeof(hStatusIcons));
+ for( i=0; i < SIZEOF(hStatusIcons); i++ )
+ {
+ _itoa(skinIconStatusToIdStatus[i], szSetting, 10);
+ hStatusIcons[i] = NULL;
+ if(!DBGetContactSetting(NULL,"Icons",szSetting,&dbv)) {
+ hStatusIcons[i] = ExtractIconFromPath(dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ if (!hStatusIcons[i]) hStatusIcons[i]=LoadIcon(hMiranda,MAKEINTRESOURCE(skinIconStatusToResourceId[i]));
+ }
+ protoIcons=NULL;
+ protoIconsCount=0;
+ for(i=0;;i++) {
+ z = 0;
+ szSetting[0]='p';
+ _itoa(i,szSetting+1,10);
+ if(DBGetContactSetting(NULL,"Icons",szSetting,&dbv)) break;
+ for(j=0;j<protoIconsCount;j++) {
+ if (!strcmp(dbv.pszVal,protoIcons[j].szProto)) z = 1;
+ }
+ if (!z) {
+ protoIcons=(struct ProtoIcons*)mir_realloc(protoIcons,sizeof(struct ProtoIcons)*(protoIconsCount+1));
+ protoIcons[protoIconsCount].szProto=dbv.pszVal;
+ for( j=0; j < SIZEOF(skinIconStatusToIdStatus); j++ )
+ {
+ protoIcons[protoIconsCount].hIcons[j]=ImportIcon(dbv.pszVal,j);
+ }//for
+ protoIconsCount++;
+ }
+ if (z) DBFreeVariant(&dbv); /* the proto was found, free the string */
+ }//for
+}
+
+void FreeAllIcons(void)
+{
+ int i,j;
+ for( i=0; i < SIZEOF(hOtherIcons); i++ ) DestroyIcon(hOtherIcons[i]);
+ for( i=0; i < SIZEOF(hEventIcons); i++ ) DestroyIcon(hEventIcons[i]);
+ for( i=0; i < protoIconsCount;i++) {
+ for( j=0; j < SIZEOF(skinIconStatusToIdStatus); j++ ) {
+ if(hStatusIcons[i]==protoIcons[i].hIcons[j]) continue;
+ DestroyIcon(protoIcons[i].hIcons[j]);
+ }
+ mir_free(protoIcons[i].szProto);
+ }
+ mir_free(protoIcons);
+ for( i=0; i < SIZEOF(hStatusIcons); i++ )
+ DestroyIcon(hStatusIcons[i]);
+}
+
+int InitSkinIcons(void)
+{
+ hMiranda=GetModuleHandle(NULL);
+ LoadAllIcons();
+ CreateServiceFunction(MS_SKIN_LOADICON,LoadSkinIcon);
+ CreateServiceFunction(MS_SKIN_LOADPROTOICON,LoadSkinProtoIcon);
+ hIconsChangedEvent=CreateHookableEvent(ME_SKIN_ICONSCHANGED);
+ return 0;
+}
+
+void UninitSkinIcons(void)
+{
+ FreeAllIcons();
+}
+
+struct ProtoIconsData {
+ PROTOCOLDESCRIPTOR *proto;
+ char **iconPath;
+};
+struct IconsOptsData {
+ struct ProtoIconsData *protoIcons;
+ int protoCount;
+ char **mainIconPath;
+ char **mainStatusPath;
+ HWND hwndIndex;
+ int originalGroupWidth;
+ int shortGroupWidth;
+ int groupHeight;
+};
+#define DM_REBUILDICONSPREVIEW (WM_USER+10)
+#define DM_CHANGEICON (WM_USER+11)
+#define DM_CHANGESPECIFICICON (WM_USER+12)
+BOOL CALLBACK DlgProcIconsOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct IconsOptsData *dat;
+
+ dat=(struct IconsOptsData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ { PROTOCOLDESCRIPTOR *proto,**protoList;
+ int protoCount,i,j;
+ char szSetting[64];
+ DBVARIANT dbv;
+
+ TranslateDialogDefault(hwndDlg);
+ dat=(struct IconsOptsData*)mir_alloc(sizeof(struct IconsOptsData));
+ SetWindowLong(hwndDlg,GWL_USERDATA,(LONG)dat);
+ dat->mainIconPath=(char**)mir_alloc(sizeof(char*) * SIZEOF(mainIcons));
+ dat->mainStatusPath=(char**)mir_alloc(sizeof(char*) * SIZEOF(skinIconStatusToIdStatus));
+ for( i=0; i < SIZEOF(mainIcons); i++ ) {
+ _itoa(mainIcons[i].id,szSetting,10);
+ if ( DBGetContactSetting( NULL, "Icons", szSetting, &dbv ))
+ dat->mainIconPath[i]=NULL;
+ else
+ dat->mainIconPath[i]=dbv.pszVal;
+ }
+
+ for ( i=0; i < SIZEOF(skinIconStatusToIdStatus); i++ ) {
+ _itoa(skinIconStatusToIdStatus[i],szSetting,10);
+ if ( DBGetContactSetting( NULL, "Icons", szSetting, &dbv ))
+ dat->mainStatusPath[i]=NULL;
+ else
+ dat->mainStatusPath[i]=dbv.pszVal;
+ }
+
+ ListView_SetImageList(GetDlgItem(hwndDlg,IDC_PREVIEW),ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),ILC_COLOR32|ILC_MASK,0,30),LVSIL_NORMAL);
+ ListView_SetIconSpacing(GetDlgItem(hwndDlg,IDC_PREVIEW),56,67);
+ i=SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_ADDSTRING,0,(LPARAM)TranslateT("Main Icons"));
+ SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_SETITEMDATA,i,0);
+ i=SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_ADDSTRING,0,(LPARAM)TranslateT("Global Status Icons"));
+ SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_SETITEMDATA,i,0);
+ CallService(MS_PROTO_ENUMPROTOCOLS,(WPARAM)&protoCount,(LPARAM)&protoList);
+ for ( i=0; i < protoCount; i++ ) {
+ TCHAR str[128];
+ char protoName[96];
+ if(protoList[i]->type!=PROTOTYPE_PROTOCOL || CallProtoService(protoList[i]->szName,PS_GETCAPS,PFLAGNUM_2,0)==0) continue;
+ CallProtoService(protoList[i]->szName,PS_GETNAME,SIZEOF(protoName),(LPARAM)protoName);
+ { TCHAR* ptszProtoName = LangPackPcharToTchar( protoName );
+ mir_sntprintf( str, SIZEOF(str), TranslateT("%s Icons"), ptszProtoName );
+ mir_free( ptszProtoName );
+ }
+ j = SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_ADDSTRING,0,(LPARAM)str );
+ SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_SETITEMDATA,j,(LPARAM)protoList[i]);
+ }
+ dat->protoCount=SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETCOUNT,0,0)-2;
+ dat->protoIcons=(struct ProtoIconsData*)mir_alloc(sizeof(struct ProtoIconsData)*dat->protoCount);
+ for(i=0;i<dat->protoCount;i++) {
+ proto=(PROTOCOLDESCRIPTOR*)SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETITEMDATA,i+2,0);
+ dat->protoIcons[i].proto=proto;
+ dat->protoIcons[i].iconPath=(char**)mir_alloc(sizeof(char*) * SIZEOF(skinIconStatusToIdStatus));
+ for( j=0; j < SIZEOF(skinIconStatusToIdStatus); j++ ) {
+ mir_snprintf(szSetting,SIZEOF(szSetting),"%s%d",proto->szName,skinIconStatusToIdStatus[j]);
+ if(DBGetContactSetting(NULL,"Icons",szSetting,&dbv))
+ dat->protoIcons[i].iconPath[j]=NULL;
+ else
+ dat->protoIcons[i].iconPath[j]=dbv.pszVal;
+ } }
+
+ SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_SETCURSEL,0,0);
+ { RECT rc,rcReorder;
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_STSIMPLERIGHT),&rcReorder);
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_STICONSGROUP),&rc);
+ dat->originalGroupWidth=rc.right-rc.left;
+ dat->shortGroupWidth=rcReorder.right-rc.left;
+ dat->groupHeight=rc.bottom-rc.top;
+ }
+ SendMessage(hwndDlg,DM_REBUILDICONSPREVIEW,0,0);
+ return TRUE;
+ }
+ case DM_REBUILDICONSPREVIEW:
+ { LVITEM lvi;
+ HIMAGELIST hIml;
+ PROTOCOLDESCRIPTOR *proto;
+ HICON hIcon;
+
+ SetCursor(LoadCursor(NULL,IDC_WAIT));
+ proto=(PROTOCOLDESCRIPTOR*)SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETCURSEL,0,0),0);
+ ListView_DeleteAllItems(GetDlgItem(hwndDlg,IDC_PREVIEW));
+ hIml=ListView_GetImageList(GetDlgItem(hwndDlg,IDC_PREVIEW),LVSIL_NORMAL);
+ ImageList_RemoveAll(hIml);
+
+ lvi.mask=LVIF_TEXT|LVIF_IMAGE;
+ lvi.iSubItem=0;
+ if(proto==NULL) {
+ if (SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETCURSEL,0,0)==0) {
+ for ( lvi.iItem=0; lvi.iItem < SIZEOF(mainIcons); lvi.iItem++ ) {
+ lvi.pszText = LangPackPcharToTchar( mainIcons[lvi.iItem].description );
+ hIcon = ExtractIconFromPath( dat->mainIconPath[lvi.iItem] );
+ if(hIcon==NULL) hIcon=LoadIcon(hMiranda,MAKEINTRESOURCE(mainIcons[lvi.iItem].id<SKINICON_OTHER_MIRANDA?eventIconToResourceId[mainIcons[lvi.iItem].id-SKINICON_EVENT_MESSAGE]:otherIconToResourceId[mainIcons[lvi.iItem].id-SKINICON_OTHER_MIRANDA]));
+ lvi.iImage=ImageList_AddIcon(hIml,hIcon);
+ ListView_InsertItem( GetDlgItem(hwndDlg,IDC_PREVIEW), &lvi );
+ mir_free( lvi.pszText );
+ }
+ }
+ else {
+ for( lvi.iItem=0; lvi.iItem < SIZEOF(skinIconStatusToIdStatus); lvi.iItem++ ) {
+ lvi.pszText = LangPackPcharToTchar(( LPCSTR )CallService( MS_CLIST_GETSTATUSMODEDESCRIPTION, skinIconStatusToIdStatus[lvi.iItem], 0 ));
+ hIcon=ExtractIconFromPath(dat->mainStatusPath[lvi.iItem]);
+ if(hIcon==NULL) hIcon=LoadIcon(hMiranda,MAKEINTRESOURCE(skinIconStatusToResourceId[lvi.iItem]));
+ lvi.iImage=ImageList_AddIcon(hIml,hIcon);
+ ListView_InsertItem( GetDlgItem(hwndDlg,IDC_PREVIEW), &lvi );
+ mir_free( lvi.pszText );
+ } }
+ }
+ else {
+ int i;
+ DWORD caps2=CallProtoService(proto->szName,PS_GETCAPS,PFLAGNUM_2,0);
+ lvi.mask|=LVIF_PARAM;
+ for(i=0;i<dat->protoCount;i++)
+ if(proto==dat->protoIcons[i].proto) break;
+ for(lvi.iItem=0; lvi.iItem < SIZEOF(skinIconStatusToIdStatus); lvi.iItem++) {
+ if(!(caps2&skinIconStatusToPf2[lvi.iItem])) continue;
+ lvi.pszText = LangPackPcharToTchar(( LPCSTR )CallService( MS_CLIST_GETSTATUSMODEDESCRIPTION, skinIconStatusToIdStatus[lvi.iItem], 0 ));
+ lvi.lParam = lvi.iItem;
+ hIcon = ExtractIconFromPath(dat->protoIcons[i].iconPath[lvi.iItem]);
+ if(hIcon==NULL) {
+ char szPath[MAX_PATH], szFullPath[MAX_PATH],*str;
+
+ GetModuleFileNameA(GetModuleHandle(NULL), szPath, MAX_PATH);
+ str=strrchr(szPath,'\\');
+ if(str!=NULL) *str=0;
+ mir_snprintf(szFullPath, SIZEOF(szFullPath), "%s\\Icons\\proto_%s.dll,%d", szPath, dat->protoIcons[i].proto->szName, -(int)skinIconStatusToResourceId[lvi.iItem]);
+ hIcon=ExtractIconFromPath(szFullPath);
+ }
+ if(hIcon==NULL) hIcon=ExtractIconFromPath(dat->mainStatusPath[lvi.iItem]);
+ if(hIcon==NULL) hIcon=LoadIcon(hMiranda,MAKEINTRESOURCE(skinIconStatusToResourceId[lvi.iItem]));
+ lvi.iImage=ImageList_AddIcon(hIml,hIcon);
+ ListView_InsertItem( GetDlgItem(hwndDlg,IDC_PREVIEW), &lvi );
+ } }
+
+ SetCursor(LoadCursor(NULL,IDC_ARROW));
+ break;
+ }
+ case DM_CHANGEICON:
+ { char *path=(char*)lParam;
+ PROTOCOLDESCRIPTOR *proto;
+
+ proto=(PROTOCOLDESCRIPTOR*)SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETCURSEL,0,0),0);
+ if(proto==NULL) {
+ if (SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETCURSEL,0,0)==0) {
+ if(dat->mainIconPath[wParam]!=NULL) mir_free(dat->mainIconPath[wParam]);
+ dat->mainIconPath[wParam]=mir_strdup(path);
+ }
+ else {
+ if(dat->mainStatusPath[wParam]!=NULL) mir_free(dat->mainStatusPath[wParam]);
+ dat->mainStatusPath[wParam]=mir_strdup(path);
+ }
+ }
+ else {
+ LVITEM lvi;
+ int i;
+ for(i=0;i<dat->protoCount;i++)
+ if(proto==dat->protoIcons[i].proto) break;
+ lvi.mask=LVIF_PARAM;
+ lvi.iItem=wParam;
+ ListView_GetItem(GetDlgItem(hwndDlg,IDC_PREVIEW),&lvi);
+ if(dat->protoIcons[i].iconPath[lvi.lParam]!=NULL) mir_free(dat->protoIcons[i].iconPath[lvi.lParam]);
+ dat->protoIcons[i].iconPath[lvi.lParam]=mir_strdup(path);
+ }
+ }
+ SendMessage(hwndDlg,DM_REBUILDICONSPREVIEW,0,0);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case DM_CHANGESPECIFICICON:
+ { struct IconPreview *ico=(struct IconPreview*)lParam;
+ PROTOCOLDESCRIPTOR *proto=(PROTOCOLDESCRIPTOR*)wParam;
+ int i;
+
+ if(proto==NULL) {
+ if (ico->main) {
+ for( i=0; i < SIZEOF(mainIcons); i++ )
+ if(mainIcons[i].id==ico->id) break;
+ if( i < SIZEOF(mainIcons)) {
+ if(dat->mainIconPath[i]!=NULL) mir_free(dat->mainIconPath[i]);
+ dat->mainIconPath[i]=mir_strdup(ico->description);
+ }
+ }
+ else {
+ for( i=0; i < SIZEOF(skinIconStatusToResourceId); i++ )
+ if(i==ico->id) break;
+ if( i < SIZEOF(skinIconStatusToIdStatus)) {
+ if(dat->mainStatusPath[i]!=NULL) mir_free(dat->mainStatusPath[i]);
+ dat->mainStatusPath[i]=mir_strdup(ico->description);
+ }
+ }
+ }
+ else {
+ for(i=0;i<dat->protoCount;i++)
+ if(proto==dat->protoIcons[i].proto) break;
+ if(dat->protoIcons[i].iconPath[ico->id]!=NULL) mir_free(dat->protoIcons[i].iconPath[ico->id]);
+ dat->protoIcons[i].iconPath[ico->id]=mir_strdup(ico->description);
+ }
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_COMMAND:
+ if(LOWORD(wParam)==IDC_IMPORT) {
+ dat->hwndIndex=CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_ICONINDEX),GetParent(hwndDlg),DlgProcIconIndex,(LPARAM)hwndDlg);
+ EnableWindow((HWND)lParam,FALSE);
+ }
+ else if(LOWORD(wParam)==IDC_LOADICONS) {
+ char filetmp[MAX_PATH],filename[MAX_PATH];
+ OPENFILENAMEA ofn={0};
+ char filter[512],*pfilter;
+
+ filetmp[0]=0;
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner = hwndDlg;
+ ofn.hInstance = NULL;
+ strcpy(filter,Translate("Icon Sets"));
+ strcat(filter," (*.dll)");
+ pfilter=filter+strlen(filter)+1;
+ strcpy(pfilter,"*.DLL");
+ pfilter=pfilter+strlen(pfilter)+1;
+ strcpy(pfilter,Translate("All Files"));
+ strcat(pfilter," (*)");
+ pfilter=pfilter+strlen(pfilter)+1;
+ strcpy(pfilter,"*");
+ pfilter=pfilter+strlen(pfilter)+1;
+ *pfilter='\0';
+ ofn.lpstrFilter = filter;
+ ofn.lpstrFile = filetmp;
+ ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
+ ofn.nMaxFile = SIZEOF(filename);
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.lpstrDefExt = "dll";
+ if(GetOpenFileNameA(&ofn)) {
+ char path[MAX_PATH];
+ int i;
+ struct IconPreview ico;
+ HICON hIcon;
+
+ CallService(MS_UTILS_PATHTORELATIVE, (WPARAM)filetmp, (LPARAM)filename);
+ ico.description=path;
+ if(SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETCURSEL,0,0)==0) {
+ for( i=0; i < SIZEOF(mainIcons); i++ ) {
+ hIcon=ExtractIconA(GetModuleHandle(NULL),filename,-(int)(mainIcons[i].id<SKINICON_OTHER_MIRANDA?eventIconToResourceId[mainIcons[i].id-SKINICON_EVENT_MESSAGE]:otherIconToResourceId[mainIcons[i].id-SKINICON_OTHER_MIRANDA]));
+ if(hIcon==NULL) continue;
+ ico.id=mainIcons[i].id;
+ ico.main=1;
+ wsprintfA(path,"%s,%d",filename,-(int)(mainIcons[i].id<SKINICON_OTHER_MIRANDA?eventIconToResourceId[mainIcons[i].id-SKINICON_EVENT_MESSAGE]:otherIconToResourceId[mainIcons[i].id-SKINICON_OTHER_MIRANDA]));
+ SendMessage(hwndDlg,DM_CHANGESPECIFICICON,(WPARAM)(PROTOCOLDESCRIPTOR*)NULL,(LPARAM)&ico);
+ }
+ }
+ else if(SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETCURSEL,0,0)==1) {
+ for( i=0; i < SIZEOF(skinIconStatusToIdStatus); i++ ) {
+ hIcon=ExtractIconA(GetModuleHandle(NULL),filename,-(int)skinIconStatusToResourceId[i]);
+ if(hIcon==NULL) continue;
+ ico.id=i;
+ ico.main=0;
+ wsprintfA(path,"%s,%d",filename,-(int)skinIconStatusToResourceId[i]);
+ SendMessage(hwndDlg,DM_CHANGESPECIFICICON,(WPARAM)(PROTOCOLDESCRIPTOR**)NULL,(LPARAM)&ico);
+ }
+ }
+ else {
+ PROTOCOLDESCRIPTOR *proto;
+ proto=(PROTOCOLDESCRIPTOR*)SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETCURSEL,0,0),0);
+ for( i=0; i < SIZEOF(skinIconStatusToIdStatus); i++ ) {
+ hIcon=ExtractIconA(GetModuleHandle(NULL),filename,-(int)skinIconStatusToResourceId[i]);
+ if(hIcon==NULL) continue;
+ ico.id=i;
+ ico.main=0;
+ wsprintfA(path,"%s,%d",filename,-(int)skinIconStatusToResourceId[i]);
+ SendMessage(hwndDlg,DM_CHANGESPECIFICICON,(WPARAM)proto,(LPARAM)&ico);
+ }
+ }
+ SendMessage(hwndDlg,DM_REBUILDICONSPREVIEW,0,0);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ }
+ else if(LOWORD(wParam)==IDC_GETMORE) {
+ char szVer[64],szUrl[256];
+ CallService(MS_SYSTEM_GETVERSIONTEXT,SIZEOF(szVer),(LPARAM)szVer);
+ while(strchr(szVer,' ')) *strchr(szVer,' ')='_';
+ wsprintfA(szUrl,"http://addons.miranda-im.org/",szVer);
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)szUrl);
+ break;
+ }
+ else if(wParam==MAKEWPARAM(IDC_CATEGORYLIST,CBN_SELCHANGE)) {
+ if(dat->protoCount>1)
+ {
+ SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETCURSEL,0,0);
+ }
+ SendMessage(hwndDlg,DM_REBUILDICONSPREVIEW,0,0);
+ }
+ break;
+ case WM_CONTEXTMENU:
+ { LVHITTESTINFO lvhti;
+ GetCursorPos(&lvhti.pt);
+ ScreenToClient(GetDlgItem(hwndDlg,IDC_PREVIEW),&lvhti.pt);
+ if(ListView_HitTest(GetDlgItem(hwndDlg,IDC_PREVIEW),&lvhti)!=-1) {
+ HMENU hMenu;
+ POINT pt;
+ int cmd;
+ GetCursorPos(&pt);
+ hMenu=GetSubMenu(LoadMenu(GetModuleHandle(NULL),MAKEINTRESOURCE(IDR_CONTEXT)),3);
+ CallService(MS_LANGPACK_TRANSLATEMENU,(WPARAM)hMenu,0);
+ cmd=TrackPopupMenu(hMenu,TPM_RIGHTBUTTON|TPM_RETURNCMD,pt.x,pt.y,0,hwndDlg,NULL);
+ DestroyMenu(hMenu);
+ switch(cmd) {
+ case ID_RESET:
+ {
+ PROTOCOLDESCRIPTOR *proto;
+ proto=(PROTOCOLDESCRIPTOR*)SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETCURSEL,0,0),0);
+ if(proto==NULL) {
+ if(SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETCURSEL,0,0)==0) {
+ if(dat->mainIconPath[lvhti.iItem]!=NULL) {
+ mir_free(dat->mainIconPath[lvhti.iItem]);
+ dat->mainIconPath[lvhti.iItem]=NULL;
+ }
+ }
+ else {
+ if(dat->mainStatusPath[lvhti.iItem]!=NULL) {
+ mir_free(dat->mainStatusPath[lvhti.iItem]);
+ dat->mainStatusPath[lvhti.iItem]=NULL;
+ }
+ }
+ }
+ else {
+ LVITEM lvi;
+ int i;
+ for(i=0;i<dat->protoCount;i++)
+ if(proto==dat->protoIcons[i].proto) break;
+ lvi.mask=LVIF_PARAM;
+ lvi.iItem=lvhti.iItem;
+ ListView_GetItem(GetDlgItem(hwndDlg,IDC_PREVIEW),&lvi);
+ if(dat->protoIcons[i].iconPath[lvi.lParam]!=NULL) {
+ mir_free(dat->protoIcons[i].iconPath[lvi.lParam]);
+ dat->protoIcons[i].iconPath[lvi.lParam]=NULL;
+ }
+ }
+ SendMessage(hwndDlg,DM_REBUILDICONSPREVIEW,0,0);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ }
+ return TRUE;
+ }
+ }
+ break;
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->code) {
+ case PSN_APPLY:
+ { int i,j;
+ char szSetting[64];
+ DWORD flags;
+ PROTOCOLDESCRIPTOR *proto;
+ for( i=0; i < SIZEOF(mainIcons); i++ ) {
+ _itoa(mainIcons[i].id,szSetting,10);
+ if(dat->mainIconPath[i]==NULL)
+ DBDeleteContactSetting(NULL,"Icons",szSetting);
+ else
+ DBWriteContactSettingString(NULL,"Icons",szSetting,dat->mainIconPath[i]);
+ }
+ for( i=0; i < SIZEOF(skinIconStatusToIdStatus); i++ ) {
+ _itoa(skinIconStatusToIdStatus[i],szSetting,10);
+ if(dat->mainStatusPath[i]==NULL)
+ DBDeleteContactSetting(NULL,"Icons",szSetting);
+ else
+ DBWriteContactSettingString(NULL,"Icons",szSetting,dat->mainStatusPath[i]);
+ }
+ for(i=0;i<dat->protoCount;i++) {
+ for( j=0; j < SIZEOF(skinIconStatusToIdStatus); j++ ) {
+ flags=(DWORD)CallProtoService(dat->protoIcons[i].proto->szName,PS_GETCAPS,PFLAGNUM_2,0);
+ mir_snprintf(szSetting,SIZEOF(szSetting),"%s%d",dat->protoIcons[i].proto->szName,skinIconStatusToIdStatus[j]);
+ if(dat->protoIcons[i].iconPath[j]==NULL || !(flags&skinIconStatusToPf2[j]))
+ DBDeleteContactSetting(NULL,"Icons",szSetting);
+ else
+ DBWriteContactSettingString(NULL,"Icons",szSetting,dat->protoIcons[i].iconPath[j]);
+ }
+ }
+ szSetting[0]='p';
+ i=SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETCOUNT,0,0)-1;
+ _itoa(i,szSetting+1,10);
+ DBDeleteContactSetting(NULL,"Icons",szSetting);
+ for(;i>=2;i--) {
+ proto=(PROTOCOLDESCRIPTOR*)SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETITEMDATA,i,0);
+ _itoa(i-2,szSetting+1,10);
+ DBWriteContactSettingString(NULL,"Icons",szSetting,proto->szName);
+ }
+ FreeAllIcons();
+ LoadAllIcons();
+ NotifyEventHooks(hIconsChangedEvent,0,0);
+ return TRUE;
+ }
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ { int i,j;
+ DestroyWindow(dat->hwndIndex);
+ for( i=0; i < SIZEOF(mainIcons); i++ )
+ if(dat->mainIconPath[i]!=NULL) mir_free(dat->mainIconPath[i]);
+ mir_free(dat->mainIconPath);
+ for( i=0; i < SIZEOF(skinIconStatusToIdStatus); i++ )
+ if(dat->mainStatusPath[i]!=NULL) mir_free(dat->mainStatusPath[i]);
+ mir_free(dat->mainStatusPath);
+ for(i=0;i<dat->protoCount;i++) {
+ for( j=0; j < SIZEOF(skinIconStatusToIdStatus); j++ ) {
+ if(dat->protoIcons[i].iconPath[j]!=NULL) mir_free(dat->protoIcons[i].iconPath[j]);
+ }
+ mir_free(dat->protoIcons[i].iconPath);
+ }
+ mir_free(dat->protoIcons);
+ mir_free(dat);
+ break;
+ }
+ }
+ return FALSE;
+}
+
+static int IconExists(const char *filename,int id)
+{
+ HICON hIcon;
+ hIcon=ExtractIconA(hMiranda,filename,-id);
+ if(hIcon==NULL) return 0;
+ if((int)hIcon==1) return 0;
+ DestroyIcon(hIcon);
+ return 1;
+}
+
+static UINT mirandaIconSetIds[]={IDI_RECVMSG,IDI_URL,IDI_ONLINE,IDI_OFFLINE,IDI_AWAY,IDI_NA};
+static int IsMirandaIconSet(const char *filename)
+{
+ int i;
+ if(_access(filename,0)!=0) return 0;
+ for( i=0; i < SIZEOF(mirandaIconSetIds); i++ )
+ if(!IconExists(filename,mirandaIconSetIds[i])) return 0;
+ return 1;
+}
+
+BOOL CALLBACK DlgProcIconIndex(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static HWND hwndParent,hwndDragOver;
+ static int dragging;
+ static int dragItem,dropHiLite;
+ static int originalPreviewHeight;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ hwndParent=(HWND)lParam;
+ dragging=dragItem=0;
+ TranslateDialogDefault(hwndDlg);
+ ListView_SetImageList(GetDlgItem(hwndDlg,IDC_PREVIEW),ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),ILC_COLOR32|ILC_MASK,0,100),LVSIL_NORMAL);
+ ListView_SetIconSpacing(GetDlgItem(hwndDlg,IDC_PREVIEW),56,67);
+ { RECT rcThis,rcParent;
+ GetWindowRect(hwndDlg,&rcThis);
+ GetWindowRect(hwndParent,&rcParent);
+ OffsetRect(&rcThis,rcParent.right-rcThis.left,0);
+ OffsetRect(&rcThis,0,rcParent.top-rcThis.top);
+ GetWindowRect(GetParent(hwndParent),&rcParent);
+ if(rcThis.right>GetSystemMetrics(SM_CXSCREEN)) {
+ OffsetRect(&rcParent,GetSystemMetrics(SM_CXSCREEN)-rcThis.right,0);
+ OffsetRect(&rcThis,GetSystemMetrics(SM_CXSCREEN)-rcThis.right,0);
+ MoveWindow(GetParent(hwndParent),rcParent.left,rcParent.top,rcParent.right-rcParent.left,rcParent.bottom-rcParent.top,TRUE);
+ }
+ MoveWindow(hwndDlg,rcThis.left,rcThis.top,rcThis.right-rcThis.left,rcThis.bottom-rcThis.top,FALSE);
+ }
+ { RECT rc;
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_PREVIEW),&rc);
+ originalPreviewHeight=rc.bottom-rc.top;
+ }
+ { int i,item;
+ TCHAR text[128];
+ LPARAM lData;
+ for ( i = SendDlgItemMessage(hwndParent,IDC_CATEGORYLIST,LB_GETCOUNT,0,0)-1; i >= 2; i-- ) {
+ SendDlgItemMessage(hwndParent,IDC_CATEGORYLIST,LB_GETTEXT,i,(LPARAM)text);
+ lData=SendDlgItemMessage(hwndParent,IDC_CATEGORYLIST,LB_GETITEMDATA,i,0);
+ item = SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_ADDSTRING,0,(LPARAM)text);
+ SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_SETITEMDATA,item,lData);
+ }
+ SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_SETCURSEL,0,0);
+ }
+ { HRESULT (STDAPICALLTYPE *MySHAutoComplete)(HWND,DWORD);
+ MySHAutoComplete=(HRESULT (STDAPICALLTYPE*)(HWND,DWORD))GetProcAddress(GetModuleHandleA("shlwapi"),"SHAutoComplete");
+ if(MySHAutoComplete) MySHAutoComplete(GetDlgItem(hwndDlg,IDC_ICONSET),1);
+ }
+ SetDlgItemTextA(hwndDlg,IDC_ICONSET,"icons.dll");
+ return TRUE;
+ case DM_REBUILDICONSPREVIEW:
+ { LVITEMA lvi;
+ char filename[MAX_PATH],caption[64];
+ HIMAGELIST hIml;
+ int count,isMiranda,i;
+ HICON hIcon;
+
+ SetCursor(LoadCursor(NULL,IDC_WAIT));
+ ListView_DeleteAllItems(GetDlgItem(hwndDlg,IDC_PREVIEW));
+ hIml=ListView_GetImageList(GetDlgItem(hwndDlg,IDC_PREVIEW),LVSIL_NORMAL);
+ ImageList_RemoveAll(hIml);
+ GetDlgItemTextA(hwndDlg,IDC_ICONSET,filename,SIZEOF(filename));
+
+ isMiranda=IsMirandaIconSet(filename);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_IMPORTMULTI),isMiranda);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_TOMAIN),isMiranda);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_TODEFICON),isMiranda);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_TOPROTO),isMiranda);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_PROTOLIST),isMiranda);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_IMPORT),isMiranda);
+ { RECT rcPreview,rcGroup;
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_PREVIEW),&rcPreview);
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_IMPORTMULTI),&rcGroup);
+ SetWindowPos(GetDlgItem(hwndDlg,IDC_PREVIEW),0,0,0,rcPreview.right-rcPreview.left,isMiranda?originalPreviewHeight:rcGroup.bottom-rcPreview.top,SWP_NOZORDER|SWP_NOMOVE);
+ }
+
+ if(_access(filename,0)!=0) {
+ SetCursor(LoadCursor(NULL,IDC_ARROW));
+ break;
+ }
+
+ lvi.mask=LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;
+ lvi.iSubItem=0;
+ lvi.iItem=0;
+ if(isMiranda) {
+ for( i=0; i < SIZEOF(mainIcons); i++ ) {
+ hIcon=ExtractIconA(GetModuleHandle(NULL),filename,-(int)(mainIcons[i].id<SKINICON_OTHER_MIRANDA?eventIconToResourceId[mainIcons[i].id-SKINICON_EVENT_MESSAGE]:otherIconToResourceId[mainIcons[i].id-SKINICON_OTHER_MIRANDA]));
+ if(hIcon==NULL) continue;
+ lvi.iImage=ImageList_AddIcon(hIml,hIcon);
+ DestroyIcon(hIcon);
+ lvi.pszText=Translate(mainIcons[lvi.iItem].description);
+ lvi.lParam=-(int)(mainIcons[i].id<SKINICON_OTHER_MIRANDA?eventIconToResourceId[mainIcons[i].id-SKINICON_EVENT_MESSAGE]:otherIconToResourceId[mainIcons[i].id-SKINICON_OTHER_MIRANDA]);
+ SendMessageA( GetDlgItem(hwndDlg,IDC_PREVIEW), LVM_INSERTITEMA, 0, (LPARAM)&lvi );
+ lvi.iItem++;
+ }
+ for( i=0; i < SIZEOF(skinIconStatusToIdStatus); i++ ) {
+ hIcon=ExtractIconA(GetModuleHandle(NULL),filename,-(int)skinIconStatusToResourceId[i]);
+ if(hIcon==NULL) continue;
+ lvi.iImage=ImageList_AddIcon(hIml,hIcon);
+ DestroyIcon(hIcon);
+ lvi.pszText=(char*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION,skinIconStatusToIdStatus[i],0);
+ lvi.lParam=-(int)skinIconStatusToResourceId[i];
+ SendMessageA( GetDlgItem(hwndDlg,IDC_PREVIEW), LVM_INSERTITEMA, 0, (LPARAM)&lvi );
+ lvi.iItem++;
+ }
+ }
+ count=(int)ExtractIconA(GetModuleHandle(NULL),filename,-1);
+ for(i=0;i<count;lvi.iItem++,i++) {
+ wsprintfA(caption,"%d",i+1);
+ lvi.pszText=caption;
+ hIcon=ExtractIconA(GetModuleHandle(NULL),filename,i);
+ lvi.iImage=ImageList_AddIcon(hIml,hIcon);
+ DestroyIcon(hIcon);
+ lvi.lParam=i;
+ SendMessageA( GetDlgItem(hwndDlg,IDC_PREVIEW), LVM_INSERTITEMA, 0, (LPARAM)&lvi );
+ }
+ SetCursor(LoadCursor(NULL,IDC_ARROW));
+ break;
+ }
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_BROWSE:
+ { char str[MAX_PATH];
+ OPENFILENAMEA ofn;
+ char filter[512],*pfilter;
+
+ GetDlgItemTextA(hwndDlg,IDC_ICONSET,str,SIZEOF(str));
+ ZeroMemory(&ofn, sizeof(ofn));
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner = GetParent(hwndDlg);
+ ofn.hInstance = NULL;
+ strcpy(filter,Translate("Icon Sets"));
+ strcat(filter," (*.dll;*.icl;*.exe;*.ico)");
+ pfilter=filter+strlen(filter)+1;
+ strcpy(pfilter,"*.DLL;*.ICL;*.EXE;*.ICO");
+ pfilter=pfilter+strlen(pfilter)+1;
+ strcpy(pfilter,Translate("All Files"));
+ strcat(pfilter," (*)");
+ pfilter=pfilter+strlen(pfilter)+1;
+ strcpy(pfilter,"*");
+ pfilter=pfilter+strlen(pfilter)+1;
+ *pfilter='\0';
+ ofn.lpstrFilter = filter;
+ ofn.lpstrFile = str;
+ ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
+ ofn.nMaxFile = SIZEOF(str);
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.lpstrDefExt = "dll";
+ if(!GetOpenFileNameA(&ofn)) break;
+ SetDlgItemTextA(hwndDlg,IDC_ICONSET,str);
+ break;
+ }
+ case IDC_GETMORE:
+ { char szVer[64],szUrl[256];
+ CallService(MS_SYSTEM_GETVERSIONTEXT,SIZEOF(szVer),(LPARAM)szVer);
+ while(strchr(szVer,' ')) *strchr(szVer,' ')='_';
+ wsprintfA(szUrl,"http://www.miranda-im.org/download/index.php",szVer);
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)szUrl);
+ break;
+ }
+ case IDC_ICONSET:
+ if(HIWORD(wParam)==EN_CHANGE)
+ SendMessage(hwndDlg,DM_REBUILDICONSPREVIEW,0,0);
+ break;
+ case IDC_TOMAIN:
+ case IDC_TODEFICON:
+ case IDC_TOPROTO:
+ EnableWindow(GetDlgItem(hwndDlg,IDC_IMPORT),IsDlgButtonChecked(hwndDlg,IDC_TOMAIN) || IsDlgButtonChecked(hwndDlg,IDC_TODEFICON) || IsDlgButtonChecked(hwndDlg,IDC_TOPROTO));
+ break;
+ case IDC_IMPORT:
+ { char filetmp[MAX_PATH],filename[MAX_PATH],path[MAX_PATH];
+ int i;
+ struct IconPreview ico;
+ HICON hIcon;
+
+ GetDlgItemTextA(hwndDlg,IDC_ICONSET,filetmp,SIZEOF(filetmp));
+ CallService(MS_UTILS_PATHTORELATIVE, (WPARAM)filetmp, (LPARAM)filename);
+ ico.description=path;
+ if(IsDlgButtonChecked(hwndDlg,IDC_TOMAIN)) {
+ for( i=0; i < SIZEOF(mainIcons); i++ ) {
+ hIcon=ExtractIconA(GetModuleHandle(NULL),filename,-(int)(mainIcons[i].id<SKINICON_OTHER_MIRANDA?eventIconToResourceId[mainIcons[i].id-SKINICON_EVENT_MESSAGE]:otherIconToResourceId[mainIcons[i].id-SKINICON_OTHER_MIRANDA]));
+ if(hIcon==NULL) continue;
+ ico.id=mainIcons[i].id;
+ ico.main=1;
+ wsprintfA(path,"%s,%d",filename,-(int)(mainIcons[i].id<SKINICON_OTHER_MIRANDA?eventIconToResourceId[mainIcons[i].id-SKINICON_EVENT_MESSAGE]:otherIconToResourceId[mainIcons[i].id-SKINICON_OTHER_MIRANDA]));
+ SendMessage(hwndParent,DM_CHANGESPECIFICICON,(WPARAM)(PROTOCOLDESCRIPTOR*)NULL,(LPARAM)&ico);
+ }
+ }
+ if(IsDlgButtonChecked(hwndDlg,IDC_TODEFICON)) {
+ for( i=0; i < SIZEOF(skinIconStatusToIdStatus); i++ ) {
+ hIcon=ExtractIconA(GetModuleHandle(NULL),filename,-(int)skinIconStatusToResourceId[i]);
+ if(hIcon==NULL) continue;
+ ico.id=i;
+ ico.main=0;
+ wsprintfA(path,"%s,%d",filename,-(int)skinIconStatusToResourceId[i]);
+ SendMessage(hwndParent,DM_CHANGESPECIFICICON,(WPARAM)(PROTOCOLDESCRIPTOR**)NULL,(LPARAM)&ico);
+ }
+ }
+ if(IsDlgButtonChecked(hwndDlg,IDC_TOPROTO)) {
+ PROTOCOLDESCRIPTOR *proto;
+ proto=(PROTOCOLDESCRIPTOR*)SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETCURSEL,0,0),0);
+ for( i=0; i < SIZEOF(skinIconStatusToIdStatus); i++ ) {
+ hIcon=ExtractIconA(GetModuleHandle(NULL),filename,-(int)skinIconStatusToResourceId[i]);
+ if(hIcon==NULL) continue;
+ ico.id=i;
+ ico.main=0;
+ wsprintfA(path,"%s,%d",filename,-(int)skinIconStatusToResourceId[i]);
+ SendMessage(hwndParent,DM_CHANGESPECIFICICON,(WPARAM)proto,(LPARAM)&ico);
+ }
+ }
+ SendMessage(hwndParent,DM_REBUILDICONSPREVIEW,0,0);
+ break;
+ }
+ }
+ break;
+ case WM_MOUSEMOVE:
+ if(dragging) {
+ LVHITTESTINFO lvhti;
+ int onItem=0;
+ HWND hwndOver;
+ RECT rc;
+ POINT ptDrag;
+
+ lvhti.pt.x=(short)LOWORD(lParam); lvhti.pt.y=(short)HIWORD(lParam);
+ ClientToScreen(hwndDlg,&lvhti.pt);
+ hwndOver=WindowFromPoint(lvhti.pt);
+ GetWindowRect(hwndOver,&rc);
+ ptDrag.x=lvhti.pt.x-rc.left; ptDrag.y=lvhti.pt.y-rc.top;
+ if(hwndOver!=hwndDragOver) {
+ ImageList_DragLeave(hwndDragOver);
+ hwndDragOver=hwndOver;
+ ImageList_DragEnter(hwndDragOver,ptDrag.x,ptDrag.y);
+ }
+ ImageList_DragMove(ptDrag.x,ptDrag.y);
+ if(hwndOver==GetDlgItem(hwndParent,IDC_PREVIEW)) {
+ ScreenToClient(GetDlgItem(hwndParent,IDC_PREVIEW),&lvhti.pt);
+ if(ListView_HitTest(GetDlgItem(hwndParent,IDC_PREVIEW),&lvhti)!=-1) {
+ if(lvhti.iItem!=dropHiLite) {
+ ImageList_DragLeave(hwndDragOver);
+ if(dropHiLite!=-1) ListView_SetItemState(GetDlgItem(hwndParent,IDC_PREVIEW),dropHiLite,0,LVIS_DROPHILITED);
+ dropHiLite=lvhti.iItem;
+ ListView_SetItemState(GetDlgItem(hwndParent,IDC_PREVIEW),dropHiLite,LVIS_DROPHILITED,LVIS_DROPHILITED);
+ UpdateWindow(GetDlgItem(hwndParent,IDC_PREVIEW));
+ ImageList_DragEnter(hwndDragOver,ptDrag.x,ptDrag.y);
+ }
+ onItem=1;
+ }
+ }
+ if(!onItem && dropHiLite!=-1) {
+ ImageList_DragLeave(hwndDragOver);
+ ListView_SetItemState(GetDlgItem(hwndParent,IDC_PREVIEW),dropHiLite,0,LVIS_DROPHILITED);
+ UpdateWindow(GetDlgItem(hwndParent,IDC_PREVIEW));
+ ImageList_DragEnter(hwndDragOver,ptDrag.x,ptDrag.y);
+ dropHiLite=-1;
+ }
+ SetCursor(LoadCursor(NULL,onItem?IDC_ARROW:IDC_NO));
+ }
+ break;
+ case WM_LBUTTONUP:
+ if(dragging) {
+ ReleaseCapture();
+ ImageList_EndDrag();
+ dragging=0;
+ if(dropHiLite!=-1) {
+ char path[MAX_PATH],fullPath[MAX_PATH],filename[MAX_PATH];
+ LVITEM lvi;
+ GetDlgItemTextA(hwndDlg,IDC_ICONSET,fullPath,SIZEOF(fullPath));
+ CallService(MS_UTILS_PATHTORELATIVE, (WPARAM)fullPath, (LPARAM)filename);
+ lvi.mask=LVIF_PARAM;
+ lvi.iItem=dragItem; lvi.iSubItem=0;
+ ListView_GetItem(GetDlgItem(hwndDlg,IDC_PREVIEW),&lvi);
+ wsprintfA(path,"%s,%d",filename,(int)lvi.lParam);
+ SendMessage(hwndParent,DM_CHANGEICON,dropHiLite,(LPARAM)path);
+ ListView_SetItemState(GetDlgItem(hwndParent,IDC_PREVIEW),dropHiLite,0,LVIS_DROPHILITED);
+ }
+ }
+ break;
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case IDC_PREVIEW:
+ switch(((LPNMHDR)lParam)->code) {
+ case LVN_BEGINDRAG:
+ SetCapture(hwndDlg);
+ dragging=1;
+ dragItem=((LPNMLISTVIEW)lParam)->iItem;
+ dropHiLite=-1;
+ ImageList_BeginDrag(ListView_GetImageList(GetDlgItem(hwndDlg,IDC_PREVIEW),LVSIL_NORMAL),dragItem,GetSystemMetrics(SM_CXICON)/2,GetSystemMetrics(SM_CYICON)/2);
+ { POINT pt;
+ RECT rc;
+ GetCursorPos(&pt);
+ GetWindowRect(hwndDlg,&rc);
+ ImageList_DragEnter(hwndDlg,pt.x-rc.left,pt.y-rc.top);
+ hwndDragOver=hwndDlg;
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ DestroyWindow(hwndDlg);
+ EnableWindow(GetDlgItem(hwndParent,IDC_IMPORT),TRUE);
+ break;
+ }
+ return FALSE;
+}
diff --git a/miranda-wine/src/modules/skin/sounds.c b/miranda-wine/src/modules/skin/sounds.c
new file mode 100644
index 0000000..2ae2847
--- /dev/null
+++ b/miranda-wine/src/modules/skin/sounds.c
@@ -0,0 +1,403 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+struct SoundItem {
+ char* name;
+ TCHAR* section;
+ TCHAR* description;
+ char* tempFile;
+};
+
+static struct SoundItem *soundList = NULL;
+static int soundCount;
+static HANDLE hPlayEvent = NULL;
+
+static int ServiceSkinAddNewSound(WPARAM wParam,LPARAM lParam)
+{
+ struct SoundItem* item;
+ SKINSOUNDDESCEX *ssd=(SKINSOUNDDESCEX*)lParam;
+
+ if (ssd->cbSize!=sizeof(SKINSOUNDDESC) && ssd->cbSize!=sizeof(SKINSOUNDDESCEX))
+ return 0;
+
+ soundList=(struct SoundItem*)mir_realloc(soundList,sizeof(struct SoundItem)*(soundCount+1));
+ item = &soundList[soundCount++];
+ item->name = mir_strdup( ssd->pszName );
+ item->description = LangPackPcharToTchar( ssd->pszDescription );
+ item->section = LangPackPcharToTchar( ssd->cbSize==sizeof(SKINSOUNDDESCEX) ? ssd->pszSection : "Other" );
+ item->tempFile = NULL;
+ if ( ssd->pszDefaultFile ) {
+ DBVARIANT dbv;
+
+ if ( DBGetContactSetting(NULL, "SkinSounds", item->name, &dbv))
+ DBWriteContactSettingString(NULL, "SkinSounds", item->name, ssd->pszDefaultFile);
+ else
+ DBFreeVariant(&dbv);
+ }
+ return 0;
+}
+
+static int SkinPlaySoundDefault(WPARAM wParam, LPARAM lParam)
+{
+ char * pszFile = (char *) lParam;
+ if ( pszFile && (DBGetContactSettingByte(NULL,"Skin","UseSound",1) || (int)wParam==1)) {
+ PlaySoundA(pszFile, NULL, SND_ASYNC | SND_FILENAME | SND_NOWAIT);
+ }
+ return 0;
+}
+
+static int ServiceSkinPlaySound(WPARAM wParam, LPARAM lParam)
+{
+ char * pszSoundName = (char *)lParam;
+ int j;
+
+ for (j=0; j<soundCount; j++) {
+ if (pszSoundName&&strcmp(soundList[j].name, pszSoundName)== 0) {
+ if (DBGetContactSettingByte(NULL, "SkinSoundsOff", pszSoundName, 0)==0) {
+ DBVARIANT dbv;
+
+ if (DBGetContactSetting(NULL, "SkinSounds", pszSoundName, &dbv)==0) {
+ char szFull[MAX_PATH];
+
+ CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM)dbv.pszVal, (LPARAM)szFull);
+ NotifyEventHooks(hPlayEvent, 0, (LPARAM)szFull);
+ DBFreeVariant(&dbv);
+ }
+ }
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static HTREEITEM FindNamedTreeItemAtRoot(HWND hwndTree, const TCHAR* name)
+{
+ TVITEM tvi;
+ TCHAR str[128];
+
+ tvi.mask = TVIF_TEXT;
+ tvi.pszText = str;
+ tvi.cchTextMax = SIZEOF(str);
+ tvi.hItem = TreeView_GetRoot(hwndTree);
+ while( tvi.hItem != NULL ) {
+ TreeView_GetItem( hwndTree, &tvi );
+ if ( !_tcsicmp( str, name ))
+ return tvi.hItem;
+
+ tvi.hItem = TreeView_GetNextSibling( hwndTree, tvi.hItem );
+ }
+ return NULL;
+}
+
+#define DM_REBUILD_STREE (WM_USER+1)
+#define DM_HIDEPANE (WM_USER+2)
+#define DM_SHOWPANE (WM_USER+3)
+BOOL CALLBACK DlgProcSoundOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static HWND hwndTree = NULL;
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ hwndTree = GetDlgItem(hwndDlg, IDC_SOUNDTREE);
+ SetWindowLong(hwndTree,GWL_STYLE,GetWindowLong(hwndTree,GWL_STYLE)|TVS_NOHSCROLL|TVS_CHECKBOXES);
+ SendMessage(hwndDlg, DM_HIDEPANE, 0, 0);
+ SendMessage(hwndDlg, DM_REBUILD_STREE, 0, 0);
+ TreeView_SetItemState(hwndTree, 0, TVIS_SELECTED, TVIS_SELECTED);
+ return TRUE;
+
+ case DM_REBUILD_STREE:
+ {
+ TVINSERTSTRUCT tvis;
+ int i;
+
+ TreeView_SelectItem(hwndTree, NULL);
+ ShowWindow(hwndTree, SW_HIDE);
+ TreeView_DeleteAllItems(hwndTree);
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_SORT;
+ tvis.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
+ tvis.item.state = tvis.item.stateMask = TVIS_EXPANDED;
+ for( i=0; i < soundCount; i++ ) {
+ tvis.item.stateMask = TVIS_EXPANDED;
+ tvis.item.state = TVIS_EXPANDED;
+ tvis.hParent = FindNamedTreeItemAtRoot( hwndTree, soundList[i].section );
+ if ( tvis.hParent == NULL ) {
+ tvis.item.lParam = -1;
+ tvis.item.pszText = soundList[i].section;
+ tvis.hParent = tvis.item.hItem = TreeView_InsertItem( hwndTree, &tvis );
+ tvis.item.stateMask = TVIS_STATEIMAGEMASK;
+ tvis.item.state = INDEXTOSTATEIMAGEMASK(0);
+ TreeView_SetItem( hwndTree, &tvis.item );
+ }
+ tvis.item.stateMask = TVIS_STATEIMAGEMASK;
+ tvis.item.state = INDEXTOSTATEIMAGEMASK(!DBGetContactSettingByte(NULL,"SkinSoundsOff",soundList[i].name,0)?2:1);
+ tvis.item.lParam = i;
+ tvis.item.pszText = soundList[i].description;
+ TreeView_InsertItem( hwndTree, &tvis );
+ }
+ { TVITEM tvi;
+ tvi.hItem = TreeView_GetRoot(hwndTree);
+ while ( tvi.hItem != NULL ) {
+ tvi.mask = TVIF_PARAM | TVIF_HANDLE | TVIF_STATE;
+ TreeView_GetItem(hwndTree, &tvi);
+ if ( tvi.lParam == -1 )
+ TreeView_SetItemState(hwndTree, tvi.hItem, INDEXTOSTATEIMAGEMASK(0), TVIS_STATEIMAGEMASK);
+
+ tvi.hItem=TreeView_GetNextSibling(hwndTree,tvi.hItem);
+ } }
+
+ ShowWindow(hwndTree, SW_SHOW);
+ break;
+ }
+ case DM_HIDEPANE:
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SGROUP), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_NAME), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_NAMEVAL), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SLOC), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_LOCATION), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_CHANGE), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_PREVIEW), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_GETMORE), SW_HIDE);
+ break;
+ case DM_SHOWPANE:
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SGROUP), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_NAME), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_NAMEVAL), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SLOC), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_LOCATION), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_CHANGE), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_PREVIEW), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_GETMORE), SW_SHOW);
+ break;
+ case WM_COMMAND:
+ if(LOWORD(wParam)==IDC_PREVIEW) {
+ TVITEM tvi;
+ HTREEITEM hti;
+
+ ZeroMemory(&tvi,sizeof(tvi));
+ ZeroMemory(&hti,sizeof(hti));
+ hti=TreeView_GetSelection(hwndTree);
+ if (hti==NULL) break;
+ tvi.mask=TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM|TVIF_TEXT;
+ tvi.hItem = hti;
+ if (TreeView_GetItem(hwndTree, &tvi)==FALSE) break;
+ if (tvi.lParam==-1) break;
+ if (soundList[tvi.lParam].tempFile)
+ NotifyEventHooks(hPlayEvent, 1, (LPARAM)soundList[tvi.lParam].tempFile);
+ else {
+ DBVARIANT dbv;
+ if(!DBGetContactSetting(NULL,"SkinSounds",soundList[tvi.lParam].name,&dbv)) {
+ char szPathFull[MAX_PATH];
+
+ CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM)dbv.pszVal, (LPARAM)szPathFull);
+ NotifyEventHooks(hPlayEvent, 1, (LPARAM)szPathFull);
+ DBFreeVariant(&dbv);
+ } }
+ break;
+ }
+ if(LOWORD(wParam)==IDC_CHANGE) {
+ char str[MAX_PATH], strFull[MAX_PATH];
+ OPENFILENAMEA ofn;
+ TVITEM tvi;
+ HTREEITEM hti;
+
+ ZeroMemory(&tvi,sizeof(tvi));
+ ZeroMemory(&hti,sizeof(hti));
+ hti=TreeView_GetSelection(hwndTree);
+ if (hti==NULL) break;
+ tvi.mask=TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM|TVIF_TEXT;
+ tvi.hItem = hti;
+ if (TreeView_GetItem(hwndTree, &tvi)==FALSE) break;
+ if (tvi.lParam==-1) break;
+ str[0] = 0;
+ if (soundList[tvi.lParam].tempFile) {
+ mir_snprintf(strFull, SIZEOF(strFull), "%s", soundList[tvi.lParam].tempFile);
+ }
+ else {
+ if (DBGetContactSettingByte(NULL, "SkinSoundsOff", soundList[tvi.lParam].name, 0)==0) {
+ DBVARIANT dbv;
+
+ if (DBGetContactSetting(NULL, "SkinSounds", soundList[tvi.lParam].name, &dbv)==0) {
+ CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM)dbv.pszVal, (LPARAM)str);
+ DBFreeVariant(&dbv);
+ }
+ }
+ }
+ mir_snprintf(strFull, SIZEOF(strFull), "%s", soundList[tvi.lParam].tempFile?soundList[tvi.lParam].tempFile:"");
+ CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM)strFull, (LPARAM)str);
+ ZeroMemory(&ofn, sizeof(ofn));
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner = GetParent(hwndDlg);
+ ofn.hInstance = NULL;
+ ofn.lpstrFilter = "Wave Files (*.wav)\0*.WAV\0All Files (*)\0*\0";
+ ofn.lpstrFile = str;
+ ofn.Flags = OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
+ ofn.nMaxFile = SIZEOF(str);
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.lpstrDefExt = "wav";
+ if(!GetOpenFileNameA(&ofn)) break;
+ CallService(MS_UTILS_PATHTORELATIVE, (WPARAM)str, (LPARAM)strFull);
+ soundList[tvi.lParam].tempFile = mir_strdup(strFull);
+ SetDlgItemTextA(hwndDlg, IDC_LOCATION, strFull);
+ }
+ if(LOWORD(wParam)==IDC_GETMORE) {
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)"http://addons.miranda-im.org/index.php?action=display&id=5");
+ break;
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ if (((LPNMHDR)lParam)->code == PSN_APPLY)
+ {
+ int i;
+ for(i=0;i<soundCount;i++) {
+ if(soundList[i].tempFile)
+ DBWriteContactSettingString(NULL,"SkinSounds",soundList[i].name,soundList[i].tempFile);
+ }
+ {
+ TVITEM tvi,tvic;
+ tvi.hItem = TreeView_GetRoot(hwndTree);
+ while(tvi.hItem!=NULL) {
+ tvi.mask = TVIF_PARAM|TVIF_HANDLE|TVIF_STATE;
+ TreeView_GetItem(hwndTree, &tvi);
+ if (tvi.lParam==-1) {
+ tvic.hItem = TreeView_GetChild(hwndTree, tvi.hItem);
+ while(tvic.hItem!=NULL) {
+ tvic.mask = TVIF_PARAM|TVIF_HANDLE|TVIF_STATE;
+ TreeView_GetItem(hwndTree, &tvic);
+ if(((tvic.state&TVIS_STATEIMAGEMASK)>>12==2)) {
+ DBCONTACTGETSETTING cgs;
+ cgs.szModule="SkinSoundsOff";
+ cgs.szSetting=soundList[tvic.lParam].name;
+ CallService(MS_DB_CONTACT_DELETESETTING,(WPARAM)(HANDLE)NULL,(LPARAM)&cgs);
+ }
+ else DBWriteContactSettingByte(NULL,"SkinSoundsOff",soundList[tvic.lParam].name,1);
+ tvic.hItem=TreeView_GetNextSibling(hwndTree,tvic.hItem);
+ } }
+
+ tvi.hItem=TreeView_GetNextSibling(hwndTree,tvi.hItem);
+ } }
+
+ return TRUE;
+ }
+ break;
+ case IDC_SOUNDTREE:
+ switch(((NMHDR*)lParam)->code) {
+ case TVN_SELCHANGEDA:
+ {
+ NMTREEVIEW *pnmtv = (NMTREEVIEW*)lParam;
+ TVITEM tvi = pnmtv->itemNew;
+
+ if (tvi.lParam==-1) {
+ SendMessage(hwndDlg, DM_HIDEPANE, 0, 0);
+ }
+ else {
+ TCHAR buf[256];
+ DBVARIANT dbv;
+
+ mir_sntprintf(buf, SIZEOF(buf), _T("%s: %s"), soundList[tvi.lParam].section, soundList[tvi.lParam].description);
+ SetDlgItemText(hwndDlg, IDC_NAMEVAL, buf);
+ if (soundList[tvi.lParam].tempFile)
+ SetDlgItemTextA(hwndDlg, IDC_LOCATION, soundList[tvi.lParam].tempFile);
+ else if(!DBGetContactSetting(NULL,"SkinSounds",soundList[tvi.lParam].name,&dbv)) {
+ SetDlgItemTextA(hwndDlg, IDC_LOCATION, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ else SetDlgItemText(hwndDlg, IDC_LOCATION, TranslateT("<not specified>"));
+ SendMessage(hwndDlg, DM_SHOWPANE, 0, 0);
+ }
+ }
+ break;
+ case TVN_KEYDOWN:
+ {
+ NMTVKEYDOWN* ptkd = (NMTVKEYDOWN*)lParam;
+ TVHITTESTINFO hti;
+
+ if (ptkd) {
+ if (ptkd->wVKey == 0x0020) {
+ hti.pt.x=(short)LOWORD(GetMessagePos());
+ hti.pt.y=(short)HIWORD(GetMessagePos());
+ ScreenToClient(((LPNMHDR)lParam)->hwndFrom,&hti.pt);
+ if(TreeView_HitTest(((LPNMHDR)lParam)->hwndFrom,&hti)) {
+ if (hti.flags&TVHT_ONITEM) {
+ if (TreeView_GetParent(hwndTree, hti.hItem)!=TreeView_GetRoot(hwndTree)) {
+ // the stupid checkbox gets enabled here.
+ }
+ else {
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+ case NM_CLICK:
+ {
+ TVHITTESTINFO hti;
+ hti.pt.x=(short)LOWORD(GetMessagePos());
+ hti.pt.y=(short)HIWORD(GetMessagePos());
+ ScreenToClient(((LPNMHDR)lParam)->hwndFrom,&hti.pt);
+ if(TreeView_HitTest(((LPNMHDR)lParam)->hwndFrom,&hti)) {
+ if (hti.flags&TVHT_ONITEM) {
+ if(hti.flags&TVHT_ONITEMSTATEICON) {
+ if (TreeView_GetParent(hwndTree, hti.hItem)!=TreeView_GetRoot(hwndTree))
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+int InitSkinSounds(void)
+{
+ soundList=NULL;
+ soundCount=0;
+ CreateServiceFunction(MS_SKIN_ADDNEWSOUND,ServiceSkinAddNewSound);
+ CreateServiceFunction(MS_SKIN_PLAYSOUND,ServiceSkinPlaySound);
+ hPlayEvent=CreateHookableEvent(ME_SKIN_PLAYINGSOUND);
+ SetHookDefaultForHookableEvent(hPlayEvent, SkinPlaySoundDefault);
+ return 0;
+}
+
+void UninitSkinSounds(void)
+{
+ int i;
+ for(i=0;i<soundCount;i++) {
+ mir_free(soundList[i].name);
+ mir_free(soundList[i].section);
+ mir_free(soundList[i].description);
+ if (soundList[i].tempFile) mir_free(soundList[i].tempFile);
+ }
+ if(soundCount) mir_free(soundList);
+}
diff --git a/miranda-wine/src/modules/srauth/auth.c b/miranda-wine/src/modules/srauth/auth.c
new file mode 100644
index 0000000..cefe88c
--- /dev/null
+++ b/miranda-wine/src/modules/srauth/auth.c
@@ -0,0 +1,97 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+#define MS_AUTH_SHOWREQUEST "Auth/ShowRequest"
+#define MS_AUTH_SHOWADDED "Auth/ShowAdded"
+
+BOOL CALLBACK DlgProcAuthReq(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+BOOL CALLBACK DlgProcAdded(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+
+int ShowReqWindow(WPARAM wParam,LPARAM lParam)
+{
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_AUTHREQ),NULL,DlgProcAuthReq,(LPARAM)((CLISTEVENT *)lParam)->hDbEvent);
+ return 0;
+}
+
+int ShowAddedWindow(WPARAM wParam,LPARAM lParam)
+{
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_ADDED),NULL,DlgProcAdded,(LPARAM)((CLISTEVENT *)lParam)->hDbEvent);
+ return 0;
+}
+
+static int AuthEventAdded(WPARAM wParam,LPARAM lParam)
+{
+ DBEVENTINFO dbei;
+ CLISTEVENT cli;
+ char szTooltip[256];
+ HANDLE hcontact;
+
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=0;
+ CallService(MS_DB_EVENT_GET,(WPARAM)lParam,(LPARAM)&dbei);
+ if(dbei.flags&(DBEF_SENT|DBEF_READ) || (dbei.eventType!=EVENTTYPE_AUTHREQUEST && dbei.eventType!=EVENTTYPE_ADDED)) return 0;
+
+ dbei.cbBlob=CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)lParam,0);
+ dbei.pBlob=mir_alloc(dbei.cbBlob);
+ CallService(MS_DB_EVENT_GET,(WPARAM)(HANDLE)lParam,(LPARAM)&dbei);
+
+ hcontact=*((PHANDLE)(dbei.pBlob+sizeof(DWORD)));
+
+ ZeroMemory(&cli,sizeof(cli));
+ cli.cbSize=sizeof(cli);
+ cli.hContact=hcontact;
+ cli.pszTooltip=szTooltip;
+ cli.lParam=lParam;
+ cli.hDbEvent=(HANDLE)lParam;
+
+ if(dbei.eventType==EVENTTYPE_AUTHREQUEST)
+ {
+ mir_snprintf(szTooltip,256,Translate("%u requests authorization"),*((PDWORD)dbei.pBlob));
+
+ cli.hIcon=LoadSkinnedIcon(SKINICON_OTHER_MIRANDA);
+ cli.pszService=MS_AUTH_SHOWREQUEST;
+ CallService(MS_CLIST_ADDEVENT,0,(LPARAM)&cli);
+ mir_free(dbei.pBlob);
+ }
+ else if(dbei.eventType==EVENTTYPE_ADDED)
+ {
+ mir_snprintf(szTooltip,256,Translate("%u added you to their contact list"),*((PDWORD)dbei.pBlob));
+
+ cli.hIcon=LoadSkinnedIcon(SKINICON_OTHER_MIRANDA);
+ cli.pszService=MS_AUTH_SHOWADDED;
+ CallService(MS_CLIST_ADDEVENT,0,(LPARAM)&cli);
+ mir_free(dbei.pBlob);
+ }
+ return 0;
+}
+
+int LoadSendRecvAuthModule(void)
+{
+ CreateServiceFunction(MS_AUTH_SHOWREQUEST,ShowReqWindow);
+ CreateServiceFunction(MS_AUTH_SHOWADDED,ShowAddedWindow);
+ HookEvent(ME_DB_EVENT_ADDED,AuthEventAdded);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/srauth/authdialogs.c b/miranda-wine/src/modules/srauth/authdialogs.c
new file mode 100644
index 0000000..7307917
--- /dev/null
+++ b/miranda-wine/src/modules/srauth/authdialogs.c
@@ -0,0 +1,269 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+
+BOOL CALLBACK DlgProcAdded(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ { DBEVENTINFO dbei;
+ DWORD *uin;
+ char *nick,*first,*last,*email;
+ HANDLE hDbEvent,hcontact;
+
+ TranslateDialogDefault(hwndDlg);
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MIRANDA)));
+ SendDlgItemMessage(hwndDlg,IDC_DETAILS,BM_SETIMAGE,IMAGE_ICON,(LPARAM)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_USERDETAILS),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0));
+ SendDlgItemMessage(hwndDlg,IDC_ADD,BM_SETIMAGE,IMAGE_ICON,(LPARAM)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_ADDCONTACT),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0));
+ SendDlgItemMessage(hwndDlg,IDC_DETAILS,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_ADD,BUTTONSETASFLATBTN,0,0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_ADD), BUTTONADDTOOLTIP, (WPARAM)Translate("Add Contact Permanently to List"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_DETAILS), BUTTONADDTOOLTIP, (WPARAM)Translate("View User's Details"), 0);
+ hDbEvent=(HANDLE)lParam;
+ //blob is: uin(DWORD), hcontact(HANDLE), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ)
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)hDbEvent,0);
+ dbei.pBlob=mir_alloc(dbei.cbBlob);
+ CallService(MS_DB_EVENT_GET,(WPARAM)hDbEvent,(LPARAM)&dbei);
+ uin=(PDWORD)dbei.pBlob;
+ hcontact=*((PHANDLE)(dbei.pBlob+sizeof(DWORD)));
+ if ((hcontact == INVALID_HANDLE_VALUE) || !DBGetContactSettingByte(hcontact, "CList", "NotOnList", 0))
+ ShowWindow(GetDlgItem(hwndDlg,IDC_ADD),FALSE);
+ nick=(char*)(dbei.pBlob+sizeof(DWORD)+sizeof(HANDLE));
+ first=nick+strlen(nick)+1;
+ last=first+strlen(first)+1;
+ email=last+strlen(last)+1;
+ if (*uin)
+ SetDlgItemInt(hwndDlg,IDC_NAME,*uin,FALSE);
+ else
+ SetDlgItemText(hwndDlg,IDC_NAME,TranslateT("(Unknown)"));
+ SetWindowLong(hwndDlg,GWL_USERDATA,lParam);
+ SetWindowLong(GetDlgItem(hwndDlg,IDC_DETAILS),GWL_USERDATA,(LONG)hcontact);
+ mir_free(dbei.pBlob);
+ return TRUE;
+ }
+ case WM_DRAWITEM:
+ { LPDRAWITEMSTRUCT dis=(LPDRAWITEMSTRUCT)lParam;
+ if(dis->hwndItem==GetDlgItem(hwndDlg, IDC_PROTOCOL)) {
+ DBEVENTINFO dbei;
+ char *szProto;
+ HANDLE hDbEvent=(HANDLE)GetWindowLong(hwndDlg,GWL_USERDATA);
+
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=0;
+ CallService(MS_DB_EVENT_GET,(WPARAM)hDbEvent,(LPARAM)&dbei);
+
+ szProto=dbei.szModule;
+ if (szProto) {
+ HICON hIcon;
+
+ hIcon=(HICON)CallProtoService(szProto,PS_LOADICON,PLI_PROTOCOL|PLIF_SMALL,0);
+ if (hIcon) DrawIconEx(dis->hDC,dis->rcItem.left,dis->rcItem.top,hIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL);
+ }
+ return TRUE;
+ }
+ break;
+ }
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDC_ADD:
+ { HANDLE hDbEvent=(HANDLE)GetWindowLong(hwndDlg,GWL_USERDATA);
+ ADDCONTACTSTRUCT acs={0};
+
+ acs.handle=hDbEvent;
+ acs.handleType=HANDLE_EVENT;
+ acs.szProto="";
+ CallService(MS_ADDCONTACT_SHOW,(WPARAM)hwndDlg,(LPARAM)&acs);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_ADD),FALSE);
+ return TRUE;
+ }
+ case IDC_DETAILS:
+ CallService(MS_USERINFO_SHOWDIALOG,(WPARAM)(HANDLE)GetWindowLong((HWND)lParam,GWL_USERDATA),0);
+ return TRUE;
+ case IDOK:
+ { HANDLE hDbEvent=(HANDLE)GetWindowLong(hwndDlg,GWL_USERDATA);
+ ADDCONTACTSTRUCT acs={0};
+
+ acs.handle=hDbEvent;
+ acs.handleType=HANDLE_EVENT;
+ acs.szProto="";
+ CallService(MS_ADDCONTACT_SHOW,(WPARAM)hwndDlg,(LPARAM)&acs);
+ }
+ //fall through
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+BOOL CALLBACK DenyReasonProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static char szReason[256];
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLong(hwndDlg,GWL_USERDATA,lParam);
+ SendDlgItemMessage(hwndDlg,IDC_REASON,EM_LIMITTEXT,(WPARAM)256,0);
+ return TRUE;
+
+ case WM_COMMAND:
+ if(LOWORD(wParam)!=IDOK) break;
+ {
+ DBEVENTINFO dbei;
+
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=0;
+ CallService(MS_DB_EVENT_GET,(WPARAM)GetWindowLong(hwndDlg,GWL_USERDATA),(LPARAM)&dbei);
+ GetDlgItemTextA(hwndDlg,IDC_REASON,szReason,256);
+ CallProtoService(dbei.szModule,PS_AUTHDENY,(WPARAM)GetWindowLong(hwndDlg,GWL_USERDATA),(LPARAM)szReason);
+ }
+ // fall through
+ case WM_CLOSE:
+ EndDialog(hwndDlg,0);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOL CALLBACK DlgProcAuthReq(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ { DBEVENTINFO dbei;
+ DWORD *uin;
+ char *nick,*first,*last,*email,*reason;
+ HANDLE hDbEvent,*hcontact;
+
+ TranslateDialogDefault(hwndDlg);
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MIRANDA)));
+ SendDlgItemMessage(hwndDlg,IDC_ADD,BM_SETIMAGE,IMAGE_ICON,(LPARAM)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_ADDCONTACT),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0));
+ SendDlgItemMessage(hwndDlg,IDC_DETAILS,BM_SETIMAGE,IMAGE_ICON,(LPARAM)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_USERDETAILS),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0));
+ SendDlgItemMessage(hwndDlg,IDC_ADD,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_DETAILS,BUTTONSETASFLATBTN,0,0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_ADD), BUTTONADDTOOLTIP, (WPARAM)Translate("Add Contact Permanently to List"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_DETAILS), BUTTONADDTOOLTIP, (WPARAM)Translate("View User's Details"), 0);
+ hDbEvent=(HANDLE)lParam;
+ //blob is: uin(DWORD),hcontact(HANDLE),nick(ASCIIZ),first(ASCIIZ),last(ASCIIZ),email(ASCIIZ),reason(ASCIIZ)
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)hDbEvent,0);
+ dbei.pBlob=mir_alloc(dbei.cbBlob);
+ CallService(MS_DB_EVENT_GET,(WPARAM)hDbEvent,(LPARAM)&dbei);
+ uin=(PDWORD)dbei.pBlob;
+ hcontact=*(PHANDLE)(dbei.pBlob+sizeof(DWORD));
+ nick=(char *)(dbei.pBlob+sizeof(DWORD)+sizeof(HANDLE));
+ first=nick+strlen(nick)+1;
+ last=first+strlen(first)+1;
+ email=last+strlen(last)+1;
+ reason=email+strlen(email)+1;
+ SetDlgItemTextA(hwndDlg,IDC_NAME,nick[0]?nick:Translate("(Unknown)"));
+ if (hcontact == INVALID_HANDLE_VALUE || !DBGetContactSettingByte(hcontact, "CList", "NotOnList", 0))
+ ShowWindow(GetDlgItem(hwndDlg,IDC_ADD),FALSE);
+ if (*uin)
+ SetDlgItemInt(hwndDlg,IDC_UIN,*uin,FALSE);
+ else SetDlgItemText(hwndDlg,IDC_UIN,TranslateT("(Unknown)"));
+ SetDlgItemTextA(hwndDlg,IDC_MAIL,email[0]?email:Translate("(Unknown)"));
+ SetDlgItemTextA(hwndDlg,IDC_REASON,reason);
+ SetWindowLong(hwndDlg,GWL_USERDATA,lParam);
+ SetWindowLong(GetDlgItem(hwndDlg,IDC_DETAILS),GWL_USERDATA,(LONG)hcontact);
+ mir_free(dbei.pBlob);
+ return TRUE;
+ }
+ case WM_DRAWITEM:
+ { LPDRAWITEMSTRUCT dis=(LPDRAWITEMSTRUCT)lParam;
+ if(dis->hwndItem==GetDlgItem(hwndDlg, IDC_PROTOCOL)) {
+ DBEVENTINFO dbei;
+ char *szProto;
+ HANDLE hDbEvent=(HANDLE)GetWindowLong(hwndDlg,GWL_USERDATA);
+
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=0;
+ CallService(MS_DB_EVENT_GET,(WPARAM)hDbEvent,(LPARAM)&dbei);
+
+ szProto=dbei.szModule;
+ if (szProto) {
+ HICON hIcon;
+
+ hIcon=(HICON)CallProtoService(szProto,PS_LOADICON,PLI_PROTOCOL|PLIF_SMALL,0);
+ if (hIcon) DrawIconEx(dis->hDC,dis->rcItem.left,dis->rcItem.top,hIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL);
+ }
+ return TRUE;
+ }
+ break;
+ }
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDC_ADD:
+ { HANDLE hDbEvent=(HANDLE)GetWindowLong(hwndDlg,GWL_USERDATA);
+ ADDCONTACTSTRUCT acs={0};
+
+ acs.handle=hDbEvent;
+ acs.handleType=HANDLE_EVENT;
+ acs.szProto="";
+ CallService(MS_ADDCONTACT_SHOW,(WPARAM)hwndDlg,(LPARAM)&acs);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_ADD),FALSE);
+ return TRUE;
+ }
+ case IDC_DETAILS:
+ { HANDLE hcontact=(HANDLE)GetWindowLong((HANDLE)lParam,GWL_USERDATA);
+ CallService(MS_USERINFO_SHOWDIALOG,(WPARAM)hcontact,0);
+ }
+ return TRUE;
+ case IDOK:
+ { HANDLE hDbEvent=(HANDLE)GetWindowLong(hwndDlg,GWL_USERDATA);
+ DBEVENTINFO dbei;
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=0;
+ CallService(MS_DB_EVENT_GET,(WPARAM)hDbEvent,(LPARAM)&dbei);
+ CallProtoService(dbei.szModule,PS_AUTHALLOW,(WPARAM)hDbEvent,0);
+ }
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ case IDCANCEL:
+ { HANDLE hDbEvent=(HANDLE)GetWindowLong(hwndDlg,GWL_USERDATA);
+ DialogBoxParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_DENYREASON),hwndDlg,DenyReasonProc,(LPARAM)hDbEvent);
+ }
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+
diff --git a/miranda-wine/src/modules/srawaymsg/awaymsg.c b/miranda-wine/src/modules/srawaymsg/awaymsg.c
new file mode 100644
index 0000000..9bba52b
--- /dev/null
+++ b/miranda-wine/src/modules/srawaymsg/awaymsg.c
@@ -0,0 +1,161 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+int LoadAwayMessageSending(void);
+
+static HANDLE hAwayMsgMenuItem;
+static HANDLE hWindowList;
+
+struct AwayMsgDlgData {
+ HANDLE hContact;
+ HANDLE hSeq;
+ HANDLE hAwayMsgEvent;
+};
+#define HM_AWAYMSG (WM_USER+10)
+static BOOL CALLBACK ReadAwayMsgDlgProc(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ struct AwayMsgDlgData *dat;
+ dat=(struct AwayMsgDlgData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch(message) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ dat=(struct AwayMsgDlgData*)mir_alloc(sizeof(struct AwayMsgDlgData));
+ SetWindowLong(hwndDlg,GWL_USERDATA,(LONG)dat);
+ dat->hContact=(HANDLE)lParam;
+ dat->hAwayMsgEvent=HookEventMessage(ME_PROTO_ACK,hwndDlg,HM_AWAYMSG);
+ dat->hSeq=(HANDLE)CallContactService(dat->hContact,PSS_GETAWAYMSG,0,0);
+ WindowList_Add(hWindowList,hwndDlg,dat->hContact);
+ { TCHAR str[256],format[128];
+ TCHAR* contactName=(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)dat->hContact,GCDNF_TCHAR);
+ char* szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ WORD dwStatus = DBGetContactSettingWord(dat->hContact,szProto,"Status",ID_STATUS_OFFLINE);
+ TCHAR* status=(TCHAR*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION,dwStatus,GCMDF_TCHAR);
+ GetWindowText(hwndDlg,format,SIZEOF(format));
+ mir_sntprintf(str,SIZEOF(str),format,status,contactName);
+ SetWindowText(hwndDlg,str);
+ GetDlgItemText(hwndDlg,IDC_RETRIEVING,format,SIZEOF(format));
+ mir_sntprintf(str,SIZEOF(str),format,status);
+ SetDlgItemText(hwndDlg,IDC_RETRIEVING,str);
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedProtoIcon(szProto, dwStatus));
+ }
+ return TRUE;
+ case HM_AWAYMSG:
+ { ACKDATA *ack=(ACKDATA*)lParam;
+ if(ack->hContact!=dat->hContact) break;
+ if(ack->type!=ACKTYPE_AWAYMSG) break;
+ if(ack->hProcess!=dat->hSeq) break;
+ if(ack->result!=ACKRESULT_SUCCESS) break;
+ if(dat->hAwayMsgEvent!=NULL) {UnhookEvent(dat->hAwayMsgEvent); dat->hAwayMsgEvent=NULL;}
+ SetDlgItemTextA(hwndDlg,IDC_MSG,(const char*)ack->lParam);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_RETRIEVING),SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_MSG),SW_SHOW);
+ SetDlgItemText(hwndDlg,IDOK,TranslateT("&Close"));
+ break;
+ }
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ case IDOK:
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ DestroyWindow(hwndDlg);
+ break;
+ case WM_DESTROY:
+ if(dat->hAwayMsgEvent!=NULL) UnhookEvent(dat->hAwayMsgEvent);
+ WindowList_Remove(hWindowList,hwndDlg);
+ mir_free(dat);
+ break;
+ }
+ return FALSE;
+}
+
+static int GetMessageCommand(WPARAM wParam,LPARAM lParam)
+{
+ HWND hwnd;
+ if(hwnd=WindowList_Find(hWindowList,(HANDLE)wParam)) {
+ SetForegroundWindow(hwnd);
+ SetFocus(hwnd);
+ }
+ else CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_READAWAYMSG),NULL,ReadAwayMsgDlgProc,wParam);
+ return 0;
+}
+
+static int AwayMsgPreBuildMenu(WPARAM wParam,LPARAM lParam)
+{
+ CLISTMENUITEM clmi;
+ char str[128];
+ int status;
+ char *szProto;
+
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,wParam,0);
+ ZeroMemory(&clmi,sizeof(clmi));
+ clmi.cbSize=sizeof(clmi);
+ clmi.flags=CMIM_FLAGS|CMIF_NOTOFFLINE|CMIF_HIDDEN;
+
+ if(szProto!=NULL) {
+ int chatRoom = szProto?DBGetContactSettingByte((HANDLE)wParam, szProto, "ChatRoom", 0):0;
+ if ( !chatRoom ) {
+ status=DBGetContactSettingWord((HANDLE)wParam,szProto,"Status",ID_STATUS_OFFLINE);
+ wsprintfA(str,Translate("Re&ad %s Message"),(char*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION,status,0));
+ clmi.pszName=str;
+ if(CallProtoService(szProto,PS_GETCAPS,PFLAGNUM_1,0)&PF1_MODEMSGRECV) {
+ if(CallProtoService(szProto,PS_GETCAPS,PFLAGNUM_3,0)&Proto_Status2Flag(status)){
+ clmi.flags=CMIM_FLAGS|CMIM_NAME|CMIF_NOTOFFLINE|CMIM_ICON;
+ clmi.hIcon = LoadSkinnedProtoIcon(szProto, status);
+ }
+ }
+ }
+ }
+ CallService(MS_CLIST_MODIFYMENUITEM,(WPARAM)hAwayMsgMenuItem,(LPARAM)&clmi);
+ return 0;
+}
+
+static int AwayMsgPreShutdown(WPARAM wParam, LPARAM lParam)
+{
+ if (hWindowList) WindowList_BroadcastAsync(hWindowList,WM_CLOSE,0,0);
+ return 0;
+}
+
+int LoadAwayMsgModule(void)
+{
+ CLISTMENUITEM mi;
+
+ hWindowList=(HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST,0,0);
+ CreateServiceFunction(MS_AWAYMSG_SHOWAWAYMSG,GetMessageCommand);
+ ZeroMemory(&mi,sizeof(mi));
+ mi.cbSize=sizeof(mi);
+ mi.position=-2000005000;
+ mi.flags=CMIF_NOTOFFLINE;
+ mi.hIcon=NULL;
+ mi.pszContactOwner=NULL;
+ mi.pszName=Translate("Re&ad Away Message");
+ mi.pszService=MS_AWAYMSG_SHOWAWAYMSG;
+ hAwayMsgMenuItem=(HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi);
+ HookEvent(ME_CLIST_PREBUILDCONTACTMENU,AwayMsgPreBuildMenu);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN,AwayMsgPreShutdown);
+ return LoadAwayMessageSending();
+}
diff --git a/miranda-wine/src/modules/srawaymsg/sendmsg.c b/miranda-wine/src/modules/srawaymsg/sendmsg.c
new file mode 100644
index 0000000..83d8aa1
--- /dev/null
+++ b/miranda-wine/src/modules/srawaymsg/sendmsg.c
@@ -0,0 +1,414 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+static DWORD protoModeMsgFlags;
+
+static char *GetDefaultMessage(int status)
+{
+ switch(status) {
+ case ID_STATUS_AWAY: return Translate("I've been away since %time%.");
+ case ID_STATUS_NA: return Translate("Give it up, I'm not in!");
+ case ID_STATUS_OCCUPIED: return Translate("Not right now.");
+ case ID_STATUS_DND: return Translate("Give a guy some peace, would ya?");
+ case ID_STATUS_FREECHAT: return Translate("I'm a chatbot!");
+ case ID_STATUS_ONLINE: return Translate("Yep, I'm here.");
+ case ID_STATUS_OFFLINE: return Translate("Nope, not here.");
+ case ID_STATUS_INVISIBLE: return Translate("I'm hiding from the mafia.");
+ case ID_STATUS_ONTHEPHONE: return Translate("That'll be the phone.");
+ case ID_STATUS_OUTTOLUNCH: return Translate("Mmm...food.");
+ case ID_STATUS_IDLE: return Translate("idleeeeeeee");
+ }
+ return NULL;
+}
+
+static char *StatusModeToDbSetting(int status,const char *suffix)
+{
+ char *prefix;
+ static char str[64];
+
+ switch(status) {
+ case ID_STATUS_AWAY: prefix="Away"; break;
+ case ID_STATUS_NA: prefix="Na"; break;
+ case ID_STATUS_DND: prefix="Dnd"; break;
+ case ID_STATUS_OCCUPIED: prefix="Occupied"; break;
+ case ID_STATUS_FREECHAT: prefix="FreeChat"; break;
+ case ID_STATUS_ONLINE: prefix="On"; break;
+ case ID_STATUS_OFFLINE: prefix="Off"; break;
+ case ID_STATUS_INVISIBLE: prefix="Inv"; break;
+ case ID_STATUS_ONTHEPHONE: prefix="Otp"; break;
+ case ID_STATUS_OUTTOLUNCH: prefix="Otl"; break;
+ case ID_STATUS_IDLE: prefix="Idl"; break;
+ default: return NULL;
+ }
+ lstrcpyA(str,prefix); lstrcatA(str,suffix);
+ return str;
+}
+
+//remember to mir_free() the return value
+static int GetAwayMessage(WPARAM wParam, LPARAM lParam)
+{
+ DBVARIANT dbv;
+ int statusMode = (int)wParam;
+
+ if(DBGetContactSettingByte(NULL,"SRAway",StatusModeToDbSetting(wParam,"Ignore"),0)) {
+ return (int)NULL;
+ }
+ if(DBGetContactSettingByte(NULL,"SRAway",StatusModeToDbSetting(statusMode,"UsePrev"),0)) {
+ if(DBGetContactSetting(NULL,"SRAway",StatusModeToDbSetting(statusMode,"Msg"),&dbv))
+ dbv.pszVal=mir_strdup(GetDefaultMessage(statusMode));
+ }
+ else {
+ int i;
+ char substituteStr[128];
+ if(DBGetContactSetting(NULL,"SRAway",StatusModeToDbSetting(statusMode,"Default"),&dbv))
+ dbv.pszVal=mir_strdup(GetDefaultMessage(statusMode));
+ for(i=0;dbv.pszVal[i];i++) {
+ if(dbv.pszVal[i]!='%') continue;
+ if(!_strnicmp(dbv.pszVal+i,"%time%",6))
+ GetTimeFormatA(LOCALE_USER_DEFAULT,TIME_NOSECONDS,NULL,NULL,substituteStr,SIZEOF(substituteStr));
+ else if(!_strnicmp(dbv.pszVal+i,"%date%",6))
+ GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,NULL,NULL,substituteStr,SIZEOF(substituteStr));
+ else continue;
+ if(lstrlenA(substituteStr)>6) dbv.pszVal=(char*)mir_realloc(dbv.pszVal,lstrlenA(dbv.pszVal)+1+lstrlenA(substituteStr)-6);
+ MoveMemory(dbv.pszVal+i+lstrlenA(substituteStr),dbv.pszVal+i+6,lstrlenA(dbv.pszVal)-i-5);
+ CopyMemory(dbv.pszVal+i,substituteStr,lstrlenA(substituteStr));
+ }
+ }
+ return (int)dbv.pszVal;
+}
+
+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;
+ TCHAR *text;
+ int textLen;
+ 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);
+ textLen = GetWindowTextLength(hwnd);
+ text = (TCHAR *) mir_alloc(sizeof(TCHAR) * (textLen + 1));
+ GetWindowText(hwnd, text, textLen + 1);
+ MoveMemory(text + start, text + end, sizeof(TCHAR) * (textLen + 1 - end));
+ SetWindowText(hwnd, text);
+ mir_free(text);
+ SendMessage(hwnd, EM_SETSEL, start, start);
+ SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), EN_CHANGE), (LPARAM) hwnd);
+ return 0;
+ }
+ break;
+ }
+ return CallWindowProc(OldMessageEditProc,hwnd,msg,wParam,lParam);
+}
+
+void ChangeAllProtoMessages(char *szProto, int statusMode,char *msg)
+{
+ int protoCount,i;
+ PROTOCOLDESCRIPTOR **proto;
+
+ CallService(MS_PROTO_ENUMPROTOCOLS,(WPARAM)&protoCount,(LPARAM)&proto);
+ if (szProto) CallProtoService(szProto,PS_SETAWAYMSG,statusMode,(LPARAM)msg);
+ else {
+ for(i=0;i<protoCount;i++) {
+ if (CallProtoService(proto[i]->szName,PS_GETCAPS,PFLAGNUM_1,0)&PF1_MODEMSGSEND)
+ CallProtoService(proto[i]->szName,PS_SETAWAYMSG,statusMode,(LPARAM)msg);
+ }
+ }
+}
+
+struct SetAwayMsgData {
+ int statusMode;
+ int countdown;
+ char okButtonFormat[64];
+ char *szProto;
+ HANDLE hPreshutdown;
+};
+struct SetAwasMsgNewData {
+ char *szProto;
+ int statusMode;
+};
+
+#define DM_SRAWAY_SHUTDOWN WM_USER+10
+
+static BOOL CALLBACK SetAwayMsgDlgProc(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ struct SetAwayMsgData *dat;
+
+ dat=(struct SetAwayMsgData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch(message) {
+ case WM_INITDIALOG:
+ {
+ struct SetAwasMsgNewData *newdat = (struct SetAwasMsgNewData*)lParam;
+ TranslateDialogDefault(hwndDlg);
+ dat=(struct SetAwayMsgData*)mir_alloc(sizeof(struct SetAwayMsgData));
+ SetWindowLong(hwndDlg,GWL_USERDATA,(LONG)dat);
+ dat->statusMode=newdat->statusMode;
+ dat->szProto=newdat->szProto;
+ mir_free(newdat);
+ SendDlgItemMessage(hwndDlg,IDC_MSG,EM_LIMITTEXT,1024,0);
+ OldMessageEditProc=(WNDPROC)SetWindowLong(GetDlgItem(hwndDlg,IDC_MSG),GWL_WNDPROC,(LONG)MessageEditSubclassProc);
+ { char str[256],format[128];
+ GetWindowTextA(hwndDlg,format,SIZEOF(format));
+ mir_snprintf(str,SIZEOF(str),format,(char*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION,dat->statusMode,0));
+ SetWindowTextA(hwndDlg,str);
+ }
+ GetDlgItemTextA(hwndDlg,IDOK,dat->okButtonFormat,SIZEOF(dat->okButtonFormat));
+ { char *msg=(char*)GetAwayMessage((WPARAM)dat->statusMode,0);
+ SetDlgItemTextA(hwndDlg,IDC_MSG,msg);
+ mir_free(msg);
+ }
+ dat->countdown=5;
+ SendMessage(hwndDlg,WM_TIMER,0,0);
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedProtoIcon(dat->szProto, dat->statusMode));
+ SetTimer(hwndDlg,1,1000,0);
+ dat->hPreshutdown=HookEventMessage(ME_SYSTEM_PRESHUTDOWN,hwndDlg,DM_SRAWAY_SHUTDOWN);
+ return TRUE;
+ }
+ case WM_TIMER:
+ if(dat->countdown==-1) {DestroyWindow(hwndDlg); break;}
+ { char str[64];
+ mir_snprintf(str,SIZEOF(str),dat->okButtonFormat,dat->countdown);
+ SetDlgItemTextA(hwndDlg,IDOK,str);
+ }
+ dat->countdown--;
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDOK:
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ break;
+ case IDC_MSG:
+ KillTimer(hwndDlg,1);
+ SetDlgItemText(hwndDlg,IDOK,TranslateT("OK"));
+ break;
+ }
+ break;
+ case DM_SRAWAY_SHUTDOWN:
+ DestroyWindow(hwndDlg);
+ break;
+ case WM_DESTROY:
+ { char str[1024];
+ GetDlgItemTextA(hwndDlg,IDC_MSG,str,SIZEOF(str));
+ ChangeAllProtoMessages(dat->szProto,dat->statusMode,str);
+ DBWriteContactSettingString(NULL,"SRAway",StatusModeToDbSetting(dat->statusMode,"Msg"),str);
+ }
+ SetWindowLong(GetDlgItem(hwndDlg,IDC_MSG),GWL_WNDPROC,(LONG)OldMessageEditProc);
+ mir_free(dat);
+ break;
+ }
+ return FALSE;
+}
+
+static int StatusModeChange(WPARAM wParam,LPARAM lParam)
+{
+ BOOL bScreenSaverRunning=FALSE;
+ char *szProto = (char*)lParam;
+
+ // If its a global change check the complete PFLAGNUM_3 flags to see if a popup might be needed
+ if(!szProto) {
+ if(!(protoModeMsgFlags&Proto_Status2Flag(wParam)))
+ return 0;
+ }
+ // If its a single protocol check the PFLAGNUM_3 for the single protocol
+ else if (!(CallProtoService(szProto,PS_GETCAPS,PFLAGNUM_1,0)&PF1_MODEMSGSEND)||!(CallProtoService(szProto,PS_GETCAPS,PFLAGNUM_3,0)&Proto_Status2Flag(wParam)))
+ return 0;
+ SystemParametersInfo(SPI_GETSCREENSAVERRUNNING,0,&bScreenSaverRunning,FALSE);
+ if(DBGetContactSettingByte(NULL,"SRAway",StatusModeToDbSetting(wParam,"Ignore"),0)) {
+ ChangeAllProtoMessages((char*)lParam,wParam,NULL);
+ }
+ else if(bScreenSaverRunning || DBGetContactSettingByte(NULL,"SRAway",StatusModeToDbSetting(wParam,"NoDlg"),0)) {
+ char *msg=(char*)GetAwayMessage(wParam, 0);
+ ChangeAllProtoMessages((char*)lParam,wParam,msg);
+ mir_free(msg);
+ }
+ else {
+ struct SetAwasMsgNewData *newdat = (struct SetAwasMsgNewData*)mir_alloc(sizeof(struct SetAwasMsgNewData));
+ newdat->szProto = (char*)lParam;
+ newdat->statusMode = (int)wParam;
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_SETAWAYMSG),NULL,SetAwayMsgDlgProc,(LPARAM)newdat);
+ }
+ return 0;
+}
+
+static int statusModes[]={ID_STATUS_OFFLINE,ID_STATUS_ONLINE,ID_STATUS_AWAY,ID_STATUS_NA,ID_STATUS_OCCUPIED,ID_STATUS_DND,ID_STATUS_FREECHAT,ID_STATUS_INVISIBLE,ID_STATUS_OUTTOLUNCH,ID_STATUS_ONTHEPHONE, ID_STATUS_IDLE};
+
+struct AwayMsgInfo {
+ int ignore;
+ int noDialog;
+ int usePrevious;
+ char msg[1024];
+};
+struct AwayMsgDlgData {
+ struct AwayMsgInfo info[ SIZEOF(statusModes) ];
+ int oldPage;
+};
+static BOOL CALLBACK DlgProcAwayMsgOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct AwayMsgDlgData *dat;
+
+ dat=(struct AwayMsgDlgData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ { int i,j;
+ DBVARIANT dbv;
+ TranslateDialogDefault(hwndDlg);
+ dat=(struct AwayMsgDlgData*)mir_alloc(sizeof(struct AwayMsgDlgData));
+ SetWindowLong(hwndDlg,GWL_USERDATA,(LONG)dat);
+ dat->oldPage=-1;
+ for( i=0; i < SIZEOF(statusModes); i++ ) {
+ if(!(protoModeMsgFlags&Proto_Status2Flag(statusModes[i]))) continue;
+ { TCHAR* ptszDescr = LangPackPcharToTchar(( LPCSTR )CallService( MS_CLIST_GETSTATUSMODEDESCRIPTION, statusModes[i], 0 ));
+ j = SendDlgItemMessage( hwndDlg, IDC_STATUS, CB_ADDSTRING, 0, (LPARAM)ptszDescr );
+ mir_free( ptszDescr );
+ }
+ SendDlgItemMessage(hwndDlg,IDC_STATUS,CB_SETITEMDATA,j,statusModes[i]);
+ dat->info[j].ignore=DBGetContactSettingByte(NULL,"SRAway",StatusModeToDbSetting(statusModes[i],"Ignore"),0);
+ dat->info[j].noDialog=DBGetContactSettingByte(NULL,"SRAway",StatusModeToDbSetting(statusModes[i],"NoDlg"),0);
+ dat->info[j].usePrevious=DBGetContactSettingByte(NULL,"SRAway",StatusModeToDbSetting(statusModes[i],"UsePrev"),0);
+ if(DBGetContactSetting(NULL,"SRAway",StatusModeToDbSetting(statusModes[i],"Default"),&dbv))
+ if(DBGetContactSetting(NULL,"SRAway",StatusModeToDbSetting(statusModes[i],"Msg"),&dbv))
+ dbv.pszVal=mir_strdup(GetDefaultMessage(statusModes[i]));
+ lstrcpyA(dat->info[j].msg,dbv.pszVal);
+ mir_free(dbv.pszVal);
+ }
+ SendDlgItemMessage(hwndDlg,IDC_STATUS,CB_SETCURSEL,0,0);
+ SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_STATUS,CBN_SELCHANGE),0);
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_STATUS:
+ if(HIWORD(wParam)==CBN_SELCHANGE) {
+ int i=SendDlgItemMessage(hwndDlg,IDC_STATUS,CB_GETCURSEL,0,0);
+ if(dat->oldPage!=-1) {
+ dat->info[dat->oldPage].ignore=IsDlgButtonChecked(hwndDlg,IDC_DONTREPLY);
+ dat->info[dat->oldPage].noDialog=IsDlgButtonChecked(hwndDlg,IDC_NODIALOG);
+ dat->info[dat->oldPage].usePrevious=IsDlgButtonChecked(hwndDlg,IDC_USEPREVIOUS);
+ GetDlgItemTextA(hwndDlg,IDC_MSG,dat->info[dat->oldPage].msg,SIZEOF(dat->info[dat->oldPage].msg));
+ }
+ CheckDlgButton(hwndDlg,IDC_DONTREPLY,i<0?0:dat->info[i].ignore);
+ CheckDlgButton(hwndDlg,IDC_NODIALOG,i<0?0:dat->info[i].noDialog);
+ CheckDlgButton(hwndDlg,IDC_USEPREVIOUS,i<0?0:dat->info[i].usePrevious);
+ CheckDlgButton(hwndDlg,IDC_USESPECIFIC,i<0?0:!dat->info[i].usePrevious);
+ SetDlgItemTextA(hwndDlg,IDC_MSG,i<0?"":dat->info[i].msg);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_NODIALOG),i<0?0:!dat->info[i].ignore);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_USEPREVIOUS),i<0?0:!dat->info[i].ignore);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_USESPECIFIC),i<0?0:!dat->info[i].ignore);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_MSG),i<0?0:!(dat->info[i].ignore || dat->info[i].usePrevious));
+ dat->oldPage=i;
+ }
+ return 0;
+ case IDC_DONTREPLY:
+ case IDC_USEPREVIOUS:
+ case IDC_USESPECIFIC:
+ SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_STATUS,CBN_SELCHANGE),0);
+ break;
+ case IDC_MSG:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ break;
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch(((LPNMHDR)lParam)->code) {
+ case PSN_APPLY:
+ { int i,status;
+ SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_STATUS,CBN_SELCHANGE),0);
+ for(i=SendDlgItemMessage(hwndDlg,IDC_STATUS,CB_GETCOUNT,0,0)-1;i>=0;i--) {
+ status=SendDlgItemMessage(hwndDlg,IDC_STATUS,CB_GETITEMDATA,i,0);
+ DBWriteContactSettingByte(NULL,"SRAway",StatusModeToDbSetting(status,"Ignore"),(BYTE)dat->info[i].ignore);
+ DBWriteContactSettingByte(NULL,"SRAway",StatusModeToDbSetting(status,"NoDlg"),(BYTE)dat->info[i].noDialog);
+ DBWriteContactSettingByte(NULL,"SRAway",StatusModeToDbSetting(status,"UsePrev"),(BYTE)dat->info[i].usePrevious);
+ DBWriteContactSettingString(NULL,"SRAway",StatusModeToDbSetting(status,"Default"),dat->info[i].msg);
+ }
+ return TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ mir_free(dat);
+ break;
+ }
+ return FALSE;
+}
+
+static int AwayMsgOptInitialise(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.position = 870000000;
+ odp.hInstance = GetModuleHandle(NULL);
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_AWAYMSG);
+ odp.pszTitle = "Status Messages";
+ odp.pszGroup = "Status";
+ odp.pfnDlgProc = DlgProcAwayMsgOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
+
+static int AwayMsgSendModulesLoaded(WPARAM wParam,LPARAM lParam)
+{
+ int i,protoCount;
+ PROTOCOLDESCRIPTOR **proto;
+
+ protoModeMsgFlags=0;
+ CallService(MS_PROTO_ENUMPROTOCOLS,(WPARAM)&protoCount,(LPARAM)&proto);
+ for(i=0;i<protoCount;i++)
+ protoModeMsgFlags|=CallProtoService(proto[i]->szName,PS_GETCAPS,PFLAGNUM_3,0);
+ if(protoModeMsgFlags) {
+ HookEvent(ME_CLIST_STATUSMODECHANGE,StatusModeChange);
+ HookEvent(ME_OPT_INITIALISE,AwayMsgOptInitialise);
+ }
+ return 0;
+}
+
+int LoadAwayMessageSending(void)
+{
+ HookEvent(ME_SYSTEM_MODULESLOADED,AwayMsgSendModulesLoaded);
+ CreateServiceFunction(MS_AWAYMSG_GETSTATUSMSG, GetAwayMessage);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/sremail/email.c b/miranda-wine/src/modules/sremail/email.c
new file mode 100644
index 0000000..3a44d96
--- /dev/null
+++ b/miranda-wine/src/modules/sremail/email.c
@@ -0,0 +1,92 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+static HANDLE hEMailMenuItem;
+
+void SendEmailThread(char *szUrl)
+{
+ ShellExecuteA(NULL,"open",szUrl,"","",SW_SHOW);
+ mir_free(szUrl);
+ return;
+}
+
+static int SendEMailCommand(WPARAM wParam,LPARAM lParam)
+{
+ DBVARIANT dbv;
+ char *szUrl;
+ char *szProto;
+
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,wParam,0);
+ if(szProto==NULL || DBGetContactSetting((HANDLE)wParam,szProto,"e-mail",&dbv)) {
+ if(DBGetContactSetting((HANDLE)wParam,"UserInfo","Mye-mail0",&dbv)) {
+ MessageBox((HWND)lParam,TranslateT("User has not registered an e-mail address"),TranslateT("Send e-mail"),MB_OK);
+ return 1;
+ }
+ }
+ szUrl=(char*)mir_alloc(lstrlenA(dbv.pszVal)+8);
+ lstrcpyA(szUrl,"mailto:");
+ lstrcatA(szUrl,dbv.pszVal);
+ mir_free(dbv.pszVal);
+ forkthread(SendEmailThread,0,szUrl);
+ return 0;
+}
+
+static int EMailPreBuildMenu(WPARAM wParam, LPARAM lParam)
+{
+ CLISTMENUITEM mi;
+ DBVARIANT dbv = { 0 };
+ char *szProto;
+
+ ZeroMemory(&mi,sizeof(mi));
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIM_FLAGS;
+
+ szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (szProto == NULL || DBGetContactSetting((HANDLE)wParam, szProto, "e-mail",& dbv)) {
+ if (DBGetContactSetting((HANDLE)wParam, "UserInfo", "Mye-mail0", &dbv))
+ mi.flags = CMIM_FLAGS | CMIF_HIDDEN;
+ }
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hEMailMenuItem, (LPARAM)&mi);
+ if (dbv.pszVal) DBFreeVariant(&dbv);
+ return 0;
+}
+
+int LoadSendRecvEMailModule(void)
+{
+ CLISTMENUITEM mi;
+
+ CreateServiceFunction(MS_EMAIL_SENDEMAIL, SendEMailCommand);
+ ZeroMemory(&mi, sizeof(mi));
+ mi.cbSize = sizeof(mi);
+ mi.position = -2000010000;
+ mi.flags = 0;
+ mi.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_SENDEMAIL));
+ mi.pszContactOwner = NULL;
+ mi.pszName = Translate("&E-mail");
+ mi.pszService = MS_EMAIL_SENDEMAIL;
+ hEMailMenuItem = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM)&mi);
+ HookEvent(ME_CLIST_PREBUILDCONTACTMENU, EMailPreBuildMenu);
+
+ return 0;
+}
diff --git a/miranda-wine/src/modules/srfile/file.c b/miranda-wine/src/modules/srfile/file.c
new file mode 100644
index 0000000..f69ccbf
--- /dev/null
+++ b/miranda-wine/src/modules/srfile/file.c
@@ -0,0 +1,287 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "file.h"
+
+static HANDLE *hFileMenu;
+static int hFileMenuCount = 0;
+
+static int SendFileCommand(WPARAM wParam,LPARAM lParam)
+{
+ struct FileSendData fsd;
+ fsd.hContact=(HANDLE)wParam;
+ fsd.ppFiles=NULL;
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_FILESEND),NULL,DlgProcSendFile,(LPARAM)&fsd);
+ return 0;
+}
+
+static int SendSpecificFiles(WPARAM wParam,LPARAM lParam)
+{
+ struct FileSendData fsd;
+ fsd.hContact=(HANDLE)wParam;
+ fsd.ppFiles=(const char**)lParam;
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_FILESEND),NULL,DlgProcSendFile,(LPARAM)&fsd);
+ return 0;
+}
+
+static int GetReceivedFilesFolder(WPARAM wParam,LPARAM lParam)
+{
+ GetContactReceivedFilesDir((HANDLE)wParam,(char*)lParam,MAX_PATH);
+ return 0;
+}
+
+static int RecvFileCommand(WPARAM wParam,LPARAM lParam)
+{
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_FILERECV),NULL,DlgProcRecvFile,lParam);
+ return 0;
+}
+
+static int FileEventAdded(WPARAM wParam,LPARAM lParam)
+{
+ DBEVENTINFO dbei={0};
+ CLISTEVENT cle={0};
+
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=0;
+ CallService(MS_DB_EVENT_GET,lParam,(LPARAM)&dbei);
+ if(dbei.flags&(DBEF_SENT|DBEF_READ) || dbei.eventType!=EVENTTYPE_FILE) return 0;
+
+ cle.cbSize=sizeof(cle);
+ cle.hContact=(HANDLE)wParam;
+ cle.hDbEvent=(HANDLE)lParam;
+ if(DBGetContactSettingByte(NULL,"SRFile","AutoAccept",0) && !DBGetContactSettingByte((HANDLE)wParam,"CList","NotOnList",0)) {
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_FILERECV),NULL,DlgProcRecvFile,(LPARAM)&cle);
+ }
+ else {
+ char *contactName;
+ char szTooltip[256];
+
+ SkinPlaySound("RecvFile");
+ cle.hIcon=LoadSkinnedIcon(SKINICON_EVENT_FILE);
+ cle.pszService="SRFile/RecvFile";
+ contactName=(char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,wParam,0);
+ mir_snprintf(szTooltip,SIZEOF(szTooltip),Translate("File from %s"),contactName);
+ cle.pszTooltip=szTooltip;
+ CallService(MS_CLIST_ADDEVENT,0,(LPARAM)&cle);
+ }
+ return 0;
+}
+
+void CreateDirectoryTree(char *szDir)
+{
+ DWORD dwAttributes;
+ char *pszLastBackslash,szTestDir[MAX_PATH];
+
+ lstrcpynA(szTestDir,szDir,SIZEOF(szTestDir));
+ if((dwAttributes=GetFileAttributesA(szTestDir))!=0xffffffff
+ && dwAttributes&FILE_ATTRIBUTE_DIRECTORY) return;
+ pszLastBackslash=strrchr(szTestDir,'\\');
+ if(pszLastBackslash==NULL) {GetCurrentDirectoryA(MAX_PATH,szDir); return;}
+ *pszLastBackslash='\0';
+ CreateDirectoryTree(szTestDir);
+ CreateDirectoryA(szTestDir,NULL);
+}
+
+int SRFile_GetRegValue(HKEY hKeyBase,const char *szSubKey,const char *szValue,char *szOutput,int cbOutput)
+{
+ HKEY hKey;
+ DWORD cbOut=cbOutput;
+
+ if(RegOpenKeyExA(hKeyBase,szSubKey,0,KEY_QUERY_VALUE,&hKey)!=ERROR_SUCCESS) return 0;
+ if(RegQueryValueExA(hKey,szValue,NULL,NULL,(PBYTE)szOutput,&cbOut)!=ERROR_SUCCESS) {RegCloseKey(hKey); return 0;}
+ RegCloseKey(hKey);
+ return 1;
+}
+
+void GetSensiblyFormattedSize(DWORD size,TCHAR *szOut,int cchOut,int unitsOverride,int appendUnits,int *unitsUsed)
+{
+ if(!unitsOverride) {
+ if(size<1000) unitsOverride=UNITS_BYTES;
+ else if(size<100*1024) unitsOverride=UNITS_KBPOINT1;
+ else if(size<1024*1024) unitsOverride=UNITS_KBPOINT0;
+ else unitsOverride=UNITS_MBPOINT2;
+ }
+ if(unitsUsed) *unitsUsed=unitsOverride;
+ switch(unitsOverride) {
+ case UNITS_BYTES: mir_sntprintf(szOut,cchOut,_T("%u%s%s"),size,appendUnits?_T(" "):_T(""),appendUnits?TranslateT("bytes"):_T("")); break;
+ case UNITS_KBPOINT1: mir_sntprintf(szOut,cchOut,_T("%.1lf%s"),size/1024.0,appendUnits?_T(" KB"):_T("")); break;
+ case UNITS_KBPOINT0: mir_sntprintf(szOut,cchOut,_T("%u%s"),size/1024,appendUnits?_T(" KB"):_T("")); break;
+ default: mir_sntprintf(szOut,cchOut,_T("%.2lf%s"),size/1048576.0,appendUnits?_T(" MB"):_T("")); break;
+ }
+}
+
+// Tripple redirection sucks but is needed to nullify the array pointer
+void FreeFilesMatrix(char ***files)
+{
+
+ char **pFile;
+
+ if (*files == NULL)
+ return;
+
+ // Free each filename in the pointer array
+ pFile = *files;
+ while (*pFile != NULL)
+ {
+ mir_free(*pFile);
+ *pFile = NULL;
+ pFile++;
+ }
+
+ // Free the array itself
+ mir_free(*files);
+ *files = NULL;
+
+}
+
+void FreeProtoFileTransferStatus(PROTOFILETRANSFERSTATUS *fts)
+{
+ if(fts->currentFile) mir_free(fts->currentFile);
+ if(fts->files) {
+ int i;
+ for(i=0;i<fts->totalFiles;i++) mir_free(fts->files[i]);
+ mir_free(fts->files);
+ }
+ if(fts->workingDir) mir_free(fts->workingDir);
+}
+
+void CopyProtoFileTransferStatus(PROTOFILETRANSFERSTATUS *dest,PROTOFILETRANSFERSTATUS *src)
+{
+ *dest=*src;
+ if(src->currentFile) dest->currentFile=mir_strdup(src->currentFile);
+ if(src->files) {
+ int i;
+ dest->files=(char**)mir_alloc(sizeof(char*)*src->totalFiles);
+ for(i=0;i<src->totalFiles;i++)
+ dest->files[i]=mir_strdup(src->files[i]);
+ }
+ if(src->workingDir) dest->workingDir=mir_strdup(src->workingDir);
+}
+
+static void RemoveUnreadFileEvents(void)
+{
+ DBEVENTINFO dbei={0};
+ HANDLE hDbEvent,hContact;
+
+ dbei.cbSize=sizeof(dbei);
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ while(hContact) {
+ hDbEvent=(HANDLE)CallService(MS_DB_EVENT_FINDFIRSTUNREAD,(WPARAM)hContact,0);
+ while(hDbEvent) {
+ dbei.cbBlob=0;
+ CallService(MS_DB_EVENT_GET,(WPARAM)hDbEvent,(LPARAM)&dbei);
+ if(!(dbei.flags&(DBEF_SENT|DBEF_READ)) && dbei.eventType==EVENTTYPE_FILE)
+ CallService(MS_DB_EVENT_MARKREAD,(WPARAM)hContact,(LPARAM)hDbEvent);
+ hDbEvent=(HANDLE)CallService(MS_DB_EVENT_FINDNEXT,(WPARAM)hDbEvent,0);
+ }
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0);
+ }
+}
+
+static int SRFileModulesLoaded(WPARAM wParam,LPARAM lParam)
+{
+ CLISTMENUITEM mi;
+ PROTOCOLDESCRIPTOR **protocol;
+ int protoCount,i;
+
+ ZeroMemory(&mi,sizeof(mi));
+ mi.cbSize=sizeof(mi);
+ mi.position=-2000020000;
+ mi.flags=CMIF_NOTOFFLINE;
+ mi.hIcon=LoadSkinnedIcon(SKINICON_EVENT_FILE);
+ mi.pszName=Translate("&File");
+ mi.pszService=MS_FILE_SENDFILE;
+ CallService(MS_PROTO_ENUMPROTOCOLS,(WPARAM)&protoCount,(LPARAM)&protocol);
+ for(i=0;i<protoCount;i++) {
+ if(protocol[i]->type!=PROTOTYPE_PROTOCOL) continue;
+ if(CallProtoService(protocol[i]->szName,PS_GETCAPS,PFLAGNUM_1,0)&PF1_FILESEND) {
+ mi.pszContactOwner=protocol[i]->szName;
+ hFileMenu = (HANDLE*)mir_realloc(hFileMenu,sizeof(HANDLE)*(hFileMenuCount+1));
+ hFileMenu[hFileMenuCount] = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi);
+ hFileMenuCount++;
+ }
+ }
+ RemoveUnreadFileEvents();
+ return 0;
+}
+
+static int hUpdateIcons = 0;
+int FilePreBuildContactMenu(WPARAM wParam,LPARAM lParam) {
+ if (hUpdateIcons) {
+ CLISTMENUITEM mi;
+ int i;
+
+ hUpdateIcons = 0;
+ ZeroMemory(&mi,sizeof(mi));
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIM_FLAGS|CMIM_ICON;
+ mi.hIcon = LoadSkinnedIcon(SKINICON_EVENT_FILE);
+
+ for(i=0;i<hFileMenuCount;i++)
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hFileMenu[i], (LPARAM)&mi);
+ }
+ return 0;
+}
+
+int FileIconsChanged(WPARAM wParam,LPARAM lParam) {
+ hUpdateIcons = 1;
+ return 0;
+}
+
+int FileShutdownProc(WPARAM wParam,LPARAM lParam) {
+ mir_free(hFileMenu);
+ return 0;
+}
+
+int LoadSendRecvFileModule(void)
+{
+ HookEvent(ME_SYSTEM_MODULESLOADED,SRFileModulesLoaded);
+ HookEvent(ME_DB_EVENT_ADDED,FileEventAdded);
+ HookEvent(ME_OPT_INITIALISE,FileOptInitialise);
+ HookEvent(ME_CLIST_PREBUILDCONTACTMENU,FilePreBuildContactMenu);
+ HookEvent(ME_SKIN_ICONSCHANGED,FileIconsChanged);
+ HookEvent(ME_SYSTEM_SHUTDOWN,FileShutdownProc);
+ CreateServiceFunction(MS_FILE_SENDFILE,SendFileCommand);
+ CreateServiceFunction(MS_FILE_SENDSPECIFICFILES,SendSpecificFiles);
+ CreateServiceFunction(MS_FILE_GETRECEIVEDFILESFOLDER,GetReceivedFilesFolder);
+ CreateServiceFunction("SRFile/RecvFile",RecvFileCommand);
+ SkinAddNewSoundEx("RecvFile",Translate("File"),Translate("Incoming"));
+ SkinAddNewSoundEx("FileDone",Translate("File"),Translate("Complete"));
+ SkinAddNewSoundEx("FileFailed",Translate("File"),Translate("Error"));
+ SkinAddNewSoundEx("FileDenied",Translate("File"),Translate("Denied"));
+ // Upgrade Routine for File Received Path - Remove me after 0.3.4
+ {
+ DBVARIANT dbv;
+
+ if(!DBGetContactSetting(NULL,"SRFile","RecvFilesDir",&dbv)) {
+ char szPath[MAX_PATH];
+
+ mir_snprintf(szPath, SIZEOF(szPath), "%s%s%s", dbv.pszVal, dbv.pszVal[strlen(dbv.pszVal)-1]=='\\'?"":"\\" , "%userid%");
+ DBFreeVariant(&dbv);
+ DBWriteContactSettingString(NULL,"SRFile","RecvFilesDirAdv",szPath);
+ DBDeleteContactSetting(NULL,"SRFile","RecvFilesDir");
+ }
+ }
+ // End Upgrade
+ return 0;
+}
diff --git a/miranda-wine/src/modules/srfile/file.h b/miranda-wine/src/modules/srfile/file.h
new file mode 100644
index 0000000..2c578b4
--- /dev/null
+++ b/miranda-wine/src/modules/srfile/file.h
@@ -0,0 +1,88 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 VIRUSSCAN_DISABLE 0
+#define VIRUSSCAN_AFTERDL 1
+#define VIRUSSCAN_DURINGDL 2
+
+#define FILERESUME_ASK 0
+//1,2,3,4: resume, overwrite, rename, skip: from proto library
+#define FILERESUMEF_ALL 0x80
+#define FILERESUME_RESUMEALL (FILERESUME_RESUME|FILERESUMEF_ALL)
+#define FILERESUME_OVERWRITEALL (FILERESUME_OVERWRITE|FILERESUMEF_ALL)
+#define FILERESUME_RENAMEALL (FILERESUME_RENAME|FILERESUMEF_ALL)
+#define FILERESUME_CANCEL 0xFFFFFFFF
+
+#define M_FILEEXISTSDLGREPLY (WM_USER+200)
+#define M_PRESHUTDOWN (WM_USER+201)
+
+struct FileSendData {
+ HANDLE hContact;
+ const char **ppFiles;
+};
+
+#define BYTESRECVEDHISTORYCOUNT 10 //the number of bytes recved is sampled once a second and the last 10 are used to get the transfer speed
+struct FileDlgData {
+ HWND hwndTransfer;
+ HANDLE fs;
+ HANDLE hContact;
+ HANDLE hDbEvent;
+ HANDLE hNotifyEvent;
+ char **files;
+ HICON hUIIcons[4];
+ int send;
+ int closeIfFileChooseCancelled;
+ int resumeBehaviour;
+ int bytesRecvedHistory[BYTESRECVEDHISTORYCOUNT];
+ int bytesRecvedHistorySize;
+ int waitingForAcceptance;
+ PROTOFILETRANSFERSTATUS transferStatus;
+ int *fileVirusScanned;
+ HANDLE hPreshutdownEvent;
+ DWORD dwTicks;
+};
+
+//file.c
+void CreateDirectoryTree(char *szDir);
+#define UNITS_BYTES 1 // 0<=size<1000: "%d bytes"
+#define UNITS_KBPOINT1 2 // 1000<=size<100*1024: "%.1f KB"
+#define UNITS_KBPOINT0 3 // 100*1024<=size<1024*1024: "%d KB"
+#define UNITS_MBPOINT2 4 // 1024*1024<=size: "%.2f MB"
+void GetSensiblyFormattedSize(DWORD size,TCHAR *szOut,int cchOut,int unitsOverride,int appendUnits,int *unitsUsed);
+void FreeFilesMatrix(char ***files); //loving that triple indirection
+void FreeProtoFileTransferStatus(PROTOFILETRANSFERSTATUS *fts);
+void CopyProtoFileTransferStatus(PROTOFILETRANSFERSTATUS *dest,PROTOFILETRANSFERSTATUS *src);
+int SRFile_GetRegValue(HKEY hKeyBase,const char *szSubKey,const char *szValue,char *szOutput,int cbOutput);
+//filesenddlg.c
+BOOL CALLBACK DlgProcSendFile(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+//filerecv.c
+BOOL CALLBACK DlgProcRecvFile(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+void GetContactReceivedFilesDir(HANDLE hContact,char *szDir,int cchDir);
+int BrowseForFolder(HWND hwnd,char *szPath);
+//fileexistsdlg.c
+BOOL CALLBACK DlgProcFileExists(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+//filexferdlg.c
+BOOL CALLBACK DlgProcFileTransfer(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+//fileopts.c
+int FileOptInitialise(WPARAM wParam,LPARAM lParam);
+
diff --git a/miranda-wine/src/modules/srfile/fileexistsdlg.c b/miranda-wine/src/modules/srfile/fileexistsdlg.c
new file mode 100644
index 0000000..73d2bf3
--- /dev/null
+++ b/miranda-wine/src/modules/srfile/fileexistsdlg.c
@@ -0,0 +1,331 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include <shlobj.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "file.h"
+
+static void SetControlToUnixTime(HWND hwndDlg, UINT idCtrl, time_t unixTime)
+{
+ LARGE_INTEGER liFiletime;
+ FILETIME filetime;
+ SYSTEMTIME st;
+ char szTime[64],szDate[64],szOutput[128];
+
+ liFiletime.QuadPart=(BIGI(11644473600)+(__int64)unixTime)*10000000;
+ filetime.dwHighDateTime=liFiletime.HighPart;
+ filetime.dwLowDateTime=liFiletime.LowPart;
+ FileTimeToSystemTime(&filetime,&st);
+ GetTimeFormatA(LOCALE_USER_DEFAULT,0,&st,NULL,szTime,SIZEOF(szTime));
+ GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&st,NULL,szDate,SIZEOF(szDate));
+ wsprintfA(szOutput,"%s %s",szDate,szTime);
+ SetDlgItemTextA(hwndDlg,idCtrl,szOutput);
+}
+
+#define C_CONTEXTMENU 0
+#define C_PROPERTIES 1
+// not defined in VC++ 6.0 SE
+#ifndef CMF_EXTENDEDVERBS
+#define CMF_EXTENDEDVERBS 0x00000100
+#endif
+static void DoAnnoyingShellCommand(HWND hwnd,const char *szFilename,int cmd,POINT *ptCursor)
+{
+ IMalloc *pShellMalloc;
+
+ OleInitialize(NULL);
+ if(SHGetMalloc(&pShellMalloc)==NOERROR) {
+ IShellFolder *pDesktopFolder;
+ if(SHGetDesktopFolder(&pDesktopFolder)==NOERROR) {
+ WCHAR wszFilename[MAX_PATH];
+ ITEMIDLIST *pCurrentIdl;
+ MultiByteToWideChar(CP_ACP,0,szFilename,-1,wszFilename,SIZEOF(wszFilename));
+ if(pDesktopFolder->lpVtbl->ParseDisplayName(pDesktopFolder,NULL,NULL,wszFilename,NULL,&pCurrentIdl,NULL)==NOERROR) {
+ if(pCurrentIdl->mkid.cb) {
+ ITEMIDLIST *pidl,*pidlNext,*pidlFilename;
+ IShellFolder *pFileFolder;
+
+ for(pidl=pCurrentIdl;;) {
+ pidlNext=(ITEMIDLIST*)((PBYTE)pidl+pidl->mkid.cb);
+ if(pidlNext->mkid.cb==0) {
+ pidlFilename=pShellMalloc->lpVtbl->Alloc(pShellMalloc,pidl->mkid.cb+sizeof(pidl->mkid.cb));
+ CopyMemory(pidlFilename,pidl,pidl->mkid.cb+sizeof(pidl->mkid.cb));
+ pidl->mkid.cb=0;
+ break;
+ }
+ pidl=pidlNext;
+ }
+ if(pDesktopFolder->lpVtbl->BindToObject(pDesktopFolder,pCurrentIdl,NULL,&IID_IShellFolder,&pFileFolder)==NOERROR) {
+ IContextMenu *pContextMenu;
+ if(pFileFolder->lpVtbl->GetUIObjectOf(pFileFolder,NULL,1,&pidlFilename,&IID_IContextMenu,NULL,&pContextMenu)==NOERROR) {
+ switch(cmd) {
+ case C_PROPERTIES:
+ { CMINVOKECOMMANDINFO ici={0};
+ ici.cbSize=sizeof(ici);
+ ici.hwnd=hwnd;
+ ici.lpVerb="properties";
+ ici.nShow=SW_SHOW;
+ pContextMenu->lpVtbl->InvokeCommand(pContextMenu,&ici);
+ break;
+ }
+ case C_CONTEXTMENU:
+ { HMENU hMenu;
+ hMenu=CreatePopupMenu();
+ if(SUCCEEDED(pContextMenu->lpVtbl->QueryContextMenu(pContextMenu,hMenu,0,1000,65535,(GetKeyState(VK_SHIFT)&0x8000?CMF_EXTENDEDVERBS:0)|CMF_NORMAL))) {
+ int cmd;
+ cmd=TrackPopupMenu(hMenu,TPM_RETURNCMD,ptCursor->x,ptCursor->y,0,hwnd,NULL);
+ if(cmd) {
+ CMINVOKECOMMANDINFO ici={0};
+ ici.cbSize=sizeof(ici);
+ ici.hwnd=hwnd;
+ ici.lpVerb=MAKEINTRESOURCEA(cmd-1000);
+ ici.nShow=SW_SHOW;
+ pContextMenu->lpVtbl->InvokeCommand(pContextMenu,&ici);
+ }
+ }
+ DestroyMenu(hMenu);
+ break;
+ }
+ }
+ pContextMenu->lpVtbl->Release(pContextMenu);
+ }
+ pFileFolder->lpVtbl->Release(pFileFolder);
+ }
+ pShellMalloc->lpVtbl->Free(pShellMalloc,pidlFilename);
+ }
+ pShellMalloc->lpVtbl->Free(pShellMalloc,pCurrentIdl);
+ }
+ pDesktopFolder->lpVtbl->Release(pDesktopFolder);
+ }
+ pShellMalloc->lpVtbl->Release(pShellMalloc);
+ }
+ OleUninitialize();
+}
+
+static WNDPROC pfnIconWindowProc;
+static LRESULT CALLBACK IconCtrlSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_LBUTTONDBLCLK:
+ ShellExecuteA(hwnd,NULL,((PROTOFILETRANSFERSTATUS*)GetWindowLong(GetParent(hwnd),GWL_USERDATA))->currentFile,NULL,NULL,SW_SHOW);
+ break;
+ case WM_RBUTTONUP:
+ { POINT pt;
+ pt.x=(short)LOWORD(lParam); pt.y=(short)HIWORD(lParam);
+ ClientToScreen(hwnd,&pt);
+ DoAnnoyingShellCommand(hwnd,((PROTOFILETRANSFERSTATUS*)GetWindowLong(GetParent(hwnd),GWL_USERDATA))->currentFile,C_CONTEXTMENU,&pt);
+ return 0;
+ }
+ }
+ return CallWindowProc(pfnIconWindowProc,hwnd,msg,wParam,lParam);
+}
+
+struct loadiconsstartinfo {
+ HWND hwndDlg;
+ char *szFilename;
+};
+void __cdecl LoadIconsAndTypesThread(struct loadiconsstartinfo *info)
+{
+ SHFILEINFOA fileInfo;
+
+ OleInitialize(NULL);
+ if(SHGetFileInfoA(info->szFilename,0,&fileInfo,sizeof(fileInfo),SHGFI_TYPENAME|SHGFI_ICON|SHGFI_LARGEICON)) {
+ char *pszExtension,*pszFilename;
+ char szExtension[64];
+ char szIconFile[MAX_PATH];
+
+ pszFilename=strrchr(info->szFilename,'\\');
+ if(pszFilename==NULL) pszFilename=info->szFilename;
+ pszExtension=strrchr(pszFilename,'.');
+ if(pszExtension) lstrcpynA(szExtension,pszExtension+1,SIZEOF(szExtension));
+ else {pszExtension="."; szExtension[0]='\0';}
+ CharUpperA(szExtension);
+ if(fileInfo.szTypeName[0]=='\0')
+ wsprintfA(fileInfo.szTypeName,Translate("%s File"),szExtension);
+ SetDlgItemTextA(info->hwndDlg,IDC_EXISTINGTYPE,fileInfo.szTypeName);
+ SetDlgItemTextA(info->hwndDlg,IDC_NEWTYPE,fileInfo.szTypeName);
+ SendDlgItemMessage(info->hwndDlg,IDC_EXISTINGICON,STM_SETICON,(WPARAM)fileInfo.hIcon,0);
+ szIconFile[0]='\0';
+ if(!lstrcmpA(szExtension,"EXE")) {
+ SRFile_GetRegValue(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Icons","2",szIconFile,SIZEOF(szIconFile));
+ }
+ else {
+ char szTypeName[MAX_PATH];
+ if(SRFile_GetRegValue(HKEY_CLASSES_ROOT,pszExtension,NULL,szTypeName,SIZEOF(szTypeName))) {
+ lstrcatA(szTypeName,"\\DefaultIcon");
+ if(SRFile_GetRegValue(HKEY_CLASSES_ROOT,szTypeName,NULL,szIconFile,SIZEOF(szIconFile))) {
+ if(strstr(szIconFile,"%1"))
+ SRFile_GetRegValue(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Icons","0",szIconFile,SIZEOF(szIconFile));
+ else szIconFile[0]='\0';
+ }
+ }
+ }
+ if(szIconFile[0]) {
+ int iconIndex;
+ HICON hIcon;
+ char *pszComma=strrchr(szIconFile,',');
+ if(pszComma==NULL) iconIndex=0;
+ else {iconIndex=atoi(pszComma+1); *pszComma='\0';}
+ hIcon=ExtractIconA(GetModuleHandle(NULL),szIconFile,iconIndex);
+ if(hIcon) fileInfo.hIcon=hIcon;
+ }
+ SendDlgItemMessage(info->hwndDlg,IDC_NEWICON,STM_SETICON,(WPARAM)fileInfo.hIcon,0);
+ }
+ OleUninitialize();
+ mir_free(info->szFilename);
+ mir_free(info);
+}
+
+BOOL CALLBACK DlgProcFileExists(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ PROTOFILETRANSFERSTATUS *fts;
+
+ fts=(PROTOFILETRANSFERSTATUS*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch(msg) {
+ case WM_INITDIALOG:
+ { TCHAR szSize[64];
+ struct _stat statbuf;
+ struct loadiconsstartinfo *lisi;
+ HWND hwndFocus;
+
+ SetPropA(hwndDlg,"Miranda.Preshutdown",HookEventMessage(ME_SYSTEM_PRESHUTDOWN,hwndDlg,M_PRESHUTDOWN));
+
+ TranslateDialogDefault(hwndDlg);
+ fts=(PROTOFILETRANSFERSTATUS*)mir_alloc(sizeof(PROTOFILETRANSFERSTATUS));
+ CopyProtoFileTransferStatus(fts,(PROTOFILETRANSFERSTATUS*)lParam);
+ SetWindowLong(hwndDlg,GWL_USERDATA,(LONG)fts);
+ SetDlgItemTextA(hwndDlg,IDC_FILENAME,fts->currentFile);
+ SetControlToUnixTime(hwndDlg,IDC_NEWDATE,fts->currentFileTime);
+ GetSensiblyFormattedSize(fts->currentFileSize,szSize,SIZEOF(szSize),0,1,NULL);
+ SetDlgItemText(hwndDlg,IDC_NEWSIZE,szSize);
+
+ pfnIconWindowProc=(WNDPROC)SetWindowLong(GetDlgItem(hwndDlg,IDC_EXISTINGICON),GWL_WNDPROC,(LONG)IconCtrlSubclassProc);
+
+ hwndFocus=GetDlgItem(hwndDlg,IDC_RESUME);
+ if(_stat(fts->currentFile,&statbuf)==0) {
+ SetControlToUnixTime(hwndDlg,IDC_EXISTINGDATE,statbuf.st_mtime);
+ GetSensiblyFormattedSize(statbuf.st_size,szSize,SIZEOF(szSize),0,1,NULL);
+ SetDlgItemText(hwndDlg,IDC_EXISTINGSIZE,szSize);
+ if(statbuf.st_size>(int)fts->currentFileSize) {
+ EnableWindow(GetDlgItem(hwndDlg,IDC_RESUME),FALSE);
+ hwndFocus=GetDlgItem(hwndDlg,IDC_OVERWRITE);
+ }
+ }
+ lisi=(struct loadiconsstartinfo*)mir_alloc(sizeof(struct loadiconsstartinfo));
+ lisi->hwndDlg=hwndDlg;
+ lisi->szFilename=mir_strdup(fts->currentFile);
+ //can be a little slow, so why not?
+ forkthread(LoadIconsAndTypesThread,0,lisi);
+ SetFocus(hwndFocus);
+ SetWindowLong(hwndFocus,GWL_STYLE,GetWindowLong(hwndFocus,GWL_STYLE)|BS_DEFPUSHBUTTON);
+ return FALSE;
+ }
+ case WM_COMMAND:
+ { PROTOFILERESUME pfr={0};
+ switch(LOWORD(wParam)) {
+ case IDC_OPENFILE:
+ ShellExecuteA(hwndDlg,NULL,fts->currentFile,NULL,NULL,SW_SHOW);
+ return FALSE;
+ case IDC_OPENFOLDER:
+ { char szFile[MAX_PATH];
+ char *pszLastBackslash;
+ lstrcpynA(szFile,fts->currentFile,SIZEOF(szFile));
+ pszLastBackslash=strrchr(szFile,'\\');
+ if(pszLastBackslash) *pszLastBackslash='\0';
+ ShellExecuteA(hwndDlg,NULL,szFile,NULL,NULL,SW_SHOW);
+ return FALSE;
+ }
+ case IDC_PROPERTIES:
+ DoAnnoyingShellCommand(hwndDlg,fts->currentFile,C_PROPERTIES,NULL);
+ return FALSE;
+ case IDC_RESUME:
+ pfr.action=FILERESUME_RESUME;
+ break;
+ case IDC_RESUMEALL:
+ pfr.action=FILERESUME_RESUMEALL;
+ break;
+ case IDC_OVERWRITE:
+ pfr.action=FILERESUME_OVERWRITE;
+ break;
+ case IDC_OVERWRITEALL:
+ pfr.action=FILERESUME_OVERWRITEALL;
+ break;
+ case IDC_SAVEAS:
+ { OPENFILENAMEA ofn={0};
+ char filter[512],*pfilter;
+ char str[MAX_PATH];
+
+ lstrcpynA(str,fts->currentFile,SIZEOF(str));
+ ofn.lStructSize=OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner=hwndDlg;
+ ofn.Flags=OFN_PATHMUSTEXIST|OFN_OVERWRITEPROMPT|OFN_HIDEREADONLY;
+ strcpy(filter,Translate("All Files"));
+ strcat(filter," (*)");
+ pfilter=filter+strlen(filter)+1;
+ strcpy(pfilter,"*");
+ pfilter=pfilter+strlen(pfilter)+1;
+ *pfilter='\0';
+ ofn.lpstrFilter=filter;
+ ofn.lpstrFile=str;
+ ofn.nMaxFile=SIZEOF(str);
+ ofn.nMaxFileTitle=MAX_PATH;
+ if(!GetSaveFileNameA(&ofn)) break;
+ pfr.szFilename=mir_strdup(str);
+ pfr.action=FILERESUME_RENAME;
+ break;
+ }
+ case IDC_SKIP:
+ pfr.action=FILERESUME_SKIP;
+ break;
+ case IDCANCEL:
+ pfr.action=FILERESUME_CANCEL;
+ break;
+ default:
+ return FALSE;
+ }
+ { PROTOFILERESUME *pfrCopy;
+ pfrCopy=(PROTOFILERESUME*)mir_alloc(sizeof(pfr));
+ CopyMemory(pfrCopy,&pfr,sizeof(pfr));
+ PostMessage(GetParent(hwndDlg),M_FILEEXISTSDLGREPLY,(WPARAM)mir_strdup(fts->currentFile),(LPARAM)pfrCopy);
+ DestroyWindow(hwndDlg);
+ }
+ break;
+ }
+ case WM_CLOSE:
+ PostMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDCANCEL,BN_CLICKED),(LPARAM)GetDlgItem(hwndDlg,IDCANCEL));
+ break;
+ case M_PRESHUTDOWN:
+ {
+ PostMessage(hwndDlg,WM_CLOSE,0,0);
+ break;
+ }
+ case WM_DESTROY:
+ UnhookEvent(GetPropA(hwndDlg,"Miranda.Preshutdown")); // GetProp() will return NULL if it couldnt find anything
+ DestroyIcon((HICON)SendDlgItemMessage(hwndDlg,IDC_EXISTINGICON,STM_GETICON,0,0));
+ DestroyIcon((HICON)SendDlgItemMessage(hwndDlg,IDC_NEWICON,STM_GETICON,0,0));
+ FreeProtoFileTransferStatus(fts);
+ mir_free(fts);
+ break;
+ }
+ return FALSE;
+}
diff --git a/miranda-wine/src/modules/srfile/fileopts.c b/miranda-wine/src/modules/srfile/fileopts.c
new file mode 100644
index 0000000..3208f89
--- /dev/null
+++ b/miranda-wine/src/modules/srfile/fileopts.c
@@ -0,0 +1,227 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "file.h"
+
+#define VSCAN_MCAFEE 1
+#define VSCAN_DRSOLOMON 2
+#define VSCAN_NORTON 3
+#define VSCAN_CA 4
+
+struct virusscannerinfo {
+ char *szProductName;
+ char *szExeRegPath;
+ char *szExeRegValue;
+ char *szCommandLine;
+};
+
+static struct virusscannerinfo virusScanners[]={
+ {"Network Associates/McAfee VirusScan","SOFTWARE\\McAfee\\VirusScan","Scan32EXE","\"%s\" %%f /nosplash /comp /autoscan /autoexit /noboot"},
+ {"Dr Solomon's VirusScan (Network Associates)","SOFTWARE\\Network Associates\\TVD\\VirusScan\\AVConsol\\General","szScannerExe","\"%s\" %%f /uinone /noboot /comp /prompt /autoexit"},
+ {"Norton AntiVirus","SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Navw32.exe",NULL,"\"%s\" %%f /b- /m- /s+ /noresults"},
+ {"Computer Associates/Inoculate IT","Software\\Antivirus","ImageFilename","\"%s\" %%f /display=progress /exit"},
+ {"Computer Associates eTrust","SOFTWARE\\ComputerAssociates\\Anti-Virus\\Resident","VetPath","\"%s\" %%f /display=progress /exit"},
+ {"Kaspersky Anti-Virus","SOFTWARE\\KasperskyLab\\Components\\101","EXEName","\"%s\" /S /Q %%f"},
+};
+
+#define M_UPDATEENABLING (WM_USER+100)
+#define M_SCANCMDLINESELCHANGE (WM_USER+101)
+static BOOL CALLBACK DlgProcFileOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ { DBVARIANT dbv;
+
+ TranslateDialogDefault(hwndDlg);
+ {
+ char str[MAX_PATH];
+ GetContactReceivedFilesDir(NULL,str,SIZEOF(str));
+ SetDlgItemTextA(hwndDlg,IDC_FILEDIR,str);
+ }
+ { HRESULT (STDAPICALLTYPE *MySHAutoComplete)(HWND,DWORD);
+
+ MySHAutoComplete=(HRESULT (STDAPICALLTYPE*)(HWND,DWORD))GetProcAddress(GetModuleHandleA("shlwapi"),"SHAutoComplete");
+ if(MySHAutoComplete) MySHAutoComplete(GetWindow(GetDlgItem(hwndDlg,IDC_FILEDIR),GW_CHILD),1);
+ }
+ CheckDlgButton(hwndDlg, IDC_AUTOACCEPT, DBGetContactSettingByte(NULL,"SRFile","AutoAccept",0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_AUTOMIN, DBGetContactSettingByte(NULL,"SRFile","AutoMin",0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_AUTOCLOSE, DBGetContactSettingByte(NULL,"SRFile","AutoClose",0) ? BST_CHECKED : BST_UNCHECKED);
+ switch(DBGetContactSettingByte(NULL,"SRFile","UseScanner",VIRUSSCAN_DISABLE)) {
+ case VIRUSSCAN_AFTERDL: CheckDlgButton(hwndDlg, IDC_SCANAFTERDL, BST_CHECKED); break;
+ case VIRUSSCAN_DURINGDL: CheckDlgButton(hwndDlg, IDC_SCANDURINGDL, BST_CHECKED); break;
+ default: CheckDlgButton(hwndDlg, IDC_NOSCANNER, BST_CHECKED); break;
+ }
+ CheckDlgButton(hwndDlg, IDC_WARNBEFOREOPENING, DBGetContactSettingByte(NULL,"SRFile","WarnBeforeOpening",1) ? BST_CHECKED : BST_UNCHECKED);
+ { char szScanExe[MAX_PATH];
+ int i,iItem;
+ for( i=0; i < SIZEOF(virusScanners); i++ ) {
+ if(SRFile_GetRegValue(HKEY_LOCAL_MACHINE,virusScanners[i].szExeRegPath,virusScanners[i].szExeRegValue,szScanExe,SIZEOF(szScanExe))) {
+ iItem=SendDlgItemMessageA(hwndDlg,IDC_SCANCMDLINE,CB_ADDSTRING,0,(LPARAM)virusScanners[i].szProductName);
+ SendDlgItemMessage(hwndDlg,IDC_SCANCMDLINE,CB_SETITEMDATA,iItem,i);
+ }
+ }
+ }
+ if(DBGetContactSetting(NULL,"SRFile","ScanCmdLine",&dbv)==0) {
+ SetDlgItemTextA(hwndDlg,IDC_SCANCMDLINE,dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ else {
+ if(SendDlgItemMessage(hwndDlg,IDC_SCANCMDLINE,CB_GETCOUNT,0,0)) {
+ SendDlgItemMessage(hwndDlg,IDC_SCANCMDLINE,CB_SETCURSEL,0,0);
+ PostMessage(hwndDlg,M_SCANCMDLINESELCHANGE,0,0);
+ }
+ }
+ switch(DBGetContactSettingByte(NULL,"SRFile","IfExists",FILERESUME_ASK)) {
+ case FILERESUME_RESUMEALL: CheckDlgButton(hwndDlg, IDC_RESUME, BST_CHECKED); break;
+ case FILERESUME_OVERWRITEALL: CheckDlgButton(hwndDlg, IDC_OVERWRITE, BST_CHECKED); break;
+ case FILERESUME_RENAMEALL: CheckDlgButton(hwndDlg, IDC_RENAME, BST_CHECKED); break;
+ default: CheckDlgButton(hwndDlg, IDC_ASK, BST_CHECKED); break;
+ }
+ SendMessage(hwndDlg,M_UPDATEENABLING,0,0);
+ return TRUE;
+ }
+ case M_UPDATEENABLING:
+ { int on=!IsDlgButtonChecked(hwndDlg,IDC_NOSCANNER);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_ST_CMDLINE),on);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_SCANCMDLINE),on);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_SCANCMDLINEBROWSE),on);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_ST_CMDLINEHELP),on);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_AUTOMIN),IsDlgButtonChecked(hwndDlg,IDC_AUTOACCEPT));
+ break;
+ }
+ case M_SCANCMDLINESELCHANGE:
+ { char str[512],szScanExe[MAX_PATH];
+ int iScanner=SendDlgItemMessage(hwndDlg,IDC_SCANCMDLINE,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_SCANCMDLINE,CB_GETCURSEL,0,0),0);
+ if(iScanner >= SIZEOF(virusScanners) || iScanner<0) break;
+ str[0]='\0';
+ if(SRFile_GetRegValue(HKEY_LOCAL_MACHINE,virusScanners[iScanner].szExeRegPath,virusScanners[iScanner].szExeRegValue,szScanExe,SIZEOF(szScanExe)))
+ wsprintfA(str,virusScanners[iScanner].szCommandLine,szScanExe);
+ SetDlgItemTextA(hwndDlg,IDC_SCANCMDLINE,str);
+ break;
+ }
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_FILEDIR:
+ if((HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus())) return 0;
+ break;
+ case IDC_FILEDIRBROWSE:
+ { char str[MAX_PATH];
+ GetDlgItemTextA(hwndDlg,IDC_FILEDIR,str,SIZEOF(str));
+ if(BrowseForFolder(hwndDlg,str))
+ SetDlgItemTextA(hwndDlg,IDC_FILEDIR,str);
+ break;
+ }
+ case IDC_AUTOACCEPT:
+ case IDC_NOSCANNER:
+ case IDC_SCANAFTERDL:
+ case IDC_SCANDURINGDL:
+ SendMessage(hwndDlg,M_UPDATEENABLING,0,0);
+ break;
+ case IDC_SCANCMDLINE:
+ if(HIWORD(wParam)==CBN_SELCHANGE) PostMessage(hwndDlg,M_SCANCMDLINESELCHANGE,0,0);
+ else if(HIWORD(wParam)!=CBN_EDITCHANGE) return 0;
+ break;
+ case IDC_SCANCMDLINEBROWSE:
+ { char str[MAX_PATH+2];
+ OPENFILENAMEA ofn={0};
+ char filter[512],*pfilter;
+
+ GetDlgItemTextA(hwndDlg,IDC_SCANCMDLINE,str,SIZEOF(str));
+ ofn.lStructSize=OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner=hwndDlg;
+ ofn.Flags=OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
+ strcpy(filter,Translate("Executable Files"));
+ strcat(filter," (*.exe)");
+ pfilter=filter+strlen(filter)+1;
+ strcpy(pfilter,"*.exe");
+ pfilter=pfilter+strlen(pfilter)+1;
+ strcpy(pfilter,Translate("All Files"));
+ strcat(pfilter," (*)");
+ pfilter=pfilter+strlen(pfilter)+1;
+ strcpy(pfilter,"*");
+ pfilter=pfilter+strlen(pfilter)+1;
+ *pfilter='\0';
+ ofn.lpstrFilter=filter;
+ ofn.lpstrFile=str;
+ ofn.nMaxFile=SIZEOF(str)-2;
+ if(str[0]=='"') {
+ char *pszQuote=strchr(str+1,'"');
+ if(pszQuote) *pszQuote='\0';
+ MoveMemory(str,str+1,lstrlenA(str));
+ }
+ else {
+ char *pszSpace=strchr(str,' ');
+ if(pszSpace) *pszSpace='\0';
+ }
+ ofn.nMaxFileTitle=MAX_PATH;
+ if(!GetOpenFileNameA(&ofn)) break;
+ if(strchr(str,' ')!=NULL) {
+ MoveMemory(str+1,str,SIZEOF(str)-2);
+ str[0]='"';
+ lstrcatA(str,"\"");
+ }
+ SetDlgItemTextA(hwndDlg,IDC_SCANCMDLINE,str);
+ break;
+ }
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case PSN_APPLY:
+ { char str[512];
+ GetDlgItemTextA(hwndDlg,IDC_FILEDIR,str,SIZEOF(str));
+ DBWriteContactSettingString(NULL,"SRFile","RecvFilesDirAdv",str);
+ DBWriteContactSettingByte(NULL,"SRFile","AutoAccept",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_AUTOACCEPT));
+ DBWriteContactSettingByte(NULL,"SRFile","AutoMin",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_AUTOMIN));
+ DBWriteContactSettingByte(NULL,"SRFile","AutoClose",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_AUTOCLOSE));
+ DBWriteContactSettingByte(NULL,"SRFile","UseScanner",(BYTE)(IsDlgButtonChecked(hwndDlg,IDC_SCANAFTERDL)?VIRUSSCAN_AFTERDL:(IsDlgButtonChecked(hwndDlg,IDC_SCANDURINGDL)?VIRUSSCAN_DURINGDL:VIRUSSCAN_DISABLE)));
+ GetDlgItemTextA(hwndDlg,IDC_SCANCMDLINE,str,SIZEOF(str));
+ DBWriteContactSettingString(NULL,"SRFile","ScanCmdLine",str);
+ DBWriteContactSettingByte(NULL,"SRFile","WarnBeforeOpening",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_WARNBEFOREOPENING));
+ DBWriteContactSettingByte(NULL,"SRFile","IfExists",(BYTE)(IsDlgButtonChecked(hwndDlg,IDC_ASK)?FILERESUME_ASK:(IsDlgButtonChecked(hwndDlg,IDC_RESUME)?FILERESUME_RESUMEALL:(IsDlgButtonChecked(hwndDlg,IDC_OVERWRITE)?FILERESUME_OVERWRITEALL:FILERESUME_RENAMEALL))));
+ return TRUE;
+ }
+ }
+ break;
+ }
+ return FALSE;
+}
+
+int FileOptInitialise(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp={0};
+ odp.cbSize = sizeof(odp);
+ odp.position = 900000000;
+ odp.hInstance = GetModuleHandle(NULL);
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_FILETRANSFER);
+ odp.pszTitle = "File Transfers";
+ odp.pszGroup = "Events";
+ odp.pfnDlgProc = DlgProcFileOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.nIDBottomSimpleControl = IDC_VIRUSSCANNERGROUP;
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
+
diff --git a/miranda-wine/src/modules/srfile/filerecvdlg.c b/miranda-wine/src/modules/srfile/filerecvdlg.c
new file mode 100644
index 0000000..602cb2c
--- /dev/null
+++ b/miranda-wine/src/modules/srfile/filerecvdlg.c
@@ -0,0 +1,431 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include <shlobj.h>
+#include "file.h"
+
+#define MAX_MRU_DIRS 5
+
+static BOOL CALLBACK ClipSiblingsChildEnumProc(HWND hwnd,LPARAM lParam)
+{
+ SetWindowLong(hwnd,GWL_STYLE,GetWindowLong(hwnd,GWL_STYLE)|WS_CLIPSIBLINGS);
+ return TRUE;
+}
+
+static void GetLowestExistingDirName(const char *szTestDir,char *szExistingDir,int cchExistingDir)
+{
+ DWORD dwAttributes;
+ char *pszLastBackslash;
+
+ lstrcpynA(szExistingDir,szTestDir,cchExistingDir);
+ while((dwAttributes=GetFileAttributesA(szExistingDir))!=0xffffffff && !(dwAttributes&FILE_ATTRIBUTE_DIRECTORY)) {
+ pszLastBackslash=strrchr(szExistingDir,'\\');
+ if(pszLastBackslash==NULL) {*szExistingDir='\0'; break;}
+ *pszLastBackslash='\0';
+ }
+ if(szExistingDir[0]=='\0') GetCurrentDirectoryA(cchExistingDir,szExistingDir);
+}
+
+static const char validFilenameChars[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_!&{}-=#@~,. ";
+static void RemoveInvalidFilenameChars(char *szString)
+{
+ int i;
+ for(i=strspn(szString,validFilenameChars);szString[i];i+=strspn(szString+i+1,validFilenameChars)+1)
+ if(szString[i]>=0) szString[i]='%';
+}
+
+static INT CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData)
+{
+ char szDir[MAX_PATH];
+ switch(uMsg) {
+ case BFFM_INITIALIZED:
+ SendMessage(hwnd, BFFM_SETSELECTION, TRUE, pData);
+ break;
+ case BFFM_SELCHANGED:
+ if (SHGetPathFromIDListA((LPITEMIDLIST) lp ,szDir))
+ SendMessage(hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM)szDir);
+ break;
+ }
+ return 0;
+}
+
+int BrowseForFolder(HWND hwnd,char *szPath)
+{
+ BROWSEINFOA bi={0};
+ LPMALLOC pMalloc;
+ ITEMIDLIST *pidlResult;
+ int result=0;
+
+ if(SUCCEEDED(OleInitialize(NULL))) {
+ if(SUCCEEDED(CoGetMalloc(1,&pMalloc))) {
+ bi.hwndOwner=hwnd;
+ bi.pszDisplayName=szPath;
+ bi.lpszTitle=Translate("Select Folder");
+ bi.ulFlags=BIF_NEWDIALOGSTYLE|BIF_EDITBOX|BIF_RETURNONLYFSDIRS; // Use this combo instead of BIF_USENEWUI
+ bi.lpfn=BrowseCallbackProc;
+ bi.lParam=(LPARAM)szPath;
+
+ pidlResult=SHBrowseForFolderA(&bi);
+ if(pidlResult) {
+ SHGetPathFromIDListA(pidlResult,szPath);
+ lstrcatA(szPath,"\\");
+ result=1;
+ }
+ pMalloc->lpVtbl->Free(pMalloc,pidlResult);
+ pMalloc->lpVtbl->Release(pMalloc);
+ }
+ OleUninitialize();
+ }
+ return result;
+}
+
+static void ReplaceStr(char str[], int len, char *from, char *to) {
+ char *tmp;
+
+ if (tmp=strstr(str, from)) {
+ int pos = tmp - str;
+ int tlen = lstrlenA(from);
+
+ tmp = mir_strdup(str);
+ if (lstrlenA(to)>tlen)
+ tmp = (char*)mir_realloc(tmp, lstrlenA(tmp)+1+lstrlenA(to)-tlen);
+
+ MoveMemory(tmp+pos+lstrlenA(to), tmp+pos+tlen, lstrlenA(tmp)+1-pos-tlen);
+ CopyMemory(tmp+pos, to, lstrlenA(to));
+ mir_snprintf(str, len, "%s", tmp);
+ mir_free(tmp);
+ }
+}
+
+void GetContactReceivedFilesDir(HANDLE hContact,char *szDir,int cchDir)
+{
+ DBVARIANT dbv;
+ char *szRecvFilesDir, szTemp[MAX_PATH];
+ int len;
+
+ if(DBGetContactSetting(NULL,"SRFile","RecvFilesDirAdv",&dbv)||lstrlenA(dbv.pszVal)==0) {
+ char szDbPath[MAX_PATH];
+
+ CallService(MS_DB_GETPROFILEPATH,(WPARAM)MAX_PATH,(LPARAM)szDbPath);
+ lstrcatA(szDbPath,"\\");
+ lstrcatA(szDbPath,Translate("Received Files"));
+ lstrcatA(szDbPath,"\\%userid%");
+ szRecvFilesDir=mir_strdup(szDbPath);
+ }
+ else {
+ char szDrive[_MAX_DRIVE];
+ _splitpath(dbv.pszVal, szDrive, NULL, NULL, NULL);
+ if ( szDrive[0] == 0 && memcmp( dbv.pszVal, "\\\\", 2 ) != 0 ) {
+ char szDbPath[MAX_PATH];
+ CallService(MS_DB_GETPROFILEPATH,(WPARAM)MAX_PATH,(LPARAM)szDbPath);
+ lstrcatA(szDbPath,"\\");
+ lstrcatA(szDbPath,dbv.pszVal);
+ szRecvFilesDir=mir_strdup(szDbPath);
+ }
+ else szRecvFilesDir=mir_strdup(dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ lstrcpynA(szTemp,szRecvFilesDir,SIZEOF(szTemp));
+ if (hContact) {
+ CONTACTINFO ci;
+ char szNick[64];
+ char szUsername[64];
+ char szProto[64];
+
+ szNick[0] = '\0';
+ szUsername[0] = '\0';
+ szProto[0] = '\0';
+
+ ZeroMemory(&ci, sizeof(ci));
+ ci.cbSize = sizeof(ci);
+ ci.hContact = hContact;
+ ci.szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ ci.dwFlag = CNF_UNIQUEID;
+ mir_snprintf(szProto, SIZEOF(szProto), "%s", ci.szProto);
+ if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
+ switch (ci.type) {
+ case CNFT_ASCIIZ:
+ mir_snprintf(szUsername, SIZEOF(szUsername), "%s", ci.pszVal);
+ miranda_sys_free(ci.pszVal);
+ break;
+ case CNFT_DWORD:
+ mir_snprintf(szUsername, SIZEOF(szUsername), "%u", ci.dVal);
+ break;
+ } }
+
+ mir_snprintf(szNick, SIZEOF(szNick), "%s", (char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)hContact,0));
+ if (lstrlenA(szUsername)==0)
+ mir_snprintf(szUsername, SIZEOF(szUsername), "%s", (char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)hContact,0));
+
+ RemoveInvalidFilenameChars(szNick);
+ RemoveInvalidFilenameChars(szUsername);
+ RemoveInvalidFilenameChars(szProto);
+ ReplaceStr(szTemp, SIZEOF(szTemp), "%nick%", szNick);
+ ReplaceStr(szTemp, SIZEOF(szTemp), "%userid%", szUsername);
+ ReplaceStr(szTemp, SIZEOF(szTemp), "%proto%", szProto);
+ }
+ lstrcpynA(szDir,szTemp,cchDir);
+ mir_free(szRecvFilesDir);
+ len=lstrlenA(szDir);
+ if(len+1<cchDir && szDir[len-1]!='\\') lstrcpyA(szDir+len,"\\");
+}
+
+BOOL CALLBACK DlgProcRecvFile(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct FileDlgData *dat;
+
+ dat=(struct FileDlgData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch (msg) {
+ case WM_INITDIALOG: {
+ TCHAR *contactName;
+ char szPath[450];
+
+ TranslateDialogDefault(hwndDlg);
+
+ dat=(struct FileDlgData*)mir_calloc(sizeof(struct FileDlgData));
+ SetWindowLong(hwndDlg,GWL_USERDATA,(LONG)dat);
+ dat->hContact=((CLISTEVENT*)lParam)->hContact;
+ dat->hDbEvent=((CLISTEVENT*)lParam)->hDbEvent;
+ dat->hPreshutdownEvent=HookEventMessage(ME_SYSTEM_PRESHUTDOWN,hwndDlg,M_PRESHUTDOWN);
+ dat->dwTicks=GetTickCount();
+
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_FILE));
+ EnumChildWindows(hwndDlg,ClipSiblingsChildEnumProc,0);
+ dat->hUIIcons[0]=LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_ADDCONTACT),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ dat->hUIIcons[1]=LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_USERDETAILS),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ dat->hUIIcons[2]=LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_HISTORY),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ dat->hUIIcons[3]=LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_DOWNARROW),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ SendDlgItemMessage(hwndDlg,IDC_ADD,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hUIIcons[0]);
+ SendDlgItemMessage(hwndDlg,IDC_DETAILS,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hUIIcons[1]);
+ SendDlgItemMessage(hwndDlg,IDC_HISTORY,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hUIIcons[2]);
+ SendDlgItemMessage(hwndDlg,IDC_USERMENU,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hUIIcons[3]);
+ SendDlgItemMessage(hwndDlg,IDC_ADD,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_DETAILS,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_HISTORY,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_USERMENU,BUTTONSETASFLATBTN,0,0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_ADD), BUTTONADDTOOLTIP, (WPARAM)Translate("Add Contact Permanently to List"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_USERMENU), BUTTONADDTOOLTIP, (WPARAM)Translate("User Menu"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_DETAILS), BUTTONADDTOOLTIP, (WPARAM)Translate("View User's Details"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_HISTORY), BUTTONADDTOOLTIP, (WPARAM)Translate("View User's History"), 0);
+
+ contactName=(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)dat->hContact,GCDNF_TCHAR);
+ SetDlgItemText(hwndDlg,IDC_FROM,contactName);
+ GetContactReceivedFilesDir(dat->hContact,szPath,SIZEOF(szPath));
+ SetDlgItemTextA(hwndDlg,IDC_FILEDIR,szPath);
+ { int i;
+ char idstr[32];
+ DBVARIANT dbv;
+ HRESULT (STDAPICALLTYPE *MySHAutoComplete)(HWND,DWORD);
+
+ MySHAutoComplete=(HRESULT (STDAPICALLTYPE*)(HWND,DWORD))GetProcAddress(GetModuleHandleA("shlwapi"),"SHAutoComplete");
+ if(MySHAutoComplete) MySHAutoComplete(GetWindow(GetDlgItem(hwndDlg,IDC_FILEDIR),GW_CHILD),1);
+ for(i=0;i<MAX_MRU_DIRS;i++) {
+ wsprintfA(idstr,"MruDir%d",i);
+ if(DBGetContactSetting(NULL,"SRFile",idstr,&dbv)) break;
+ SendDlgItemMessageA(hwndDlg,IDC_FILEDIR,CB_ADDSTRING,0,(LPARAM)dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ }
+
+ CallService(MS_DB_EVENT_MARKREAD,(WPARAM)dat->hContact,(LPARAM)dat->hDbEvent);
+
+ { DBEVENTINFO dbei={0};
+ DBTIMETOSTRINGT dbtts;
+ TCHAR datetimestr[64];
+
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)dat->hDbEvent,0);
+ dbei.pBlob=(PBYTE)mir_alloc(dbei.cbBlob);
+ CallService(MS_DB_EVENT_GET,(WPARAM)dat->hDbEvent,(LPARAM)&dbei);
+ dat->fs=(HANDLE)*(PDWORD)dbei.pBlob;
+ lstrcpynA(szPath, dbei.pBlob+4, min(dbei.cbBlob+1,SIZEOF(szPath)));
+ SetDlgItemTextA(hwndDlg,IDC_FILENAMES,szPath);
+ lstrcpynA(szPath, dbei.pBlob+4+strlen(dbei.pBlob+4)+1, min(dbei.cbBlob-4-strlen(dbei.pBlob+4),SIZEOF(szPath)));
+ SetDlgItemTextA(hwndDlg,IDC_MSG,szPath);
+ mir_free(dbei.pBlob);
+
+ dbtts.szFormat = _T("t d");
+ dbtts.szDest = datetimestr;
+ dbtts.cbDest = SIZEOF(datetimestr);
+ CallService(MS_DB_TIME_TIMESTAMPTOSTRINGT, dbei.timestamp, ( LPARAM )&dbtts);
+ SetDlgItemText(hwndDlg, IDC_DATE, datetimestr);
+ }
+ { char* szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)dat->hContact, 0);
+ if (szProto) {
+ CONTACTINFO ci;
+ int hasName = 0;
+ char buf[128];
+ ZeroMemory(&ci,sizeof(ci));
+
+ ci.cbSize = sizeof(ci);
+ ci.hContact = dat->hContact;
+ ci.szProto = szProto;
+ ci.dwFlag = CNF_UNIQUEID;
+ if (!CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&ci)) {
+ switch(ci.type) {
+ case CNFT_ASCIIZ:
+ hasName = 1;
+ mir_snprintf(buf, SIZEOF(buf), "%s", ci.pszVal);
+ mir_free(ci.pszVal);
+ break;
+ case CNFT_DWORD:
+ hasName = 1;
+ mir_snprintf(buf, SIZEOF(buf),"%u",ci.dVal);
+ break;
+ } }
+ if (hasName)
+ SetDlgItemTextA(hwndDlg, IDC_NAME, buf );
+ else
+ SetDlgItemText(hwndDlg, IDC_NAME, contactName);
+ } }
+
+ if(DBGetContactSettingByte(dat->hContact,"CList","NotOnList",0)) {
+ RECT rcBtn1,rcBtn2,rcDateCtrl;
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_ADD),&rcBtn1);
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_USERMENU),&rcBtn2);
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_DATE),&rcDateCtrl);
+ SetWindowPos(GetDlgItem(hwndDlg,IDC_DATE),0,0,0,rcDateCtrl.right-rcDateCtrl.left-(rcBtn2.left-rcBtn1.left),rcDateCtrl.bottom-rcDateCtrl.top,SWP_NOZORDER|SWP_NOMOVE);
+ }
+ else if(DBGetContactSettingByte(NULL,"SRFile","AutoAccept",0)) {
+ //don't check auto-min here to fix BUG#647620
+ PostMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDOK,BN_CLICKED),(LPARAM)GetDlgItem(hwndDlg,IDOK));
+ }
+ if(!DBGetContactSettingByte(dat->hContact,"CList","NotOnList",0))
+ ShowWindow(GetDlgItem(hwndDlg, IDC_ADD),SW_HIDE);
+ return TRUE;
+ }
+ case M_FILEEXISTSDLGREPLY:
+ return SendMessage(dat->hwndTransfer,msg,wParam,lParam);
+ case WM_MEASUREITEM:
+ return CallService(MS_CLIST_MENUMEASUREITEM,wParam,lParam);
+ case WM_DRAWITEM:
+ { LPDRAWITEMSTRUCT dis=(LPDRAWITEMSTRUCT)lParam;
+ if(dis->hwndItem==GetDlgItem(hwndDlg, IDC_PROTOCOL)) {
+ char *szProto;
+
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ if (szProto) {
+ HICON hIcon;
+
+ hIcon=(HICON)CallProtoService(szProto,PS_LOADICON,PLI_PROTOCOL|PLIF_SMALL,0);
+ if (hIcon) {
+ DrawIconEx(dis->hDC,dis->rcItem.left,dis->rcItem.top,hIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL);
+ DestroyIcon(hIcon);
+ } } }
+
+ return CallService(MS_CLIST_MENUDRAWITEM,wParam,lParam);
+ }
+ case WM_COMMAND:
+ if ( CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam),MPCF_CONTACTMENU), (LPARAM)dat->hContact ))
+ break;
+
+ switch ( LOWORD( wParam )) {
+ case IDC_FILEDIRBROWSE:
+ {
+ char szDirName[MAX_PATH],szExistingDirName[MAX_PATH];
+
+ GetDlgItemTextA(hwndDlg,IDC_FILEDIR,szDirName,SIZEOF(szDirName));
+ GetLowestExistingDirName(szDirName,szExistingDirName,SIZEOF(szExistingDirName));
+ if(BrowseForFolder(hwndDlg,szExistingDirName))
+ SetDlgItemTextA(hwndDlg,IDC_FILEDIR,szExistingDirName);
+ return TRUE;
+ }
+ case IDOK:
+ if(dat->hwndTransfer) return SendMessage(dat->hwndTransfer,msg,wParam,lParam);
+ { //most recently used directories
+ char szRecvDir[MAX_PATH],szDefaultRecvDir[MAX_PATH];
+ GetDlgItemTextA(hwndDlg,IDC_FILEDIR,szRecvDir,SIZEOF(szRecvDir));
+ GetContactReceivedFilesDir(NULL,szDefaultRecvDir,SIZEOF(szDefaultRecvDir));
+ if(_strnicmp(szRecvDir,szDefaultRecvDir,lstrlenA(szDefaultRecvDir))) {
+ char idstr[32];
+ int i;
+ DBVARIANT dbv;
+ for(i=MAX_MRU_DIRS-2;i>=0;i--) {
+ wsprintfA(idstr,"MruDir%d",i);
+ if(DBGetContactSetting(NULL,"SRFile",idstr,&dbv)) continue;
+ wsprintfA(idstr,"MruDir%d",i+1);
+ DBWriteContactSettingString(NULL,"SRFile",idstr,dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ DBWriteContactSettingString(NULL,"SRFile",idstr,szRecvDir);
+ }
+ }
+ EnableWindow(GetDlgItem(hwndDlg,IDC_FILENAMES),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_MSG),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_FILEDIR),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_FILEDIRBROWSE),FALSE);
+ dat->hwndTransfer=CreateDialog(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_FILETRANSFERINFO),hwndDlg,DlgProcFileTransfer);
+ //check for auto-minimize here to fix BUG#647620
+ if(DBGetContactSettingByte(NULL,"SRFile","AutoAccept",0) && DBGetContactSettingByte(NULL,"SRFile","AutoMin",0))
+ ShowWindow(hwndDlg,SW_SHOWMINIMIZED);
+ return TRUE;
+ case IDCANCEL:
+ if (dat->fs) CallContactService(dat->hContact,PSS_FILEDENY,(WPARAM)dat->fs,(LPARAM)Translate("Cancelled"));
+ dat->fs=NULL; /* the protocol will free the handle */
+ if(dat->hwndTransfer) return SendMessage(dat->hwndTransfer,msg,wParam,lParam);
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ case IDC_ADD:
+ { ADDCONTACTSTRUCT acs={0};
+
+ acs.handle=dat->hContact;
+ acs.handleType=HANDLE_CONTACT;
+ acs.szProto="";
+ CallService(MS_ADDCONTACT_SHOW,(WPARAM)hwndDlg,(LPARAM)&acs);
+ if(!DBGetContactSettingByte(dat->hContact,"CList","NotOnList",0))
+ ShowWindow(GetDlgItem(hwndDlg,IDC_ADD), SW_HIDE);
+ return TRUE;
+ }
+ case IDC_USERMENU:
+ { RECT rc;
+ HMENU hMenu=(HMENU)CallService(MS_CLIST_MENUBUILDCONTACT,(WPARAM)dat->hContact,0);
+ GetWindowRect((HWND)lParam,&rc);
+ TrackPopupMenu(hMenu,0,rc.left,rc.bottom,0,hwndDlg,NULL);
+ DestroyMenu(hMenu);
+ break;
+ }
+ case IDC_DETAILS:
+ CallService(MS_USERINFO_SHOWDIALOG,(WPARAM)dat->hContact,0);
+ return TRUE;
+ case IDC_HISTORY:
+ CallService(MS_HISTORY_SHOWCONTACTHISTORY,(WPARAM)dat->hContact,0);
+ return TRUE;
+ }
+ break;
+
+ case M_PRESHUTDOWN:
+ if (IsWindow(dat->hwndTransfer)) PostMessage(dat->hwndTransfer,WM_CLOSE,0,0);
+ break;
+
+ case WM_DESTROY:
+ if(dat->hPreshutdownEvent) UnhookEvent(dat->hPreshutdownEvent);
+ if(dat->hwndTransfer) DestroyWindow(dat->hwndTransfer);
+ DestroyIcon(dat->hUIIcons[3]);
+ DestroyIcon(dat->hUIIcons[2]);
+ DestroyIcon(dat->hUIIcons[1]);
+ DestroyIcon(dat->hUIIcons[0]);
+ mir_free(dat);
+ return TRUE;
+ }
+ return FALSE;
+}
diff --git a/miranda-wine/src/modules/srfile/filesenddlg.c b/miranda-wine/src/modules/srfile/filesenddlg.c
new file mode 100644
index 0000000..fe6ada6
--- /dev/null
+++ b/miranda-wine/src/modules/srfile/filesenddlg.c
@@ -0,0 +1,380 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "file.h"
+
+static void SetFileListAndSizeControls(HWND hwndDlg,struct FileDlgData *dat)
+{
+ int fileCount=0,dirCount=0,totalSize=0,i;
+ struct _stat statbuf;
+ TCHAR str[64];
+
+ for(i=0;dat->files[i];i++) {
+ if(_stat(dat->files[i],&statbuf)==0) {
+ if(statbuf.st_mode&_S_IFDIR) dirCount++;
+ else fileCount++;
+ totalSize+=statbuf.st_size;
+ }
+ }
+ GetSensiblyFormattedSize(totalSize,str,SIZEOF(str),0,1,NULL);
+ SetDlgItemText(hwndDlg,IDC_TOTALSIZE,str);
+ if(i>1) {
+ TCHAR szFormat[32];
+ if(fileCount && dirCount) {
+ mir_sntprintf(szFormat,SIZEOF(szFormat),_T("%s, %s"),TranslateTS(fileCount==1?_T("%d file"):_T("%d files")),TranslateTS(dirCount==1?_T("%d directory"):_T("%d directories")));
+ mir_sntprintf(str,SIZEOF(str),szFormat,fileCount,dirCount);
+ }
+ else if(fileCount) {
+ lstrcpy(szFormat,TranslateT("%d files"));
+ mir_sntprintf(str,SIZEOF(str),szFormat,fileCount);
+ }
+ else {
+ lstrcpy(szFormat,TranslateT("%d directories"));
+ mir_sntprintf(str,SIZEOF(str),szFormat,dirCount);
+ }
+ SetDlgItemText(hwndDlg,IDC_FILE,str);
+ }
+ else SetDlgItemTextA(hwndDlg,IDC_FILE,dat->files[0]);
+}
+
+static void FilenameToFileList(HWND hwndDlg, struct FileDlgData* dat, const TCHAR* buf)
+{
+ DWORD dwFileAttributes;
+
+ // Make sure that the file matrix is empty (the user may select files several times)
+ FreeFilesMatrix(&dat->files);
+
+ // Get the file attributes of selection
+ dwFileAttributes = GetFileAttributes( buf );
+ if (dwFileAttributes == INVALID_FILE_ATTRIBUTES)
+ return;
+
+ // Check if the selection is a directory or a file
+ if ( GetFileAttributes( buf ) & FILE_ATTRIBUTE_DIRECTORY ) {
+ const TCHAR* pBuf;
+ int nNumberOfFiles = 0;
+ int nTemp;
+ int fileOffset;
+
+ // :NOTE: The first string in the buffer is the directory, followed by a
+ // NULL separated list of all files
+
+ // fileOffset is the offset to the first file.
+ fileOffset = lstrlen(buf) + 1;
+
+ // Count number of files
+ pBuf = buf + fileOffset;
+ while ( *pBuf ) {
+ pBuf += lstrlen(pBuf) + 1;
+ nNumberOfFiles++;
+ }
+
+ // Allocate memory for a pointer array
+ if (( dat->files = (char**)mir_alloc((nNumberOfFiles + 1) * sizeof(char*))) == NULL )
+ return;
+
+ // Fill the array
+ pBuf = buf + fileOffset;
+ nTemp = 0;
+ while(*pBuf)
+ {
+ // Allocate space for path+filename
+ int cbFileNameLen = lstrlen( pBuf );
+ dat->files[nTemp] = mir_alloc(fileOffset + cbFileNameLen + 1);
+
+ // Add path to filename and copy into array
+ #if defined( _UNICODE )
+ WideCharToMultiByte( CP_ACP, 0, buf, fileOffset-1, dat->files[nTemp], fileOffset - 1, 0, 0 );
+ dat->files[nTemp][fileOffset-1] = '\\';
+ WideCharToMultiByte( CP_ACP, 0, pBuf, -1, dat->files[nTemp] + fileOffset - (buf[fileOffset-2]=='\\'?1:0), cbFileNameLen+1, 0, 0 );
+ #else
+ CopyMemory(dat->files[nTemp], buf, fileOffset-1 );
+ dat->files[nTemp][fileOffset-1] = '\\';
+ strcpy(dat->files[nTemp] + fileOffset - (buf[fileOffset-2]=='\\'?1:0), pBuf);
+ #endif
+ // Move pointers to next file...
+ pBuf += cbFileNameLen + 1;
+ nTemp++;
+ }
+ // Terminate array
+ dat->files[nNumberOfFiles] = NULL;
+ }
+ // ...the selection is a single file
+ else
+ {
+ if (( dat->files = (char**)mir_alloc(2 * sizeof(char*))) == NULL ) // Leaks when aborted
+ return;
+
+ #if defined( _UNICODE )
+ {
+ char szFileName[ MAX_PATH ];
+ BOOL bUsed;
+ WideCharToMultiByte( CP_ACP, 0, buf, -1, szFileName, MAX_PATH, NULL, &bUsed );
+ if ( bUsed ) {
+ WIN32_FIND_DATA dat;
+ HANDLE hSearch = FindFirstFile( buf, &dat );
+ if ( hSearch != INVALID_HANDLE_VALUE ) {
+ WideCharToMultiByte( CP_ACP, 0, dat.cAlternateFileName, -1, szFileName, MAX_PATH, 0, 0 );
+ FindClose( hSearch );
+ } }
+
+ dat->files[0] = mir_strdup(szFileName);
+ }
+ #else
+ dat->files[0] = mir_strdup(buf);
+ #endif
+
+ dat->files[1] = NULL;
+ }
+
+ // Update dialog text with new file selection
+ SetFileListAndSizeControls(hwndDlg, dat);
+}
+
+#define M_FILECHOOSEDONE (WM_USER+100)
+void __cdecl ChooseFilesThread(HWND hwndDlg)
+{
+ TCHAR filter[128], *pfilter;
+ TCHAR* buf = ( TCHAR* )mir_alloc( sizeof(TCHAR)*32767 );
+ if ( buf == NULL )
+ PostMessage( hwndDlg, M_FILECHOOSEDONE, 0, ( LPARAM )( TCHAR* )NULL );
+ else {
+ OPENFILENAME ofn = {0};
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner = hwndDlg;
+ lstrcpy( filter, TranslateT( "All Files" ));
+ lstrcat( filter, _T(" (*)" ));
+ pfilter = filter + lstrlen( filter )+1;
+ lstrcpy( pfilter, _T( "*" ));
+ pfilter = filter + lstrlen( filter )+1;
+ pfilter[ 0 ] = '\0';
+ ofn.lpstrFilter = filter;
+ ofn.lpstrFile = buf; *buf = 0;
+ ofn.nMaxFile = 32767;
+ ofn.Flags = OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT | OFN_EXPLORER | OFN_HIDEREADONLY;
+ if ( GetOpenFileName( &ofn ))
+ PostMessage( hwndDlg, M_FILECHOOSEDONE, 0, ( LPARAM )buf );
+ else {
+ mir_free( buf );
+ PostMessage( hwndDlg, M_FILECHOOSEDONE, 0, ( LPARAM )( TCHAR* )NULL );
+} } }
+
+static BOOL CALLBACK ClipSiblingsChildEnumProc(HWND hwnd,LPARAM lParam)
+{
+ SetWindowLong(hwnd,GWL_STYLE,GetWindowLong(hwnd,GWL_STYLE)|WS_CLIPSIBLINGS);
+ return TRUE;
+}
+
+static WNDPROC OldSendEditProc;
+static LRESULT CALLBACK SendEditSubclassProc(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;
+ }
+ break;
+ case WM_SYSCHAR:
+ if((wParam=='s' || wParam=='S') && GetKeyState(VK_MENU)&0x8000) {
+ PostMessage(GetParent(hwnd),WM_COMMAND,IDOK,0);
+ return 0;
+ }
+ break;
+ }
+ return CallWindowProc(OldSendEditProc,hwnd,msg,wParam,lParam);
+}
+
+BOOL CALLBACK DlgProcSendFile(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct FileDlgData *dat;
+
+ dat=(struct FileDlgData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ struct FileSendData *fsd=(struct FileSendData*)lParam;
+
+ dat=(struct FileDlgData*)mir_alloc(sizeof(struct FileDlgData));
+ memset(dat,0,sizeof(struct FileDlgData));
+ SetWindowLong(hwndDlg,GWL_USERDATA,(long)dat);
+ dat->hContact=fsd->hContact;
+ dat->send=1;
+ dat->hPreshutdownEvent=HookEventMessage(ME_SYSTEM_PRESHUTDOWN,hwndDlg,M_PRESHUTDOWN);
+ dat->fs=NULL;
+ dat->dwTicks=GetTickCount();
+
+ TranslateDialogDefault(hwndDlg);
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_FILE));
+ EnumChildWindows(hwndDlg,ClipSiblingsChildEnumProc,0);
+ OldSendEditProc=(WNDPROC)SetWindowLong(GetDlgItem(hwndDlg,IDC_MSG),GWL_WNDPROC,(LONG)SendEditSubclassProc);
+
+ dat->hUIIcons[0]=LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_USERDETAILS),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ dat->hUIIcons[1]=LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_HISTORY),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ dat->hUIIcons[2]=LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_DOWNARROW),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ SendDlgItemMessage(hwndDlg,IDC_DETAILS,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hUIIcons[0]);
+ SendDlgItemMessage(hwndDlg,IDC_HISTORY,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hUIIcons[1]);
+ SendDlgItemMessage(hwndDlg,IDC_USERMENU,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hUIIcons[2]);
+ SendDlgItemMessage(hwndDlg,IDC_DETAILS,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_HISTORY,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_USERMENU,BUTTONSETASFLATBTN,0,0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_USERMENU), BUTTONADDTOOLTIP, (WPARAM)Translate("User Menu"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_DETAILS), BUTTONADDTOOLTIP, (WPARAM)Translate("View User's Details"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_HISTORY), BUTTONADDTOOLTIP, (WPARAM)Translate("View User's History"), 0);
+
+ if(fsd->ppFiles!=NULL && fsd->ppFiles[0]!=NULL) {
+ int totalCount,i;
+ for(totalCount=0;fsd->ppFiles[totalCount];totalCount++);
+ dat->files=(char**)mir_alloc(sizeof(char*)*(totalCount+1)); // Leaks
+ for(i=0;i<totalCount;i++)
+ dat->files[i]=mir_strdup(fsd->ppFiles[i]);
+ dat->files[totalCount]=NULL;
+ SetFileListAndSizeControls(hwndDlg,dat);
+ }
+ {
+ char *szProto;
+ TCHAR* contactName=(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)dat->hContact,GCDNF_TCHAR);
+ SetDlgItemText(hwndDlg,IDC_TO,contactName);
+
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ if (szProto) {
+ CONTACTINFO ci;
+ int hasName = 0;
+ char buf[128];
+ ZeroMemory(&ci,sizeof(ci));
+
+ ci.cbSize = sizeof(ci);
+ ci.hContact = dat->hContact;
+ ci.szProto = szProto;
+ ci.dwFlag = CNF_UNIQUEID;
+ if (!CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&ci)) {
+ switch(ci.type) {
+ case CNFT_ASCIIZ:
+ hasName = 1;
+ mir_snprintf(buf, SIZEOF(buf), "%s", ci.pszVal);
+ mir_free(ci.pszVal);
+ break;
+ case CNFT_DWORD:
+ hasName = 1;
+ mir_snprintf(buf, SIZEOF(buf),"%u",ci.dVal);
+ break;
+ }
+ }
+ if ( hasName )
+ SetDlgItemTextA(hwndDlg,IDC_NAME,buf);
+ else
+ SetDlgItemText(hwndDlg,IDC_NAME,contactName);
+ }
+ }
+ if(fsd->ppFiles==NULL) {
+ dat->closeIfFileChooseCancelled=1;
+ PostMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_CHOOSE,BN_CLICKED),(LPARAM)GetDlgItem(hwndDlg,IDC_CHOOSE));
+ }
+ return TRUE;
+ }
+ case WM_MEASUREITEM:
+ return CallService(MS_CLIST_MENUMEASUREITEM,wParam,lParam);
+ case WM_DRAWITEM:
+ { LPDRAWITEMSTRUCT dis=(LPDRAWITEMSTRUCT)lParam;
+ if(dis->hwndItem==GetDlgItem(hwndDlg, IDC_PROTOCOL)) {
+ char *szProto;
+
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ if (szProto) {
+ HICON hIcon;
+
+ hIcon=(HICON)CallProtoService(szProto,PS_LOADICON,PLI_PROTOCOL|PLIF_SMALL,0);
+ if (hIcon) {
+ DrawIconEx(dis->hDC,dis->rcItem.left,dis->rcItem.top,hIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL);
+ DestroyIcon(hIcon);
+ }
+ }
+ }
+ return CallService(MS_CLIST_MENUDRAWITEM,wParam,lParam);
+ }
+ case M_FILECHOOSEDONE:
+ if( lParam != 0 ) {
+ FilenameToFileList( hwndDlg, dat, ( TCHAR* )lParam );
+ mir_free(( TCHAR* )lParam );
+ dat->closeIfFileChooseCancelled = 0;
+ }
+ else if(dat->closeIfFileChooseCancelled) DestroyWindow(hwndDlg);
+ EnableWindow(hwndDlg,TRUE);
+ break;
+ case WM_COMMAND:
+ if(CallService(MS_CLIST_MENUPROCESSCOMMAND,MAKEWPARAM(LOWORD(wParam),MPCF_CONTACTMENU),(LPARAM)dat->hContact))
+ break;
+ switch (LOWORD(wParam))
+ {
+ case IDC_CHOOSE:
+ EnableWindow(hwndDlg,FALSE);
+ //GetOpenFileName() creates its own message queue which prevents any incoming events being processed
+ forkthread(ChooseFilesThread,0,hwndDlg);
+ break;
+ case IDOK:
+ if(dat->hwndTransfer) return SendMessage(dat->hwndTransfer,msg,wParam,lParam);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_FILENAME),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_MSG),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_CHOOSE),FALSE);
+ dat->hwndTransfer=CreateDialog(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_FILETRANSFERINFO),hwndDlg,DlgProcFileTransfer);
+ return TRUE;
+ case IDCANCEL:
+ if(dat->hwndTransfer) return SendMessage(dat->hwndTransfer,msg,wParam,lParam);
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ case IDC_USERMENU:
+ { RECT rc;
+ HMENU hMenu=(HMENU)CallService(MS_CLIST_MENUBUILDCONTACT,(WPARAM)dat->hContact,0);
+ GetWindowRect((HWND)lParam,&rc);
+ TrackPopupMenu(hMenu,0,rc.left,rc.bottom,0,hwndDlg,NULL);
+ DestroyMenu(hMenu);
+ break;
+ }
+ case IDC_DETAILS:
+ CallService(MS_USERINFO_SHOWDIALOG,(WPARAM)dat->hContact,0);
+ return TRUE;
+ case IDC_HISTORY:
+ CallService(MS_HISTORY_SHOWCONTACTHISTORY,(WPARAM)dat->hContact,0);
+ return TRUE;
+ }
+ break;
+ case M_PRESHUTDOWN:
+ {
+ if (IsWindow(dat->hwndTransfer)) PostMessage(dat->hwndTransfer,WM_CLOSE,0,0);
+ break;
+ }
+ case WM_DESTROY:
+ if(dat->hPreshutdownEvent) UnhookEvent(dat->hPreshutdownEvent);
+ if(dat->hwndTransfer) DestroyWindow(dat->hwndTransfer);
+ FreeFilesMatrix(&dat->files);
+ SetWindowLong(GetDlgItem(hwndDlg,IDC_MSG),GWL_WNDPROC,(LONG)OldSendEditProc);
+ DestroyIcon(dat->hUIIcons[2]);
+ DestroyIcon(dat->hUIIcons[1]);
+ DestroyIcon(dat->hUIIcons[0]);
+ mir_free(dat);
+ return TRUE;
+ }
+ return FALSE;
+}
diff --git a/miranda-wine/src/modules/srfile/filexferdlg.c b/miranda-wine/src/modules/srfile/filexferdlg.c
new file mode 100644
index 0000000..468ce47
--- /dev/null
+++ b/miranda-wine/src/modules/srfile/filexferdlg.c
@@ -0,0 +1,562 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include <io.h>
+#include "file.h"
+
+#define HM_RECVEVENT (WM_USER+10)
+
+static int CheckVirusScanned(HWND hwnd,struct FileDlgData *dat,int i)
+{
+ if(dat->send) return 1;
+ if(dat->fileVirusScanned[i]) return 1;
+ if(DBGetContactSettingByte(NULL,"SRFile","WarnBeforeOpening",1)==0) return 1;
+ return IDYES==MessageBox(hwnd,TranslateT("This file has not yet been scanned for viruses. Are you certain you want to open it?"),TranslateT("File Received"),MB_YESNO|MB_DEFBUTTON2);
+}
+
+#define M_VIRUSSCANDONE (WM_USER+100)
+struct virusscanthreadstartinfo {
+ char *szFile;
+ int returnCode;
+ HWND hwndReply;
+};
+
+static void SetOpenFileButtonStyle(HWND hwndButton,int downarrow,int enabled)
+{
+ if(downarrow) {
+ SendMessage(hwndButton,BUTTONSETARROW,1,0);
+ }
+ else {
+ SendMessage(hwndButton,BUTTONSETARROW,0,0);
+ }
+ EnableWindow(hwndButton,enabled);
+}
+
+static void __cdecl RunVirusScannerThread(struct virusscanthreadstartinfo *info)
+{
+ PROCESS_INFORMATION pi;
+ STARTUPINFOA si={0};
+ DBVARIANT dbv;
+ char szCmdLine[768];
+
+ if(!DBGetContactSetting(NULL,"SRFile","ScanCmdLine",&dbv)) {
+ if(dbv.pszVal[0]) {
+ char *pszReplace;
+ si.cb=sizeof(si);
+ pszReplace=strstr(dbv.pszVal,"%f");
+ if(pszReplace) {
+ if(info->szFile[lstrlenA(info->szFile)-1]=='\\') info->szFile[lstrlenA(info->szFile)-1]='\0';
+ *pszReplace=0;
+ mir_snprintf(szCmdLine,SIZEOF(szCmdLine),"%s\"%s\"%s",dbv.pszVal,info->szFile,pszReplace+2);
+ }
+ else lstrcpynA(szCmdLine,dbv.pszVal,SIZEOF(szCmdLine));
+ if(CreateProcessA(NULL,szCmdLine,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi)) {
+ if(WaitForSingleObject(pi.hProcess,3600*1000)==WAIT_OBJECT_0)
+ PostMessage(info->hwndReply,M_VIRUSSCANDONE,info->returnCode,0);
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ }
+ }
+ DBFreeVariant(&dbv);
+ }
+ mir_free(info->szFile);
+ mir_free(info);
+}
+
+static void SetFilenameControls(HWND hwndDlg,PROTOFILETRANSFERSTATUS *fts)
+{
+ char str[MAX_PATH];
+ HWND hwndFilename;
+
+ { TCHAR msg[MAX_PATH];
+ GetDlgItemText(hwndDlg,IDC_FILENAME,msg,SIZEOF(msg));
+ if(msg[0]) return;
+
+ wsprintf(msg,TranslateT("Current file (%d of %d)"),fts->currentFileNumber+1,fts->totalFiles);
+ SetDlgItemText(hwndDlg,IDC_CURRENTFILEGROUP,msg);
+ }
+
+ hwndFilename=GetDlgItem(hwndDlg,IDC_FILENAME);
+ lstrcpynA(str,fts->currentFile,SIZEOF(str));
+ if(strchr(str,'\\')) {
+ RECT rcFilename;
+ HDC hdc;
+ SIZE textSize;
+ HFONT hFont;
+ int driveNameLen,driveAndEllipsisLen=0;
+ char *pszBackslash;
+
+ GetClientRect(hwndFilename,&rcFilename);
+ hdc = GetDC(hwndFilename);
+ hFont = SelectObject(hdc,(HFONT)SendMessage(hwndFilename,WM_GETFONT,0,0));
+ if(str[0] && str[1]==':' && str[2]=='\\') driveNameLen=3;
+ else if(str[0]=='\\' && str[1]=='\\') {
+ if((pszBackslash=strchr(str+2,'\\'))!=NULL && (pszBackslash=strchr(pszBackslash+1,'\\'))!=NULL)
+ driveNameLen=pszBackslash-str+1;
+ else driveNameLen=2;
+ }
+ else driveNameLen=0;
+ for(;;) {
+ GetTextExtentPoint32A(hdc,str,lstrlenA(str),&textSize);
+ if(textSize.cx<rcFilename.right) break;
+ pszBackslash=strchr(str+(driveAndEllipsisLen?driveAndEllipsisLen:driveNameLen),'\\');
+ if(pszBackslash==NULL) {
+ lstrcpyA(str,strrchr(fts->currentFile,'\\')+1);
+ break;
+ }
+ if(driveAndEllipsisLen)
+ MoveMemory(str+driveAndEllipsisLen,pszBackslash+1,lstrlenA(pszBackslash));
+ else {
+ MoveMemory(str+driveNameLen+4,pszBackslash,lstrlenA(pszBackslash)+1);
+ CopyMemory(str+driveNameLen,"...\\",4);
+ driveAndEllipsisLen=driveNameLen+4;
+ }
+ }
+ SelectObject(hdc,hFont);
+ ReleaseDC(hwndFilename,hdc);
+ }
+ SetWindowTextA(hwndFilename,str);
+}
+
+BOOL CALLBACK DlgProcFileTransfer(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct FileDlgData *dat=NULL;
+
+ dat=(struct FileDlgData*)GetWindowLong(GetParent(hwndDlg),GWL_USERDATA);
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ dat->hNotifyEvent=HookEventMessage(ME_PROTO_ACK,hwndDlg,HM_RECVEVENT);
+ dat->transferStatus.currentFileNumber=-1;
+ if(dat->send) {
+ char szMsg[450];
+ GetDlgItemTextA(GetParent(hwndDlg),IDC_MSG,szMsg,SIZEOF(szMsg));
+ dat->fs=(HANDLE)CallContactService(dat->hContact,PSS_FILE,(WPARAM)szMsg,(LPARAM)dat->files);
+ SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("Request sent, waiting for acceptance..."));
+ SetOpenFileButtonStyle(GetDlgItem(hwndDlg,IDC_OPENFILE),dat->files[1]!=NULL,1);
+ dat->waitingForAcceptance=1;
+ }
+ else { //recv
+ char szSavePath[MAX_PATH];
+
+ GetDlgItemTextA(GetParent(hwndDlg),IDC_FILEDIR,szSavePath,SIZEOF(szSavePath));
+ CreateDirectoryTree(szSavePath);
+ dat->fs=(HANDLE)CallContactService(dat->hContact,PSS_FILEALLOW,(WPARAM)dat->fs,(LPARAM)szSavePath);
+ dat->transferStatus.workingDir=mir_strdup(szSavePath);
+ if(DBGetContactSettingByte(dat->hContact,"CList","NotOnList",0)) dat->resumeBehaviour=FILERESUME_ASK;
+ else dat->resumeBehaviour=DBGetContactSettingByte(NULL,"SRFile","IfExists",FILERESUME_ASK);
+ SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("Waiting for connection..."));
+ }
+ {
+ /* check we actually got an fs handle back from the protocol */
+ if (!dat->fs) {
+ SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("Unable to initiate transfer."));
+ dat->waitingForAcceptance=0;
+ }
+ }
+ { LOGFONT lf;
+ HFONT hFont;
+ hFont=(HFONT)SendDlgItemMessage(hwndDlg,IDC_CURRENTFILEGROUP,WM_GETFONT,0,0);
+ GetObject(hFont,sizeof(lf),&lf);
+ lf.lfWeight=FW_BOLD;
+ hFont=CreateFontIndirect(&lf);
+ SendDlgItemMessage(hwndDlg,IDC_CURRENTFILEGROUP,WM_SETFONT,(WPARAM)hFont,0);
+ SendDlgItemMessage(hwndDlg,IDC_ALLFILESGROUP,WM_SETFONT,(WPARAM)hFont,0);
+ }
+ { RECT rcParentClient;
+ RECT rcThisDlg;
+ BOOL (WINAPI *MyAnimateWindow)(HWND hWnd,DWORD dwTime,DWORD dwFlags);
+
+ GetClientRect(GetParent(hwndDlg),&rcParentClient);
+ GetClientRect(hwndDlg,&rcThisDlg);
+ SetWindowPos(hwndDlg,HWND_TOP,0,rcParentClient.bottom-rcThisDlg.bottom,0,0,SWP_NOSIZE);
+ MyAnimateWindow=(BOOL (WINAPI*)(HWND,DWORD,DWORD))GetProcAddress(GetModuleHandleA("USER32"),"AnimateWindow");
+ if(MyAnimateWindow)
+ MyAnimateWindow(hwndDlg,200,AW_ACTIVATE|AW_SLIDE|AW_VER_NEGATIVE);
+ else ShowWindow(hwndDlg,SW_SHOW);
+ }
+ SendDlgItemMessage(hwndDlg,IDC_OPENFILE,BUTTONSETDEFAULT,1,0);
+ if(!dat->waitingForAcceptance) SetTimer(hwndDlg,1,1000,NULL);
+ return TRUE;
+ case WM_TIMER:
+ MoveMemory(dat->bytesRecvedHistory+1,dat->bytesRecvedHistory,sizeof(dat->bytesRecvedHistory)-sizeof(dat->bytesRecvedHistory[0]));
+ dat->bytesRecvedHistory[0]=dat->transferStatus.totalProgress;
+ if ( dat->bytesRecvedHistorySize < SIZEOF(dat->bytesRecvedHistory))
+ dat->bytesRecvedHistorySize++;
+
+ { TCHAR szSpeed[32], szTime[32], szDisplay[96];
+ SYSTEMTIME st;
+ ULARGE_INTEGER li;
+ FILETIME ft;
+
+ GetSensiblyFormattedSize((dat->bytesRecvedHistory[0]-dat->bytesRecvedHistory[dat->bytesRecvedHistorySize-1])/dat->bytesRecvedHistorySize,szSpeed,SIZEOF(szSpeed),0,1,NULL);
+ if(dat->bytesRecvedHistory[0]==dat->bytesRecvedHistory[dat->bytesRecvedHistorySize-1])
+ lstrcpy(szTime,_T("??:??:??"));
+ else {
+ li.QuadPart=BIGI(10000000)*(dat->transferStatus.currentFileSize-dat->transferStatus.currentFileProgress)*dat->bytesRecvedHistorySize/(dat->bytesRecvedHistory[0]-dat->bytesRecvedHistory[dat->bytesRecvedHistorySize-1]);
+ ft.dwHighDateTime=li.HighPart; ft.dwLowDateTime=li.LowPart;
+ FileTimeToSystemTime(&ft,&st);
+ GetTimeFormat(LOCALE_USER_DEFAULT,TIME_FORCE24HOURFORMAT|TIME_NOTIMEMARKER,&st,NULL,szTime,SIZEOF(szTime));
+ }
+ mir_sntprintf(szDisplay,SIZEOF(szDisplay),_T("%s/%s (%s %s)"),szSpeed,TranslateT("sec"),szTime,TranslateT("remaining"));
+ SetDlgItemText(hwndDlg,IDC_CURRENTSPEED,szDisplay);
+ if(dat->bytesRecvedHistory[0]!=dat->bytesRecvedHistory[dat->bytesRecvedHistorySize-1]) {
+ li.QuadPart=BIGI(10000000)*(dat->transferStatus.totalBytes-dat->transferStatus.totalProgress)*dat->bytesRecvedHistorySize/(dat->bytesRecvedHistory[0]-dat->bytesRecvedHistory[dat->bytesRecvedHistorySize-1]);
+ ft.dwHighDateTime=li.HighPart; ft.dwLowDateTime=li.LowPart;
+ FileTimeToSystemTime(&ft,&st);
+ GetTimeFormat(LOCALE_USER_DEFAULT,TIME_FORCE24HOURFORMAT|TIME_NOTIMEMARKER,&st,NULL,szTime,SIZEOF(szTime));
+ }
+ mir_sntprintf(szDisplay,SIZEOF(szDisplay),_T("%s/%s (%s %s)"),szSpeed,TranslateT("sec"),szTime,TranslateT("remaining"));
+ SetDlgItemText(hwndDlg,IDC_ALLSPEED,szDisplay);
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ case IDOK:
+ DestroyWindow(GetParent(hwndDlg));
+ break;
+ case IDC_OPENFOLDER:
+ ShellExecuteA(NULL,NULL,dat->transferStatus.workingDir,NULL,NULL,SW_SHOW);
+ break;
+
+ case IDC_OPENFILE:
+ {
+ char **files;
+
+ if (dat->send)
+ if (dat->files == NULL)
+ files = dat->transferStatus.files;
+ else
+ files = dat->files;
+ else
+ files=dat->files;
+
+ if (files == NULL || *files == NULL)
+ break;
+
+
+ // Only one single file
+ if (files[1] == NULL) {
+ if (!CheckVirusScanned(hwndDlg, dat, 0))
+ break;
+ ShellExecuteA(NULL, NULL, files[0], NULL, NULL, SW_SHOW);
+ }
+ // Multiple files
+ else {
+ RECT rc;
+ int i,limit;
+ char *pszFilename,*pszNewFileName;
+ HMENU hMenu = CreatePopupMenu();
+
+ if (dat->send)
+ limit = dat->transferStatus.totalFiles;
+ else
+ limit = dat->transferStatus.currentFileNumber;
+
+ // Loop over all transfered files and add them to the menu
+ for (i = 0; i < limit; i++) {
+ pszFilename = strrchr(files[i], '\\');
+ if (pszFilename == NULL)
+ pszFilename = files[i];
+ else
+ pszFilename++;
+ {
+ if (pszFilename) {
+ int pszlen;
+ char *p;
+
+ pszNewFileName = (char*)mir_alloc(strlen(pszFilename)*2);
+ p = pszNewFileName;
+ for (pszlen=0; pszlen<(int)strlen(pszFilename); pszlen++) {
+ *p++ = pszFilename[pszlen];
+ if (pszFilename[pszlen]=='&')
+ *p++ = '&';
+ }
+ *p = '\0';
+ AppendMenuA(hMenu, MF_STRING, i+1, pszNewFileName);
+ mir_free(pszNewFileName);
+ }
+ }
+ }
+
+ GetWindowRect((HWND)lParam, &rc);
+ i = TrackPopupMenu(hMenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL);
+ DestroyMenu(hMenu);
+
+ if (i && CheckVirusScanned(hwndDlg, dat, i))
+ ShellExecuteA(NULL, NULL, files[i-1], NULL, NULL, SW_SHOW);
+ }
+
+ break;
+ }
+
+ }
+ break;
+ case M_FILEEXISTSDLGREPLY:
+ { PROTOFILERESUME *pfr=(PROTOFILERESUME*)lParam;
+ char *szOriginalFilename=(char*)wParam;
+ char *szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+
+ EnableWindow(hwndDlg,TRUE);
+ switch(pfr->action) {
+ case FILERESUME_CANCEL:
+ if (dat->fs) CallContactService(dat->hContact,PSS_FILECANCEL,(WPARAM)dat->fs,0);
+ dat->fs=NULL;
+ DestroyWindow(GetParent(hwndDlg));
+ mir_free(szOriginalFilename);
+ if(pfr->szFilename) mir_free((char*)pfr->szFilename);
+ mir_free(pfr);
+ return 0;
+ case FILERESUME_RESUMEALL:
+ case FILERESUME_OVERWRITEALL:
+ dat->resumeBehaviour=wParam;
+ pfr->action&=~FILERESUMEF_ALL;
+ break;
+ case FILERESUME_RENAMEALL:
+ pfr->action=FILERESUME_RENAME;
+ { char *pszExtension,*pszFilename;
+ int i;
+ if((pszFilename=strrchr(szOriginalFilename,'\\'))==NULL) pszFilename=szOriginalFilename;
+ if((pszExtension=strrchr(pszFilename+1,'.'))==NULL) pszExtension=pszFilename+lstrlenA(pszFilename);
+ if(pfr->szFilename) mir_free((char*)pfr->szFilename);
+ pfr->szFilename=(char*)mir_alloc((pszExtension-szOriginalFilename)+21+lstrlenA(pszExtension));
+ for(i=1;;i++) {
+ sprintf((char*)pfr->szFilename,"%.*s (%u)%s",pszExtension-szOriginalFilename,szOriginalFilename,i,pszExtension);
+ if(_access(pfr->szFilename,0)!=0) break;
+ }
+ }
+ break;
+ }
+ mir_free(szOriginalFilename);
+ CallProtoService(szProto,PS_FILERESUME,(WPARAM)dat->fs,(LPARAM)pfr);
+ if(pfr->szFilename) mir_free((char*)pfr->szFilename);
+ mir_free(pfr);
+ break;
+ }
+ case HM_RECVEVENT:
+ { ACKDATA *ack=(ACKDATA*)lParam;
+ if (ack->hProcess!=dat->fs) break; /* icq abuses this sometimes */
+ if(ack->hContact!=dat->hContact) break;
+ if(ack->type!=ACKTYPE_FILE) break;
+
+ if(dat->waitingForAcceptance) {
+ SetTimer(hwndDlg,1,1000,NULL);
+ dat->waitingForAcceptance=0;
+ }
+ switch(ack->result) {
+ case ACKRESULT_SENTREQUEST: SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("Decision sent")); break;
+ case ACKRESULT_CONNECTING: SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("Connecting...")); break;
+ case ACKRESULT_CONNECTED: SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("Connected")); break;
+ case ACKRESULT_INITIALISING: SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("Initialising...")); break;
+ case ACKRESULT_NEXTFILE:
+ SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("Moving to next file..."));
+ SetDlgItemTextA(hwndDlg,IDC_FILENAME,"");
+ if(dat->transferStatus.currentFileNumber==1 && dat->transferStatus.totalFiles>1 && !dat->send)
+ SetOpenFileButtonStyle(GetDlgItem(hwndDlg,IDC_OPENFILE),1,1);
+ if(dat->transferStatus.currentFileNumber!=-1 && dat->files && !dat->send && DBGetContactSettingByte(NULL,"SRFile","UseScanner",VIRUSSCAN_DISABLE)==VIRUSSCAN_DURINGDL) {
+ if(GetFileAttributesA(dat->files[dat->transferStatus.currentFileNumber])&FILE_ATTRIBUTE_DIRECTORY)
+ PostMessage(hwndDlg,M_VIRUSSCANDONE,dat->transferStatus.currentFileNumber,0);
+ else {
+ struct virusscanthreadstartinfo *vstsi;
+ vstsi=(struct virusscanthreadstartinfo*)mir_alloc(sizeof(struct virusscanthreadstartinfo));
+ vstsi->hwndReply=hwndDlg;
+ vstsi->szFile=mir_strdup(dat->files[dat->transferStatus.currentFileNumber]);
+ vstsi->returnCode=dat->transferStatus.currentFileNumber;
+ forkthread((void (*)(void*))RunVirusScannerThread,0,vstsi);
+ }
+ }
+ break;
+ case ACKRESULT_FILERESUME:
+ {
+ PROTOFILETRANSFERSTATUS *fts=(PROTOFILETRANSFERSTATUS*)ack->lParam;
+
+ FreeProtoFileTransferStatus(&dat->transferStatus);
+ CopyProtoFileTransferStatus(&dat->transferStatus,fts);
+ SetFilenameControls(hwndDlg,fts);
+ if(_access(fts->currentFile,0)!=0) break;
+ SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("File already exists"));
+ if(dat->resumeBehaviour==FILERESUME_ASK) {
+ ShowWindow(hwndDlg,SW_SHOWNORMAL);
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_FILEEXISTS),hwndDlg,DlgProcFileExists,(LPARAM)fts);
+ EnableWindow(hwndDlg,FALSE);
+ }
+ else {
+ PROTOFILERESUME *pfr;
+ pfr=(PROTOFILERESUME*)mir_alloc(sizeof(PROTOFILERESUME));
+ pfr->action=dat->resumeBehaviour;
+ pfr->szFilename=NULL;
+ PostMessage(hwndDlg,M_FILEEXISTSDLGREPLY,(WPARAM)mir_strdup(fts->currentFile),(LPARAM)pfr);
+ }
+ SetWindowLong(hwndDlg,DWL_MSGRESULT,1);
+ return TRUE;
+ }
+ case ACKRESULT_DATA:
+ {
+ PROTOFILETRANSFERSTATUS *fts=(PROTOFILETRANSFERSTATUS*)ack->lParam;
+ TCHAR str[256],szSizeDone[32],szSizeTotal[32],*contactName;
+ int units;
+
+ /* HACK: for 0.3.3, limit updates to around 1.1 ack per second */
+ if (fts->totalProgress!=fts->totalBytes && GetTickCount() - dat->dwTicks < 650) break; // the last update was less than a second ago!
+ dat->dwTicks=GetTickCount();
+
+/* FIXME: There is a leak with this, and a major performance issue with creating and freeing this list EVERY DAMN ACK! */
+ FreeProtoFileTransferStatus(&dat->transferStatus);
+ CopyProtoFileTransferStatus(&dat->transferStatus,fts);
+ if(dat->fileVirusScanned==NULL) dat->fileVirusScanned=(int*)mir_calloc(sizeof(int) * fts->totalFiles);
+ if(!dat->send) {
+ if(dat->files==NULL) dat->files=(char**)mir_calloc((fts->totalFiles+1)*sizeof(char*));
+ if(fts->currentFileNumber<fts->totalFiles) dat->files[fts->currentFileNumber]=mir_strdup(fts->currentFile);
+ }
+/* FIXME: There is a performance issue of creating this list here if it does not exist */
+
+ SetDlgItemText(hwndDlg,IDC_STATUS,TranslateTS(fts->sending?_T("Sending..."):_T("Receiving...")));
+ SetFilenameControls(hwndDlg,fts);
+ SendDlgItemMessage(hwndDlg,IDC_CURRENTFILEPROGRESS, PBM_SETPOS, fts->currentFileSize?(WPARAM)(BIGI(100)*fts->currentFileProgress/fts->currentFileSize):0, 0);
+ SendDlgItemMessage(hwndDlg,IDC_ALLFILESPROGRESS, PBM_SETPOS, fts->totalBytes?(WPARAM)(BIGI(100)*fts->totalProgress/fts->totalBytes):0, 0);
+
+ GetSensiblyFormattedSize(fts->currentFileSize,szSizeTotal,SIZEOF(szSizeTotal),0,1,&units);
+ GetSensiblyFormattedSize(fts->currentFileProgress,szSizeDone,SIZEOF(szSizeTotal),units,0,NULL);
+ mir_sntprintf(str,SIZEOF(str),_T("%s / %s (%d%%)"),szSizeDone,szSizeTotal,fts->currentFileSize?(int)(BIGI(100)*fts->currentFileProgress/fts->currentFileSize):0);
+ SetDlgItemText(hwndDlg,IDC_CURRENTTRANSFERRED,str);
+
+ GetSensiblyFormattedSize(fts->totalBytes,szSizeTotal,SIZEOF(szSizeTotal),0,1,&units);
+ GetSensiblyFormattedSize(fts->totalProgress,szSizeDone,SIZEOF(szSizeTotal),units,0,NULL);
+ mir_sntprintf(str,SIZEOF(str),_T("%s / %s (%d%%)"),szSizeDone,szSizeTotal,fts->totalBytes?(int)(BIGI(100)*fts->totalProgress/fts->totalBytes):0);
+ SetDlgItemText(hwndDlg,IDC_ALLTRANSFERRED,str);
+
+ contactName=(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)dat->hContact,GCDNF_TCHAR);
+ mir_sntprintf(str,SIZEOF(str),_T("%d%%: %s: %s"),fts->totalBytes?(int)(BIGI(100)*fts->totalProgress/fts->totalBytes):0,contactName,TranslateTS(dat->send?(fts->totalFiles==1?_T("Sending file"):_T("Sending files")):(fts->totalFiles==1?_T("Receiving file"):_T("Receiving files"))));
+ SetWindowText(GetParent(hwndDlg),str);
+ break;
+ }
+ case ACKRESULT_SUCCESS:
+ {
+ dat->fs=NULL; /* protocol will free structure */
+ SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("Transfer completed"));
+ if (ack->result==ACKRESULT_SUCCESS) SkinPlaySound("FileDone");
+ if(!dat->send) { //receiving
+ int useScanner=DBGetContactSettingByte(NULL,"SRFile","UseScanner",VIRUSSCAN_DISABLE);
+ if(useScanner!=VIRUSSCAN_DISABLE) {
+ struct virusscanthreadstartinfo *vstsi;
+ vstsi=(struct virusscanthreadstartinfo*)mir_alloc(sizeof(struct virusscanthreadstartinfo));
+ vstsi->hwndReply=hwndDlg;
+ if(useScanner==VIRUSSCAN_DURINGDL) {
+ vstsi->returnCode=dat->transferStatus.currentFileNumber;
+ if(GetFileAttributesA(dat->files[dat->transferStatus.currentFileNumber])&FILE_ATTRIBUTE_DIRECTORY) {
+ PostMessage(hwndDlg,M_VIRUSSCANDONE,vstsi->returnCode,0);
+ mir_free(vstsi);
+ vstsi=NULL;
+ }
+ else vstsi->szFile=mir_strdup(dat->files[dat->transferStatus.currentFileNumber]);
+ }
+ else {
+ vstsi->szFile=mir_strdup(dat->transferStatus.workingDir);
+ vstsi->returnCode=-1;
+ }
+ SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("Scanning for viruses..."));
+ if(vstsi) forkthread((void (*)(void*))RunVirusScannerThread,0,vstsi);
+ }
+ dat->transferStatus.currentFileNumber=dat->transferStatus.totalFiles;
+ }
+ else { //sending
+ DBEVENTINFO dbei={0};
+ char szMsg[450],szFilenames[1024];
+ GetDlgItemTextA(GetParent(hwndDlg),IDC_FILE,szFilenames,SIZEOF(szFilenames));
+ GetDlgItemTextA(GetParent(hwndDlg),IDC_MSG,szMsg,SIZEOF(szMsg));
+ dbei.cbSize=sizeof(dbei);
+ dbei.szModule=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ dbei.eventType=EVENTTYPE_FILE;
+ dbei.flags=DBEF_SENT;
+ dbei.timestamp=time(NULL);
+ dbei.cbBlob=sizeof(DWORD)+lstrlenA(szFilenames)+lstrlenA(szMsg)+2;
+ dbei.pBlob=(PBYTE)mir_alloc(dbei.cbBlob);
+ *(PDWORD)dbei.pBlob=0;
+ lstrcpyA(dbei.pBlob+sizeof(DWORD),szFilenames);
+ lstrcpyA(dbei.pBlob+sizeof(DWORD)+lstrlenA(szFilenames)+1,szMsg);
+ CallService(MS_DB_EVENT_ADD,(WPARAM)dat->hContact,(LPARAM)&dbei);
+ if (dbei.pBlob)
+ mir_free(dbei.pBlob);
+ dat->files=NULL; //protocol library frees this
+ }
+ }
+ //fall through
+ case ACKRESULT_FAILED:
+ dat->fs=NULL; /* protocol will free structure */
+ KillTimer(hwndDlg,1);
+ if(!dat->send) SetOpenFileButtonStyle(GetDlgItem(hwndDlg,IDC_OPENFILE),dat->transferStatus.totalFiles>1,1);
+ SetDlgItemText(hwndDlg,IDCANCEL,TranslateT("Close"));
+ if (dat->hNotifyEvent) UnhookEvent(dat->hNotifyEvent);
+ dat->hNotifyEvent=NULL;
+ if(ack->result==ACKRESULT_FAILED) {
+ SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("File transfer failed"));
+ SkinPlaySound("FileFailed");
+ } else
+ if(DBGetContactSettingByte(NULL,"SRFile","AutoClose",0))
+ PostMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDCANCEL,BN_CLICKED),(LPARAM)GetDlgItem(hwndDlg,IDCANCEL));
+ break;
+
+ case ACKRESULT_DENIED:
+ dat->fs=NULL; /* protocol will free structure */
+ SkinPlaySound("FileDenied");
+ KillTimer(hwndDlg, 1);
+ if (!dat->send) SetOpenFileButtonStyle(GetDlgItem(hwndDlg, IDC_OPENFILE), dat->transferStatus.totalFiles > 1, 1);
+ SetDlgItemText(hwndDlg, IDCANCEL, TranslateT("Close"));
+ SetDlgItemText(hwndDlg, IDC_STATUS, TranslateT("File transfer denied"));
+ UnhookEvent(dat->hNotifyEvent);
+ dat->hNotifyEvent = NULL;
+ break;
+
+ }
+ break;
+ }
+ case M_VIRUSSCANDONE:
+ { int done=1,i;
+ if((int)wParam==-1) {
+ for(i=0;i<dat->transferStatus.totalFiles;i++) dat->fileVirusScanned[i]=1;
+ }
+ else {
+ dat->fileVirusScanned[wParam]=1;
+ for(i=0;i<dat->transferStatus.totalFiles;i++) if(!dat->fileVirusScanned[i]) {done=0; break;}
+ }
+ if(done) SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("Transfer and virus scan complete"));
+ break;
+ }
+ case WM_DESTROY:
+ KillTimer(hwndDlg,1);
+ if(dat->fs) CallContactService(dat->hContact,PSS_FILECANCEL,(WPARAM)dat->fs,0);
+ dat->fs=NULL;
+ if(dat->hNotifyEvent) {UnhookEvent(dat->hNotifyEvent); dat->hNotifyEvent=NULL;}
+ FreeProtoFileTransferStatus(&dat->transferStatus);
+ if(!dat->send) FreeFilesMatrix(&dat->files);
+ if(dat->fileVirusScanned) mir_free(dat->fileVirusScanned);
+ { HFONT hFont;
+ hFont=(HFONT)SendDlgItemMessage(hwndDlg,IDC_CURRENTFILEGROUP,WM_GETFONT,0,0);
+ DeleteObject(hFont);
+ }
+ break;
+ }
+ return FALSE;
+}
diff --git a/miranda-wine/src/modules/srurl/url.c b/miranda-wine/src/modules/srurl/url.c
new file mode 100644
index 0000000..9ae10d4
--- /dev/null
+++ b/miranda-wine/src/modules/srurl/url.c
@@ -0,0 +1,203 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include <m_url.h>
+#include "url.h"
+
+HANDLE hUrlWindowList = NULL;
+static HANDLE hEventContactSettingChange = NULL;
+HANDLE hContactDeleted=NULL;
+HANDLE *hUrlContactMenu=NULL;
+int hUrlContactMenuCount=0;
+
+BOOL CALLBACK DlgProcUrlSend(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+BOOL CALLBACK DlgProcUrlRecv(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+static int ReadUrlCommand(WPARAM wParam,LPARAM lParam)
+{
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_URLRECV),NULL,DlgProcUrlRecv,lParam);
+ return 0;
+}
+
+static int UrlEventAdded(WPARAM wParam,LPARAM lParam)
+{
+ CLISTEVENT cle;
+ DBEVENTINFO dbei;
+ char *contactName;
+ char szTooltip[256];
+
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=0;
+ CallService(MS_DB_EVENT_GET,lParam,(LPARAM)&dbei);
+ if(dbei.flags&(DBEF_SENT|DBEF_READ) || dbei.eventType!=EVENTTYPE_URL) return 0;
+
+ SkinPlaySound("RecvUrl");
+ ZeroMemory(&cle,sizeof(cle));
+ cle.cbSize=sizeof(cle);
+ cle.hContact=(HANDLE)wParam;
+ cle.hDbEvent=(HANDLE)lParam;
+ cle.hIcon=LoadSkinnedIcon(SKINICON_EVENT_URL);
+ cle.pszService="SRUrl/ReadUrl";
+ contactName=(char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,wParam,0);
+ mir_snprintf(szTooltip,SIZEOF(szTooltip),Translate("URL from %s"),contactName);
+ cle.pszTooltip=szTooltip;
+ CallService(MS_CLIST_ADDEVENT,0,(LPARAM)&cle);
+ return 0;
+}
+
+static int SendUrlCommand(WPARAM wParam,LPARAM lParam)
+{
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_URLSEND),NULL,DlgProcUrlSend,wParam);
+ return 0;
+}
+
+static void RestoreUnreadUrlAlerts(void)
+{
+ CLISTEVENT cle={0};
+ DBEVENTINFO dbei={0};
+ char toolTip[256];
+ HANDLE hDbEvent,hContact;
+
+ dbei.cbSize=sizeof(dbei);
+ cle.cbSize=sizeof(cle);
+ cle.hIcon=LoadSkinnedIcon(SKINICON_EVENT_URL);
+ cle.pszService="SRUrl/ReadUrl";
+
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ while(hContact) {
+ hDbEvent=(HANDLE)CallService(MS_DB_EVENT_FINDFIRSTUNREAD,(WPARAM)hContact,0);
+ while(hDbEvent) {
+ dbei.cbBlob=0;
+ CallService(MS_DB_EVENT_GET,(WPARAM)hDbEvent,(LPARAM)&dbei);
+ if(!(dbei.flags&(DBEF_SENT|DBEF_READ)) && dbei.eventType==EVENTTYPE_URL) {
+ cle.hContact=hContact;
+ cle.hDbEvent=hDbEvent;
+ mir_snprintf(toolTip,SIZEOF(toolTip),Translate("URL from %s"),(char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)hContact,0));
+ cle.pszTooltip=toolTip;
+ CallService(MS_CLIST_ADDEVENT,0,(LPARAM)&cle);
+ }
+ hDbEvent=(HANDLE)CallService(MS_DB_EVENT_FINDNEXT,(WPARAM)hDbEvent,0);
+ }
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0);
+ }
+}
+
+static int ContactSettingChanged(WPARAM wParam, LPARAM lParam)
+{
+ DBCONTACTWRITESETTING *cws=(DBCONTACTWRITESETTING*)lParam;
+ char *szProto;
+
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,wParam,0);
+ if(lstrcmpA(cws->szModule,"CList") && (szProto==NULL || lstrcmpA(cws->szModule,szProto))) return 0;
+ WindowList_Broadcast(hUrlWindowList,DM_UPDATETITLE,0,0);
+ return 0;
+}
+
+static int SRUrlModulesLoaded(WPARAM wParam,LPARAM lParam)
+{
+ CLISTMENUITEM mi;
+ PROTOCOLDESCRIPTOR **protocol;
+ int protoCount,i;
+
+ ZeroMemory(&mi,sizeof(mi));
+ mi.cbSize=sizeof(mi);
+ mi.position=-2000040000;
+ mi.flags=0;
+ mi.hIcon=LoadSkinnedIcon(SKINICON_EVENT_URL);
+ mi.pszName=Translate("Web Page Address (&URL)");
+ mi.pszService=MS_URL_SENDURL;
+ CallService(MS_PROTO_ENUMPROTOCOLS,(WPARAM)&protoCount,(LPARAM)&protocol);
+ for(i=0;i<protoCount;i++) {
+ if(protocol[i]->type!=PROTOTYPE_PROTOCOL) continue;
+ if(CallProtoService(protocol[i]->szName,PS_GETCAPS,PFLAGNUM_1,0)&PF1_URLSEND) {
+ mi.pszContactOwner=protocol[i]->szName;
+ hUrlContactMenu=mir_realloc(hUrlContactMenu,(hUrlContactMenuCount+1)*sizeof(HANDLE));
+ hUrlContactMenu[hUrlContactMenuCount++]=(HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi);
+ }
+ }
+ RestoreUnreadUrlAlerts();
+ return 0;
+}
+
+static int UrlMenuIconChanged(WPARAM wParam, LPARAM lParam)
+{
+
+ if (hUrlContactMenu) {
+
+ int j;
+ CLISTMENUITEM mi;
+
+ mi.cbSize=sizeof(mi);
+ mi.flags=CMIM_ICON;
+ mi.hIcon=LoadSkinnedIcon(SKINICON_EVENT_URL);
+
+ for (j=0; j<hUrlContactMenuCount; j++) {
+ CallService(MS_CLIST_MODIFYMENUITEM,(WPARAM)hUrlContactMenu[j],(LPARAM)&mi);
+ }
+
+ }
+ return 0;
+}
+
+static int SRUrlShutdown(WPARAM wParam,LPARAM lParam)
+{
+
+ if (hEventContactSettingChange) UnhookEvent(hEventContactSettingChange);
+ if (hContactDeleted) UnhookEvent(hContactDeleted);
+ if (hUrlWindowList) {
+ WindowList_BroadcastAsync(hUrlWindowList,WM_CLOSE,0,0);
+ }
+ if (hUrlContactMenu) {
+ mir_free(hUrlContactMenu); hUrlContactMenu=NULL;
+ hUrlContactMenuCount=0;
+ }
+ return 0;
+
+}
+
+int UrlContactDeleted(WPARAM wParam, LPARAM lParam)
+{
+ HWND h;
+ h=WindowList_Find(hUrlWindowList,(HANDLE)wParam);
+ if (h) {
+ SendMessage(h,WM_CLOSE,0,0);
+ }
+ return 0;
+}
+
+int LoadSendRecvUrlModule(void)
+{
+ hUrlWindowList=(HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST,0,0);
+ HookEvent(ME_SYSTEM_MODULESLOADED,SRUrlModulesLoaded);
+ HookEvent(ME_DB_EVENT_ADDED,UrlEventAdded);
+ HookEvent(ME_SKIN_ICONSCHANGED,UrlMenuIconChanged);
+ hEventContactSettingChange = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, ContactSettingChanged);
+ hContactDeleted = HookEvent(ME_DB_CONTACT_DELETED, UrlContactDeleted);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN,SRUrlShutdown);
+ CreateServiceFunction(MS_URL_SENDURL,SendUrlCommand);
+ CreateServiceFunction("SRUrl/ReadUrl",ReadUrlCommand);
+ SkinAddNewSoundEx("RecvUrl",Translate("URL"),Translate("Incoming"));
+ return 0;
+}
+
diff --git a/miranda-wine/src/modules/srurl/url.h b/miranda-wine/src/modules/srurl/url.h
new file mode 100644
index 0000000..de8f442
--- /dev/null
+++ b/miranda-wine/src/modules/srurl/url.h
@@ -0,0 +1,43 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 TIMEOUT_URLSEND 9000
+#define HM_EVENTSENT (WM_USER+10)
+#define DM_UPDATETITLE (WM_USER+11)
+
+#define DDEMESSAGETIMEOUT 1000
+
+
+struct UrlRcvData {
+ HANDLE hContact;
+ HANDLE hDbEvent;
+ HICON hIcons[4];
+};
+
+struct UrlSendData {
+ HANDLE hContact;
+ HANDLE hSendId;
+ HANDLE hAckEvent;
+ char *sendBuffer;
+ HICON hIcons[4];
+};
diff --git a/miranda-wine/src/modules/srurl/urldialogs.c b/miranda-wine/src/modules/srurl/urldialogs.c
new file mode 100644
index 0000000..083d825
--- /dev/null
+++ b/miranda-wine/src/modules/srurl/urldialogs.c
@@ -0,0 +1,737 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include "url.h"
+
+
+BOOL CALLBACK DlgProcUrlSend(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+extern HANDLE hUrlWindowList;
+
+
+BOOL CALLBACK DlgProcUrlRecv(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct UrlRcvData *dat = NULL;
+
+ dat=(struct UrlRcvData *)GetWindowLong(hwndDlg, GWL_USERDATA);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_URL));
+
+ dat=(struct UrlRcvData*)mir_alloc(sizeof(struct UrlRcvData));
+ SetWindowLong(hwndDlg, GWL_USERDATA, (LONG)dat);
+
+ dat->hContact = ((CLISTEVENT*)lParam)->hContact;
+ dat->hDbEvent = ((CLISTEVENT*)lParam)->hDbEvent;
+
+ WindowList_Add(hUrlWindowList, hwndDlg, dat->hContact);
+
+ {
+ DBEVENTINFO dbei;
+ DBTIMETOSTRINGT dbtts;
+ TCHAR* contactName;
+ TCHAR msg[128];
+
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)dat->hDbEvent,0);
+ dbei.pBlob=(PBYTE)mir_alloc(dbei.cbBlob);
+ CallService(MS_DB_EVENT_GET,(WPARAM)dat->hDbEvent,(LPARAM)&dbei);
+ SetDlgItemTextA(hwndDlg,IDC_URL,dbei.pBlob);
+ SetDlgItemTextA(hwndDlg,IDC_MSG,dbei.pBlob+lstrlenA(dbei.pBlob)+1);
+ mir_free(dbei.pBlob);
+
+ CallService(MS_DB_EVENT_MARKREAD,(WPARAM)dat->hContact,(LPARAM)dat->hDbEvent);
+
+ contactName=(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)dat->hContact,GCDNF_TCHAR);
+ mir_sntprintf(msg,SIZEOF(msg),TranslateT("URL from %s"),contactName);
+ SetWindowText(hwndDlg,msg);
+ SetDlgItemText(hwndDlg,IDC_FROM,contactName);
+ SendDlgItemMessage(hwndDlg,IDOK,BUTTONSETARROW,1,0);
+ { TCHAR str[128];
+ dbtts.szFormat = _T("t d");
+ dbtts.szDest = str;
+ dbtts.cbDest = SIZEOF(str);
+ CallService(MS_DB_TIME_TIMESTAMPTOSTRINGT, dbei.timestamp, (LPARAM)&dbtts);
+ SetDlgItemText(hwndDlg, IDC_DATE, str);
+ } }
+
+ // From message dlg
+ if (!DBGetContactSettingByte(dat->hContact, "CList", "NotOnList", 0))
+ ShowWindow(GetDlgItem(hwndDlg, IDC_ADD), SW_HIDE);
+
+ dat->hIcons[0]=(HICON)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_ADDCONTACT),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ dat->hIcons[1]=(HICON)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_USERDETAILS),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ dat->hIcons[2]=(HICON)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_HISTORY),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ dat->hIcons[3]=(HICON)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_DOWNARROW),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ SendDlgItemMessage(hwndDlg,IDC_ADD,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hIcons[0]);
+ SendDlgItemMessage(hwndDlg,IDC_DETAILS,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hIcons[1]);
+ SendDlgItemMessage(hwndDlg,IDC_HISTORY,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hIcons[2]);
+ SendDlgItemMessage(hwndDlg,IDC_USERMENU,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hIcons[3]);
+ SendDlgItemMessage(hwndDlg,IDC_ADD,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_DETAILS,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_HISTORY,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_USERMENU,BUTTONSETASFLATBTN,0,0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_ADD), BUTTONADDTOOLTIP, (WPARAM)Translate("Add Contact Permanently to List"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_USERMENU), BUTTONADDTOOLTIP, (WPARAM)Translate("User Menu"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_DETAILS), BUTTONADDTOOLTIP, (WPARAM)Translate("View User's Details"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_HISTORY), BUTTONADDTOOLTIP, (WPARAM)Translate("View User's History"), 0);
+
+ SendMessage(hwndDlg,DM_UPDATETITLE,0,0);
+ // From message dlg end
+
+ Utils_RestoreWindowPositionNoSize(hwndDlg,NULL,"SRUrl","recv");
+ return TRUE;
+
+ case WM_MEASUREITEM:
+ return CallService(MS_CLIST_MENUMEASUREITEM,wParam,lParam);
+
+ case WM_DRAWITEM:
+ { LPDRAWITEMSTRUCT dis=(LPDRAWITEMSTRUCT)lParam;
+ if(dis->hwndItem==GetDlgItem(hwndDlg, IDC_PROTOCOL)) {
+ char *szProto;
+
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ if (szProto) {
+ HICON hIcon;
+
+ hIcon=(HICON)CallProtoService(szProto,PS_LOADICON,PLI_PROTOCOL|PLIF_SMALL,0);
+ if (hIcon) DrawIconEx(dis->hDC,dis->rcItem.left,dis->rcItem.top,hIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL);
+ }
+ }
+ return CallService(MS_CLIST_MENUDRAWITEM,wParam,lParam);
+ }
+
+ case DM_UPDATETITLE:
+ {
+ char newtitle[256],oldtitle[256];
+ char *szStatus,*contactName,*pszNewTitleStart;
+ char *szProto;
+
+ pszNewTitleStart=Translate("URL from ");
+
+ if (dat->hContact) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ if (szProto) {
+ CONTACTINFO ci;
+ int hasName = 0;
+ char buf[128];
+ ZeroMemory(&ci,sizeof(ci));
+
+ ci.cbSize = sizeof(ci);
+ ci.hContact = dat->hContact;
+ ci.szProto = szProto;
+ ci.dwFlag = CNF_UNIQUEID;
+ if (!CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&ci)) {
+ switch(ci.type) {
+ case CNFT_ASCIIZ:
+ hasName = 1;
+ mir_snprintf(buf, SIZEOF(buf), "%s", ci.pszVal);
+ mir_free(ci.pszVal);
+ break;
+ case CNFT_DWORD:
+ hasName = 1;
+ mir_snprintf(buf, SIZEOF(buf),"%u",ci.dVal);
+ break;
+ }
+ }
+
+ //
+ contactName=(char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)dat->hContact,0);
+ SetDlgItemTextA(hwndDlg,IDC_NAME,hasName?buf:contactName);
+
+ szStatus=(char*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION,szProto==NULL?ID_STATUS_OFFLINE:DBGetContactSettingWord(dat->hContact,szProto,"Status",ID_STATUS_OFFLINE),0);
+ mir_snprintf(newtitle,SIZEOF(newtitle),"%s %s (%s)", pszNewTitleStart, contactName, szStatus);
+ }
+ }
+ else
+ lstrcpynA(newtitle, pszNewTitleStart, SIZEOF(newtitle));
+
+ GetWindowTextA(hwndDlg,oldtitle,SIZEOF(oldtitle));
+
+ if(lstrcmpA(newtitle,oldtitle)) //swt() flickers even if the title hasn't actually changed
+ SetWindowTextA(hwndDlg,newtitle);
+
+ break;
+
+ }
+
+ case WM_COMMAND:
+ if (dat)
+ if(CallService(MS_CLIST_MENUPROCESSCOMMAND,MAKEWPARAM(LOWORD(wParam),MPCF_CONTACTMENU),(LPARAM)dat->hContact))
+ break;
+ switch(LOWORD(wParam))
+ {
+ case IDOK:
+ { HMENU hMenu,hSubMenu;
+ RECT rc;
+ char url[256];
+
+ hMenu=LoadMenu(GetModuleHandle(NULL),MAKEINTRESOURCE(IDR_CONTEXT));
+ hSubMenu=GetSubMenu(hMenu,6);
+ CallService(MS_LANGPACK_TRANSLATEMENU,(WPARAM)hSubMenu,0);
+ GetWindowRect((HWND)lParam, &rc);
+ GetDlgItemTextA(hwndDlg, IDC_URL, url, SIZEOF(url));
+ switch(TrackPopupMenu(hSubMenu,TPM_RETURNCMD,rc.left,rc.bottom,0,hwndDlg,NULL)) {
+ case IDM_OPENNEW:
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)url);
+ break;
+ case IDM_OPENEXISTING:
+ CallService(MS_UTILS_OPENURL,0,(LPARAM)url);
+ break;
+ case IDM_COPYLINK:
+ { HGLOBAL hData;
+ if(!OpenClipboard(hwndDlg)) break;
+ EmptyClipboard();
+ hData=GlobalAlloc(GMEM_MOVEABLE,lstrlenA(url)+1);
+ lstrcpyA((char*)GlobalLock(hData),url);
+ GlobalUnlock(hData);
+ SetClipboardData(CF_TEXT,hData);
+ CloseClipboard();
+ break;
+ }
+ }
+ }
+ return TRUE;
+
+ case IDC_USERMENU:
+ {
+ RECT rc;
+ HMENU hMenu=(HMENU)CallService(MS_CLIST_MENUBUILDCONTACT,(WPARAM)dat->hContact,0);
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_USERMENU),&rc);
+ TrackPopupMenu(hMenu,0,rc.left,rc.bottom,0,hwndDlg,NULL);
+ DestroyMenu(hMenu);
+ }
+ break;
+
+ case IDC_HISTORY:
+ CallService(MS_HISTORY_SHOWCONTACTHISTORY,(WPARAM)dat->hContact,0);
+ break;
+ case IDC_DETAILS:
+ CallService(MS_USERINFO_SHOWDIALOG,(WPARAM)dat->hContact,0);
+ break;
+ case IDC_ADD:
+ {
+ ADDCONTACTSTRUCT acs={0};
+
+ acs.handle=dat->hContact;
+ acs.handleType=HANDLE_CONTACT;
+ acs.szProto=0;
+ CallService(MS_ADDCONTACT_SHOW,(WPARAM)hwndDlg,(LPARAM)&acs);
+ }
+ if (!DBGetContactSettingByte(dat->hContact,"CList","NotOnList",0)) {
+ ShowWindow(GetDlgItem(hwndDlg,IDC_ADD),FALSE);
+ }
+ break;
+ case IDC_REPLY:
+ CallService(MS_MSG_SENDMESSAGE,(WPARAM)dat->hContact,0);
+ //fall through
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ }
+ break;
+ case WM_DESTROY:
+ WindowList_Remove(hUrlWindowList, hwndDlg);
+ {int i;for(i=0; i < SIZEOF(dat->hIcons); i++ ) DestroyIcon(dat->hIcons[i]);}
+ mir_free(dat);
+ Utils_SaveWindowPosition(hwndDlg,NULL,"SRUrl","recv");
+ break;
+ }
+ return FALSE;
+}
+
+static int ddeAcked,ddeData;
+static ATOM hSzDdeData;
+static HWND hwndDde;
+static HGLOBAL hGlobalDdeData;
+static LRESULT DdeMessage(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ ATOM hSzItem;
+
+ switch(msg) {
+ case WM_DDE_ACK:
+ ddeAcked=1;
+ hwndDde=(HWND)wParam;
+ return 0;
+ case WM_DDE_DATA:
+ UnpackDDElParam(msg,lParam,(PUINT)&hGlobalDdeData,(PUINT)&hSzItem);
+ ddeData=1;
+ if(hGlobalDdeData) {
+ DDEDATA *data;
+ data=(DDEDATA*)GlobalLock(hGlobalDdeData);
+ if(data->fAckReq) {
+ DDEACK ack={0};
+ PostMessage((HWND)wParam,WM_DDE_ACK,(WPARAM)hwndDlg,PackDDElParam(WM_DDE_ACK,*(PUINT)&ack,(UINT)hSzItem));
+ }
+ else GlobalDeleteAtom(hSzItem);
+ GlobalUnlock(hGlobalDdeData);
+ }
+ else GlobalDeleteAtom(hSzItem);
+ return 0;
+ }
+ return 0;
+}
+
+static HGLOBAL DoDdeRequest(const char *szItemName,HWND hwndDlg)
+{
+ ATOM hSzItemName;
+ DWORD timeoutTick,thisTick;
+ MSG msg;
+
+ hSzItemName=GlobalAddAtomA(szItemName);
+ if(!PostMessage(hwndDde,WM_DDE_REQUEST,(WPARAM)hwndDlg,MAKELPARAM(CF_TEXT,hSzItemName))) {
+ GlobalDeleteAtom(hSzItemName);
+ return NULL;
+ }
+ timeoutTick=GetTickCount()+5000;
+ ddeData=0; ddeAcked=0;
+ do {
+ if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ if(ddeData || ddeAcked) break;
+ thisTick=GetTickCount();
+ if(thisTick>timeoutTick) break;
+ } while(MsgWaitForMultipleObjects(0,NULL,FALSE,timeoutTick-thisTick,QS_ALLINPUT)==WAIT_OBJECT_0);
+
+ if(!ddeData) {
+ GlobalDeleteAtom(hSzItemName);
+ return NULL;
+ }
+
+ return hGlobalDdeData;
+}
+
+static void FreeDdeRequestData(HGLOBAL hData)
+{
+ DDEDATA *data;
+ data=(DDEDATA*)GlobalLock(hData);
+ if(data->fRelease) {
+ GlobalUnlock(hData);
+ GlobalFree(hData);
+ }
+ else GlobalUnlock(hData);
+}
+
+static void AddBrowserPageToCombo(char *url,HWND hwndCombo)
+{
+ char *title,*frame,*end;
+
+ if(url[0]!='"') return;
+ url++;
+ title=strchr(url,'"');
+ if(title==NULL) return;
+ *title='\0'; title++;
+ if(*title) {
+ title+=2;
+ frame=strchr(title,'"');
+ if(frame==NULL) return;
+ *frame='\0'; frame++;
+ if(*frame) {
+ frame+=2;
+ end=strchr(frame,'"');
+ if(end==NULL) return;
+ *end='\0';
+ }
+ else frame=NULL;
+ }
+ else title=frame=NULL;
+ if(frame==NULL || *frame==0) {
+ char *szItemData;
+ int i;
+ char szExistingUrl[1024];
+
+ for(i=SendMessage(hwndCombo,CB_GETCOUNT,0,0)-1;i>=0;i--) {
+ if(SendMessage(hwndCombo,CB_GETLBTEXTLEN,i,0) >= SIZEOF(szExistingUrl))
+ continue;
+ SendMessageA(hwndCombo,CB_GETLBTEXT,i,(LPARAM)szExistingUrl);
+ if(!lstrcmpA(szExistingUrl,url)) return;
+ }
+ i=SendMessageA(hwndCombo,CB_ADDSTRING,0,(LPARAM)url);
+ szItemData=mir_strdup(title);
+ SendMessage(hwndCombo,CB_SETITEMDATA,i,(LPARAM)szItemData);
+ }
+}
+
+//see Q160957 and http://developer.netscape.com/docs/manuals/communicator/DDE/index.htm
+static void GetOpenBrowserUrlsForBrowser(const char *szBrowser,HWND hwndDlg,HWND hwndCombo)
+{
+ ATOM hSzBrowser,hSzTopic;
+ int windowCount,i;
+ DWORD *windowId;
+ DWORD dwResult;
+ HGLOBAL hData;
+ DDEDATA *data;
+ int dataLength;
+
+ hSzBrowser=GlobalAddAtomA(szBrowser);
+
+ hSzTopic=GlobalAddAtomA("WWW_ListWindows");
+ ddeAcked=0;
+ if(!SendMessageTimeout(HWND_BROADCAST,WM_DDE_INITIATE,(WPARAM)hwndDlg,MAKELPARAM(hSzBrowser,hSzTopic),SMTO_ABORTIFHUNG|SMTO_NORMAL,DDEMESSAGETIMEOUT,&dwResult)
+ || !ddeAcked) {
+ GlobalDeleteAtom(hSzTopic);
+ GlobalDeleteAtom(hSzBrowser);
+ return;
+ }
+ hData=DoDdeRequest("WWW_ListWindows",hwndDlg);
+ if(hData==NULL) {
+ GlobalDeleteAtom(hSzTopic);
+ GlobalDeleteAtom(hSzBrowser);
+ return;
+ }
+ dataLength=GlobalSize(hData)-offsetof(DDEDATA,Value);
+ data=(DDEDATA*)GlobalLock(hData);
+ windowCount=dataLength/sizeof(DWORD);
+ windowId=(PDWORD)mir_alloc(sizeof(DWORD)*windowCount);
+ memcpy(windowId,data->Value,windowCount*sizeof(DWORD));
+ GlobalUnlock(hData);
+ FreeDdeRequestData(hData);
+ PostMessage(hwndDde,WM_DDE_TERMINATE,(WPARAM)hwndDlg,0);
+ GlobalDeleteAtom(hSzTopic);
+
+ hSzTopic=GlobalAddAtomA("WWW_GetWindowInfo");
+ ddeAcked=0;
+ if(!SendMessageTimeout(HWND_BROADCAST,WM_DDE_INITIATE,(WPARAM)hwndDlg,MAKELPARAM(hSzBrowser,hSzTopic),SMTO_ABORTIFHUNG|SMTO_NORMAL,DDEMESSAGETIMEOUT,&dwResult)
+ || !ddeAcked) {
+ GlobalDeleteAtom(hSzTopic);
+ GlobalDeleteAtom(hSzBrowser);
+ mir_free(windowId);
+ return;
+ }
+ for(i=0;i<windowCount;i++) {
+ if(windowId[i]==0) break;
+ { char str[16];
+ wsprintfA(str,"%d",windowId[i]);
+ hData=DoDdeRequest(str,hwndDlg);
+ }
+ if(hData!=NULL) {
+ dataLength=GlobalSize(hData)-offsetof(DDEDATA,Value);
+ data=(DDEDATA*)GlobalLock(hData);
+ AddBrowserPageToCombo(data->Value,hwndCombo);
+ GlobalUnlock(hData);
+ FreeDdeRequestData(hData);
+ }
+ }
+ PostMessage(hwndDde,WM_DDE_TERMINATE,(WPARAM)hwndDlg,0);
+ GlobalDeleteAtom(hSzTopic);
+ GlobalDeleteAtom(hSzBrowser);
+ mir_free(windowId);
+}
+
+static void GetOpenBrowserUrls(HWND hwndDlg,HWND hwndCombo)
+{
+ GetOpenBrowserUrlsForBrowser("opera",hwndDlg,hwndCombo);
+ GetOpenBrowserUrlsForBrowser("netscape",hwndDlg,hwndCombo);
+ GetOpenBrowserUrlsForBrowser("iexplore",hwndDlg,hwndCombo);
+}
+
+static WNDPROC OldSendEditProc;
+static LRESULT CALLBACK SendEditSubclassProc(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;
+ }
+ break;
+ case WM_SYSCHAR:
+ if((wParam=='s' || wParam=='S') && GetKeyState(VK_MENU)&0x8000) {
+ PostMessage(GetParent(hwnd),WM_COMMAND,IDOK,0);
+ return 0;
+ }
+ break;
+ }
+ return CallWindowProc(OldSendEditProc,hwnd,msg,wParam,lParam);
+}
+
+BOOL CALLBACK DlgProcUrlSend(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct UrlSendData *dat;
+
+ dat=(struct UrlSendData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_LIMITTEXT, 450, 0);
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_URL));
+ dat=(struct UrlSendData*)mir_alloc(sizeof(struct UrlSendData));
+ SetWindowLong(hwndDlg,GWL_USERDATA,(LONG)dat);
+ dat->hContact=(HANDLE)lParam;
+ dat->hAckEvent=NULL;
+ dat->hSendId=NULL;
+ dat->sendBuffer=NULL;
+
+ WindowList_Add(hUrlWindowList, hwndDlg, dat->hContact);
+
+ { TCHAR *str = (TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)dat->hContact,GCDNF_TCHAR);
+ SetDlgItemText(hwndDlg,IDC_NAME,str);
+ }
+
+ GetOpenBrowserUrls(hwndDlg,GetDlgItem(hwndDlg,IDC_URLS));
+ SendDlgItemMessage(hwndDlg, IDC_URLS, CB_SETCURSEL, 0, 0);
+ if (SendDlgItemMessage(hwndDlg,IDC_URLS,CB_GETCOUNT,0,0))SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_URLS,CBN_SELCHANGE),0);
+ EnableWindow(GetDlgItem(hwndDlg, IDOK), (SendDlgItemMessage(hwndDlg, IDC_URLS, CB_GETCURSEL, 0, 0) == CB_ERR)?FALSE:TRUE);
+ Utils_RestoreWindowPositionNoSize(hwndDlg,NULL,"SRUrl","send");
+ OldSendEditProc=(WNDPROC)SetWindowLong(GetDlgItem(hwndDlg,IDC_MESSAGE),GWL_WNDPROC,(LONG)SendEditSubclassProc);
+ OldSendEditProc=(WNDPROC)SetWindowLong(GetWindow(GetDlgItem(hwndDlg,IDC_URLS),GW_CHILD),GWL_WNDPROC,(LONG)SendEditSubclassProc);
+
+ // From message dlg
+ if (!DBGetContactSettingByte(dat->hContact, "CList", "NotOnList", 0))
+ ShowWindow(GetDlgItem(hwndDlg, IDC_ADD), SW_HIDE);
+
+ dat->hIcons[0]=(HICON)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_ADDCONTACT),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ dat->hIcons[1]=(HICON)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_USERDETAILS),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ dat->hIcons[2]=(HICON)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_HISTORY),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ dat->hIcons[3]=(HICON)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_DOWNARROW),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ SendDlgItemMessage(hwndDlg,IDC_ADD,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hIcons[0]);
+ SendDlgItemMessage(hwndDlg,IDC_DETAILS,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hIcons[1]);
+ SendDlgItemMessage(hwndDlg,IDC_HISTORY,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hIcons[2]);
+ SendDlgItemMessage(hwndDlg,IDC_USERMENU,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hIcons[3]);
+ SendDlgItemMessage(hwndDlg,IDC_ADD,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_DETAILS,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_HISTORY,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_USERMENU,BUTTONSETASFLATBTN,0,0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_ADD), BUTTONADDTOOLTIP, (WPARAM)Translate("Add Contact Permanently to List"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_USERMENU), BUTTONADDTOOLTIP, (WPARAM)Translate("User Menu"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_DETAILS), BUTTONADDTOOLTIP, (WPARAM)Translate("View User's Details"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_HISTORY), BUTTONADDTOOLTIP, (WPARAM)Translate("View User's History"), 0);
+
+ SendMessage(hwndDlg,DM_UPDATETITLE,0,0);
+ // From message dlg end
+
+ return TRUE;
+ case WM_DDE_DATA:
+ case WM_DDE_ACK:
+ return DdeMessage(hwndDlg,msg,wParam,lParam);
+ case WM_TIMER:
+ if (wParam==0)
+ {//ICQ sendurl timed out
+ KillTimer(hwndDlg,0);
+ MessageBox(hwndDlg,TranslateT("Send timed out"),_T(""),MB_OK);
+ EnableWindow(GetDlgItem(hwndDlg,IDOK),TRUE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_URLS),TRUE);
+ SendDlgItemMessage(hwndDlg,IDC_MESSAGE,EM_SETREADONLY,FALSE,0);
+ }
+ break;
+ case WM_MEASUREITEM:
+ return CallService(MS_CLIST_MENUMEASUREITEM,wParam,lParam);
+ case WM_DRAWITEM:
+ { LPDRAWITEMSTRUCT dis=(LPDRAWITEMSTRUCT)lParam;
+ if(dis->hwndItem==GetDlgItem(hwndDlg, IDC_PROTOCOL)) {
+ char *szProto;
+
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ if (szProto) {
+ HICON hIcon;
+
+ hIcon=(HICON)CallProtoService(szProto,PS_LOADICON,PLI_PROTOCOL|PLIF_SMALL,0);
+ if (hIcon) DrawIconEx(dis->hDC,dis->rcItem.left,dis->rcItem.top,hIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL);
+ }
+ }
+ return CallService(MS_CLIST_MENUDRAWITEM,wParam,lParam);
+ }
+
+ case DM_UPDATETITLE:
+ {
+ char newtitle[256],oldtitle[256];
+ char *szStatus,*contactName,*pszNewTitleStart;
+ char *szProto;
+
+ pszNewTitleStart=Translate("Send URL to");
+
+ if (dat->hContact) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ if (szProto) {
+ CONTACTINFO ci;
+ int hasName = 0;
+ char buf[128];
+ ZeroMemory(&ci,sizeof(ci));
+
+ ci.cbSize = sizeof(ci);
+ ci.hContact = dat->hContact;
+ ci.szProto = szProto;
+ ci.dwFlag = CNF_UNIQUEID;
+ if (!CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&ci)) {
+ switch(ci.type) {
+ case CNFT_ASCIIZ:
+ hasName = 1;
+ mir_snprintf(buf, SIZEOF(buf), "%s", ci.pszVal);
+ mir_free(ci.pszVal);
+ break;
+ case CNFT_DWORD:
+ hasName = 1;
+ mir_snprintf(buf, SIZEOF(buf),"%u",ci.dVal);
+ break;
+ }
+ }
+
+ contactName=(char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)dat->hContact,0);
+ SetDlgItemTextA(hwndDlg,IDC_NAME,hasName?buf:contactName);
+
+ szStatus=(char*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION,szProto==NULL?ID_STATUS_OFFLINE:DBGetContactSettingWord(dat->hContact,szProto,"Status",ID_STATUS_OFFLINE),0);
+ mir_snprintf(newtitle,SIZEOF(newtitle),"%s %s (%s)", pszNewTitleStart, contactName, szStatus);
+ }
+ }
+ else
+ lstrcpynA(newtitle, pszNewTitleStart, SIZEOF(newtitle));
+
+ GetWindowTextA(hwndDlg,oldtitle,SIZEOF(oldtitle));
+
+ if(lstrcmpA(newtitle,oldtitle)) //swt() flickers even if the title hasn't actually changed
+ SetWindowTextA(hwndDlg,newtitle);
+
+ break;
+
+ }
+
+ case WM_COMMAND:
+ if(CallService(MS_CLIST_MENUPROCESSCOMMAND,MAKEWPARAM(LOWORD(wParam),MPCF_CONTACTMENU),(LPARAM)dat->hContact))
+ break;
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ {
+ char *body,*url;
+ int bodySize,urlSize;
+
+ urlSize=GetWindowTextLength(GetDlgItem(hwndDlg,IDC_URLS))+1;
+ url=(char*)mir_alloc(urlSize);
+ GetDlgItemTextA(hwndDlg,IDC_URLS,url,urlSize);
+ if (url[0] == 0) {
+ mir_free(url);
+ break;
+ }
+ bodySize=GetWindowTextLength(GetDlgItem(hwndDlg,IDC_MESSAGE))+1;
+ body=(char*)mir_alloc(bodySize);
+ GetDlgItemTextA(hwndDlg,IDC_MESSAGE,body,bodySize);
+
+ dat->sendBuffer=(char*)mir_realloc(dat->sendBuffer,lstrlenA(url)+lstrlenA(body)+2);
+ lstrcpyA(dat->sendBuffer,url);
+ lstrcpyA(dat->sendBuffer+lstrlenA(url)+1,body);
+ dat->hAckEvent=HookEventMessage(ME_PROTO_ACK,hwndDlg,HM_EVENTSENT);
+ dat->hSendId=(HANDLE)CallContactService(dat->hContact,PSS_URL,0,(LPARAM)dat->sendBuffer);
+ mir_free(url);
+ mir_free(body);
+
+ //create a timeout timer
+ SetTimer(hwndDlg,0,TIMEOUT_URLSEND,NULL);
+ EnableWindow(GetDlgItem(hwndDlg,IDOK),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_URLS),FALSE);
+ SendDlgItemMessage(hwndDlg,IDC_MESSAGE,EM_SETREADONLY,TRUE,0);
+
+ return TRUE;
+ }
+
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ case IDC_URLS:
+ if(HIWORD(wParam)==CBN_SELCHANGE) {
+ int i, urlSize;
+ char *title;
+ i=SendDlgItemMessage(hwndDlg,IDC_URLS,CB_GETCURSEL,0,0);
+ title=(char*)SendDlgItemMessage(hwndDlg,IDC_URLS,CB_GETITEMDATA,(WPARAM)i,0);
+ SetDlgItemTextA(hwndDlg,IDC_MESSAGE,title);
+ urlSize=SendDlgItemMessage(hwndDlg,IDC_URLS,CB_GETLBTEXTLEN,(WPARAM)i,0);
+ EnableWindow(GetDlgItem(hwndDlg,IDOK), (urlSize>0));
+ }
+ else if(HIWORD(wParam)==CBN_EDITCHANGE) {
+ int urlSize = GetWindowTextLength(GetDlgItem(hwndDlg,IDC_URLS));
+ EnableWindow(GetDlgItem(hwndDlg,IDOK), (urlSize>0));
+ }
+ break;
+ case IDC_USERMENU:
+ { RECT rc;
+ HMENU hMenu=(HMENU)CallService(MS_CLIST_MENUBUILDCONTACT,(WPARAM)dat->hContact,0);
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_USERMENU),&rc);
+ TrackPopupMenu(hMenu,0,rc.left,rc.bottom,0,hwndDlg,NULL);
+ DestroyMenu(hMenu);
+ }
+ break;
+ case IDC_HISTORY:
+ CallService(MS_HISTORY_SHOWCONTACTHISTORY,(WPARAM)dat->hContact,0);
+ break;
+ case IDC_DETAILS:
+ CallService(MS_USERINFO_SHOWDIALOG,(WPARAM)dat->hContact,0);
+ break;
+ case IDC_ADD:
+ { ADDCONTACTSTRUCT acs={0};
+
+ acs.handle=dat->hContact;
+ acs.handleType=HANDLE_CONTACT;
+ acs.szProto=0;
+ CallService(MS_ADDCONTACT_SHOW,(WPARAM)hwndDlg,(LPARAM)&acs);
+ }
+ if (!DBGetContactSettingByte(dat->hContact,"CList","NotOnList",0)) {
+ ShowWindow(GetDlgItem(hwndDlg,IDC_ADD),FALSE);
+ }
+ break;
+ }
+ break;
+ case HM_EVENTSENT:
+ { ACKDATA *ack=(ACKDATA*)lParam;
+ DBEVENTINFO dbei;
+ if(ack->hProcess!=dat->hSendId) break;
+ if(ack->hContact!=dat->hContact) break;
+ if(ack->type!=ACKTYPE_URL || ack->result!=ACKRESULT_SUCCESS) break;
+
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.eventType=EVENTTYPE_URL;
+ dbei.flags=DBEF_SENT;
+ dbei.szModule=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ dbei.timestamp=time(NULL);
+ dbei.cbBlob=strlen(dat->sendBuffer)+strlen(dat->sendBuffer+strlen(dat->sendBuffer)+1)+2;
+ dbei.pBlob=dat->sendBuffer;
+ CallService(MS_DB_EVENT_ADD,(WPARAM)dat->hContact,(LPARAM)&dbei);
+ KillTimer(hwndDlg,0);
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ case WM_DESTROY:
+ WindowList_Remove(hUrlWindowList, hwndDlg);
+ {int i;for(i=0; i < SIZEOF(dat->hIcons); i++ ) DestroyIcon(dat->hIcons[i]);}
+ SetWindowLong(GetWindow(GetDlgItem(hwndDlg,IDC_URLS),GW_CHILD),GWL_WNDPROC,(LONG)OldSendEditProc);
+ SetWindowLong(GetDlgItem(hwndDlg,IDC_MESSAGE),GWL_WNDPROC,(LONG)OldSendEditProc);
+ if(dat->hAckEvent) UnhookEvent(dat->hAckEvent);
+ if(dat->sendBuffer!=NULL) mir_free(dat->sendBuffer);
+ mir_free(dat);
+ Utils_SaveWindowPosition(hwndDlg,NULL,"SRUrl","send");
+ { int i;
+ for(i=SendDlgItemMessage(hwndDlg,IDC_URLS,CB_GETCOUNT,0,0)-1;i>=0;i--)
+ mir_free((char*)SendDlgItemMessage(hwndDlg,IDC_URLS,CB_GETITEMDATA,i,0));
+ }
+ break;
+ }
+
+ return FALSE;
+
+}
diff --git a/miranda-wine/src/modules/userinfo/contactinfo.c b/miranda-wine/src/modules/userinfo/contactinfo.c
new file mode 100644
index 0000000..978a34a
--- /dev/null
+++ b/miranda-wine/src/modules/userinfo/contactinfo.c
@@ -0,0 +1,503 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+static HFONT hEmailFont=NULL;
+static HCURSOR hHandCursor=NULL;
+
+static BOOL CALLBACK EditUserEmailDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ SetWindowLong(hwndDlg,GWL_USERDATA,lParam);
+ if(*(char*)lParam) SetWindowText(hwndDlg,TranslateT("Edit E-Mail Address"));
+ TranslateDialogDefault(hwndDlg);
+ SetDlgItemTextA(hwndDlg,IDC_EMAIL,(char*)lParam);
+ EnableWindow(GetDlgItem(hwndDlg,IDOK),*(char*)lParam);
+ return TRUE;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDOK:
+ GetDlgItemTextA(hwndDlg,IDC_EMAIL,(char*)GetWindowLong(hwndDlg,GWL_USERDATA),256);
+ //fall through
+ case IDCANCEL:
+ EndDialog(hwndDlg,wParam);
+ case IDC_EMAIL:
+ if(HIWORD(wParam)==EN_CHANGE)
+ EnableWindow(GetDlgItem(hwndDlg,IDOK),GetWindowTextLength(GetDlgItem(hwndDlg,IDC_EMAIL)));
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK EditUserPhoneDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ { char *szText=(char*)lParam;
+ int i,item,countryCount;
+ struct CountryListEntry *countries;
+ SetWindowLong(hwndDlg,GWL_USERDATA,lParam);
+ if(szText[0]) SetWindowTextA(hwndDlg,"Edit Phone Number");
+ TranslateDialogDefault(hwndDlg);
+ if(lstrlenA(szText)>4 && !lstrcmpA(szText+lstrlenA(szText)-4," SMS")) {
+ CheckDlgButton(hwndDlg,IDC_SMS,BST_CHECKED);
+ szText[lstrlenA(szText)-4]='\0';
+ }
+ EnableWindow(GetDlgItem(hwndDlg,IDOK),szText[0]);
+ SendDlgItemMessage(hwndDlg,IDC_AREA,EM_LIMITTEXT,31,0);
+ SendDlgItemMessage(hwndDlg,IDC_NUMBER,EM_LIMITTEXT,63,0);
+ CallService(MS_UTILS_GETCOUNTRYLIST,(WPARAM)&countryCount,(LPARAM)&countries);
+ for(i=0;i<countryCount;i++) {
+ if(countries[i].id==0 || countries[i].id==0xFFFF) continue;
+ item=SendDlgItemMessageA(hwndDlg,IDC_COUNTRY,CB_ADDSTRING,0,(LPARAM)countries[i].szName);
+ SendDlgItemMessage(hwndDlg,IDC_COUNTRY,CB_SETITEMDATA,item,countries[i].id);
+ }
+ SetDlgItemTextA(hwndDlg,IDC_PHONE,szText);
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ static int noRecursion=0;
+
+ case IDOK:
+ { char *szText=(char*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ int isValid=1;
+ GetDlgItemTextA(hwndDlg,IDC_PHONE,szText,252);
+ if(lstrlenA(szText)<7 || szText[0]!='+') isValid=0;
+ if(isValid) isValid=(lstrlenA(szText+1)==(int)strspn(szText+1,"0123456789 ()-"));
+ if(!isValid) {
+ MessageBox(hwndDlg,TranslateT("The phone number should start with a + and consist of numbers, spaces, brackets and hyphens only."),TranslateT("Invalid Phone Number"),MB_OK);
+ break;
+ }
+ if(IsDlgButtonChecked(hwndDlg,IDC_SMS)) lstrcatA(szText," SMS");
+ }
+ //fall through
+ case IDCANCEL:
+ EndDialog(hwndDlg,wParam);
+ case IDC_COUNTRY:
+ if(HIWORD(wParam)!=CBN_SELCHANGE) break;
+ case IDC_AREA:
+ case IDC_NUMBER:
+ if(LOWORD(wParam)!=IDC_COUNTRY && HIWORD(wParam)!=EN_CHANGE) break;
+ if(noRecursion) break;
+ EnableWindow(GetDlgItem(hwndDlg,IDOK),TRUE);
+ { char szPhone[96],szArea[32],szNumber[64];
+ GetDlgItemTextA(hwndDlg,IDC_AREA,szArea,SIZEOF(szArea));
+ GetDlgItemTextA(hwndDlg,IDC_NUMBER,szNumber,SIZEOF(szNumber));
+ mir_snprintf(szPhone,SIZEOF(szPhone),"+%u (%s) %s",SendDlgItemMessage(hwndDlg,IDC_COUNTRY,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_COUNTRY,CB_GETCURSEL,0,0),0),szArea,szNumber);
+ noRecursion=1;
+ SetDlgItemTextA(hwndDlg,IDC_PHONE,szPhone);
+ noRecursion=0;
+ }
+ break;
+ case IDC_PHONE:
+ if(HIWORD(wParam)!=EN_UPDATE) break;
+ if(noRecursion) break;
+ noRecursion=1;
+ { char szText[256],*pText,*pArea,*pNumber;
+ int isValid=1;
+ GetDlgItemTextA(hwndDlg,IDC_PHONE,szText,SIZEOF(szText));
+ if(szText[0]!='+') isValid=0;
+ if(isValid) {
+ int i,country=strtol(szText+1,&pText,10);
+ if(pText-szText>4) isValid=0;
+ else for(i=SendDlgItemMessage(hwndDlg,IDC_COUNTRY,CB_GETCOUNT,0,0)-1;i>=0;i--)
+ if(country==SendDlgItemMessage(hwndDlg,IDC_COUNTRY,CB_GETITEMDATA,i,0))
+ {SendDlgItemMessage(hwndDlg,IDC_COUNTRY,CB_SETCURSEL,i,0); break;}
+ if(i<0) isValid=0;
+ }
+ if(isValid) {
+ pArea=pText+strcspn(pText,"0123456789");
+ pText=pArea+strspn(pArea,"0123456789");
+ if(*pText) {
+ *pText='\0';
+ pNumber=pText+1+strcspn(pText+1,"0123456789");
+ SetDlgItemTextA(hwndDlg,IDC_NUMBER,pNumber);
+ }
+ SetDlgItemTextA(hwndDlg,IDC_AREA,pArea);
+ }
+ if(!isValid) {
+ SendDlgItemMessage(hwndDlg,IDC_COUNTRY,CB_SETCURSEL,-1,0);
+ SetDlgItemTextA(hwndDlg,IDC_AREA,"");
+ SetDlgItemTextA(hwndDlg,IDC_NUMBER,"");
+ }
+ }
+ noRecursion=0;
+ EnableWindow(GetDlgItem(hwndDlg,IDOK),GetWindowTextLength(GetDlgItem(hwndDlg,IDC_PHONE)));
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static int IsOverEmail(HWND hwndDlg,TCHAR* szEmail,int cchEmail)
+{
+ RECT rc;
+ HWND hwndEmails;
+ TCHAR szText[256];
+ HDC hdc;
+ SIZE textSize;
+ LVHITTESTINFO hti;
+
+ hwndEmails=GetDlgItem(hwndDlg,IDC_EMAILS);
+ GetCursorPos(&hti.pt);
+ ScreenToClient(hwndEmails,&hti.pt);
+ GetClientRect(hwndEmails,&rc);
+ if(!PtInRect(&rc,hti.pt)) return 0;
+ if(ListView_SubItemHitTest(hwndEmails,&hti)==-1) return 0;
+ if(hti.iSubItem!=1) return 0;
+ if(!(hti.flags&LVHT_ONITEMLABEL)) return 0;
+ ListView_GetSubItemRect(hwndEmails,hti.iItem,1,LVIR_LABEL,&rc);
+ ListView_GetItemText(hwndEmails,hti.iItem,1,szText,SIZEOF(szText));
+ hdc=GetDC(hwndEmails);
+ SelectObject(hdc,hEmailFont);
+ GetTextExtentPoint32(hdc,szText,lstrlen(szText),&textSize);
+ ReleaseDC(hwndEmails,hdc);
+ if(hti.pt.x<rc.left+textSize.cx) {
+ if(szEmail && cchEmail) lstrcpyn(szEmail,szText,cchEmail);
+ return 1;
+ }
+ return 0;
+}
+
+#define M_REMAKELISTS (WM_USER+1)
+BOOL CALLBACK ContactDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ SetWindowLong(hwndDlg,GWL_USERDATA,lParam);
+ if(hEmailFont) DeleteObject(hEmailFont);
+ { LOGFONT lf;
+ hEmailFont=(HFONT)SendDlgItemMessage(hwndDlg,IDC_EMAILS,WM_GETFONT,0,0);
+ GetObject(hEmailFont,sizeof(lf),&lf);
+ lf.lfUnderline=1;
+ hEmailFont=CreateFontIndirect(&lf);
+ }
+ if(hHandCursor==NULL) {
+ if(IsWinVer2000Plus()) hHandCursor=LoadCursor(NULL,IDC_HAND);
+ else hHandCursor=LoadCursor(GetModuleHandle(NULL),MAKEINTRESOURCE(IDC_HYPERLINKHAND));
+ }
+ TranslateDialogDefault(hwndDlg);
+ { LVCOLUMN lvc;
+ RECT rc;
+ GetClientRect(GetDlgItem(hwndDlg,IDC_EMAILS),&rc);
+ rc.right-=GetSystemMetrics(SM_CXVSCROLL);
+ lvc.mask=LVCF_WIDTH;
+ lvc.cx=rc.right/4;
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_EMAILS),0,&lvc);
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_PHONES),0,&lvc);
+ lvc.cx=rc.right-rc.right/4-40;
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_EMAILS),1,&lvc);
+ lvc.cx=rc.right-rc.right/4-90;
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_PHONES),1,&lvc);
+ lvc.cx=50;
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_PHONES),2,&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),3,&lvc);
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_PHONES),4,&lvc);
+ }
+ return TRUE;
+ case M_REMAKELISTS:
+ { char *szProto;
+ LVITEM lvi;
+ int i;
+ char idstr[33];
+ TCHAR idstr2[33];
+ DBVARIANT dbv;
+ HANDLE hContact=(HANDLE)GetWindowLong(hwndDlg,GWL_USERDATA);
+
+ if (hContact != NULL) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if (szProto==NULL) break;
+ //e-mails
+ ListView_DeleteAllItems(GetDlgItem(hwndDlg,IDC_EMAILS));
+ lvi.mask=LVIF_TEXT|LVIF_PARAM;
+ lvi.lParam=(LPARAM)(-1);
+ lvi.iSubItem=0;
+ lvi.iItem=0;
+ for(i=-1;;i++) {
+ if(i==-1) {
+ if(DBGetContactSettingTString(hContact,szProto,"e-mail",&dbv))
+ continue;
+ lvi.pszText=TranslateT("Primary");
+ }
+ else {
+ wsprintfA(idstr, "e-mail%d", i );
+ if(DBGetContactSettingTString(hContact,szProto,idstr,&dbv))
+ break;
+ lvi.pszText=idstr2;
+ wsprintf(idstr2,_T("%d"),i+2);
+ }
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_EMAILS),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_EMAILS),lvi.iItem,1,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ lvi.iSubItem=0;
+ for(i=0;;i++) {
+ lvi.lParam=i;
+ wsprintfA(idstr,"Mye-mail%d",i);
+ if(DBGetContactSettingTString(hContact,"UserInfo",idstr,&dbv))
+ break;
+ lvi.pszText=idstr2;
+ wsprintf(idstr2,TranslateT("Custom %d"),i+1);
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_EMAILS),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_EMAILS),lvi.iItem,1,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ lvi.mask=LVIF_PARAM;
+ lvi.lParam=(LPARAM)(-2);
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_EMAILS),&lvi);
+ //phones
+ ListView_DeleteAllItems(GetDlgItem(hwndDlg,IDC_PHONES));
+ lvi.mask=LVIF_TEXT|LVIF_PARAM;
+ lvi.lParam=(LPARAM)(-1);
+ lvi.iSubItem=0;
+ lvi.iItem=0;
+ if(!DBGetContactSettingTString(hContact,szProto,"Phone",&dbv)) {
+ lvi.pszText=TranslateT("Primary");
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PHONES),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PHONES),lvi.iItem,1,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ if(!DBGetContactSettingTString(hContact,szProto,"Fax",&dbv)) {
+ lvi.pszText=TranslateT("Fax");
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PHONES),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PHONES),lvi.iItem,1,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ if(!DBGetContactSettingTString(hContact,szProto,"Cellular",&dbv)) {
+ lvi.pszText=TranslateT("Mobile");
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PHONES),&lvi);
+ if(lstrlenA(dbv.pszVal)>4 && !lstrcmpA(dbv.pszVal+lstrlenA(dbv.pszVal)-4," SMS")) {
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PHONES),lvi.iItem,2,_T("y"));
+ dbv.ptszVal[lstrlen(dbv.ptszVal)-4]='\0';
+ }
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PHONES),lvi.iItem,1,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ if(!DBGetContactSettingTString(hContact,szProto,"CompanyPhone",&dbv)) {
+ lvi.pszText=TranslateT("Work Phone");
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PHONES),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PHONES),lvi.iItem,1,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ if(!DBGetContactSettingTString(hContact,szProto,"CompanyFax",&dbv)) {
+ lvi.pszText=TranslateT("Work Fax");
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PHONES),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PHONES),lvi.iItem,1,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ lvi.iSubItem=0;
+ for(i=0;;i++) {
+ lvi.lParam=i;
+ wsprintfA(idstr,"MyPhone%d",i);
+ if(DBGetContactSettingTString(hContact,"UserInfo",idstr,&dbv))
+ break;
+ lvi.pszText=idstr2;
+ wsprintf(idstr2,TranslateT("Custom %d"),i+1);
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PHONES),&lvi);
+ if(lstrlen(dbv.ptszVal)>4 && !lstrcmp(dbv.ptszVal+lstrlen(dbv.ptszVal)-4,_T(" SMS"))) {
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PHONES),lvi.iItem,2,_T("y"));
+ dbv.ptszVal[lstrlen(dbv.ptszVal)-4]='\0';
+ }
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PHONES),lvi.iItem,1,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ lvi.mask=LVIF_PARAM;
+ lvi.lParam=(LPARAM)(-2);
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PHONES),&lvi);
+ }
+ break;
+ }
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_INFOCHANGED:
+ SendMessage(hwndDlg,M_REMAKELISTS,0,0);
+ break;
+ }
+ break;
+ case IDC_EMAILS:
+ case IDC_PHONES:
+ switch (((LPNMHDR)lParam)->code) {
+ case NM_CUSTOMDRAW:
+ { NMLVCUSTOMDRAW *nm=(NMLVCUSTOMDRAW*)lParam;
+ switch(nm->nmcd.dwDrawStage) {
+ case CDDS_PREPAINT:
+ case CDDS_ITEMPREPAINT:
+ 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 && nm->nmcd.hdr.idFrom==IDC_EMAILS) {
+ HFONT hoFont;
+ TCHAR szText[256];
+ ListView_GetItemText(nm->nmcd.hdr.hwndFrom,nm->nmcd.dwItemSpec,nm->iSubItem,szText,SIZEOF(szText));
+ hoFont=(HFONT)SelectObject(nm->nmcd.hdc,hEmailFont);
+ SetTextColor(nm->nmcd.hdc,RGB(0,0,255));
+ DrawText(nm->nmcd.hdc,szText,-1,&rc,DT_END_ELLIPSIS|DT_LEFT|DT_NOPREFIX|DT_SINGLELINE|DT_TOP);
+ SelectObject(nm->nmcd.hdc,hoFont);
+ SetWindowLong(hwndDlg,DWL_MSGRESULT,CDRF_SKIPDEFAULT);
+ return TRUE;
+ }
+ if(nm->nmcd.lItemlParam==(LPARAM)(-2) && nm->iSubItem-3==(nm->nmcd.hdr.idFrom==IDC_PHONES))
+ hIcon=LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_ADDCONTACT),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ else if(nm->iSubItem>1 && nm->nmcd.lItemlParam!=(LPARAM)(-1) && nm->nmcd.lItemlParam!=(LPARAM)(-2)) {
+ static int iconResources[3]={IDI_RENAME,IDI_DELETE};
+ if(nm->iSubItem==2 && nm->nmcd.hdr.idFrom==IDC_PHONES) {
+ TCHAR szText[2];
+ ListView_GetItemText(nm->nmcd.hdr.hwndFrom,nm->nmcd.dwItemSpec,nm->iSubItem,szText,SIZEOF(szText));
+ if(szText[0]) hIcon=LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_SMS),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ }
+ else hIcon=LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(iconResources[nm->iSubItem-3+(nm->nmcd.hdr.idFrom==IDC_EMAILS)]),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;
+ TCHAR szEmail[256];
+ HANDLE hContact=(HANDLE)GetWindowLong(hwndDlg,GWL_USERDATA);
+ char *szIdTemplate=nm->hdr.idFrom==IDC_PHONES?"MyPhone%d":"Mye-mail%d";
+ LVHITTESTINFO hti;
+
+ if(IsOverEmail(hwndDlg,szEmail,SIZEOF(szEmail))) {
+ TCHAR szExec[264];
+ lstrcpy(szExec, _T("mailto:"));
+ lstrcat(szExec,szEmail);
+ ShellExecute(hwndDlg,_T("open"),szExec,NULL,NULL,SW_SHOW);
+ break;
+ }
+ 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)) break;
+ if(lvi.lParam==(LPARAM)(-2)) {
+ if(hti.iSubItem-3==(nm->hdr.idFrom==IDC_PHONES)) {
+ //add
+ char szNewData[256]="",idstr[33];
+ int i;
+ DBVARIANT dbv;
+ if(IDOK!=DialogBoxParam(GetModuleHandle(NULL),MAKEINTRESOURCE(nm->hdr.idFrom==IDC_PHONES?IDD_ADDPHONE:IDD_ADDEMAIL),hwndDlg,nm->hdr.idFrom==IDC_PHONES?EditUserPhoneDlgProc:EditUserEmailDlgProc,(LPARAM)szNewData))
+ break;
+ for(i=0;;i++) {
+ wsprintfA(idstr,szIdTemplate,i);
+ if(DBGetContactSetting(hContact,"UserInfo",idstr,&dbv)) break;
+ DBFreeVariant(&dbv);
+ }
+ DBWriteContactSettingString(hContact,"UserInfo",idstr,szNewData);
+ SendMessage(hwndDlg,M_REMAKELISTS,0,0);
+ }
+ }
+ else {
+ if(hti.iSubItem-3==(nm->hdr.idFrom==IDC_PHONES)) {
+ //delete
+ int i;
+ char idstr[33];
+ DBVARIANT dbv;
+ for(i=lvi.lParam;;i++) {
+ wsprintfA(idstr,szIdTemplate,i+1);
+ if(DBGetContactSetting(hContact,"UserInfo",idstr,&dbv)) break;
+ wsprintfA(idstr,szIdTemplate,i);
+ DBWriteContactSettingString(hContact,"UserInfo",idstr,dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ wsprintfA(idstr,szIdTemplate,i);
+ DBDeleteContactSetting(hContact,"UserInfo",idstr);
+ SendMessage(hwndDlg,M_REMAKELISTS,0,0);
+ }
+ else if(hti.iSubItem-2==(nm->hdr.idFrom==IDC_PHONES)) {
+ //edit
+ char szText[256],idstr[33];
+ DBVARIANT dbv;
+ wsprintfA(idstr,szIdTemplate,lvi.lParam);
+ if(DBGetContactSetting(hContact,"UserInfo",idstr,&dbv)) break;
+ lstrcpynA(szText,dbv.pszVal,SIZEOF(szText));
+ DBFreeVariant(&dbv);
+ if(IDOK!=DialogBoxParam(GetModuleHandle(NULL),MAKEINTRESOURCE(nm->hdr.idFrom==IDC_PHONES?IDD_ADDPHONE:IDD_ADDEMAIL),hwndDlg,nm->hdr.idFrom==IDC_PHONES?EditUserPhoneDlgProc:EditUserEmailDlgProc,(LPARAM)szText))
+ break;
+ DBWriteContactSettingString(hContact,"UserInfo",idstr,szText);
+ SendMessage(hwndDlg,M_REMAKELISTS,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
+ }
+ if(IsOverEmail(hwndDlg,NULL,0)) {
+ SetCursor(hHandCursor);
+ SetWindowLong(hwndDlg,DWL_MSGRESULT,TRUE);
+ return TRUE;
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ SendMessage(GetParent(hwndDlg),msg,wParam,lParam);
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
diff --git a/miranda-wine/src/modules/userinfo/stdinfo.c b/miranda-wine/src/modules/userinfo/stdinfo.c
new file mode 100644
index 0000000..79928bd
--- /dev/null
+++ b/miranda-wine/src/modules/userinfo/stdinfo.c
@@ -0,0 +1,541 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+BOOL CALLBACK ContactDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+void Utf8Decode( char* str, wchar_t** ucs2 );
+
+
+#define SVS_NORMAL 0
+#define SVS_GENDER 1
+#define SVS_ZEROISUNSPEC 2
+#define SVS_IP 3
+#define SVS_COUNTRY 4
+#define SVS_MONTH 5
+#define SVS_SIGNED 6
+#define SVS_TIMEZONE 7
+#define SVS_ICQVERSION 8
+
+static void SetValue(HWND hwndDlg,int idCtrl,HANDLE hContact,char *szModule,char *szSetting,int special)
+{
+ DBVARIANT dbv;
+ char str[80],*pstr = NULL;
+ TCHAR* ptstr = NULL;
+ int unspecified=0;
+
+ dbv.type=DBVT_DELETED;
+ if(szModule==NULL) unspecified=1;
+ else unspecified=DBGetContactSettingW(hContact,szModule,szSetting,&dbv);
+ if(!unspecified) {
+ switch(dbv.type) {
+ case DBVT_BYTE:
+ if(special==SVS_GENDER) {
+ if(dbv.cVal=='M') ptstr=TranslateT("Male");
+ else if(dbv.cVal=='F') ptstr=TranslateT("Female");
+ else unspecified=1;
+ }
+ else if(special==SVS_MONTH) {
+ if(dbv.bVal>0 && dbv.bVal<=12) {
+ pstr=str;
+ GetLocaleInfoA(LOCALE_USER_DEFAULT,LOCALE_SABBREVMONTHNAME1-1+dbv.bVal,str,SIZEOF(str));
+ }
+ else unspecified=1;
+ }
+ else if(special==SVS_TIMEZONE) {
+ if(dbv.cVal==-100) unspecified=1;
+ else {
+ pstr=str;
+ sprintf(str,dbv.cVal?"GMT%+d:%02d":"GMT",-dbv.cVal/2,(dbv.cVal&1)*30);
+ }
+ }
+ else {
+ 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_COUNTRY) {
+ pstr=(char*)CallService(MS_UTILS_GETCOUNTRYBYNUMBER,dbv.wVal,0);
+ unspecified=pstr==NULL;
+ }
+ else if (special == SVS_ICQVERSION) {
+ if (dbv.wVal != 0) {
+ static char *szVersionDescr[] = {"", "ICQ 1.x", "ICQ 2.x", "Unknown", "ICQ98", "Unknown", "ICQ99 / licq", "ICQ2000", "ICQ2001-2003, Miranda or Trillian", "ICQ Lite"};
+ pstr = str;
+ wsprintfA(str, "%d: %s", dbv.wVal, dbv.wVal > 9 ? Translate("Unknown") : Translate(szVersionDescr[dbv.wVal]));
+ }
+ else unspecified = 1;
+ }
+ 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 pstr=_itoa(special==SVS_SIGNED?dbv.lVal:dbv.dVal,str,10);
+ break;
+ case DBVT_ASCIIZ:
+ unspecified=(special==SVS_ZEROISUNSPEC && dbv.pszVal[0]=='\0');
+ pstr=dbv.pszVal;
+ break;
+ case DBVT_UTF8:
+ unspecified=(special==SVS_ZEROISUNSPEC && dbv.pszVal[0]=='\0');
+ #if defined( _UNICODE )
+ if ( !unspecified )
+ { WCHAR* wszStr;
+ Utf8Decode( dbv.pszVal, &wszStr );
+ SetDlgItemTextW( hwndDlg, idCtrl, wszStr);
+ mir_free( wszStr );
+ goto LBL_Exit;
+ }
+ #endif
+ pstr=dbv.pszVal;
+ Utf8Decode( dbv.pszVal, NULL );
+ break;
+ default: pstr=str; lstrcpyA(str,"???"); break;
+ } }
+
+ if (unspecified)
+ SetDlgItemText(hwndDlg, idCtrl, TranslateT("<not specified>"));
+ else if ( ptstr != NULL )
+ SetDlgItemText(hwndDlg, idCtrl, ptstr);
+ else
+ SetDlgItemTextA(hwndDlg, idCtrl, pstr);
+
+#if defined( _UNICODE )
+LBL_Exit:
+#endif
+ EnableWindow(GetDlgItem(hwndDlg, idCtrl), !unspecified);
+ DBFreeVariant(&dbv);
+}
+
+static BOOL CALLBACK SummaryDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ return TRUE;
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ if (((LPNMHDR)lParam)->code == PSN_INFOCHANGED )
+ { char *szProto;
+ HANDLE hContact=(HANDLE)((LPPSHNOTIFY)lParam)->lParam;
+ if (hContact != NULL) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if (szProto==NULL) break;
+ SetValue(hwndDlg,IDC_NICK,hContact,szProto,"Nick",0);
+ SetValue(hwndDlg,IDC_FIRSTNAME,hContact,szProto,"FirstName",0);
+ SetValue(hwndDlg,IDC_LASTNAME,hContact,szProto,"LastName",0);
+ SetValue(hwndDlg,IDC_EMAIL,hContact,szProto,"e-mail",0);
+ SetValue(hwndDlg,IDC_AGE,hContact,szProto,"Age",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_GENDER,hContact,szProto,"Gender",SVS_GENDER);
+ SetValue(hwndDlg,IDC_DOBDAY,hContact,szProto,"BirthDay",0);
+ SetValue(hwndDlg,IDC_DOBMONTH,hContact,szProto,"BirthMonth",SVS_MONTH);
+ SetValue(hwndDlg,IDC_DOBYEAR,hContact,szProto,"BirthYear",0);
+ } }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ SendMessage(GetParent(hwndDlg),msg,wParam,lParam);
+ break;
+ case IDC_EMAIL:
+ if(IsWindowEnabled(GetDlgItem(hwndDlg,IDC_EMAIL))) {
+ char szExec[264],szEmail[256];
+ GetDlgItemTextA(hwndDlg,IDC_EMAIL,szEmail,SIZEOF(szEmail));
+ lstrcpyA(szExec,"mailto:");
+ lstrcatA(szExec,szEmail);
+ ShellExecuteA(hwndDlg,"open",szExec,NULL,NULL,SW_SHOW);
+ }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK LocationDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ SetWindowLong(hwndDlg,GWL_USERDATA,lParam);
+ TranslateDialogDefault(hwndDlg);
+ SetTimer(hwndDlg,1,1000,NULL);
+ SendMessage(hwndDlg,WM_TIMER,0,0);
+ return TRUE;
+ case WM_TIMER:
+ { char *szProto;
+ HANDLE hContact=(HANDLE)GetWindowLong(hwndDlg,GWL_USERDATA);
+ int timezone;
+ FILETIME ft;
+ LARGE_INTEGER lift;
+ char szTime[80];
+ SYSTEMTIME st;
+
+ if (hContact != NULL) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if (szProto==NULL) break;
+ timezone=DBGetContactSettingByte(hContact,szProto,"Timezone",256);
+ if(timezone==256 || (char)timezone==-100) {
+ EnableWindow(GetDlgItem(hwndDlg,IDC_LOCALTIME),FALSE);
+ SetDlgItemText(hwndDlg,IDC_LOCALTIME,TranslateT("<not specified>"));
+ }
+ else {
+ TIME_ZONE_INFORMATION tzi;
+
+ EnableWindow(GetDlgItem(hwndDlg,IDC_LOCALTIME),TRUE);
+ timezone=(char)timezone;
+ GetSystemTimeAsFileTime(&ft);
+ switch (GetTimeZoneInformation(&tzi)) {
+ case TIME_ZONE_ID_DAYLIGHT:
+ timezone+=tzi.DaylightBias/30;
+ break;
+ }
+ lift.QuadPart=*(__int64*)&ft;
+ lift.QuadPart-=(__int64)timezone*BIGI(30)*BIGI(60)*BIGI(10000000);
+ *(__int64*)&ft=lift.QuadPart;
+ FileTimeToSystemTime(&ft,&st);
+ GetTimeFormatA(LOCALE_USER_DEFAULT,0,&st,NULL,szTime,SIZEOF(szTime));
+ SetDlgItemTextA(hwndDlg,IDC_LOCALTIME,szTime);
+ }
+ }
+ break;
+ }
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ if (((LPNMHDR)lParam)->code == PSN_INFOCHANGED )
+ { char *szProto;
+ HANDLE hContact=(HANDLE)((LPPSHNOTIFY)lParam)->lParam;
+ if (hContact != NULL) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if (szProto==NULL) break;
+ SetValue(hwndDlg,IDC_STREET,hContact,szProto,"Street",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_CITY,hContact,szProto,"City",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_STATE,hContact,szProto,"State",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_ZIP,hContact,szProto,"ZIP",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_COUNTRY,hContact,szProto,"Country",SVS_COUNTRY);
+ SetValue(hwndDlg,IDC_LANGUAGE1,hContact,szProto,"Language1",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_LANGUAGE2,hContact,szProto,"Language2",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_LANGUAGE3,hContact,szProto,"Language3",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_TIMEZONE,hContact,szProto,"Timezone",SVS_TIMEZONE);
+ } }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ SendMessage(GetParent(hwndDlg),msg,wParam,lParam);
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK WorkDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ return TRUE;
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ if (((LPNMHDR)lParam)->code == PSN_INFOCHANGED)
+ { char *szProto;
+ HANDLE hContact=(HANDLE)((LPPSHNOTIFY)lParam)->lParam;
+ if (hContact != NULL) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if (szProto==NULL) break;
+ SetValue(hwndDlg,IDC_COMPANY,hContact,szProto,"Company",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_DEPARTMENT,hContact,szProto,"CompanyDepartment",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_POSITION,hContact,szProto,"CompanyPosition",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_STREET,hContact,szProto,"CompanyStreet",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_CITY,hContact,szProto,"CompanyCity",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_STATE,hContact,szProto,"CompanyState",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_ZIP,hContact,szProto,"CompanyZIP",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_COUNTRY,hContact,szProto,"CompanyCountry",SVS_COUNTRY);
+ SetValue(hwndDlg,IDC_WEBPAGE,hContact,szProto,"CompanyHomepage",SVS_ZEROISUNSPEC);
+ } }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ SendMessage(GetParent(hwndDlg),msg,wParam,lParam);
+ break;
+ case IDC_WEBPAGE:
+ if(IsWindowEnabled(GetDlgItem(hwndDlg,IDC_WEBPAGE))) {
+ char szPage[256];
+ GetDlgItemTextA(hwndDlg,IDC_WEBPAGE,szPage,SIZEOF(szPage));
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)szPage);
+ }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+// Resizes all columns in a listview (report style)
+// to make all text visible
+void ResizeColumns(HWND hwndLV)
+{
+ int nCol = 0; LVCOLUMN lvCol;
+ lvCol.mask = LVCF_WIDTH;
+ while(ListView_GetColumn(hwndLV, nCol++, &lvCol))
+ ListView_SetColumnWidth(hwndLV, nCol-1, LVSCW_AUTOSIZE);
+}
+
+static BOOL CALLBACK BackgroundDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ { LVCOLUMN lvc;
+ RECT rc;
+ GetClientRect(GetDlgItem(hwndDlg,IDC_PAST),&rc);
+ rc.right-=GetSystemMetrics(SM_CXVSCROLL);
+ lvc.mask=LVCF_WIDTH;
+ lvc.cx=rc.right/3;
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_PAST),0,&lvc);
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_INTERESTS),0,&lvc);
+ lvc.cx=rc.right-rc.right/3;
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_PAST),1,&lvc);
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_INTERESTS),1,&lvc);
+ }
+ ListView_SetExtendedListViewStyleEx(GetDlgItem(hwndDlg,IDC_PAST),LVS_EX_LABELTIP,LVS_EX_LABELTIP);
+ ListView_SetExtendedListViewStyleEx(GetDlgItem(hwndDlg,IDC_INTERESTS),LVS_EX_LABELTIP,LVS_EX_LABELTIP);
+ return TRUE;
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ if (((LPNMHDR)lParam)->code == PSN_INFOCHANGED)
+ { char *szProto;
+ LVITEM lvi;
+ int i;
+ char idstr[33];
+ DBVARIANT dbv,dbvText;
+ HANDLE hContact=(HANDLE)((LPPSHNOTIFY)lParam)->lParam;
+
+ if (hContact != NULL) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if (szProto==NULL) break;
+ SetValue(hwndDlg,IDC_WEBPAGE,hContact,szProto,"Homepage",SVS_ZEROISUNSPEC);
+
+ //past
+ ListView_DeleteAllItems(GetDlgItem(hwndDlg,IDC_PAST));
+ lvi.mask=LVIF_TEXT;
+ lvi.iSubItem=0;
+ lvi.iItem=0;
+ for(i=0;;i++) {
+ wsprintfA(idstr,"Past%d",i);
+ if(DBGetContactSettingTString(hContact,szProto,idstr,&dbv))
+ break;
+ wsprintfA(idstr,"Past%dText",i);
+ if(DBGetContactSettingTString(hContact,szProto,idstr,&dbvText))
+ {DBFreeVariant(&dbv); break;}
+ lvi.pszText=dbv.ptszVal;
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PAST),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PAST),lvi.iItem,1,dbvText.ptszVal);
+ DBFreeVariant(&dbvText);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+
+ for(i=0;;i++) {
+ wsprintfA(idstr,"Affiliation%d",i);
+ if(DBGetContactSettingTString(hContact,szProto,idstr,&dbv))
+ break;
+ wsprintfA(idstr,"Affiliation%dText",i);
+ if(DBGetContactSettingTString(hContact,szProto,idstr,&dbvText))
+ {DBFreeVariant(&dbv); break;}
+ lvi.pszText=dbv.ptszVal;
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PAST),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PAST),lvi.iItem,1,dbvText.ptszVal);
+ DBFreeVariant(&dbvText);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+
+ ResizeColumns(GetDlgItem(hwndDlg,IDC_PAST));
+
+ //interests
+ ListView_DeleteAllItems(GetDlgItem(hwndDlg,IDC_INTERESTS));
+ lvi.mask=LVIF_TEXT;
+ lvi.iSubItem=0;
+ lvi.iItem=0;
+ for(i=0;;i++) {
+ wsprintfA(idstr,"Interest%dCat",i);
+ if(DBGetContactSettingTString(hContact,szProto,idstr,&dbv))
+ break;
+ wsprintfA(idstr,"Interest%dText",i);
+ if(DBGetContactSettingTString(hContact,szProto,idstr,&dbvText))
+ {DBFreeVariant(&dbv); break;}
+ lvi.pszText=dbv.ptszVal;
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_INTERESTS),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_INTERESTS),lvi.iItem,1,dbvText.ptszVal);
+ DBFreeVariant(&dbvText);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ ResizeColumns(GetDlgItem(hwndDlg,IDC_INTERESTS));
+ } }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ SendMessage(GetParent(hwndDlg),msg,wParam,lParam);
+ break;
+ case IDC_WEBPAGE:
+ if(IsWindowEnabled(GetDlgItem(hwndDlg,IDC_WEBPAGE))) {
+ char szPage[256];
+ GetDlgItemTextA(hwndDlg,IDC_WEBPAGE,szPage,SIZEOF(szPage));
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)szPage);
+ }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK NotesDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ { DBVARIANT dbv;
+ if(!DBGetContactSetting((HANDLE)lParam,"UserInfo","MyNotes",&dbv)) {
+ SetDlgItemTextA(hwndDlg,IDC_MYNOTES,dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ }
+ SendDlgItemMessage(hwndDlg,IDC_MYNOTES,EM_LIMITTEXT,2048,0);
+ 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=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if (szProto==NULL) break;
+ SetValue(hwndDlg,IDC_ABOUT,hContact,szProto,"About",0);
+ }
+ break;
+ }
+ case PSN_APPLY:
+ { HANDLE hContact=(HANDLE)((LPPSHNOTIFY)lParam)->lParam;
+ if(GetWindowTextLength(GetDlgItem(hwndDlg,IDC_MYNOTES))) {
+ char text[2048];
+ GetDlgItemTextA(hwndDlg,IDC_MYNOTES,text,SIZEOF(text));
+ DBWriteContactSettingString(hContact,"UserInfo","MyNotes",text);
+ }
+ else DBDeleteContactSetting(hContact,"UserInfo","MyNotes");
+ break;
+ }
+ }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ if(wParam==MAKEWPARAM(IDC_MYNOTES,EN_CHANGE))
+ SendMessage(GetParent(hwndDlg),PSM_CHANGED,0,0);
+ else if(LOWORD(wParam)==IDCANCEL)
+ SendMessage(GetParent(hwndDlg),msg,wParam,lParam);
+ break;
+ }
+ return FALSE;
+}
+
+int DetailsInit(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp;
+
+ if ((HANDLE)lParam == NULL)
+ return 0;
+
+ if ( CallService(MS_PROTO_GETCONTACTBASEPROTO, lParam, 0) == 0 )
+ return 0;
+
+ odp.cbSize = sizeof(odp);
+ odp.hIcon = NULL;
+ odp.hInstance = GetModuleHandle(NULL);
+ odp.flags = 0;
+
+ odp.pfnDlgProc = SummaryDlgProc;
+ odp.position = -2100000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO_SUMMARY);
+ odp.pszTitle = "Summary";
+ CallService(MS_USERINFO_ADDPAGE, wParam, ( LPARAM )&odp);
+
+ odp.pfnDlgProc = ContactDlgProc;
+ odp.position = -1800000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO_CONTACT);
+ odp.pszTitle = "Contact";
+ CallService(MS_USERINFO_ADDPAGE, wParam, ( LPARAM )&odp );
+
+ odp.pfnDlgProc = LocationDlgProc;
+ odp.position = -1500000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO_LOCATION);
+ odp.pszTitle = "Location";
+ CallService(MS_USERINFO_ADDPAGE, wParam, ( LPARAM )&odp);
+
+ odp.pfnDlgProc = WorkDlgProc;
+ odp.position = -1200000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO_WORK);
+ odp.pszTitle = "Work";
+ CallService(MS_USERINFO_ADDPAGE, wParam, ( LPARAM )&odp);
+
+ odp.pfnDlgProc = BackgroundDlgProc;
+ odp.position = -900000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO_BACKGROUND);
+ odp.pszTitle = "Background";
+ CallService(MS_USERINFO_ADDPAGE, wParam, ( LPARAM )&odp );
+
+ odp.pfnDlgProc = NotesDlgProc;
+ odp.position = 0;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO_NOTES);
+ odp.pszTitle = "Notes";
+ CallService(MS_USERINFO_ADDPAGE, wParam, ( LPARAM )&odp);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/userinfo/userinfo.c b/miranda-wine/src/modules/userinfo/userinfo.c
new file mode 100644
index 0000000..1456c95
--- /dev/null
+++ b/miranda-wine/src/modules/userinfo/userinfo.c
@@ -0,0 +1,500 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#define UPDATEANIMFRAMES 20
+
+int DetailsInit(WPARAM wParam,LPARAM lParam);
+static BOOL CALLBACK DlgProcDetails(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+static HANDLE hWindowList=NULL;
+static HANDLE hDetailsInitEvent;
+
+struct DetailsPageInit {
+ int pageCount;
+ OPTIONSDIALOGPAGE *odp;
+};
+
+struct DetailsPageData {
+ DLGTEMPLATE *pTemplate;
+ HINSTANCE hInst;
+ DLGPROC dlgProc;
+ HWND hwnd;
+ HTREEITEM hItem;
+ int changed;
+};
+
+struct DetailsData {
+ HANDLE hContact;
+ HANDLE hProtoAckEvent;
+ HINSTANCE hInstIcmp;
+ HFONT hBoldFont;
+ int pageCount;
+ int currentPage;
+ struct DetailsPageData *opd;
+ RECT rcDisplay;
+ int updateAnimFrame;
+ TCHAR szUpdating[64];
+ int *infosUpdated;
+};
+
+static int PageSortProc(OPTIONSDIALOGPAGE *item1,OPTIONSDIALOGPAGE *item2)
+{
+ if(item2->position>item1->position) return -1;
+ if(item2->position<item1->position) return 1;
+ return 0;
+}
+
+static int ShowDetailsDialogCommand(WPARAM wParam,LPARAM lParam)
+{
+ HWND hwnd;
+ PROPSHEETHEADER psh;
+ struct DetailsPageInit opi;
+ int i;
+
+ if(hwnd=WindowList_Find(hWindowList,(HANDLE)wParam)) {
+ SetForegroundWindow(hwnd);
+ SetFocus(hwnd);
+ return 0;
+ }
+
+ opi.pageCount=0;
+ opi.odp=NULL;
+ NotifyEventHooks(hDetailsInitEvent,(WPARAM)&opi,wParam);
+ if(opi.pageCount==0) return 0;
+ qsort(opi.odp,opi.pageCount,sizeof(OPTIONSDIALOGPAGE),(int (*)(const void*,const void*))PageSortProc);
+
+ ZeroMemory(&psh,sizeof(psh));
+ psh.dwSize = sizeof(psh);
+ psh.dwFlags = PSH_PROPSHEETPAGE|PSH_NOAPPLYNOW;
+ psh.hwndParent = NULL;
+ psh.nPages = opi.pageCount;
+ psh.pStartPage = 0;
+ psh.pszCaption = (TCHAR*)wParam; //more abuses of structure: this is hContact
+ psh.ppsp = (PROPSHEETPAGE*)opi.odp; //blatent misuse of the structure, but what the hell
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_DETAILS),NULL,DlgProcDetails,(LPARAM)&psh);
+ for(i=0;i<opi.pageCount;i++) {
+ mir_free((char*)opi.odp[i].pszTitle);
+ if(opi.odp[i].pszGroup!=NULL) mir_free(opi.odp[i].pszGroup);
+ if((DWORD)opi.odp[i].pszTemplate&0xFFFF0000) mir_free((char*)opi.odp[i].pszTemplate);
+ }
+ mir_free(opi.odp);
+ return 0;
+}
+
+static int AddDetailsPage(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE *odp=(OPTIONSDIALOGPAGE*)lParam, *dst;
+ struct DetailsPageInit *opi=(struct DetailsPageInit*)wParam;
+
+ if(odp==NULL||opi==NULL) return 1;
+ if(odp->cbSize!=sizeof(OPTIONSDIALOGPAGE)) return 1;
+ opi->odp=(OPTIONSDIALOGPAGE*)mir_realloc(opi->odp,sizeof(OPTIONSDIALOGPAGE)*(opi->pageCount+1));
+ dst = opi->odp + opi->pageCount;
+ dst->cbSize = sizeof(OPTIONSDIALOGPAGE);
+ dst->hInstance = odp->hInstance;
+ dst->pfnDlgProc = odp->pfnDlgProc;
+ dst->position = odp->position;
+ if((DWORD)odp->pszTemplate&0xFFFF0000) dst->pszTemplate = mir_strdup(odp->pszTemplate);
+ else dst->pszTemplate = odp->pszTemplate;
+
+ #if defined(_UNICODE)
+ if ( odp->flags == ODPF_UNICODE )
+ dst->ptszTitle = (odp->ptszTitle==0) ? NULL : mir_wstrdup(odp->ptszTitle);
+ else
+ #endif
+ dst->ptszTitle = (odp->pszTitle==0) ? NULL : LangPackPcharToTchar(odp->pszTitle);
+
+ dst->pszGroup = NULL;
+ dst->groupPosition = odp->groupPosition;
+ dst->hGroupIcon = odp->hGroupIcon;
+ dst->hIcon = odp->hIcon;
+ opi->pageCount++;
+ return 0;
+}
+
+static int UserInfoContactDelete(WPARAM wParam,LPARAM lParam)
+{
+ HWND hwnd;
+ hwnd=WindowList_Find(hWindowList,(HANDLE)wParam);
+ if(hwnd!=NULL) DestroyWindow(hwnd);
+ return 0;
+}
+
+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
+ }
+ }
+}
+
+#define HM_PROTOACK (WM_USER+10)
+#define M_CHECKONLINE (WM_USER+11)
+static BOOL CALLBACK DlgProcDetails(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct DetailsData *dat =(struct DetailsData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ { PROPSHEETHEADER *psh=(PROPSHEETHEADER*)lParam;
+ TranslateDialogDefault(hwndDlg);
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_USERDETAILS)));
+ dat=(struct DetailsData*)mir_alloc(sizeof(struct DetailsData));
+ SetWindowLong(hwndDlg, GWL_USERDATA, (LONG)dat);
+ dat->hContact=(HANDLE)psh->pszCaption;
+ dat->hProtoAckEvent=HookEventMessage(ME_PROTO_ACK,hwndDlg,HM_PROTOACK);
+ dat->infosUpdated=NULL;
+ WindowList_Add(hWindowList,hwndDlg,dat->hContact);
+ {
+ TCHAR *name, oldTitle[256], newTitle[256];
+ if (dat->hContact == NULL)
+ name = TranslateT("Owner");
+ else
+ name = ( TCHAR* )CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)dat->hContact, GCDNF_TCHAR);
+
+ GetWindowText( hwndDlg, oldTitle, SIZEOF( oldTitle ));
+ mir_sntprintf( newTitle, SIZEOF(newTitle), oldTitle, name );
+ SetWindowText( hwndDlg, newTitle );
+ SetDlgItemText( hwndDlg, IDC_NAME, name );
+ }
+ { LOGFONT lf;
+ HFONT hNormalFont=(HFONT)SendDlgItemMessage(hwndDlg,IDC_NAME,WM_GETFONT,0,0);
+ GetObject(hNormalFont,sizeof(lf),&lf);
+ lf.lfWeight=FW_BOLD;
+ dat->hBoldFont=CreateFontIndirect(&lf);
+ SendDlgItemMessage(hwndDlg,IDC_NAME,WM_SETFONT,(WPARAM)dat->hBoldFont,0);
+ }
+ { OPTIONSDIALOGPAGE *odp;
+ int i;
+ TVINSERTSTRUCT tvis;
+ DBVARIANT dbv;
+
+ dat->currentPage=0;
+ if(DBGetContactSettingTString(NULL,"UserInfo","LastTab",&dbv))
+ dbv.type=DBVT_DELETED;
+ dat->pageCount=psh->nPages;
+ dat->opd=(struct DetailsPageData*)mir_alloc(sizeof(struct DetailsPageData)*dat->pageCount);
+ odp=(OPTIONSDIALOGPAGE*)psh->ppsp;
+
+ for(i=0;i<dat->pageCount;i++) {
+ dat->opd[i].pTemplate=(DLGTEMPLATE *)LockResource(LoadResource(odp[i].hInstance,FindResourceA(odp[i].hInstance,odp[i].pszTemplate,MAKEINTRESOURCEA(5))));
+ dat->opd[i].dlgProc=odp[i].pfnDlgProc;
+ dat->opd[i].hInst=odp[i].hInstance;
+ dat->opd[i].hwnd=NULL;
+ dat->opd[i].changed=0;
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_LAST;
+ tvis.item.mask = TVIF_TEXT | TVIF_PARAM;
+ tvis.item.lParam = (LPARAM) i;
+ tvis.item.pszText = odp[i].ptszTitle;
+ if(dbv.type!=DBVT_DELETED && !lstrcmp(tvis.item.pszText,dbv.ptszVal))
+ dat->currentPage=i;
+ dat->opd[i].hItem = TreeView_InsertItem(GetDlgItem(hwndDlg, IDC_PAGETREE), &tvis);
+ }
+ DBFreeVariant(&dbv);
+ }
+
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_TABS),&dat->rcDisplay);
+ TabCtrl_AdjustRect(GetDlgItem(hwndDlg,IDC_TABS),FALSE,&dat->rcDisplay);
+ { POINT pt={0,0};
+ ClientToScreen(hwndDlg,&pt);
+ OffsetRect(&dat->rcDisplay,-pt.x,-pt.y);
+ }
+ TreeView_Select(GetDlgItem(hwndDlg,IDC_PAGETREE), dat->opd[dat->currentPage].hItem, TVGN_CARET);
+ dat->opd[dat->currentPage].hwnd=CreateDialogIndirectParam(dat->opd[dat->currentPage].hInst,dat->opd[dat->currentPage].pTemplate,hwndDlg,dat->opd[dat->currentPage].dlgProc,(LPARAM)dat->hContact);
+ ThemeDialogBackground(dat->opd[dat->currentPage].hwnd);
+ SetWindowPos(dat->opd[dat->currentPage].hwnd, HWND_TOP, dat->rcDisplay.left, dat->rcDisplay.top, dat->rcDisplay.right - dat->rcDisplay.left, dat->rcDisplay.bottom - dat->rcDisplay.top, 0);
+ { PSHNOTIFY pshn;
+ pshn.hdr.code=PSN_INFOCHANGED;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)dat->hContact;
+ SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+ ShowWindow(dat->opd[dat->currentPage].hwnd,SW_SHOW);
+ dat->updateAnimFrame=0;
+ GetDlgItemText(hwndDlg,IDC_UPDATING,dat->szUpdating,SIZEOF(dat->szUpdating));
+ SendMessage(hwndDlg,M_CHECKONLINE,0,0);
+ if(!IsWindowEnabled(GetDlgItem(hwndDlg,IDC_UPDATE)))
+ ShowWindow(GetDlgItem(hwndDlg,IDC_UPDATING),SW_HIDE);
+ else {
+ EnableWindow(GetDlgItem(hwndDlg,IDC_UPDATE),FALSE);
+ SetTimer(hwndDlg,1,100,NULL);
+ }
+ CallContactService(dat->hContact,PSS_GETINFO,SGIF_ONOPEN,0);
+ return TRUE;
+ }
+ case WM_TIMER:
+ { TCHAR str[128];
+ mir_sntprintf(str,SIZEOF(str), _T("%.*s%s%.*s"),dat->updateAnimFrame%10,_T("........."),dat->szUpdating,dat->updateAnimFrame%10,_T("........."));
+ SetDlgItemText(hwndDlg,IDC_UPDATING,str);
+ if(++dat->updateAnimFrame==UPDATEANIMFRAMES) dat->updateAnimFrame=0;
+ break;
+ }
+ case WM_CTLCOLORSTATIC:
+ switch (GetDlgCtrlID((HWND)lParam)) {
+ case IDC_WHITERECT:
+ case IDC_LOGO:
+ SetBkColor((HDC)wParam,RGB(255,255,255));
+ return (BOOL)GetStockObject(WHITE_BRUSH);
+
+ case IDC_UPDATING:
+ {
+ COLORREF textCol,bgCol,newCol;
+ int ratio;
+ textCol=GetSysColor(COLOR_BTNTEXT);
+ bgCol=GetSysColor(COLOR_3DFACE);
+ ratio=abs(UPDATEANIMFRAMES/2-dat->updateAnimFrame)*510/UPDATEANIMFRAMES;
+ newCol=RGB(GetRValue(bgCol)+(GetRValue(textCol)-GetRValue(bgCol))*ratio/256,
+ GetGValue(bgCol)+(GetGValue(textCol)-GetGValue(bgCol))*ratio/256,
+ GetBValue(bgCol)+(GetBValue(textCol)-GetBValue(bgCol))*ratio/256);
+ SetTextColor((HDC)wParam,newCol);
+ SetBkColor((HDC)wParam,GetSysColor(COLOR_3DFACE));
+ return (BOOL)GetSysColorBrush(COLOR_3DFACE);
+ }
+ default:
+ SetBkMode((HDC)wParam,TRANSPARENT);
+ return (BOOL)GetStockObject(NULL_BRUSH);
+ }
+ break;
+ case PSM_CHANGED:
+ dat->opd[dat->currentPage].changed=1;
+ return TRUE;
+ case PSM_FORCECHANGED:
+ { PSHNOTIFY pshn;
+ int i;
+
+ pshn.hdr.code=PSN_INFOCHANGED;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)dat->hContact;
+ for(i=0;i<dat->pageCount;i++) {
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ if(dat->opd[i].hwnd!=NULL)
+ SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+ break;
+ }
+ case M_CHECKONLINE:
+ {
+ char *szProto;
+ if (dat->hContact != NULL) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ if(szProto==NULL) {EnableWindow(GetDlgItem(hwndDlg,IDC_UPDATE),FALSE); break;}
+ if(CallProtoService(szProto,PS_GETSTATUS,0,0)<ID_STATUS_ONLINE) EnableWindow(GetDlgItem(hwndDlg,IDC_UPDATE),FALSE);
+ else EnableWindow(GetDlgItem(hwndDlg,IDC_UPDATE),!IsWindowVisible(GetDlgItem(hwndDlg,IDC_UPDATING)));
+ }
+ break;
+ }
+ case HM_PROTOACK:
+ { ACKDATA *ack=(ACKDATA*)lParam;
+ int i;
+
+ if(ack->hContact==NULL && ack->type==ACKTYPE_STATUS) {
+ SendMessage(hwndDlg,M_CHECKONLINE,0,0);
+ break;
+ }
+ if(ack->hContact!=dat->hContact) break;
+ if(ack->type!=ACKTYPE_GETINFO) break;
+ SendMessage(hwndDlg,PSM_FORCECHANGED,0,0);
+ /* if they're not gonna send any more ACK's don't let that mean we should crash */
+ if (!ack->hProcess && !ack->lParam) {
+ ShowWindow(GetDlgItem(hwndDlg,IDC_UPDATING),SW_HIDE);
+ KillTimer(hwndDlg,1);
+ SendMessage(hwndDlg,M_CHECKONLINE,0,0);
+ break;
+ } //if
+ if(dat->infosUpdated==NULL) dat->infosUpdated=(int*)mir_calloc(sizeof(int)*(int)ack->hProcess);
+ if(ack->result==ACKRESULT_SUCCESS || ack->result==ACKRESULT_FAILED) dat->infosUpdated[ack->lParam]=1;
+ for(i=0;i<(int)ack->hProcess;i++)
+ if(dat->infosUpdated[i]==0) break;
+ if(i==(int)ack->hProcess) {
+ ShowWindow(GetDlgItem(hwndDlg,IDC_UPDATING),SW_HIDE);
+ KillTimer(hwndDlg,1);
+ SendMessage(hwndDlg,M_CHECKONLINE,0,0);
+ }
+ break;
+ }
+ case WM_NOTIFY:
+ switch(wParam) {
+ case IDC_PAGETREE:
+ switch(((LPNMHDR)lParam)->code) {
+ case TVN_SELCHANGING:
+ { PSHNOTIFY pshn;
+ if(dat->currentPage==-1 || dat->opd[dat->currentPage].hwnd==NULL) break;
+ pshn.hdr.code=PSN_KILLACTIVE;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)dat->hContact;
+ if(SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn)) {
+ SetWindowLong(hwndDlg,DWL_MSGRESULT,TRUE);
+ return TRUE;
+ }
+ break;
+ }
+ case TVN_SELCHANGED:
+ if(dat->currentPage!=-1 && dat->opd[dat->currentPage].hwnd!=NULL) {
+ ShowWindow(dat->opd[dat->currentPage].hwnd,SW_HIDE);
+ {
+ LPNMTREEVIEW pnmtv = (LPNMTREEVIEW) lParam;
+ TVITEM tvi = pnmtv->itemNew;
+ dat->currentPage=tvi.lParam;
+ }
+ if(dat->currentPage!=-1) {
+ if(dat->opd[dat->currentPage].hwnd==NULL) {
+ PSHNOTIFY pshn;
+ dat->opd[dat->currentPage].hwnd=CreateDialogIndirectParam(dat->opd[dat->currentPage].hInst,dat->opd[dat->currentPage].pTemplate,hwndDlg,dat->opd[dat->currentPage].dlgProc,(LPARAM)dat->hContact);
+ ThemeDialogBackground(dat->opd[dat->currentPage].hwnd);
+ SetWindowPos(dat->opd[dat->currentPage].hwnd, HWND_TOP, dat->rcDisplay.left, dat->rcDisplay.top, dat->rcDisplay.right - dat->rcDisplay.left, dat->rcDisplay.bottom - dat->rcDisplay.top, 0);
+ pshn.hdr.code=PSN_INFOCHANGED;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)dat->hContact;
+ SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+ ShowWindow(dat->opd[dat->currentPage].hwnd,SW_SHOW);
+ SetFocus(GetDlgItem(hwndDlg,IDC_PAGETREE));
+ }
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ { int i;
+ PSHNOTIFY pshn;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)dat->hContact;
+ pshn.hdr.code=PSN_RESET;
+ for(i=0;i<dat->pageCount;i++) {
+ if(dat->opd[i].hwnd==NULL || !dat->opd[i].changed) continue;
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ case IDOK:
+ { int i;
+ PSHNOTIFY pshn;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)dat->hContact;
+ if(dat->currentPage!=-1) {
+ pshn.hdr.code=PSN_KILLACTIVE;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ if(SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn))
+ break;
+ }
+
+ pshn.hdr.code=PSN_APPLY;
+ for(i=0;i<dat->pageCount;i++) {
+ if(dat->opd[i].hwnd==NULL || !dat->opd[i].changed) continue;
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ if(SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn)==PSNRET_INVALID_NOCHANGEPAGE) {
+ TreeView_Select(GetDlgItem(hwndDlg,IDC_PAGETREE), dat->opd[i].hItem, TVGN_CARET);
+ if(dat->currentPage!=-1) ShowWindow(dat->opd[dat->currentPage].hwnd,SW_HIDE);
+ dat->currentPage=i;
+ ShowWindow(dat->opd[dat->currentPage].hwnd,SW_SHOW);
+ return 0;
+ }
+ }
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ case IDC_UPDATE:
+ if(dat->infosUpdated!=NULL) {mir_free(dat->infosUpdated); dat->infosUpdated=NULL;}
+ if(dat->hContact != NULL) {
+ CallContactService(dat->hContact,PSS_GETINFO,0,0);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_UPDATE),FALSE);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_UPDATING),SW_SHOW);
+ SetTimer(hwndDlg,1,100,NULL);
+ }
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDOK,BN_CLICKED),(LPARAM)GetDlgItem(hwndDlg,IDOK));
+ break;
+ case WM_DESTROY:
+ {
+ TCHAR name[128];
+ TVITEM tvi;
+ tvi.mask = TVIF_TEXT;
+ tvi.hItem = dat->opd[dat->currentPage].hItem;
+ tvi.pszText=name;
+ tvi.cchTextMax=SIZEOF(name);
+ TreeView_GetItem(GetDlgItem(hwndDlg, IDC_PAGETREE), &tvi);
+ DBWriteContactSettingTString(NULL,"UserInfo","LastTab", name);
+ }
+ SendDlgItemMessage(hwndDlg,IDC_NAME,WM_SETFONT,SendDlgItemMessage(hwndDlg,IDC_WHITERECT,WM_GETFONT,0,0),0);
+ DeleteObject(dat->hBoldFont);
+ WindowList_Remove(hWindowList,hwndDlg);
+ UnhookEvent(dat->hProtoAckEvent);
+ { int i;
+ for(i=0;i<dat->pageCount;i++)
+ if(dat->opd[i].hwnd!=NULL) DestroyWindow(dat->opd[i].hwnd);
+ }
+ if(dat->infosUpdated!=NULL) mir_free(dat->infosUpdated);
+ mir_free(dat->opd);
+ mir_free(dat);
+ break;
+ }
+ return FALSE;
+}
+
+int ShutdownUserInfo(WPARAM wParam,LPARAM lParam)
+{
+ WindowList_BroadcastAsync(hWindowList,WM_DESTROY,0,0);
+ return 0;
+}
+
+int LoadUserInfoModule(void)
+{
+ CLISTMENUITEM mi;
+
+ CreateServiceFunction(MS_USERINFO_SHOWDIALOG,ShowDetailsDialogCommand);
+ hDetailsInitEvent=CreateHookableEvent(ME_USERINFO_INITIALISE);
+ HookEvent(ME_USERINFO_INITIALISE,DetailsInit);
+ HookEvent(ME_DB_CONTACT_DELETED,UserInfoContactDelete);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN,ShutdownUserInfo);
+ CreateServiceFunction(MS_USERINFO_ADDPAGE,AddDetailsPage);
+ ZeroMemory(&mi,sizeof(mi));
+ mi.cbSize=sizeof(mi);
+ mi.position=1000050000;
+ mi.flags=0;
+ mi.hIcon=LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_USERDETAILS));
+ mi.pszContactOwner=NULL;
+ mi.pszName=Translate("User &Details");
+ mi.pszService=MS_USERINFO_SHOWDIALOG;
+ CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi);
+ mi.position=500050000;
+ mi.pszName=Translate("View/Change My &Details...");
+ CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi);
+ hWindowList=(HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST,0,0);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/useronline/useronline.c b/miranda-wine/src/modules/useronline/useronline.c
new file mode 100644
index 0000000..08652f6
--- /dev/null
+++ b/miranda-wine/src/modules/useronline/useronline.c
@@ -0,0 +1,96 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+static int uniqueEventId=0;
+
+static int UserOnlineSettingChanged(WPARAM wParam,LPARAM lParam)
+{
+ DBCONTACTWRITESETTING *cws=(DBCONTACTWRITESETTING*)lParam;
+ int newStatus,oldStatus;
+
+ if((HANDLE)wParam==NULL || strcmp(cws->szSetting,"Status")) return 0;
+ newStatus=cws->value.wVal;
+ oldStatus=DBGetContactSettingWord((HANDLE)wParam,"UserOnline","OldStatus",ID_STATUS_OFFLINE);
+ DBWriteContactSettingWord((HANDLE)wParam,"UserOnline","OldStatus",(WORD)newStatus);
+ if(CallService(MS_IGNORE_ISIGNORED,wParam,IGNOREEVENT_USERONLINE)) return 0;
+ if(DBGetContactSettingByte((HANDLE)wParam,"CList","Hidden",0)) return 0;
+ if((newStatus==ID_STATUS_ONLINE || newStatus==ID_STATUS_FREECHAT) &&
+ oldStatus!=ID_STATUS_ONLINE && oldStatus!=ID_STATUS_FREECHAT) {
+ {
+ DWORD ticked = db_dword_get(NULL, "UserOnline", cws->szModule, GetTickCount());
+ // only play the sound (or show event) if this event happens at least 10 secs after the proto went from offline
+ if ( GetTickCount() - ticked > (1000*10) ) {
+ CLISTEVENT cle;
+ char tooltip[256];
+
+ ZeroMemory(&cle,sizeof(cle));
+ cle.cbSize=sizeof(cle);
+ cle.flags=CLEF_ONLYAFEW;
+ cle.hContact=(HANDLE)wParam;
+ cle.hDbEvent=(HANDLE)(uniqueEventId++);
+ cle.hIcon=LoadSkinnedIcon(SKINICON_OTHER_USERONLINE);
+ cle.pszService="UserOnline/Description";
+ mir_snprintf(tooltip,SIZEOF(tooltip),Translate("%s is Online"),(char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,wParam,0));
+ cle.pszTooltip=tooltip;
+ CallService(MS_CLIST_ADDEVENT,0,(LPARAM)&cle);
+
+ SkinPlaySound("UserOnline");
+ }
+ }
+ }
+ return 0;
+}
+
+static int UserOnlineAck(WPARAM wParam, LPARAM lParam)
+{
+ ACKDATA * ack = (ACKDATA*) lParam;
+ if ( ack != 0 && ack->szModule && ack->type == ACKTYPE_STATUS && ack->result == ACKRESULT_SUCCESS && ack->hProcess == (HANDLE)ID_STATUS_OFFLINE) {
+ // if going from offline to any other mode, remember when it happened.
+ db_dword_set(NULL, "UserOnline", ack->szModule, GetTickCount());
+ }
+ return 0;
+}
+
+static int UserOnlineModulesLoaded(WPARAM wParam, LPARAM lParam)
+{
+ int protoCount=0, j;
+ PROTOCOLDESCRIPTOR **protos = 0;
+
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM)&protoCount, (LPARAM)&protos);
+ // reset the counter
+ for (j=0 ; j < protoCount; j++)
+ if (protos[j]->type == PROTOTYPE_PROTOCOL) {
+ db_dword_set(NULL, "UserOnline", protos[j]->szName, GetTickCount());
+ }
+ return 0;
+}
+
+int LoadUserOnlineModule(void)
+{
+ HookEvent(ME_DB_CONTACT_SETTINGCHANGED,UserOnlineSettingChanged);
+ HookEvent(ME_PROTO_ACK, UserOnlineAck);
+ HookEvent(ME_SYSTEM_MODULESLOADED, UserOnlineModulesLoaded);
+ SkinAddNewSoundEx("UserOnline",Translate("Alerts"),Translate("Online"));
+ return 0;
+}
diff --git a/miranda-wine/src/modules/utils/bmpfilter.c b/miranda-wine/src/modules/utils/bmpfilter.c
new file mode 100644
index 0000000..eb20d33
--- /dev/null
+++ b/miranda-wine/src/modules/utils/bmpfilter.c
@@ -0,0 +1,180 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include <ocidl.h>
+#include <olectl.h>
+
+#include "m_png.h"
+
+static int BmpFilterLoadBitmap(WPARAM wParam,LPARAM lParam)
+{
+ IPicture *pic;
+ HBITMAP hBmp,hBmpCopy;
+ HBITMAP hOldBitmap, hOldBitmap2;
+ BITMAP bmpInfo;
+ WCHAR pszwFilename[MAX_PATH];
+ HDC hdc,hdcMem1,hdcMem2;
+ short picType;
+ const char *szFile=(const char *)lParam;
+ char szFilename[MAX_PATH];
+ int filenameLen;
+
+ if (!CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM)szFile, (LPARAM)szFilename))
+ mir_snprintf(szFilename, SIZEOF(szFilename), "%s", szFile);
+ filenameLen=lstrlenA(szFilename);
+ if(filenameLen>4) {
+ char* pszExt = szFilename+filenameLen-4;
+ if ( !lstrcmpiA( pszExt,".bmp" ) || !lstrcmpiA( pszExt, ".rle" )) {
+ //LoadImage can do this much faster
+ return (int)LoadImageA( GetModuleHandle(NULL), szFilename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
+ }
+
+ if ( !lstrcmpiA( pszExt, ".png" )) {
+ HANDLE hFile, hMap = NULL;
+ BYTE* ppMap = NULL;
+ long cbFileSize = 0;
+ BITMAPINFOHEADER* pDib;
+ BYTE* pDibBits;
+
+ if ( !ServiceExists( MS_PNG2DIB )) {
+ MessageBox( NULL, TranslateT( "You need the png2dib plugin v. 0.1.3.x or later to process PNG images" ), TranslateT( "Error" ), MB_OK );
+ return (int)(HBITMAP)NULL;
+ }
+
+ if (( hFile = CreateFileA( szFilename, 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 ) {
+ PNG2DIB param;
+ param.pSource = ppMap;
+ param.cbSourceSize = cbFileSize;
+ param.pResult = &pDib;
+ if ( CallService( MS_PNG2DIB, 0, ( LPARAM )&param ))
+ pDibBits = ( BYTE* )( pDib+1 );
+ else
+ cbFileSize = 0;
+ }
+
+ if ( ppMap != NULL ) UnmapViewOfFile( ppMap );
+ if ( hMap != NULL ) CloseHandle( hMap );
+ if ( hFile != NULL ) CloseHandle( hFile );
+
+ if ( cbFileSize == 0 )
+ return (int)(HBITMAP)NULL;
+
+ { HDC sDC = GetDC( NULL );
+ HBITMAP hBitmap = CreateDIBitmap( sDC, pDib, CBM_INIT, pDibBits, ( BITMAPINFO* )pDib, DIB_PAL_COLORS );
+ SelectObject( sDC, hBitmap );
+ ReleaseDC( NULL, sDC );
+ GlobalFree( pDib );
+ return (int)hBitmap;
+ } } }
+
+ OleInitialize(NULL);
+ MultiByteToWideChar(CP_ACP,0,szFilename,-1,pszwFilename,MAX_PATH);
+ if(S_OK!=OleLoadPicturePath(pszwFilename,NULL,0,0,&IID_IPicture,(PVOID*)&pic)) {
+ OleUninitialize();
+ return (int)(HBITMAP)NULL;
+ }
+ pic->lpVtbl->get_Type(pic,&picType);
+ if(picType!=PICTYPE_BITMAP) {
+ pic->lpVtbl->Release(pic);
+ OleUninitialize();
+ return (int)(HBITMAP)NULL;
+ }
+ pic->lpVtbl->get_Handle(pic,(OLE_HANDLE*)&hBmp);
+ GetObject(hBmp,sizeof(bmpInfo),&bmpInfo);
+
+ //need to copy bitmap so we can free the IPicture
+ hdc=GetDC(NULL);
+ hdcMem1=CreateCompatibleDC(hdc);
+ hdcMem2=CreateCompatibleDC(hdc);
+ hOldBitmap=SelectObject(hdcMem1,hBmp);
+ hBmpCopy=CreateCompatibleBitmap(hdcMem1,bmpInfo.bmWidth,bmpInfo.bmHeight);
+ hOldBitmap2=SelectObject(hdcMem2,hBmpCopy);
+ BitBlt(hdcMem2,0,0,bmpInfo.bmWidth,bmpInfo.bmHeight,hdcMem1,0,0,SRCCOPY);
+ SelectObject(hdcMem1,hOldBitmap);
+ SelectObject(hdcMem2,hOldBitmap2);
+ DeleteDC(hdcMem2);
+ DeleteDC(hdcMem1);
+ ReleaseDC(NULL,hdc);
+
+ DeleteObject(hBmp);
+ pic->lpVtbl->Release(pic);
+ OleUninitialize();
+ return (int)hBmpCopy;
+}
+
+static int BmpFilterGetStrings(WPARAM wParam,LPARAM lParam)
+{
+ int bytesLeft=wParam;
+ char *filter=(char*)lParam,*pfilter;
+
+ lstrcpynA(filter,Translate("All Bitmaps"),bytesLeft); bytesLeft-=lstrlenA(filter);
+ strncat(filter," (*.bmp;*.jpg;*.gif;*.png)",bytesLeft);
+ pfilter=filter+lstrlenA(filter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpynA(pfilter,"*.BMP;*.RLE;*.JPG;*.JPEG;*.GIF;*.PNG",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpynA(pfilter,Translate("Windows Bitmaps"),bytesLeft); bytesLeft-=lstrlenA(pfilter);
+ strncat(pfilter," (*.bmp;*.rle)",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpynA(pfilter,"*.BMP;*.RLE",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpynA(pfilter,Translate("JPEG Bitmaps"),bytesLeft); bytesLeft-=lstrlenA(pfilter);
+ strncat(pfilter," (*.jpg;*.jpeg)",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpynA(pfilter,"*.JPG;*.JPEG",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpynA(pfilter,Translate("GIF Bitmaps"),bytesLeft); bytesLeft-=lstrlenA(pfilter);
+ strncat(pfilter," (*.gif)",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpynA(pfilter,"*.GIF",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpynA(pfilter,Translate("PNG Bitmaps"),bytesLeft); bytesLeft-=lstrlenA(pfilter);
+ strncat(pfilter," (*.png)",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpynA(pfilter,"*.PNG",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpynA(pfilter,Translate("All Files"),bytesLeft); bytesLeft-=lstrlenA(pfilter);
+ strncat(pfilter," (*)",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpynA(pfilter,"*",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ if(bytesLeft) *pfilter='\0';
+ return 0;
+}
+
+int InitBitmapFilter(void)
+{
+ CreateServiceFunction(MS_UTILS_LOADBITMAP,BmpFilterLoadBitmap);
+ CreateServiceFunction(MS_UTILS_GETBITMAPFILTERSTRINGS,BmpFilterGetStrings);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/utils/colourpicker.c b/miranda-wine/src/modules/utils/colourpicker.c
new file mode 100644
index 0000000..4192e62
--- /dev/null
+++ b/miranda-wine/src/modules/utils/colourpicker.c
@@ -0,0 +1,107 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+static LRESULT CALLBACK ColourPickerWndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ switch(message) {
+ case WM_CREATE:
+ SetWindowLong(hwnd,0,0);
+ SetWindowLong(hwnd,sizeof(COLORREF),0);
+ break;
+ case CPM_SETDEFAULTCOLOUR:
+ SetWindowLong(hwnd,sizeof(COLORREF),lParam);
+ break;
+ case CPM_GETDEFAULTCOLOUR:
+ return GetWindowLong(hwnd,sizeof(COLORREF));
+ case CPM_SETCOLOUR:
+ SetWindowLong(hwnd,0,lParam);
+ InvalidateRect(hwnd,NULL,FALSE);
+ break;
+ case CPM_GETCOLOUR:
+ return GetWindowLong(hwnd,0);
+ case WM_LBUTTONUP:
+ {
+ CHOOSECOLOR cc={0};
+ COLORREF custColours[16]={0};
+ custColours[0]=GetWindowLong(hwnd,sizeof(COLORREF));
+ cc.lStructSize=sizeof(CHOOSECOLOR);
+ cc.hwndOwner=hwnd;
+ cc.hInstance=(HWND)GetModuleHandle(NULL);
+ cc.rgbResult=GetWindowLong(hwnd,0);
+ cc.lpCustColors=custColours;
+ cc.Flags=CC_ANYCOLOR|CC_FULLOPEN|CC_RGBINIT;
+ if(ChooseColor(&cc)) {
+ SetWindowLong(hwnd,0,cc.rgbResult);
+ SendMessage(GetParent(hwnd),WM_COMMAND,MAKEWPARAM(GetDlgCtrlID(hwnd),CPN_COLOURCHANGED),(LPARAM)hwnd);
+ InvalidateRect(hwnd,NULL,FALSE);
+ }
+ break;
+ }
+ case WM_ENABLE:
+ InvalidateRect(hwnd,NULL,FALSE);
+ break;
+ case WM_NCPAINT:
+ case WM_PAINT:
+ { PAINTSTRUCT ps;
+ HDC hdc1;
+ RECT rc;
+ HBRUSH hBrush;
+
+ hdc1=BeginPaint(hwnd,&ps);
+ GetClientRect(hwnd,&rc);
+ DrawEdge(hdc1,&rc,EDGE_ETCHED,BF_RECT);
+ InflateRect(&rc,-2,-2);
+ if(IsWindowEnabled(hwnd))
+ hBrush=CreateSolidBrush(GetWindowLong(hwnd,0));
+ else
+ hBrush=CreateHatchBrush(HS_BDIAGONAL,GetSysColor(COLOR_GRAYTEXT));
+ SetBkColor(hdc1,GetSysColor(COLOR_BTNFACE));
+ FillRect(hdc1,&rc,hBrush);
+ DeleteObject(hBrush);
+ EndPaint(hwnd,&ps);
+ break;
+ }
+ case WM_DESTROY:
+ break;
+ }
+ return DefWindowProc(hwnd,message,wParam,lParam);
+}
+
+int InitColourPicker(void)
+{
+ WNDCLASS wcl;
+
+ wcl.lpfnWndProc=ColourPickerWndProc;
+ wcl.cbClsExtra=0;
+ wcl.cbWndExtra=sizeof(COLORREF)*2;
+ wcl.hInstance=GetModuleHandle(NULL);
+ wcl.hCursor=NULL;
+ wcl.lpszClassName=WNDCLASS_COLOURPICKER;
+ wcl.hbrBackground=(HBRUSH)(COLOR_BTNFACE+1);
+ wcl.hIcon=NULL;
+ wcl.lpszMenuName=NULL;
+ wcl.style=CS_HREDRAW|CS_VREDRAW|CS_GLOBALCLASS;
+ RegisterClass(&wcl);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/utils/hyperlink.c b/miranda-wine/src/modules/utils/hyperlink.c
new file mode 100644
index 0000000..affc1ff
--- /dev/null
+++ b/miranda-wine/src/modules/utils/hyperlink.c
@@ -0,0 +1,183 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+static HCURSOR hHandCursor;
+
+struct HyperlinkWndData {
+ HFONT hFont;
+ HFONT hSetFont;
+ RECT rcText;
+ DWORD enableColor;
+ DWORD disableColor;
+};
+#define IM_MEASURETEXT (WM_USER+1)
+#define HLK_INVALIDATE (WM_USER+2)
+static LRESULT CALLBACK HyperlinkWndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ struct HyperlinkWndData *dat;
+ dat=(struct HyperlinkWndData*)GetWindowLong(hwnd,0);
+ switch(message) {
+ case WM_CREATE:
+ dat=(struct HyperlinkWndData*)mir_alloc(sizeof(struct HyperlinkWndData));
+ SetWindowLong(hwnd,0,(LONG)dat);
+ dat->hFont=NULL;
+ dat->hSetFont=NULL;
+ dat->enableColor=GetSysColor(COLOR_HOTLIGHT);
+ if(dat->enableColor==0 && GetLastError()!=ERROR_SUCCESS) dat->enableColor=RGB(0,0,255);
+ dat->disableColor=GetSysColor(COLOR_GRAYTEXT);
+ SendMessage(hwnd,IM_MEASURETEXT,0,0);
+ break;
+ case WM_LBUTTONDOWN:
+ { POINT pt;
+ pt.x=(short)LOWORD(lParam); pt.y=(short)HIWORD(lParam);
+ if(PtInRect(&dat->rcText,pt))
+ SendMessage(GetParent(hwnd),WM_COMMAND,MAKEWPARAM(GetDlgCtrlID(hwnd),STN_CLICKED),(LPARAM)hwnd);
+ break;
+ }
+ case WM_SETFONT:
+ { LOGFONT lf;
+ dat->hSetFont=(HFONT)wParam;
+ GetObject(dat->hSetFont,sizeof(lf),&lf);
+ lf.lfUnderline=1;
+ dat->hFont=CreateFontIndirect(&lf);
+ if(LOWORD(lParam)) SendMessage(hwnd,HLK_INVALIDATE,0,0);
+ SendMessage(hwnd,IM_MEASURETEXT,0,0);
+ break;
+ }
+ case WM_ERASEBKGND: return(1); break;
+ case HLK_INVALIDATE: // invalidate
+ {
+ RECT rcWnd;
+ POINT pt;
+ GetWindowRect(hwnd,&rcWnd);
+ pt.x = rcWnd.left;
+ pt.y = rcWnd.top;
+ ScreenToClient(GetParent(hwnd),&pt);
+ rcWnd.right = pt.x + (rcWnd.right-rcWnd.left);
+ rcWnd.bottom = pt.y + (rcWnd.bottom-rcWnd.top);
+ rcWnd.left = pt.x;
+ rcWnd.top = pt.y;
+
+ InvalidateRect(GetParent(hwnd),&rcWnd,TRUE);
+ break;
+ }
+ case WM_GETFONT:
+ return (LRESULT)dat->hSetFont;
+ case IM_MEASURETEXT:
+ { char text[256];
+ GetWindowTextA(hwnd,text,SIZEOF(text));
+ lParam=(LPARAM)text;
+ //fall thru
+ case WM_SETTEXT:
+ { HFONT hoFont;
+ SIZE textSize;
+ RECT rc;
+
+ HDC hdc1=GetDC(hwnd);
+ if(dat->hFont!=NULL) hoFont=(HFONT)SelectObject(hdc1,dat->hFont);
+ GetTextExtentPoint32(hdc1,(const TCHAR*)lParam,lstrlen((const TCHAR*)lParam),&textSize);
+ dat->rcText.top=0; dat->rcText.bottom=dat->rcText.top+textSize.cy;
+ GetClientRect(hwnd,&rc);
+ if(GetWindowLong(hwnd,GWL_STYLE)&SS_CENTER) dat->rcText.left=(rc.right-textSize.cx)/2;
+ else if(GetWindowLong(hwnd,GWL_STYLE)&SS_RIGHT) dat->rcText.left=rc.right-textSize.cx;
+ else dat->rcText.left=0;
+ dat->rcText.right=dat->rcText.left+textSize.cx;
+ if(dat->hFont!=NULL) SelectObject(hdc1,hoFont);
+ ReleaseDC(hwnd,hdc1);
+ SendMessage(hwnd,HLK_INVALIDATE,0,0);
+ break;
+ }}
+ case WM_SETCURSOR:
+ { POINT pt;
+ GetCursorPos(&pt);
+ ScreenToClient(hwnd,&pt);
+ if(PtInRect(&dat->rcText,pt)) SetCursor(hHandCursor);
+ else SetCursor(LoadCursor(NULL,IDC_ARROW));
+ return TRUE;
+ }
+ case HLK_SETENABLECOLOUR:
+ if ((DWORD)wParam) dat->enableColor = (DWORD)wParam;
+ break;
+ case HLK_SETDISABLECOLOUR:
+ if ((DWORD)wParam) dat->disableColor = (DWORD)wParam;
+ break;
+ case WM_NCPAINT:
+ case WM_PAINT:
+ {
+ HFONT hoFont;
+ RECT rc;
+ TCHAR text[256];
+ int alignFlag;
+ DWORD textColour;
+
+ PAINTSTRUCT ps;
+ HDC hdc1=BeginPaint(hwnd,&ps);
+ if(IsWindowEnabled(hwnd)) {
+ hoFont=(HFONT)SelectObject(hdc1,dat->hFont);
+ textColour=dat->enableColor;
+ }
+ else {
+ hoFont=(HFONT)SelectObject(hdc1,dat->hSetFont);
+ textColour=dat->disableColor;
+ }
+ SetTextColor(hdc1,textColour);
+ SetBkMode(hdc1,TRANSPARENT);
+ if(GetWindowLong(hwnd,GWL_STYLE)&SS_CENTER) alignFlag=DT_CENTER;
+ else if(GetWindowLong(hwnd,GWL_STYLE)&SS_RIGHT) alignFlag=DT_RIGHT;
+ else alignFlag=DT_LEFT;
+ GetClientRect(hwnd,&rc);
+ GetWindowText(hwnd,text,SIZEOF(text));
+ DrawText(hdc1,text,-1,&rc,alignFlag|DT_NOPREFIX|DT_SINGLELINE|DT_TOP);
+ SelectObject(hdc1,hoFont);
+ EndPaint(hwnd,&ps);
+ break;
+ }
+ case WM_DESTROY:
+ if(dat->hFont!=NULL) DeleteObject(dat->hFont);
+ mir_free(dat); dat=NULL;
+ SetWindowLong(hwnd,0,(LONG)dat);
+ break;
+ }
+ return DefWindowProc(hwnd,message,wParam,lParam);
+}
+
+int InitHyperlink(void)
+{
+ WNDCLASS wcl;
+
+ if(IsWinVer2000Plus()) hHandCursor=LoadCursor(NULL,IDC_HAND);
+ else hHandCursor=LoadCursor(GetModuleHandle(NULL),MAKEINTRESOURCE(IDC_HYPERLINKHAND));
+ wcl.lpfnWndProc=HyperlinkWndProc;
+ wcl.cbClsExtra=0;
+ wcl.cbWndExtra=sizeof(void*);
+ wcl.hInstance=GetModuleHandle(NULL);
+ wcl.hCursor=NULL;
+ wcl.lpszClassName=WNDCLASS_HYPERLINK;
+ wcl.hbrBackground=NULL;
+ wcl.hIcon=NULL;
+ wcl.lpszMenuName=NULL;
+ wcl.style=CS_HREDRAW|CS_VREDRAW|CS_GLOBALCLASS|CS_PARENTDC;
+ RegisterClass(&wcl);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/utils/openurl.c b/miranda-wine/src/modules/utils/openurl.c
new file mode 100644
index 0000000..02c415c
--- /dev/null
+++ b/miranda-wine/src/modules/utils/openurl.c
@@ -0,0 +1,228 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+#include <ctype.h>
+
+#define DDEMESSAGETIMEOUT 1000
+#define WNDCLASS_DDEMSGWINDOW _T("MirandaDdeMsgWindow")
+
+struct DdeMsgWindowData {
+ int fAcked,fData;
+ HWND hwndDde;
+};
+
+static LRESULT CALLBACK DdeMessageWindow(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ struct DdeMsgWindowData *dat;
+ ATOM hSzItem;
+ HGLOBAL hDdeData;
+
+ dat=(struct DdeMsgWindowData*)GetWindowLong(hwnd,0);
+ switch(msg) {
+ case WM_DDE_ACK:
+ dat->fAcked=1;
+ dat->hwndDde=(HWND)wParam;
+ return 0;
+ case WM_DDE_DATA:
+ UnpackDDElParam(msg,lParam,(PUINT)&hDdeData,(PUINT)&hSzItem);
+ dat->fData=1;
+ if(hDdeData) {
+ DDEDATA *data;
+ int release;
+ data=(DDEDATA*)GlobalLock(hDdeData);
+ if(data->fAckReq) {
+ DDEACK ack={0};
+ PostMessage((HWND)wParam,WM_DDE_ACK,(WPARAM)hwnd,PackDDElParam(WM_DDE_ACK,*(PUINT)&ack,(UINT)hSzItem));
+ }
+ else GlobalDeleteAtom(hSzItem);
+ release=data->fRelease;
+ GlobalUnlock(hDdeData);
+ if(release) GlobalFree(hDdeData);
+ }
+ else GlobalDeleteAtom(hSzItem);
+ return 0;
+ }
+ return DefWindowProc(hwnd,msg,wParam,lParam);
+}
+
+static int DoDdeRequest(const char *szItemName,HWND hwndDdeMsg)
+{
+ ATOM hSzItemName;
+ DWORD timeoutTick,thisTick;
+ MSG msg;
+ struct DdeMsgWindowData *dat=(struct DdeMsgWindowData*)GetWindowLong(hwndDdeMsg,0);
+
+ hSzItemName=GlobalAddAtomA(szItemName);
+ if(!PostMessage(dat->hwndDde,WM_DDE_REQUEST,(WPARAM)hwndDdeMsg,MAKELPARAM(CF_TEXT,hSzItemName))) {
+ GlobalDeleteAtom(hSzItemName);
+ return 1;
+ }
+ timeoutTick=GetTickCount()+5000;
+ dat->fData=0; dat->fAcked=0;
+ do {
+ if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ if(dat->fData || dat->fAcked) break;
+ thisTick=GetTickCount();
+ if(thisTick>timeoutTick) break;
+ } while(MsgWaitForMultipleObjects(0,NULL,FALSE,timeoutTick-thisTick,QS_ALLINPUT)==WAIT_OBJECT_0);
+
+ if(!dat->fData) {
+ GlobalDeleteAtom(hSzItemName);
+ return 1;
+ }
+ return 0;
+}
+
+//see Q160957 and http://developer.netscape.com/docs/manuals/communicator/DDE/index.htm
+static int DdeOpenUrl(const char *szBrowser,char *szUrl,int newWindow,HWND hwndDdeMsg)
+{
+ ATOM hSzBrowser,hSzTopic;
+ DWORD dwResult;
+ char *szItemName;
+ struct DdeMsgWindowData *dat=(struct DdeMsgWindowData*)GetWindowLong(hwndDdeMsg,0);
+
+ hSzBrowser=GlobalAddAtomA(szBrowser);
+ hSzTopic=GlobalAddAtomA("WWW_OpenURL");
+ dat->fAcked=0;
+ if(!SendMessageTimeout(HWND_BROADCAST,WM_DDE_INITIATE,(WPARAM)hwndDdeMsg,MAKELPARAM(hSzBrowser,hSzTopic),SMTO_ABORTIFHUNG|SMTO_NORMAL,DDEMESSAGETIMEOUT,&dwResult)
+ || !dat->fAcked) {
+ GlobalDeleteAtom(hSzTopic);
+ GlobalDeleteAtom(hSzBrowser);
+ return 1;
+ }
+ szItemName=(char*)mir_alloc(lstrlenA(szUrl)+7);
+ wsprintfA(szItemName,"\"%s\",,%d",szUrl,newWindow?0:-1);
+ if(DoDdeRequest(szItemName,hwndDdeMsg)) {
+ mir_free(szItemName);
+ GlobalDeleteAtom(hSzTopic);
+ GlobalDeleteAtom(hSzBrowser);
+ return 1;
+ }
+ PostMessage(dat->hwndDde,WM_DDE_TERMINATE,(WPARAM)hwndDdeMsg,0);
+ GlobalDeleteAtom(hSzTopic);
+ GlobalDeleteAtom(hSzBrowser);
+ mir_free(szItemName);
+ return 0;
+}
+
+typedef struct {
+ char *szUrl;
+ int newWindow;
+} TOpenUrlInfo;
+
+static void OpenURLThread(void *arg)
+{
+ TOpenUrlInfo *hUrlInfo = (TOpenUrlInfo*)arg;
+ char *szResult;
+ HWND hwndDdeMsg;
+ struct DdeMsgWindowData msgWndData={0};
+ char *pszProtocol;
+ HKEY hKey;
+ char szSubkey[80];
+ char szCommandName[MAX_PATH];
+ DWORD dataLength;
+ int success=0;
+
+ if (!hUrlInfo->szUrl) return;
+ hwndDdeMsg=CreateWindow(WNDCLASS_DDEMSGWINDOW,_T(""),0,0,0,0,0,NULL,NULL,GetModuleHandle(NULL),NULL);
+ SetWindowLong(hwndDdeMsg,0,(LONG)&msgWndData);
+
+ if(!_strnicmp(hUrlInfo->szUrl,"ftp:",4) || !_strnicmp(hUrlInfo->szUrl,"ftp.",4)) pszProtocol="ftp";
+ if(!_strnicmp(hUrlInfo->szUrl,"mailto:",7)) pszProtocol="mailto";
+ if(!_strnicmp(hUrlInfo->szUrl,"news:",5)) pszProtocol="news";
+ else pszProtocol="http";
+ wsprintfA(szSubkey,"%s\\shell\\open\\command",pszProtocol);
+ if(RegOpenKeyExA(HKEY_CURRENT_USER,szSubkey,0,KEY_QUERY_VALUE,&hKey)==ERROR_SUCCESS
+ || RegOpenKeyExA(HKEY_CLASSES_ROOT,szSubkey,0,KEY_QUERY_VALUE,&hKey)==ERROR_SUCCESS) {
+ dataLength=SIZEOF(szCommandName);
+ if(RegQueryValueEx(hKey,NULL,NULL,NULL,(PBYTE)szCommandName,&dataLength)==ERROR_SUCCESS) {
+ _strlwr(szCommandName);
+ if(strstr(szCommandName,"mozilla") || strstr(szCommandName,"netscape"))
+ success=(DdeOpenUrl("mozilla",hUrlInfo->szUrl,hUrlInfo->newWindow,hwndDdeMsg)==0 || DdeOpenUrl("netscape",hUrlInfo->szUrl,hUrlInfo->newWindow,hwndDdeMsg)==0);
+ else if(strstr(szCommandName,"iexplore") || strstr(szCommandName,"msimn"))
+ success=0==DdeOpenUrl("iexplore",hUrlInfo->szUrl,hUrlInfo->newWindow,hwndDdeMsg);
+ else if(strstr(szCommandName,"opera"))
+ success=0==DdeOpenUrl("opera",hUrlInfo->szUrl,hUrlInfo->newWindow,hwndDdeMsg);
+ //opera's the default anyway
+ }
+ RegCloseKey(hKey);
+ }
+
+ DestroyWindow(hwndDdeMsg);
+ if(success) return;
+
+ //wack a protocol on it
+ if((isalpha(hUrlInfo->szUrl[0]) && hUrlInfo->szUrl[1]==':') || hUrlInfo->szUrl[0]=='\\') {
+ szResult=(char*)mir_alloc(lstrlenA(hUrlInfo->szUrl)+9);
+ wsprintfA(szResult,"file:///%s",hUrlInfo->szUrl);
+ }
+ else {
+ int i;
+ for(i=0;isalpha(hUrlInfo->szUrl[i]);i++);
+ if(hUrlInfo->szUrl[i]==':') szResult=mir_strdup(hUrlInfo->szUrl);
+ else {
+ if(!_strnicmp(hUrlInfo->szUrl,"ftp.",4)) {
+ szResult=(char*)mir_alloc(lstrlenA(hUrlInfo->szUrl)+7);
+ wsprintfA(szResult,"ftp://%s",hUrlInfo->szUrl);
+ }
+ else {
+ szResult=(char*)mir_alloc(lstrlenA(hUrlInfo->szUrl)+8);
+ wsprintfA(szResult,"http://%s",hUrlInfo->szUrl);
+ }
+ }
+ }
+ ShellExecuteA(NULL, "open", szResult, NULL, NULL, SW_SHOW);
+ mir_free(szResult);
+ mir_free(hUrlInfo->szUrl);
+ mir_free(hUrlInfo);
+ return;
+}
+
+static int OpenURL(WPARAM wParam,LPARAM lParam) {
+ TOpenUrlInfo *hUrlInfo = (TOpenUrlInfo*)mir_alloc(sizeof(TOpenUrlInfo));
+ hUrlInfo->szUrl = (char*)lParam?mir_strdup((char*)lParam):NULL;
+ hUrlInfo->newWindow = (int)wParam;
+ forkthread(OpenURLThread, 0, (void*)hUrlInfo);
+ return 0;
+}
+
+int InitOpenUrl(void)
+{
+ WNDCLASS wcl;
+ wcl.lpfnWndProc=DdeMessageWindow;
+ wcl.cbClsExtra=0;
+ wcl.cbWndExtra=sizeof(void*);
+ wcl.hInstance=GetModuleHandle(NULL);
+ wcl.hCursor=NULL;
+ wcl.lpszClassName=WNDCLASS_DDEMSGWINDOW;
+ wcl.hbrBackground=NULL;
+ wcl.hIcon=NULL;
+ wcl.lpszMenuName=NULL;
+ wcl.style=0;
+ RegisterClass(&wcl);
+ CreateServiceFunction(MS_UTILS_OPENURL,OpenURL);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/utils/path.c b/miranda-wine/src/modules/utils/path.c
new file mode 100644
index 0000000..ba7caee
--- /dev/null
+++ b/miranda-wine/src/modules/utils/path.c
@@ -0,0 +1,83 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+static char szMirandaPath[MAX_PATH];
+
+static int pathIsAbsolute(char *path)
+{
+ if (!path||!strlen(path)>2) return 0;
+ if ((path[1]==':'&&path[2]=='\\')||(path[0]=='\\'&&path[1]=='\\')) return 1;
+ return 0;
+}
+
+static int pathToRelative(WPARAM wParam, LPARAM lParam)
+{
+ char *pSrc = (char*)wParam;
+ char *pOut = (char*)lParam;
+ if (!pSrc||!strlen(pSrc)||strlen(pSrc)>MAX_PATH) return 0;
+ if (!pathIsAbsolute(pSrc)) {
+ mir_snprintf(pOut, MAX_PATH, "%s", pSrc);
+ return strlen(pOut);
+ }
+ else {
+ char szTmp[MAX_PATH];
+
+ mir_snprintf(szTmp, SIZEOF(szTmp), "%s", pSrc);
+ _strlwr(szTmp);
+ if (strstr(szTmp, szMirandaPath)) {
+ mir_snprintf(pOut, MAX_PATH, "%s", pSrc+strlen(szMirandaPath));
+ return strlen(pOut);
+ }
+ else {
+ mir_snprintf(pOut, MAX_PATH, "%s", pSrc);
+ return strlen(pOut);
+ }
+ }
+}
+
+static int pathToAbsolute(WPARAM wParam, LPARAM lParam) {
+ char *pSrc = (char*)wParam;
+ char *pOut = (char*)lParam;
+ if (!pSrc||!strlen(pSrc)||strlen(pSrc)>MAX_PATH) return 0;
+ if (pathIsAbsolute(pSrc)||!isalnum(pSrc[0])) {
+ mir_snprintf(pOut, MAX_PATH, "%s", pSrc);
+ return strlen(pOut);
+ }
+ else {
+ mir_snprintf(pOut, MAX_PATH, "%s%s", szMirandaPath, pSrc);
+ return strlen(pOut);
+ }
+}
+
+int InitPathUtils(void)
+{
+ char *p = 0;
+ GetModuleFileNameA(GetModuleHandle(NULL), szMirandaPath, SIZEOF(szMirandaPath));
+ p=strrchr(szMirandaPath,'\\');
+ if (p&&p+1) *(p+1)=0;
+ _strlwr(szMirandaPath);
+ CreateServiceFunction(MS_UTILS_PATHTORELATIVE, pathToRelative);
+ CreateServiceFunction(MS_UTILS_PATHTOABSOLUTE, pathToAbsolute);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/utils/resizer.c b/miranda-wine/src/modules/utils/resizer.c
new file mode 100644
index 0000000..06e79d3
--- /dev/null
+++ b/miranda-wine/src/modules/utils/resizer.c
@@ -0,0 +1,152 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+typedef struct {
+ DWORD helpID;
+ DWORD exStyle;
+ DWORD style;
+ short x;
+ short y;
+ short cx;
+ short cy;
+ WORD id;
+} START_OF_DLGITEMTEMPLATEEX;
+
+typedef struct {
+ WORD dlgVer;
+ WORD signature;
+ DWORD helpID;
+ DWORD exStyle;
+ DWORD style;
+ WORD cDlgItems;
+ short x;
+ short y;
+ short cx;
+ short cy;
+} START_OF_DLGTEMPLATEEX;
+
+int ResizeDialog(WPARAM wParam,LPARAM lParam)
+{
+ UTILRESIZEDIALOG *urd=(UTILRESIZEDIALOG*)lParam;
+ HDWP hDwp;
+ int i;
+ DLGITEMTEMPLATE *pItem;
+ START_OF_DLGITEMTEMPLATEEX *pItemEx;
+ RECT rc;
+ PWORD pWord;
+ DLGTEMPLATE *pTemplate;
+ START_OF_DLGTEMPLATEEX *pTemplateEx;
+ UTILRESIZECONTROL urc;
+ int procResult;
+ int extendedDlg,itemCount;
+
+ if(urd==NULL||urd->cbSize!=sizeof(UTILRESIZEDIALOG)) return 1;
+ pTemplate=(DLGTEMPLATE*)LockResource(LoadResource(urd->hInstance,FindResourceA(urd->hInstance,urd->lpTemplate,MAKEINTRESOURCEA(5))));
+ pTemplateEx=(START_OF_DLGTEMPLATEEX*)pTemplate;
+ extendedDlg=pTemplateEx->signature==0xFFFF;
+ if(extendedDlg && pTemplateEx->dlgVer!=1)
+ return 1;
+
+ if(extendedDlg) pWord=(PWORD)(pTemplateEx+1);
+ else pWord=(PWORD)(pTemplate+1);
+ if(*pWord==0xFFFF) pWord+=2; else while(*pWord++); //menu
+ if(*pWord==0xFFFF) pWord+=2; else while(*pWord++); //class
+ while(*pWord++); //title
+ if(extendedDlg) {
+ if(pTemplateEx->style&DS_SETFONT) {
+ pWord+=3; //font size,weight,italic
+ while(*pWord++); //font name
+ }
+ }
+ else {
+ if(pTemplate->style&DS_SETFONT) {
+ pWord++; //font size
+ while(*pWord++); //font name
+ }
+ }
+
+ urc.cbSize=sizeof(UTILRESIZECONTROL);
+ rc.left=0; rc.top=0;
+ if(extendedDlg) {rc.right=pTemplateEx->cx; rc.bottom=pTemplateEx->cy;}
+ else {rc.right=pTemplate->cx; rc.bottom=pTemplate->cy;}
+ MapDialogRect(urd->hwndDlg,&rc);
+ urc.dlgOriginalSize.cx=rc.right; urc.dlgOriginalSize.cy=rc.bottom;
+ GetClientRect(urd->hwndDlg,&rc);
+ urc.dlgNewSize.cx=rc.right; urc.dlgNewSize.cy=rc.bottom;
+
+ if(extendedDlg) itemCount=pTemplateEx->cDlgItems;
+ else itemCount=pTemplate->cdit;
+ hDwp=BeginDeferWindowPos(itemCount);
+ for(i=0;i<itemCount;i++) {
+ if((unsigned)pWord&2) pWord++; //dword align
+
+ if(extendedDlg) {
+ pItemEx=(START_OF_DLGITEMTEMPLATEEX*)pWord;
+ pWord=(PWORD)(pItemEx+1);
+
+ urc.wId=pItemEx->id;
+ urc.rcItem.left=pItemEx->x; urc.rcItem.top=pItemEx->y;
+ urc.rcItem.right=urc.rcItem.left+pItemEx->cx; urc.rcItem.bottom=urc.rcItem.top+pItemEx->cy;
+ }
+ else {
+ pItem=(DLGITEMTEMPLATE*)pWord;
+ pWord=(PWORD)(pItem+1);
+
+ urc.wId=pItem->id;
+ urc.rcItem.left=pItem->x; urc.rcItem.top=pItem->y;
+ urc.rcItem.right=urc.rcItem.left+pItem->cx; urc.rcItem.bottom=urc.rcItem.top+pItem->cy;
+ }
+ if(*pWord==0xFFFF) pWord+=2; else while(*pWord++); //menu
+ if(*pWord==0xFFFF) pWord+=2; else while(*pWord++); //class
+ pWord+=1+(1+*pWord)/2; //creation data
+
+ if(urc.wId==65535) continue; //using this breaks the dwp, so just ignore it
+
+ MapDialogRect(urd->hwndDlg,&urc.rcItem);
+ procResult=(urd->pfnResizer)(urd->hwndDlg,urd->lParam,&urc);
+ if(procResult&RD_ANCHORX_RIGHT) {
+ urc.rcItem.left+=urc.dlgNewSize.cx-urc.dlgOriginalSize.cx;
+ urc.rcItem.right+=urc.dlgNewSize.cx-urc.dlgOriginalSize.cx;
+ }
+ else if(procResult&RD_ANCHORX_WIDTH)
+ urc.rcItem.right+=urc.dlgNewSize.cx-urc.dlgOriginalSize.cx;
+ else if(procResult&RD_ANCHORX_CENTRE) {
+ urc.rcItem.left+=(urc.dlgNewSize.cx-urc.dlgOriginalSize.cx)/2;
+ urc.rcItem.right+=(urc.dlgNewSize.cx-urc.dlgOriginalSize.cx)/2;
+ }
+ if(procResult&RD_ANCHORY_BOTTOM) {
+ urc.rcItem.top+=urc.dlgNewSize.cy-urc.dlgOriginalSize.cy;
+ urc.rcItem.bottom+=urc.dlgNewSize.cy-urc.dlgOriginalSize.cy;
+ }
+ else if(procResult&RD_ANCHORY_HEIGHT)
+ urc.rcItem.bottom+=urc.dlgNewSize.cy-urc.dlgOriginalSize.cy;
+ else if(procResult&RD_ANCHORY_CENTRE) {
+ urc.rcItem.top+=(urc.dlgNewSize.cy-urc.dlgOriginalSize.cy)/2;
+ urc.rcItem.bottom+=(urc.dlgNewSize.cy-urc.dlgOriginalSize.cy)/2;
+ }
+ hDwp=DeferWindowPos(hDwp,GetDlgItem(urd->hwndDlg,extendedDlg?pItemEx->id:pItem->id),0,urc.rcItem.left,urc.rcItem.top,urc.rcItem.right-urc.rcItem.left,urc.rcItem.bottom-urc.rcItem.top,SWP_NOZORDER);
+ }
+ EndDeferWindowPos(hDwp);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/utils/utf.c b/miranda-wine/src/modules/utils/utf.c
new file mode 100644
index 0000000..57f72c8
--- /dev/null
+++ b/miranda-wine/src/modules/utils/utf.c
@@ -0,0 +1,165 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Utf8Decode - converts UTF8-encoded string to the UCS2/MBCS format
+
+void Utf8Decode( char* str, wchar_t** ucs2 )
+{
+ int len;
+ wchar_t* tempBuf;
+
+ if ( str == NULL )
+ return;
+
+ 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;
+ }
+
+ 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* )mir_alloc( 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* Utf8Encode( const char* src )
+{
+ int len;
+ char* result;
+ wchar_t* tempBuf;
+
+ if ( src == NULL )
+ return NULL;
+
+ len = strlen( src );
+ result = ( char* )mir_alloc( len*3 + 1 );
+ if ( result == NULL )
+ return NULL;
+
+ 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* Utf8EncodeUcs2( const wchar_t* src )
+{
+ int len = wcslen( src );
+ char* result = ( char* )mir_alloc( 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;
+}
diff --git a/miranda-wine/src/modules/utils/utils.c b/miranda-wine/src/modules/utils/utils.c
new file mode 100644
index 0000000..5f72a56
--- /dev/null
+++ b/miranda-wine/src/modules/utils/utils.c
@@ -0,0 +1,364 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+int ResizeDialog(WPARAM wParam,LPARAM lParam);
+int InitOpenUrl(void);
+int InitWindowList(void);
+int InitHyperlink(void);
+int InitColourPicker(void);
+int InitBitmapFilter(void);
+int InitPathUtils(void);
+
+static struct CountryListEntry countries[]={
+ {0 ,"Unspecified"},
+ {9999,"Other"},
+ {0xFFFF,"Unknown"},
+ {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 int SaveWindowPosition(WPARAM wParam,LPARAM lParam)
+{
+ SAVEWINDOWPOS *swp=(SAVEWINDOWPOS*)lParam;
+ WINDOWPLACEMENT wp;
+ char szSettingName[64];
+
+ wp.length=sizeof(wp);
+ GetWindowPlacement(swp->hwnd,&wp);
+ wsprintfA(szSettingName,"%sx",swp->szNamePrefix);
+ DBWriteContactSettingDword(swp->hContact,swp->szModule,szSettingName,wp.rcNormalPosition.left);
+ wsprintfA(szSettingName,"%sy",swp->szNamePrefix);
+ DBWriteContactSettingDword(swp->hContact,swp->szModule,szSettingName,wp.rcNormalPosition.top);
+ wsprintfA(szSettingName,"%swidth",swp->szNamePrefix);
+ DBWriteContactSettingDword(swp->hContact,swp->szModule,szSettingName,wp.rcNormalPosition.right-wp.rcNormalPosition.left);
+ wsprintfA(szSettingName,"%sheight",swp->szNamePrefix);
+ DBWriteContactSettingDword(swp->hContact,swp->szModule,szSettingName,wp.rcNormalPosition.bottom-wp.rcNormalPosition.top);
+ return 0;
+}
+
+static int RestoreWindowPosition(WPARAM wParam,LPARAM lParam)
+{
+ SAVEWINDOWPOS *swp=(SAVEWINDOWPOS*)lParam;
+ WINDOWPLACEMENT wp;
+ char szSettingName[64];
+ int x,y;
+
+ wp.length=sizeof(wp);
+ GetWindowPlacement(swp->hwnd,&wp);
+ wsprintfA(szSettingName,"%sx",swp->szNamePrefix);
+ x=DBGetContactSettingDword(swp->hContact,swp->szModule,szSettingName,-1);
+ wsprintfA(szSettingName,"%sy",swp->szNamePrefix);
+ y=(int)DBGetContactSettingDword(swp->hContact,swp->szModule,szSettingName,-1);
+ if(x==-1) return 1;
+ if(wParam&RWPF_NOSIZE) {
+ OffsetRect(&wp.rcNormalPosition,x-wp.rcNormalPosition.left,y-wp.rcNormalPosition.top);
+ }
+ else {
+ wp.rcNormalPosition.left=x;
+ wp.rcNormalPosition.top=y;
+ wsprintfA(szSettingName,"%swidth",swp->szNamePrefix);
+ wp.rcNormalPosition.right=wp.rcNormalPosition.left+DBGetContactSettingDword(swp->hContact,swp->szModule,szSettingName,-1);
+ wsprintfA(szSettingName,"%sheight",swp->szNamePrefix);
+ wp.rcNormalPosition.bottom=wp.rcNormalPosition.top+DBGetContactSettingDword(swp->hContact,swp->szModule,szSettingName,-1);
+ }
+ wp.flags=0;
+ if(wParam&RWPF_NOACTIVATE)
+ wp.showCmd = SW_SHOWNOACTIVATE;
+
+ SetWindowPlacement(swp->hwnd,&wp);
+ return 0;
+}
+
+static int GetCountryByNumber(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+
+ for(i=0; i < SIZEOF(countries); i++ )
+ if((int)wParam==countries[i].id) return (int)countries[i].szName;
+ return (int)(char*)NULL;
+}
+
+static int GetCountryList(WPARAM wParam,LPARAM lParam)
+{
+ *(int*)wParam = SIZEOF(countries);
+ *(struct CountryListEntry**)lParam=countries;
+ return 0;
+}
+
+int LoadUtilsModule(void)
+{
+ CreateServiceFunction(MS_UTILS_RESIZEDIALOG,ResizeDialog);
+ CreateServiceFunction(MS_UTILS_SAVEWINDOWPOSITION,SaveWindowPosition);
+ CreateServiceFunction(MS_UTILS_RESTOREWINDOWPOSITION,RestoreWindowPosition);
+ CreateServiceFunction(MS_UTILS_GETCOUNTRYBYNUMBER,GetCountryByNumber);
+ CreateServiceFunction(MS_UTILS_GETCOUNTRYLIST,GetCountryList);
+ InitOpenUrl();
+ InitWindowList();
+ InitHyperlink();
+ InitColourPicker();
+ InitBitmapFilter();
+ InitPathUtils();
+ return 0;
+}
diff --git a/miranda-wine/src/modules/utils/windowlist.c b/miranda-wine/src/modules/utils/windowlist.c
new file mode 100644
index 0000000..d8f53b4
--- /dev/null
+++ b/miranda-wine/src/modules/utils/windowlist.c
@@ -0,0 +1,107 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+static WINDOWLISTENTRY *windowList=NULL;
+static int windowListCount=0;
+static int nextWindowListId=1;
+
+static int AllocWindowList(WPARAM wParam,LPARAM lParam)
+{
+ return nextWindowListId++;
+}
+
+static int AddToWindowList(WPARAM wParam,LPARAM lParam)
+{
+ windowList=(WINDOWLISTENTRY*)mir_realloc(windowList,sizeof(WINDOWLISTENTRY)*(windowListCount+1));
+ windowList[windowListCount++]=*(WINDOWLISTENTRY*)lParam;
+ return 0;
+}
+
+static int RemoveFromWindowList(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ for(i=0;i<windowListCount;i++)
+ if(windowList[i].hwnd==(HWND)lParam && windowList[i].hList==(HANDLE)wParam) {
+ MoveMemory(&windowList[i],&windowList[i+1],sizeof(WINDOWLISTENTRY)*(windowListCount-i-1));
+ windowListCount--;
+ return 0;
+ }
+ return 1;
+}
+
+static int FindInWindowList(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ for(i=0;i<windowListCount;i++)
+ if(windowList[i].hContact==(HANDLE)lParam && windowList[i].hList==(HANDLE)wParam)
+ return (int)windowList[i].hwnd;
+ return (int)(HWND)NULL;
+}
+
+static int BroadcastToWindowList(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ MSG *msg=(MSG*)lParam;
+ for(i=0;i<windowListCount;i++)
+ if(windowList[i].hList==(HANDLE)wParam)
+ SendMessage(windowList[i].hwnd,msg->message,msg->wParam,msg->lParam);
+ return 0;
+}
+
+static int BroadcastToWindowListAsync(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ MSG *msg=(MSG*)lParam;
+ for(i=0;i<windowListCount;i++)
+ if(windowList[i].hList==(HANDLE)wParam)
+ PostMessage(windowList[i].hwnd,msg->message,msg->wParam,msg->lParam);
+ return 0;
+}
+
+static int FreeWindowList(WPARAM wParam,LPARAM lParam)
+{
+ if (windowList) mir_free(windowList);
+ windowList=NULL;
+ windowListCount=0;
+ nextWindowListId=1;
+ return 0;
+}
+
+static int HookShutdown(WPARAM wParam, LPARAM lParam)
+{
+ HookEvent(ME_SYSTEM_SHUTDOWN,FreeWindowList);
+ return 0;
+}
+
+int InitWindowList(void)
+{
+ CreateServiceFunction(MS_UTILS_ALLOCWINDOWLIST,AllocWindowList);
+ CreateServiceFunction(MS_UTILS_ADDTOWINDOWLIST,AddToWindowList);
+ CreateServiceFunction(MS_UTILS_REMOVEFROMWINDOWLIST,RemoveFromWindowList);
+ CreateServiceFunction(MS_UTILS_BROADCASTTOWINDOWLIST,BroadcastToWindowList);
+ CreateServiceFunction(MS_UTILS_BROADCASTTOWINDOWLIST_ASYNC,BroadcastToWindowListAsync);
+ CreateServiceFunction(MS_UTILS_FINDWINDOWINLIST,FindInWindowList);
+ HookEvent(ME_SYSTEM_MODULESLOADED,HookShutdown);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/visibility/visibility.c b/miranda-wine/src/modules/visibility/visibility.c
new file mode 100644
index 0000000..2b8c870
--- /dev/null
+++ b/miranda-wine/src/modules/visibility/visibility.c
@@ -0,0 +1,297 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 "commonheaders.h"
+
+static void SetListGroupIcons(HWND hwndList,HANDLE hFirstItem,HANDLE hParentItem,int *groupChildCount)
+{
+ int typeOfFirst;
+ int iconOn[2]={1,1};
+ int childCount[2]={0,0},i;
+ int iImage;
+ HANDLE hItem,hChildItem;
+
+ typeOfFirst=SendMessage(hwndList,CLM_GETITEMTYPE,(WPARAM)hFirstItem,0);
+ //check groups
+ if(typeOfFirst==CLCIT_GROUP) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hFirstItem);
+ while(hItem) {
+ hChildItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_CHILD,(LPARAM)hItem);
+ if(hChildItem) SetListGroupIcons(hwndList,hChildItem,hItem,childCount);
+ for( i=0; i < SIZEOF(iconOn); i++)
+ if(iconOn[i] && SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,i)==0) iconOn[i]=0;
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hItem);
+ }
+ //check contacts
+ if(typeOfFirst==CLCIT_CONTACT) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hFirstItem);
+ while(hItem) {
+ for ( i=0; i < SIZEOF(iconOn); i++) {
+ iImage=SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,i);
+ if(iconOn[i] && iImage==0) iconOn[i]=0;
+ if(iImage!=0xFF) childCount[i]++;
+ }
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hItem);
+ }
+ //set icons
+ for( i=0; i < SIZEOF(iconOn); i++) {
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hParentItem,MAKELPARAM(i,childCount[i]?(iconOn[i]?i+1:0):0xFF));
+ if(groupChildCount) groupChildCount[i]+=childCount[i];
+ }
+}
+
+static void SetAllChildIcons(HWND hwndList,HANDLE hFirstItem,int iColumn,int iImage)
+{
+ int typeOfFirst,iOldIcon;
+ HANDLE hItem,hChildItem;
+
+ typeOfFirst=SendMessage(hwndList,CLM_GETITEMTYPE,(WPARAM)hFirstItem,0);
+ //check groups
+ if(typeOfFirst==CLCIT_GROUP) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hFirstItem);
+ while(hItem) {
+ hChildItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_CHILD,(LPARAM)hItem);
+ if(hChildItem) SetAllChildIcons(hwndList,hChildItem,iColumn,iImage);
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hItem);
+ }
+ //check contacts
+ if(typeOfFirst==CLCIT_CONTACT) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hFirstItem);
+ while(hItem) {
+ iOldIcon=SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,iColumn);
+ if(iOldIcon!=0xFF && iOldIcon!=iImage) SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(iColumn,iImage));
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hItem);
+ }
+}
+
+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,hItem;
+ char *szProto;
+ DWORD flags;
+ WORD status;
+
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ do {
+ hItem=(HANDLE)SendMessage(hwndList,CLM_FINDCONTACT,(WPARAM)hContact,0);
+ if(hItem) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if(szProto==NULL) {flags=0; status=0;}
+ else {
+ flags=CallProtoService(szProto,PS_GETCAPS,PFLAGNUM_1,0);
+ status=DBGetContactSettingWord(hContact,szProto,"ApparentMode",0);
+ }
+ if(flags&PF1_INVISLIST) {
+ if(SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(0,0))==0xFF)
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(0,status==ID_STATUS_ONLINE?1:0));
+ }
+ if(flags&PF1_VISLIST) {
+ if(SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(1,0))==0xFF)
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(1,status==ID_STATUS_OFFLINE?2:0));
+ }
+ }
+ } while(hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0));
+}
+
+static BOOL CALLBACK DlgProcVisibilityOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static HICON hVisibleIcon,hInvisibleIcon;
+ static HANDLE hItemAll;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ { HIMAGELIST hIml;
+ hIml=ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),(IsWinVerXPPlus()?ILC_COLOR32:ILC_COLOR16)|ILC_MASK,3,3);
+ ImageList_AddIcon(hIml,LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_SMALLDOT)));
+ ImageList_AddIcon(hIml,LoadSkinnedIcon(SKINICON_STATUS_INVISIBLE));
+ ImageList_AddIcon(hIml,LoadSkinnedIcon(SKINICON_STATUS_OFFLINE));
+ SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_SETEXTRAIMAGELIST,0,(LPARAM)hIml);
+ hVisibleIcon=ImageList_GetIcon(hIml,1,ILD_NORMAL);
+ SendDlgItemMessage(hwndDlg,IDC_VISIBLEICON,STM_SETICON,(WPARAM)hVisibleIcon,0);
+ hInvisibleIcon=ImageList_GetIcon(hIml,2,ILD_NORMAL);
+ SendDlgItemMessage(hwndDlg,IDC_INVISIBLEICON,STM_SETICON,(WPARAM)hInvisibleIcon,0);
+ }
+
+ ResetListOptions(GetDlgItem(hwndDlg,IDC_LIST));
+ SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_SETEXTRACOLUMNS,2,0);
+
+ { CLCINFOITEM cii={0};
+ cii.cbSize=sizeof(cii);
+ cii.flags=CLCIIF_GROUPFONT;
+ cii.pszText=TranslateT("** All contacts **");
+ hItemAll=(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_ADDINFOITEM,0,(LPARAM)&cii);
+ }
+
+ SetAllContactIcons(GetDlgItem(hwndDlg,IDC_LIST));
+ SetListGroupIcons(GetDlgItem(hwndDlg,IDC_LIST),(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETNEXTITEM,CLGN_ROOT,0),hItemAll,NULL);
+ return TRUE;
+ case WM_SETFOCUS:
+ SetFocus(GetDlgItem(hwndDlg,IDC_LIST));
+ break;
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case IDC_LIST:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case CLN_NEWCONTACT:
+ case CLN_LISTREBUILT:
+ SetAllContactIcons(GetDlgItem(hwndDlg,IDC_LIST));
+ //fall through
+ case CLN_CONTACTMOVED:
+ SetListGroupIcons(GetDlgItem(hwndDlg,IDC_LIST),(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETNEXTITEM,CLGN_ROOT,0),hItemAll,NULL);
+ break;
+ 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
+ if (nm->iColumn == -1)
+ 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 a visbility icon
+ if (!(hitFlags & CLCHT_ONITEMEXTRA)) break;
+
+ // Get image in clicked column (0=none, 1=visible, 2=invisible)
+ iImage = SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(nm->iColumn, 0));
+ if (iImage == 0)
+ iImage=nm->iColumn + 1;
+ else
+ if (iImage == 1 || iImage == 2)
+ iImage = 0;
+
+ // Get item type (contact, group, etc...)
+ itemType = SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_GETITEMTYPE, (WPARAM)hItem, 0);
+
+ // Update list, making sure that the options are mutually exclusive
+ 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(nm->iColumn?0:1,0))!=0xFF)
+ SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(nm->iColumn?0:1, 0));
+ }
+ else if (itemType == CLCIT_INFO) { // All Contacts
+ SetAllChildIcons(GetDlgItem(hwndDlg, IDC_LIST), hItem, nm->iColumn, iImage);
+ if (iImage)
+ SetAllChildIcons(GetDlgItem(hwndDlg, IDC_LIST), hItem, nm->iColumn?0:1, 0);
+ }
+ else if (itemType == CLCIT_GROUP) { // A group
+ hItem = (HANDLE)SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem);
+ if (hItem) {
+ SetAllChildIcons(GetDlgItem(hwndDlg, IDC_LIST), hItem, nm->iColumn, iImage);
+ if (iImage)
+ SetAllChildIcons(GetDlgItem(hwndDlg, IDC_LIST), hItem, nm->iColumn?0:1, 0);
+ }
+ }
+ // Update the all/none icons
+ SetListGroupIcons(GetDlgItem(hwndDlg, IDC_LIST), (HANDLE)SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_GETNEXTITEM, CLGN_ROOT, 0), hItemAll, NULL);
+
+ // Activate Apply button
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ }
+ break;
+ case 0:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case PSN_APPLY:
+ { HANDLE hContact,hItem;
+ int set,i,iImage;
+
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ do {
+ hItem=(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_FINDCONTACT,(WPARAM)hContact,0);
+ if(hItem) {
+ set=0;
+ for(i=0;i<2;i++) {
+ iImage=SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(i,0));
+ if(iImage==i+1) {
+ CallContactService(hContact,PSS_SETAPPARENTMODE,iImage==1?ID_STATUS_ONLINE:ID_STATUS_OFFLINE,0);
+ set=1;
+ break;
+ }
+ }
+ if(!set) CallContactService(hContact,PSS_SETAPPARENTMODE,0,0);
+ }
+ } while(hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0));
+ return TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ DestroyIcon(hVisibleIcon);
+ DestroyIcon(hInvisibleIcon);
+ { HIMAGELIST hIml=(HIMAGELIST)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETEXTRAIMAGELIST,0,0);
+ ImageList_Destroy(hIml);
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static int VisibilityOptInitialise(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.position = 850000000;
+ odp.hInstance = GetModuleHandle(NULL);
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_VISIBILITY);
+ odp.pszTitle = "Visibility";
+ odp.pszGroup = "Status";
+ odp.pfnDlgProc = DlgProcVisibilityOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
+
+int LoadVisibilityModule(void)
+{
+ HookEvent(ME_OPT_INITIALISE,VisibilityOptInitialise);
+ return 0;
+}
diff --git a/miranda-wine/src/res/addcontact.ico b/miranda-wine/src/res/addcontact.ico
new file mode 100644
index 0000000..2efc4dc
--- /dev/null
+++ b/miranda-wine/src/res/addcontact.ico
Binary files differ
diff --git a/miranda-wine/src/res/away.ico b/miranda-wine/src/res/away.ico
new file mode 100644
index 0000000..1e22d9b
--- /dev/null
+++ b/miranda-wine/src/res/away.ico
Binary files differ
diff --git a/miranda-wine/src/res/blank.ico b/miranda-wine/src/res/blank.ico
new file mode 100644
index 0000000..7845f62
--- /dev/null
+++ b/miranda-wine/src/res/blank.ico
Binary files differ
diff --git a/miranda-wine/src/res/changefont.ico b/miranda-wine/src/res/changefont.ico
new file mode 100644
index 0000000..2c152dc
--- /dev/null
+++ b/miranda-wine/src/res/changefont.ico
Binary files differ
diff --git a/miranda-wine/src/res/delete.ico b/miranda-wine/src/res/delete.ico
new file mode 100644
index 0000000..c541793
--- /dev/null
+++ b/miranda-wine/src/res/delete.ico
Binary files differ
diff --git a/miranda-wine/src/res/detailsl.ico b/miranda-wine/src/res/detailsl.ico
new file mode 100644
index 0000000..a37e05d
--- /dev/null
+++ b/miranda-wine/src/res/detailsl.ico
Binary files differ
diff --git a/miranda-wine/src/res/dnd.ico b/miranda-wine/src/res/dnd.ico
new file mode 100644
index 0000000..6ccd9d2
--- /dev/null
+++ b/miranda-wine/src/res/dnd.ico
Binary files differ
diff --git a/miranda-wine/src/res/downarrow.ico b/miranda-wine/src/res/downarrow.ico
new file mode 100644
index 0000000..76a473c
--- /dev/null
+++ b/miranda-wine/src/res/downarrow.ico
Binary files differ
diff --git a/miranda-wine/src/res/dragcopy.cur b/miranda-wine/src/res/dragcopy.cur
new file mode 100644
index 0000000..89c7c96
--- /dev/null
+++ b/miranda-wine/src/res/dragcopy.cur
Binary files differ
diff --git a/miranda-wine/src/res/dropuser.cur b/miranda-wine/src/res/dropuser.cur
new file mode 100644
index 0000000..a84b19e
--- /dev/null
+++ b/miranda-wine/src/res/dropuser.cur
Binary files differ
diff --git a/miranda-wine/src/res/emptyblo.ico b/miranda-wine/src/res/emptyblo.ico
new file mode 100644
index 0000000..05469b9
--- /dev/null
+++ b/miranda-wine/src/res/emptyblo.ico
Binary files differ
diff --git a/miranda-wine/src/res/file.ico b/miranda-wine/src/res/file.ico
new file mode 100644
index 0000000..7d24e6d
--- /dev/null
+++ b/miranda-wine/src/res/file.ico
Binary files differ
diff --git a/miranda-wine/src/res/filledbl.ico b/miranda-wine/src/res/filledbl.ico
new file mode 100644
index 0000000..35752d2
--- /dev/null
+++ b/miranda-wine/src/res/filledbl.ico
Binary files differ
diff --git a/miranda-wine/src/res/finduser.ico b/miranda-wine/src/res/finduser.ico
new file mode 100644
index 0000000..a105678
--- /dev/null
+++ b/miranda-wine/src/res/finduser.ico
Binary files differ
diff --git a/miranda-wine/src/res/freechat.ico b/miranda-wine/src/res/freechat.ico
new file mode 100644
index 0000000..56d6661
--- /dev/null
+++ b/miranda-wine/src/res/freechat.ico
Binary files differ
diff --git a/miranda-wine/src/res/groupope.ico b/miranda-wine/src/res/groupope.ico
new file mode 100644
index 0000000..64b8dc2
--- /dev/null
+++ b/miranda-wine/src/res/groupope.ico
Binary files differ
diff --git a/miranda-wine/src/res/groupshu.ico b/miranda-wine/src/res/groupshu.ico
new file mode 100644
index 0000000..8b6f797
--- /dev/null
+++ b/miranda-wine/src/res/groupshu.ico
Binary files differ
diff --git a/miranda-wine/src/res/help.ico b/miranda-wine/src/res/help.ico
new file mode 100644
index 0000000..7fd7196
--- /dev/null
+++ b/miranda-wine/src/res/help.ico
Binary files differ
diff --git a/miranda-wine/src/res/history.ico b/miranda-wine/src/res/history.ico
new file mode 100644
index 0000000..2749b50
--- /dev/null
+++ b/miranda-wine/src/res/history.ico
Binary files differ
diff --git a/miranda-wine/src/res/hyperlin.cur b/miranda-wine/src/res/hyperlin.cur
new file mode 100644
index 0000000..f0f548c
--- /dev/null
+++ b/miranda-wine/src/res/hyperlin.cur
Binary files differ
diff --git a/miranda-wine/src/res/invisible.ico b/miranda-wine/src/res/invisible.ico
new file mode 100644
index 0000000..a2cd800
--- /dev/null
+++ b/miranda-wine/src/res/invisible.ico
Binary files differ
diff --git a/miranda-wine/src/res/message.ico b/miranda-wine/src/res/message.ico
new file mode 100644
index 0000000..34bc390
--- /dev/null
+++ b/miranda-wine/src/res/message.ico
Binary files differ
diff --git a/miranda-wine/src/res/miranda.ico b/miranda-wine/src/res/miranda.ico
new file mode 100644
index 0000000..f7791c3
--- /dev/null
+++ b/miranda-wine/src/res/miranda.ico
Binary files differ
diff --git a/miranda-wine/src/res/mirandaw.ico b/miranda-wine/src/res/mirandaw.ico
new file mode 100644
index 0000000..bc62b68
--- /dev/null
+++ b/miranda-wine/src/res/mirandaw.ico
Binary files differ
diff --git a/miranda-wine/src/res/multisend.ico b/miranda-wine/src/res/multisend.ico
new file mode 100644
index 0000000..3303179
--- /dev/null
+++ b/miranda-wine/src/res/multisend.ico
Binary files differ
diff --git a/miranda-wine/src/res/na2.ico b/miranda-wine/src/res/na2.ico
new file mode 100644
index 0000000..cab81c4
--- /dev/null
+++ b/miranda-wine/src/res/na2.ico
Binary files differ
diff --git a/miranda-wine/src/res/notick.ico b/miranda-wine/src/res/notick.ico
new file mode 100644
index 0000000..b96b9ec
--- /dev/null
+++ b/miranda-wine/src/res/notick.ico
Binary files differ
diff --git a/miranda-wine/src/res/notick1.ico b/miranda-wine/src/res/notick1.ico
new file mode 100644
index 0000000..9fe70c4
--- /dev/null
+++ b/miranda-wine/src/res/notick1.ico
Binary files differ
diff --git a/miranda-wine/src/res/occupied.ico b/miranda-wine/src/res/occupied.ico
new file mode 100644
index 0000000..d60bcd7
--- /dev/null
+++ b/miranda-wine/src/res/occupied.ico
Binary files differ
diff --git a/miranda-wine/src/res/offline2.ico b/miranda-wine/src/res/offline2.ico
new file mode 100644
index 0000000..7058c74
--- /dev/null
+++ b/miranda-wine/src/res/offline2.ico
Binary files differ
diff --git a/miranda-wine/src/res/online2.ico b/miranda-wine/src/res/online2.ico
new file mode 100644
index 0000000..d559fb9
--- /dev/null
+++ b/miranda-wine/src/res/online2.ico
Binary files differ
diff --git a/miranda-wine/src/res/onthepho.ico b/miranda-wine/src/res/onthepho.ico
new file mode 100644
index 0000000..09d6dfa
--- /dev/null
+++ b/miranda-wine/src/res/onthepho.ico
Binary files differ
diff --git a/miranda-wine/src/res/options.ico b/miranda-wine/src/res/options.ico
new file mode 100644
index 0000000..af93fd2
--- /dev/null
+++ b/miranda-wine/src/res/options.ico
Binary files differ
diff --git a/miranda-wine/src/res/outtolun.ico b/miranda-wine/src/res/outtolun.ico
new file mode 100644
index 0000000..6e5d40e
--- /dev/null
+++ b/miranda-wine/src/res/outtolun.ico
Binary files differ
diff --git a/miranda-wine/src/res/rename.ico b/miranda-wine/src/res/rename.ico
new file mode 100644
index 0000000..6dd597e
--- /dev/null
+++ b/miranda-wine/src/res/rename.ico
Binary files differ
diff --git a/miranda-wine/src/res/reply.ico b/miranda-wine/src/res/reply.ico
new file mode 100644
index 0000000..ddaf242
--- /dev/null
+++ b/miranda-wine/src/res/reply.ico
Binary files differ
diff --git a/miranda-wine/src/res/searchal.ico b/miranda-wine/src/res/searchal.ico
new file mode 100644
index 0000000..8146dfb
--- /dev/null
+++ b/miranda-wine/src/res/searchal.ico
Binary files differ
diff --git a/miranda-wine/src/res/sendmail.ico b/miranda-wine/src/res/sendmail.ico
new file mode 100644
index 0000000..55097a1
--- /dev/null
+++ b/miranda-wine/src/res/sendmail.ico
Binary files differ
diff --git a/miranda-wine/src/res/smalldot.ico b/miranda-wine/src/res/smalldot.ico
new file mode 100644
index 0000000..47f0556
--- /dev/null
+++ b/miranda-wine/src/res/smalldot.ico
Binary files differ
diff --git a/miranda-wine/src/res/sms.ico b/miranda-wine/src/res/sms.ico
new file mode 100644
index 0000000..4beb6e7
--- /dev/null
+++ b/miranda-wine/src/res/sms.ico
Binary files differ
diff --git a/miranda-wine/src/res/sortcold.bmp b/miranda-wine/src/res/sortcold.bmp
new file mode 100644
index 0000000..1fc197f
--- /dev/null
+++ b/miranda-wine/src/res/sortcold.bmp
Binary files differ
diff --git a/miranda-wine/src/res/sortcolu.bmp b/miranda-wine/src/res/sortcolu.bmp
new file mode 100644
index 0000000..271acc9
--- /dev/null
+++ b/miranda-wine/src/res/sortcolu.bmp
Binary files differ
diff --git a/miranda-wine/src/res/timestamp.ico b/miranda-wine/src/res/timestamp.ico
new file mode 100644
index 0000000..83b8abf
--- /dev/null
+++ b/miranda-wine/src/res/timestamp.ico
Binary files differ
diff --git a/miranda-wine/src/res/url.ico b/miranda-wine/src/res/url.ico
new file mode 100644
index 0000000..34a5643
--- /dev/null
+++ b/miranda-wine/src/res/url.ico
Binary files differ
diff --git a/miranda-wine/src/res/useronli.ico b/miranda-wine/src/res/useronli.ico
new file mode 100644
index 0000000..b6e4190
--- /dev/null
+++ b/miranda-wine/src/res/useronli.ico
Binary files differ
diff --git a/miranda-wine/src/res/viewdetails.ico b/miranda-wine/src/res/viewdetails.ico
new file mode 100644
index 0000000..c9fb124
--- /dev/null
+++ b/miranda-wine/src/res/viewdetails.ico
Binary files differ
diff --git a/miranda-wine/src/resource.h b/miranda-wine/src/resource.h
new file mode 100644
index 0000000..eaec7a7
--- /dev/null
+++ b/miranda-wine/src/resource.h
@@ -0,0 +1,392 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by resource.rc
+//
+#define IDC_AUTHICON 1
+#define IDC_NOTOALL 3
+#define IDC_APPLY 3
+#define IDI_MIRANDA 102
+#define IDD_ABOUT 103
+#define IDI_SMS 103
+#define IDI_ONLINE 104
+#define IDI_OFFLINE 105
+#define IDD_ADDED 115
+#define IDD_URLSEND 119
+#define IDD_URLRECV 120
+#define IDD_AUTHREQ 121
+#define IDD_DETAILS 125
+#define IDD_HISTORY 127
+#define IDI_AWAY 128
+#define IDI_FREE4CHAT 129
+#define IDI_INVISIBLE 130
+#define IDI_NA 131
+#define IDD_OPT_SOUND 134
+#define IDI_RECVMSG 136
+#define IDI_SENDMSG 137
+#define IDI_URL 138
+#define IDI_DND 158
+#define IDI_OCCUPIED 159
+#define IDI_USERDETAILS 160
+#define IDI_FINDUSER 161
+#define IDI_HELP 162
+#define IDI_OPTIONS 163
+#define IDI_MIRANDAWEBSITE 172
+#define IDI_RENAME 173
+#define IDI_HISTORY 174
+#define IDI_DELETE 175
+#define IDR_CONTEXT 180
+#define IDC_DROP 183
+#define IDD_HISTORY_FIND 192
+#define IDI_SENDEMAIL 193
+#define IDD_FILERECV 194
+#define IDD_PROFILEMANAGER 197
+#define IDR_CLISTMENU 199
+#define IDI_BLANK 200
+#define IDD_FINDADD 201
+#define IDI_USERONLINE 201
+#define IDI_GROUPSHUT 202
+#define IDD_OPTIONS 203
+#define IDI_GROUPOPEN 203
+#define IDD_FILESEND 205
+#define IDI_NOTICK 205
+#define IDD_OPT_PLUGINS 206
+#define IDI_TICK 206
+#define IDD_OPT_ICONS 207
+#define IDI_FILE 207
+#define IDI_TIMESTAMP 208
+#define IDI_CHANGEFONT 209
+#define IDI_ADDCONTACT 210
+#define IDI_SMALLDOT 211
+#define IDI_FILLEDBLOB 212
+#define IDD_READAWAYMSG 213
+#define IDI_EMPTYBLOB 213
+#define IDD_OPT_IGNORE 214
+#define IDC_HYPERLINKHAND 214
+#define IDD_OPT_VISIBILITY 215
+#define IDC_DROPUSER 215
+#define IDD_SETAWAYMSG 216
+#define IDI_DETAILSLOGO 216
+#define IDD_OPT_AWAYMSG 217
+#define IDD_INFO_SUMMARY 220
+#define IDD_INFO_CONTACT 221
+#define IDR_CREDITS 221
+#define IDD_INFO_BACKGROUND 222
+#define IDD_INFO_NOTES 223
+#define IDD_ADDEMAIL 226
+#define IDD_ICONINDEX 227
+#define IDD_INFO_LOCATION 231
+#define IDD_INFO_WORK 232
+#define IDD_ADDPHONE 233
+#define IDD_INSTALLINI 235
+#define IDD_WARNINICHANGE 236
+#define IDD_INIIMPORTDONE 237
+#define IDB_SORTCOLUP 239
+#define IDB_SORTCOLDOWN 240
+#define IDD_OPT_NETLIB 246
+#define IDD_NETLIBLOGOPTS 247
+#define IDD_FILETRANSFERINFO 249
+#define IDD_OPT_FILETRANSFER 250
+#define IDD_FILEEXISTS 251
+#define IDD_DELETECONTACT 254
+#define IDD_DENYREASON 256
+#define IDD_ADDCONTACT 257
+#define IDD_OPT_CONTACT 261
+#define IDI_MULTISEND 263
+#define IDI_DOWNARROW 264
+#define IDD_OPT_IDLE 268
+#define IDD_PROFILE_SELECTION 269
+#define IDD_PROFILE_NEW 270
+#define IDC_SAVE 1001
+#define IDI_ONTHEPHONE 1002
+#define IDC_MESSAGE 1002
+#define IDI_OUTTOLUNCH 1003
+#define IDC_AUTOCLOSE 1004
+#define IDC_FROM 1005
+#define IDC_AUTOMIN 1005
+#define IDC_DATE 1006
+#define IDC_DUMPRECV 1006
+#define IDC_MSG 1008
+#define IDC_PROXYDNS 1008
+#define IDC_NAME 1009
+#define IDC_PROXYTYPE 1009
+#define IDC_STATIC23 1010
+#define IDC_NAMEVAL 1010
+#define IDC_SPECIFYPORTS 1013
+#define IDC_ST_ENTERMSG 1013
+#define IDC_ST_ENTERURL 1014
+#define IDC_SPECIFYPORTSO 1014
+#define IDC_SHOWNAMES 1024
+#define IDC_ABOUT 1032
+#define IDC_MYNOTES 1033
+#define IDC_URLS 1037
+#define IDC_REPLY 1039
+#define IDC_URL 1041
+#define IDC_REASON 1046
+#define IDC_EMAIL 1048
+#define IDC_NAMENICK 1049
+#define IDC_NAMEFIRST 1050
+#define IDC_NAMELAST 1051
+#define IDC_NICK 1053
+#define IDC_GENDER 1060
+#define IDC_CITY 1061
+#define IDC_STATE 1062
+#define IDC_COUNTRY 1063
+#define IDC_AGE 1064
+#define IDC_ZIP 1064
+#define IDC_PHONE 1065
+#define IDC_STREET 1065
+#define IDC_COMPANY 1066
+#define IDC_LANGUAGE1 1066
+#define IDC_TIMEZONE 1067
+#define IDC_DEPARTMENT 1067
+#define IDC_LOCALTIME 1068
+#define IDC_DETAILS 1069
+#define IDC_POSITION 1069
+#define IDC_LANGUAGE2 1069
+#define IDC_ADD 1070
+#define IDC_LANGUAGE3 1070
+#define IDC_MOREOPTIONS 1071
+#define IDC_USERMENU 1071
+#define IDC_EDIT 1078
+#define IDC_LIST 1079
+#define IDC_HISTORY 1080
+#define IDC_BUILDTIME 1108
+#define IDC_CREDITSFILE 1109
+#define IDC_NUMBER 1113
+#define IDC_UIN 1123
+#define IDC_FINDWHAT 1131
+#define IDC_FIND 1132
+#define IDC_FILE 1133
+#define IDC_PROFILELIST 1134
+#define IDC_TABS 1141
+#define IDC_RESULTS 1142
+#define IDC_STATUS 1144
+#define IDC_USEPROXY 1148
+#define IDC_PROXYAUTH 1149
+#define IDC_PROXYHOST 1150
+#define IDC_PROXYPORT 1151
+#define IDC_PROXYUSER 1152
+#define IDC_PROXYPASS 1153
+#define IDC_STATIC12 1155
+#define IDC_STATIC21 1156
+#define IDC_STATIC22 1157
+#define IDC_STATIC31 1158
+#define IDC_STATIC32 1159
+#define IDC_PROXYAUTHNTLM 1160
+#define IDC_CHANGE 1164
+#define IDC_PREVIEW 1165
+#define IDC_CHOOSE 1169
+#define IDC_TO 1170
+#define IDC_VERSION 1179
+#define IDC_ICONSET 1183
+#define IDC_BROWSE 1184
+#define IDC_RUNATSTARTBROWSE 1185
+#define IDC_PAGETREE 1186
+#define IDC_RUNNOW 1186
+#define IDC_RETRIEVING 1193
+#define IDC_GETMORE 1200
+#define IDC_VISIBLEICON 1204
+#define IDC_INVISIBLEICON 1205
+#define IDC_FILEICON 1206
+#define IDC_ONLINEICON 1207
+#define IDC_FILENAMES 1208
+#define IDC_ALLICON 1208
+#define IDC_DONTREPLY 1209
+#define IDC_NONEICON 1209
+#define IDC_USEPREVIOUS 1210
+#define IDC_NODIALOG 1211
+#define IDC_USESPECIFIC 1212
+#define IDC_FILEDIR 1213
+#define IDC_ALLFILESPROGRESS 1217
+#define IDC_CURRENTSPEED 1219
+#define IDC_WHITERECT 1221
+#define IDC_ALLSPEED 1221
+#define IDC_CURRENTFILEPROGRESS 1222
+#define IDC_CURRENTFILEGROUP 1223
+#define IDC_FIRSTNAME 1224
+#define IDC_LASTNAME 1225
+#define IDC_CURRENTTRANSFERRED 1225
+#define IDC_DOBDAY 1226
+#define IDC_DOBMONTH 1227
+#define IDC_WEBPAGE 1228
+#define IDC_DOBYEAR 1228
+#define IDC_UPDATING 1231
+#define IDC_NAMEORDER 1234
+#define IDC_RECONNECTREQD 1239
+#define IDC_IMPORT 1241
+#define IDC_TOMAIN 1243
+#define IDC_TOPROTO 1244
+#define IDC_PROTOLIST 1245
+#define IDC_TODEFICON 1246
+#define IDC_IMPORTMULTI 1247
+#define IDC_FILENAME 1271
+#define IDC_INTERESTS 1305
+#define IDC_EMAILS 1306
+#define IDC_PAST 1307
+#define IDC_PHONES 1308
+#define IDC_SMS 1310
+#define IDC_AREA 1312
+#define IDC_UPDATE 1313
+#define IDC_ININAME 1333
+#define IDC_VIEWINI 1334
+#define IDC_SECURITYINFO 1335
+#define IDC_SETTINGNAME 1336
+#define IDC_NEWVALUE 1337
+#define IDC_WARNNOMORE 1338
+#define IDC_DELETE 1339
+#define IDC_RECYCLE 1340
+#define IDC_NEWNAME 1341
+#define IDC_MOVE 1342
+#define IDC_LEAVE 1343
+#define IDC_EXPERT 1346
+#define IDC_CATEGORYLIST 1366
+#define IDC_LOADICONS 1369
+#define IDC_STICONSGROUP 1371
+#define IDC_MSGICON 1375
+#define IDC_URLICON 1376
+#define IDC_STNOPAGE 1377
+#define IDC_STCHECKMARKS 1380
+#define IDC_MIRANDA 1388
+#define IDC_STATUSBAR 1389
+#define IDC_PROTOIDGROUP 1392
+#define IDC_BYPROTOID 1393
+#define IDC_PROTOID 1394
+#define IDC_EMAILGROUP 1395
+#define IDC_BYEMAIL 1396
+#define IDC_STNAMENICK 1397
+#define IDC_NAMEGROUP 1398
+#define IDC_BYNAME 1399
+#define IDC_STNAMEFIRST 1400
+#define IDC_STNAMELAST 1401
+#define IDC_ADVANCEDGROUP 1402
+#define IDC_BYADVANCED 1403
+#define IDC_ADVANCED 1404
+#define IDC_STSIMPLERIGHT 1440
+#define IDC_NETLIBUSERS 1443
+#define IDC_STOFTENPORT 1445
+#define IDC_STATIC51 1446
+#define IDC_STATIC52 1447
+#define IDC_STATIC43 1448
+#define IDC_LOGOPTIONS 1449
+#define IDC_PORTSRANGE 1450
+#define IDC_STATIC53 1451
+#define IDC_PORTSRANGEO 1452
+#define IDC_STATIC54 1453
+#define IDC_TOOUTPUTDEBUGSTRING 1455
+#define IDC_TOFILE 1456
+#define IDC_RUNATSTART 1458
+#define IDC_DUMPSENT 1464
+#define IDC_DUMPPROXY 1466
+#define IDC_TEXTDUMPS 1467
+#define IDC_AUTODETECTTEXT 1468
+#define IDC_TIMEFORMAT 1469
+#define IDC_FILENAMEBROWSE 1470
+#define IDC_SHOWTHISDLGATSTART 1471
+#define IDC_FILEDIRBROWSE 1475
+#define IDC_ALLFILESGROUP 1476
+#define IDC_SCANCMDLINEBROWSE 1476
+#define IDC_ALLTRANSFERRED 1477
+#define IDC_OPENFOLDER 1478
+#define IDC_OPENFILE 1479
+#define IDC_TOTALSIZE 1480
+#define IDC_AUTOACCEPT 1484
+#define IDC_SCANCMDLINE 1485
+#define IDC_WARNBEFOREOPENING 1488
+#define IDC_SCANDURINGDL 1489
+#define IDC_SCANAFTERDL 1490
+#define IDC_NOSCANNER 1491
+#define IDC_ST_CMDLINE 1492
+#define IDC_ST_CMDLINEHELP 1493
+#define IDC_PROPERTIES 1496
+#define IDC_RESUME 1497
+#define IDC_EXISTINGICON 1499
+#define IDC_RESUMEALL 1500
+#define IDC_OVERWRITE 1501
+#define IDC_OVERWRITEALL 1502
+#define IDC_SKIP 1503
+#define IDC_EXISTINGSIZE 1506
+#define IDC_EXISTINGDATE 1507
+#define IDC_EXISTINGTYPE 1508
+#define IDC_NEWICON 1509
+#define IDC_NEWSIZE 1510
+#define IDC_NEWDATE 1511
+#define IDC_NEWTYPE 1512
+#define IDC_SAVEAS 1513
+#define IDC_ASK 1516
+#define IDC_RENAME 1519
+#define IDC_VIRUSSCANNERGROUP 1520
+#define IDC_HIDE 1534
+#define IDC_TOPLINE 1535
+#define IDC_MAIL 1536
+#define IDC_DESCRIPTION 1538
+#define IDC_MYHANDLE 1540
+#define IDC_GROUP 1541
+#define IDC_ADDED 1542
+#define IDC_AUTH 1543
+#define IDC_DELETEHISTORY 1560
+#define IDC_AUTHREQ 1577
+#define IDC_AUTHGB 1578
+#define IDC_PROTOCOL 1580
+#define IDC_CONTRIBLINK 1586
+#define IDC_DEVS 1589
+#define IDC_LOGO 1591
+#define IDC_IDLEONWINDOWS 1637
+#define IDC_IDLEONMIRANDA 1638
+#define IDC_SCREENSAVER 1642
+#define IDC_LOCKED 1643
+#define IDC_IDLESHORT 1644
+#define IDC_IDLE1STTIME 1646
+#define IDC_IDLEPRIVATE 1649
+#define IDC_AASTATUS 1650
+#define IDC_AASHORTIDLE 1651
+#define IDC_SOUNDTREE 1657
+#define IDC_LOCATION 1659
+#define IDC_SGROUP 1660
+#define IDC_SLOC 1661
+#define IDC_PROFILENAME 1673
+#define IDC_PROFILEDRIVERS 1674
+#define IDC_PLUGLIST 1676
+#define IDC_PLUGINLONGINFO 1677
+#define IDC_PLUGINAUTHOR 1679
+#define IDC_PLUGININFOFRAME 1680
+#define IDC_PLUGINCPYR 1681
+#define IDC_PLUGINURL 1682
+#define IDC_PLUGINEMAIL 1684
+#define IDC_IDLESPIN 1687
+#define IDC_NODBDRIVERS 1690
+#define IDC_IDLESTATUSLOCK 1691
+#define IDC_RESTART 1692
+#define IDI_SEARCHALL 32548
+#define ID_ICQ_EXIT 40001
+#define IDM_COPY 40001
+#define ID_RESET 40002
+#define POPUP_HIDEEMPTYGROUPS 40003
+#define POPUP_NEWSUBGROUP 40004
+#define POPUP_HIDEOFFLINE 40005
+#define POPUP_GROUPHIDEOFFLINE 40006
+#define POPUP_HIDEOFFLINEROOT 40007
+#define POPUP_DISABLEGROUPS 40008
+#define IDC_SENDMESSAGE 40009
+#define IDM_COPYALL 40011
+#define IDM_SELECTALL 40012
+#define IDM_CLEAR 40013
+#define IDM_OPENNEW 40014
+#define IDM_OPENEXISTING 40015
+#define IDM_COPYLINK 40016
+#define POPUP_HIDEMIRANDA 40017
+#define ID_TRAY_HIDE 40038
+#define ID_TRAY_EXIT 40040
+#define POPUP_NEWGROUP 40050
+#define POPUP_RENAMEGROUP 40052
+#define POPUP_DELETEGROUP 40053
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 274
+#define _APS_NEXT_COMMAND_VALUE 40018
+#define _APS_NEXT_CONTROL_VALUE 1693
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/miranda-wine/src/resource.rc b/miranda-wine/src/resource.rc
new file mode 100644
index 0000000..688efbd
--- /dev/null
+++ b/miranda-wine/src/resource.rc
@@ -0,0 +1,1765 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include <windows.h>
+#include <winres.h>
+#include "../include/statusmodes.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
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_AUTHREQ DIALOGEX 0, 0, 242, 107
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Authorization Request"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "&Authorize",IDOK,66,88,50,14
+ PUSHBUTTON "&Deny",IDCANCEL,132,88,50,14
+ CONTROL "&U",IDC_ADD,"MButtonClass",WS_TABSTOP,201,4,16,14,
+ 0x18000000L
+ CONTROL "&I",IDC_DETAILS,"MButtonClass",WS_TABSTOP,219,4,16,14,
+ 0x18000000L
+ LTEXT "",IDC_NAME,53,24,134,10,SS_CENTERIMAGE
+ LTEXT "",IDC_MAIL,53,39,110,10,SS_CENTERIMAGE
+ LTEXT "",IDC_UIN,20,7,178,10,SS_CENTERIMAGE
+ EDITTEXT IDC_REASON,53,58,182,26,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_READONLY | NOT WS_BORDER | WS_VSCROLL,
+ WS_EX_STATICEDGE
+ LTEXT "Nick:",IDC_STATIC,7,24,40,10,SS_CENTERIMAGE
+ LTEXT "E-mail:",IDC_STATIC,7,39,40,10,SS_CENTERIMAGE
+ LTEXT "Reason:",IDC_STATIC,7,55,40,10,SS_CENTERIMAGE
+ CONTROL "",IDC_PROTOCOL,"Button",BS_OWNERDRAW | WS_TABSTOP,4,6,
+ 12,12
+END
+
+IDD_DENYREASON DIALOGEX 0, 0, 172, 70
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Enter a reason for denial"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ EDITTEXT IDC_REASON,6,6,160,36,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_WANTRETURN
+ DEFPUSHBUTTON "&Send",IDOK,61,50,50,14
+END
+
+IDD_ADDCONTACT DIALOGEX 0, 0, 230, 151
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Add %s"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "&Add",IDOK,20,130,72,14
+ PUSHBUTTON "&Cancel",IDCANCEL,139,130,71,14
+ EDITTEXT IDC_MYHANDLE,6,16,90,12,ES_AUTOHSCROLL
+ COMBOBOX IDC_GROUP,112,16,110,60,CBS_DROPDOWNLIST | CBS_SORT |
+ WS_VSCROLL | WS_TABSTOP
+ CONTROL "Send ""You were added""",IDC_ADDED,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,11,46,204,10
+ CONTROL "Send authorization request",IDC_AUTH,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,11,60,204,10
+ LTEXT "Custom name:",IDC_STATIC,6,4,70,10
+ LTEXT "Group:",IDC_STATIC,112,4,70,10
+ GROUPBOX "Options",IDC_STATIC,7,33,216,43
+ GROUPBOX "Authorization Request",IDC_AUTHGB,7,79,216,45
+ EDITTEXT IDC_AUTHREQ,13,89,204,29,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_WANTRETURN | WS_VSCROLL
+END
+
+IDD_ADDED DIALOGEX 0, 0, 225, 57
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "You Were Added"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ PUSHBUTTON "&Close",IDCANCEL,83,38,60,14
+ CTEXT "You were added to this user's contact list.",IDC_STATIC,
+ 7,19,210,14,SS_CENTERIMAGE
+ EDITTEXT IDC_NAME,17,5,160,12,ES_READONLY | NOT WS_BORDER
+ CONTROL "&I",IDC_DETAILS,"MButtonClass",WS_TABSTOP,201,3,16,14,
+ 0x18000000L
+ CONTROL "&U",IDC_ADD,"MButtonClass",WS_TABSTOP,183,3,16,14,
+ 0x18000000L
+ CONTROL "",IDC_PROTOCOL,"Button",BS_OWNERDRAW | WS_TABSTOP,4,4,
+ 12,12
+END
+
+IDD_ABOUT DIALOGEX 0, 0, 212, 131
+STYLE DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP |
+ WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "About Miranda IM"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "",IDC_WHITERECT,0,0,213,105
+ DEFPUSHBUTTON "OK",IDOK,152,112,55,14
+ LTEXT "Miranda IM",IDC_MIRANDA,5,7,150,15
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,106,213,1
+ LTEXT "",IDC_DEVS,5,44,202,42
+ ICON IDI_MIRANDA,IDC_LOGO,187,2,20,20
+ EDITTEXT IDC_BUILDTIME,4,91,146,12,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ PUSHBUTTON "Credits >",IDC_CONTRIBLINK,5,112,55,14
+ LTEXT "Version",IDC_VERSION,5,25,150,15
+ EDITTEXT IDC_CREDITSFILE,4,44,202,56,ES_CENTER | ES_MULTILINE |
+ ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | NOT
+ WS_BORDER | WS_VSCROLL
+END
+
+IDD_DELETECONTACT DIALOGEX 0, 0, 284, 90
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP |
+ WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Delete Contact"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "No",IDNO,162,38,65,14
+ PUSHBUTTON "Yes",IDYES,54,38,65,14
+ CONTROL "Hide from list only, in order to keep their history and ignore/visibility settings",
+ IDC_HIDE,"Button",BS_AUTOCHECKBOX | BS_MULTILINE |
+ WS_TABSTOP,7,65,270,9
+ LTEXT "Use Options->Ignore (expert mode) to unhide contacts.",
+ IDC_STATIC,20,78,257,8
+ CONTROL "Are you sure you want to delete %s?",IDC_TOPLINE,"Static",
+ SS_SIMPLE | SS_NOPREFIX | WS_GROUP,7,7,270,8
+ LTEXT "This will erase all history and settings for this contact!",
+ IDC_STATIC,7,18,239,14
+END
+
+IDD_OPT_CONTACT DIALOGEX 0, 0, 199, 144
+STYLE DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Contact Display Options",IDC_STATIC,13,7,176,127
+ LTEXT "Instead of displaying contacts by their nickname, drag to choose another order:",
+ IDC_STATIC,19,17,165,23
+ CONTROL "Tree1",IDC_NAMEORDER,"SysTreeView32",TVS_NOTOOLTIPS |
+ TVS_FULLROWSELECT | WS_BORDER | WS_TABSTOP,19,43,164,86
+END
+
+IDD_PROFILEMANAGER DIALOGEX 0, 0, 400, 211
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER |
+ WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Miranda IM Profile Manager"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "Tab1",IDC_TABS,"SysTabControl32",TCS_HOTTRACK |
+ WS_TABSTOP,4,31,393,160
+ PUSHBUTTON "&Run",IDOK,298,194,48,14
+ PUSHBUTTON "&Exit",IDCANCEL,348,194,48,14
+ LTEXT "",IDC_WHITERECT,0,0,400,26
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,25,410,1
+ ICON IDI_DETAILSLOGO,IDC_LOGO,7,3,20,20
+ LTEXT "Miranda",IDC_NAME,35,4,360,8,0,WS_EX_TRANSPARENT
+ LTEXT "Select and/or create your Miranda IM user profile",
+ IDC_DESCRIPTION,45,14,349,8,0,WS_EX_TRANSPARENT
+END
+
+IDD_FINDADD DIALOGEX 0, 0, 427, 232
+STYLE DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_MAXIMIZEBOX |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Find/Add Contacts"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Search:",IDC_STATIC,5,7,37,8
+ CONTROL "",IDC_PROTOLIST,"ComboBoxEx32",CBS_DROPDOWNLIST |
+ CBS_SORT | WS_VSCROLL | WS_TABSTOP,42,5,80,88
+ GROUPBOX "",IDC_PROTOIDGROUP,5,21,117,32
+ CONTROL "",IDC_BYPROTOID,"Button",BS_AUTORADIOBUTTON,11,21,85,10
+ EDITTEXT IDC_PROTOID,11,34,105,12,ES_AUTOHSCROLL
+ GROUPBOX "",IDC_EMAILGROUP,5,58,117,32
+ CONTROL "E-mail address",IDC_BYEMAIL,"Button",BS_AUTORADIOBUTTON,
+ 11,58,80,10
+ EDITTEXT IDC_EMAIL,11,71,105,12,ES_AUTOHSCROLL
+ GROUPBOX "",IDC_NAMEGROUP,5,95,117,59
+ CONTROL "Name",IDC_BYNAME,"Button",BS_AUTORADIOBUTTON,11,95,49,
+ 10
+ LTEXT "Nick:",IDC_STNAMENICK,11,110,31,8,NOT WS_GROUP
+ EDITTEXT IDC_NAMENICK,42,108,74,12,ES_AUTOHSCROLL
+ LTEXT "First:",IDC_STNAMEFIRST,11,124,31,8,NOT WS_GROUP
+ EDITTEXT IDC_NAMEFIRST,42,122,74,12,ES_AUTOHSCROLL
+ LTEXT "Last:",IDC_STNAMELAST,11,138,31,8,NOT WS_GROUP
+ EDITTEXT IDC_NAMELAST,42,136,74,12,ES_AUTOHSCROLL
+ GROUPBOX "",IDC_ADVANCEDGROUP,5,159,117,32
+ CONTROL "Advanced",IDC_BYADVANCED,"Button",BS_AUTORADIOBUTTON,11,
+ 159,62,10
+ CONTROL "Advanced >>",IDC_ADVANCED,"Button",BS_AUTOCHECKBOX |
+ BS_PUSHLIKE | WS_TABSTOP,11,171,105,14
+ DEFPUSHBUTTON "&Search",IDOK,5,197,117,17
+ CONTROL "List1",IDC_RESULTS,"SysListView32",LVS_REPORT |
+ LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_AUTOARRANGE |
+ WS_BORDER | WS_TABSTOP,129,5,293,191
+ CONTROL "More options",IDC_MOREOPTIONS,"MButtonClass",
+ WS_DISABLED | WS_TABSTOP,272,200,77,14,0x18000000L
+ PUSHBUTTON "Add to list",IDC_ADD,354,200,68,14,WS_DISABLED
+ CONTROL "",IDC_STATUSBAR,"msctls_statusbar32",WS_TABSTOP | 0x100,
+ 0,220,427,10
+END
+
+IDD_OPTIONS DIALOGEX 0, 0, 428, 271
+STYLE DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX |
+ WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Options"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,266,253,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,320,253,50,14
+ PUSHBUTTON "Apply",IDC_APPLY,374,253,50,14
+ CONTROL "Tree1",IDC_PAGETREE,"SysTreeView32",TVS_HASBUTTONS |
+ TVS_HASLINES | TVS_LINESATROOT | TVS_DISABLEDRAGDROP |
+ TVS_SHOWSELALWAYS | TVS_TRACKSELECT | WS_TABSTOP,4,4,102,
+ 247,WS_EX_STATICEDGE
+ CONTROL "Show expert options",IDC_EXPERT,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,5,257,102,10
+ CTEXT "Please select a subentry from the list",IDC_STNOPAGE,
+ 111,4,313,240,SS_CENTERIMAGE
+END
+
+IDD_READAWAYMSG DIALOGEX 0, 0, 187, 72
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "%s Message for %s"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "&Cancel",IDOK,69,53,50,14
+ CTEXT "Retrieving %s message...",IDC_RETRIEVING,5,21,177,8,
+ SS_NOPREFIX
+ EDITTEXT IDC_MSG,5,5,177,43,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_READONLY | NOT WS_VISIBLE | WS_VSCROLL
+END
+
+IDD_SETAWAYMSG DIALOGEX 0, 0, 187, 72
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Change %s Message"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "Closing in %d",IDOK,61,53,65,14
+ EDITTEXT IDC_MSG,5,5,177,43,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_WANTRETURN | WS_VSCROLL
+END
+
+IDD_DETAILS DIALOGEX 0, 0, 318, 210
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "%s: User Details"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,263,191,50,14
+ LTEXT "",IDC_WHITERECT,0,0,318,26
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,26,320,1
+ ICON IDI_DETAILSLOGO,IDC_LOGO,7,4,20,20
+ LTEXT "",IDC_NAME,33,5,200,8,0,WS_EX_TRANSPARENT
+ CONTROL "",IDC_PAGETREE,"SysTreeView32",TVS_DISABLEDRAGDROP |
+ TVS_SHOWSELALWAYS | TVS_NOTOOLTIPS | TVS_TRACKSELECT |
+ TVS_FULLROWSELECT | TVS_NONEVENHEIGHT | WS_TABSTOP,3,30,76,176,
+ WS_EX_STATICEDGE
+ CONTROL "Tab1",IDC_TABS,"SysTabControl32",TCS_HOTTRACK |
+ TCS_MULTILINE | WS_TABSTOP,85,29,228,158
+ LTEXT "View personal user details and more.",IDC_STATIC,44,13,
+ 189,8,0,WS_EX_TRANSPARENT
+ CTEXT "Updating",IDC_UPDATING,145,194,113,8,SS_NOPREFIX |
+ SS_CENTERIMAGE
+ PUSHBUTTON "Update Now",IDC_UPDATE,85,191,55,14,WS_DISABLED
+END
+
+IDD_INFO_SUMMARY 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 "Nickname:",IDC_STATIC,5,5,46,8
+ EDITTEXT IDC_NICK,51,5,166,8,ES_AUTOHSCROLL | ES_READONLY | NOT
+ WS_BORDER
+ LTEXT "First name:",IDC_STATIC,5,18,46,8
+ EDITTEXT IDC_FIRSTNAME,51,18,74,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ LTEXT "Gender:",IDC_STATIC,126,18,44,8
+ EDITTEXT IDC_GENDER,170,18,47,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ LTEXT "Last name:",IDC_STATIC,5,31,46,8
+ EDITTEXT IDC_LASTNAME,51,31,74,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ LTEXT "Age:",IDC_STATIC,126,31,44,8
+ EDITTEXT IDC_AGE,170,31,47,8,ES_AUTOHSCROLL | ES_READONLY | NOT
+ WS_BORDER
+ LTEXT "E-mail:",IDC_STATIC,5,44,46,8
+ CONTROL "",IDC_EMAIL,"Hyperlink",WS_TABSTOP,51,44,166,8
+ LTEXT "Date of birth:",IDC_STATIC,5,58,46,8
+ EDITTEXT IDC_DOBDAY,51,58,17,8,ES_RIGHT | ES_AUTOHSCROLL |
+ ES_READONLY | NOT WS_BORDER
+ EDITTEXT IDC_DOBMONTH,68,58,19,8,ES_CENTER | ES_AUTOHSCROLL |
+ ES_READONLY | NOT WS_BORDER
+ EDITTEXT IDC_DOBYEAR,87,58,25,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+END
+
+IDD_INFO_CONTACT 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 "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_INFO_BACKGROUND 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 "Web page:",IDC_STATIC,5,5,44,8
+ CONTROL "",IDC_WEBPAGE,"Hyperlink",WS_TABSTOP,49,5,168,8
+ LTEXT "Past background:",IDC_STATIC,5,18,212,8
+ CONTROL "List1",IDC_PAST,"SysListView32",LVS_REPORT |
+ LVS_SINGLESEL | LVS_NOLABELWRAP | LVS_AUTOARRANGE |
+ LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER |
+ WS_TABSTOP,5,27,212,44
+ LTEXT "Interests:",IDC_STATIC,5,74,212,8
+ CONTROL "List1",IDC_INTERESTS,"SysListView32",LVS_REPORT |
+ LVS_SINGLESEL | LVS_NOLABELWRAP | LVS_AUTOARRANGE |
+ LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER |
+ WS_TABSTOP,5,83,212,44
+END
+
+IDD_INFO_NOTES 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 "About:",IDC_STATIC,5,5,212,8
+ EDITTEXT IDC_ABOUT,5,13,212,45,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_READONLY | WS_VSCROLL
+ LTEXT "My notes:",IDC_STATIC,5,61,212,8
+ EDITTEXT IDC_MYNOTES,5,69,212,58,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_WANTRETURN | WS_VSCROLL
+END
+
+IDD_INFO_LOCATION 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 "Street:",IDC_STATIC,5,5,51,8
+ EDITTEXT IDC_STREET,56,5,161,16,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "City:",IDC_STATIC,5,22,51,8
+ EDITTEXT IDC_CITY,56,22,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT
+ WS_BORDER
+ LTEXT "State:",IDC_STATIC,5,33,51,8
+ EDITTEXT IDC_STATE,56,33,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT
+ WS_BORDER
+ LTEXT "Postal code:",IDC_STATIC,5,44,51,8
+ EDITTEXT IDC_ZIP,56,44,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT
+ WS_BORDER
+ LTEXT "Country:",IDC_STATIC,5,55,51,8
+ EDITTEXT IDC_COUNTRY,56,55,161,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ LTEXT "Spoken languages:",IDC_STATIC,5,70,51,16
+ EDITTEXT IDC_LANGUAGE1,56,70,161,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ EDITTEXT IDC_LANGUAGE2,56,78,161,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ EDITTEXT IDC_LANGUAGE3,56,86,161,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ LTEXT "Timezone:",IDC_STATIC,5,97,51,8
+ EDITTEXT IDC_TIMEZONE,56,97,161,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ LTEXT "Local time:",IDC_STATIC,5,108,51,8
+ EDITTEXT IDC_LOCALTIME,56,108,161,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+END
+
+IDD_INFO_WORK 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 "Company:",IDC_STATIC,5,5,51,8
+ EDITTEXT IDC_COMPANY,56,5,161,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ LTEXT "Department:",IDC_STATIC,5,17,51,8
+ EDITTEXT IDC_DEPARTMENT,56,17,161,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ LTEXT "Position:",IDC_STATIC,5,28,51,8
+ EDITTEXT IDC_POSITION,56,28,161,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ LTEXT "Street:",IDC_STATIC,5,48,51,8
+ EDITTEXT IDC_STREET,56,48,161,16,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "City:",IDC_STATIC,5,65,51,8
+ EDITTEXT IDC_CITY,56,65,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT
+ WS_BORDER
+ LTEXT "State:",IDC_STATIC,5,76,51,8
+ EDITTEXT IDC_STATE,56,76,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT
+ WS_BORDER
+ LTEXT "Postal code:",IDC_STATIC,5,87,51,8
+ EDITTEXT IDC_ZIP,56,87,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT
+ WS_BORDER
+ LTEXT "Country:",IDC_STATIC,5,98,51,8
+ EDITTEXT IDC_COUNTRY,56,98,161,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ LTEXT "Website:",IDC_STATIC,5,109,51,8
+ CONTROL "",IDC_WEBPAGE,"Hyperlink",WS_TABSTOP,57,109,160,8
+END
+
+IDD_ADDEMAIL DIALOGEX 0, 0, 187, 42
+STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Add E-Mail Address"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ EDITTEXT IDC_EMAIL,5,5,177,12,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,36,23,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,102,23,50,14
+END
+
+IDD_ADDPHONE DIALOGEX 0, 0, 210, 91
+STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Add Phone Number"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Enter country, area code and phone number:",IDC_STATIC,
+ 5,5,200,8
+ COMBOBOX IDC_COUNTRY,21,15,66,120,CBS_DROPDOWNLIST | CBS_SORT |
+ WS_VSCROLL | WS_TABSTOP
+ EDITTEXT IDC_AREA,91,15,36,12,ES_AUTOHSCROLL | ES_NUMBER
+ EDITTEXT IDC_NUMBER,131,15,74,12,ES_AUTOHSCROLL | ES_NUMBER
+ LTEXT "Or enter a full international number:",IDC_STATIC,5,30,
+ 200,8
+ EDITTEXT IDC_PHONE,21,40,184,12,ES_AUTOHSCROLL
+ CONTROL "Phone can receive SMS text messages",IDC_SMS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,5,56,200,10
+ DEFPUSHBUTTON "OK",IDOK,47,72,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,113,72,50,14
+END
+
+IDD_INSTALLINI DIALOGEX 0, 0, 213, 103
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Install Database Settings"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "Yes",IDOK,26,84,50,14
+ PUSHBUTTON "No",IDCANCEL,81,84,50,14
+ LTEXT "A file containing new database settings has been placed in the Miranda IM directory.",
+ IDC_STATIC,5,5,203,16
+ LTEXT "Do you want to import the settings now?",IDC_STATIC,5,
+ 69,203,8
+ PUSHBUTTON "No to all",IDC_NOTOALL,136,84,50,14
+ LTEXT "",IDC_ININAME,5,24,143,16,SS_NOPREFIX | SS_CENTERIMAGE
+ PUSHBUTTON "&View contents",IDC_VIEWINI,150,25,58,14
+ LTEXT "Security systems to prevent malicious changes are in place and you will be warned before changes that are not known to be safe.",
+ IDC_SECURITYINFO,5,43,203,24
+END
+
+IDD_WARNINICHANGE DIALOGEX 0, 0, 187, 113
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Database Setting Change"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Database settings are being imported from",IDC_STATIC,5,
+ 5,177,8
+ CONTROL "",IDC_ININAME,"Static",SS_SIMPLE | SS_NOPREFIX |
+ WS_GROUP,5,13,177,8
+ LTEXT "This file wishes to change the setting",IDC_STATIC,5,24,
+ 177,8
+ CONTROL "",IDC_SETTINGNAME,"Static",SS_SIMPLE | SS_NOPREFIX |
+ WS_GROUP,12,33,170,8
+ LTEXT "to the value",IDC_STATIC,5,42,177,8
+ CONTROL "",IDC_NEWVALUE,"Static",SS_SIMPLE | SS_NOPREFIX |
+ WS_GROUP,12,51,170,8
+ LTEXT "",IDC_SECURITYINFO,5,60,177,8
+ LTEXT "Do you want to allow this change?",IDC_STATIC,5,71,177,
+ 8
+ CONTROL "&Allow all further changes to this section",
+ IDC_WARNNOMORE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,
+ 80,169,10
+ DEFPUSHBUTTON "&Yes",IDYES,5,94,50,14
+ PUSHBUTTON "&No",IDNO,59,94,50,14
+ PUSHBUTTON "Cancel Import",IDCANCEL,123,94,59,14
+END
+
+IDD_INIIMPORTDONE DIALOGEX 0, 0, 186, 73
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Database Import Complete"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "The import has completed from",IDC_STATIC,5,5,176,8
+ CONTROL "",IDC_ININAME,"Static",SS_SIMPLE | SS_NOPREFIX |
+ WS_GROUP,5,13,176,8
+ LTEXT "What do you want to do with the file now?",IDC_STATIC,5,
+ 24,176,8
+ PUSHBUTTON "&Recycle",IDC_RECYCLE,5,36,50,14
+ PUSHBUTTON "&Delete",IDC_DELETE,68,36,50,14
+ EDITTEXT IDC_NEWNAME,5,55,117,12,ES_AUTOHSCROLL
+ PUSHBUTTON "&Move/Rename",IDC_MOVE,124,54,57,14
+ PUSHBUTTON "&Leave",IDC_LEAVE,131,36,50,14
+END
+
+IDD_NETLIBLOGOPTS DIALOGEX 0, 0, 261, 201
+STYLE DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP |
+ WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Netlib Log Options"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Show",IDC_STATIC,5,5,250,78
+ CONTROL "Sent bytes",IDC_DUMPSENT,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,148,17,65,10
+ CONTROL "Received bytes",IDC_DUMPRECV,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,13,17,133,10
+ CONTROL "Additional data due to proxy communication",
+ IDC_DUMPPROXY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,
+ 28,234,10
+ CONTROL "Text dumps where available",IDC_TEXTDUMPS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,13,39,133,10
+ CONTROL "Auto-detect text",IDC_AUTODETECTTEXT,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,148,39,99,10
+ COMBOBOX IDC_TIMEFORMAT,13,52,164,69,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ CONTROL "Calling modules' names",IDC_SHOWNAMES,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,13,66,234,10
+ GROUPBOX "Log to",IDC_STATIC,5,87,250,43
+ CONTROL "OutputDebugString()",IDC_TOOUTPUTDEBUGSTRING,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,13,100,122,10
+ CONTROL "File",IDC_TOFILE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 13,113,42,10
+ EDITTEXT IDC_FILENAME,56,112,173,12,ES_AUTOHSCROLL
+ PUSHBUTTON "...",IDC_FILENAMEBROWSE,232,112,15,12
+ CONTROL "Show this dialog box when Miranda IM starts",
+ IDC_SHOWTHISDLGATSTART,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,5,135,250,10
+ LTEXT "Run programme when Miranda IM starts (eg tail -f, dbgview, etc):",
+ IDC_STATIC,5,147,250,8
+ EDITTEXT IDC_RUNATSTART,13,158,170,12,ES_AUTOHSCROLL
+ PUSHBUTTON "...",IDC_RUNATSTARTBROWSE,186,158,15,12
+ PUSHBUTTON "Run now",IDC_RUNNOW,205,158,42,12
+ PUSHBUTTON "Save as default",IDC_SAVE,5,182,77,14
+ DEFPUSHBUTTON "Close",IDOK,205,182,50,14
+END
+
+IDD_HISTORY_FIND DIALOGEX 0, 0, 230, 46
+STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Find"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ EDITTEXT IDC_FINDWHAT,48,11,115,12,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "&Find Next",IDOK,173,7,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,173,24,50,14
+ LTEXT "Find What:",IDC_STATIC,7,13,39,9
+END
+
+IDD_FILESEND DIALOGEX 0, 0, 256, 177
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CAPTION |
+ WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Send File(s)"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ EDITTEXT IDC_MSG,6,102,245,46,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_WANTRETURN | WS_VSCROLL
+ DEFPUSHBUTTON "&Send",IDOK,67,157,50,15
+ PUSHBUTTON "Cancel",IDCANCEL,140,157,50,15
+ LTEXT "To:",IDC_STATIC,6,23,24,9,SS_CENTERIMAGE
+ CONTROL "",IDC_TO,"Static",SS_SIMPLE | SS_NOPREFIX | WS_GROUP,43,
+ 24,159,9
+ LTEXT "File(s):",IDC_STATIC,7,39,30,8
+ EDITTEXT IDC_FILE,38,38,213,31,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_READONLY
+ PUSHBUTTON "&Choose Again...",IDC_CHOOSE,39,74,77,14
+ RTEXT "Total size:",IDC_STATIC,119,76,68,8
+ CONTROL "",IDC_TOTALSIZE,"Static",SS_SIMPLE | SS_NOPREFIX |
+ WS_GROUP,191,76,58,8
+ LTEXT "Description:",IDC_STATIC,6,93,96,8
+ CONTROL "6",IDC_USERMENU,"MButtonClass",WS_TABSTOP,195,5,16,14,
+ 0x18000000L
+ CONTROL "&D",IDC_DETAILS,"MButtonClass",WS_TABSTOP,213,5,16,14,
+ 0x18000000L
+ CONTROL "&H",IDC_HISTORY,"MButtonClass",WS_TABSTOP,231,5,16,14,
+ 0x18000000L
+ CONTROL "",IDC_PROTOCOL,"Button",BS_OWNERDRAW | WS_TABSTOP,5,7,
+ 12,12
+ LTEXT "",IDC_NAME,19,7,151,9,SS_NOPREFIX | SS_CENTERIMAGE
+END
+
+IDD_FILERECV DIALOGEX 0, 0, 256, 174
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER |
+ WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CAPTION |
+ WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Incoming File Transfer"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "A&ccept",IDOK,68,155,50,14
+ PUSHBUTTON "&Decline",IDCANCEL,138,155,50,14
+ LTEXT "From:",IDC_STATIC,6,20,24,9,SS_CENTERIMAGE
+ CONTROL "",IDC_FROM,"Static",SS_SIMPLE | SS_NOPREFIX | WS_GROUP,
+ 39,21,159,9
+ LTEXT "Date:",IDC_STATIC,6,35,28,9,SS_CENTERIMAGE
+ CONTROL "",IDC_DATE,"Static",SS_SIMPLE | SS_NOPREFIX | WS_GROUP,
+ 39,34,159,9
+ LTEXT "Files:",IDC_STATIC,6,50,28,8
+ EDITTEXT IDC_FILENAMES,39,50,210,16,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_READONLY | NOT WS_BORDER
+ LTEXT "Description:",IDC_STATIC,6,69,64,8
+ EDITTEXT IDC_MSG,6,79,243,45,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_READONLY
+ LTEXT "Save to:",IDC_STATIC,6,131,34,8
+ PUSHBUTTON "...",IDC_FILEDIRBROWSE,235,130,14,10
+ COMBOBOX IDC_FILEDIR,45,129,187,108,CBS_DROPDOWN |
+ CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP
+ CONTROL "&A",IDC_ADD,"MButtonClass",WS_TABSTOP,177,5,16,14,
+ 0x18000000L
+ CONTROL "6",IDC_USERMENU,"MButtonClass",WS_TABSTOP,195,5,16,14,
+ 0x18000000L
+ CONTROL "&D",IDC_DETAILS,"MButtonClass",WS_TABSTOP,213,5,16,14,
+ 0x18000000L
+ CONTROL "&H",IDC_HISTORY,"MButtonClass",WS_TABSTOP,231,5,16,14,
+ 0x18000000L
+ CONTROL "",IDC_PROTOCOL,"Button",BS_OWNERDRAW | WS_TABSTOP,5,7,
+ 12,12
+ LTEXT "",IDC_NAME,19,7,151,9,SS_NOPREFIX | SS_CENTERIMAGE
+END
+
+IDD_FILETRANSFERINFO DIALOGEX 0, 0, 256, 155
+STYLE DS_3DLOOK | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "Cancel",IDCANCEL,162,136,89,14
+ LTEXT "Status:",IDC_STATIC,9,0,31,9,SS_CENTERIMAGE
+ CONTROL "",IDC_STATUS,"Static",SS_SIMPLE | SS_NOPREFIX |
+ WS_GROUP,41,0,210,9
+ GROUPBOX "Current file",IDC_CURRENTFILEGROUP,5,13,246,62
+ CONTROL "",IDC_FILENAME,"Static",SS_LEFTNOWORDWRAP | SS_NOPREFIX |
+ WS_GROUP,11,25,234,8
+ CONTROL "Transferred:",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP |
+ SS_NOPREFIX,11,36,58,8
+ CONTROL "",IDC_CURRENTTRANSFERRED,"Static",SS_LEFTNOWORDWRAP |
+ SS_NOPREFIX | WS_GROUP,69,36,176,8
+ CONTROL "Speed:",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP |
+ SS_NOPREFIX,11,47,58,8
+ CONTROL "",IDC_CURRENTSPEED,"Static",SS_LEFTNOWORDWRAP |
+ SS_NOPREFIX | WS_GROUP,69,47,176,8
+ CONTROL "Progress1",IDC_CURRENTFILEPROGRESS,"msctls_progress32",
+ PBS_SMOOTH | WS_DISABLED,11,59,234,8
+ GROUPBOX "All files",IDC_ALLFILESGROUP,5,79,246,51
+ CONTROL "Transferred:",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP |
+ SS_NOPREFIX,11,91,58,8
+ CONTROL "",IDC_ALLTRANSFERRED,"Static",SS_LEFTNOWORDWRAP |
+ SS_NOPREFIX | WS_GROUP,69,91,176,8
+ CONTROL "Speed:",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP |
+ SS_NOPREFIX,11,102,58,8
+ CONTROL "",IDC_ALLSPEED,"Static",SS_LEFTNOWORDWRAP | SS_NOPREFIX |
+ WS_GROUP,69,102,176,8
+ CONTROL "Progress1",IDC_ALLFILESPROGRESS,"msctls_progress32",
+ PBS_SMOOTH | WS_DISABLED,11,114,234,8
+ PUSHBUTTON "Open folder",IDC_OPENFOLDER,5,136,64,14
+ CONTROL "Open file",IDC_OPENFILE,"MButtonClass",WS_DISABLED |
+ WS_TABSTOP,75,136,66,14,0x18000000L
+END
+
+IDD_FILEEXISTS DIALOGEX 0, 0, 288, 181
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP |
+ WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "File Already Exists"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ PUSHBUTTON "Resume",IDC_RESUME,5,144,65,14
+ PUSHBUTTON "Resume all",IDC_RESUMEALL,5,162,65,14
+ PUSHBUTTON "Overwrite",IDC_OVERWRITE,76,144,65,14
+ PUSHBUTTON "Overwrite all",IDC_OVERWRITEALL,76,162,65,14
+ PUSHBUTTON "Save as...",IDC_SAVEAS,147,144,65,14
+ PUSHBUTTON "Skip",IDC_SKIP,218,144,65,14
+ PUSHBUTTON "Cancel transfer",IDCANCEL,218,162,65,14
+ LTEXT "You are about to receive the file",IDC_STATIC,5,5,278,8
+ EDITTEXT IDC_FILENAME,15,16,268,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ GROUPBOX "Existing file",IDC_STATIC,5,29,278,61
+ ICON "",IDC_EXISTINGICON,14,45,20,20,SS_NOTIFY
+ LTEXT "Size:",IDC_STATIC,40,42,27,8
+ LTEXT "",IDC_EXISTINGSIZE,67,42,35,8
+ RTEXT "Last modified:",IDC_STATIC,103,42,58,8
+ LTEXT "",IDC_EXISTINGDATE,166,42,115,8
+ LTEXT "Type:",IDC_STATIC,40,55,27,8
+ LTEXT "",IDC_EXISTINGTYPE,67,55,214,8
+ PUSHBUTTON "Open file",IDC_OPENFILE,12,70,62,13
+ PUSHBUTTON "Open folder",IDC_OPENFOLDER,82,70,62,13
+ PUSHBUTTON "File properties",IDC_PROPERTIES,201,70,74,13
+ GROUPBOX "File being received",IDC_STATIC,5,95,278,42
+ ICON "",IDC_NEWICON,14,110,20,20,SS_NOTIFY
+ LTEXT "Size:",IDC_STATIC,40,108,27,8
+ LTEXT "",IDC_NEWSIZE,67,108,35,8
+ RTEXT "Last modified:",IDC_STATIC,103,108,58,8
+ LTEXT "",IDC_NEWDATE,166,108,115,8
+ LTEXT "Type:",IDC_STATIC,40,121,27,8
+ LTEXT "",IDC_NEWTYPE,67,121,214,8
+END
+
+IDD_URLSEND DIALOGEX 0, 0, 215, 126
+STYLE DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP |
+ WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ COMBOBOX IDC_URLS,5,30,205,92,CBS_DROPDOWN | CBS_AUTOHSCROLL |
+ WS_VSCROLL | WS_TABSTOP
+ EDITTEXT IDC_MESSAGE,5,57,205,44,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_WANTRETURN | WS_VSCROLL
+ DEFPUSHBUTTON "&Send",IDOK,54,107,50,14
+ PUSHBUTTON "&Cancel",IDCANCEL,113,107,50,14
+ CONTROL "",IDC_PROTOCOL,"Button",BS_OWNERDRAW | WS_TABSTOP,5,7,
+ 12,12
+ LTEXT "",IDC_NAME,19,7,118,9,SS_NOPREFIX | SS_CENTERIMAGE
+ CONTROL "&A",IDC_ADD,"MButtonClass",WS_TABSTOP,140,5,16,14,
+ 0x18000000L
+ CONTROL "6",IDC_USERMENU,"MButtonClass",WS_TABSTOP,158,5,16,14,
+ 0x18000000L
+ CONTROL "&D",IDC_DETAILS,"MButtonClass",WS_TABSTOP,176,5,16,14,
+ 0x18000000L
+ CONTROL "&H",IDC_HISTORY,"MButtonClass",WS_TABSTOP,194,5,16,14,
+ 0x18000000L
+ LTEXT "Enter URL:",IDC_ST_ENTERURL,5,20,205,8
+ LTEXT "Enter description:",IDC_ST_ENTERMSG,5,47,205,8
+END
+
+IDD_URLRECV DIALOGEX 0, 0, 215, 140
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER |
+ WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "URL Recieved"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "&Open URL",IDOK,"MButtonClass",WS_TABSTOP,11,120,57,14,
+ 0x18000000L
+ PUSHBUTTON "&Reply",IDC_REPLY,82,120,50,14
+ PUSHBUTTON "&Close",IDCANCEL,148,120,50,14
+ CONTROL "",IDC_PROTOCOL,"Button",BS_OWNERDRAW | WS_TABSTOP,5,7,
+ 12,12
+ LTEXT "",IDC_NAME,19,7,118,9,SS_NOPREFIX | SS_CENTERIMAGE
+ CONTROL "&A",IDC_ADD,"MButtonClass",WS_TABSTOP,140,5,16,14,
+ 0x18000000L
+ CONTROL "6",IDC_USERMENU,"MButtonClass",WS_TABSTOP,158,5,16,14,
+ 0x18000000L
+ CONTROL "&D",IDC_DETAILS,"MButtonClass",WS_TABSTOP,176,5,16,14,
+ 0x18000000L
+ CONTROL "&H",IDC_HISTORY,"MButtonClass",WS_TABSTOP,194,5,16,14,
+ 0x18000000L
+ LTEXT "Date:",IDC_STATIC,5,21,29,8
+ EDITTEXT IDC_DATE,34,21,176,12,ES_AUTOHSCROLL | ES_READONLY | NOT
+ WS_BORDER
+ LTEXT "URL:",IDC_STATIC,5,33,205,8
+ EDITTEXT IDC_URL,5,43,205,12,ES_AUTOHSCROLL | ES_READONLY
+ LTEXT "Description:",IDC_ST_ENTERMSG,5,60,205,8
+ EDITTEXT IDC_MSG,5,70,205,44,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_READONLY | WS_VSCROLL
+END
+
+IDD_HISTORY DIALOGEX 0, 0, 296, 166
+STYLE DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE |
+ WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Message History"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "Close",IDOK,239,144,50,14
+ EDITTEXT IDC_EDIT,7,83,282,52,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_READONLY | WS_VSCROLL
+ LISTBOX IDC_LIST,7,7,282,72,LBS_NOINTEGRALHEIGHT | WS_VSCROLL |
+ WS_TABSTOP
+ PUSHBUTTON "&Find...",IDC_FIND,7,144,50,14
+ PUSHBUTTON "Delete",IDC_DELETEHISTORY,66,144,50,14
+END
+
+IDD_OPT_SOUND DIALOGEX 0, 0, 285, 240
+STYLE DS_3DLOOK | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Sounds",IDC_STATIC,4,4,277,154
+ PUSHBUTTON "&Change...",IDC_CHANGE,16,213,50,14
+ PUSHBUTTON "&Preview",IDC_PREVIEW,70,213,50,14
+ CONTROL "Download more sounds",IDC_GETMORE,"Hyperlink",
+ WS_TABSTOP | 0x2,127,216,137,8
+ CONTROL "Tree1",IDC_SOUNDTREE,"SysTreeView32",TVS_HASBUTTONS |
+ TVS_HASLINES | TVS_LINESATROOT | TVS_DISABLEDRAGDROP |
+ TVS_SHOWSELALWAYS | TVS_FULLROWSELECT | WS_BORDER |
+ WS_TABSTOP,12,15,261,137
+ GROUPBOX "Sound Information",IDC_SGROUP,4,162,277,71
+ LTEXT "Location:",IDC_SLOC,17,190,40,9
+ LTEXT "",IDC_LOCATION,65,190,208,18
+ LTEXT "Name:",IDC_NAME,17,174,39,9
+ LTEXT "",IDC_NAMEVAL,64,174,209,9
+END
+
+IDD_OPT_ICONS DIALOGEX 0, 0, 257, 193
+STYLE DS_3DLOOK | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Icons",IDC_STICONSGROUP,4,4,248,185
+ LTEXT "Show category:",IDC_STATIC,12,18,66,16
+ LISTBOX IDC_CATEGORYLIST,114,17,129,41,LBS_NOINTEGRALHEIGHT |
+ WS_VSCROLL | WS_TABSTOP
+ CONTROL "List1",IDC_PREVIEW,"SysListView32",LVS_SINGLESEL |
+ LVS_AUTOARRANGE | WS_BORDER | WS_TABSTOP,12,66,231,83
+ PUSHBUTTON "&Load icon set...",IDC_LOADICONS,12,158,94,13
+ PUSHBUTTON "&Import icons >>",IDC_IMPORT,154,158,89,13
+ CONTROL "Download more icons",IDC_GETMORE,"Hyperlink",WS_TABSTOP |
+ 0x1,12,178,232,8
+ LTEXT "",IDC_STSIMPLERIGHT,200,104,8,32,NOT WS_VISIBLE
+END
+
+IDD_OPT_IGNORE DIALOGEX 0, 0, 313, 240
+STYLE DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "The following events are being ignored:",IDC_STATIC,8,
+ 14,297,8
+ ICON IDI_RECVMSG,IDC_MSGICON,8,172,20,20,SS_CENTERIMAGE
+ LTEXT "Ignore messages",IDC_STATIC,26,178,70,8,SS_NOPREFIX |
+ SS_CENTERIMAGE
+ ICON IDI_URL,IDC_URLICON,8,187,20,20,SS_CENTERIMAGE
+ LTEXT "Ignore URLs",IDC_STATIC,26,193,70,8,SS_NOPREFIX |
+ SS_CENTERIMAGE
+ ICON IDI_FILE,IDC_FILEICON,8,202,20,20,SS_CENTERIMAGE
+ LTEXT "Ignore files",IDC_STATIC,26,208,70,8,SS_NOPREFIX |
+ SS_CENTERIMAGE
+ ICON IDI_MIRANDA,IDC_AUTHICON,96,172,20,20,SS_CENTERIMAGE
+ LTEXT "Suppress auth requests",IDC_STATIC,114,178,107,8,
+ SS_NOPREFIX | SS_CENTERIMAGE
+ ICON IDI_USERONLINE,IDC_ONLINEICON,96,187,20,20,
+ SS_CENTERIMAGE
+ LTEXT "Suppress online notification",IDC_STATIC,114,193,107,8,
+ SS_NOPREFIX | SS_CENTERIMAGE
+ ICON IDI_FILLEDBLOB,IDC_ALLICON,221,172,20,20,SS_CENTERIMAGE
+ LTEXT "Ignore all",IDC_STATIC,239,178,66,8,SS_NOPREFIX |
+ SS_CENTERIMAGE
+ ICON IDI_EMPTYBLOB,IDC_NONEICON,221,187,20,20,SS_CENTERIMAGE
+ LTEXT "Ignore none",IDC_STATIC,239,193,66,8,SS_NOPREFIX |
+ SS_CENTERIMAGE
+ CTEXT "Only the ticked contacts will be shown on the main contact list",
+ IDC_STCHECKMARKS,8,227,297,8
+ CONTROL "",IDC_LIST,"CListControl",WS_TABSTOP | 0x3da,8,26,297,
+ 146,WS_EX_CLIENTEDGE
+ GROUPBOX "Ignore",IDC_STATIC,0,0,313,240
+ ICON IDI_ADDCONTACT,IDC_ADDED,96,202,20,20,SS_CENTERIMAGE
+ LTEXT "Suppress added notification",IDC_STATIC,114,208,107,8,
+ SS_NOPREFIX | SS_CENTERIMAGE
+END
+
+IDD_OPT_VISIBILITY DIALOGEX 0, 0, 313, 240
+STYLE DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ ICON IDI_ONLINE,IDC_VISIBLEICON,8,203,12,12,SS_CENTERIMAGE
+ LTEXT "You are visible to this person even when in invisible mode",
+ IDC_STATIC,26,205,279,8,SS_NOPREFIX | SS_CENTERIMAGE
+ ICON IDI_INVISIBLE,IDC_INVISIBLEICON,8,218,12,12,
+ SS_CENTERIMAGE
+ LTEXT "You are never visible to this person",IDC_STATIC,26,220,
+ 279,8,SS_NOPREFIX | SS_CENTERIMAGE
+ GROUPBOX "Visibility",IDC_STATIC,0,0,313,240
+ CONTROL "",IDC_LIST,"CListControl",WS_TABSTOP | 0x1d0,8,14,297,
+ 183,WS_EX_CLIENTEDGE
+END
+
+IDD_OPT_AWAYMSG DIALOGEX 0, 0, 263, 151
+STYLE DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Status Messages",IDC_STATIC,4,5,255,142
+ COMBOBOX IDC_STATUS,12,19,240,97,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ CONTROL "Do not reply to requests for this message",
+ IDC_DONTREPLY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,24,
+ 37,227,10
+ CONTROL "Do not pop up dialog asking for new message",
+ IDC_NODIALOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,24,50,
+ 227,10
+ CONTROL "By default, use the same message as last time",
+ IDC_USEPREVIOUS,"Button",BS_AUTORADIOBUTTON,23,65,227,10
+ CONTROL "By default, use this message:",IDC_USESPECIFIC,"Button",
+ BS_AUTORADIOBUTTON,23,78,227,10
+ EDITTEXT IDC_MSG,33,91,219,38,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_WANTRETURN | WS_VSCROLL
+ LTEXT "Use %time% for the current time, %date% for the current date",
+ IDC_STATIC,33,131,219,8
+END
+
+IDD_ICONINDEX DIALOGEX 0, 0, 219, 197
+STYLE DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE |
+ WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Icon Index"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ RTEXT "Icon library:",IDC_STATIC,4,6,54,8
+ EDITTEXT IDC_ICONSET,60,4,139,12,ES_AUTOHSCROLL
+ PUSHBUTTON "...",IDC_BROWSE,201,5,14,10
+ LTEXT "Drag icons to main list to assign them:",IDC_STATIC,4,
+ 18,211,8
+ CONTROL "List1",IDC_PREVIEW,"SysListView32",LVS_SINGLESEL |
+ LVS_AUTOARRANGE | WS_BORDER | WS_TABSTOP,4,27,211,82
+ GROUPBOX "Import multiple",IDC_IMPORTMULTI,4,122,211,61
+ CONTROL "To main icons",IDC_TOMAIN,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,8,132,74,12
+ CONTROL "To",IDC_TOPROTO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,
+ 165,25,12
+ COMBOBOX IDC_PROTOLIST,34,164,79,58,CBS_DROPDOWNLIST | CBS_SORT |
+ WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "<< &Import",IDC_IMPORT,164,164,48,14,WS_DISABLED
+ CONTROL "Download more icons",IDC_GETMORE,"Hyperlink",WS_TABSTOP |
+ 0x1,4,185,211,8
+ CONTROL "To default status icons",IDC_TODEFICON,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,8,148,123,12
+END
+
+IDD_OPT_NETLIB DIALOGEX 0, 0, 313, 238
+STYLE DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Incoming connections",IDC_STATIC43,0,173,313,51
+ COMBOBOX IDC_NETLIBUSERS,0,1,231,110,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "Log Options...",IDC_LOGOPTIONS,258,1,55,13
+ CONTROL "Use proxy server",IDC_USEPROXY,"Button",BS_3STATE |
+ WS_TABSTOP,7,29,90,9
+ LTEXT "Proxy type:",IDC_STATIC21,19,43,57,8,WS_DISABLED
+ COMBOBOX IDC_PROXYTYPE,80,40,86,62,CBS_DROPDOWNLIST | WS_DISABLED |
+ WS_VSCROLL | WS_TABSTOP
+ LTEXT "Proxy server:",IDC_STATIC22,19,58,57,8,WS_DISABLED
+ EDITTEXT IDC_PROXYHOST,80,56,86,12,ES_AUTOHSCROLL | WS_DISABLED
+ LTEXT "Port:",IDC_STATIC23,177,58,35,8,WS_DISABLED
+ EDITTEXT IDC_PROXYPORT,213,56,35,12,ES_AUTOHSCROLL | ES_NUMBER |
+ WS_DISABLED
+ LTEXT "(often %d)",IDC_STOFTENPORT,258,57,48,8,WS_DISABLED
+ CONTROL "Proxy requires authorization",IDC_PROXYAUTH,"Button",
+ BS_3STATE | WS_DISABLED | WS_TABSTOP,20,73,154,10
+ LTEXT "Username:",IDC_STATIC31,32,87,47,8,WS_DISABLED
+ EDITTEXT IDC_PROXYUSER,80,85,86,12,ES_AUTOHSCROLL | WS_DISABLED
+ LTEXT "Password:",IDC_STATIC32,177,87,49,8,WS_DISABLED
+ EDITTEXT IDC_PROXYPASS,232,83,74,12,ES_PASSWORD | ES_AUTOHSCROLL |
+ WS_DISABLED
+ CONTROL "Resolve hostnames through proxy",IDC_PROXYDNS,"Button",
+ BS_3STATE | WS_DISABLED | WS_TABSTOP,20,115,154,10
+ CONTROL "Specify ports to be used for incoming connections",
+ IDC_SPECIFYPORTS,"Button",BS_3STATE | BS_TOP |
+ BS_MULTILINE | WS_TABSTOP,7,185,186,9
+ LTEXT "Range:",IDC_STATIC51,19,199,58,8,WS_DISABLED
+ EDITTEXT IDC_PORTSRANGE,80,197,142,12,ES_AUTOHSCROLL |
+ WS_DISABLED
+ LTEXT "Example: 1050-1070, 2000-2010, 2500",IDC_STATIC52,80,
+ 212,196,8,WS_DISABLED
+ CTEXT "You will need to reconnect for the changes you have made on this page to take effect.",
+ IDC_RECONNECTREQD,7,227,307,8,NOT WS_VISIBLE
+ CONTROL "Use NTLM authentication",IDC_PROXYAUTHNTLM,"Button",
+ BS_3STATE | WS_DISABLED | WS_TABSTOP,32,101,154,10
+ GROUPBOX "Outgoing connections",IDC_STATIC12,0,18,313,151
+ CONTROL "Specify ports to be used for outgoing connections",
+ IDC_SPECIFYPORTSO,"Button",BS_3STATE | BS_TOP |
+ BS_MULTILINE | WS_TABSTOP,7,130,186,9
+ LTEXT "Range:",IDC_STATIC53,19,144,58,8,WS_DISABLED
+ EDITTEXT IDC_PORTSRANGEO,80,142,142,12,ES_AUTOHSCROLL |
+ WS_DISABLED
+ LTEXT "Example: 1050-1070, 2000-2010, 2500",IDC_STATIC54,80,
+ 157,196,8,WS_DISABLED
+END
+
+IDD_OPT_FILETRANSFER DIALOGEX 0, 0, 313, 228
+STYLE DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Receiving files",IDC_STATIC,0,0,313,80
+ LTEXT "Received files folder:",IDC_STATIC,8,15,82,8
+ EDITTEXT IDC_FILEDIR,92,13,190,12,ES_AUTOHSCROLL
+ PUSHBUTTON "...",IDC_FILEDIRBROWSE,287,14,15,11
+ CONTROL "Auto-accept incoming files from people on my contact list",
+ IDC_AUTOACCEPT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,
+ 39,294,10
+ CONTROL "Minimize the file transfer window",IDC_AUTOMIN,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,17,52,285,10
+ CONTROL "Close window when transfer completes",IDC_AUTOCLOSE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,65,294,10
+ GROUPBOX "Virus scanner",IDC_VIRUSSCANNERGROUP,0,85,313,93
+ LTEXT "Scan files:",IDC_STATIC,8,97,43,9,SS_CENTERIMAGE
+ CONTROL "Never, do not use virus scanning",IDC_NOSCANNER,"Button",
+ BS_AUTORADIOBUTTON,52,97,250,10
+ CONTROL "When all files have been downloaded",IDC_SCANAFTERDL,
+ "Button",BS_AUTORADIOBUTTON,52,109,250,10
+ CONTROL "As each file finishes downloading",IDC_SCANDURINGDL,
+ "Button",BS_AUTORADIOBUTTON,52,121,250,10
+ LTEXT "Command line:",IDC_ST_CMDLINE,7,137,62,8
+ COMBOBOX IDC_SCANCMDLINE,70,136,213,71,CBS_DROPDOWN |
+ CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "...",IDC_SCANCMDLINEBROWSE,287,137,15,11
+ LTEXT "%f will be replaced by the file or folder name to be scanned",
+ IDC_ST_CMDLINEHELP,70,150,232,8
+ CONTROL "Warn me before opening a file that has not been scanned",
+ IDC_WARNBEFOREOPENING,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,8,163,294,10
+ GROUPBOX "If incoming files already exist",IDC_STATIC,0,183,313,
+ 43
+ CONTROL "Ask me",IDC_ASK,"Button",BS_AUTORADIOBUTTON,8,197,73,10
+ CONTROL "Resume",IDC_RESUME,"Button",BS_AUTORADIOBUTTON,82,197,
+ 125,10
+ CONTROL "Overwrite",IDC_OVERWRITE,"Button",BS_AUTORADIOBUTTON,8,
+ 209,73,10
+ CONTROL "Rename (append "" (1)"", etc.)",IDC_RENAME,"Button",
+ BS_AUTORADIOBUTTON,82,209,125,10
+ LTEXT "You will always be asked about files from people not on your contact list",
+ IDC_STATIC,212,195,90,24
+ LTEXT "Variables Allowed: %userid%, %nick%, %proto%",
+ IDC_STATIC,93,27,167,11,WS_DISABLED
+END
+
+IDD_OPT_IDLE DIALOGEX 0, 0, 312, 172
+STYLE DS_FIXEDSYS | WS_CHILD | WS_BORDER
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "Become idle if the following is left unattended:",
+ IDC_IDLESHORT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,25,
+ 18,259,9
+ CONTROL "Windows",IDC_IDLEONWINDOWS,"Button",BS_AUTORADIOBUTTON,
+ 45,31,104,9
+ CONTROL "Miranda",IDC_IDLEONMIRANDA,"Button",BS_AUTORADIOBUTTON,
+ 45,43,103,9
+ EDITTEXT IDC_IDLE1STTIME,59,59,27,14,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "Spin2",IDC_IDLESPIN,"msctls_updown32",UDS_WRAP |
+ UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_ARROWKEYS |
+ UDS_NOTHOUSANDS | UDS_HOTTRACK,71,55,12,23
+ CONTROL "Become idle if the screen saver is active",
+ IDC_SCREENSAVER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,25,
+ 83,268,9
+ CONTROL "Become idle if the computer is locked (2000/XP+ only)",
+ IDC_LOCKED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,25,99,
+ 249,9
+ CONTROL "Do not let protocols report any idle information",
+ IDC_IDLEPRIVATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,25,
+ 115,251,9
+ LTEXT "minute(s)",IDC_STATIC,91,61,76,9
+ RTEXT "for",IDC_STATIC,12,59,41,9
+ COMBOBOX IDC_AASTATUS,128,130,64,50,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ CONTROL "Change my status mode to:",IDC_AASHORTIDLE,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,25,131,101,11
+ CONTROL "Do not set status back to online when returning from idle",
+ IDC_IDLESTATUSLOCK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 35,148,246,10
+ GROUPBOX "Idle Options",IDC_STATIC,3,3,304,165
+END
+
+IDD_PROFILE_SELECTION DIALOGEX 0, 0, 386, 142
+STYLE DS_FIXEDSYS | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "List1",IDC_PROFILELIST,"SysListView32",LVS_REPORT |
+ LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER |
+ WS_TABSTOP,3,2,382,137
+END
+
+IDD_PROFILE_NEW DIALOGEX 0, 0, 386, 142
+STYLE DS_FIXEDSYS | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Please complete the following form to create a new user profile",
+ IDC_STATIC,7,7,372,10
+ EDITTEXT IDC_PROFILENAME,49,27,75,12,ES_AUTOHSCROLL
+ COMBOBOX IDC_PROFILEDRIVERS,49,72,75,56,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ LTEXT "Profile",IDC_STATIC,20,28,26,9
+ LTEXT "e.g. Workplace",IDC_STATIC,131,28,77,11
+ LTEXT "You can select a different profile driver from the default, it may offer more features or abilities, if in doubt use the default.",
+ IDC_STATIC,7,49,372,17
+ LTEXT "e.g. Miranda Database",IDC_STATIC,131,73,84,11
+ LTEXT "Driver",IDC_STATIC,20,74,23,9
+ LTEXT "Problem: Unable to find any database drivers, this means you can not create a new profile, you need to get dbx_3x.dll",
+ IDC_NODBDRIVERS,7,113,372,22,NOT WS_VISIBLE
+END
+
+IDD_OPT_PLUGINS DIALOGEX 0, 0, 315, 247
+STYLE DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "List1",IDC_PLUGLIST,"SysListView32",LVS_REPORT |
+ LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING |
+ LVS_AUTOARRANGE | LVS_NOSORTHEADER | WS_BORDER |
+ WS_TABSTOP,4,0,306,145
+ EDITTEXT IDC_PLUGINLONGINFO,50,159,253,19,ES_MULTILINE |
+ ES_READONLY | ES_WANTRETURN | NOT WS_BORDER | WS_VSCROLL
+ GROUPBOX "",IDC_PLUGININFOFRAME,4,148,307,80,BS_RIGHT
+ EDITTEXT IDC_PLUGINAUTHOR,50,178,253,12,ES_READONLY |
+ ES_WANTRETURN | NOT WS_BORDER
+ EDITTEXT IDC_PLUGINCPYR,50,190,249,12,ES_AUTOHSCROLL |
+ ES_READONLY | ES_WANTRETURN | NOT WS_BORDER
+ CONTROL "",IDC_PLUGINURL,"Hyperlink",WS_TABSTOP,50,213,254,10
+ CONTROL "",IDC_PLUGINEMAIL,"Hyperlink",WS_TABSTOP,50,201,208,10
+ RTEXT "Description:",IDC_STATIC,8,158,38,10
+ RTEXT "Author(s):",IDC_STATIC,8,177,38,9
+ RTEXT "Copyright:",IDC_STATIC,8,190,38,9
+ RTEXT "E-mail:",IDC_STATIC,8,202,38,8
+ RTEXT "Homepage:",IDC_STATIC,7,213,38,8
+ CTEXT "Please restart Miranda IM for your changes to take effect.",
+ IDC_RESTART,5,233,305,11,NOT WS_VISIBLE
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO MOVEABLE PURE
+BEGIN
+ IDD_AUTHREQ, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 235
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 102
+ END
+
+ IDD_DENYREASON, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 165
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 63
+ END
+
+ IDD_ADDCONTACT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 223
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 144
+ END
+
+ IDD_ADDED, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 217
+ TOPMARGIN, 3
+ BOTTOMMARGIN, 52
+ END
+
+ IDD_ABOUT, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 207
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 126
+ END
+
+ IDD_DELETECONTACT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 277
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 85
+ END
+
+ IDD_OPT_CONTACT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 192
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 137
+ END
+
+ IDD_FINDADD, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 422
+ VERTGUIDE, 11
+ VERTGUIDE, 42
+ VERTGUIDE, 53
+ VERTGUIDE, 116
+ VERTGUIDE, 122
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 227
+ END
+
+ IDD_OPTIONS, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 424
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 267
+ END
+
+ IDD_READAWAYMSG, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 182
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 67
+ END
+
+ IDD_SETAWAYMSG, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 182
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 67
+ END
+
+ IDD_DETAILS, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 233
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 205
+ END
+
+ IDD_INFO_SUMMARY, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ VERTGUIDE, 51
+ VERTGUIDE, 126
+ VERTGUIDE, 170
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ HORZGUIDE, 22
+ HORZGUIDE, 35
+ HORZGUIDE, 48
+ HORZGUIDE, 62
+ END
+
+ IDD_INFO_CONTACT, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ END
+
+ IDD_INFO_BACKGROUND, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ VERTGUIDE, 49
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ END
+
+ IDD_INFO_NOTES, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ END
+
+ IDD_INFO_LOCATION, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ VERTGUIDE, 56
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ HORZGUIDE, 22
+ HORZGUIDE, 33
+ HORZGUIDE, 45
+ HORZGUIDE, 56
+ HORZGUIDE, 70
+ HORZGUIDE, 95
+ HORZGUIDE, 106
+ END
+
+ IDD_INFO_WORK, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ VERTGUIDE, 56
+ VERTGUIDE, 126
+ VERTGUIDE, 170
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ HORZGUIDE, 16
+ HORZGUIDE, 27
+ HORZGUIDE, 44
+ HORZGUIDE, 61
+ HORZGUIDE, 72
+ HORZGUIDE, 83
+ HORZGUIDE, 94
+ HORZGUIDE, 105
+ END
+
+ IDD_ADDEMAIL, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 182
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 37
+ END
+
+ IDD_ADDPHONE, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 205
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 86
+ END
+
+ IDD_INSTALLINI, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 208
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 98
+ END
+
+ IDD_WARNINICHANGE, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 182
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 108
+ END
+
+ IDD_INIIMPORTDONE, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 181
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 68
+ END
+
+ IDD_NETLIBLOGOPTS, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 255
+ VERTGUIDE, 13
+ VERTGUIDE, 148
+ VERTGUIDE, 247
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 196
+ END
+
+ IDD_HISTORY_FIND, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 223
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 39
+ HORZGUIDE, 17
+ END
+
+ IDD_FILESEND, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 251
+ VERTGUIDE, 7
+ VERTGUIDE, 249
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 172
+ END
+
+ IDD_FILERECV, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 249
+ VERTGUIDE, 7
+ VERTGUIDE, 249
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 169
+ END
+
+ IDD_FILETRANSFERINFO, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 251
+ VERTGUIDE, 11
+ VERTGUIDE, 69
+ VERTGUIDE, 245
+ BOTTOMMARGIN, 150
+ END
+
+ IDD_FILEEXISTS, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 283
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 176
+ END
+
+ IDD_URLSEND, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 210
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 121
+ END
+
+ IDD_URLRECV, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 210
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 135
+ END
+
+ IDD_HISTORY, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 289
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 158
+ END
+
+ IDD_OPT_SOUND, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 281
+ VERTGUIDE, 12
+ VERTGUIDE, 273
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 236
+ END
+
+ IDD_OPT_ICONS, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 253
+ VERTGUIDE, 12
+ VERTGUIDE, 200
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 189
+ END
+
+ IDD_OPT_IGNORE, DIALOG
+ BEGIN
+ VERTGUIDE, 8
+ VERTGUIDE, 96
+ VERTGUIDE, 221
+ VERTGUIDE, 305
+ END
+
+ IDD_OPT_VISIBILITY, DIALOG
+ BEGIN
+ VERTGUIDE, 8
+ VERTGUIDE, 305
+ END
+
+ IDD_OPT_AWAYMSG, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 259
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 147
+ END
+
+ IDD_ICONINDEX, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 215
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 193
+ END
+
+ IDD_OPT_NETLIB, DIALOG
+ BEGIN
+ VERTGUIDE, 7
+ VERTGUIDE, 20
+ VERTGUIDE, 80
+ VERTGUIDE, 166
+ VERTGUIDE, 177
+ VERTGUIDE, 306
+ BOTTOMMARGIN, 235
+ HORZGUIDE, 80
+ HORZGUIDE, 113
+ END
+
+ IDD_OPT_FILETRANSFER, DIALOG
+ BEGIN
+ VERTGUIDE, 8
+ VERTGUIDE, 302
+ END
+
+ IDD_PROFILE_SELECTION, DIALOG
+ BEGIN
+ RIGHTMARGIN, 225
+ BOTTOMMARGIN, 141
+ END
+
+ IDD_PROFILE_NEW, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 219
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 135
+ END
+
+ IDD_OPT_PLUGINS, DIALOG
+ BEGIN
+ BOTTOMMARGIN, 235
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE MOVEABLE PURE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE MOVEABLE PURE
+BEGIN
+ "#include <windows.h>\r\n"
+ "#include <winres.h>\r\n"
+ "#include ""../include/statusmodes.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE MOVEABLE PURE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_MIRANDA ICON DISCARDABLE "res\\miranda.ico"
+IDI_SEARCHALL ICON DISCARDABLE "res\\searchal.ico"
+IDI_SMS ICON DISCARDABLE "res\\sms.ico"
+IDI_BLANK ICON DISCARDABLE "res\\blank.ico"
+IDI_NOTICK ICON DISCARDABLE "res\\notick.ico"
+IDI_TICK ICON DISCARDABLE "res\\notick1.ico"
+IDI_FILE ICON DISCARDABLE "res\\file.ico"
+IDI_TIMESTAMP ICON DISCARDABLE "res\\timestamp.ico"
+IDI_CHANGEFONT ICON DISCARDABLE "res\\changefont.ico"
+IDI_ADDCONTACT ICON DISCARDABLE "res\\addcontact.ico"
+IDI_USERDETAILS ICON DISCARDABLE "res\\viewdetails.ico"
+IDI_SMALLDOT ICON DISCARDABLE "res\\smalldot.ico"
+IDI_FILLEDBLOB ICON DISCARDABLE "res\\filledbl.ico"
+IDI_EMPTYBLOB ICON DISCARDABLE "res\\emptyblo.ico"
+IDI_DETAILSLOGO ICON DISCARDABLE "res\\detailsl.ico"
+IDI_RECVMSG ICON DISCARDABLE "res\\message.ico"
+IDI_SENDMSG ICON DISCARDABLE "res\\reply.ico"
+IDI_URL ICON DISCARDABLE "res\\url.ico"
+IDI_NA ICON DISCARDABLE "res\\na2.ico"
+IDI_AWAY ICON DISCARDABLE "res\\away.ico"
+IDI_FREE4CHAT ICON DISCARDABLE "res\\freechat.ico"
+IDI_ONLINE ICON DISCARDABLE "res\\online2.ico"
+IDI_OFFLINE ICON DISCARDABLE "res\\offline2.ico"
+IDI_DND ICON DISCARDABLE "res\\dnd.ico"
+IDI_OCCUPIED ICON DISCARDABLE "res\\occupied.ico"
+IDI_FINDUSER ICON DISCARDABLE "res\\finduser.ico"
+IDI_HELP ICON DISCARDABLE "res\\help.ico"
+IDI_OPTIONS ICON DISCARDABLE "res\\options.ico"
+IDI_MIRANDAWEBSITE ICON DISCARDABLE "res\\mirandaw.ico"
+IDI_RENAME ICON DISCARDABLE "res\\rename.ico"
+IDI_HISTORY ICON DISCARDABLE "res\\history.ico"
+IDI_DELETE ICON DISCARDABLE "res\\delete.ico"
+IDI_SENDEMAIL ICON DISCARDABLE "res\\sendmail.ico"
+IDI_USERONLINE ICON DISCARDABLE "res\\useronli.ico"
+IDI_GROUPSHUT ICON DISCARDABLE "res\\groupshu.ico"
+IDI_GROUPOPEN ICON DISCARDABLE "res\\groupope.ico"
+IDI_ONTHEPHONE ICON DISCARDABLE "res\\onthepho.ico"
+IDI_OUTTOLUNCH ICON DISCARDABLE "res\\outtolun.ico"
+IDI_INVISIBLE ICON DISCARDABLE "res\\invisible.ico"
+IDI_MULTISEND ICON DISCARDABLE "res\\multisend.ico"
+IDI_DOWNARROW ICON DISCARDABLE "res\\downarrow.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Cursor
+//
+
+IDC_HYPERLINKHAND CURSOR DISCARDABLE "res\\hyperlin.cur"
+IDC_DROP CURSOR DISCARDABLE "res\\dragcopy.cur"
+IDC_DROPUSER CURSOR DISCARDABLE "res\\dropuser.cur"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_CLISTMENU MENU DISCARDABLE
+BEGIN
+ POPUP "&¤"
+ BEGIN
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit", ID_ICQ_EXIT
+ END
+ POPUP "&Status"
+ BEGIN
+ MENUITEM "&Offline\tCtrl+0", ID_STATUS_OFFLINE, CHECKED
+ MENUITEM "On&line\tCtrl+1", ID_STATUS_ONLINE
+ MENUITEM "&Away\tCtrl+2", ID_STATUS_AWAY
+ MENUITEM "&NA\tCtrl+3", ID_STATUS_NA
+ MENUITEM "Occ&upied\tCtrl+4", ID_STATUS_OCCUPIED
+ MENUITEM "&DND\tCtrl+5", ID_STATUS_DND
+ MENUITEM "&Free for chat\tCtrl+6", ID_STATUS_FREECHAT
+ MENUITEM "&Invisible\tCtrl+7", ID_STATUS_INVISIBLE
+ MENUITEM "On the &Phone\tCtrl+8", ID_STATUS_ONTHEPHONE
+ MENUITEM "Out to &Lunch\tCtrl+9", ID_STATUS_OUTTOLUNCH
+ END
+END
+
+IDR_CONTEXT MENU DISCARDABLE
+BEGIN
+ POPUP "Tray"
+ BEGIN
+ MENUITEM "&Hide/Show", ID_TRAY_HIDE
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit", ID_TRAY_EXIT
+ END
+ POPUP "Nowhere"
+ BEGIN
+ MENUITEM "&New Group", POPUP_NEWGROUP
+ MENUITEM SEPARATOR
+ MENUITEM "&Hide Offline Users", POPUP_HIDEOFFLINE
+ MENUITEM "Hide &Offline Users out here", POPUP_HIDEOFFLINEROOT
+ MENUITEM "Hide &Empty Groups", POPUP_HIDEEMPTYGROUPS
+ MENUITEM "Disable &Groups", POPUP_DISABLEGROUPS
+ MENUITEM SEPARATOR
+ MENUITEM "Hide Miranda", POPUP_HIDEMIRANDA
+ END
+ POPUP "Group"
+ BEGIN
+ MENUITEM "&New Subgroup", POPUP_NEWSUBGROUP
+ MENUITEM "&Hide Offline Users in here", POPUP_GROUPHIDEOFFLINE
+ MENUITEM SEPARATOR
+ MENUITEM "&Rename Group", POPUP_RENAMEGROUP
+ MENUITEM "&Delete Group", POPUP_DELETEGROUP
+ END
+ POPUP "IconOptions"
+ BEGIN
+ MENUITEM "&Reset to default", ID_RESET
+ END
+ POPUP "find/add"
+ BEGIN
+ MENUITEM "&Add to List", IDC_ADD
+ MENUITEM SEPARATOR
+ MENUITEM "User &Details", IDC_DETAILS
+ MENUITEM "Send &Message", IDC_SENDMESSAGE
+ END
+ POPUP "Log"
+ BEGIN
+ MENUITEM "&Copy", IDM_COPY
+ MENUITEM "Co&py All", IDM_COPYALL
+ MENUITEM "Select &All", IDM_SELECTALL
+ MENUITEM SEPARATOR
+ MENUITEM "C&lear Log", IDM_CLEAR
+ END
+ POPUP "LogLink"
+ BEGIN
+ MENUITEM "Open in &new window", IDM_OPENNEW
+ MENUITEM "&Open in existing window", IDM_OPENEXISTING
+ MENUITEM "&Copy link", IDM_COPYLINK
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXT
+//
+
+IDR_CREDITS TEXT MOVEABLE PURE "..\\docs\\credits.txt"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_SORTCOLUP BITMAP MOVEABLE PURE "res\\sortcolu.bmp"
+IDB_SORTCOLDOWN BITMAP MOVEABLE PURE "res\\sortcold.bmp"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// RT_MANIFEST
+//
+
+1 RT_MANIFEST MOVEABLE PURE "miranda32.exe.manifest"
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#include "version.rc"
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/miranda-wine/src/version.rc b/miranda-wine/src/version.rc
new file mode 100644
index 0000000..78083f2
--- /dev/null
+++ b/miranda-wine/src/version.rc
@@ -0,0 +1,45 @@
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 0,6,0,6
+ PRODUCTVERSION 0,6,0,6
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "000004b0"
+ BEGIN
+ VALUE "Comments", "Licensed under the terms of the GNU General Public License\0"
+ VALUE "CompanyName", " \0"
+ VALUE "FileDescription", "Miranda IM\0"
+ VALUE "FileVersion", "0.6 alpha build #6\0"
+ VALUE "InternalName", "miranda32\0"
+ VALUE "LegalCopyright", "Copyright © 2000-2006 Miranda IM Project. This software is released under the terms of the GNU General Public License.\0"
+ VALUE "LegalTrademarks", "\0"
+ VALUE "OriginalFilename", "miranda32.exe\0"
+ VALUE "PrivateBuild", "\0"
+ VALUE "ProductName", "Miranda IM\0"
+ VALUE "ProductVersion", "0.6 alpha build #6\0"
+ VALUE "SpecialBuild", "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0, 1200
+ END
+END
+
+#endif // !_MAC
+