summaryrefslogtreecommitdiff
path: root/protocols/Sametime
diff options
context:
space:
mode:
authorSzymon Tokarz <wsx22@o2.pl>2014-03-21 23:45:44 +0000
committerSzymon Tokarz <wsx22@o2.pl>2014-03-21 23:45:44 +0000
commit1a5937099e9333a426edc5fb6eef2ac626557857 (patch)
treeaabe4beebb6a459338b4a0f2cbf0cd7eb0a795e7 /protocols/Sametime
parent34daf458e330dd8258293db8067ef5bc3f6cb72c (diff)
Sametime protocol adopted
- Meanwhile Library included into plugin sources - needs glib dll files inside Miranda root directory \dll_x32\libglib-2.0-0.dll and \dll_x32\intl.dll for x32 \dll_x64\libglib-2.0-0.dll and \dll_x64\libintl-8.dll for x64 - more info at docs\readme.txt git-svn-id: http://svn.miranda-ng.org/main/trunk@8676 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'protocols/Sametime')
-rw-r--r--protocols/Sametime/docs/dll_x32/intl.dllbin0 -> 152489 bytes
-rw-r--r--protocols/Sametime/docs/dll_x32/libglib-2.0-0.dllbin0 -> 1243068 bytes
-rw-r--r--protocols/Sametime/docs/dll_x64/libglib-2.0-0.dllbin0 -> 1268114 bytes
-rw-r--r--protocols/Sametime/docs/dll_x64/libintl-8.dllbin0 -> 240862 bytes
-rw-r--r--protocols/Sametime/docs/license.txt674
-rw-r--r--protocols/Sametime/docs/readme.txt66
-rw-r--r--protocols/Sametime/proto_sametime/Proto_Sametime_10.vcxproj131
-rw-r--r--protocols/Sametime/proto_sametime/Proto_Sametime_10.vcxproj.filters23
-rw-r--r--protocols/Sametime/proto_sametime/Proto_Sametime_12.vcxproj135
-rw-r--r--protocols/Sametime/proto_sametime/Proto_Sametime_12.vcxproj.filters23
-rw-r--r--protocols/Sametime/proto_sametime/res/Away.icobin0 -> 318 bytes
-rw-r--r--protocols/Sametime/proto_sametime/res/DND.icobin0 -> 318 bytes
-rw-r--r--protocols/Sametime/proto_sametime/res/Offline.icobin0 -> 318 bytes
-rw-r--r--protocols/Sametime/proto_sametime/res/Online.icobin0 -> 318 bytes
-rw-r--r--protocols/Sametime/proto_sametime/res/Proto_Sametime.rc72
-rw-r--r--protocols/Sametime/proto_sametime/src/resource.h19
-rw-r--r--protocols/Sametime/res/announce.icobin0 -> 1406 bytes
-rw-r--r--protocols/Sametime/res/error.icobin0 -> 1150 bytes
-rw-r--r--protocols/Sametime/res/invite.icobin0 -> 318 bytes
-rw-r--r--protocols/Sametime/res/notify.icobin0 -> 1150 bytes
-rw-r--r--protocols/Sametime/res/online.icobin0 -> 1150 bytes
-rw-r--r--protocols/Sametime/res/part.icobin0 -> 2294 bytes
-rw-r--r--protocols/Sametime/res/resource.rc177
-rw-r--r--protocols/Sametime/sametime_10.vcxproj306
-rw-r--r--protocols/Sametime/sametime_10.vcxproj.filters217
-rw-r--r--protocols/Sametime/sametime_12.vcxproj311
-rw-r--r--protocols/Sametime/sametime_12.vcxproj.filters217
-rw-r--r--protocols/Sametime/src/StdAfx.cpp8
-rw-r--r--protocols/Sametime/src/StdAfx.h97
-rw-r--r--protocols/Sametime/src/conference.cpp566
-rw-r--r--protocols/Sametime/src/files.cpp457
-rw-r--r--protocols/Sametime/src/glib/include/glib.h99
-rw-r--r--protocols/Sametime/src/glib/include/glib/galloca.h110
-rw-r--r--protocols/Sametime/src/glib/include/glib/garray.h179
-rw-r--r--protocols/Sametime/src/glib/include/glib/gasyncqueue.h120
-rw-r--r--protocols/Sametime/src/glib/include/glib/gatomic.h105
-rw-r--r--protocols/Sametime/src/glib/include/glib/gbacktrace.h68
-rw-r--r--protocols/Sametime/src/glib/include/glib/gbase64.h57
-rw-r--r--protocols/Sametime/src/glib/include/glib/gbitlock.h43
-rw-r--r--protocols/Sametime/src/glib/include/glib/gbookmarkfile.h215
-rw-r--r--protocols/Sametime/src/glib/include/glib/gcache.h69
-rw-r--r--protocols/Sametime/src/glib/include/glib/gchecksum.h86
-rw-r--r--protocols/Sametime/src/glib/include/glib/gcompletion.h81
-rw-r--r--protocols/Sametime/src/glib/include/glib/gconvert.h162
-rw-r--r--protocols/Sametime/src/glib/include/glib/gdataset.h122
-rw-r--r--protocols/Sametime/src/glib/include/glib/gdate.h263
-rw-r--r--protocols/Sametime/src/glib/include/glib/gdatetime.h217
-rw-r--r--protocols/Sametime/src/glib/include/glib/gdir.h52
-rw-r--r--protocols/Sametime/src/glib/include/glib/gerror.h98
-rw-r--r--protocols/Sametime/src/glib/include/glib/gfileutils.h128
-rw-r--r--protocols/Sametime/src/glib/include/glib/ghash.h166
-rw-r--r--protocols/Sametime/src/glib/include/glib/ghook.h181
-rw-r--r--protocols/Sametime/src/glib/include/glib/ghostutils.h40
-rw-r--r--protocols/Sametime/src/glib/include/glib/giochannel.h366
-rw-r--r--protocols/Sametime/src/glib/include/glib/gkeyfile.h266
-rw-r--r--protocols/Sametime/src/glib/include/glib/glist.h120
-rw-r--r--protocols/Sametime/src/glib/include/glib/gmacros.h284
-rw-r--r--protocols/Sametime/src/glib/include/glib/gmain.h531
-rw-r--r--protocols/Sametime/src/glib/include/glib/gmappedfile.h49
-rw-r--r--protocols/Sametime/src/glib/include/glib/gmarkup.h163
-rw-r--r--protocols/Sametime/src/glib/include/glib/gmem.h309
-rw-r--r--protocols/Sametime/src/glib/include/glib/gmessages.h343
-rw-r--r--protocols/Sametime/src/glib/include/glib/gnode.h290
-rw-r--r--protocols/Sametime/src/glib/include/glib/goption.h370
-rw-r--r--protocols/Sametime/src/glib/include/glib/gpattern.h49
-rw-r--r--protocols/Sametime/src/glib/include/glib/gpoll.h117
-rw-r--r--protocols/Sametime/src/glib/include/glib/gprimes.h51
-rw-r--r--protocols/Sametime/src/glib/include/glib/gqsort.h46
-rw-r--r--protocols/Sametime/src/glib/include/glib/gquark.h52
-rw-r--r--protocols/Sametime/src/glib/include/glib/gqueue.h127
-rw-r--r--protocols/Sametime/src/glib/include/glib/grand.h85
-rw-r--r--protocols/Sametime/src/glib/include/glib/gregex.h471
-rw-r--r--protocols/Sametime/src/glib/include/glib/grel.h101
-rw-r--r--protocols/Sametime/src/glib/include/glib/gscanner.h278
-rw-r--r--protocols/Sametime/src/glib/include/glib/gsequence.h128
-rw-r--r--protocols/Sametime/src/glib/include/glib/gshell.h55
-rw-r--r--protocols/Sametime/src/glib/include/glib/gslice.h86
-rw-r--r--protocols/Sametime/src/glib/include/glib/gslist.h114
-rw-r--r--protocols/Sametime/src/glib/include/glib/gspawn.h139
-rw-r--r--protocols/Sametime/src/glib/include/glib/gstrfuncs.h269
-rw-r--r--protocols/Sametime/src/glib/include/glib/gstring.h178
-rw-r--r--protocols/Sametime/src/glib/include/glib/gtestutils.h297
-rw-r--r--protocols/Sametime/src/glib/include/glib/gthread.h407
-rw-r--r--protocols/Sametime/src/glib/include/glib/gthreadpool.h114
-rw-r--r--protocols/Sametime/src/glib/include/glib/gtimer.h65
-rw-r--r--protocols/Sametime/src/glib/include/glib/gtimezone.h44
-rw-r--r--protocols/Sametime/src/glib/include/glib/gtree.h91
-rw-r--r--protocols/Sametime/src/glib/include/glib/gtypes.h451
-rw-r--r--protocols/Sametime/src/glib/include/glib/gunicode.h421
-rw-r--r--protocols/Sametime/src/glib/include/glib/gurifuncs.h81
-rw-r--r--protocols/Sametime/src/glib/include/glib/gutils.h490
-rw-r--r--protocols/Sametime/src/glib/include/glib/gvariant.h248
-rw-r--r--protocols/Sametime/src/glib/include/glib/gvarianttype.h334
-rw-r--r--protocols/Sametime/src/glib/include/glib/gwin32.h114
-rw-r--r--protocols/Sametime/src/glib/include/glibconfig.h284
-rw-r--r--protocols/Sametime/src/glib/lib32/glib-2.0.libbin0 -> 336604 bytes
-rw-r--r--protocols/Sametime/src/glib/lib64/glib-2.0.libbin0 -> 329262 bytes
-rw-r--r--protocols/Sametime/src/meanwhile/AUTHORS10
-rw-r--r--protocols/Sametime/src/meanwhile/LICENSE481
-rw-r--r--protocols/Sametime/src/meanwhile/README39
-rw-r--r--protocols/Sametime/src/meanwhile/src/channel.c972
-rw-r--r--protocols/Sametime/src/meanwhile/src/cipher.c982
-rw-r--r--protocols/Sametime/src/meanwhile/src/common.c947
-rw-r--r--protocols/Sametime/src/meanwhile/src/error.c97
-rw-r--r--protocols/Sametime/src/meanwhile/src/message.c853
-rw-r--r--protocols/Sametime/src/meanwhile/src/mpi/mpi-config.h84
-rw-r--r--protocols/Sametime/src/meanwhile/src/mpi/mpi-types.h18
-rw-r--r--protocols/Sametime/src/meanwhile/src/mpi/mpi.c4022
-rw-r--r--protocols/Sametime/src/meanwhile/src/mpi/mpi.h221
-rw-r--r--protocols/Sametime/src/meanwhile/src/mw_channel.h380
-rw-r--r--protocols/Sametime/src/meanwhile/src/mw_cipher.h297
-rw-r--r--protocols/Sametime/src/meanwhile/src/mw_common.h437
-rw-r--r--protocols/Sametime/src/meanwhile/src/mw_debug.c184
-rw-r--r--protocols/Sametime/src/meanwhile/src/mw_debug.h130
-rw-r--r--protocols/Sametime/src/meanwhile/src/mw_error.h174
-rw-r--r--protocols/Sametime/src/meanwhile/src/mw_message.h305
-rw-r--r--protocols/Sametime/src/meanwhile/src/mw_service.h370
-rw-r--r--protocols/Sametime/src/meanwhile/src/mw_session.h397
-rw-r--r--protocols/Sametime/src/meanwhile/src/mw_srvc_aware.h289
-rw-r--r--protocols/Sametime/src/meanwhile/src/mw_srvc_conf.h216
-rw-r--r--protocols/Sametime/src/meanwhile/src/mw_srvc_dir.h212
-rw-r--r--protocols/Sametime/src/meanwhile/src/mw_srvc_ft.h255
-rw-r--r--protocols/Sametime/src/meanwhile/src/mw_srvc_im.h281
-rw-r--r--protocols/Sametime/src/meanwhile/src/mw_srvc_place.h148
-rw-r--r--protocols/Sametime/src/meanwhile/src/mw_srvc_resolve.h155
-rw-r--r--protocols/Sametime/src/meanwhile/src/mw_srvc_store.h201
-rw-r--r--protocols/Sametime/src/meanwhile/src/mw_st_list.h218
-rw-r--r--protocols/Sametime/src/meanwhile/src/mw_util.c80
-rw-r--r--protocols/Sametime/src/meanwhile/src/mw_util.h85
-rw-r--r--protocols/Sametime/src/meanwhile/src/service.c267
-rw-r--r--protocols/Sametime/src/meanwhile/src/session.c1220
-rw-r--r--protocols/Sametime/src/meanwhile/src/srvc_aware.c1341
-rw-r--r--protocols/Sametime/src/meanwhile/src/srvc_conf.c884
-rw-r--r--protocols/Sametime/src/meanwhile/src/srvc_dir.c664
-rw-r--r--protocols/Sametime/src/meanwhile/src/srvc_ft.c667
-rw-r--r--protocols/Sametime/src/meanwhile/src/srvc_im.c1095
-rw-r--r--protocols/Sametime/src/meanwhile/src/srvc_place.c1089
-rw-r--r--protocols/Sametime/src/meanwhile/src/srvc_resolve.c396
-rw-r--r--protocols/Sametime/src/meanwhile/src/srvc_store.c615
-rw-r--r--protocols/Sametime/src/meanwhile/src/st_list.c668
-rw-r--r--protocols/Sametime/src/messaging.cpp222
-rw-r--r--protocols/Sametime/src/options.cpp369
-rw-r--r--protocols/Sametime/src/places.cpp67
-rw-r--r--protocols/Sametime/src/resource.h59
-rw-r--r--protocols/Sametime/src/sametime.cpp296
-rw-r--r--protocols/Sametime/src/sametime.h121
-rw-r--r--protocols/Sametime/src/sametime_proto.cpp430
-rw-r--r--protocols/Sametime/src/sametime_proto.h248
-rw-r--r--protocols/Sametime/src/sametime_session.cpp634
-rw-r--r--protocols/Sametime/src/session_announce_win.cpp147
-rw-r--r--protocols/Sametime/src/userlist.cpp836
-rw-r--r--protocols/Sametime/src/utils.cpp170
-rw-r--r--protocols/Sametime/src/version.h13
153 files changed, 41096 insertions, 0 deletions
diff --git a/protocols/Sametime/docs/dll_x32/intl.dll b/protocols/Sametime/docs/dll_x32/intl.dll
new file mode 100644
index 0000000000..d2612081ca
--- /dev/null
+++ b/protocols/Sametime/docs/dll_x32/intl.dll
Binary files differ
diff --git a/protocols/Sametime/docs/dll_x32/libglib-2.0-0.dll b/protocols/Sametime/docs/dll_x32/libglib-2.0-0.dll
new file mode 100644
index 0000000000..143e1daadc
--- /dev/null
+++ b/protocols/Sametime/docs/dll_x32/libglib-2.0-0.dll
Binary files differ
diff --git a/protocols/Sametime/docs/dll_x64/libglib-2.0-0.dll b/protocols/Sametime/docs/dll_x64/libglib-2.0-0.dll
new file mode 100644
index 0000000000..cde4d25439
--- /dev/null
+++ b/protocols/Sametime/docs/dll_x64/libglib-2.0-0.dll
Binary files differ
diff --git a/protocols/Sametime/docs/dll_x64/libintl-8.dll b/protocols/Sametime/docs/dll_x64/libintl-8.dll
new file mode 100644
index 0000000000..de0ef3043f
--- /dev/null
+++ b/protocols/Sametime/docs/dll_x64/libintl-8.dll
Binary files differ
diff --git a/protocols/Sametime/docs/license.txt b/protocols/Sametime/docs/license.txt
new file mode 100644
index 0000000000..818433ecc0
--- /dev/null
+++ b/protocols/Sametime/docs/license.txt
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/protocols/Sametime/docs/readme.txt b/protocols/Sametime/docs/readme.txt
new file mode 100644
index 0000000000..337d12e892
--- /dev/null
+++ b/protocols/Sametime/docs/readme.txt
@@ -0,0 +1,66 @@
+
+sametime.dll
+
+Miranda NG Sametime protocol
+
+
+
+
+
+The Meanwhile Library
+Fork of meanwhile 1.0.2 from
+http://meanwhile.sourceforge.net/
+
+
+
+
+
+INSTALATION
+
+This plugin needs glib windows dll libraries copied into main Miranda directory (directory with Miranda32.exe or Miranda64.exe) to work.
+
+For 32 bit version (\docs\dll_x32\):
+libglib-2.0-0.dll from http://ftp.gnome.org/pub/gnome/binaries/win32/glib/2.26/glib_2.26.1-1_win32.zip
+intl.dll from http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/gettext-runtime_0.18.1.1-2_win32.zip
+
+For 64 bit version (\docs\dll_x64\):
+libglib-2.0-0.dll from http://ftp.gnome.org/pub/gnome/binaries/win64/glib/2.26/glib_2.26.1-1_win64.zip
+libintl-8.dll from http://ftp.gnome.org/pub/gnome/binaries/win64/dependencies/gettext-runtime_0.18.1.1-2_win64.zip
+
+
+
+
+
+
+KNOWN ISSUES
+
+1)
+Receiving files from same oryginal clients (Lotus Sametime 8.0.2) doesn't work.
+At Miranda IM too.
+Miranda NG <-> Miranda NG file transfers are ok.
+
+2)
+Receiving conferences announcements is unimplemented
+
+3)
+Crash on Miranda exit. (environment depends)
+Exception: User Defined Breakpoint at address 74923C38.
+764E1DA7 (KERNELBASE 764D0000): (filename not available) (0): FreeLibrary
+0042A156 (Miranda32 00400000): e:\sources\miranda_ng_compilation\src\modules\plugins\newplugins.cpp (308): Plugin_Uninit
+0042AC81 (Miranda32 00400000): e:\sources\miranda_ng_compilation\src\modules\plugins\newplugins.cpp (716): UnloadNewPlugins
+00401A78 (Miranda32 00400000): e:\sources\miranda_ng_compilation\src\core\modules.cpp (169): UnloadDefaultModules
+00401104 (Miranda32 00400000): e:\sources\miranda_ng_compilation\src\core\miranda.cpp (130): SystemShutdownProc
+
+
+
+
+
+
+TESTING SERVER ENVIRONMENT
+
+https://apps.ce.collabserv.com/manage/account/public/trial/showCreateTrialAccount?country=PL&ibm-continue=Continue
+see: http://www.wissel.net/blog/d6plinks/SHWL-84KE8U
+
+
+
+
diff --git a/protocols/Sametime/proto_sametime/Proto_Sametime_10.vcxproj b/protocols/Sametime/proto_sametime/Proto_Sametime_10.vcxproj
new file mode 100644
index 0000000000..6cb5cbf6ad
--- /dev/null
+++ b/protocols/Sametime/proto_sametime/Proto_Sametime_10.vcxproj
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{217C99B1-0D5E-4A85-A84F-836FCA167B25}</ProjectGuid>
+ <ProjectName>Proto_Sametime</ProjectName>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Icons\</OutDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Icons\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Icons\</OutDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Icons\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
+ <IgnoreImportLibrary>true</IgnoreImportLibrary>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <NoEntryPoint>true</NoEntryPoint>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
+ </Link>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <NoEntryPoint>true</NoEntryPoint>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
+ </Link>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <NoEntryPoint>true</NoEntryPoint>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
+ </Link>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <NoEntryPoint>true</NoEntryPoint>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
+ </Link>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="src\resource.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="res\Proto_Sametime.rc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/Sametime/proto_sametime/Proto_Sametime_10.vcxproj.filters b/protocols/Sametime/proto_sametime/Proto_Sametime_10.vcxproj.filters
new file mode 100644
index 0000000000..2fa8a4aabd
--- /dev/null
+++ b/protocols/Sametime/proto_sametime/Proto_Sametime_10.vcxproj.filters
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="src\resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="res\Proto_Sametime.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/Sametime/proto_sametime/Proto_Sametime_12.vcxproj b/protocols/Sametime/proto_sametime/Proto_Sametime_12.vcxproj
new file mode 100644
index 0000000000..e113fe994a
--- /dev/null
+++ b/protocols/Sametime/proto_sametime/Proto_Sametime_12.vcxproj
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{217C99B1-0D5E-4A85-A84F-836FCA167B25}</ProjectGuid>
+ <ProjectName>Proto_Sametime</ProjectName>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v120_xp</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v120_xp</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v120_xp</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v120_xp</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Icons\</OutDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Icons\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Icons\</OutDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Icons\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
+ <IgnoreImportLibrary>true</IgnoreImportLibrary>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <NoEntryPoint>true</NoEntryPoint>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
+ </Link>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <NoEntryPoint>true</NoEntryPoint>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
+ </Link>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <NoEntryPoint>true</NoEntryPoint>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
+ </Link>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <NoEntryPoint>true</NoEntryPoint>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
+ </Link>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="src\resource.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="res\Proto_Sametime.rc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/Sametime/proto_sametime/Proto_Sametime_12.vcxproj.filters b/protocols/Sametime/proto_sametime/Proto_Sametime_12.vcxproj.filters
new file mode 100644
index 0000000000..2fa8a4aabd
--- /dev/null
+++ b/protocols/Sametime/proto_sametime/Proto_Sametime_12.vcxproj.filters
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="src\resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="res\Proto_Sametime.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/Sametime/proto_sametime/res/Away.ico b/protocols/Sametime/proto_sametime/res/Away.ico
new file mode 100644
index 0000000000..6204baa145
--- /dev/null
+++ b/protocols/Sametime/proto_sametime/res/Away.ico
Binary files differ
diff --git a/protocols/Sametime/proto_sametime/res/DND.ico b/protocols/Sametime/proto_sametime/res/DND.ico
new file mode 100644
index 0000000000..f198b121f5
--- /dev/null
+++ b/protocols/Sametime/proto_sametime/res/DND.ico
Binary files differ
diff --git a/protocols/Sametime/proto_sametime/res/Offline.ico b/protocols/Sametime/proto_sametime/res/Offline.ico
new file mode 100644
index 0000000000..323f880ce5
--- /dev/null
+++ b/protocols/Sametime/proto_sametime/res/Offline.ico
Binary files differ
diff --git a/protocols/Sametime/proto_sametime/res/Online.ico b/protocols/Sametime/proto_sametime/res/Online.ico
new file mode 100644
index 0000000000..839e79c9f7
--- /dev/null
+++ b/protocols/Sametime/proto_sametime/res/Online.ico
Binary files differ
diff --git a/protocols/Sametime/proto_sametime/res/Proto_Sametime.rc b/protocols/Sametime/proto_sametime/res/Proto_Sametime.rc
new file mode 100644
index 0000000000..2553b55145
--- /dev/null
+++ b/protocols/Sametime/proto_sametime/res/Proto_Sametime.rc
@@ -0,0 +1,72 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "..\src\resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Russian (Russia) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)
+LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "..\\src\\resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.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_ICON1 ICON "Offline.ico"
+IDI_ICON2 ICON "Online.ico"
+IDI_ICON3 ICON "Away.ico"
+IDI_ICON4 ICON "DND.ico"
+#endif // Russian (Russia) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/protocols/Sametime/proto_sametime/src/resource.h b/protocols/Sametime/proto_sametime/src/resource.h
new file mode 100644
index 0000000000..3decee6cf7
--- /dev/null
+++ b/protocols/Sametime/proto_sametime/src/resource.h
@@ -0,0 +1,19 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by Proto_Sametime.rc
+//
+#define IDI_ICON1 105
+#define IDI_ICON2 104
+#define IDI_ICON3 128
+#define IDI_ICON4 158
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 108
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/protocols/Sametime/res/announce.ico b/protocols/Sametime/res/announce.ico
new file mode 100644
index 0000000000..ac9673a7dc
--- /dev/null
+++ b/protocols/Sametime/res/announce.ico
Binary files differ
diff --git a/protocols/Sametime/res/error.ico b/protocols/Sametime/res/error.ico
new file mode 100644
index 0000000000..5f8956218e
--- /dev/null
+++ b/protocols/Sametime/res/error.ico
Binary files differ
diff --git a/protocols/Sametime/res/invite.ico b/protocols/Sametime/res/invite.ico
new file mode 100644
index 0000000000..944ebf818c
--- /dev/null
+++ b/protocols/Sametime/res/invite.ico
Binary files differ
diff --git a/protocols/Sametime/res/notify.ico b/protocols/Sametime/res/notify.ico
new file mode 100644
index 0000000000..b4934e4e1f
--- /dev/null
+++ b/protocols/Sametime/res/notify.ico
Binary files differ
diff --git a/protocols/Sametime/res/online.ico b/protocols/Sametime/res/online.ico
new file mode 100644
index 0000000000..8362c83159
--- /dev/null
+++ b/protocols/Sametime/res/online.ico
Binary files differ
diff --git a/protocols/Sametime/res/part.ico b/protocols/Sametime/res/part.ico
new file mode 100644
index 0000000000..1b698a76b3
--- /dev/null
+++ b/protocols/Sametime/res/part.ico
Binary files differ
diff --git a/protocols/Sametime/res/resource.rc b/protocols/Sametime/res/resource.rc
new file mode 100644
index 0000000000..1f7384711d
--- /dev/null
+++ b/protocols/Sametime/res/resource.rc
@@ -0,0 +1,177 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "..\src\resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (Australia) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_OPTNET DIALOGEX 0, 0, 314, 203
+STYLE DS_SETFONT | WS_CHILD
+FONT 8, "MS Sans Serif", 0, 0, 0x0
+BEGIN
+ RTEXT "Server name:",IDC_STATIC,14,61,49,8
+ EDITTEXT IDC_ED_SNAME,70,57,92,14,ES_AUTOHSCROLL
+ RTEXT "Port:",IDC_STATIC,14,81,49,8
+ EDITTEXT IDC_ED_PORT,70,77,36,14,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "Get contacts from server",IDC_CHK_GETSERVERCONTACTS,
+ "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,180,15,115,15
+ PUSHBUTTON "Upload Contacts",IDC_BTN_UPLOADCONTACTS,180,29,115,15
+ PUSHBUTTON "Import from file...",IDC_BTN_IMPORTCONTACTS,180,48,115,15
+ COMBOBOX IDC_CMB_CLIENT,10,109,114,107,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ EDITTEXT IDC_ED_CLIENTID,126,109,37,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
+ RTEXT "Id:",IDC_STATIC,14,17,49,8
+ EDITTEXT IDC_ED_NAME,70,13,92,14,ES_AUTOHSCROLL
+ RTEXT "Password:",IDC_STATIC,14,39,49,8
+ EDITTEXT IDC_ED_PWORD,70,35,92,14,ES_PASSWORD | ES_AUTOHSCROLL
+ GROUPBOX "Error Display",IDC_STATIC,7,143,161,53
+ CONTROL "Use message boxes",IDC_RAD_ERRMB,"Button",BS_AUTORADIOBUTTON | WS_GROUP,20,156,122,10
+ CONTROL "Use popups",IDC_RAD_ERRPOP,"Button",BS_AUTORADIOBUTTON,20,169,122,10
+ CONTROL "Use system tray baloons",IDC_RAD_ERRBAL,"Button",BS_AUTORADIOBUTTON,21,182,122,10
+ GROUPBOX "Connection",IDC_STATIC,7,7,161,91
+ GROUPBOX "Contacts",IDC_STATIC,172,7,135,91
+ GROUPBOX "Client ID",IDC_STATIC,7,98,161,44
+ CONTROL "Auto-add new contacts",IDC_CHK_ADDCONTACTS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,180,67,115,11
+ GROUPBOX "Encryption",IDC_STATIC,172,98,135,44
+ CONTROL "40 or 128 bit",IDC_RAD_ENC,"Button",BS_AUTORADIOBUTTON | WS_GROUP,190,113,88,10
+ CONTROL "None",IDC_RAD_NOENC,"Button",BS_AUTORADIOBUTTON,190,126,88,10
+ CTEXT "Static",IDC_ST_CLIENTVER,185,165,102,12,SS_SUNKEN
+ CTEXT "Static",IDC_ST_SERVERVER,185,180,102,12,SS_SUNKEN
+ CONTROL "Treat 'idle' as 'away'",IDC_CHK_IDLEAWAY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,180,81,115,11
+ CTEXT "Meanwhile lib ver: 1.0.2",IDC_ST_LIBVER,185,150,102,12
+ GROUPBOX "",IDC_STATIC,172,143,135,53
+ CONTROL "Use old client version",IDC_CHK_OLDDEFAULTVER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,33,127,115,11
+END
+
+IDD_SESSIONANNOUNCE DIALOG 0, 0, 286, 263
+STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Send Announcement"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,95,242,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,150,242,50,14
+ EDITTEXT IDC_ED_ANMSG,10,20,264,60,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN
+ LTEXT "Message Text:",IDC_STATIC,9,9,142,8
+ CONTROL "List1",IDC_LST_ANTO,"SysListView32",LVS_REPORT | WS_BORDER | WS_TABSTOP,10,92,197,132
+ PUSHBUTTON "Select All",IDC_BUT_SELALL,214,122,58,36
+ PUSHBUTTON "Invert\n Selection",IDC_BUT_SELINV,214,167,58,36,BS_MULTILINE
+END
+
+IDD_USERSEARCH DIALOG 0, 0, 155, 86
+STYLE DS_SETFONT | WS_POPUP
+FONT 8, "MS Sans Serif"
+BEGIN
+ EDITTEXT IDC_EDIT1,34,32,103,14,ES_AUTOHSCROLL
+ LTEXT "ID:",IDC_STATIC,18,35,10,8
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_OPTNET, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 307
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 196
+ END
+
+ IDD_SESSIONANNOUNCE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 279
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 256
+ END
+
+ IDD_USERSEARCH, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 148
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 79
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.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_ICON_PROTO ICON "online.ico"
+IDI_ICON_LEAVE ICON "part.ico"
+IDI_ICON_INVITE ICON "invite.ico"
+IDI_ICON_ANNOUNCE ICON "announce.ico"
+IDI_ICON_NOTIFY ICON "notify.ico"
+IDI_ICON_ERROR ICON "error.ico"
+#endif // English (Australia) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/protocols/Sametime/sametime_10.vcxproj b/protocols/Sametime/sametime_10.vcxproj
new file mode 100644
index 0000000000..a9e17c8773
--- /dev/null
+++ b/protocols/Sametime/sametime_10.vcxproj
@@ -0,0 +1,306 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>Sametime</ProjectName>
+ <ProjectGuid>{BE22A21F-73B7-453F-86A0-B867F0056490}</ProjectGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
+ <IgnoreImportLibrary>true</IgnoreImportLibrary>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>.\Debug/sametime.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..\include;src\meanwhile\src;src\glib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>./src/glib/lib32/glib-2.0.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <ModuleDefinitionFile>
+ </ModuleDefinitionFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin10\lib</AdditionalLibraryDirectories>
+ <SubSystem>Windows</SubSystem>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>.\Debug/sametime.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..\include;src\meanwhile\src;src\glib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <WarningLevel>Level3</WarningLevel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>./src/glib/lib64/glib-2.0.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <ModuleDefinitionFile>
+ </ModuleDefinitionFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin10\lib</AdditionalLibraryDirectories>
+ <SubSystem>Windows</SubSystem>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>.\Release/sametime.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <AdditionalIncludeDirectories>..\..\include;src\meanwhile\src;src\glib\include;src\glib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <WarningLevel>Level3</WarningLevel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>./src/glib/lib32/glib-2.0.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin10\lib</AdditionalLibraryDirectories>
+ <SubSystem>Windows</SubSystem>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>.\Release/sametime.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <AdditionalIncludeDirectories>..\..\include;src\meanwhile\src;src\glib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <WarningLevel>Level3</WarningLevel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>./src/glib/lib64/glib-2.0.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin10\lib</AdditionalLibraryDirectories>
+ <SubSystem>Windows</SubSystem>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="src\conference.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\files.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\channel.c" />
+ <ClCompile Include="src\meanwhile\src\cipher.c" />
+ <ClCompile Include="src\meanwhile\src\common.c" />
+ <ClCompile Include="src\meanwhile\src\error.c" />
+ <ClCompile Include="src\meanwhile\src\message.c" />
+ <ClCompile Include="src\meanwhile\src\mpi\mpi.c" />
+ <ClCompile Include="src\meanwhile\src\mw_debug.c" />
+ <ClCompile Include="src\meanwhile\src\mw_util.c" />
+ <ClCompile Include="src\meanwhile\src\service.c" />
+ <ClCompile Include="src\meanwhile\src\session.c" />
+ <ClCompile Include="src\meanwhile\src\srvc_aware.c" />
+ <ClCompile Include="src\meanwhile\src\srvc_conf.c" />
+ <ClCompile Include="src\meanwhile\src\srvc_dir.c" />
+ <ClCompile Include="src\meanwhile\src\srvc_ft.c" />
+ <ClCompile Include="src\meanwhile\src\srvc_im.c" />
+ <ClCompile Include="src\meanwhile\src\srvc_place.c" />
+ <ClCompile Include="src\meanwhile\src\srvc_resolve.c" />
+ <ClCompile Include="src\meanwhile\src\srvc_store.c" />
+ <ClCompile Include="src\meanwhile\src\st_list.c" />
+ <ClCompile Include="src\messaging.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\options.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\places.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\sametime.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\sametime_proto.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\sametime_session.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\session_announce_win.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\StdAfx.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\userlist.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\utils.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="src\meanwhile\src\mpi\mpi-config.h" />
+ <ClInclude Include="src\meanwhile\src\mpi\mpi-types.h" />
+ <ClInclude Include="src\meanwhile\src\mpi\mpi.h" />
+ <ClInclude Include="src\meanwhile\src\mw_channel.h" />
+ <ClInclude Include="src\meanwhile\src\mw_cipher.h" />
+ <ClInclude Include="src\meanwhile\src\mw_common.h" />
+ <ClInclude Include="src\meanwhile\src\mw_debug.h" />
+ <ClInclude Include="src\meanwhile\src\mw_error.h" />
+ <ClInclude Include="src\meanwhile\src\mw_message.h" />
+ <ClInclude Include="src\meanwhile\src\mw_service.h" />
+ <ClInclude Include="src\meanwhile\src\mw_session.h" />
+ <ClInclude Include="src\meanwhile\src\mw_srvc_aware.h" />
+ <ClInclude Include="src\meanwhile\src\mw_srvc_conf.h" />
+ <ClInclude Include="src\meanwhile\src\mw_srvc_dir.h" />
+ <ClInclude Include="src\meanwhile\src\mw_srvc_ft.h" />
+ <ClInclude Include="src\meanwhile\src\mw_srvc_im.h" />
+ <ClInclude Include="src\meanwhile\src\mw_srvc_place.h" />
+ <ClInclude Include="src\meanwhile\src\mw_srvc_resolve.h" />
+ <ClInclude Include="src\meanwhile\src\mw_srvc_store.h" />
+ <ClInclude Include="src\meanwhile\src\mw_st_list.h" />
+ <ClInclude Include="src\meanwhile\src\mw_util.h" />
+ <ClInclude Include="src\resource.h" />
+ <ClInclude Include="src\sametime.h" />
+ <ClInclude Include="src\sametime_proto.h" />
+ <ClInclude Include="src\StdAfx.h" />
+ <ClInclude Include="src\version.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="res\announce.ico" />
+ <None Include="res\invite.ico" />
+ <None Include="res\online.ico" />
+ <None Include="res\part.ico" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="res\resource.rc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/Sametime/sametime_10.vcxproj.filters b/protocols/Sametime/sametime_10.vcxproj.filters
new file mode 100644
index 0000000000..e97b6b31da
--- /dev/null
+++ b/protocols/Sametime/sametime_10.vcxproj.filters
@@ -0,0 +1,217 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{b2fb3090-cd03-4404-a154-94e31360b079}</UniqueIdentifier>
+ <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{97a29dbd-67df-4a06-a2d0-a82721b109c2}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{34e64f6c-b825-450f-bf46-f974acd71f72}</UniqueIdentifier>
+ <Extensions>ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe</Extensions>
+ </Filter>
+ <Filter Include="Source Files\Meanwhile">
+ <UniqueIdentifier>{addc907a-8009-4c31-b03d-37759cb8c021}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files\Meanwhile\mpi">
+ <UniqueIdentifier>{c23f9d40-96f3-4bce-a8eb-670346163e26}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="src\conference.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\files.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\messaging.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\options.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\places.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\sametime.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\session_announce_win.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\userlist.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\utils.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\StdAfx.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\sametime_proto.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\st_list.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\channel.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\cipher.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\common.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\error.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\message.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\mw_debug.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\mw_util.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\service.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\session.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\srvc_aware.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\srvc_conf.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\srvc_dir.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\srvc_ft.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\srvc_im.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\srvc_place.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\srvc_resolve.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\srvc_store.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\mpi\mpi.c">
+ <Filter>Source Files\Meanwhile\mpi</Filter>
+ </ClCompile>
+ <ClCompile Include="src\sametime_session.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="src\resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\sametime.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\StdAfx.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\version.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\sametime_proto.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_channel.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_cipher.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_common.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_debug.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_error.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_message.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_service.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_session.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_srvc_aware.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_srvc_conf.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_srvc_dir.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_srvc_ft.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_srvc_im.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_srvc_place.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_srvc_resolve.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_srvc_store.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_st_list.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_util.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mpi\mpi-types.h">
+ <Filter>Source Files\Meanwhile\mpi</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mpi\mpi.h">
+ <Filter>Source Files\Meanwhile\mpi</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mpi\mpi-config.h">
+ <Filter>Source Files\Meanwhile\mpi</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="res\announce.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\invite.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\online.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\part.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="res\resource.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/Sametime/sametime_12.vcxproj b/protocols/Sametime/sametime_12.vcxproj
new file mode 100644
index 0000000000..f56100fd70
--- /dev/null
+++ b/protocols/Sametime/sametime_12.vcxproj
@@ -0,0 +1,311 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>Sametime</ProjectName>
+ <ProjectGuid>{BE22A21F-73B7-453F-86A0-B867F0056490}</ProjectGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <PlatformToolset>v120_xp</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v120_xp</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <PlatformToolset>v120_xp</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v120_xp</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
+ <IgnoreImportLibrary>true</IgnoreImportLibrary>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>.\Debug/sametime.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..\include;src\meanwhile\src;src\glib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>./src/glib/lib32/glib-2.0.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <ModuleDefinitionFile>
+ </ModuleDefinitionFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin12\lib</AdditionalLibraryDirectories>
+ <SubSystem>Windows</SubSystem>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>.\Debug/sametime.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..\include;src\meanwhile\src;src\glib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <WarningLevel>Level3</WarningLevel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>./src/glib/lib64/glib-2.0.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <ModuleDefinitionFile>
+ </ModuleDefinitionFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin12\lib</AdditionalLibraryDirectories>
+ <SubSystem>Windows</SubSystem>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>.\Release/sametime.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <AdditionalIncludeDirectories>..\..\include;src\meanwhile\src;src\glib\include;src\glib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <WarningLevel>Level3</WarningLevel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>./src/glib/lib32/glib-2.0.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin12\lib</AdditionalLibraryDirectories>
+ <SubSystem>Windows</SubSystem>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>.\Release/sametime.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <AdditionalIncludeDirectories>..\..\include;src\meanwhile\src;src\glib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <WarningLevel>Level3</WarningLevel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>./src/glib/lib64/glib-2.0.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin12\lib</AdditionalLibraryDirectories>
+ <SubSystem>Windows</SubSystem>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="src\conference.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\files.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\channel.c" />
+ <ClCompile Include="src\meanwhile\src\cipher.c" />
+ <ClCompile Include="src\meanwhile\src\common.c" />
+ <ClCompile Include="src\meanwhile\src\error.c" />
+ <ClCompile Include="src\meanwhile\src\message.c" />
+ <ClCompile Include="src\meanwhile\src\mpi\mpi.c" />
+ <ClCompile Include="src\meanwhile\src\mw_debug.c" />
+ <ClCompile Include="src\meanwhile\src\mw_util.c" />
+ <ClCompile Include="src\meanwhile\src\service.c" />
+ <ClCompile Include="src\meanwhile\src\session.c" />
+ <ClCompile Include="src\meanwhile\src\srvc_aware.c" />
+ <ClCompile Include="src\meanwhile\src\srvc_conf.c" />
+ <ClCompile Include="src\meanwhile\src\srvc_dir.c" />
+ <ClCompile Include="src\meanwhile\src\srvc_ft.c" />
+ <ClCompile Include="src\meanwhile\src\srvc_im.c" />
+ <ClCompile Include="src\meanwhile\src\srvc_place.c" />
+ <ClCompile Include="src\meanwhile\src\srvc_resolve.c" />
+ <ClCompile Include="src\meanwhile\src\srvc_store.c" />
+ <ClCompile Include="src\meanwhile\src\st_list.c" />
+ <ClCompile Include="src\messaging.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\options.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\places.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\sametime.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\sametime_proto.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\sametime_session.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\session_announce_win.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\StdAfx.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\userlist.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\utils.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="src\meanwhile\src\mpi\mpi-config.h" />
+ <ClInclude Include="src\meanwhile\src\mpi\mpi-types.h" />
+ <ClInclude Include="src\meanwhile\src\mpi\mpi.h" />
+ <ClInclude Include="src\meanwhile\src\mw_channel.h" />
+ <ClInclude Include="src\meanwhile\src\mw_cipher.h" />
+ <ClInclude Include="src\meanwhile\src\mw_common.h" />
+ <ClInclude Include="src\meanwhile\src\mw_debug.h" />
+ <ClInclude Include="src\meanwhile\src\mw_error.h" />
+ <ClInclude Include="src\meanwhile\src\mw_message.h" />
+ <ClInclude Include="src\meanwhile\src\mw_service.h" />
+ <ClInclude Include="src\meanwhile\src\mw_session.h" />
+ <ClInclude Include="src\meanwhile\src\mw_srvc_aware.h" />
+ <ClInclude Include="src\meanwhile\src\mw_srvc_conf.h" />
+ <ClInclude Include="src\meanwhile\src\mw_srvc_dir.h" />
+ <ClInclude Include="src\meanwhile\src\mw_srvc_ft.h" />
+ <ClInclude Include="src\meanwhile\src\mw_srvc_im.h" />
+ <ClInclude Include="src\meanwhile\src\mw_srvc_place.h" />
+ <ClInclude Include="src\meanwhile\src\mw_srvc_resolve.h" />
+ <ClInclude Include="src\meanwhile\src\mw_srvc_store.h" />
+ <ClInclude Include="src\meanwhile\src\mw_st_list.h" />
+ <ClInclude Include="src\meanwhile\src\mw_util.h" />
+ <ClInclude Include="src\resource.h" />
+ <ClInclude Include="src\sametime.h" />
+ <ClInclude Include="src\sametime_proto.h" />
+ <ClInclude Include="src\StdAfx.h" />
+ <ClInclude Include="src\version.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="res\announce.ico" />
+ <None Include="res\invite.ico" />
+ <None Include="res\online.ico" />
+ <None Include="res\part.ico" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="res\resource.rc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/Sametime/sametime_12.vcxproj.filters b/protocols/Sametime/sametime_12.vcxproj.filters
new file mode 100644
index 0000000000..e97b6b31da
--- /dev/null
+++ b/protocols/Sametime/sametime_12.vcxproj.filters
@@ -0,0 +1,217 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{b2fb3090-cd03-4404-a154-94e31360b079}</UniqueIdentifier>
+ <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{97a29dbd-67df-4a06-a2d0-a82721b109c2}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{34e64f6c-b825-450f-bf46-f974acd71f72}</UniqueIdentifier>
+ <Extensions>ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe</Extensions>
+ </Filter>
+ <Filter Include="Source Files\Meanwhile">
+ <UniqueIdentifier>{addc907a-8009-4c31-b03d-37759cb8c021}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files\Meanwhile\mpi">
+ <UniqueIdentifier>{c23f9d40-96f3-4bce-a8eb-670346163e26}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="src\conference.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\files.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\messaging.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\options.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\places.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\sametime.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\session_announce_win.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\userlist.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\utils.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\StdAfx.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\sametime_proto.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\st_list.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\channel.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\cipher.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\common.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\error.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\message.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\mw_debug.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\mw_util.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\service.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\session.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\srvc_aware.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\srvc_conf.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\srvc_dir.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\srvc_ft.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\srvc_im.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\srvc_place.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\srvc_resolve.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\srvc_store.c">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClCompile>
+ <ClCompile Include="src\meanwhile\src\mpi\mpi.c">
+ <Filter>Source Files\Meanwhile\mpi</Filter>
+ </ClCompile>
+ <ClCompile Include="src\sametime_session.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="src\resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\sametime.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\StdAfx.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\version.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\sametime_proto.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_channel.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_cipher.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_common.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_debug.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_error.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_message.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_service.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_session.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_srvc_aware.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_srvc_conf.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_srvc_dir.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_srvc_ft.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_srvc_im.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_srvc_place.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_srvc_resolve.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_srvc_store.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_st_list.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mw_util.h">
+ <Filter>Source Files\Meanwhile</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mpi\mpi-types.h">
+ <Filter>Source Files\Meanwhile\mpi</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mpi\mpi.h">
+ <Filter>Source Files\Meanwhile\mpi</Filter>
+ </ClInclude>
+ <ClInclude Include="src\meanwhile\src\mpi\mpi-config.h">
+ <Filter>Source Files\Meanwhile\mpi</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="res\announce.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\invite.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\online.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\part.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="res\resource.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/Sametime/src/StdAfx.cpp b/protocols/Sametime/src/StdAfx.cpp
new file mode 100644
index 0000000000..287357e7a4
--- /dev/null
+++ b/protocols/Sametime/src/StdAfx.cpp
@@ -0,0 +1,8 @@
+// stdafx.cpp : source file that includes just the standard includes
+// sametime.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "StdAfx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/protocols/Sametime/src/StdAfx.h b/protocols/Sametime/src/StdAfx.h
new file mode 100644
index 0000000000..a5e7c9b64f
--- /dev/null
+++ b/protocols/Sametime/src/StdAfx.h
@@ -0,0 +1,97 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+#pragma warning( disable : 4503 4786 )
+
+
+// Windows
+#define _WIN32_WINNT 0x501 // for QueueUserAPC
+#include <windows.h>
+#include <commctrl.h>
+#include <process.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+
+
+// STL
+#include <queue> // for conference.cpp, messaging.cpp
+#include <string> // for conference.cpp, userlist.cpp
+#include <map> // for messaging.cpp
+#include <fstream> // for userlist.cpp
+#include <iostream> // for userlist.cpp
+
+
+// Glib
+//
+// Subset of libs and includes from Glib v 2.26 from:
+// http://ftp.gnome.org/pub/gnome/binaries/win32/glib/2.26/glib-dev_2.26.1-1_win32.zip
+// http://ftp.gnome.org/pub/gnome/binaries/win32/glib/2.26/glib-dev_2.26.1-1_win64.zip
+//
+//
+// dll files needed in main Miranda directory:
+//
+// x32
+// libglib-2.0-0.dll from http://ftp.gnome.org/pub/gnome/binaries/win32/glib/2.26/glib_2.26.1-1_win32.zip
+// intl.dll from http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/gettext-runtime_0.18.1.1-2_win32.zip
+//
+// x64
+// libglib-2.0-0.dll from http://ftp.gnome.org/pub/gnome/binaries/win64/glib/2.26/glib_2.26.1-1_win64.zip
+// libintl-8.dll from http://ftp.gnome.org/pub/gnome/binaries/win64/dependencies/gettext-runtime_0.18.1.1-2_win64.zip
+//
+#include <glib.h> //for meanwhile and session.cpp
+
+
+// Menwhile
+// Sources of Meanwhile v 1.0.2 from
+// http://meanwhile.sourceforge.net/
+extern "C" {
+#include <mw_session.h>
+#include <mw_cipher.h>
+#include <mw_st_list.h>
+//#include <mw_util.h>
+#include <mw_service.h>
+#include <mw_channel.h>
+#include <mw_srvc_im.h>
+#include <mw_srvc_aware.h>
+#include <mw_srvc_resolve.h>
+#include <mw_srvc_store.h>
+#include <mw_srvc_place.h>
+#include <mw_srvc_ft.h>
+#include <mw_srvc_conf.h>
+#include <mw_error.h>
+#include <mw_message.h>
+};
+
+
+// Miranda
+#include <newpluginapi.h>
+#include <m_system.h>
+#include <m_protoint.h>
+#include <m_options.h>
+#include <m_skin.h>
+#include <m_clist.h>
+#include <m_message.h>
+#include <statusmodes.h>
+#include <m_langpack.h>
+#include <m_netlib.h>
+#include <m_database.h>
+#include <m_protocols.h>
+#include <m_protomod.h>
+#include <m_protosvc.h>
+#include <m_ignore.h>
+#include <m_clui.h>
+#include <m_clc.h>
+#include <m_utils.h>
+#include <m_idle.h>
+#include <m_addcontact.h>
+#include <m_popup.h>
+#include <m_chat.h>
+#include <m_genmenu.h>
+#include <m_icolib.h>
+
diff --git a/protocols/Sametime/src/conference.cpp b/protocols/Sametime/src/conference.cpp
new file mode 100644
index 0000000000..e72c089e73
--- /dev/null
+++ b/protocols/Sametime/src/conference.cpp
@@ -0,0 +1,566 @@
+#include "StdAfx.h"
+#include "sametime.h"
+
+
+
+void CloseMyConference(CSametimeProto* proto) {
+ mwConference_destroy(proto->my_conference, 0, Translate("I'm outa here."));
+ proto->my_conference = 0;
+}
+
+
+CSametimeProto* getProtoFromMwConference(mwConference* conf)
+{
+ mwServiceConference* servConference = mwConference_getServiceConference(conf);
+ mwService* service = mwServiceConference_getService(servConference);
+ mwSession* session = mwService_getSession(service);
+ return (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
+}
+
+
+/** triggered when we receive a conference invitation. Call
+ mwConference_accept to accept the invitation and join the
+ conference, or mwConference_close to reject the invitation.
+
+ @param conf the newly created conference
+ @param inviter the indentity of the user who sent the invitation
+ @param invite the invitation text
+*/
+void mwServiceConf_on_invited(mwConference* conf, mwLoginInfo* inviter, const char* invite) {
+
+ GList *members, *mem;
+ CSametimeProto* proto = getProtoFromMwConference(conf);
+ proto->debugLog(_T("mwServiceConf_on_invited() start"));
+
+ members = mem = mwConference_getMembers(conf);
+ for (;mem;mem=mem->next) {
+ if (proto->my_login_info && strcmp(proto->my_login_info->login_id, ((mwLoginInfo*)mem->data)->login_id) == 0) {
+ proto->debugLog(_T("mwServiceConf_on_invited() already present"));
+ char* utfs = mir_utf8encodeT(TranslateT("Invitation rejected - already present."));
+ mwConference_reject(conf, 0, utfs);
+ mir_free(utfs);
+ return;
+ }
+ }
+ g_list_free(members);
+
+ wchar_t ws_username[128];
+ MultiByteToWideChar(CP_UTF8, 0, (const char*)inviter->user_name, -1, ws_username, 128);
+
+ wchar_t ws_invite[512];
+ MultiByteToWideChar(CP_UTF8, 0, (const char*)invite, -1, ws_invite, 128);
+
+ if (MessageBoxW(0, ws_invite, ws_username, MB_OKCANCEL) == IDOK) {
+ proto->debugLog(_T("mwServiceConf_on_invited() mwConference_accept"));
+ mwConference_accept(conf);
+ } else {
+ proto->debugLog(_T("mwServiceConf_on_invited() mwConference_reject"));
+ char* temp = mir_utf8encodeT(TranslateT("Your invitation has been rejected."));
+ mwConference_reject(conf, 0, temp);
+ mir_free(temp);
+ }
+
+}
+
+void CSametimeProto::ClearInviteQueue() {
+
+ debugLog(_T("CSametimeProto::ClearInviteQueue() start"));
+ if (!my_conference) return;
+
+ mwIdBlock idb;
+ idb.community = 0;
+
+ while(invite_queue.size()) {
+ idb.user = (char *)invite_queue.front().c_str();
+
+ MCONTACT hContact = FindContactByUserId(idb.user);
+ if (!hContact) {
+ mwSametimeList* user_list = mwSametimeList_new();
+ char* utfs = mir_utf8encodeT(TranslateT("None"));
+ mwSametimeGroup* stgroup = mwSametimeGroup_new(user_list, mwSametimeGroup_NORMAL, utfs);
+ mwSametimeUser* stuser = mwSametimeUser_new(stgroup, mwSametimeUser_NORMAL, &idb);
+
+ hContact = AddContact(stuser, (options.add_contacts ? false : true));
+ mwSametimeList_free(user_list);
+ mir_free(utfs);
+
+ }
+
+ bool found = false;
+ GList *members, *mem;
+ members = mem = mwConference_getMembers(my_conference);
+ for (;mem;mem=mem->next) {
+ if (my_login_info && strcmp(idb.user, ((mwLoginInfo *)mem->data)->user_id) == 0) {
+ found = true;
+ break;
+ }
+ }
+ g_list_free(members);
+
+ if (!found) {
+ char* temp = mir_utf8encodeT(TranslateT("Please join this meeting."));
+ mwConference_invite(my_conference, &idb, temp);
+ mir_free(temp);
+ }
+
+ invite_queue.pop();
+ }
+}
+
+/** triggered when we enter the conference. Provides the initial
+ conference membership list as a GList of mwLoginInfo structures
+
+ @param conf the conference just joined
+ @param members mwLoginInfo list of existing conference members
+*/
+void mwServiceConf_conf_opened(mwConference* conf, GList* members)
+{
+ CSametimeProto* proto = getProtoFromMwConference(conf);
+ proto->debugLog(_T("mwServiceConf_conf_opened() start"));
+
+ TCHAR* tszConfId = mir_utf8decodeT(mwConference_getName(conf));
+ TCHAR* tszConfTitle = mir_utf8decodeT(mwConference_getTitle(conf));
+
+ // create new chat session
+ GCSESSION gcs = { sizeof(gcs) };
+ gcs.dwFlags = 0;
+ gcs.iType = GCW_CHATROOM;
+ gcs.pszModule = proto->m_szModuleName;
+ gcs.ptszID = tszConfId;
+ gcs.ptszName = tszConfTitle;
+ gcs.dwItemData = 0;
+
+ CallServiceSync(MS_GC_NEWSESSION, 0, (LPARAM)&gcs);
+ mir_free(tszConfTitle);
+
+ //add a group
+ GCDEST gcd = { proto->m_szModuleName, 0 };
+ gcd.iType = GC_EVENT_ADDGROUP;
+ gcd.ptszID = tszConfId;
+
+ GCEVENT gce = { sizeof(gce), &gcd };
+ gce.dwFlags = GCEF_ADDTOLOG;
+ gce.ptszStatus = TranslateT("Normal");
+
+ CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
+
+ // add users
+ gcd.iType = GC_EVENT_JOIN;
+
+ GList *user = members;
+ for (;user; user=user->next) {
+ proto->debugLog(_T("mwServiceConf_conf_opened() add user"));
+
+ TCHAR* tszUserName = mir_utf8decodeT(((mwLoginInfo*)user->data)->user_name);
+ TCHAR* tszUserId = mir_utf8decodeT(((mwLoginInfo*)user->data)->login_id);
+ gce.ptszNick = tszUserName;
+ gce.ptszUID = tszUserId;
+ gce.bIsMe = (strcmp(((mwLoginInfo*)user->data)->login_id, proto->my_login_info->login_id) == 0);
+
+ CallServiceSync(MS_GC_EVENT, 0, (LPARAM) &gce);
+
+ mir_free(tszUserName);
+ mir_free(tszUserId);
+ }
+
+ // finalize setup (show window)
+ gcd.iType = GC_EVENT_CONTROL;
+ CallServiceSync(MS_GC_EVENT, SESSION_INITDONE, (LPARAM)&gce);
+
+ gcd.iType = GC_EVENT_CONTROL;
+ CallServiceSync(MS_GC_EVENT, SESSION_ONLINE, (LPARAM)&gce);
+
+ if (conf == proto->my_conference) {
+ proto->ClearInviteQueue();
+ }
+
+ mir_free(tszConfId);
+}
+
+/** triggered when a conference is closed. This is typically when
+ we've left it */
+void mwServiceConf_conf_closed(mwConference* conf, guint32 reason)
+{
+ CSametimeProto* proto = getProtoFromMwConference(conf);
+ proto->debugLog(_T("mwServiceConf_conf_closed() start"));
+
+ TCHAR* tszConfId = mir_utf8decodeT(mwConference_getName(conf));
+
+ GCDEST gcd = { proto->m_szModuleName };
+ gcd.ptszID = tszConfId;
+ gcd.iType = GC_EVENT_CONTROL;
+
+ GCEVENT gce = { sizeof(gce), &gcd };
+ gce.dwFlags = GCEF_ADDTOLOG;
+
+ CallService(MS_GC_EVENT, SESSION_OFFLINE, (LPARAM)&gce);
+ CallService(MS_GC_EVENT, SESSION_TERMINATE, (LPARAM)&gce);
+ mir_free(tszConfId);
+}
+
+/** triggered when someone joins the conference */
+void mwServiceConf_on_peer_joined(mwConference* conf, mwLoginInfo* user)
+{
+ CSametimeProto* proto = getProtoFromMwConference(conf);
+ proto->debugLog(_T("mwServiceConf_on_peer_joined() start"));
+
+ TCHAR* tszConfId = mir_utf8decodeT(mwConference_getName(conf));
+
+ MCONTACT hContact = proto->FindContactByUserId(((mwLoginInfo*)user)->user_id);
+ if (!hContact) {
+ mwIdBlock idb;
+ idb.user = ((mwLoginInfo *)user)->user_id;
+ idb.community = 0;
+
+ mwSametimeList* user_list = mwSametimeList_new();
+ char* utfs = mir_utf8encodeT(TranslateT("None"));
+ mwSametimeGroup* stgroup = mwSametimeGroup_new(user_list, mwSametimeGroup_NORMAL, utfs);
+ mwSametimeUser* stuser = mwSametimeUser_new(stgroup, mwSametimeUser_NORMAL, &idb);
+
+ hContact = proto->AddContact(stuser, (proto->options.add_contacts ? false : true));
+
+ mwSametimeList_free(user_list);
+ mir_free(utfs);
+ }
+
+ // add user
+ GCDEST gcd = { proto->m_szModuleName };
+ gcd.ptszID = tszConfId;
+ gcd.iType = GC_EVENT_JOIN;
+
+ GCEVENT gce = { sizeof(gce), &gcd };
+ gce.dwFlags = GCEF_ADDTOLOG;
+ TCHAR* tszUserName = mir_utf8decodeT(((mwLoginInfo*)user)->user_name);
+ TCHAR* tszUserId = mir_utf8decodeT(((mwLoginInfo*)user)->login_id);
+ gce.ptszNick = tszUserName;
+ gce.ptszUID = tszUserId;
+ gce.ptszStatus = _T("Normal");
+ gce.time = (DWORD)time(0);
+
+ CallServiceSync(MS_GC_EVENT, 0, (LPARAM) &gce);
+
+ mir_free(tszUserName);
+ mir_free(tszUserId);
+ mir_free(tszConfId);
+}
+
+/** triggered when someone leaves the conference */
+void mwServiceConf_on_peer_parted(mwConference* conf, mwLoginInfo* user)
+{
+ CSametimeProto* proto = getProtoFromMwConference(conf);
+ proto->debugLog(_T("mwServiceConf_on_peer_parted() start"));
+
+ TCHAR* tszConfId = mir_utf8decodeT(mwConference_getName(conf));
+
+ // remove user
+ GCDEST gcd = { proto->m_szModuleName };
+ gcd.ptszID = tszConfId;
+ gcd.iType = GC_EVENT_PART;
+
+ GCEVENT gce = { sizeof(gce), &gcd };
+ gce.dwFlags = GCEF_ADDTOLOG;
+ TCHAR* tszUserName = mir_utf8decodeT(((mwLoginInfo*)user)->user_name);
+ TCHAR* tszUserId = mir_utf8decodeT(((mwLoginInfo*)user)->login_id);
+ gce.ptszNick = tszUserName;
+ gce.ptszUID = tszUserId;
+ gce.ptszStatus = _T("Normal");
+ gce.time = (DWORD)time(0);
+
+ CallServiceSync(MS_GC_EVENT, 0, (LPARAM)(GCEVENT *) &gce);
+
+ mir_free(tszUserName);
+ mir_free(tszUserId);
+ mir_free(tszConfId);
+}
+
+/** triggered when someone says something */
+void mwServiceConf_on_text(mwConference* conf, mwLoginInfo* user, const char* what)
+{
+ CSametimeProto* proto = getProtoFromMwConference(conf);
+ proto->debugLog(_T("mwServiceConf_on_text() start"));
+
+ TCHAR* tszConfId = mir_utf8decodeT(mwConference_getName(conf));
+
+ GCDEST gcd = { proto->m_szModuleName };
+ gcd.ptszID = tszConfId;
+ gcd.iType = GC_EVENT_MESSAGE;
+
+ GCEVENT gce = { sizeof(gce), &gcd };
+ gce.dwFlags = GCEF_ADDTOLOG;
+
+ TCHAR* textT = mir_utf8decodeT(what);
+ TCHAR* tszUserName = mir_utf8decodeT(((mwLoginInfo*)user)->user_name);
+ TCHAR* tszUserId = mir_utf8decodeT(((mwLoginInfo*)user)->login_id);
+ gce.ptszText = textT;
+ gce.ptszNick = tszUserName;
+ gce.ptszUID = tszUserId;
+ gce.time = (DWORD)time(0);
+
+ CallService(MS_GC_EVENT, 0, (LPARAM)(GCEVENT *) &gce);
+
+ mir_free(textT);
+ mir_free(tszUserName);
+ mir_free(tszUserId);
+ mir_free(tszConfId);
+}
+
+/** typing notification */
+void mwServiceConf_on_typing(mwConference* conf, mwLoginInfo* who, gboolean typing)
+{
+ CSametimeProto* proto = getProtoFromMwConference(conf);
+ proto->debugLog(_T("mwServiceConf_on_typing() start"));
+ ///TODO unimplemented
+}
+
+/** optional. called from mwService_free */
+void mwServiceConf_clear(mwServiceConference* srvc)
+{
+}
+
+mwConferenceHandler mwConference_handler = {
+ mwServiceConf_on_invited,
+ mwServiceConf_conf_opened,
+ mwServiceConf_conf_closed,
+ mwServiceConf_on_peer_joined,
+ mwServiceConf_on_peer_parted,
+ mwServiceConf_on_text,
+ mwServiceConf_on_typing,
+ mwServiceConf_clear
+};
+
+void CSametimeProto::TerminateConference(char* name)
+{
+ debugLog(_T("CSametimeProto::TerminateConference() start"));
+
+ GList *conferences, *conf;
+ conferences = conf = mwServiceConference_getConferences(service_conference);
+ for (;conf;conf = conf->next) {
+ if (strcmp(name, mwConference_getName((mwConference*)conf->data)) == 0) {
+
+ TCHAR* idt = mir_utf8decodeT(name);
+ GCDEST gcd = {m_szModuleName, idt, GC_EVENT_CONTROL};
+
+ GCEVENT gce = { sizeof(gce), &gcd };
+ gce.dwFlags = GCEF_ADDTOLOG;
+ CallService(MS_GC_EVENT, SESSION_TERMINATE, (LPARAM)&gce);
+
+ mir_free(idt);
+ }
+ }
+ g_list_free(conferences);
+}
+
+
+int CSametimeProto::GcEventHook(WPARAM wParam, LPARAM lParam) {
+
+ GCHOOK* gch = (GCHOOK*)lParam;
+
+ if (strcmp(gch->pDest->pszModule, m_szModuleName) != 0) return 0;
+
+ GList *conferences, *conf;
+ conferences = conf = mwServiceConference_getConferences(service_conference);
+ for (;conf;conf = conf->next) {
+ TCHAR* tszConfId = mir_utf8decodeT(mwConference_getName((mwConference*)conf->data));
+ if (_tcscmp(gch->pDest->ptszID, tszConfId) == 0) {
+
+ switch(gch->pDest->iType) {
+ case GC_USER_MESSAGE:
+ {
+ debugLog(_T("CSametimeProto::GcEventHook() GC_USER_MESSAGE"));
+ char* utf_msg;
+ utf_msg = mir_utf8encodeT(gch->ptszText);
+ mwConference_sendText((mwConference*)conf->data, utf_msg);
+ mir_free(utf_msg);
+ }
+ break;
+ case GC_SESSION_TERMINATE:
+ {
+ if (my_conference == conf->data){
+ debugLog(_T("CSametimeProto::GcEventHook() GC_SESSION_TERMINATE CloseMyConference"));
+ CloseMyConference(this);
+ } else {
+ debugLog(_T("CSametimeProto::GcEventHook() GC_SESSION_TERMINATE mwConference_destroy"));
+ char* utfs = mir_utf8encodeT(TranslateT("I'm outa here."));
+ mwConference_destroy((mwConference*)conf->data, 0, utfs);
+ mir_free(utfs);
+ }
+ }
+ break;
+ }
+
+ break;
+ }
+ mir_free(tszConfId);
+ }
+
+ g_list_free(conferences);
+
+ return 0;
+}
+
+int CSametimeProto::ChatDeleted(MCONTACT hContact) {
+
+ if (db_get_b(hContact, m_szModuleName, "ChatRoom", 0) == 0)
+ return 0;
+
+ debugLog(_T("CSametimeProto::ChatDeleted() hContact=[%x]"), hContact);
+ DBVARIANT dbv;
+ if (!db_get_s(hContact, m_szModuleName, "ChatRoomID", &dbv)) {
+ TerminateConference(dbv.pszVal);
+ db_free(&dbv);
+ }
+
+ return 0;
+}
+
+
+INT_PTR CSametimeProto::onMenuLeaveChat(WPARAM wParam, LPARAM lParam)
+{
+ MCONTACT hContact = (MCONTACT)wParam;
+ debugLog(_T("CSametimeProto::onMenuLeaveChat() hContact=[%x]"), hContact);
+ ChatDeleted(hContact);
+ return 0;
+}
+
+
+INT_PTR CSametimeProto::onMenuCreateChat(WPARAM wParam, LPARAM lParam)
+{
+ MCONTACT hContact = (MCONTACT)wParam;
+ debugLog(_T("CSametimeProto::onMenuCreateChat() hContact=[%x]"), hContact);
+ mwAwareIdBlock id_block;
+ mwIdBlock idb;
+ if (my_login_info && GetAwareIdFromContact(hContact, &id_block)) {
+ TCHAR title[512];
+ TCHAR* ts = mir_utf8decodeT(my_login_info->user_name);
+ mir_sntprintf(title, SIZEOF(title), TranslateT("%s's Conference"), ts);
+ mir_free(ts);
+
+ idb.user = id_block.user;
+ idb.community = id_block.community;
+
+ invite_queue.push(idb.user);
+
+ if (!my_conference) {
+ debugLog(_T("CSametimeProto::onMenuCreateChat() mwConference_open"));
+ char* utfs;
+ my_conference = mwConference_new(service_conference, utfs = mir_utf8encodeT(title));
+ mwConference_open(my_conference);
+ mir_free(utfs);
+ } else {
+ debugLog(_T("CSametimeProto::onMenuCreateChat() ClearInviteQueue"));
+ ClearInviteQueue();
+ }
+
+ free(id_block.user);
+ }
+
+ return 0;
+}
+
+int CSametimeProto::PrebuildContactMenu(WPARAM wParam, LPARAM lParam)
+{
+ MCONTACT hContact = (MCONTACT)wParam;
+ debugLog(_T("CSametimeProto::PrebuildContactMenu() hContact=[%x]"), hContact);
+ CLISTMENUITEM mi = {0};
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIM_FLAGS | (db_get_b(hContact, m_szModuleName, "ChatRoom", 0) == 1 ? 0 : CMIF_HIDDEN);
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hLeaveChatMenuItem, (LPARAM)&mi);
+
+ // if user is already in our meeting,
+ bool not_present = true;
+ DBVARIANT dbv;
+ if (my_conference && !db_get_utf(hContact, m_szModuleName, "stid", &dbv)) {
+ char* user_id = dbv.pszVal;
+
+ GList *members, *mem;
+ members = mem = mwConference_getMembers(my_conference);
+ for (;mem;mem=mem->next) {
+ if (my_login_info && strcmp(user_id, ((mwLoginInfo *)mem->data)->user_id) == 0) {
+ not_present = false;
+ break;
+ }
+ }
+ g_list_free(members);
+
+ db_free(&dbv);
+ }
+ mi.flags = CMIM_FLAGS | CMIF_NOTOFFLINE | (db_get_b(hContact, m_szModuleName, "ChatRoom", 0) == 0 && not_present ? 0 : CMIF_HIDDEN);
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hCreateChatMenuItem, (LPARAM)&mi);
+
+ return 0;
+}
+
+void CSametimeProto::InitConference()
+{
+ debugLog(_T("CSametimeProto::InitConference()"));
+
+ my_login_info = mwSession_getLoginInfo(session);
+
+ service_conference = mwServiceConference_new(session, &mwConference_handler);
+ mwSession_addService(session, (struct mwService*)service_conference);
+
+ HookProtoEvent(ME_GC_EVENT, &CSametimeProto::GcEventHook);
+}
+
+void CSametimeProto::DeinitConference()
+{
+ GList *conferences, *conf;
+ debugLog(_T("CSametimeProto::DeinitConference()"));
+
+ if (service_conference){
+ conferences = conf = mwServiceConference_getConferences(service_conference);
+ for (;conf;conf = conf->next) {
+ if (my_conference == conf->data) CloseMyConference(this);
+ else {
+ char* utfs = mir_utf8encodeT(TranslateT("I'm outa here."));
+ mwConference_destroy((mwConference*)conf->data, 0, utfs);
+ mir_free(utfs);
+ }
+ }
+ g_list_free(conferences);
+ }
+
+ my_login_info = 0;
+
+ mwSession_removeService(session, mwService_CONFERENCE);
+ if (service_conference){
+ mwService_free((mwService*)service_conference);
+ service_conference = 0;
+ }
+}
+
+void CSametimeProto::InitConferenceMenu()
+{
+ debugLog(_T("CSametimeProto::InitConferenceMenu()"));
+
+ CreateProtoService(MS_SAMETIME_MENULEAVECHAT, &CSametimeProto::onMenuLeaveChat);
+ CreateProtoService(MS_SAMETIME_MENUCREATECHAT, &CSametimeProto::onMenuCreateChat);
+
+ char service[128];
+
+ CLISTMENUITEM mi = { sizeof(mi) };
+ mi.flags = CMIF_TCHAR | CMIF_NOTOFFLINE;
+ mi.pszContactOwner = m_szModuleName;
+
+ mi.ptszName = LPGENT("Leave Conference");
+ mir_snprintf(service, sizeof(service), "%s%s", m_szModuleName, MS_SAMETIME_MENULEAVECHAT);
+ mi.pszService = service;
+ mi.icolibItem = GetIconHandle(IDI_ICON_LEAVE);
+ hLeaveChatMenuItem = Menu_AddContactMenuItem(&mi);
+
+ mi.ptszName = LPGENT("Start Conference");
+ mir_snprintf(service, sizeof(service), "%s%s", m_szModuleName, MS_SAMETIME_MENUCREATECHAT);
+ mi.pszService = service;
+ mi.icolibItem = GetIconHandle(IDI_ICON_INVITE);
+ hCreateChatMenuItem = Menu_AddContactMenuItem(&mi);
+
+ HookProtoEvent(ME_CLIST_PREBUILDCONTACTMENU, &CSametimeProto::PrebuildContactMenu);
+}
+
+void CSametimeProto::DeinitConferenceMenu()
+{
+ debugLog(_T("CSametimeProto::DeinitConferenceMenu()"));
+ CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hLeaveChatMenuItem, (LPARAM)0);
+ CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hCreateChatMenuItem, (LPARAM)0);
+}
+
diff --git a/protocols/Sametime/src/files.cpp b/protocols/Sametime/src/files.cpp
new file mode 100644
index 0000000000..a08fa49968
--- /dev/null
+++ b/protocols/Sametime/src/files.cpp
@@ -0,0 +1,457 @@
+#include "StdAfx.h"
+#include "sametime.h"
+
+
+CSametimeProto* getProtoFromMwFileTransfer(mwFileTransfer* ft)
+{
+ mwServiceFileTransfer* serviceFT = mwFileTransfer_getService(ft);
+ mwService* service = mwServiceFileTransfer_getService(serviceFT);
+ mwSession* session = mwService_getSession(service);
+ return (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
+}
+
+
+/** an incoming file transfer has been offered */
+void mwFileTransfer_offered(mwFileTransfer* ft) {
+
+ CSametimeProto* proto = getProtoFromMwFileTransfer(ft);
+ proto->debugLog(_T("mwFileTransfer_offered() start"));
+
+ const mwIdBlock* idb = mwFileTransfer_getUser(ft);
+ MCONTACT hContact = proto->FindContactByUserId(idb->user);
+ proto->debugLog(_T("Sametime mwFileTransfer_offered hContact=[%x]"), hContact);
+
+ if (!hContact) {
+ mwSametimeList* user_list = mwSametimeList_new();
+ mwSametimeGroup* stgroup = mwSametimeGroup_new(user_list, mwSametimeGroup_NORMAL, Translate("None"));
+ mwSametimeUser* stuser = mwSametimeUser_new(stgroup, mwSametimeUser_NORMAL, (mwIdBlock*)idb);
+ hContact = proto->AddContact(stuser, (proto->options.add_contacts ? false : true));
+ }
+
+ proto->ProtoBroadcastAck(hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, (HANDLE)ft, 0);
+
+ TCHAR* filenameT = mir_utf8decodeT(mwFileTransfer_getFileName(ft));
+ const char* message = mwFileTransfer_getMessage(ft);
+ TCHAR descriptionT[512];
+ if (message) {
+ TCHAR* messageT = mir_utf8decodeT(message);
+ mir_sntprintf(descriptionT, SIZEOF(descriptionT), _T("%s - %s"), filenameT, messageT);
+ mir_free(messageT);
+ } else {
+ mir_sntprintf(descriptionT, SIZEOF(descriptionT), _T("%s"), filenameT);
+ }
+
+ PROTORECVFILET pre = {0};
+ pre.flags = PREF_TCHAR;
+ pre.fileCount = 1;
+ pre.timestamp = time(NULL);
+ pre.tszDescription = descriptionT;
+ pre.ptszFiles = &filenameT;
+ pre.lParam = (LPARAM)ft;
+
+ ProtoChainRecvFile(hContact, &pre);
+
+ mir_free(filenameT);
+
+}
+
+//returns 0 if finished with current file
+int SendFileChunk(CSametimeProto* proto, mwFileTransfer* ft, FileTransferClientData* ftcd) {
+ DWORD bytes_read;
+ mwOpaque o;
+
+ if (!ftcd || !ftcd->buffer)
+ return 0;
+
+ if (!ReadFile(ftcd->hFile, ftcd->buffer, FILE_BUFF_SIZE, &bytes_read, 0)) {
+ proto->debugLog(_T("Sametime closing file transfer (SendFileChunk)"));
+ mwFileTransfer_close(ft, mwFileTransfer_SUCCESS);
+ return 0;
+ }
+ o.data = (unsigned char*)ftcd->buffer;
+ o.len = bytes_read;
+
+ mwFileTransfer_send(ft, &o);
+
+ return bytes_read;
+}
+
+void __cdecl SendThread(LPVOID param) {
+
+ mwFileTransfer* ft = (mwFileTransfer*)param;
+ if (!ft) return;
+ CSametimeProto* proto = getProtoFromMwFileTransfer(ft);
+ FileTransferClientData* ftcd = (FileTransferClientData*)mwFileTransfer_getClientData(ft);
+
+ proto->debugLog(_T("SendThread() start"));
+
+ PROTOFILETRANSFERSTATUS pfts = {0};
+
+ pfts.cbSize = sizeof(pfts);
+ pfts.flags = PFTS_UTF;
+ pfts.hContact = ftcd->hContact;
+ if (ftcd->sending == 1){
+ pfts.flags |= PFTS_SENDING;
+ }
+ pfts.pszFiles = NULL;
+ pfts.totalFiles = ftcd->first->ft_count;
+ pfts.totalBytes = ftcd->first->totalSize;
+
+ while(SendFileChunk(proto, ft, ftcd) && !Miranda_Terminated()) {
+
+ pfts.currentFileNumber = ftcd->ft_number;
+ pfts.totalProgress = ftcd->sizeToHere + mwFileTransfer_getSent(ft);
+ pfts.szWorkingDir = ftcd->save_path;
+ pfts.szCurrentFile = (char*)mwFileTransfer_getFileName(ft);
+ pfts.currentFileSize = mwFileTransfer_getFileSize(ft);
+ pfts.currentFileProgress = mwFileTransfer_getSent(ft);
+ pfts.currentFileTime = 0; //?
+
+ proto->ProtoBroadcastAck(ftcd->hContact, ACKTYPE_FILE, ACKRESULT_DATA, ftcd->hFt, (LPARAM)&pfts);
+
+ SleepEx(500,TRUE);
+ }
+
+ proto->ProtoBroadcastAck(ftcd->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ftcd->hFt, 0);
+
+ mwFileTransfer_removeClientData(ft);
+ if (ftcd->save_path) free(ftcd->save_path);
+ if (ftcd->buffer) delete[] ftcd->buffer;
+ delete ftcd;
+
+ proto->debugLog(_T("SendThread() end"));
+ return;
+}
+
+/** a file transfer has been fully initiated */
+void mwFileTransfer_opened(mwFileTransfer* ft) {
+
+ CSametimeProto* proto = getProtoFromMwFileTransfer(ft);
+ FileTransferClientData* ftcd = (FileTransferClientData*)mwFileTransfer_getClientData(ft);
+
+ proto->debugLog(_T("Sametime mwFileTransfer_opened start"));
+
+ if (ftcd->sending) {
+ // create a thread to send chunks - since it seems not all clients send acks for each of our chunks!
+ mir_forkthread(SendThread, (void*)ft);
+ }
+}
+
+/** a file transfer has been closed. Check the status of the file
+ transfer to determine if the transfer was complete or if it had
+ been interrupted */
+void mwFileTransfer_closed(mwFileTransfer* ft, guint32 code) {
+
+ CSametimeProto* proto = getProtoFromMwFileTransfer(ft);
+ FileTransferClientData* ftcd = (FileTransferClientData*)mwFileTransfer_getClientData(ft);
+ proto->debugLog(_T("mwFileTransfer_closed() start"));
+
+ if (ftcd) {
+ if (ftcd->hFile != INVALID_HANDLE_VALUE)
+ CloseHandle(ftcd->hFile);
+
+ if (code != mwFileTransfer_SUCCESS || !mwFileTransfer_isDone(ft)) {
+ if (!ftcd->sending) {
+ char fn[MAX_PATH];
+ if (ftcd->save_path) strcpy(fn, ftcd->save_path);
+ else fn[0] = 0;
+ strcat(fn, mwFileTransfer_getFileName(ft));
+
+ DeleteFileA(fn);
+ }
+
+ if (code == mwFileTransfer_REJECTED) {
+ proto->ProtoBroadcastAck(ftcd->hContact, ACKTYPE_FILE, ACKRESULT_DENIED, ftcd->hFt, 0);
+ } else {
+ proto->ProtoBroadcastAck(ftcd->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ftcd->hFt, 0);
+ }
+
+ if (ftcd->sending) {
+ FileTransferClientData* ftcd_next = ftcd->next, *ftcd_temp;
+ while(ftcd_next) {
+ mwFileTransfer_free((mwFileTransfer*)ftcd_next->ft);
+ ftcd_temp = ftcd_next->next;
+
+ if (ftcd_next->hFile != INVALID_HANDLE_VALUE)
+ CloseHandle(ftcd->hFile);
+
+ if (ftcd_next->save_path) free(ftcd_next->save_path);
+ if (ftcd_next->buffer) delete[] ftcd_next->buffer;
+ delete ftcd_next;
+ ftcd_next = ftcd_temp;
+ }
+ } else {
+ mwFileTransfer_removeClientData(ft);
+ if (ftcd->save_path) free(ftcd->save_path);
+ if (ftcd->buffer) delete[] ftcd->buffer;
+ delete ftcd;
+
+ mwFileTransfer_free(ft);
+ }
+
+ } else {
+ if (ftcd->sending) {
+ // check if we have more files to send...
+ if (ftcd->next) {
+ proto->ProtoBroadcastAck(ftcd->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ftcd->hFt, 0);
+ mwFileTransfer_offer(ftcd->next->ft);
+ }
+ } else {
+ proto->ProtoBroadcastAck(ftcd->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ftcd->hFt, 0);
+
+ mwFileTransfer_removeClientData(ft);
+ if (ftcd->save_path) free(ftcd->save_path);
+ if (ftcd->buffer) delete[] ftcd->buffer;
+ delete ftcd;
+
+ mwFileTransfer_free(ft);
+ }
+ }
+
+ }
+
+}
+
+/** receive a chunk of a file from an inbound file transfer. */
+void mwFileTransfer_recv(mwFileTransfer* ft, struct mwOpaque* data) {
+
+ CSametimeProto* proto = getProtoFromMwFileTransfer(ft);
+ FileTransferClientData* ftcd = (FileTransferClientData*)mwFileTransfer_getClientData(ft);
+ proto->debugLog(_T("mwFileTransfer_recv() start"));
+
+ DWORD bytes_written;
+ if (!WriteFile(ftcd->hFile, data->data, data->len, &bytes_written, 0)) {
+ proto->debugLog(_T("mwFileTransfer_recv() !WriteFile"));
+ mwFileTransfer_cancel(ft);
+ proto->ProtoBroadcastAck(ftcd->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ftcd->hFt, 0);
+ proto->debugLog(_T("mwFileTransfer_recv() ACKRESULT_FAILED"));
+ } else {
+ //if (mwFileTransfer_isOpen(ft))
+ mwFileTransfer_ack(ft); // acknowledge chunk
+
+ PROTOFILETRANSFERSTATUS pfts = {0};
+ pfts.cbSize = sizeof(pfts);
+ pfts.flags = PFTS_UTF;
+ pfts.hContact = ftcd->hContact;
+ if (ftcd->sending == 1){
+ pfts.flags |= PFTS_SENDING;
+ }
+ pfts.pszFiles = NULL;
+ pfts.totalFiles = 1;
+ pfts.currentFileNumber = 0;
+ pfts.totalBytes = mwFileTransfer_getFileSize(ft);
+ pfts.totalProgress = mwFileTransfer_getSent(ft);
+ pfts.szWorkingDir = ftcd->save_path;
+ pfts.szCurrentFile = (char*)mwFileTransfer_getFileName(ft);
+ pfts.currentFileSize = mwFileTransfer_getFileSize(ft);
+ pfts.currentFileProgress = mwFileTransfer_getSent(ft);
+ pfts.currentFileTime = 0; //?
+
+ proto->ProtoBroadcastAck(ftcd->hContact, ACKTYPE_FILE, ACKRESULT_DATA, ftcd->hFt, (LPARAM)&pfts);
+ proto->debugLog(_T("mwFileTransfer_recv() ACKRESULT_DATA"));
+
+ if (mwFileTransfer_isDone(ft)){
+ proto->ProtoBroadcastAck(ftcd->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ftcd->hFt, 0);
+ proto->debugLog(_T("mwFileTransfer_recv() ACKRESULT_SUCCESS"));
+ }
+ }
+
+}
+
+/** received an ack for a sent chunk on an outbound file transfer.
+ this indicates that a previous call to mwFileTransfer_send has
+ reached the target and that the target has responded. */
+void mwFileTransfer_handle_ack(mwFileTransfer* ft) {
+ // see SendThread above - not all clients send us acks
+ CSametimeProto* proto = getProtoFromMwFileTransfer(ft);
+ //FileTransferClientData* ftcd = (FileTransferClientData*)mwFileTransfer_getClientData(ft);
+ proto->debugLog(_T("mwFileTransfer_handle_ack()"));
+}
+
+/** optional. called from mwService_free */
+void mwFileTransfer_clear(mwServiceFileTransfer* srvc) {
+
+}
+
+mwFileTransferHandler mwFileTransfer_handler = {
+ mwFileTransfer_offered,
+ mwFileTransfer_opened,
+ mwFileTransfer_closed,
+ mwFileTransfer_recv,
+ mwFileTransfer_handle_ack,
+ mwFileTransfer_clear
+};
+
+HANDLE CSametimeProto::SendFilesToUser(MCONTACT hContact, PROTOCHAR** files, const PROTOCHAR* ptszDesc)
+{
+ debugLog(_T("CSametimeProto::SendFilesToUser() start"));
+
+ mwAwareIdBlock id_block;
+ if (GetAwareIdFromContact(hContact, &id_block)) {
+ mwIdBlock idb;
+ idb.user = id_block.user;
+ idb.community = id_block.community;
+
+ HANDLE hFile;
+ DWORD filesize;
+ FileTransferClientData *ftcd, *prev_ftcd = 0, *first_ftcd = 0;
+ mwFileTransfer *ft, *first_ft = 0;
+
+ TCHAR* fn;
+
+ for (int i = 0; files[i]; i++) {
+ hFile = CreateFile(files[i], GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
+ if (hFile != INVALID_HANDLE_VALUE) {
+ filesize = GetFileSize(hFile, 0);
+
+ fn = _tcsrchr(files[i], '\\');
+ if (fn) fn++;
+
+ char* pszDesc_utf8 = mir_utf8encodeT(ptszDesc);
+ char* pszFile_utf8;
+ if (fn) {
+ pszFile_utf8 = mir_utf8encodeT(fn);
+ } else {
+ pszFile_utf8 = mir_utf8encodeT(files[i]);
+ }
+ ft = mwFileTransfer_new(service_files, &idb, pszDesc_utf8, pszFile_utf8, filesize);
+ mir_free(pszFile_utf8);
+ mir_free(pszDesc_utf8);
+
+ ftcd = new FileTransferClientData;
+ memset((void*)ftcd, 0, sizeof(FileTransferClientData));
+
+ ftcd->ft = ft;
+ ftcd->hContact = hContact;
+
+ ftcd->next = 0;
+ if (prev_ftcd) {
+ prev_ftcd->next = ftcd; // link into list
+
+ // each node contains a pointer to the first - it will contain infor linke the count etc
+ ftcd->first = prev_ftcd->first;
+ } else {
+ ftcd->first = ftcd;
+ }
+
+ if (!first_ft) first_ft = ft;
+
+ ftcd->sending = true;
+ ftcd->hFile = hFile;
+ ftcd->hFt = (HANDLE)first_ft;
+
+ ftcd->save_path = 0;
+ ftcd->buffer = new char[FILE_BUFF_SIZE];
+
+ ftcd->ft_number = ftcd->first->ft_count;
+ ftcd->first->ft_count++;
+ ftcd->sizeToHere = ftcd->first->totalSize;
+ ftcd->first->totalSize += filesize;
+
+ mwFileTransfer_setClientData(ft, (gpointer)ftcd, 0);
+
+ prev_ftcd = ftcd;
+ }
+ }
+
+ free(id_block.user);
+
+ if (first_ft) {
+ mwFileTransfer_offer(first_ft);
+ return (HANDLE)first_ft;
+ }
+
+ }
+
+ return 0;
+}
+
+HANDLE CSametimeProto::AcceptFileTransfer(MCONTACT hContact, HANDLE hFt, char* save_path)
+{
+
+ mwFileTransfer* ft = (mwFileTransfer*)(hFt);
+ CSametimeProto* proto = getProtoFromMwFileTransfer(ft);
+ debugLog(_T("CSametimeProto::AcceptFileTransfer() start"));
+
+ FileTransferClientData* ftcd = new FileTransferClientData;
+ memset((void*)ftcd, 0, sizeof(FileTransferClientData));
+ ftcd->ft = ft;
+ ftcd->sending = false;
+ ftcd->hFt = (HANDLE)ft;
+
+ if (save_path) // save path
+ ftcd->save_path = _strdup(save_path);
+ else
+ ftcd->save_path = 0;
+
+ mwFileTransfer_setClientData(ft, (gpointer)ftcd, 0);
+
+ char fp[MAX_PATH];
+ char* fn = strrchr((char*)mwFileTransfer_getFileName(ft), '\\');
+ if (fn) fn++;
+
+ if (ftcd->save_path)
+ strcpy(fp, ftcd->save_path);
+ else
+ fp[0] = 0;
+
+ if (fn) strcat(fp, fn);
+ else strcat(fp, mwFileTransfer_getFileName(ft));
+
+ ftcd->hFile = CreateFileA(fp, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS, 0, 0);
+ if (ftcd->hFile == INVALID_HANDLE_VALUE) {
+ debugLog(_T("CSametimeProto::AcceptFileTransfer() INVALID_HANDLE_VALUE"));
+ mwFileTransfer_close(ft, mwFileTransfer_ERROR);
+ return 0;
+ }
+
+ ftcd->hContact = hContact;
+
+ mwFileTransfer_setClientData(ft, (gpointer)ftcd, 0);
+
+ mwFileTransfer_accept(ft);
+ return hFt;
+}
+
+
+void CSametimeProto::RejectFileTransfer(HANDLE hFt)
+{
+ mwFileTransfer* ft = (mwFileTransfer*)hFt;
+ CSametimeProto* proto = getProtoFromMwFileTransfer(ft);
+ debugLog(_T("CSametimeProto::RejectFileTransfer() start"));
+
+ mwFileTransfer_reject(ft);
+}
+
+
+void CSametimeProto::CancelFileTransfer(HANDLE hFt)
+{
+ mwFileTransfer* ft = (mwFileTransfer*)hFt;
+ CSametimeProto* proto = getProtoFromMwFileTransfer(ft);
+ debugLog(_T("CSametimeProto::CancelFileTransfer() start"));
+
+ FileTransferClientData* ftcd = (FileTransferClientData*)mwFileTransfer_getClientData(ft);
+
+ if (ftcd) {
+ while(mwFileTransfer_isDone(ftcd->ft) && ftcd)
+ ftcd = ftcd->next;
+
+ if (ftcd) mwFileTransfer_cancel(ftcd->ft);
+ } else
+ mwFileTransfer_cancel(ft);
+}
+
+void CSametimeProto::InitFiles()
+{
+ debugLog(_T("CSametimeProto::InitFiles()"));
+ mwSession_addService(session, (mwService*)(service_files = mwServiceFileTransfer_new(session, &mwFileTransfer_handler)));
+}
+
+void CSametimeProto::DeinitFiles()
+{
+ debugLog(_T("CSametimeProto::DeinitFiles()"));
+ mwSession_removeService(session, mwService_FILE_TRANSFER);
+ mwService_free((mwService*)service_files);
+ service_files = 0;
+}
+
diff --git a/protocols/Sametime/src/glib/include/glib.h b/protocols/Sametime/src/glib/include/glib.h
new file mode 100644
index 0000000000..06d0190b24
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib.h
@@ -0,0 +1,99 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#ifndef __G_LIB_H__
+#define __G_LIB_H__
+
+#define __GLIB_H_INSIDE__
+
+#include <glib/galloca.h>
+#include <glib/garray.h>
+#include <glib/gasyncqueue.h>
+#include <glib/gatomic.h>
+#include <glib/gbacktrace.h>
+#include <glib/gbase64.h>
+#include <glib/gbitlock.h>
+#include <glib/gbookmarkfile.h>
+#include <glib/gcache.h>
+#include <glib/gchecksum.h>
+#include <glib/gcompletion.h>
+#include <glib/gconvert.h>
+#include <glib/gdataset.h>
+#include <glib/gdate.h>
+#include <glib/gdatetime.h>
+#include <glib/gdir.h>
+#include <glib/gerror.h>
+#include <glib/gfileutils.h>
+#include <glib/ghash.h>
+#include <glib/ghook.h>
+#include <glib/ghostutils.h>
+#include <glib/giochannel.h>
+#include <glib/gkeyfile.h>
+#include <glib/glist.h>
+#include <glib/gmacros.h>
+#include <glib/gmain.h>
+#include <glib/gmappedfile.h>
+#include <glib/gmarkup.h>
+#include <glib/gmem.h>
+#include <glib/gmessages.h>
+#include <glib/gnode.h>
+#include <glib/goption.h>
+#include <glib/gpattern.h>
+#include <glib/gpoll.h>
+#include <glib/gprimes.h>
+#include <glib/gqsort.h>
+#include <glib/gquark.h>
+#include <glib/gqueue.h>
+#include <glib/grand.h>
+#include <glib/grel.h>
+#include <glib/gregex.h>
+#include <glib/gscanner.h>
+#include <glib/gsequence.h>
+#include <glib/gshell.h>
+#include <glib/gslice.h>
+#include <glib/gslist.h>
+#include <glib/gspawn.h>
+#include <glib/gstrfuncs.h>
+#include <glib/gstring.h>
+#include <glib/gtestutils.h>
+#include <glib/gthread.h>
+#include <glib/gthreadpool.h>
+#include <glib/gtimer.h>
+#include <glib/gtimezone.h>
+#include <glib/gtree.h>
+#include <glib/gtypes.h>
+#include <glib/gunicode.h>
+#include <glib/gurifuncs.h>
+#include <glib/gutils.h>
+#include <glib/gvarianttype.h>
+#include <glib/gvariant.h>
+#ifdef G_PLATFORM_WIN32
+#include <glib/gwin32.h>
+#endif
+
+#undef __GLIB_H_INSIDE__
+
+#endif /* __G_LIB_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/galloca.h b/protocols/Sametime/src/glib/include/glib/galloca.h
new file mode 100644
index 0000000000..8876836a6f
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/galloca.h
@@ -0,0 +1,110 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_ALLOCA_H__
+#define __G_ALLOCA_H__
+
+#include <glib/gtypes.h>
+
+#ifdef __GNUC__
+/* GCC does the right thing */
+# undef alloca
+# define alloca(size) __builtin_alloca (size)
+#elif defined (GLIB_HAVE_ALLOCA_H)
+/* a native and working alloca.h is there */
+# include <alloca.h>
+#else /* !__GNUC__ && !GLIB_HAVE_ALLOCA_H */
+# if defined(_MSC_VER) || defined(__DMC__)
+# include <malloc.h>
+# define alloca _alloca
+# else /* !_MSC_VER && !__DMC__ */
+# ifdef _AIX
+# pragma alloca
+# else /* !_AIX */
+# ifndef alloca /* predefined by HP cc +Olibcalls */
+G_BEGIN_DECLS
+char *alloca ();
+G_END_DECLS
+# endif /* !alloca */
+# endif /* !_AIX */
+# endif /* !_MSC_VER && !__DMC__ */
+#endif /* !__GNUC__ && !GLIB_HAVE_ALLOCA_H */
+
+/**
+ * g_alloca:
+ * @size: number of bytes to allocate.
+ *
+ * Allocates @size bytes on the stack; these bytes will be freed when the current
+ * stack frame is cleaned up. This macro essentially just wraps the alloca()
+ * function present on most UNIX variants.
+ * Thus it provides the same advantages and pitfalls as alloca():
+ * <variablelist>
+ * <varlistentry><term></term><listitem><para>
+ * + alloca() is very fast, as on most systems it's implemented by just adjusting
+ * the stack pointer register.
+ * </para></listitem></varlistentry>
+ * <varlistentry><term></term><listitem><para>
+ * + It doesn't cause any memory fragmentation, within its scope, separate alloca()
+ * blocks just build up and are released together at function end.
+ * </para></listitem></varlistentry>
+ * <varlistentry><term></term><listitem><para>
+ * - Allocation sizes have to fit into the current stack frame. For instance in a
+ * threaded environment on Linux, the per-thread stack size is limited to 2 Megabytes,
+ * so be sparse with alloca() uses.
+ * </para></listitem></varlistentry>
+ * <varlistentry><term></term><listitem><para>
+ * - Allocation failure due to insufficient stack space is not indicated with a %NULL
+ * return like e.g. with malloc(). Instead, most systems probably handle it the same
+ * way as out of stack space situations from infinite function recursion, i.e.
+ * with a segmentation fault.
+ * </para></listitem></varlistentry>
+ * <varlistentry><term></term><listitem><para>
+ * - Special care has to be taken when mixing alloca() with GNU C variable sized arrays.
+ * Stack space allocated with alloca() in the same scope as a variable sized array
+ * will be freed together with the variable sized array upon exit of that scope, and
+ * not upon exit of the enclosing function scope.
+ * </para></listitem></varlistentry>
+ * </variablelist>
+ *
+ * Returns: space for @size bytes, allocated on the stack
+ */
+#define g_alloca(size) alloca (size)
+/**
+ * g_newa:
+ * @struct_type: Type of memory chunks to be allocated
+ * @n_structs: Number of chunks to be allocated
+ *
+ * Wraps g_alloca() in a more typesafe manner.
+ *
+ * Returns: Pointer to stack space for @n_structs chunks of type @struct_type
+ */
+#define g_newa(struct_type, n_structs) ((struct_type*) g_alloca (sizeof (struct_type) * (gsize) (n_structs)))
+
+#endif /* __G_ALLOCA_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/garray.h b/protocols/Sametime/src/glib/include/glib/garray.h
new file mode 100644
index 0000000000..6bc51f797e
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/garray.h
@@ -0,0 +1,179 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_ARRAY_H__
+#define __G_ARRAY_H__
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GArray GArray;
+typedef struct _GByteArray GByteArray;
+typedef struct _GPtrArray GPtrArray;
+
+struct _GArray
+{
+ gchar *data;
+ guint len;
+};
+
+struct _GByteArray
+{
+ guint8 *data;
+ guint len;
+};
+
+struct _GPtrArray
+{
+ gpointer *pdata;
+ guint len;
+};
+
+/* Resizable arrays. remove fills any cleared spot and shortens the
+ * array, while preserving the order. remove_fast will distort the
+ * order by moving the last element to the position of the removed.
+ */
+
+#define g_array_append_val(a,v) g_array_append_vals (a, &(v), 1)
+#define g_array_prepend_val(a,v) g_array_prepend_vals (a, &(v), 1)
+#define g_array_insert_val(a,i,v) g_array_insert_vals (a, i, &(v), 1)
+#define g_array_index(a,t,i) (((t*) (void *) (a)->data) [(i)])
+
+GArray* g_array_new (gboolean zero_terminated,
+ gboolean clear_,
+ guint element_size);
+GArray* g_array_sized_new (gboolean zero_terminated,
+ gboolean clear_,
+ guint element_size,
+ guint reserved_size);
+gchar* g_array_free (GArray *array,
+ gboolean free_segment);
+GArray *g_array_ref (GArray *array);
+void g_array_unref (GArray *array);
+guint g_array_get_element_size (GArray *array);
+GArray* g_array_append_vals (GArray *array,
+ gconstpointer data,
+ guint len);
+GArray* g_array_prepend_vals (GArray *array,
+ gconstpointer data,
+ guint len);
+GArray* g_array_insert_vals (GArray *array,
+ guint index_,
+ gconstpointer data,
+ guint len);
+GArray* g_array_set_size (GArray *array,
+ guint length);
+GArray* g_array_remove_index (GArray *array,
+ guint index_);
+GArray* g_array_remove_index_fast (GArray *array,
+ guint index_);
+GArray* g_array_remove_range (GArray *array,
+ guint index_,
+ guint length);
+void g_array_sort (GArray *array,
+ GCompareFunc compare_func);
+void g_array_sort_with_data (GArray *array,
+ GCompareDataFunc compare_func,
+ gpointer user_data);
+
+/* Resizable pointer array. This interface is much less complicated
+ * than the above. Add appends a pointer. Remove fills any cleared
+ * spot and shortens the array. remove_fast will again distort order.
+ */
+#define g_ptr_array_index(array,index_) ((array)->pdata)[index_]
+GPtrArray* g_ptr_array_new (void);
+GPtrArray* g_ptr_array_new_with_free_func (GDestroyNotify element_free_func);
+GPtrArray* g_ptr_array_sized_new (guint reserved_size);
+gpointer* g_ptr_array_free (GPtrArray *array,
+ gboolean free_seg);
+GPtrArray* g_ptr_array_ref (GPtrArray *array);
+void g_ptr_array_unref (GPtrArray *array);
+void g_ptr_array_set_free_func (GPtrArray *array,
+ GDestroyNotify element_free_func);
+void g_ptr_array_set_size (GPtrArray *array,
+ gint length);
+gpointer g_ptr_array_remove_index (GPtrArray *array,
+ guint index_);
+gpointer g_ptr_array_remove_index_fast (GPtrArray *array,
+ guint index_);
+gboolean g_ptr_array_remove (GPtrArray *array,
+ gpointer data);
+gboolean g_ptr_array_remove_fast (GPtrArray *array,
+ gpointer data);
+void g_ptr_array_remove_range (GPtrArray *array,
+ guint index_,
+ guint length);
+void g_ptr_array_add (GPtrArray *array,
+ gpointer data);
+void g_ptr_array_sort (GPtrArray *array,
+ GCompareFunc compare_func);
+void g_ptr_array_sort_with_data (GPtrArray *array,
+ GCompareDataFunc compare_func,
+ gpointer user_data);
+void g_ptr_array_foreach (GPtrArray *array,
+ GFunc func,
+ gpointer user_data);
+
+
+/* Byte arrays, an array of guint8. Implemented as a GArray,
+ * but type-safe.
+ */
+
+GByteArray* g_byte_array_new (void);
+GByteArray* g_byte_array_sized_new (guint reserved_size);
+guint8* g_byte_array_free (GByteArray *array,
+ gboolean free_segment);
+GByteArray *g_byte_array_ref (GByteArray *array);
+void g_byte_array_unref (GByteArray *array);
+GByteArray* g_byte_array_append (GByteArray *array,
+ const guint8 *data,
+ guint len);
+GByteArray* g_byte_array_prepend (GByteArray *array,
+ const guint8 *data,
+ guint len);
+GByteArray* g_byte_array_set_size (GByteArray *array,
+ guint length);
+GByteArray* g_byte_array_remove_index (GByteArray *array,
+ guint index_);
+GByteArray* g_byte_array_remove_index_fast (GByteArray *array,
+ guint index_);
+GByteArray* g_byte_array_remove_range (GByteArray *array,
+ guint index_,
+ guint length);
+void g_byte_array_sort (GByteArray *array,
+ GCompareFunc compare_func);
+void g_byte_array_sort_with_data (GByteArray *array,
+ GCompareDataFunc compare_func,
+ gpointer user_data);
+
+G_END_DECLS
+
+#endif /* __G_ARRAY_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gasyncqueue.h b/protocols/Sametime/src/glib/include/glib/gasyncqueue.h
new file mode 100644
index 0000000000..9da43e36da
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gasyncqueue.h
@@ -0,0 +1,120 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_ASYNCQUEUE_H__
+#define __G_ASYNCQUEUE_H__
+
+#include <glib/gthread.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GAsyncQueue GAsyncQueue;
+
+/* Asyncronous Queues, can be used to communicate between threads */
+
+/* Get a new GAsyncQueue with the ref_count 1 */
+GAsyncQueue* g_async_queue_new (void);
+
+GAsyncQueue* g_async_queue_new_full (GDestroyNotify item_free_func);
+
+/* Lock and unlock a GAsyncQueue. All functions lock the queue for
+ * themselves, but in certain cirumstances you want to hold the lock longer,
+ * thus you lock the queue, call the *_unlocked functions and unlock it again.
+ */
+void g_async_queue_lock (GAsyncQueue *queue);
+void g_async_queue_unlock (GAsyncQueue *queue);
+
+/* Ref and unref the GAsyncQueue. */
+GAsyncQueue* g_async_queue_ref (GAsyncQueue *queue);
+void g_async_queue_unref (GAsyncQueue *queue);
+
+#ifndef G_DISABLE_DEPRECATED
+/* You don't have to hold the lock for calling *_ref and *_unref anymore. */
+void g_async_queue_ref_unlocked (GAsyncQueue *queue);
+void g_async_queue_unref_and_unlock (GAsyncQueue *queue);
+#endif /* !G_DISABLE_DEPRECATED */
+
+/* Push data into the async queue. Must not be NULL. */
+void g_async_queue_push (GAsyncQueue *queue,
+ gpointer data);
+void g_async_queue_push_unlocked (GAsyncQueue *queue,
+ gpointer data);
+
+void g_async_queue_push_sorted (GAsyncQueue *queue,
+ gpointer data,
+ GCompareDataFunc func,
+ gpointer user_data);
+void g_async_queue_push_sorted_unlocked (GAsyncQueue *queue,
+ gpointer data,
+ GCompareDataFunc func,
+ gpointer user_data);
+
+/* Pop data from the async queue. When no data is there, the thread is blocked
+ * until data arrives.
+ */
+gpointer g_async_queue_pop (GAsyncQueue *queue);
+gpointer g_async_queue_pop_unlocked (GAsyncQueue *queue);
+
+/* Try to pop data. NULL is returned in case of empty queue. */
+gpointer g_async_queue_try_pop (GAsyncQueue *queue);
+gpointer g_async_queue_try_pop_unlocked (GAsyncQueue *queue);
+
+
+
+/* Wait for data until at maximum until end_time is reached. NULL is returned
+ * in case of empty queue.
+ */
+gpointer g_async_queue_timed_pop (GAsyncQueue *queue,
+ GTimeVal *end_time);
+gpointer g_async_queue_timed_pop_unlocked (GAsyncQueue *queue,
+ GTimeVal *end_time);
+
+/* Return the length of the queue. Negative values mean that threads
+ * are waiting, positve values mean that there are entries in the
+ * queue. Actually this function returns the length of the queue minus
+ * the number of waiting threads, g_async_queue_length == 0 could also
+ * mean 'n' entries in the queue and 'n' thread waiting. Such can
+ * happen due to locking of the queue or due to scheduling.
+ */
+gint g_async_queue_length (GAsyncQueue *queue);
+gint g_async_queue_length_unlocked (GAsyncQueue *queue);
+void g_async_queue_sort (GAsyncQueue *queue,
+ GCompareDataFunc func,
+ gpointer user_data);
+void g_async_queue_sort_unlocked (GAsyncQueue *queue,
+ GCompareDataFunc func,
+ gpointer user_data);
+
+/* Private API */
+GMutex* _g_async_queue_get_mutex (GAsyncQueue *queue);
+
+G_END_DECLS
+
+#endif /* __G_ASYNCQUEUE_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gatomic.h b/protocols/Sametime/src/glib/include/glib/gatomic.h
new file mode 100644
index 0000000000..ddd39b8a3a
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gatomic.h
@@ -0,0 +1,105 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * g_atomic_*: atomic operations.
+ * Copyright (C) 2003 Sebastian Wilhelmi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_ATOMIC_H__
+#define __G_ATOMIC_H__
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+gint g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic,
+ gint val);
+void g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic,
+ gint val);
+gboolean g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic,
+ gint oldval,
+ gint newval);
+gboolean g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic,
+ gpointer oldval,
+ gpointer newval);
+
+gint g_atomic_int_get (volatile gint G_GNUC_MAY_ALIAS *atomic);
+void g_atomic_int_set (volatile gint G_GNUC_MAY_ALIAS *atomic,
+ gint newval);
+gpointer g_atomic_pointer_get (volatile gpointer G_GNUC_MAY_ALIAS *atomic);
+void g_atomic_pointer_set (volatile gpointer G_GNUC_MAY_ALIAS *atomic,
+ gpointer newval);
+
+#ifndef G_ATOMIC_OP_MEMORY_BARRIER_NEEDED
+# define g_atomic_int_get(atomic) ((gint)*(atomic))
+# define g_atomic_int_set(atomic, newval) ((void) (*(atomic) = (newval)))
+# define g_atomic_pointer_get(atomic) ((gpointer)*(atomic))
+# define g_atomic_pointer_set(atomic, newval) ((void) (*(atomic) = (newval)))
+#else
+# define g_atomic_int_get(atomic) \
+ ((void) sizeof (gchar [sizeof (*(atomic)) == sizeof (gint) ? 1 : -1]), \
+ (g_atomic_int_get) ((volatile gint G_GNUC_MAY_ALIAS *) (volatile void *) (atomic)))
+# define g_atomic_int_set(atomic, newval) \
+ ((void) sizeof (gchar [sizeof (*(atomic)) == sizeof (gint) ? 1 : -1]), \
+ (g_atomic_int_set) ((volatile gint G_GNUC_MAY_ALIAS *) (volatile void *) (atomic), (newval)))
+# define g_atomic_pointer_get(atomic) \
+ ((void) sizeof (gchar [sizeof (*(atomic)) == sizeof (gpointer) ? 1 : -1]), \
+ (g_atomic_pointer_get) ((volatile gpointer G_GNUC_MAY_ALIAS *) (volatile void *) (atomic)))
+# define g_atomic_pointer_set(atomic, newval) \
+ ((void) sizeof (gchar [sizeof (*(atomic)) == sizeof (gpointer) ? 1 : -1]), \
+ (g_atomic_pointer_set) ((volatile gpointer G_GNUC_MAY_ALIAS *) (volatile void *) (atomic), (newval)))
+#endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */
+
+/**
+ * g_atomic_int_inc:
+ * @atomic: a pointer to an integer.
+ *
+ * Atomically increments the integer pointed to by @atomic by 1.
+ *
+ * Since: 2.4
+ */
+#define g_atomic_int_inc(atomic) (g_atomic_int_add ((atomic), 1))
+
+/**
+ * g_atomic_int_dec_and_test:
+ * @atomic: a pointer to an integer
+ *
+ * Atomically decrements the integer pointed to by @atomic by 1.
+ *
+ * Returns: %TRUE if the integer pointed to by @atomic is 0
+ * after decrementing it
+ *
+ * Since: 2.4
+ */
+#define g_atomic_int_dec_and_test(atomic) \
+ (g_atomic_int_exchange_and_add ((atomic), -1) == 1)
+
+G_END_DECLS
+
+#endif /* __G_ATOMIC_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gbacktrace.h b/protocols/Sametime/src/glib/include/glib/gbacktrace.h
new file mode 100644
index 0000000000..43a0c46a21
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gbacktrace.h
@@ -0,0 +1,68 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_BACKTRACE_H__
+#define __G_BACKTRACE_H__
+
+#include <glib/gtypes.h>
+#include <signal.h>
+
+G_BEGIN_DECLS
+
+/* Fatal error handlers.
+ * g_on_error_query() will prompt the user to either
+ * [E]xit, [H]alt, [P]roceed or show [S]tack trace.
+ * g_on_error_stack_trace() invokes gdb, which attaches to the current
+ * process and shows a stack trace.
+ * These function may cause different actions on non-unix platforms.
+ * The prg_name arg is required by gdb to find the executable, if it is
+ * passed as NULL, g_on_error_query() will try g_get_prgname().
+ */
+void g_on_error_query (const gchar *prg_name);
+void g_on_error_stack_trace (const gchar *prg_name);
+
+/* Hacker macro to place breakpoints for selected machines.
+ * Actual use is strongly discouraged of course ;)
+ */
+#if (defined (__i386__) || defined (__x86_64__)) && defined (__GNUC__) && __GNUC__ >= 2
+# define G_BREAKPOINT() G_STMT_START{ __asm__ __volatile__ ("int $03"); }G_STMT_END
+#elif (defined (_MSC_VER) || defined (__DMC__)) && defined (_M_IX86)
+# define G_BREAKPOINT() G_STMT_START{ __asm int 3h }G_STMT_END
+#elif defined (_MSC_VER)
+# define G_BREAKPOINT() G_STMT_START{ __debugbreak(); }G_STMT_END
+#elif defined (__alpha__) && !defined(__osf__) && defined (__GNUC__) && __GNUC__ >= 2
+# define G_BREAKPOINT() G_STMT_START{ __asm__ __volatile__ ("bpt"); }G_STMT_END
+#else /* !__i386__ && !__alpha__ */
+# define G_BREAKPOINT() G_STMT_START{ raise (SIGTRAP); }G_STMT_END
+#endif /* __i386__ */
+
+G_END_DECLS
+
+#endif /* __G_BACKTRACE_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gbase64.h b/protocols/Sametime/src/glib/include/glib/gbase64.h
new file mode 100644
index 0000000000..930389a674
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gbase64.h
@@ -0,0 +1,57 @@
+/* gbase64.h - Base64 coding functions
+ *
+ * Copyright (C) 2005 Alexander Larsson <alexl@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_BASE64_H__
+#define __G_BASE64_H__
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+gsize g_base64_encode_step (const guchar *in,
+ gsize len,
+ gboolean break_lines,
+ gchar *out,
+ gint *state,
+ gint *save);
+gsize g_base64_encode_close (gboolean break_lines,
+ gchar *out,
+ gint *state,
+ gint *save);
+gchar* g_base64_encode (const guchar *data,
+ gsize len) G_GNUC_MALLOC;
+gsize g_base64_decode_step (const gchar *in,
+ gsize len,
+ guchar *out,
+ gint *state,
+ guint *save);
+guchar *g_base64_decode (const gchar *text,
+ gsize *out_len) G_GNUC_MALLOC;
+guchar *g_base64_decode_inplace (gchar *text,
+ gsize *out_len);
+
+
+G_END_DECLS
+
+#endif /* __G_BASE64_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gbitlock.h b/protocols/Sametime/src/glib/include/glib/gbitlock.h
new file mode 100644
index 0000000000..5f6a67fd84
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gbitlock.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright © 2008 Ryan Lortie
+ * Copyright © 2010 Codethink Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Ryan Lortie <desrt@desrt.ca>
+ */
+
+#ifndef __G_BITLOCK_H__
+#define __G_BITLOCK_H__
+
+#include <glib/gtypes.h>
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+G_BEGIN_DECLS
+
+void g_bit_lock (volatile gint *address,
+ gint lock_bit);
+gboolean g_bit_trylock (volatile gint *address,
+ gint lock_bit);
+void g_bit_unlock (volatile gint *address,
+ gint lock_bit);
+
+G_END_DECLS
+
+#endif /* __G_BITLOCK_H_ */
diff --git a/protocols/Sametime/src/glib/include/glib/gbookmarkfile.h b/protocols/Sametime/src/glib/include/glib/gbookmarkfile.h
new file mode 100644
index 0000000000..f663ebf27f
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gbookmarkfile.h
@@ -0,0 +1,215 @@
+/* gbookmarkfile.h: parsing and building desktop bookmarks
+ *
+ * Copyright (C) 2005-2006 Emmanuele Bassi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_BOOKMARK_FILE_H__
+#define __G_BOOKMARK_FILE_H__
+
+#include <glib/gerror.h>
+#include <time.h>
+
+G_BEGIN_DECLS
+
+/**
+ * G_BOOKMARK_FILE_ERROR:
+ *
+ * Error domain for bookmark file parsing.
+ * Errors in this domain will be from the #GBookmarkFileError
+ * enumeration. See #GError for information on error domains.
+ */
+#define G_BOOKMARK_FILE_ERROR (g_bookmark_file_error_quark ())
+
+
+/**
+ * GBookmarkFileError:
+ * @G_BOOKMARK_FILE_ERROR_INVALID_URI: URI was ill-formed
+ * @G_BOOKMARK_FILE_ERROR_INVALID_VALUE: a requested field was not found
+ * @G_BOOKMARK_FILE_ERROR_APP_NOT_REGISTERED: a requested application did
+ * not register a bookmark
+ * @G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND: a requested URI was not found
+ * @G_BOOKMARK_FILE_ERROR_READ: document was ill formed
+ * @G_BOOKMARK_FILE_ERROR_UNKNOWN_ENCODING: the text being parsed was
+ * in an unknown encoding
+ * @G_BOOKMARK_FILE_ERROR_WRITE: an error occurred while writing
+ * @G_BOOKMARK_FILE_ERROR_FILE_NOT_FOUND: requested file was not found
+ *
+ * Error codes returned by bookmark file parsing.
+ */
+typedef enum
+{
+ G_BOOKMARK_FILE_ERROR_INVALID_URI,
+ G_BOOKMARK_FILE_ERROR_INVALID_VALUE,
+ G_BOOKMARK_FILE_ERROR_APP_NOT_REGISTERED,
+ G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND,
+ G_BOOKMARK_FILE_ERROR_READ,
+ G_BOOKMARK_FILE_ERROR_UNKNOWN_ENCODING,
+ G_BOOKMARK_FILE_ERROR_WRITE,
+ G_BOOKMARK_FILE_ERROR_FILE_NOT_FOUND
+} GBookmarkFileError;
+
+GQuark g_bookmark_file_error_quark (void);
+
+/**
+ * GBookmarkFile:
+ *
+ * The <structname>GBookmarkFile</structname> struct contains only
+ * private data and should not be directly accessed.
+ */
+typedef struct _GBookmarkFile GBookmarkFile;
+
+GBookmarkFile *g_bookmark_file_new (void);
+void g_bookmark_file_free (GBookmarkFile *bookmark);
+
+gboolean g_bookmark_file_load_from_file (GBookmarkFile *bookmark,
+ const gchar *filename,
+ GError **error);
+gboolean g_bookmark_file_load_from_data (GBookmarkFile *bookmark,
+ const gchar *data,
+ gsize length,
+ GError **error);
+gboolean g_bookmark_file_load_from_data_dirs (GBookmarkFile *bookmark,
+ const gchar *file,
+ gchar **full_path,
+ GError **error);
+gchar * g_bookmark_file_to_data (GBookmarkFile *bookmark,
+ gsize *length,
+ GError **error) G_GNUC_MALLOC;
+gboolean g_bookmark_file_to_file (GBookmarkFile *bookmark,
+ const gchar *filename,
+ GError **error);
+
+void g_bookmark_file_set_title (GBookmarkFile *bookmark,
+ const gchar *uri,
+ const gchar *title);
+gchar * g_bookmark_file_get_title (GBookmarkFile *bookmark,
+ const gchar *uri,
+ GError **error) G_GNUC_MALLOC;
+void g_bookmark_file_set_description (GBookmarkFile *bookmark,
+ const gchar *uri,
+ const gchar *description);
+gchar * g_bookmark_file_get_description (GBookmarkFile *bookmark,
+ const gchar *uri,
+ GError **error) G_GNUC_MALLOC;
+void g_bookmark_file_set_mime_type (GBookmarkFile *bookmark,
+ const gchar *uri,
+ const gchar *mime_type);
+gchar * g_bookmark_file_get_mime_type (GBookmarkFile *bookmark,
+ const gchar *uri,
+ GError **error) G_GNUC_MALLOC;
+void g_bookmark_file_set_groups (GBookmarkFile *bookmark,
+ const gchar *uri,
+ const gchar **groups,
+ gsize length);
+void g_bookmark_file_add_group (GBookmarkFile *bookmark,
+ const gchar *uri,
+ const gchar *group);
+gboolean g_bookmark_file_has_group (GBookmarkFile *bookmark,
+ const gchar *uri,
+ const gchar *group,
+ GError **error);
+gchar ** g_bookmark_file_get_groups (GBookmarkFile *bookmark,
+ const gchar *uri,
+ gsize *length,
+ GError **error) G_GNUC_MALLOC;
+void g_bookmark_file_add_application (GBookmarkFile *bookmark,
+ const gchar *uri,
+ const gchar *name,
+ const gchar *exec);
+gboolean g_bookmark_file_has_application (GBookmarkFile *bookmark,
+ const gchar *uri,
+ const gchar *name,
+ GError **error);
+gchar ** g_bookmark_file_get_applications (GBookmarkFile *bookmark,
+ const gchar *uri,
+ gsize *length,
+ GError **error) G_GNUC_MALLOC;
+gboolean g_bookmark_file_set_app_info (GBookmarkFile *bookmark,
+ const gchar *uri,
+ const gchar *name,
+ const gchar *exec,
+ gint count,
+ time_t stamp,
+ GError **error);
+gboolean g_bookmark_file_get_app_info (GBookmarkFile *bookmark,
+ const gchar *uri,
+ const gchar *name,
+ gchar **exec,
+ guint *count,
+ time_t *stamp,
+ GError **error);
+void g_bookmark_file_set_is_private (GBookmarkFile *bookmark,
+ const gchar *uri,
+ gboolean is_private);
+gboolean g_bookmark_file_get_is_private (GBookmarkFile *bookmark,
+ const gchar *uri,
+ GError **error);
+void g_bookmark_file_set_icon (GBookmarkFile *bookmark,
+ const gchar *uri,
+ const gchar *href,
+ const gchar *mime_type);
+gboolean g_bookmark_file_get_icon (GBookmarkFile *bookmark,
+ const gchar *uri,
+ gchar **href,
+ gchar **mime_type,
+ GError **error);
+void g_bookmark_file_set_added (GBookmarkFile *bookmark,
+ const gchar *uri,
+ time_t added);
+time_t g_bookmark_file_get_added (GBookmarkFile *bookmark,
+ const gchar *uri,
+ GError **error);
+void g_bookmark_file_set_modified (GBookmarkFile *bookmark,
+ const gchar *uri,
+ time_t modified);
+time_t g_bookmark_file_get_modified (GBookmarkFile *bookmark,
+ const gchar *uri,
+ GError **error);
+void g_bookmark_file_set_visited (GBookmarkFile *bookmark,
+ const gchar *uri,
+ time_t visited);
+time_t g_bookmark_file_get_visited (GBookmarkFile *bookmark,
+ const gchar *uri,
+ GError **error);
+gboolean g_bookmark_file_has_item (GBookmarkFile *bookmark,
+ const gchar *uri);
+gint g_bookmark_file_get_size (GBookmarkFile *bookmark);
+gchar ** g_bookmark_file_get_uris (GBookmarkFile *bookmark,
+ gsize *length) G_GNUC_MALLOC;
+gboolean g_bookmark_file_remove_group (GBookmarkFile *bookmark,
+ const gchar *uri,
+ const gchar *group,
+ GError **error);
+gboolean g_bookmark_file_remove_application (GBookmarkFile *bookmark,
+ const gchar *uri,
+ const gchar *name,
+ GError **error);
+gboolean g_bookmark_file_remove_item (GBookmarkFile *bookmark,
+ const gchar *uri,
+ GError **error);
+gboolean g_bookmark_file_move_item (GBookmarkFile *bookmark,
+ const gchar *old_uri,
+ const gchar *new_uri,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __G_BOOKMARK_FILE_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gcache.h b/protocols/Sametime/src/glib/include/glib/gcache.h
new file mode 100644
index 0000000000..7d60d5888c
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gcache.h
@@ -0,0 +1,69 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_CACHE_H__
+#define __G_CACHE_H__
+
+#include <glib/glist.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GCache GCache;
+
+typedef gpointer (*GCacheNewFunc) (gpointer key);
+typedef gpointer (*GCacheDupFunc) (gpointer value);
+typedef void (*GCacheDestroyFunc) (gpointer value);
+
+/* Caches
+ */
+GCache* g_cache_new (GCacheNewFunc value_new_func,
+ GCacheDestroyFunc value_destroy_func,
+ GCacheDupFunc key_dup_func,
+ GCacheDestroyFunc key_destroy_func,
+ GHashFunc hash_key_func,
+ GHashFunc hash_value_func,
+ GEqualFunc key_equal_func);
+void g_cache_destroy (GCache *cache);
+gpointer g_cache_insert (GCache *cache,
+ gpointer key);
+void g_cache_remove (GCache *cache,
+ gconstpointer value);
+void g_cache_key_foreach (GCache *cache,
+ GHFunc func,
+ gpointer user_data);
+#ifndef G_DISABLE_DEPRECATED
+void g_cache_value_foreach (GCache *cache,
+ GHFunc func,
+ gpointer user_data);
+#endif
+
+G_END_DECLS
+
+#endif /* __G_CACHE_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gchecksum.h b/protocols/Sametime/src/glib/include/glib/gchecksum.h
new file mode 100644
index 0000000000..57aea103f7
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gchecksum.h
@@ -0,0 +1,86 @@
+/* gchecksum.h - data hashing functions
+ *
+ * Copyright (C) 2007 Emmanuele Bassi <ebassi@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_CHECKSUM_H__
+#define __G_CHECKSUM_H__
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GChecksumType:
+ * @G_CHECKSUM_MD5: Use the MD5 hashing algorithm
+ * @G_CHECKSUM_SHA1: Use the SHA-1 hashing algorithm
+ * @G_CHECKSUM_SHA256: Use the SHA-256 hashing algorithm
+ *
+ * The hashing algorithm to be used by #GChecksum when performing the
+ * digest of some data.
+ *
+ * Note that the #GChecksumType enumeration may be extended at a later
+ * date to include new hashing algorithm types.
+ *
+ * Since: 2.16
+ */
+typedef enum {
+ G_CHECKSUM_MD5,
+ G_CHECKSUM_SHA1,
+ G_CHECKSUM_SHA256
+} GChecksumType;
+
+/**
+ * GChecksum:
+ *
+ * An opaque structure representing a checksumming operation.
+ * To create a new GChecksum, use g_checksum_new(). To free
+ * a GChecksum, use g_checksum_free().
+ *
+ * Since: 2.16
+ */
+typedef struct _GChecksum GChecksum;
+
+gssize g_checksum_type_get_length (GChecksumType checksum_type);
+
+GChecksum * g_checksum_new (GChecksumType checksum_type);
+void g_checksum_reset (GChecksum *checksum);
+GChecksum * g_checksum_copy (const GChecksum *checksum);
+void g_checksum_free (GChecksum *checksum);
+void g_checksum_update (GChecksum *checksum,
+ const guchar *data,
+ gssize length);
+G_CONST_RETURN gchar *g_checksum_get_string (GChecksum *checksum);
+void g_checksum_get_digest (GChecksum *checksum,
+ guint8 *buffer,
+ gsize *digest_len);
+
+gchar *g_compute_checksum_for_data (GChecksumType checksum_type,
+ const guchar *data,
+ gsize length);
+gchar *g_compute_checksum_for_string (GChecksumType checksum_type,
+ const gchar *str,
+ gssize length);
+
+G_END_DECLS
+
+#endif /* __G_CHECKSUM_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gcompletion.h b/protocols/Sametime/src/glib/include/glib/gcompletion.h
new file mode 100644
index 0000000000..04c024fc5a
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gcompletion.h
@@ -0,0 +1,81 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_COMPLETION_H__
+#define __G_COMPLETION_H__
+
+#include <glib/glist.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GCompletion GCompletion;
+
+typedef gchar* (*GCompletionFunc) (gpointer);
+
+/* GCompletion
+ */
+
+typedef gint (*GCompletionStrncmpFunc) (const gchar *s1,
+ const gchar *s2,
+ gsize n);
+
+struct _GCompletion
+{
+ GList* items;
+ GCompletionFunc func;
+
+ gchar* prefix;
+ GList* cache;
+ GCompletionStrncmpFunc strncmp_func;
+};
+
+#ifndef G_DISABLE_DEPRECATED
+
+GCompletion* g_completion_new (GCompletionFunc func);
+void g_completion_add_items (GCompletion* cmp,
+ GList* items);
+void g_completion_remove_items (GCompletion* cmp,
+ GList* items);
+void g_completion_clear_items (GCompletion* cmp);
+GList* g_completion_complete (GCompletion* cmp,
+ const gchar* prefix,
+ gchar** new_prefix);
+GList* g_completion_complete_utf8 (GCompletion *cmp,
+ const gchar* prefix,
+ gchar** new_prefix);
+void g_completion_set_compare (GCompletion *cmp,
+ GCompletionStrncmpFunc strncmp_func);
+void g_completion_free (GCompletion* cmp);
+
+#endif
+
+G_END_DECLS
+
+#endif /* __G_COMPLETION_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gconvert.h b/protocols/Sametime/src/glib/include/glib/gconvert.h
new file mode 100644
index 0000000000..e4c20d77d5
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gconvert.h
@@ -0,0 +1,162 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_CONVERT_H__
+#define __G_CONVERT_H__
+
+#include <glib/gerror.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GConvertError:
+ * @G_CONVERT_ERROR_NO_CONVERSION: Conversion between the requested character
+ * sets is not supported.
+ * @G_CONVERT_ERROR_ILLEGAL_SEQUENCE: Invalid byte sequence in conversion input.
+ * @G_CONVERT_ERROR_FAILED: Conversion failed for some reason.
+ * @G_CONVERT_ERROR_PARTIAL_INPUT: Partial character sequence at end of input.
+ * @G_CONVERT_ERROR_BAD_URI: URI is invalid.
+ * @G_CONVERT_ERROR_NOT_ABSOLUTE_PATH: Pathname is not an absolute path.
+ *
+ * Error codes returned by character set conversion routines.
+ */
+typedef enum
+{
+ G_CONVERT_ERROR_NO_CONVERSION,
+ G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
+ G_CONVERT_ERROR_FAILED,
+ G_CONVERT_ERROR_PARTIAL_INPUT,
+ G_CONVERT_ERROR_BAD_URI,
+ G_CONVERT_ERROR_NOT_ABSOLUTE_PATH
+} GConvertError;
+
+/**
+ * G_CONVERT_ERROR:
+ *
+ * Error domain for character set conversions. Errors in this domain will
+ * be from the #GConvertError enumeration. See #GError for information on
+ * error domains.
+ */
+#define G_CONVERT_ERROR g_convert_error_quark()
+GQuark g_convert_error_quark (void);
+
+/**
+ * GIconv:
+ *
+ * The <structname>GIConv</structname> struct wraps an
+ * iconv() conversion descriptor. It contains private data
+ * and should only be accessed using the following functions.
+ */
+typedef struct _GIConv *GIConv;
+
+GIConv g_iconv_open (const gchar *to_codeset,
+ const gchar *from_codeset);
+gsize g_iconv (GIConv converter,
+ gchar **inbuf,
+ gsize *inbytes_left,
+ gchar **outbuf,
+ gsize *outbytes_left);
+gint g_iconv_close (GIConv converter);
+
+
+gchar* g_convert (const gchar *str,
+ gssize len,
+ const gchar *to_codeset,
+ const gchar *from_codeset,
+ gsize *bytes_read,
+ gsize *bytes_written,
+ GError **error) G_GNUC_MALLOC;
+gchar* g_convert_with_iconv (const gchar *str,
+ gssize len,
+ GIConv converter,
+ gsize *bytes_read,
+ gsize *bytes_written,
+ GError **error) G_GNUC_MALLOC;
+gchar* g_convert_with_fallback (const gchar *str,
+ gssize len,
+ const gchar *to_codeset,
+ const gchar *from_codeset,
+ const gchar *fallback,
+ gsize *bytes_read,
+ gsize *bytes_written,
+ GError **error) G_GNUC_MALLOC;
+
+
+/* Convert between libc's idea of strings and UTF-8.
+ */
+gchar* g_locale_to_utf8 (const gchar *opsysstring,
+ gssize len,
+ gsize *bytes_read,
+ gsize *bytes_written,
+ GError **error) G_GNUC_MALLOC;
+gchar* g_locale_from_utf8 (const gchar *utf8string,
+ gssize len,
+ gsize *bytes_read,
+ gsize *bytes_written,
+ GError **error) G_GNUC_MALLOC;
+
+/* Convert between the operating system (or C runtime)
+ * representation of file names and UTF-8.
+ */
+#ifdef G_OS_WIN32
+#define g_filename_to_utf8 g_filename_to_utf8_utf8
+#define g_filename_from_utf8 g_filename_from_utf8_utf8
+#define g_filename_from_uri g_filename_from_uri_utf8
+#define g_filename_to_uri g_filename_to_uri_utf8
+#endif
+
+gchar* g_filename_to_utf8 (const gchar *opsysstring,
+ gssize len,
+ gsize *bytes_read,
+ gsize *bytes_written,
+ GError **error) G_GNUC_MALLOC;
+gchar* g_filename_from_utf8 (const gchar *utf8string,
+ gssize len,
+ gsize *bytes_read,
+ gsize *bytes_written,
+ GError **error) G_GNUC_MALLOC;
+
+gchar *g_filename_from_uri (const gchar *uri,
+ gchar **hostname,
+ GError **error) G_GNUC_MALLOC;
+
+gchar *g_filename_to_uri (const gchar *filename,
+ const gchar *hostname,
+ GError **error) G_GNUC_MALLOC;
+gchar *g_filename_display_name (const gchar *filename) G_GNUC_MALLOC;
+gboolean g_get_filename_charsets (G_CONST_RETURN gchar ***charsets);
+
+gchar *g_filename_display_basename (const gchar *filename) G_GNUC_MALLOC;
+
+gchar **g_uri_list_extract_uris (const gchar *uri_list) G_GNUC_MALLOC;
+
+G_END_DECLS
+
+#endif /* __G_CONVERT_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gdataset.h b/protocols/Sametime/src/glib/include/glib/gdataset.h
new file mode 100644
index 0000000000..2733ffb033
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gdataset.h
@@ -0,0 +1,122 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_DATASET_H__
+#define __G_DATASET_H__
+
+#include <glib/gquark.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GData GData;
+
+typedef void (*GDataForeachFunc) (GQuark key_id,
+ gpointer data,
+ gpointer user_data);
+
+/* Keyed Data List
+ */
+void g_datalist_init (GData **datalist);
+void g_datalist_clear (GData **datalist);
+gpointer g_datalist_id_get_data (GData **datalist,
+ GQuark key_id);
+void g_datalist_id_set_data_full (GData **datalist,
+ GQuark key_id,
+ gpointer data,
+ GDestroyNotify destroy_func);
+gpointer g_datalist_id_remove_no_notify (GData **datalist,
+ GQuark key_id);
+void g_datalist_foreach (GData **datalist,
+ GDataForeachFunc func,
+ gpointer user_data);
+
+/**
+ * G_DATALIST_FLAGS_MASK:
+ *
+ * A bitmask that restricts the possible flags passed to
+ * g_datalist_set_flags(). Passing a flags value where
+ * flags & ~G_DATALIST_FLAGS_MASK != 0 is an error.
+ */
+#define G_DATALIST_FLAGS_MASK 0x3
+
+void g_datalist_set_flags (GData **datalist,
+ guint flags);
+void g_datalist_unset_flags (GData **datalist,
+ guint flags);
+guint g_datalist_get_flags (GData **datalist);
+
+#define g_datalist_id_set_data(dl, q, d) \
+ g_datalist_id_set_data_full ((dl), (q), (d), NULL)
+#define g_datalist_id_remove_data(dl, q) \
+ g_datalist_id_set_data ((dl), (q), NULL)
+#define g_datalist_get_data(dl, k) \
+ (g_datalist_id_get_data ((dl), g_quark_try_string (k)))
+#define g_datalist_set_data_full(dl, k, d, f) \
+ g_datalist_id_set_data_full ((dl), g_quark_from_string (k), (d), (f))
+#define g_datalist_remove_no_notify(dl, k) \
+ g_datalist_id_remove_no_notify ((dl), g_quark_try_string (k))
+#define g_datalist_set_data(dl, k, d) \
+ g_datalist_set_data_full ((dl), (k), (d), NULL)
+#define g_datalist_remove_data(dl, k) \
+ g_datalist_id_set_data ((dl), g_quark_try_string (k), NULL)
+
+
+/* Location Associated Keyed Data
+ */
+void g_dataset_destroy (gconstpointer dataset_location);
+gpointer g_dataset_id_get_data (gconstpointer dataset_location,
+ GQuark key_id);
+void g_dataset_id_set_data_full (gconstpointer dataset_location,
+ GQuark key_id,
+ gpointer data,
+ GDestroyNotify destroy_func);
+gpointer g_dataset_id_remove_no_notify (gconstpointer dataset_location,
+ GQuark key_id);
+void g_dataset_foreach (gconstpointer dataset_location,
+ GDataForeachFunc func,
+ gpointer user_data);
+#define g_dataset_id_set_data(l, k, d) \
+ g_dataset_id_set_data_full ((l), (k), (d), NULL)
+#define g_dataset_id_remove_data(l, k) \
+ g_dataset_id_set_data ((l), (k), NULL)
+#define g_dataset_get_data(l, k) \
+ (g_dataset_id_get_data ((l), g_quark_try_string (k)))
+#define g_dataset_set_data_full(l, k, d, f) \
+ g_dataset_id_set_data_full ((l), g_quark_from_string (k), (d), (f))
+#define g_dataset_remove_no_notify(l, k) \
+ g_dataset_id_remove_no_notify ((l), g_quark_try_string (k))
+#define g_dataset_set_data(l, k, d) \
+ g_dataset_set_data_full ((l), (k), (d), NULL)
+#define g_dataset_remove_data(l, k) \
+ g_dataset_id_set_data ((l), g_quark_try_string (k), NULL)
+
+G_END_DECLS
+
+#endif /* __G_DATASET_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gdate.h b/protocols/Sametime/src/glib/include/glib/gdate.h
new file mode 100644
index 0000000000..cb1f566155
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gdate.h
@@ -0,0 +1,263 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_DATE_H__
+#define __G_DATE_H__
+
+#include <time.h>
+
+#include <glib/gtypes.h>
+#include <glib/gquark.h>
+
+G_BEGIN_DECLS
+
+/* GDate
+ *
+ * Date calculations (not time for now, to be resolved). These are a
+ * mutant combination of Steffen Beyer's DateCalc routines
+ * (http://www.perl.com/CPAN/authors/id/STBEY/) and Jon Trowbridge's
+ * date routines (written for in-house software). Written by Havoc
+ * Pennington <hp@pobox.com>
+ */
+
+typedef gint32 GTime;
+typedef guint16 GDateYear;
+typedef guint8 GDateDay; /* day of the month */
+typedef struct _GDate GDate;
+
+/* enum used to specify order of appearance in parsed date strings */
+typedef enum
+{
+ G_DATE_DAY = 0,
+ G_DATE_MONTH = 1,
+ G_DATE_YEAR = 2
+} GDateDMY;
+
+/* actual week and month values */
+typedef enum
+{
+ G_DATE_BAD_WEEKDAY = 0,
+ G_DATE_MONDAY = 1,
+ G_DATE_TUESDAY = 2,
+ G_DATE_WEDNESDAY = 3,
+ G_DATE_THURSDAY = 4,
+ G_DATE_FRIDAY = 5,
+ G_DATE_SATURDAY = 6,
+ G_DATE_SUNDAY = 7
+} GDateWeekday;
+typedef enum
+{
+ G_DATE_BAD_MONTH = 0,
+ G_DATE_JANUARY = 1,
+ G_DATE_FEBRUARY = 2,
+ G_DATE_MARCH = 3,
+ G_DATE_APRIL = 4,
+ G_DATE_MAY = 5,
+ G_DATE_JUNE = 6,
+ G_DATE_JULY = 7,
+ G_DATE_AUGUST = 8,
+ G_DATE_SEPTEMBER = 9,
+ G_DATE_OCTOBER = 10,
+ G_DATE_NOVEMBER = 11,
+ G_DATE_DECEMBER = 12
+} GDateMonth;
+
+#define G_DATE_BAD_JULIAN 0U
+#define G_DATE_BAD_DAY 0U
+#define G_DATE_BAD_YEAR 0U
+
+/* Note: directly manipulating structs is generally a bad idea, but
+ * in this case it's an *incredibly* bad idea, because all or part
+ * of this struct can be invalid at any given time. Use the functions,
+ * or you will get hosed, I promise.
+ */
+struct _GDate
+{
+ guint julian_days : 32; /* julian days representation - we use a
+ * bitfield hoping that 64 bit platforms
+ * will pack this whole struct in one big
+ * int
+ */
+
+ guint julian : 1; /* julian is valid */
+ guint dmy : 1; /* dmy is valid */
+
+ /* DMY representation */
+ guint day : 6;
+ guint month : 4;
+ guint year : 16;
+};
+
+/* g_date_new() returns an invalid date, you then have to _set() stuff
+ * to get a usable object. You can also allocate a GDate statically,
+ * then call g_date_clear() to initialize.
+ */
+GDate* g_date_new (void);
+GDate* g_date_new_dmy (GDateDay day,
+ GDateMonth month,
+ GDateYear year);
+GDate* g_date_new_julian (guint32 julian_day);
+void g_date_free (GDate *date);
+
+/* check g_date_valid() after doing an operation that might fail, like
+ * _parse. Almost all g_date operations are undefined on invalid
+ * dates (the exceptions are the mutators, since you need those to
+ * return to validity).
+ */
+gboolean g_date_valid (const GDate *date);
+gboolean g_date_valid_day (GDateDay day) G_GNUC_CONST;
+gboolean g_date_valid_month (GDateMonth month) G_GNUC_CONST;
+gboolean g_date_valid_year (GDateYear year) G_GNUC_CONST;
+gboolean g_date_valid_weekday (GDateWeekday weekday) G_GNUC_CONST;
+gboolean g_date_valid_julian (guint32 julian_date) G_GNUC_CONST;
+gboolean g_date_valid_dmy (GDateDay day,
+ GDateMonth month,
+ GDateYear year) G_GNUC_CONST;
+
+GDateWeekday g_date_get_weekday (const GDate *date);
+GDateMonth g_date_get_month (const GDate *date);
+GDateYear g_date_get_year (const GDate *date);
+GDateDay g_date_get_day (const GDate *date);
+guint32 g_date_get_julian (const GDate *date);
+guint g_date_get_day_of_year (const GDate *date);
+/* First monday/sunday is the start of week 1; if we haven't reached
+ * that day, return 0. These are not ISO weeks of the year; that
+ * routine needs to be added.
+ * these functions return the number of weeks, starting on the
+ * corrsponding day
+ */
+guint g_date_get_monday_week_of_year (const GDate *date);
+guint g_date_get_sunday_week_of_year (const GDate *date);
+guint g_date_get_iso8601_week_of_year (const GDate *date);
+
+/* If you create a static date struct you need to clear it to get it
+ * in a sane state before use. You can clear a whole array at
+ * once with the ndates argument.
+ */
+void g_date_clear (GDate *date,
+ guint n_dates);
+
+/* The parse routine is meant for dates typed in by a user, so it
+ * permits many formats but tries to catch common typos. If your data
+ * needs to be strictly validated, it is not an appropriate function.
+ */
+void g_date_set_parse (GDate *date,
+ const gchar *str);
+void g_date_set_time_t (GDate *date,
+ time_t timet);
+void g_date_set_time_val (GDate *date,
+ GTimeVal *timeval);
+#ifndef G_DISABLE_DEPRECATED
+void g_date_set_time (GDate *date,
+ GTime time_);
+#endif
+void g_date_set_month (GDate *date,
+ GDateMonth month);
+void g_date_set_day (GDate *date,
+ GDateDay day);
+void g_date_set_year (GDate *date,
+ GDateYear year);
+void g_date_set_dmy (GDate *date,
+ GDateDay day,
+ GDateMonth month,
+ GDateYear y);
+void g_date_set_julian (GDate *date,
+ guint32 julian_date);
+gboolean g_date_is_first_of_month (const GDate *date);
+gboolean g_date_is_last_of_month (const GDate *date);
+
+/* To go forward by some number of weeks just go forward weeks*7 days */
+void g_date_add_days (GDate *date,
+ guint n_days);
+void g_date_subtract_days (GDate *date,
+ guint n_days);
+
+/* If you add/sub months while day > 28, the day might change */
+void g_date_add_months (GDate *date,
+ guint n_months);
+void g_date_subtract_months (GDate *date,
+ guint n_months);
+
+/* If it's feb 29, changing years can move you to the 28th */
+void g_date_add_years (GDate *date,
+ guint n_years);
+void g_date_subtract_years (GDate *date,
+ guint n_years);
+gboolean g_date_is_leap_year (GDateYear year) G_GNUC_CONST;
+guint8 g_date_get_days_in_month (GDateMonth month,
+ GDateYear year) G_GNUC_CONST;
+guint8 g_date_get_monday_weeks_in_year (GDateYear year) G_GNUC_CONST;
+guint8 g_date_get_sunday_weeks_in_year (GDateYear year) G_GNUC_CONST;
+
+/* Returns the number of days between the two dates. If date2 comes
+ before date1, a negative value is return. */
+gint g_date_days_between (const GDate *date1,
+ const GDate *date2);
+
+/* qsort-friendly (with a cast...) */
+gint g_date_compare (const GDate *lhs,
+ const GDate *rhs);
+void g_date_to_struct_tm (const GDate *date,
+ struct tm *tm);
+
+void g_date_clamp (GDate *date,
+ const GDate *min_date,
+ const GDate *max_date);
+
+/* Swap date1 and date2's values if date1 > date2. */
+void g_date_order (GDate *date1, GDate *date2);
+
+/* Just like strftime() except you can only use date-related formats.
+ * Using a time format is undefined.
+ */
+gsize g_date_strftime (gchar *s,
+ gsize slen,
+ const gchar *format,
+ const GDate *date);
+
+#ifndef G_DISABLE_DEPRECATED
+
+#define g_date_weekday g_date_get_weekday
+#define g_date_month g_date_get_month
+#define g_date_year g_date_get_year
+#define g_date_day g_date_get_day
+#define g_date_julian g_date_get_julian
+#define g_date_day_of_year g_date_get_day_of_year
+#define g_date_monday_week_of_year g_date_get_monday_week_of_year
+#define g_date_sunday_week_of_year g_date_get_sunday_week_of_year
+#define g_date_days_in_month g_date_get_days_in_month
+#define g_date_monday_weeks_in_year g_date_get_monday_weeks_in_year
+#define g_date_sunday_weeks_in_year g_date_get_sunday_weeks_in_year
+
+#endif /* G_DISABLE_DEPRECATED */
+
+G_END_DECLS
+
+#endif /* __G_DATE_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gdatetime.h b/protocols/Sametime/src/glib/include/glib/gdatetime.h
new file mode 100644
index 0000000000..b76df89c7e
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gdatetime.h
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2009-2010 Christian Hergert <chris@dronelabs.com>
+ * Copyright © 2010 Codethink Limited
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * licence, or (at your option) any later version.
+ *
+ * This is distributed in the hope that 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA.
+ *
+ * Authors: Christian Hergert <chris@dronelabs.com>
+ * Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+ * Emmanuele Bassi <ebassi@linux.intel.com>
+ * Ryan Lortie <desrt@desrt.ca>
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_DATE_TIME_H__
+#define __G_DATE_TIME_H__
+
+#include <glib/gtimezone.h>
+
+G_BEGIN_DECLS
+
+/**
+ * G_TIME_SPAN_DAY:
+ *
+ * Evaluates to a time span of one day.
+ *
+ * Since: 2.26
+ */
+#define G_TIME_SPAN_DAY (G_GINT64_CONSTANT (86400000000))
+
+/**
+ * G_TIME_SPAN_HOUR:
+ *
+ * Evaluates to a time span of one hour.
+ *
+ * Since: 2.26
+ */
+#define G_TIME_SPAN_HOUR (G_GINT64_CONSTANT (3600000000))
+
+/**
+ * G_TIME_SPAN_MINUTE:
+ *
+ * Evaluates to a time span of one minute.
+ *
+ * Since: 2.26
+ */
+#define G_TIME_SPAN_MINUTE (G_GINT64_CONSTANT (60000000))
+
+/**
+ * G_TIME_SPAN_SECOND:
+ *
+ * Evaluates to a time span of one second.
+ *
+ * Since: 2.26
+ */
+#define G_TIME_SPAN_SECOND (G_GINT64_CONSTANT (1000000))
+
+/**
+ * G_TIME_SPAN_MILLISECOND:
+ *
+ * Evaluates to a time span of one millisecond.
+ *
+ * Since: 2.26
+ */
+#define G_TIME_SPAN_MILLISECOND (G_GINT64_CONSTANT (1000))
+
+/**
+ * GTimeSpan:
+ *
+ * A value representing an interval of time, in microseconds.
+ *
+ * Since: 2.26
+ */
+typedef gint64 GTimeSpan;
+
+/**
+ * GDateTime:
+ *
+ * <structname>GDateTime</structname> is an opaque structure whose members
+ * cannot be accessed directly.
+ *
+ * Since: 2.26
+ */
+typedef struct _GDateTime GDateTime;
+
+void g_date_time_unref (GDateTime *datetime);
+GDateTime * g_date_time_ref (GDateTime *datetime);
+
+GDateTime * g_date_time_new_now (GTimeZone *tz);
+GDateTime * g_date_time_new_now_local (void);
+GDateTime * g_date_time_new_now_utc (void);
+
+GDateTime * g_date_time_new_from_unix_local (gint64 t);
+GDateTime * g_date_time_new_from_unix_utc (gint64 t);
+
+GDateTime * g_date_time_new_from_timeval_local (const GTimeVal *tv);
+GDateTime * g_date_time_new_from_timeval_utc (const GTimeVal *tv);
+
+GDateTime * g_date_time_new (GTimeZone *tz,
+ gint year,
+ gint month,
+ gint day,
+ gint hour,
+ gint minute,
+ gdouble seconds);
+GDateTime * g_date_time_new_local (gint year,
+ gint month,
+ gint day,
+ gint hour,
+ gint minute,
+ gdouble seconds);
+GDateTime * g_date_time_new_utc (gint year,
+ gint month,
+ gint day,
+ gint hour,
+ gint minute,
+ gdouble seconds);
+
+G_GNUC_WARN_UNUSED_RESULT
+GDateTime * g_date_time_add (GDateTime *datetime,
+ GTimeSpan timespan);
+
+G_GNUC_WARN_UNUSED_RESULT
+GDateTime * g_date_time_add_years (GDateTime *datetime,
+ gint years);
+G_GNUC_WARN_UNUSED_RESULT
+GDateTime * g_date_time_add_months (GDateTime *datetime,
+ gint months);
+G_GNUC_WARN_UNUSED_RESULT
+GDateTime * g_date_time_add_weeks (GDateTime *datetime,
+ gint weeks);
+G_GNUC_WARN_UNUSED_RESULT
+GDateTime * g_date_time_add_days (GDateTime *datetime,
+ gint days);
+
+G_GNUC_WARN_UNUSED_RESULT
+GDateTime * g_date_time_add_hours (GDateTime *datetime,
+ gint hours);
+G_GNUC_WARN_UNUSED_RESULT
+GDateTime * g_date_time_add_minutes (GDateTime *datetime,
+ gint minutes);
+G_GNUC_WARN_UNUSED_RESULT
+GDateTime * g_date_time_add_seconds (GDateTime *datetime,
+ gdouble seconds);
+
+G_GNUC_WARN_UNUSED_RESULT
+GDateTime * g_date_time_add_full (GDateTime *datetime,
+ gint years,
+ gint months,
+ gint days,
+ gint hours,
+ gint minutes,
+ gdouble seconds);
+
+gint g_date_time_compare (gconstpointer dt1,
+ gconstpointer dt2);
+GTimeSpan g_date_time_difference (GDateTime *end,
+ GDateTime *begin);
+guint g_date_time_hash (gconstpointer datetime);
+gboolean g_date_time_equal (gconstpointer dt1,
+ gconstpointer dt2);
+
+void g_date_time_get_ymd (GDateTime *datetime,
+ gint *year,
+ gint *month,
+ gint *day);
+
+gint g_date_time_get_year (GDateTime *datetime);
+gint g_date_time_get_month (GDateTime *datetime);
+gint g_date_time_get_day_of_month (GDateTime *datetime);
+
+gint g_date_time_get_week_numbering_year (GDateTime *datetime);
+gint g_date_time_get_week_of_year (GDateTime *datetime);
+gint g_date_time_get_day_of_week (GDateTime *datetime);
+
+gint g_date_time_get_day_of_year (GDateTime *datetime);
+
+gint g_date_time_get_hour (GDateTime *datetime);
+gint g_date_time_get_minute (GDateTime *datetime);
+gint g_date_time_get_second (GDateTime *datetime);
+gint g_date_time_get_microsecond (GDateTime *datetime);
+gdouble g_date_time_get_seconds (GDateTime *datetime);
+
+gint64 g_date_time_to_unix (GDateTime *datetime);
+gboolean g_date_time_to_timeval (GDateTime *datetime,
+ GTimeVal *tv);
+
+GTimeSpan g_date_time_get_utc_offset (GDateTime *datetime);
+const gchar * g_date_time_get_timezone_abbreviation (GDateTime *datetime);
+gboolean g_date_time_is_daylight_savings (GDateTime *datetime);
+
+GDateTime * g_date_time_to_timezone (GDateTime *datetime,
+ GTimeZone *tz);
+GDateTime * g_date_time_to_local (GDateTime *datetime);
+GDateTime * g_date_time_to_utc (GDateTime *datetime);
+
+gchar * g_date_time_format (GDateTime *datetime,
+ const gchar *format) G_GNUC_MALLOC;
+
+G_END_DECLS
+
+#endif /* __G_DATE_TIME_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gdir.h b/protocols/Sametime/src/glib/include/glib/gdir.h
new file mode 100644
index 0000000000..85e989695a
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gdir.h
@@ -0,0 +1,52 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * gdir.c: Simplified wrapper around the DIRENT functions.
+ *
+ * Copyright 2001 Hans Breuer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_DIR_H__
+#define __G_DIR_H__
+
+#include <glib/gerror.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GDir GDir;
+
+#ifdef G_OS_WIN32
+/* For DLL ABI stability, keep old names for old (non-UTF-8) functionality. */
+#define g_dir_open g_dir_open_utf8
+#define g_dir_read_name g_dir_read_name_utf8
+#endif
+
+GDir * g_dir_open (const gchar *path,
+ guint flags,
+ GError **error);
+G_CONST_RETURN gchar *g_dir_read_name (GDir *dir);
+void g_dir_rewind (GDir *dir);
+void g_dir_close (GDir *dir);
+
+G_END_DECLS
+
+#endif /* __G_DIR_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gerror.h b/protocols/Sametime/src/glib/include/glib/gerror.h
new file mode 100644
index 0000000000..b303487782
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gerror.h
@@ -0,0 +1,98 @@
+/* gerror.h - Error reporting system
+ *
+ * Copyright 2000 Red Hat, Inc.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome 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 Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_ERROR_H__
+#define __G_ERROR_H__
+
+#include <stdarg.h>
+
+#include <glib/gquark.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GError GError;
+
+struct _GError
+{
+ GQuark domain;
+ gint code;
+ gchar *message;
+};
+
+GError* g_error_new (GQuark domain,
+ gint code,
+ const gchar *format,
+ ...) G_GNUC_PRINTF (3, 4);
+
+GError* g_error_new_literal (GQuark domain,
+ gint code,
+ const gchar *message);
+GError* g_error_new_valist (GQuark domain,
+ gint code,
+ const gchar *format,
+ va_list args);
+
+void g_error_free (GError *error);
+GError* g_error_copy (const GError *error);
+
+gboolean g_error_matches (const GError *error,
+ GQuark domain,
+ gint code);
+
+/* if (err) *err = g_error_new(domain, code, format, ...), also has
+ * some sanity checks.
+ */
+void g_set_error (GError **err,
+ GQuark domain,
+ gint code,
+ const gchar *format,
+ ...) G_GNUC_PRINTF (4, 5);
+
+void g_set_error_literal (GError **err,
+ GQuark domain,
+ gint code,
+ const gchar *message);
+
+/* if (dest) *dest = src; also has some sanity checks.
+ */
+void g_propagate_error (GError **dest,
+ GError *src);
+
+/* if (err && *err) { g_error_free(*err); *err = NULL; } */
+void g_clear_error (GError **err);
+
+/* if (err) prefix the formatted string to the ->message */
+void g_prefix_error (GError **err,
+ const gchar *format,
+ ...) G_GNUC_PRINTF (2, 3);
+
+/* g_propagate_error then g_error_prefix on dest */
+void g_propagate_prefixed_error (GError **dest,
+ GError *src,
+ const gchar *format,
+ ...) G_GNUC_PRINTF (3, 4);
+
+G_END_DECLS
+
+#endif /* __G_ERROR_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gfileutils.h b/protocols/Sametime/src/glib/include/glib/gfileutils.h
new file mode 100644
index 0000000000..d8f9d3bea1
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gfileutils.h
@@ -0,0 +1,128 @@
+/* gfileutils.h - File utility functions
+ *
+ * Copyright 2000 Red Hat, Inc.
+ *
+ * GLib is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * GLib is distributed in the hope that 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 GLib; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_FILEUTILS_H__
+#define __G_FILEUTILS_H__
+
+#include <glib/gerror.h>
+
+G_BEGIN_DECLS
+
+#define G_FILE_ERROR g_file_error_quark ()
+
+typedef enum
+{
+ G_FILE_ERROR_EXIST,
+ G_FILE_ERROR_ISDIR,
+ G_FILE_ERROR_ACCES,
+ G_FILE_ERROR_NAMETOOLONG,
+ G_FILE_ERROR_NOENT,
+ G_FILE_ERROR_NOTDIR,
+ G_FILE_ERROR_NXIO,
+ G_FILE_ERROR_NODEV,
+ G_FILE_ERROR_ROFS,
+ G_FILE_ERROR_TXTBSY,
+ G_FILE_ERROR_FAULT,
+ G_FILE_ERROR_LOOP,
+ G_FILE_ERROR_NOSPC,
+ G_FILE_ERROR_NOMEM,
+ G_FILE_ERROR_MFILE,
+ G_FILE_ERROR_NFILE,
+ G_FILE_ERROR_BADF,
+ G_FILE_ERROR_INVAL,
+ G_FILE_ERROR_PIPE,
+ G_FILE_ERROR_AGAIN,
+ G_FILE_ERROR_INTR,
+ G_FILE_ERROR_IO,
+ G_FILE_ERROR_PERM,
+ G_FILE_ERROR_NOSYS,
+ G_FILE_ERROR_FAILED
+} GFileError;
+
+/* For backward-compat reasons, these are synced to an old
+ * anonymous enum in libgnome. But don't use that enum
+ * in new code.
+ */
+typedef enum
+{
+ G_FILE_TEST_IS_REGULAR = 1 << 0,
+ G_FILE_TEST_IS_SYMLINK = 1 << 1,
+ G_FILE_TEST_IS_DIR = 1 << 2,
+ G_FILE_TEST_IS_EXECUTABLE = 1 << 3,
+ G_FILE_TEST_EXISTS = 1 << 4
+} GFileTest;
+
+GQuark g_file_error_quark (void);
+/* So other code can generate a GFileError */
+GFileError g_file_error_from_errno (gint err_no);
+
+#ifdef G_OS_WIN32
+#define g_file_test g_file_test_utf8
+#define g_file_get_contents g_file_get_contents_utf8
+#define g_mkstemp g_mkstemp_utf8
+#define g_file_open_tmp g_file_open_tmp_utf8
+#endif
+
+gboolean g_file_test (const gchar *filename,
+ GFileTest test);
+gboolean g_file_get_contents (const gchar *filename,
+ gchar **contents,
+ gsize *length,
+ GError **error);
+gboolean g_file_set_contents (const gchar *filename,
+ const gchar *contents,
+ gssize length,
+ GError **error);
+gchar *g_file_read_link (const gchar *filename,
+ GError **error);
+
+/* Wrapper / workalike for mkstemp() */
+gint g_mkstemp (gchar *tmpl);
+gint g_mkstemp_full (gchar *tmpl,
+ int flags,
+ int mode);
+
+/* Wrapper for g_mkstemp */
+gint g_file_open_tmp (const gchar *tmpl,
+ gchar **name_used,
+ GError **error);
+
+char *g_format_size_for_display (goffset size);
+
+gchar *g_build_path (const gchar *separator,
+ const gchar *first_element,
+ ...) G_GNUC_MALLOC G_GNUC_NULL_TERMINATED;
+gchar *g_build_pathv (const gchar *separator,
+ gchar **args) G_GNUC_MALLOC;
+
+gchar *g_build_filename (const gchar *first_element,
+ ...) G_GNUC_MALLOC G_GNUC_NULL_TERMINATED;
+gchar *g_build_filenamev (gchar **args) G_GNUC_MALLOC;
+
+int g_mkdir_with_parents (const gchar *pathname,
+ int mode);
+
+G_END_DECLS
+
+#endif /* __G_FILEUTILS_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/ghash.h b/protocols/Sametime/src/glib/include/glib/ghash.h
new file mode 100644
index 0000000000..9128721bcf
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/ghash.h
@@ -0,0 +1,166 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_HASH_H__
+#define __G_HASH_H__
+
+#include <glib/gtypes.h>
+#include <glib/glist.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GHashTable GHashTable;
+
+typedef gboolean (*GHRFunc) (gpointer key,
+ gpointer value,
+ gpointer user_data);
+
+typedef struct _GHashTableIter GHashTableIter;
+
+struct _GHashTableIter
+{
+ /*< private >*/
+ gpointer dummy1;
+ gpointer dummy2;
+ gpointer dummy3;
+ int dummy4;
+ gboolean dummy5;
+ gpointer dummy6;
+};
+
+/* Hash tables
+ */
+GHashTable* g_hash_table_new (GHashFunc hash_func,
+ GEqualFunc key_equal_func);
+GHashTable* g_hash_table_new_full (GHashFunc hash_func,
+ GEqualFunc key_equal_func,
+ GDestroyNotify key_destroy_func,
+ GDestroyNotify value_destroy_func);
+void g_hash_table_destroy (GHashTable *hash_table);
+void g_hash_table_insert (GHashTable *hash_table,
+ gpointer key,
+ gpointer value);
+void g_hash_table_replace (GHashTable *hash_table,
+ gpointer key,
+ gpointer value);
+gboolean g_hash_table_remove (GHashTable *hash_table,
+ gconstpointer key);
+void g_hash_table_remove_all (GHashTable *hash_table);
+gboolean g_hash_table_steal (GHashTable *hash_table,
+ gconstpointer key);
+void g_hash_table_steal_all (GHashTable *hash_table);
+gpointer g_hash_table_lookup (GHashTable *hash_table,
+ gconstpointer key);
+gboolean g_hash_table_lookup_extended (GHashTable *hash_table,
+ gconstpointer lookup_key,
+ gpointer *orig_key,
+ gpointer *value);
+void g_hash_table_foreach (GHashTable *hash_table,
+ GHFunc func,
+ gpointer user_data);
+gpointer g_hash_table_find (GHashTable *hash_table,
+ GHRFunc predicate,
+ gpointer user_data);
+guint g_hash_table_foreach_remove (GHashTable *hash_table,
+ GHRFunc func,
+ gpointer user_data);
+guint g_hash_table_foreach_steal (GHashTable *hash_table,
+ GHRFunc func,
+ gpointer user_data);
+guint g_hash_table_size (GHashTable *hash_table);
+GList * g_hash_table_get_keys (GHashTable *hash_table);
+GList * g_hash_table_get_values (GHashTable *hash_table);
+
+void g_hash_table_iter_init (GHashTableIter *iter,
+ GHashTable *hash_table);
+gboolean g_hash_table_iter_next (GHashTableIter *iter,
+ gpointer *key,
+ gpointer *value);
+GHashTable* g_hash_table_iter_get_hash_table (GHashTableIter *iter);
+void g_hash_table_iter_remove (GHashTableIter *iter);
+void g_hash_table_iter_steal (GHashTableIter *iter);
+
+/* keeping hash tables alive */
+GHashTable* g_hash_table_ref (GHashTable *hash_table);
+void g_hash_table_unref (GHashTable *hash_table);
+
+#ifndef G_DISABLE_DEPRECATED
+
+/**
+ * g_hash_table_freeze:
+ * @hash_table: a #GHashTable
+ *
+ * This function is deprecated and will be removed in the next major
+ * release of GLib. It does nothing.
+ **/
+#define g_hash_table_freeze(hash_table) ((void)0)
+
+/**
+ * g_hash_table_thaw:
+ * @hash_table: a #GHashTable
+ *
+ * This function is deprecated and will be removed in the next major
+ * release of GLib. It does nothing.
+ **/
+#define g_hash_table_thaw(hash_table) ((void)0)
+
+#endif /* G_DISABLE_DEPRECATED */
+
+/* Hash Functions
+ */
+gboolean g_str_equal (gconstpointer v1,
+ gconstpointer v2);
+guint g_str_hash (gconstpointer v);
+
+gboolean g_int_equal (gconstpointer v1,
+ gconstpointer v2);
+guint g_int_hash (gconstpointer v);
+
+gboolean g_int64_equal (gconstpointer v1,
+ gconstpointer v2);
+guint g_int64_hash (gconstpointer v);
+
+gboolean g_double_equal (gconstpointer v1,
+ gconstpointer v2);
+guint g_double_hash (gconstpointer v);
+
+/* This "hash" function will just return the key's address as an
+ * unsigned integer. Useful for hashing on plain addresses or
+ * simple integer values.
+ * Passing NULL into g_hash_table_new() as GHashFunc has the
+ * same effect as passing g_direct_hash().
+ */
+guint g_direct_hash (gconstpointer v) G_GNUC_CONST;
+gboolean g_direct_equal (gconstpointer v1,
+ gconstpointer v2) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __G_HASH_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/ghook.h b/protocols/Sametime/src/glib/include/glib/ghook.h
new file mode 100644
index 0000000000..5577fc3e21
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/ghook.h
@@ -0,0 +1,181 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_HOOK_H__
+#define __G_HOOK_H__
+
+#include <glib/gmem.h>
+
+G_BEGIN_DECLS
+
+
+/* --- typedefs --- */
+typedef struct _GHook GHook;
+typedef struct _GHookList GHookList;
+
+typedef gint (*GHookCompareFunc) (GHook *new_hook,
+ GHook *sibling);
+typedef gboolean (*GHookFindFunc) (GHook *hook,
+ gpointer data);
+typedef void (*GHookMarshaller) (GHook *hook,
+ gpointer marshal_data);
+typedef gboolean (*GHookCheckMarshaller) (GHook *hook,
+ gpointer marshal_data);
+typedef void (*GHookFunc) (gpointer data);
+typedef gboolean (*GHookCheckFunc) (gpointer data);
+typedef void (*GHookFinalizeFunc) (GHookList *hook_list,
+ GHook *hook);
+typedef enum
+{
+ G_HOOK_FLAG_ACTIVE = 1 << 0,
+ G_HOOK_FLAG_IN_CALL = 1 << 1,
+ G_HOOK_FLAG_MASK = 0x0f
+} GHookFlagMask;
+#define G_HOOK_FLAG_USER_SHIFT (4)
+
+
+/* --- structures --- */
+struct _GHookList
+{
+ gulong seq_id;
+ guint hook_size : 16;
+ guint is_setup : 1;
+ GHook *hooks;
+ gpointer dummy3;
+ GHookFinalizeFunc finalize_hook;
+ gpointer dummy[2];
+};
+struct _GHook
+{
+ gpointer data;
+ GHook *next;
+ GHook *prev;
+ guint ref_count;
+ gulong hook_id;
+ guint flags;
+ gpointer func;
+ GDestroyNotify destroy;
+};
+
+
+/* --- macros --- */
+#define G_HOOK(hook) ((GHook*) (hook))
+#define G_HOOK_FLAGS(hook) (G_HOOK (hook)->flags)
+#define G_HOOK_ACTIVE(hook) ((G_HOOK_FLAGS (hook) & \
+ G_HOOK_FLAG_ACTIVE) != 0)
+#define G_HOOK_IN_CALL(hook) ((G_HOOK_FLAGS (hook) & \
+ G_HOOK_FLAG_IN_CALL) != 0)
+#define G_HOOK_IS_VALID(hook) (G_HOOK (hook)->hook_id != 0 && \
+ (G_HOOK_FLAGS (hook) & \
+ G_HOOK_FLAG_ACTIVE))
+#define G_HOOK_IS_UNLINKED(hook) (G_HOOK (hook)->next == NULL && \
+ G_HOOK (hook)->prev == NULL && \
+ G_HOOK (hook)->hook_id == 0 && \
+ G_HOOK (hook)->ref_count == 0)
+
+
+/* --- prototypes --- */
+/* callback maintenance functions */
+void g_hook_list_init (GHookList *hook_list,
+ guint hook_size);
+void g_hook_list_clear (GHookList *hook_list);
+GHook* g_hook_alloc (GHookList *hook_list);
+void g_hook_free (GHookList *hook_list,
+ GHook *hook);
+GHook * g_hook_ref (GHookList *hook_list,
+ GHook *hook);
+void g_hook_unref (GHookList *hook_list,
+ GHook *hook);
+gboolean g_hook_destroy (GHookList *hook_list,
+ gulong hook_id);
+void g_hook_destroy_link (GHookList *hook_list,
+ GHook *hook);
+void g_hook_prepend (GHookList *hook_list,
+ GHook *hook);
+void g_hook_insert_before (GHookList *hook_list,
+ GHook *sibling,
+ GHook *hook);
+void g_hook_insert_sorted (GHookList *hook_list,
+ GHook *hook,
+ GHookCompareFunc func);
+GHook* g_hook_get (GHookList *hook_list,
+ gulong hook_id);
+GHook* g_hook_find (GHookList *hook_list,
+ gboolean need_valids,
+ GHookFindFunc func,
+ gpointer data);
+GHook* g_hook_find_data (GHookList *hook_list,
+ gboolean need_valids,
+ gpointer data);
+GHook* g_hook_find_func (GHookList *hook_list,
+ gboolean need_valids,
+ gpointer func);
+GHook* g_hook_find_func_data (GHookList *hook_list,
+ gboolean need_valids,
+ gpointer func,
+ gpointer data);
+/* return the first valid hook, and increment its reference count */
+GHook* g_hook_first_valid (GHookList *hook_list,
+ gboolean may_be_in_call);
+/* return the next valid hook with incremented reference count, and
+ * decrement the reference count of the original hook
+ */
+GHook* g_hook_next_valid (GHookList *hook_list,
+ GHook *hook,
+ gboolean may_be_in_call);
+/* GHookCompareFunc implementation to insert hooks sorted by their id */
+gint g_hook_compare_ids (GHook *new_hook,
+ GHook *sibling);
+/* convenience macros */
+#define g_hook_append( hook_list, hook ) \
+ g_hook_insert_before ((hook_list), NULL, (hook))
+/* invoke all valid hooks with the (*GHookFunc) signature.
+ */
+void g_hook_list_invoke (GHookList *hook_list,
+ gboolean may_recurse);
+/* invoke all valid hooks with the (*GHookCheckFunc) signature,
+ * and destroy the hook if FALSE is returned.
+ */
+void g_hook_list_invoke_check (GHookList *hook_list,
+ gboolean may_recurse);
+/* invoke a marshaller on all valid hooks.
+ */
+void g_hook_list_marshal (GHookList *hook_list,
+ gboolean may_recurse,
+ GHookMarshaller marshaller,
+ gpointer marshal_data);
+void g_hook_list_marshal_check (GHookList *hook_list,
+ gboolean may_recurse,
+ GHookCheckMarshaller marshaller,
+ gpointer marshal_data);
+
+G_END_DECLS
+
+#endif /* __G_HOOK_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/ghostutils.h b/protocols/Sametime/src/glib/include/glib/ghostutils.h
new file mode 100644
index 0000000000..0349da364b
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/ghostutils.h
@@ -0,0 +1,40 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_HOST_UTILS_H__
+#define __G_HOST_UTILS_H__
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+gboolean g_hostname_is_non_ascii (const gchar *hostname);
+gboolean g_hostname_is_ascii_encoded (const gchar *hostname);
+gboolean g_hostname_is_ip_address (const gchar *hostname);
+
+gchar *g_hostname_to_ascii (const gchar *hostname);
+gchar *g_hostname_to_unicode (const gchar *hostname);
+
+G_END_DECLS
+
+#endif /* __G_HOST_UTILS_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/giochannel.h b/protocols/Sametime/src/glib/include/glib/giochannel.h
new file mode 100644
index 0000000000..2a40aa29ae
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/giochannel.h
@@ -0,0 +1,366 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_IOCHANNEL_H__
+#define __G_IOCHANNEL_H__
+
+#include <glib/gconvert.h>
+#include <glib/gmain.h>
+#include <glib/gstring.h>
+
+G_BEGIN_DECLS
+
+/* GIOChannel
+ */
+
+typedef struct _GIOChannel GIOChannel;
+typedef struct _GIOFuncs GIOFuncs;
+
+typedef enum
+{
+ G_IO_ERROR_NONE,
+ G_IO_ERROR_AGAIN,
+ G_IO_ERROR_INVAL,
+ G_IO_ERROR_UNKNOWN
+} GIOError;
+
+#define G_IO_CHANNEL_ERROR g_io_channel_error_quark()
+
+typedef enum
+{
+ /* Derived from errno */
+ G_IO_CHANNEL_ERROR_FBIG,
+ G_IO_CHANNEL_ERROR_INVAL,
+ G_IO_CHANNEL_ERROR_IO,
+ G_IO_CHANNEL_ERROR_ISDIR,
+ G_IO_CHANNEL_ERROR_NOSPC,
+ G_IO_CHANNEL_ERROR_NXIO,
+ G_IO_CHANNEL_ERROR_OVERFLOW,
+ G_IO_CHANNEL_ERROR_PIPE,
+ /* Other */
+ G_IO_CHANNEL_ERROR_FAILED
+} GIOChannelError;
+
+typedef enum
+{
+ G_IO_STATUS_ERROR,
+ G_IO_STATUS_NORMAL,
+ G_IO_STATUS_EOF,
+ G_IO_STATUS_AGAIN
+} GIOStatus;
+
+typedef enum
+{
+ G_SEEK_CUR,
+ G_SEEK_SET,
+ G_SEEK_END
+} GSeekType;
+
+typedef enum
+{
+ G_IO_IN GLIB_SYSDEF_POLLIN,
+ G_IO_OUT GLIB_SYSDEF_POLLOUT,
+ G_IO_PRI GLIB_SYSDEF_POLLPRI,
+ G_IO_ERR GLIB_SYSDEF_POLLERR,
+ G_IO_HUP GLIB_SYSDEF_POLLHUP,
+ G_IO_NVAL GLIB_SYSDEF_POLLNVAL
+} GIOCondition;
+
+typedef enum
+{
+ G_IO_FLAG_APPEND = 1 << 0,
+ G_IO_FLAG_NONBLOCK = 1 << 1,
+ G_IO_FLAG_IS_READABLE = 1 << 2, /* Read only flag */
+ G_IO_FLAG_IS_WRITEABLE = 1 << 3, /* Read only flag */
+ G_IO_FLAG_IS_SEEKABLE = 1 << 4, /* Read only flag */
+ G_IO_FLAG_MASK = (1 << 5) - 1,
+ G_IO_FLAG_GET_MASK = G_IO_FLAG_MASK,
+ G_IO_FLAG_SET_MASK = G_IO_FLAG_APPEND | G_IO_FLAG_NONBLOCK
+} GIOFlags;
+
+struct _GIOChannel
+{
+ /*< private >*/
+ gint ref_count;
+ GIOFuncs *funcs;
+
+ gchar *encoding;
+ GIConv read_cd;
+ GIConv write_cd;
+ gchar *line_term; /* String which indicates the end of a line of text */
+ guint line_term_len; /* So we can have null in the line term */
+
+ gsize buf_size;
+ GString *read_buf; /* Raw data from the channel */
+ GString *encoded_read_buf; /* Channel data converted to UTF-8 */
+ GString *write_buf; /* Data ready to be written to the file */
+ gchar partial_write_buf[6]; /* UTF-8 partial characters, null terminated */
+
+ /* Group the flags together, immediately after partial_write_buf, to save memory */
+
+ guint use_buffer : 1; /* The encoding uses the buffers */
+ guint do_encode : 1; /* The encoding uses the GIConv coverters */
+ guint close_on_unref : 1; /* Close the channel on final unref */
+ guint is_readable : 1; /* Cached GIOFlag */
+ guint is_writeable : 1; /* ditto */
+ guint is_seekable : 1; /* ditto */
+
+ gpointer reserved1;
+ gpointer reserved2;
+};
+
+typedef gboolean (*GIOFunc) (GIOChannel *source,
+ GIOCondition condition,
+ gpointer data);
+struct _GIOFuncs
+{
+ GIOStatus (*io_read) (GIOChannel *channel,
+ gchar *buf,
+ gsize count,
+ gsize *bytes_read,
+ GError **err);
+ GIOStatus (*io_write) (GIOChannel *channel,
+ const gchar *buf,
+ gsize count,
+ gsize *bytes_written,
+ GError **err);
+ GIOStatus (*io_seek) (GIOChannel *channel,
+ gint64 offset,
+ GSeekType type,
+ GError **err);
+ GIOStatus (*io_close) (GIOChannel *channel,
+ GError **err);
+ GSource* (*io_create_watch) (GIOChannel *channel,
+ GIOCondition condition);
+ void (*io_free) (GIOChannel *channel);
+ GIOStatus (*io_set_flags) (GIOChannel *channel,
+ GIOFlags flags,
+ GError **err);
+ GIOFlags (*io_get_flags) (GIOChannel *channel);
+};
+
+void g_io_channel_init (GIOChannel *channel);
+GIOChannel *g_io_channel_ref (GIOChannel *channel);
+void g_io_channel_unref (GIOChannel *channel);
+
+#ifndef G_DISABLE_DEPRECATED
+GIOError g_io_channel_read (GIOChannel *channel,
+ gchar *buf,
+ gsize count,
+ gsize *bytes_read);
+GIOError g_io_channel_write (GIOChannel *channel,
+ const gchar *buf,
+ gsize count,
+ gsize *bytes_written);
+GIOError g_io_channel_seek (GIOChannel *channel,
+ gint64 offset,
+ GSeekType type);
+void g_io_channel_close (GIOChannel *channel);
+#endif /* G_DISABLE_DEPRECATED */
+
+GIOStatus g_io_channel_shutdown (GIOChannel *channel,
+ gboolean flush,
+ GError **err);
+guint g_io_add_watch_full (GIOChannel *channel,
+ gint priority,
+ GIOCondition condition,
+ GIOFunc func,
+ gpointer user_data,
+ GDestroyNotify notify);
+GSource * g_io_create_watch (GIOChannel *channel,
+ GIOCondition condition);
+guint g_io_add_watch (GIOChannel *channel,
+ GIOCondition condition,
+ GIOFunc func,
+ gpointer user_data);
+
+/* character encoding conversion involved functions.
+ */
+
+void g_io_channel_set_buffer_size (GIOChannel *channel,
+ gsize size);
+gsize g_io_channel_get_buffer_size (GIOChannel *channel);
+GIOCondition g_io_channel_get_buffer_condition (GIOChannel *channel);
+GIOStatus g_io_channel_set_flags (GIOChannel *channel,
+ GIOFlags flags,
+ GError **error);
+GIOFlags g_io_channel_get_flags (GIOChannel *channel);
+void g_io_channel_set_line_term (GIOChannel *channel,
+ const gchar *line_term,
+ gint length);
+G_CONST_RETURN gchar* g_io_channel_get_line_term (GIOChannel *channel,
+ gint *length);
+void g_io_channel_set_buffered (GIOChannel *channel,
+ gboolean buffered);
+gboolean g_io_channel_get_buffered (GIOChannel *channel);
+GIOStatus g_io_channel_set_encoding (GIOChannel *channel,
+ const gchar *encoding,
+ GError **error);
+G_CONST_RETURN gchar* g_io_channel_get_encoding (GIOChannel *channel);
+void g_io_channel_set_close_on_unref (GIOChannel *channel,
+ gboolean do_close);
+gboolean g_io_channel_get_close_on_unref (GIOChannel *channel);
+
+
+GIOStatus g_io_channel_flush (GIOChannel *channel,
+ GError **error);
+GIOStatus g_io_channel_read_line (GIOChannel *channel,
+ gchar **str_return,
+ gsize *length,
+ gsize *terminator_pos,
+ GError **error);
+GIOStatus g_io_channel_read_line_string (GIOChannel *channel,
+ GString *buffer,
+ gsize *terminator_pos,
+ GError **error);
+GIOStatus g_io_channel_read_to_end (GIOChannel *channel,
+ gchar **str_return,
+ gsize *length,
+ GError **error);
+GIOStatus g_io_channel_read_chars (GIOChannel *channel,
+ gchar *buf,
+ gsize count,
+ gsize *bytes_read,
+ GError **error);
+GIOStatus g_io_channel_read_unichar (GIOChannel *channel,
+ gunichar *thechar,
+ GError **error);
+GIOStatus g_io_channel_write_chars (GIOChannel *channel,
+ const gchar *buf,
+ gssize count,
+ gsize *bytes_written,
+ GError **error);
+GIOStatus g_io_channel_write_unichar (GIOChannel *channel,
+ gunichar thechar,
+ GError **error);
+GIOStatus g_io_channel_seek_position (GIOChannel *channel,
+ gint64 offset,
+ GSeekType type,
+ GError **error);
+#ifdef G_OS_WIN32
+#define g_io_channel_new_file g_io_channel_new_file_utf8
+#endif
+
+GIOChannel* g_io_channel_new_file (const gchar *filename,
+ const gchar *mode,
+ GError **error);
+
+/* Error handling */
+
+GQuark g_io_channel_error_quark (void);
+GIOChannelError g_io_channel_error_from_errno (gint en);
+
+/* On Unix, IO channels created with this function for any file
+ * descriptor or socket.
+ *
+ * On Win32, this can be used either for files opened with the MSVCRT
+ * (the Microsoft run-time C library) _open() or _pipe, including file
+ * descriptors 0, 1 and 2 (corresponding to stdin, stdout and stderr),
+ * or for Winsock SOCKETs. If the parameter is a legal file
+ * descriptor, it is assumed to be such, otherwise it should be a
+ * SOCKET. This relies on SOCKETs and file descriptors not
+ * overlapping. If you want to be certain, call either
+ * g_io_channel_win32_new_fd() or g_io_channel_win32_new_socket()
+ * instead as appropriate.
+ *
+ * The term file descriptor as used in the context of Win32 refers to
+ * the emulated Unix-like file descriptors MSVCRT provides. The native
+ * corresponding concept is file HANDLE. There isn't as of yet a way to
+ * get GIOChannels for Win32 file HANDLEs.
+ */
+GIOChannel* g_io_channel_unix_new (int fd);
+gint g_io_channel_unix_get_fd (GIOChannel *channel);
+
+
+/* Hook for GClosure / GSource integration. Don't touch */
+GLIB_VAR GSourceFuncs g_io_watch_funcs;
+
+#ifdef G_OS_WIN32
+
+/* You can use this "pseudo file descriptor" in a GPollFD to add
+ * polling for Windows messages. GTK applications should not do that.
+ */
+
+#define G_WIN32_MSG_HANDLE 19981206
+
+/* Use this to get a GPollFD from a GIOChannel, so that you can call
+ * g_io_channel_win32_poll(). After calling this you should only use
+ * g_io_channel_read() to read from the GIOChannel, i.e. never read()
+ * from the underlying file descriptor. For SOCKETs, it is possible to call
+ * recv().
+ */
+void g_io_channel_win32_make_pollfd (GIOChannel *channel,
+ GIOCondition condition,
+ GPollFD *fd);
+
+/* This can be used to wait a until at least one of the channels is readable.
+ * On Unix you would do a select() on the file descriptors of the channels.
+ */
+gint g_io_channel_win32_poll (GPollFD *fds,
+ gint n_fds,
+ gint timeout_);
+
+/* Create an IO channel for Windows messages for window handle hwnd. */
+#if GLIB_SIZEOF_VOID_P == 8
+/* We use gsize here so that it is still an integer type and not a
+ * pointer, like the guint in the traditional prototype. We can't use
+ * intptr_t as that is not portable enough.
+ */
+GIOChannel *g_io_channel_win32_new_messages (gsize hwnd);
+#else
+GIOChannel *g_io_channel_win32_new_messages (guint hwnd);
+#endif
+
+/* Create an IO channel for C runtime (emulated Unix-like) file
+ * descriptors. After calling g_io_add_watch() on a IO channel
+ * returned by this function, you shouldn't call read() on the file
+ * descriptor. This is because adding polling for a file descriptor is
+ * implemented on Win32 by starting a thread that sits blocked in a
+ * read() from the file descriptor most of the time. All reads from
+ * the file descriptor should be done by this internal GLib
+ * thread. Your code should call only g_io_channel_read_chars().
+ */
+GIOChannel* g_io_channel_win32_new_fd (gint fd);
+
+/* Get the C runtime file descriptor of a channel. */
+gint g_io_channel_win32_get_fd (GIOChannel *channel);
+
+/* Create an IO channel for a winsock socket. The parameter should be
+ * a SOCKET. Contrary to IO channels for file descriptors (on *Win32),
+ * you can use normal recv() or recvfrom() on sockets even if GLib
+ * is polling them.
+ */
+GIOChannel *g_io_channel_win32_new_socket (gint socket);
+
+#endif
+
+G_END_DECLS
+
+#endif /* __G_IOCHANNEL_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gkeyfile.h b/protocols/Sametime/src/glib/include/glib/gkeyfile.h
new file mode 100644
index 0000000000..e16dc61272
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gkeyfile.h
@@ -0,0 +1,266 @@
+/* gkeyfile.h - desktop entry file parser
+ *
+ * Copyright 2004 Red Hat, Inc.
+ *
+ * Ray Strode <halfline@hawaii.rr.com>
+ *
+ * GLib is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * GLib is distributed in the hope that 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 GLib; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_KEY_FILE_H__
+#define __G_KEY_FILE_H__
+
+#include <glib/gerror.h>
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+ G_KEY_FILE_ERROR_UNKNOWN_ENCODING,
+ G_KEY_FILE_ERROR_PARSE,
+ G_KEY_FILE_ERROR_NOT_FOUND,
+ G_KEY_FILE_ERROR_KEY_NOT_FOUND,
+ G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
+ G_KEY_FILE_ERROR_INVALID_VALUE
+} GKeyFileError;
+
+#define G_KEY_FILE_ERROR g_key_file_error_quark()
+
+GQuark g_key_file_error_quark (void);
+
+typedef struct _GKeyFile GKeyFile;
+
+typedef enum
+{
+ G_KEY_FILE_NONE = 0,
+ G_KEY_FILE_KEEP_COMMENTS = 1 << 0,
+ G_KEY_FILE_KEEP_TRANSLATIONS = 1 << 1
+} GKeyFileFlags;
+
+GKeyFile *g_key_file_new (void);
+void g_key_file_free (GKeyFile *key_file);
+void g_key_file_set_list_separator (GKeyFile *key_file,
+ gchar separator);
+gboolean g_key_file_load_from_file (GKeyFile *key_file,
+ const gchar *file,
+ GKeyFileFlags flags,
+ GError **error);
+gboolean g_key_file_load_from_data (GKeyFile *key_file,
+ const gchar *data,
+ gsize length,
+ GKeyFileFlags flags,
+ GError **error);
+gboolean g_key_file_load_from_dirs (GKeyFile *key_file,
+ const gchar *file,
+ const gchar **search_dirs,
+ gchar **full_path,
+ GKeyFileFlags flags,
+ GError **error);
+gboolean g_key_file_load_from_data_dirs (GKeyFile *key_file,
+ const gchar *file,
+ gchar **full_path,
+ GKeyFileFlags flags,
+ GError **error);
+gchar *g_key_file_to_data (GKeyFile *key_file,
+ gsize *length,
+ GError **error) G_GNUC_MALLOC;
+gchar *g_key_file_get_start_group (GKeyFile *key_file) G_GNUC_MALLOC;
+gchar **g_key_file_get_groups (GKeyFile *key_file,
+ gsize *length) G_GNUC_MALLOC;
+gchar **g_key_file_get_keys (GKeyFile *key_file,
+ const gchar *group_name,
+ gsize *length,
+ GError **error) G_GNUC_MALLOC;
+gboolean g_key_file_has_group (GKeyFile *key_file,
+ const gchar *group_name);
+gboolean g_key_file_has_key (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ GError **error);
+gchar *g_key_file_get_value (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ GError **error) G_GNUC_MALLOC;
+void g_key_file_set_value (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ const gchar *value);
+gchar *g_key_file_get_string (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ GError **error) G_GNUC_MALLOC;
+void g_key_file_set_string (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ const gchar *string);
+gchar *g_key_file_get_locale_string (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ const gchar *locale,
+ GError **error) G_GNUC_MALLOC;
+void g_key_file_set_locale_string (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ const gchar *locale,
+ const gchar *string);
+gboolean g_key_file_get_boolean (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ GError **error);
+void g_key_file_set_boolean (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ gboolean value);
+gint g_key_file_get_integer (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ GError **error);
+void g_key_file_set_integer (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ gint value);
+gint64 g_key_file_get_int64 (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ GError **error);
+void g_key_file_set_int64 (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ gint64 value);
+guint64 g_key_file_get_uint64 (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ GError **error);
+void g_key_file_set_uint64 (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ guint64 value);
+gdouble g_key_file_get_double (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ GError **error);
+void g_key_file_set_double (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ gdouble value);
+gchar **g_key_file_get_string_list (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ gsize *length,
+ GError **error) G_GNUC_MALLOC;
+void g_key_file_set_string_list (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ const gchar * const list[],
+ gsize length);
+gchar **g_key_file_get_locale_string_list (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ const gchar *locale,
+ gsize *length,
+ GError **error) G_GNUC_MALLOC;
+void g_key_file_set_locale_string_list (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ const gchar *locale,
+ const gchar * const list[],
+ gsize length);
+gboolean *g_key_file_get_boolean_list (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ gsize *length,
+ GError **error) G_GNUC_MALLOC;
+void g_key_file_set_boolean_list (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ gboolean list[],
+ gsize length);
+gint *g_key_file_get_integer_list (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ gsize *length,
+ GError **error) G_GNUC_MALLOC;
+void g_key_file_set_double_list (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ gdouble list[],
+ gsize length);
+gdouble *g_key_file_get_double_list (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ gsize *length,
+ GError **error) G_GNUC_MALLOC;
+void g_key_file_set_integer_list (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ gint list[],
+ gsize length);
+gboolean g_key_file_set_comment (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ const gchar *comment,
+ GError **error);
+gchar *g_key_file_get_comment (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ GError **error) G_GNUC_MALLOC;
+
+gboolean g_key_file_remove_comment (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ GError **error);
+gboolean g_key_file_remove_key (GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ GError **error);
+gboolean g_key_file_remove_group (GKeyFile *key_file,
+ const gchar *group_name,
+ GError **error);
+
+/* Defines for handling freedesktop.org Desktop files */
+#define G_KEY_FILE_DESKTOP_GROUP "Desktop Entry"
+
+#define G_KEY_FILE_DESKTOP_KEY_TYPE "Type"
+#define G_KEY_FILE_DESKTOP_KEY_VERSION "Version"
+#define G_KEY_FILE_DESKTOP_KEY_NAME "Name"
+#define G_KEY_FILE_DESKTOP_KEY_GENERIC_NAME "GenericName"
+#define G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY "NoDisplay"
+#define G_KEY_FILE_DESKTOP_KEY_COMMENT "Comment"
+#define G_KEY_FILE_DESKTOP_KEY_ICON "Icon"
+#define G_KEY_FILE_DESKTOP_KEY_HIDDEN "Hidden"
+#define G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN "OnlyShowIn"
+#define G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN "NotShowIn"
+#define G_KEY_FILE_DESKTOP_KEY_TRY_EXEC "TryExec"
+#define G_KEY_FILE_DESKTOP_KEY_EXEC "Exec"
+#define G_KEY_FILE_DESKTOP_KEY_PATH "Path"
+#define G_KEY_FILE_DESKTOP_KEY_TERMINAL "Terminal"
+#define G_KEY_FILE_DESKTOP_KEY_MIME_TYPE "MimeType"
+#define G_KEY_FILE_DESKTOP_KEY_CATEGORIES "Categories"
+#define G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY "StartupNotify"
+#define G_KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS "StartupWMClass"
+#define G_KEY_FILE_DESKTOP_KEY_URL "URL"
+
+#define G_KEY_FILE_DESKTOP_TYPE_APPLICATION "Application"
+#define G_KEY_FILE_DESKTOP_TYPE_LINK "Link"
+#define G_KEY_FILE_DESKTOP_TYPE_DIRECTORY "Directory"
+
+G_END_DECLS
+
+#endif /* __G_KEY_FILE_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/glist.h b/protocols/Sametime/src/glib/include/glib/glist.h
new file mode 100644
index 0000000000..e74ed96f15
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/glist.h
@@ -0,0 +1,120 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_LIST_H__
+#define __G_LIST_H__
+
+#include <glib/gmem.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GList GList;
+
+struct _GList
+{
+ gpointer data;
+ GList *next;
+ GList *prev;
+};
+
+/* Doubly linked lists
+ */
+GList* g_list_alloc (void) G_GNUC_WARN_UNUSED_RESULT;
+void g_list_free (GList *list);
+void g_list_free_1 (GList *list);
+#define g_list_free1 g_list_free_1
+GList* g_list_append (GList *list,
+ gpointer data) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_prepend (GList *list,
+ gpointer data) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_insert (GList *list,
+ gpointer data,
+ gint position) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_insert_sorted (GList *list,
+ gpointer data,
+ GCompareFunc func) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_insert_sorted_with_data (GList *list,
+ gpointer data,
+ GCompareDataFunc func,
+ gpointer user_data) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_insert_before (GList *list,
+ GList *sibling,
+ gpointer data) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_concat (GList *list1,
+ GList *list2) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_remove (GList *list,
+ gconstpointer data) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_remove_all (GList *list,
+ gconstpointer data) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_remove_link (GList *list,
+ GList *llink) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_delete_link (GList *list,
+ GList *link_) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_reverse (GList *list) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_copy (GList *list) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_nth (GList *list,
+ guint n);
+GList* g_list_nth_prev (GList *list,
+ guint n);
+GList* g_list_find (GList *list,
+ gconstpointer data);
+GList* g_list_find_custom (GList *list,
+ gconstpointer data,
+ GCompareFunc func);
+gint g_list_position (GList *list,
+ GList *llink);
+gint g_list_index (GList *list,
+ gconstpointer data);
+GList* g_list_last (GList *list);
+GList* g_list_first (GList *list);
+guint g_list_length (GList *list);
+void g_list_foreach (GList *list,
+ GFunc func,
+ gpointer user_data);
+GList* g_list_sort (GList *list,
+ GCompareFunc compare_func) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_sort_with_data (GList *list,
+ GCompareDataFunc compare_func,
+ gpointer user_data) G_GNUC_WARN_UNUSED_RESULT;
+gpointer g_list_nth_data (GList *list,
+ guint n);
+
+
+#define g_list_previous(list) ((list) ? (((GList *)(list))->prev) : NULL)
+#define g_list_next(list) ((list) ? (((GList *)(list))->next) : NULL)
+
+#ifndef G_DISABLE_DEPRECATED
+void g_list_push_allocator (gpointer allocator);
+void g_list_pop_allocator (void);
+#endif
+
+G_END_DECLS
+
+#endif /* __G_LIST_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gmacros.h b/protocols/Sametime/src/glib/include/glib/gmacros.h
new file mode 100644
index 0000000000..9f9c25dcb1
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gmacros.h
@@ -0,0 +1,284 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+/* This file must not include any other glib header file and must thus
+ * not refer to variables from glibconfig.h
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_MACROS_H__
+#define __G_MACROS_H__
+
+/* We include stddef.h to get the system's definition of NULL
+ */
+#include <stddef.h>
+
+/* Here we provide G_GNUC_EXTENSION as an alias for __extension__,
+ * where this is valid. This allows for warningless compilation of
+ * "long long" types even in the presence of '-ansi -pedantic'.
+ */
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
+# define G_GNUC_EXTENSION __extension__
+#else
+# define G_GNUC_EXTENSION
+#endif
+
+/* Provide macros to feature the GCC function attribute.
+ */
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
+#define G_GNUC_PURE \
+ __attribute__((__pure__))
+#define G_GNUC_MALLOC \
+ __attribute__((__malloc__))
+#else
+#define G_GNUC_PURE
+#define G_GNUC_MALLOC
+#endif
+
+#if __GNUC__ >= 4
+#define G_GNUC_NULL_TERMINATED __attribute__((__sentinel__))
+#else
+#define G_GNUC_NULL_TERMINATED
+#endif
+
+#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
+#define G_GNUC_ALLOC_SIZE(x) __attribute__((__alloc_size__(x)))
+#define G_GNUC_ALLOC_SIZE2(x,y) __attribute__((__alloc_size__(x,y)))
+#else
+#define G_GNUC_ALLOC_SIZE(x)
+#define G_GNUC_ALLOC_SIZE2(x,y)
+#endif
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
+#define G_GNUC_PRINTF( format_idx, arg_idx ) \
+ __attribute__((__format__ (__printf__, format_idx, arg_idx)))
+#define G_GNUC_SCANF( format_idx, arg_idx ) \
+ __attribute__((__format__ (__scanf__, format_idx, arg_idx)))
+#define G_GNUC_FORMAT( arg_idx ) \
+ __attribute__((__format_arg__ (arg_idx)))
+#define G_GNUC_NORETURN \
+ __attribute__((__noreturn__))
+#define G_GNUC_CONST \
+ __attribute__((__const__))
+#define G_GNUC_UNUSED \
+ __attribute__((__unused__))
+#define G_GNUC_NO_INSTRUMENT \
+ __attribute__((__no_instrument_function__))
+#else /* !__GNUC__ */
+#define G_GNUC_PRINTF( format_idx, arg_idx )
+#define G_GNUC_SCANF( format_idx, arg_idx )
+#define G_GNUC_FORMAT( arg_idx )
+#define G_GNUC_NORETURN
+#define G_GNUC_CONST
+#define G_GNUC_UNUSED
+#define G_GNUC_NO_INSTRUMENT
+#endif /* !__GNUC__ */
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
+#define G_GNUC_DEPRECATED \
+ __attribute__((__deprecated__))
+#else
+#define G_GNUC_DEPRECATED
+#endif /* __GNUC__ */
+
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
+#define G_GNUC_DEPRECATED_FOR(f) \
+ __attribute__((deprecated("Use " #f " instead")))
+#else
+#define G_GNUC_DEPRECATED_FOR(f) G_GNUC_DEPRECATED
+#endif /* __GNUC__ */
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
+# define G_GNUC_MAY_ALIAS __attribute__((may_alias))
+#else
+# define G_GNUC_MAY_ALIAS
+#endif
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+#define G_GNUC_WARN_UNUSED_RESULT \
+ __attribute__((warn_unused_result))
+#else
+#define G_GNUC_WARN_UNUSED_RESULT
+#endif /* __GNUC__ */
+
+#ifndef G_DISABLE_DEPRECATED
+/* Wrap the gcc __PRETTY_FUNCTION__ and __FUNCTION__ variables with
+ * macros, so we can refer to them as strings unconditionally.
+ * usage not-recommended since gcc-3.0
+ */
+#if defined (__GNUC__) && (__GNUC__ < 3)
+#define G_GNUC_FUNCTION __FUNCTION__
+#define G_GNUC_PRETTY_FUNCTION __PRETTY_FUNCTION__
+#else /* !__GNUC__ */
+#define G_GNUC_FUNCTION ""
+#define G_GNUC_PRETTY_FUNCTION ""
+#endif /* !__GNUC__ */
+#endif /* !G_DISABLE_DEPRECATED */
+
+#define G_STRINGIFY(macro_or_string) G_STRINGIFY_ARG (macro_or_string)
+#define G_STRINGIFY_ARG(contents) #contents
+
+#define G_PASTE_ARGS(identifier1,identifier2) identifier1 ## identifier2
+#define G_PASTE(identifier1,identifier2) G_PASTE_ARGS (identifier1, identifier2)
+#define G_STATIC_ASSERT(expr) typedef struct { char Compile_Time_Assertion[(expr) ? 1 : -1]; } G_PASTE (_GStaticAssert_, __LINE__)
+
+/* Provide a string identifying the current code position */
+#if defined(__GNUC__) && (__GNUC__ < 3) && !defined(__cplusplus)
+# define G_STRLOC __FILE__ ":" G_STRINGIFY (__LINE__) ":" __PRETTY_FUNCTION__ "()"
+#else
+# define G_STRLOC __FILE__ ":" G_STRINGIFY (__LINE__)
+#endif
+
+/* Provide a string identifying the current function, non-concatenatable */
+#if defined (__GNUC__)
+# define G_STRFUNC ((const char*) (__PRETTY_FUNCTION__))
+#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 19901L
+# define G_STRFUNC ((const char*) (__func__))
+#else
+# define G_STRFUNC ((const char*) ("???"))
+#endif
+
+/* Guard C code in headers, while including them from C++ */
+#ifdef __cplusplus
+# define G_BEGIN_DECLS extern "C" {
+# define G_END_DECLS }
+#else
+# define G_BEGIN_DECLS
+# define G_END_DECLS
+#endif
+
+/* Provide definitions for some commonly used macros.
+ * Some of them are only provided if they haven't already
+ * been defined. It is assumed that if they are already
+ * defined then the current definition is correct.
+ */
+#ifndef NULL
+# ifdef __cplusplus
+# define NULL (0L)
+# else /* !__cplusplus */
+# define NULL ((void*) 0)
+# endif /* !__cplusplus */
+#endif
+
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+#undef MAX
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+#undef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+#undef ABS
+#define ABS(a) (((a) < 0) ? -(a) : (a))
+
+#undef CLAMP
+#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
+
+/* Count the number of elements in an array. The array must be defined
+ * as such; using this with a dynamically allocated array will give
+ * incorrect results.
+ */
+#define G_N_ELEMENTS(arr) (sizeof (arr) / sizeof ((arr)[0]))
+
+/* Macros by analogy to GINT_TO_POINTER, GPOINTER_TO_INT
+ */
+#define GPOINTER_TO_SIZE(p) ((gsize) (p))
+#define GSIZE_TO_POINTER(s) ((gpointer) (gsize) (s))
+
+/* Provide convenience macros for handling structure
+ * fields through their offsets.
+ */
+
+#if defined(__GNUC__) && __GNUC__ >= 4
+# define G_STRUCT_OFFSET(struct_type, member) \
+ ((glong) offsetof (struct_type, member))
+#else
+# define G_STRUCT_OFFSET(struct_type, member) \
+ ((glong) ((guint8*) &((struct_type*) 0)->member))
+#endif
+
+#define G_STRUCT_MEMBER_P(struct_p, struct_offset) \
+ ((gpointer) ((guint8*) (struct_p) + (glong) (struct_offset)))
+#define G_STRUCT_MEMBER(member_type, struct_p, struct_offset) \
+ (*(member_type*) G_STRUCT_MEMBER_P ((struct_p), (struct_offset)))
+
+/* Provide simple macro statement wrappers:
+ * G_STMT_START { statements; } G_STMT_END;
+ * This can be used as a single statement, like:
+ * if (x) G_STMT_START { ... } G_STMT_END; else ...
+ * This intentionally does not use compiler extensions like GCC's '({...})' to
+ * avoid portability issue or side effects when compiled with different compilers.
+ */
+#if !(defined (G_STMT_START) && defined (G_STMT_END))
+# define G_STMT_START do
+# define G_STMT_END while (0)
+#endif
+
+/* Allow the app programmer to select whether or not return values
+ * (usually char*) are const or not. Don't try using this feature for
+ * functions with C++ linkage.
+ */
+#ifdef G_DISABLE_CONST_RETURNS
+#define G_CONST_RETURN
+#else
+#define G_CONST_RETURN const
+#endif
+
+/*
+ * The G_LIKELY and G_UNLIKELY macros let the programmer give hints to
+ * the compiler about the expected result of an expression. Some compilers
+ * can use this information for optimizations.
+ *
+ * The _G_BOOLEAN_EXPR macro is intended to trigger a gcc warning when
+ * putting assignments in g_return_if_fail ().
+ */
+#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
+#define _G_BOOLEAN_EXPR(expr) \
+ __extension__ ({ \
+ int _g_boolean_var_; \
+ if (expr) \
+ _g_boolean_var_ = 1; \
+ else \
+ _g_boolean_var_ = 0; \
+ _g_boolean_var_; \
+})
+#define G_LIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 1))
+#define G_UNLIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 0))
+#else
+#define G_LIKELY(expr) (expr)
+#define G_UNLIKELY(expr) (expr)
+#endif
+
+#endif /* __G_MACROS_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gmain.h b/protocols/Sametime/src/glib/include/glib/gmain.h
new file mode 100644
index 0000000000..24c6171fe6
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gmain.h
@@ -0,0 +1,531 @@
+/* gmain.h - the GLib Main loop
+ * Copyright (C) 1998-2000 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_MAIN_H__
+#define __G_MAIN_H__
+
+#include <glib/gpoll.h>
+#include <glib/gslist.h>
+#include <glib/gthread.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GMainContext:
+ *
+ * The <structname>GMainContext</structname> struct is an opaque data
+ * type representing a set of sources to be handled in a main loop.
+ */
+typedef struct _GMainContext GMainContext;
+
+/**
+ * GMainLoop:
+ *
+ * The <structname>GMainLoop</structname> struct is an opaque data type
+ * representing the main event loop of a GLib or GTK+ application.
+ */
+typedef struct _GMainLoop GMainLoop;
+
+/**
+ * GSource:
+ *
+ * The <structname>GSource</structname> struct is an opaque data type
+ * representing an event source.
+ */
+typedef struct _GSource GSource;
+
+/**
+ * GSourceCallbackFuncs:
+ * @ref: Called when a reference is added to the callback object
+ * @unref: Called when a reference to the callback object is dropped
+ * @get: Called to extract the callback function and data from the
+ * callback object.
+
+ * The <structname>GSourceCallbackFuncs</structname> struct contains
+ * functions for managing callback objects.
+ */
+typedef struct _GSourceCallbackFuncs GSourceCallbackFuncs;
+
+/**
+ * GSourceFuncs:
+ * @prepare: Called before all the file descriptors are polled. If the
+ * source can determine that it is ready here (without waiting for the
+ * results of the poll() call) it should return %TRUE. It can also return
+ * a @timeout_ value which should be the maximum timeout (in milliseconds)
+ * which should be passed to the poll() call. The actual timeout used will
+ * be -1 if all sources returned -1, or it will be the minimum of all the
+ * @timeout_ values returned which were >= 0.
+ * @check: Called after all the file descriptors are polled. The source
+ * should return %TRUE if it is ready to be dispatched. Note that some
+ * time may have passed since the previous prepare function was called,
+ * so the source should be checked again here.
+ * @dispatch: Called to dispatch the event source, after it has returned
+ * %TRUE in either its @prepare or its @check function. The @dispatch
+ * function is passed in a callback function and data. The callback
+ * function may be %NULL if the source was never connected to a callback
+ * using g_source_set_callback(). The @dispatch function should call the
+ * callback function with @user_data and whatever additional parameters
+ * are needed for this type of event source.
+ * @finalize: Called when the source is finalized.
+ * @closure_callback:
+ * @closure_marshal:
+ *
+ * The <structname>GSourceFuncs</structname> struct contains a table of
+ * functions used to handle event sources in a generic manner.
+ *
+ * For idle sources, the prepare and check functions always return %TRUE
+ * to indicate that the source is always ready to be processed. The prepare
+ * function also returns a timeout value of 0 to ensure that the poll() call
+ * doesn't block (since that would be time wasted which could have been spent
+ * running the idle function).
+ *
+ * For timeout sources, the prepare and check functions both return %TRUE
+ * if the timeout interval has expired. The prepare function also returns
+ * a timeout value to ensure that the poll() call doesn't block too long
+ * and miss the next timeout.
+ *
+ * For file descriptor sources, the prepare function typically returns %FALSE,
+ * since it must wait until poll() has been called before it knows whether
+ * any events need to be processed. It sets the returned timeout to -1 to
+ * indicate that it doesn't mind how long the poll() call blocks. In the
+ * check function, it tests the results of the poll() call to see if the
+ * required condition has been met, and returns %TRUE if so.
+ */
+typedef struct _GSourceFuncs GSourceFuncs;
+
+/**
+ * GPid:
+ *
+ * A type which is used to hold a process identification.
+ *
+ * On UNIX, processes are identified by a process id (an integer),
+ * while Windows uses process handles (which are pointers).
+ */
+
+typedef gboolean (*GSourceFunc) (gpointer data);
+
+/**
+ * GChildWatchFunc:
+ * @pid: the process id of the child process
+ * @status: Status information about the child process,
+ * see waitpid(2) for more information about this field
+ * @data: user data passed to g_child_watch_add()
+ *
+ * The type of functions to be called when a child exists.
+ */
+typedef void (*GChildWatchFunc) (GPid pid,
+ gint status,
+ gpointer data);
+struct _GSource
+{
+ /*< private >*/
+ gpointer callback_data;
+ GSourceCallbackFuncs *callback_funcs;
+
+ GSourceFuncs *source_funcs;
+ guint ref_count;
+
+ GMainContext *context;
+
+ gint priority;
+ guint flags;
+ guint source_id;
+
+ GSList *poll_fds;
+
+ GSource *prev;
+ GSource *next;
+
+ char *name;
+ gpointer reserved2;
+};
+
+struct _GSourceCallbackFuncs
+{
+ void (*ref) (gpointer cb_data);
+ void (*unref) (gpointer cb_data);
+ void (*get) (gpointer cb_data,
+ GSource *source,
+ GSourceFunc *func,
+ gpointer *data);
+};
+
+typedef void (*GSourceDummyMarshal) (void);
+
+struct _GSourceFuncs
+{
+ gboolean (*prepare) (GSource *source,
+ gint *timeout_);
+ gboolean (*check) (GSource *source);
+ gboolean (*dispatch) (GSource *source,
+ GSourceFunc callback,
+ gpointer user_data);
+ void (*finalize) (GSource *source); /* Can be NULL */
+
+ /* For use by g_source_set_closure */
+ GSourceFunc closure_callback;
+ GSourceDummyMarshal closure_marshal; /* Really is of type GClosureMarshal */
+};
+
+/* Standard priorities */
+
+/**
+ * G_PRIORITY_HIGH:
+ *
+ * Use this for high priority event sources.
+ *
+ * It is not used within GLib or GTK+.
+ */
+#define G_PRIORITY_HIGH -100
+
+/**
+ * G_PRIORITY_DEFAULT:
+ *
+ * Use this for default priority event sources.
+ *
+ * In GLib this priority is used when adding timeout functions
+ * with g_timeout_add(). In GDK this priority is used for events
+ * from the X server.
+ */
+#define G_PRIORITY_DEFAULT 0
+
+/**
+ * G_PRIORITY_HIGH_IDLE:
+ *
+ * Use this for high priority idle functions.
+ *
+ * GTK+ uses #G_PRIORITY_HIGH_IDLE + 10 for resizing operations,
+ * and #G_PRIORITY_HIGH_IDLE + 20 for redrawing operations. (This is
+ * done to ensure that any pending resizes are processed before any
+ * pending redraws, so that widgets are not redrawn twice unnecessarily.)
+ */
+#define G_PRIORITY_HIGH_IDLE 100
+
+/**
+ * G_PRIORITY_DEFAULT_IDLE:
+ *
+ * Use this for default priority idle functions.
+ *
+ * In GLib this priority is used when adding idle functions with
+ * g_idle_add().
+ */
+#define G_PRIORITY_DEFAULT_IDLE 200
+
+/**
+ * G_PRIORITY_LOW:
+ *
+ * Use this for very low priority background tasks.
+ *
+ * It is not used within GLib or GTK+.
+ */
+#define G_PRIORITY_LOW 300
+
+/* GMainContext: */
+
+GMainContext *g_main_context_new (void);
+GMainContext *g_main_context_ref (GMainContext *context);
+void g_main_context_unref (GMainContext *context);
+GMainContext *g_main_context_default (void);
+
+gboolean g_main_context_iteration (GMainContext *context,
+ gboolean may_block);
+gboolean g_main_context_pending (GMainContext *context);
+
+/* For implementation of legacy interfaces
+ */
+GSource *g_main_context_find_source_by_id (GMainContext *context,
+ guint source_id);
+GSource *g_main_context_find_source_by_user_data (GMainContext *context,
+ gpointer user_data);
+GSource *g_main_context_find_source_by_funcs_user_data (GMainContext *context,
+ GSourceFuncs *funcs,
+ gpointer user_data);
+
+/* Low level functions for implementing custom main loops.
+ */
+void g_main_context_wakeup (GMainContext *context);
+gboolean g_main_context_acquire (GMainContext *context);
+void g_main_context_release (GMainContext *context);
+gboolean g_main_context_is_owner (GMainContext *context);
+gboolean g_main_context_wait (GMainContext *context,
+ GCond *cond,
+ GMutex *mutex);
+
+gboolean g_main_context_prepare (GMainContext *context,
+ gint *priority);
+gint g_main_context_query (GMainContext *context,
+ gint max_priority,
+ gint *timeout_,
+ GPollFD *fds,
+ gint n_fds);
+gint g_main_context_check (GMainContext *context,
+ gint max_priority,
+ GPollFD *fds,
+ gint n_fds);
+void g_main_context_dispatch (GMainContext *context);
+
+void g_main_context_set_poll_func (GMainContext *context,
+ GPollFunc func);
+GPollFunc g_main_context_get_poll_func (GMainContext *context);
+
+/* Low level functions for use by source implementations
+ */
+void g_main_context_add_poll (GMainContext *context,
+ GPollFD *fd,
+ gint priority);
+void g_main_context_remove_poll (GMainContext *context,
+ GPollFD *fd);
+
+gint g_main_depth (void);
+GSource *g_main_current_source (void);
+
+/* GMainContexts for other threads
+ */
+void g_main_context_push_thread_default (GMainContext *context);
+void g_main_context_pop_thread_default (GMainContext *context);
+GMainContext *g_main_context_get_thread_default (void);
+
+/* GMainLoop: */
+
+GMainLoop *g_main_loop_new (GMainContext *context,
+ gboolean is_running);
+void g_main_loop_run (GMainLoop *loop);
+void g_main_loop_quit (GMainLoop *loop);
+GMainLoop *g_main_loop_ref (GMainLoop *loop);
+void g_main_loop_unref (GMainLoop *loop);
+gboolean g_main_loop_is_running (GMainLoop *loop);
+GMainContext *g_main_loop_get_context (GMainLoop *loop);
+
+/* GSource: */
+
+GSource *g_source_new (GSourceFuncs *source_funcs,
+ guint struct_size);
+GSource *g_source_ref (GSource *source);
+void g_source_unref (GSource *source);
+
+guint g_source_attach (GSource *source,
+ GMainContext *context);
+void g_source_destroy (GSource *source);
+
+void g_source_set_priority (GSource *source,
+ gint priority);
+gint g_source_get_priority (GSource *source);
+void g_source_set_can_recurse (GSource *source,
+ gboolean can_recurse);
+gboolean g_source_get_can_recurse (GSource *source);
+guint g_source_get_id (GSource *source);
+
+GMainContext *g_source_get_context (GSource *source);
+
+void g_source_set_callback (GSource *source,
+ GSourceFunc func,
+ gpointer data,
+ GDestroyNotify notify);
+
+void g_source_set_funcs (GSource *source,
+ GSourceFuncs *funcs);
+gboolean g_source_is_destroyed (GSource *source);
+
+void g_source_set_name (GSource *source,
+ const char *name);
+G_CONST_RETURN char* g_source_get_name (GSource *source);
+void g_source_set_name_by_id (guint tag,
+ const char *name);
+
+
+/* Used to implement g_source_connect_closure and internally*/
+void g_source_set_callback_indirect (GSource *source,
+ gpointer callback_data,
+ GSourceCallbackFuncs *callback_funcs);
+
+void g_source_add_poll (GSource *source,
+ GPollFD *fd);
+void g_source_remove_poll (GSource *source,
+ GPollFD *fd);
+
+void g_source_get_current_time (GSource *source,
+ GTimeVal *timeval);
+
+ /* void g_source_connect_closure (GSource *source,
+ GClosure *closure);
+ */
+
+/* Specific source types
+ */
+GSource *g_idle_source_new (void);
+GSource *g_child_watch_source_new (GPid pid);
+GSource *g_timeout_source_new (guint interval);
+GSource *g_timeout_source_new_seconds (guint interval);
+
+/* Miscellaneous functions
+ */
+void g_get_current_time (GTimeVal *result);
+
+/* ============== Compat main loop stuff ================== */
+
+#ifndef G_DISABLE_DEPRECATED
+
+/**
+ * g_main_new:
+ * @is_running: set to %TRUE to indicate that the loop is running. This
+ * is not very important since calling g_main_run() will set this
+ * to %TRUE anyway.
+ *
+ * Creates a new #GMainLoop for th default main context.
+ *
+ * Returns: a new #GMainLoop
+ *
+ * Deprecated: 2.2: Use g_main_loop_new() instead
+ */
+#define g_main_new(is_running) g_main_loop_new (NULL, is_running)
+
+/**
+ * g_main_run:
+ * @loop: a #GMainLoop
+ *
+ * Runs a main loop until it stops running.
+ *
+ * Deprecated: 2.2: Use g_main_loop_run() instead
+ */
+#define g_main_run(loop) g_main_loop_run(loop)
+
+/**
+ * g_main_quit:
+ * @loop: a #GMainLoop
+ *
+ * Stops the #GMainLoop.
+ * If g_main_run() was called to run the #GMainLoop, it will now return.
+ *
+ * Deprecated: 2.2: Use g_main_loop_quit() instead
+ */
+#define g_main_quit(loop) g_main_loop_quit(loop)
+
+/**
+ * g_main_destroy:
+ * @loop: a #GMainLoop
+ *
+ * Frees the memory allocated for the #GMainLoop.
+ *
+ * Deprecated: 2.2: Use g_main_loop_unref() instead
+ */
+#define g_main_destroy(loop) g_main_loop_unref(loop)
+
+/**
+ * g_main_is_running:
+ * @loop: a #GMainLoop
+ *
+ * Checks if the main loop is running.
+ *
+ * Returns: %TRUE if the main loop is running
+ *
+ * Deprecated: 2.2: Use g_main_loop_is_running() instead
+ */
+#define g_main_is_running(loop) g_main_loop_is_running(loop)
+
+/**
+ * g_main_iteration:
+ * @may_block: set to %TRUE if it should block (i.e. wait) until an event
+ * source becomes ready. It will return after an event source has been
+ * processed. If set to %FALSE it will return immediately if no event
+ * source is ready to be processed.
+ *
+ * Runs a single iteration for the default #GMainContext.
+ *
+ * Returns: %TRUE if more events are pending.
+ *
+ * Deprecated: 2.2: Use g_main_context_iteration() instead.
+ */
+#define g_main_iteration(may_block) g_main_context_iteration (NULL, may_block)
+
+/**
+ * g_main_pending:
+ *
+ * Checks if any events are pending for the default #GMainContext
+ * (i.e. ready to be processed).
+ *
+ * Returns: %TRUE if any events are pending.
+ *
+ * Deprected: 2.2: Use g_main_context_pending() instead.
+ */
+#define g_main_pending() g_main_context_pending (NULL)
+
+/**
+ * g_main_set_poll_func:
+ * @func: the function to call to poll all file descriptors
+ *
+ * Sets the function to use for the handle polling of file descriptors
+ * for the default main context.
+ *
+ * Deprecated: 2.2: Use g_main_context_set_poll_func() again
+ */
+#define g_main_set_poll_func(func) g_main_context_set_poll_func (NULL, func)
+
+#endif /* G_DISABLE_DEPRECATED */
+
+/* Source manipulation by ID */
+gboolean g_source_remove (guint tag);
+gboolean g_source_remove_by_user_data (gpointer user_data);
+gboolean g_source_remove_by_funcs_user_data (GSourceFuncs *funcs,
+ gpointer user_data);
+
+/* Idles, child watchers and timeouts */
+guint g_timeout_add_full (gint priority,
+ guint interval,
+ GSourceFunc function,
+ gpointer data,
+ GDestroyNotify notify);
+guint g_timeout_add (guint interval,
+ GSourceFunc function,
+ gpointer data);
+guint g_timeout_add_seconds_full (gint priority,
+ guint interval,
+ GSourceFunc function,
+ gpointer data,
+ GDestroyNotify notify);
+guint g_timeout_add_seconds (guint interval,
+ GSourceFunc function,
+ gpointer data);
+guint g_child_watch_add_full (gint priority,
+ GPid pid,
+ GChildWatchFunc function,
+ gpointer data,
+ GDestroyNotify notify);
+guint g_child_watch_add (GPid pid,
+ GChildWatchFunc function,
+ gpointer data);
+guint g_idle_add (GSourceFunc function,
+ gpointer data);
+guint g_idle_add_full (gint priority,
+ GSourceFunc function,
+ gpointer data,
+ GDestroyNotify notify);
+gboolean g_idle_remove_by_data (gpointer data);
+
+/* Hook for GClosure / GSource integration. Don't touch */
+GLIB_VAR GSourceFuncs g_timeout_funcs;
+GLIB_VAR GSourceFuncs g_child_watch_funcs;
+GLIB_VAR GSourceFuncs g_idle_funcs;
+
+G_END_DECLS
+
+#endif /* __G_MAIN_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gmappedfile.h b/protocols/Sametime/src/glib/include/glib/gmappedfile.h
new file mode 100644
index 0000000000..dbb3f89e6a
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gmappedfile.h
@@ -0,0 +1,49 @@
+/* GLIB - Library of useful routines for C programming
+ * gmappedfile.h: Simplified wrapper around the mmap function
+ *
+ * Copyright 2005 Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_MAPPED_FILE_H__
+#define __G_MAPPED_FILE_H__
+
+#include <glib/gerror.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GMappedFile GMappedFile;
+
+GMappedFile *g_mapped_file_new (const gchar *filename,
+ gboolean writable,
+ GError **error) G_GNUC_MALLOC;
+gsize g_mapped_file_get_length (GMappedFile *file);
+gchar *g_mapped_file_get_contents (GMappedFile *file);
+GMappedFile *g_mapped_file_ref (GMappedFile *file);
+void g_mapped_file_unref (GMappedFile *file);
+
+#ifndef G_DISABLE_DEPRECATED
+void g_mapped_file_free (GMappedFile *file);
+#endif
+
+G_END_DECLS
+
+#endif /* __G_MAPPED_FILE_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gmarkup.h b/protocols/Sametime/src/glib/include/glib/gmarkup.h
new file mode 100644
index 0000000000..7bfc08641c
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gmarkup.h
@@ -0,0 +1,163 @@
+/* gmarkup.h - Simple XML-like string parser/writer
+ *
+ * Copyright 2000 Red Hat, Inc.
+ *
+ * GLib is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * GLib is distributed in the hope that 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 GLib; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_MARKUP_H__
+#define __G_MARKUP_H__
+
+#include <stdarg.h>
+
+#include <glib/gerror.h>
+#include <glib/gslist.h>
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+ G_MARKUP_ERROR_BAD_UTF8,
+ G_MARKUP_ERROR_EMPTY,
+ G_MARKUP_ERROR_PARSE,
+ /* The following are primarily intended for specific GMarkupParser
+ * implementations to set.
+ */
+ G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+ G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
+ G_MARKUP_ERROR_INVALID_CONTENT,
+ G_MARKUP_ERROR_MISSING_ATTRIBUTE
+} GMarkupError;
+
+#define G_MARKUP_ERROR g_markup_error_quark ()
+
+GQuark g_markup_error_quark (void);
+
+typedef enum
+{
+ G_MARKUP_DO_NOT_USE_THIS_UNSUPPORTED_FLAG = 1 << 0,
+ G_MARKUP_TREAT_CDATA_AS_TEXT = 1 << 1,
+ G_MARKUP_PREFIX_ERROR_POSITION = 1 << 2
+} GMarkupParseFlags;
+
+typedef struct _GMarkupParseContext GMarkupParseContext;
+typedef struct _GMarkupParser GMarkupParser;
+
+struct _GMarkupParser
+{
+ /* Called for open tags <foo bar="baz"> */
+ void (*start_element) (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error);
+
+ /* Called for close tags </foo> */
+ void (*end_element) (GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error);
+
+ /* Called for character data */
+ /* text is not nul-terminated */
+ void (*text) (GMarkupParseContext *context,
+ const gchar *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error);
+
+ /* Called for strings that should be re-saved verbatim in this same
+ * position, but are not otherwise interpretable. At the moment
+ * this includes comments and processing instructions.
+ */
+ /* text is not nul-terminated. */
+ void (*passthrough) (GMarkupParseContext *context,
+ const gchar *passthrough_text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error);
+
+ /* Called on error, including one set by other
+ * methods in the vtable. The GError should not be freed.
+ */
+ void (*error) (GMarkupParseContext *context,
+ GError *error,
+ gpointer user_data);
+};
+
+GMarkupParseContext *g_markup_parse_context_new (const GMarkupParser *parser,
+ GMarkupParseFlags flags,
+ gpointer user_data,
+ GDestroyNotify user_data_dnotify);
+void g_markup_parse_context_free (GMarkupParseContext *context);
+gboolean g_markup_parse_context_parse (GMarkupParseContext *context,
+ const gchar *text,
+ gssize text_len,
+ GError **error);
+void g_markup_parse_context_push (GMarkupParseContext *context,
+ const GMarkupParser *parser,
+ gpointer user_data);
+gpointer g_markup_parse_context_pop (GMarkupParseContext *context);
+
+gboolean g_markup_parse_context_end_parse (GMarkupParseContext *context,
+ GError **error);
+G_CONST_RETURN gchar *g_markup_parse_context_get_element (GMarkupParseContext *context);
+G_CONST_RETURN GSList *g_markup_parse_context_get_element_stack (GMarkupParseContext *context);
+
+/* For user-constructed error messages, has no precise semantics */
+void g_markup_parse_context_get_position (GMarkupParseContext *context,
+ gint *line_number,
+ gint *char_number);
+gpointer g_markup_parse_context_get_user_data (GMarkupParseContext *context);
+
+/* useful when saving */
+gchar* g_markup_escape_text (const gchar *text,
+ gssize length);
+
+gchar *g_markup_printf_escaped (const char *format,
+ ...) G_GNUC_PRINTF (1, 2);
+gchar *g_markup_vprintf_escaped (const char *format,
+ va_list args);
+
+typedef enum
+{
+ G_MARKUP_COLLECT_INVALID,
+ G_MARKUP_COLLECT_STRING,
+ G_MARKUP_COLLECT_STRDUP,
+ G_MARKUP_COLLECT_BOOLEAN,
+ G_MARKUP_COLLECT_TRISTATE,
+
+ G_MARKUP_COLLECT_OPTIONAL = (1 << 16)
+} GMarkupCollectType;
+
+
+/* useful from start_element */
+gboolean g_markup_collect_attributes (const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ GError **error,
+ GMarkupCollectType first_type,
+ const gchar *first_attr,
+ ...);
+
+G_END_DECLS
+
+#endif /* __G_MARKUP_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gmem.h b/protocols/Sametime/src/glib/include/glib/gmem.h
new file mode 100644
index 0000000000..01d953e6c5
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gmem.h
@@ -0,0 +1,309 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_MEM_H__
+#define __G_MEM_H__
+
+#include <glib/gslice.h>
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GMemVTable:
+ * @malloc: function to use for allocating memory.
+ * @realloc: function to use for reallocating memory.
+ * @free: function to use to free memory.
+ * @calloc: function to use for allocating zero-filled memory.
+ * @try_malloc: function to use for allocating memory without a default error handler.
+ * @try_realloc: function to use for reallocating memory without a default error handler.
+ *
+ * A set of functions used to perform memory allocation. The same #GMemVTable must
+ * be used for all allocations in the same program; a call to g_mem_set_vtable(),
+ * if it exists, should be prior to any use of GLib.
+ */
+typedef struct _GMemVTable GMemVTable;
+
+
+#if GLIB_SIZEOF_VOID_P > GLIB_SIZEOF_LONG
+/**
+ * G_MEM_ALIGN:
+ *
+ * Indicates the number of bytes to which memory will be aligned on the
+ * current platform.
+ */
+# define G_MEM_ALIGN GLIB_SIZEOF_VOID_P
+#else /* GLIB_SIZEOF_VOID_P <= GLIB_SIZEOF_LONG */
+# define G_MEM_ALIGN GLIB_SIZEOF_LONG
+#endif /* GLIB_SIZEOF_VOID_P <= GLIB_SIZEOF_LONG */
+
+
+/* Memory allocation functions
+ */
+
+void g_free (gpointer mem);
+
+gpointer g_malloc (gsize n_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
+gpointer g_malloc0 (gsize n_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
+gpointer g_realloc (gpointer mem,
+ gsize n_bytes) G_GNUC_WARN_UNUSED_RESULT;
+gpointer g_try_malloc (gsize n_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
+gpointer g_try_malloc0 (gsize n_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
+gpointer g_try_realloc (gpointer mem,
+ gsize n_bytes) G_GNUC_WARN_UNUSED_RESULT;
+
+gpointer g_malloc_n (gsize n_blocks,
+ gsize n_block_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE2(1,2);
+gpointer g_malloc0_n (gsize n_blocks,
+ gsize n_block_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE2(1,2);
+gpointer g_realloc_n (gpointer mem,
+ gsize n_blocks,
+ gsize n_block_bytes) G_GNUC_WARN_UNUSED_RESULT;
+gpointer g_try_malloc_n (gsize n_blocks,
+ gsize n_block_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE2(1,2);
+gpointer g_try_malloc0_n (gsize n_blocks,
+ gsize n_block_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE2(1,2);
+gpointer g_try_realloc_n (gpointer mem,
+ gsize n_blocks,
+ gsize n_block_bytes) G_GNUC_WARN_UNUSED_RESULT;
+
+
+/* Optimise: avoid the call to the (slower) _n function if we can
+ * determine at compile-time that no overflow happens.
+ */
+#if defined (__GNUC__) && (__GNUC__ >= 2) && defined (__OPTIMIZE__)
+# define _G_NEW(struct_type, n_structs, func) \
+ (struct_type *) (__extension__ ({ \
+ gsize __n = (gsize) (n_structs); \
+ gsize __s = sizeof (struct_type); \
+ gpointer __p; \
+ if (__s == 1) \
+ __p = g_##func (__n); \
+ else if (__builtin_constant_p (__n) && \
+ (__s == 0 || __n <= G_MAXSIZE / __s)) \
+ __p = g_##func (__n * __s); \
+ else \
+ __p = g_##func##_n (__n, __s); \
+ __p; \
+ }))
+# define _G_RENEW(struct_type, mem, n_structs, func) \
+ (struct_type *) (__extension__ ({ \
+ gsize __n = (gsize) (n_structs); \
+ gsize __s = sizeof (struct_type); \
+ gpointer __p = (gpointer) (mem); \
+ if (__s == 1) \
+ __p = g_##func (__p, __n); \
+ else if (__builtin_constant_p (__n) && \
+ (__s == 0 || __n <= G_MAXSIZE / __s)) \
+ __p = g_##func (__p, __n * __s); \
+ else \
+ __p = g_##func##_n (__p, __n, __s); \
+ __p; \
+ }))
+
+#else
+
+/* Unoptimised version: always call the _n() function. */
+
+#define _G_NEW(struct_type, n_structs, func) \
+ ((struct_type *) g_##func##_n ((n_structs), sizeof (struct_type)))
+#define _G_RENEW(struct_type, mem, n_structs, func) \
+ ((struct_type *) g_##func##_n (mem, (n_structs), sizeof (struct_type)))
+
+#endif
+
+/**
+ * g_new:
+ * @struct_type: the type of the elements to allocate
+ * @n_structs: the number of elements to allocate
+ *
+ * Allocates @n_structs elements of type @struct_type.
+ * The returned pointer is cast to a pointer to the given type.
+ * If @n_structs is 0 it returns %NULL.
+ * Care is taken to avoid overflow when calculating the size of the allocated block.
+ *
+ * Since the returned pointer is already casted to the right type,
+ * it is normally unnecessary to cast it explicitly, and doing
+ * so might hide memory allocation errors.
+ *
+ * Returns: a pointer to the allocated memory, cast to a pointer to @struct_type
+ */
+#define g_new(struct_type, n_structs) _G_NEW (struct_type, n_structs, malloc)
+/**
+ * g_new0:
+ * @struct_type: the type of the elements to allocate.
+ * @n_structs: the number of elements to allocate.
+ *
+ * Allocates @n_structs elements of type @struct_type, initialized to 0's.
+ * The returned pointer is cast to a pointer to the given type.
+ * If @n_structs is 0 it returns %NULL.
+ * Care is taken to avoid overflow when calculating the size of the allocated block.
+ *
+ * Since the returned pointer is already casted to the right type,
+ * it is normally unnecessary to cast it explicitly, and doing
+ * so might hide memory allocation errors.
+ *
+ * Returns: a pointer to the allocated memory, cast to a pointer to @struct_type.
+ */
+#define g_new0(struct_type, n_structs) _G_NEW (struct_type, n_structs, malloc0)
+/**
+ * g_renew:
+ * @struct_type: the type of the elements to allocate
+ * @mem: the currently allocated memory
+ * @n_structs: the number of elements to allocate
+ *
+ * Reallocates the memory pointed to by @mem, so that it now has space for
+ * @n_structs elements of type @struct_type. It returns the new address of
+ * the memory, which may have been moved.
+ * Care is taken to avoid overflow when calculating the size of the allocated block.
+ *
+ * Returns: a pointer to the new allocated memory, cast to a pointer to @struct_type
+ */
+#define g_renew(struct_type, mem, n_structs) _G_RENEW (struct_type, mem, n_structs, realloc)
+/**
+ * g_try_new:
+ * @struct_type: the type of the elements to allocate
+ * @n_structs: the number of elements to allocate
+ *
+ * Attempts to allocate @n_structs elements of type @struct_type, and returns
+ * %NULL on failure. Contrast with g_new(), which aborts the program on failure.
+ * The returned pointer is cast to a pointer to the given type.
+ * The function returns %NULL when @n_structs is 0 of if an overflow occurs.
+ *
+ * Since: 2.8
+ * Returns: a pointer to the allocated memory, cast to a pointer to @struct_type
+ */
+#define g_try_new(struct_type, n_structs) _G_NEW (struct_type, n_structs, try_malloc)
+/**
+ * g_try_new0:
+ * @struct_type: the type of the elements to allocate
+ * @n_structs: the number of elements to allocate
+ *
+ * Attempts to allocate @n_structs elements of type @struct_type, initialized
+ * to 0's, and returns %NULL on failure. Contrast with g_new0(), which aborts
+ * the program on failure.
+ * The returned pointer is cast to a pointer to the given type.
+ * The function returns %NULL when @n_structs is 0 of if an overflow occurs.
+ *
+ * Since: 2.8
+ * Returns: a pointer to the allocated memory, cast to a pointer to @struct_type
+ */
+#define g_try_new0(struct_type, n_structs) _G_NEW (struct_type, n_structs, try_malloc0)
+/**
+ * g_try_renew:
+ * @struct_type: the type of the elements to allocate
+ * @mem: the currently allocated memory
+ * @n_structs: the number of elements to allocate
+ *
+ * Attempts to reallocate the memory pointed to by @mem, so that it now has
+ * space for @n_structs elements of type @struct_type, and returns %NULL on
+ * failure. Contrast with g_renew(), which aborts the program on failure.
+ * It returns the new address of the memory, which may have been moved.
+ * The function returns %NULL if an overflow occurs.
+ *
+ * Since: 2.8
+ * Returns: a pointer to the new allocated memory, cast to a pointer to @struct_type
+ */
+#define g_try_renew(struct_type, mem, n_structs) _G_RENEW (struct_type, mem, n_structs, try_realloc)
+
+
+/* Memory allocation virtualization for debugging purposes
+ * g_mem_set_vtable() has to be the very first GLib function called
+ * if being used
+ */
+struct _GMemVTable {
+ gpointer (*malloc) (gsize n_bytes);
+ gpointer (*realloc) (gpointer mem,
+ gsize n_bytes);
+ void (*free) (gpointer mem);
+ /* optional; set to NULL if not used ! */
+ gpointer (*calloc) (gsize n_blocks,
+ gsize n_block_bytes);
+ gpointer (*try_malloc) (gsize n_bytes);
+ gpointer (*try_realloc) (gpointer mem,
+ gsize n_bytes);
+};
+void g_mem_set_vtable (GMemVTable *vtable);
+gboolean g_mem_is_system_malloc (void);
+
+GLIB_VAR gboolean g_mem_gc_friendly;
+
+/* Memory profiler and checker, has to be enabled via g_mem_set_vtable()
+ */
+GLIB_VAR GMemVTable *glib_mem_profiler_table;
+void g_mem_profile (void);
+
+
+/* deprecated memchunks and allocators */
+#if !defined (G_DISABLE_DEPRECATED) || defined (GTK_COMPILATION) || defined (GDK_COMPILATION)
+typedef struct _GAllocator GAllocator;
+typedef struct _GMemChunk GMemChunk;
+#define g_mem_chunk_create(type, pre_alloc, alloc_type) ( \
+ g_mem_chunk_new (#type " mem chunks (" #pre_alloc ")", \
+ sizeof (type), \
+ sizeof (type) * (pre_alloc), \
+ (alloc_type)) \
+)
+#define g_chunk_new(type, chunk) ( \
+ (type *) g_mem_chunk_alloc (chunk) \
+)
+#define g_chunk_new0(type, chunk) ( \
+ (type *) g_mem_chunk_alloc0 (chunk) \
+)
+#define g_chunk_free(mem, mem_chunk) G_STMT_START { \
+ g_mem_chunk_free ((mem_chunk), (mem)); \
+} G_STMT_END
+#define G_ALLOC_ONLY 1
+#define G_ALLOC_AND_FREE 2
+GMemChunk* g_mem_chunk_new (const gchar *name,
+ gint atom_size,
+ gsize area_size,
+ gint type);
+void g_mem_chunk_destroy (GMemChunk *mem_chunk);
+gpointer g_mem_chunk_alloc (GMemChunk *mem_chunk);
+gpointer g_mem_chunk_alloc0 (GMemChunk *mem_chunk);
+void g_mem_chunk_free (GMemChunk *mem_chunk,
+ gpointer mem);
+void g_mem_chunk_clean (GMemChunk *mem_chunk);
+void g_mem_chunk_reset (GMemChunk *mem_chunk);
+void g_mem_chunk_print (GMemChunk *mem_chunk);
+void g_mem_chunk_info (void);
+void g_blow_chunks (void);
+GAllocator*g_allocator_new (const gchar *name,
+ guint n_preallocs);
+void g_allocator_free (GAllocator *allocator);
+#define G_ALLOCATOR_LIST (1)
+#define G_ALLOCATOR_SLIST (2)
+#define G_ALLOCATOR_NODE (3)
+#endif /* G_DISABLE_DEPRECATED */
+
+G_END_DECLS
+
+#endif /* __G_MEM_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gmessages.h b/protocols/Sametime/src/glib/include/glib/gmessages.h
new file mode 100644
index 0000000000..9acaec6375
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gmessages.h
@@ -0,0 +1,343 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_MESSAGES_H__
+#define __G_MESSAGES_H__
+
+#include <stdarg.h>
+#include <glib/gtypes.h>
+#include <glib/gmacros.h>
+
+/* Suppress warnings when GCC is in -pedantic mode and not -std=c99
+ */
+#if (__GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96))
+#pragma GCC system_header
+#endif
+
+G_BEGIN_DECLS
+
+/* calculate a string size, guaranteed to fit format + args.
+ */
+gsize g_printf_string_upper_bound (const gchar* format,
+ va_list args);
+
+/* Log level shift offset for user defined
+ * log levels (0-7 are used by GLib).
+ */
+#define G_LOG_LEVEL_USER_SHIFT (8)
+
+/* Glib log levels and flags.
+ */
+typedef enum
+{
+ /* log flags */
+ G_LOG_FLAG_RECURSION = 1 << 0,
+ G_LOG_FLAG_FATAL = 1 << 1,
+
+ /* GLib log levels */
+ G_LOG_LEVEL_ERROR = 1 << 2, /* always fatal */
+ G_LOG_LEVEL_CRITICAL = 1 << 3,
+ G_LOG_LEVEL_WARNING = 1 << 4,
+ G_LOG_LEVEL_MESSAGE = 1 << 5,
+ G_LOG_LEVEL_INFO = 1 << 6,
+ G_LOG_LEVEL_DEBUG = 1 << 7,
+
+ G_LOG_LEVEL_MASK = ~(G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL)
+} GLogLevelFlags;
+
+/* GLib log levels that are considered fatal by default */
+#define G_LOG_FATAL_MASK (G_LOG_FLAG_RECURSION | G_LOG_LEVEL_ERROR)
+
+typedef void (*GLogFunc) (const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *message,
+ gpointer user_data);
+
+/* Logging mechanism
+ */
+guint g_log_set_handler (const gchar *log_domain,
+ GLogLevelFlags log_levels,
+ GLogFunc log_func,
+ gpointer user_data);
+void g_log_remove_handler (const gchar *log_domain,
+ guint handler_id);
+void g_log_default_handler (const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *message,
+ gpointer unused_data);
+GLogFunc g_log_set_default_handler (GLogFunc log_func,
+ gpointer user_data);
+void g_log (const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *format,
+ ...) G_GNUC_PRINTF (3, 4);
+void g_logv (const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *format,
+ va_list args);
+GLogLevelFlags g_log_set_fatal_mask (const gchar *log_domain,
+ GLogLevelFlags fatal_mask);
+GLogLevelFlags g_log_set_always_fatal (GLogLevelFlags fatal_mask);
+
+/* internal */
+G_GNUC_INTERNAL void _g_log_fallback_handler (const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *message,
+ gpointer unused_data);
+
+/* Internal functions, used to implement the following macros */
+void g_return_if_fail_warning (const char *log_domain,
+ const char *pretty_function,
+ const char *expression);
+void g_warn_message (const char *domain,
+ const char *file,
+ int line,
+ const char *func,
+ const char *warnexpr);
+#ifndef G_DISABLE_DEPRECATED
+void g_assert_warning (const char *log_domain,
+ const char *file,
+ const int line,
+ const char *pretty_function,
+ const char *expression) G_GNUC_NORETURN;
+#endif /* !G_DISABLE_DEPRECATED */
+
+
+#ifndef G_LOG_DOMAIN
+#define G_LOG_DOMAIN ((gchar*) 0)
+#endif /* G_LOG_DOMAIN */
+#ifdef G_HAVE_ISO_VARARGS
+/* for(;;) ; so that GCC knows that control doesn't go past g_error().
+ * Put space before ending semicolon to avoid C++ build warnings.
+ */
+#define g_error(...) G_STMT_START { \
+ g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_ERROR, \
+ __VA_ARGS__); \
+ for (;;) ; \
+ } G_STMT_END
+
+#define g_message(...) g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_MESSAGE, \
+ __VA_ARGS__)
+#define g_critical(...) g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_CRITICAL, \
+ __VA_ARGS__)
+#define g_warning(...) g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_WARNING, \
+ __VA_ARGS__)
+#define g_debug(...) g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_DEBUG, \
+ __VA_ARGS__)
+#elif defined(G_HAVE_GNUC_VARARGS)
+#define g_error(format...) G_STMT_START { \
+ g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_ERROR, \
+ format); \
+ for (;;) ; \
+ } G_STMT_END
+
+#define g_message(format...) g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_MESSAGE, \
+ format)
+#define g_critical(format...) g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_CRITICAL, \
+ format)
+#define g_warning(format...) g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_WARNING, \
+ format)
+#define g_debug(format...) g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_DEBUG, \
+ format)
+#else /* no varargs macros */
+static void
+g_error (const gchar *format,
+ ...)
+{
+ va_list args;
+ va_start (args, format);
+ g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, format, args);
+ va_end (args);
+
+ for(;;) ;
+}
+static void
+g_message (const gchar *format,
+ ...)
+{
+ va_list args;
+ va_start (args, format);
+ g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, format, args);
+ va_end (args);
+}
+static void
+g_critical (const gchar *format,
+ ...)
+{
+ va_list args;
+ va_start (args, format);
+ g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, format, args);
+ va_end (args);
+}
+static void
+g_warning (const gchar *format,
+ ...)
+{
+ va_list args;
+ va_start (args, format);
+ g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, format, args);
+ va_end (args);
+}
+static void
+g_debug (const gchar *format,
+ ...)
+{
+ va_list args;
+ va_start (args, format);
+ g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format, args);
+ va_end (args);
+}
+#endif /* !__GNUC__ */
+
+typedef void (*GPrintFunc) (const gchar *string);
+void g_print (const gchar *format,
+ ...) G_GNUC_PRINTF (1, 2);
+GPrintFunc g_set_print_handler (GPrintFunc func);
+void g_printerr (const gchar *format,
+ ...) G_GNUC_PRINTF (1, 2);
+GPrintFunc g_set_printerr_handler (GPrintFunc func);
+
+
+/* Provide macros for graceful error handling.
+ * The "return" macros will return from the current function.
+ * Two different definitions are given for the macros in
+ * order to support gcc's __PRETTY_FUNCTION__ capability.
+ */
+
+#define g_warn_if_reached() do { g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, NULL); } while (0)
+#define g_warn_if_fail(expr) do { if G_LIKELY (expr) ; else \
+ g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, #expr); } while (0)
+
+#ifdef G_DISABLE_CHECKS
+
+#define g_return_if_fail(expr) G_STMT_START{ (void)0; }G_STMT_END
+#define g_return_val_if_fail(expr,val) G_STMT_START{ (void)0; }G_STMT_END
+#define g_return_if_reached() G_STMT_START{ return; }G_STMT_END
+#define g_return_val_if_reached(val) G_STMT_START{ return (val); }G_STMT_END
+
+#else /* !G_DISABLE_CHECKS */
+
+#ifdef __GNUC__
+
+#define g_return_if_fail(expr) G_STMT_START{ \
+ if G_LIKELY(expr) { } else \
+ { \
+ g_return_if_fail_warning (G_LOG_DOMAIN, \
+ __PRETTY_FUNCTION__, \
+ #expr); \
+ return; \
+ }; }G_STMT_END
+
+#define g_return_val_if_fail(expr,val) G_STMT_START{ \
+ if G_LIKELY(expr) { } else \
+ { \
+ g_return_if_fail_warning (G_LOG_DOMAIN, \
+ __PRETTY_FUNCTION__, \
+ #expr); \
+ return (val); \
+ }; }G_STMT_END
+
+#define g_return_if_reached() G_STMT_START{ \
+ g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_CRITICAL, \
+ "file %s: line %d (%s): should not be reached", \
+ __FILE__, \
+ __LINE__, \
+ __PRETTY_FUNCTION__); \
+ return; }G_STMT_END
+
+#define g_return_val_if_reached(val) G_STMT_START{ \
+ g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_CRITICAL, \
+ "file %s: line %d (%s): should not be reached", \
+ __FILE__, \
+ __LINE__, \
+ __PRETTY_FUNCTION__); \
+ return (val); }G_STMT_END
+
+#else /* !__GNUC__ */
+
+#define g_return_if_fail(expr) G_STMT_START{ \
+ if (expr) { } else \
+ { \
+ g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_CRITICAL, \
+ "file %s: line %d: assertion `%s' failed", \
+ __FILE__, \
+ __LINE__, \
+ #expr); \
+ return; \
+ }; }G_STMT_END
+
+#define g_return_val_if_fail(expr, val) G_STMT_START{ \
+ if (expr) { } else \
+ { \
+ g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_CRITICAL, \
+ "file %s: line %d: assertion `%s' failed", \
+ __FILE__, \
+ __LINE__, \
+ #expr); \
+ return (val); \
+ }; }G_STMT_END
+
+#define g_return_if_reached() G_STMT_START{ \
+ g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_CRITICAL, \
+ "file %s: line %d: should not be reached", \
+ __FILE__, \
+ __LINE__); \
+ return; }G_STMT_END
+
+#define g_return_val_if_reached(val) G_STMT_START{ \
+ g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_CRITICAL, \
+ "file %s: line %d: should not be reached", \
+ __FILE__, \
+ __LINE__); \
+ return (val); }G_STMT_END
+
+#endif /* !__GNUC__ */
+
+#endif /* !G_DISABLE_CHECKS */
+
+G_END_DECLS
+
+#endif /* __G_MESSAGES_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gnode.h b/protocols/Sametime/src/glib/include/glib/gnode.h
new file mode 100644
index 0000000000..205d47c763
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gnode.h
@@ -0,0 +1,290 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_NODE_H__
+#define __G_NODE_H__
+
+#include <glib/gmem.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GNode GNode;
+
+/* Tree traverse flags */
+typedef enum
+{
+ G_TRAVERSE_LEAVES = 1 << 0,
+ G_TRAVERSE_NON_LEAVES = 1 << 1,
+ G_TRAVERSE_ALL = G_TRAVERSE_LEAVES | G_TRAVERSE_NON_LEAVES,
+ G_TRAVERSE_MASK = 0x03,
+ G_TRAVERSE_LEAFS = G_TRAVERSE_LEAVES,
+ G_TRAVERSE_NON_LEAFS = G_TRAVERSE_NON_LEAVES
+} GTraverseFlags;
+
+/* Tree traverse orders */
+typedef enum
+{
+ G_IN_ORDER,
+ G_PRE_ORDER,
+ G_POST_ORDER,
+ G_LEVEL_ORDER
+} GTraverseType;
+
+typedef gboolean (*GNodeTraverseFunc) (GNode *node,
+ gpointer data);
+typedef void (*GNodeForeachFunc) (GNode *node,
+ gpointer data);
+
+/**
+ * GCopyFunc:
+ * @src: A pointer to the data which should be copied
+ * @data: Additional data
+ *
+ * A function of this signature is used to copy the node data
+ * when doing a deep-copy of a tree.
+ *
+ * Returns: A pointer to the copy
+ *
+ * Since: 2.4
+ */
+typedef gpointer (*GCopyFunc) (gconstpointer src,
+ gpointer data);
+
+/* N-way tree implementation
+ */
+struct _GNode
+{
+ gpointer data;
+ GNode *next;
+ GNode *prev;
+ GNode *parent;
+ GNode *children;
+};
+
+/**
+ * G_NODE_IS_ROOT:
+ * @node: a #GNode
+ *
+ * Returns %TRUE if a #GNode is the root of a tree.
+ *
+ * Returns: %TRUE if the #GNode is the root of a tree
+ * (i.e. it has no parent or siblings)
+ */
+#define G_NODE_IS_ROOT(node) (((GNode*) (node))->parent == NULL && \
+ ((GNode*) (node))->prev == NULL && \
+ ((GNode*) (node))->next == NULL)
+
+/**
+ * G_NODE_IS_LEAF:
+ * @node: a #GNode
+ *
+ * Returns %TRUE if a #GNode is a leaf node.
+ *
+ * Returns: %TRUE if the #GNode is a leaf node
+ * (i.e. it has no children)
+ */
+#define G_NODE_IS_LEAF(node) (((GNode*) (node))->children == NULL)
+
+GNode* g_node_new (gpointer data);
+void g_node_destroy (GNode *root);
+void g_node_unlink (GNode *node);
+GNode* g_node_copy_deep (GNode *node,
+ GCopyFunc copy_func,
+ gpointer data);
+GNode* g_node_copy (GNode *node);
+GNode* g_node_insert (GNode *parent,
+ gint position,
+ GNode *node);
+GNode* g_node_insert_before (GNode *parent,
+ GNode *sibling,
+ GNode *node);
+GNode* g_node_insert_after (GNode *parent,
+ GNode *sibling,
+ GNode *node);
+GNode* g_node_prepend (GNode *parent,
+ GNode *node);
+guint g_node_n_nodes (GNode *root,
+ GTraverseFlags flags);
+GNode* g_node_get_root (GNode *node);
+gboolean g_node_is_ancestor (GNode *node,
+ GNode *descendant);
+guint g_node_depth (GNode *node);
+GNode* g_node_find (GNode *root,
+ GTraverseType order,
+ GTraverseFlags flags,
+ gpointer data);
+
+/* convenience macros */
+/**
+ * g_node_append:
+ * @parent: the #GNode to place the new #GNode under
+ * @node: the #GNode to insert
+ *
+ * Inserts a #GNode as the last child of the given parent.
+ *
+ * Returns: the inserted #GNode
+ */
+#define g_node_append(parent, node) \
+ g_node_insert_before ((parent), NULL, (node))
+
+/**
+ * g_node_insert_data:
+ * @parent: the #GNode to place the new #GNode under
+ * @position: the position to place the new #GNode at. If position is -1,
+ * the new #GNode is inserted as the last child of @parent
+ * @data: the data for the new #GNode
+ *
+ * Inserts a new #GNode at the given position.
+ *
+ * Returns: the new #GNode
+ */
+#define g_node_insert_data(parent, position, data) \
+ g_node_insert ((parent), (position), g_node_new (data))
+
+/**
+ * g_node_insert_data_before:
+ * @parent: the #GNode to place the new #GNode under
+ * @sibling: the sibling #GNode to place the new #GNode before
+ * @data: the data for the new #GNode
+ *
+ * Inserts a new #GNode before the given sibling.
+ *
+ * Returns: the new #GNode
+ */
+#define g_node_insert_data_before(parent, sibling, data) \
+ g_node_insert_before ((parent), (sibling), g_node_new (data))
+
+/**
+ * g_node_prepend_data:
+ * @parent: the #GNode to place the new #GNode under
+ * @data: the data for the new #GNode
+ *
+ * Inserts a new #GNode as the first child of the given parent.
+ *
+ * Returns: the new #GNode
+ */
+#define g_node_prepend_data(parent, data) \
+ g_node_prepend ((parent), g_node_new (data))
+
+/**
+ * g_node_append_data:
+ * @parent: the #GNode to place the new #GNode under
+ * @data: the data for the new #GNode
+ *
+ * Inserts a new #GNode as the last child of the given parent.
+ *
+ * Returns: the new #GNode
+ */
+#define g_node_append_data(parent, data) \
+ g_node_insert_before ((parent), NULL, g_node_new (data))
+
+/* traversal function, assumes that `node' is root
+ * (only traverses `node' and its subtree).
+ * this function is just a high level interface to
+ * low level traversal functions, optimized for speed.
+ */
+void g_node_traverse (GNode *root,
+ GTraverseType order,
+ GTraverseFlags flags,
+ gint max_depth,
+ GNodeTraverseFunc func,
+ gpointer data);
+
+/* return the maximum tree height starting with `node', this is an expensive
+ * operation, since we need to visit all nodes. this could be shortened by
+ * adding `guint height' to struct _GNode, but then again, this is not very
+ * often needed, and would make g_node_insert() more time consuming.
+ */
+guint g_node_max_height (GNode *root);
+
+void g_node_children_foreach (GNode *node,
+ GTraverseFlags flags,
+ GNodeForeachFunc func,
+ gpointer data);
+void g_node_reverse_children (GNode *node);
+guint g_node_n_children (GNode *node);
+GNode* g_node_nth_child (GNode *node,
+ guint n);
+GNode* g_node_last_child (GNode *node);
+GNode* g_node_find_child (GNode *node,
+ GTraverseFlags flags,
+ gpointer data);
+gint g_node_child_position (GNode *node,
+ GNode *child);
+gint g_node_child_index (GNode *node,
+ gpointer data);
+
+GNode* g_node_first_sibling (GNode *node);
+GNode* g_node_last_sibling (GNode *node);
+
+/**
+ * g_node_prev_sibling:
+ * @node: a #GNode
+ *
+ * Gets the previous sibling of a #GNode.
+ *
+ * Returns: the previous sibling of @node, or %NULL if @node is the first
+ * node or %NULL
+ */
+#define g_node_prev_sibling(node) ((node) ? \
+ ((GNode*) (node))->prev : NULL)
+
+/**
+ * g_node_next_sibling:
+ * @node: a #GNode
+ *
+ * Gets the next sibling of a #GNode.
+ *
+ * Returns: the next sibling of @node, or %NULL if @node is the last node
+ * or %NULL
+ */
+#define g_node_next_sibling(node) ((node) ? \
+ ((GNode*) (node))->next : NULL)
+
+/**
+ * g_node_first_child:
+ * @node: a #GNode
+ *
+ * Gets the first child of a #GNode.
+ *
+ * Returns: the first child of @node, or %NULL if @node is %NULL
+ * or has no children
+ */
+#define g_node_first_child(node) ((node) ? \
+ ((GNode*) (node))->children : NULL)
+
+#ifndef G_DISABLE_DEPRECATED
+void g_node_push_allocator (gpointer dummy);
+void g_node_pop_allocator (void);
+#endif
+
+G_END_DECLS
+
+#endif /* __G_NODE_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/goption.h b/protocols/Sametime/src/glib/include/glib/goption.h
new file mode 100644
index 0000000000..557d8f7130
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/goption.h
@@ -0,0 +1,370 @@
+/* goption.h - Option parser
+ *
+ * Copyright (C) 2004 Anders Carlsson <andersca@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_OPTION_H__
+#define __G_OPTION_H__
+
+#include <glib/gerror.h>
+#include <glib/gquark.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GOptionContext:
+ *
+ * A <structname>GOptionContext</structname> struct defines which options
+ * are accepted by the commandline option parser. The struct has only private
+ * fields and should not be directly accessed.
+ */
+typedef struct _GOptionContext GOptionContext;
+
+/**
+ * GOptionGroup:
+ *
+ * A <structname>GOptionGroup</structname> struct defines the options in a single
+ * group. The struct has only private fields and should not be directly accessed.
+ *
+ * All options in a group share the same translation function. Libraries which
+ * need to parse commandline options are expected to provide a function for
+ * getting a <structname>GOptionGroup</structname> holding their options, which
+ * the application can then add to its #GOptionContext.
+ */
+typedef struct _GOptionGroup GOptionGroup;
+typedef struct _GOptionEntry GOptionEntry;
+
+/**
+ * GOptionFlags:
+ * @G_OPTION_FLAG_HIDDEN: The option doesn't appear in <option>--help</option>
+ * output.
+ * @G_OPTION_FLAG_IN_MAIN: The option appears in the main section of the
+ * <option>--help</option> output, even if it is defined in a group.
+ * @G_OPTION_FLAG_REVERSE: For options of the %G_OPTION_ARG_NONE kind, this flag
+ * indicates that the sense of the option is reversed.
+ * @G_OPTION_FLAG_NO_ARG: For options of the %G_OPTION_ARG_CALLBACK kind,
+ * this flag indicates that the callback does not take any argument
+ * (like a %G_OPTION_ARG_NONE option). Since 2.8
+ * @G_OPTION_FLAG_FILENAME: For options of the %G_OPTION_ARG_CALLBACK
+ * kind, this flag indicates that the argument should be passed to the
+ * callback in the GLib filename encoding rather than UTF-8. Since 2.8
+ * @G_OPTION_FLAG_OPTIONAL_ARG: For options of the %G_OPTION_ARG_CALLBACK
+ * kind, this flag indicates that the argument supply is optional. If no argument
+ * is given then data of %GOptionParseFunc will be set to NULL. Since 2.8
+ * @G_OPTION_FLAG_NOALIAS: This flag turns off the automatic conflict resolution
+ * which prefixes long option names with <literal>groupname-</literal> if
+ * there is a conflict. This option should only be used in situations where
+ * aliasing is necessary to model some legacy commandline interface. It is
+ * not safe to use this option, unless all option groups are under your
+ * direct control. Since 2.8.
+ *
+ * Flags which modify individual options.
+ */
+typedef enum
+{
+ G_OPTION_FLAG_HIDDEN = 1 << 0,
+ G_OPTION_FLAG_IN_MAIN = 1 << 1,
+ G_OPTION_FLAG_REVERSE = 1 << 2,
+ G_OPTION_FLAG_NO_ARG = 1 << 3,
+ G_OPTION_FLAG_FILENAME = 1 << 4,
+ G_OPTION_FLAG_OPTIONAL_ARG = 1 << 5,
+ G_OPTION_FLAG_NOALIAS = 1 << 6
+} GOptionFlags;
+
+/**
+ * GOptionArg:
+ * @G_OPTION_ARG_NONE: No extra argument. This is useful for simple flags.
+ * @G_OPTION_ARG_STRING: The option takes a string argument.
+ * @G_OPTION_ARG_INT: The option takes an integer argument.
+ * @G_OPTION_ARG_CALLBACK: The option provides a callback to parse the
+ * extra argument.
+ * @G_OPTION_ARG_FILENAME: The option takes a filename as argument.
+ * @G_OPTION_ARG_STRING_ARRAY: The option takes a string argument, multiple
+ * uses of the option are collected into an array of strings.
+ * @G_OPTION_ARG_FILENAME_ARRAY: The option takes a filename as argument,
+ * multiple uses of the option are collected into an array of strings.
+ * @G_OPTION_ARG_DOUBLE: The option takes a double argument. The argument
+ * can be formatted either for the user's locale or for the "C" locale. Since 2.12
+ * @G_OPTION_ARG_INT64: The option takes a 64-bit integer. Like %G_OPTION_ARG_INT
+ * but for larger numbers. The number can be in decimal base, or in hexadecimal
+ * (when prefixed with <literal>0x</literal>, for example, <literal>0xffffffff</literal>).
+ * Since 2.12
+ *
+ * The #GOptionArg enum values determine which type of extra argument the
+ * options expect to find. If an option expects an extra argument, it
+ * can be specified in several ways; with a short option:
+ * <option>-x arg</option>, with a long option: <option>--name arg</option>
+ * or combined in a single argument: <option>--name=arg</option>.
+ */
+typedef enum
+{
+ G_OPTION_ARG_NONE,
+ G_OPTION_ARG_STRING,
+ G_OPTION_ARG_INT,
+ G_OPTION_ARG_CALLBACK,
+ G_OPTION_ARG_FILENAME,
+ G_OPTION_ARG_STRING_ARRAY,
+ G_OPTION_ARG_FILENAME_ARRAY,
+ G_OPTION_ARG_DOUBLE,
+ G_OPTION_ARG_INT64
+} GOptionArg;
+
+/**
+ * GOptionArgFunc:
+ * @option_name: The name of the option being parsed. This will be either a
+ * single dash followed by a single letter (for a short name) or two dashes
+ * followed by a long option name.
+ * @value: The value to be parsed.
+ * @data: User data added to the #GOptionGroup containing the option when it
+ * was created with g_option_group_new()
+ * @error: A return location for errors. The error code %G_OPTION_ERROR_FAILED
+ * is intended to be used for errors in #GOptionArgFunc callbacks.
+ *
+ * The type of function to be passed as callback for %G_OPTION_ARG_CALLBACK
+ * options.
+ *
+ * Returns: %TRUE if the option was successfully parsed, %FALSE if an error
+ * occurred, in which case @error should be set with g_set_error()
+ */
+typedef gboolean (*GOptionArgFunc) (const gchar *option_name,
+ const gchar *value,
+ gpointer data,
+ GError **error);
+
+/**
+ * GOptionParseFunc:
+ * @context: The active #GOptionContext
+ * @group: The group to which the function belongs
+ * @data: User data added to the #GOptionGroup containing the option when it
+ * was created with g_option_group_new()
+ * @error: A return location for error details
+ *
+ * The type of function that can be called before and after parsing.
+ *
+ * Returns: %TRUE if the function completed successfully, %FALSE if an error
+ * occurred, in which case @error should be set with g_set_error()
+ */
+typedef gboolean (*GOptionParseFunc) (GOptionContext *context,
+ GOptionGroup *group,
+ gpointer data,
+ GError **error);
+
+/**
+ * GOptionErrorFunc:
+ * @context: The active #GOptionContext
+ * @group: The group to which the function belongs
+ * @data: User data added to the #GOptionGroup containing the option when it
+ * was created with g_option_group_new()
+ * @error: The #GError containing details about the parse error
+ *
+ * The type of function to be used as callback when a parse error occurs.
+ */
+typedef void (*GOptionErrorFunc) (GOptionContext *context,
+ GOptionGroup *group,
+ gpointer data,
+ GError **error);
+
+/**
+ * G_OPTION_ERROR:
+ *
+ * Error domain for option parsing. Errors in this domain will
+ * be from the #GOptionError enumeration. See #GError for information on
+ * error domains.
+ */
+#define G_OPTION_ERROR (g_option_error_quark ())
+
+/**
+ * GOptionError:
+ * @G_OPTION_ERROR_UNKNOWN_OPTION: An option was not known to the parser.
+ * This error will only be reported, if the parser hasn't been instructed
+ * to ignore unknown options, see g_option_context_set_ignore_unknown_options().
+ * @G_OPTION_ERROR_BAD_VALUE: A value couldn't be parsed.
+ * @G_OPTION_ERROR_FAILED: A #GOptionArgFunc callback failed.
+ *
+ * Error codes returned by option parsing.
+ */
+typedef enum
+{
+ G_OPTION_ERROR_UNKNOWN_OPTION,
+ G_OPTION_ERROR_BAD_VALUE,
+ G_OPTION_ERROR_FAILED
+} GOptionError;
+
+GQuark g_option_error_quark (void);
+
+/**
+ * GOptionEntry:
+ * @long_name: The long name of an option can be used to specify it
+ * in a commandline as --<replaceable>long_name</replaceable>. Every
+ * option must have a long name. To resolve conflicts if multiple
+ * option groups contain the same long name, it is also possible to
+ * specify the option as
+ * --<replaceable>groupname</replaceable>-<replaceable>long_name</replaceable>.
+ * @short_name: If an option has a short name, it can be specified
+ * -<replaceable>short_name</replaceable> in a commandline. @short_name must be
+ * a printable ASCII character different from '-', or zero if the option has no
+ * short name.
+ * @flags: Flags from #GOptionFlags.
+ * @arg: The type of the option, as a #GOptionArg.
+ * @arg_data: If the @arg type is %G_OPTION_ARG_CALLBACK, then @arg_data must
+ * point to a #GOptionArgFunc callback function, which will be called to handle
+ * the extra argument. Otherwise, @arg_data is a pointer to a location to store
+ * the value, the required type of the location depends on the @arg type:
+ * <variablelist>
+ * <varlistentry>
+ * <term>%G_OPTION_ARG_NONE</term>
+ * <listitem><para>%gboolean</para></listitem>
+ * </varlistentry>
+ * <varlistentry>
+ * <term>%G_OPTION_ARG_STRING</term>
+ * <listitem><para>%gchar*</para></listitem>
+ * </varlistentry>
+ * <varlistentry>
+ * <term>%G_OPTION_ARG_INT</term>
+ * <listitem><para>%gint</para></listitem>
+ * </varlistentry>
+ * <varlistentry>
+ * <term>%G_OPTION_ARG_FILENAME</term>
+ * <listitem><para>%gchar*</para></listitem>
+ * </varlistentry>
+ * <varlistentry>
+ * <term>%G_OPTION_ARG_STRING_ARRAY</term>
+ * <listitem><para>%gchar**</para></listitem>
+ * </varlistentry>
+ * <varlistentry>
+ * <term>%G_OPTION_ARG_FILENAME_ARRAY</term>
+ * <listitem><para>%gchar**</para></listitem>
+ * </varlistentry>
+ * <varlistentry>
+ * <term>%G_OPTION_ARG_DOUBLE</term>
+ * <listitem><para>%gdouble</para></listitem>
+ * </varlistentry>
+ * </variablelist>
+ * If @arg type is %G_OPTION_ARG_STRING or %G_OPTION_ARG_FILENAME the location
+ * will contain a newly allocated string if the option was given. That string
+ * needs to be freed by the callee using g_free(). Likewise if @arg type is
+ * %G_OPTION_ARG_STRING_ARRAY or %G_OPTION_ARG_FILENAME_ARRAY, the data should
+ * be freed using g_strfreev().
+ * @description: the description for the option in <option>--help</option>
+ * output. The @description is translated using the @translate_func of the
+ * group, see g_option_group_set_translation_domain().
+ * @arg_description: The placeholder to use for the extra argument parsed
+ * by the option in <option>--help</option>
+ * output. The @arg_description is translated using the @translate_func of the
+ * group, see g_option_group_set_translation_domain().
+ *
+ * A <structname>GOptionEntry</structname> defines a single option.
+ * To have an effect, they must be added to a #GOptionGroup with
+ * g_option_context_add_main_entries() or g_option_group_add_entries().
+ */
+struct _GOptionEntry
+{
+ const gchar *long_name;
+ gchar short_name;
+ gint flags;
+
+ GOptionArg arg;
+ gpointer arg_data;
+
+ const gchar *description;
+ const gchar *arg_description;
+};
+
+/**
+ * G_OPTION_REMAINING:
+ *
+ * If a long option in the main group has this name, it is not treated as a
+ * regular option. Instead it collects all non-option arguments which would
+ * otherwise be left in <literal>argv</literal>. The option must be of type
+ * %G_OPTION_ARG_CALLBACK, %G_OPTION_ARG_STRING_ARRAY
+ * or %G_OPTION_ARG_FILENAME_ARRAY.
+ *
+ *
+ * Using #G_OPTION_REMAINING instead of simply scanning <literal>argv</literal>
+ * for leftover arguments has the advantage that GOption takes care of
+ * necessary encoding conversions for strings or filenames.
+ *
+ * Since: 2.6
+ */
+#define G_OPTION_REMAINING ""
+
+GOptionContext *g_option_context_new (const gchar *parameter_string);
+void g_option_context_set_summary (GOptionContext *context,
+ const gchar *summary);
+G_CONST_RETURN gchar *g_option_context_get_summary (GOptionContext *context);
+void g_option_context_set_description (GOptionContext *context,
+ const gchar *description);
+G_CONST_RETURN gchar *g_option_context_get_description (GOptionContext *context);
+void g_option_context_free (GOptionContext *context);
+void g_option_context_set_help_enabled (GOptionContext *context,
+ gboolean help_enabled);
+gboolean g_option_context_get_help_enabled (GOptionContext *context);
+void g_option_context_set_ignore_unknown_options (GOptionContext *context,
+ gboolean ignore_unknown);
+gboolean g_option_context_get_ignore_unknown_options (GOptionContext *context);
+
+void g_option_context_add_main_entries (GOptionContext *context,
+ const GOptionEntry *entries,
+ const gchar *translation_domain);
+gboolean g_option_context_parse (GOptionContext *context,
+ gint *argc,
+ gchar ***argv,
+ GError **error);
+void g_option_context_set_translate_func (GOptionContext *context,
+ GTranslateFunc func,
+ gpointer data,
+ GDestroyNotify destroy_notify);
+void g_option_context_set_translation_domain (GOptionContext *context,
+ const gchar *domain);
+
+void g_option_context_add_group (GOptionContext *context,
+ GOptionGroup *group);
+void g_option_context_set_main_group (GOptionContext *context,
+ GOptionGroup *group);
+GOptionGroup *g_option_context_get_main_group (GOptionContext *context);
+gchar *g_option_context_get_help (GOptionContext *context,
+ gboolean main_help,
+ GOptionGroup *group);
+
+GOptionGroup *g_option_group_new (const gchar *name,
+ const gchar *description,
+ const gchar *help_description,
+ gpointer user_data,
+ GDestroyNotify destroy);
+void g_option_group_set_parse_hooks (GOptionGroup *group,
+ GOptionParseFunc pre_parse_func,
+ GOptionParseFunc post_parse_func);
+void g_option_group_set_error_hook (GOptionGroup *group,
+ GOptionErrorFunc error_func);
+void g_option_group_free (GOptionGroup *group);
+void g_option_group_add_entries (GOptionGroup *group,
+ const GOptionEntry *entries);
+void g_option_group_set_translate_func (GOptionGroup *group,
+ GTranslateFunc func,
+ gpointer data,
+ GDestroyNotify destroy_notify);
+void g_option_group_set_translation_domain (GOptionGroup *group,
+ const gchar *domain);
+
+G_END_DECLS
+
+#endif /* __G_OPTION_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gpattern.h b/protocols/Sametime/src/glib/include/glib/gpattern.h
new file mode 100644
index 0000000000..b653d713f0
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gpattern.h
@@ -0,0 +1,49 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997, 1999 Peter Mattis, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_PATTERN_H__
+#define __G_PATTERN_H__
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _GPatternSpec GPatternSpec;
+
+GPatternSpec* g_pattern_spec_new (const gchar *pattern);
+void g_pattern_spec_free (GPatternSpec *pspec);
+gboolean g_pattern_spec_equal (GPatternSpec *pspec1,
+ GPatternSpec *pspec2);
+gboolean g_pattern_match (GPatternSpec *pspec,
+ guint string_length,
+ const gchar *string,
+ const gchar *string_reversed);
+gboolean g_pattern_match_string (GPatternSpec *pspec,
+ const gchar *string);
+gboolean g_pattern_match_simple (const gchar *pattern,
+ const gchar *string);
+
+G_END_DECLS
+
+#endif /* __G_PATTERN_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gpoll.h b/protocols/Sametime/src/glib/include/glib/gpoll.h
new file mode 100644
index 0000000000..cc79381a69
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gpoll.h
@@ -0,0 +1,117 @@
+/* gpoll.h - poll(2) support
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if !defined (__GLIB_H_INSIDE__) && !defined (__G_MAIN_H__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_POLL_H__
+#define __G_POLL_H__
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+/* Any definitions using GPollFD or GPollFunc are primarily
+ * for Unix and not guaranteed to be the compatible on all
+ * operating systems on which GLib runs. Right now, the
+ * GLib does use these functions on Win32 as well, but interprets
+ * them in a fairly different way than on Unix. If you use
+ * these definitions, you are should be prepared to recode
+ * for different operating systems.
+ *
+ * Note that on systems with a working poll(2), that function is used
+ * in place of g_poll(). Thus g_poll() must have the same signature as
+ * poll(), meaning GPollFD must have the same layout as struct pollfd.
+ *
+ *
+ * On Win32, the fd in a GPollFD should be Win32 HANDLE (*not* a file
+ * descriptor as provided by the C runtime) that can be used by
+ * MsgWaitForMultipleObjects. This does *not* include file handles
+ * from CreateFile, SOCKETs, nor pipe handles. (But you can use
+ * WSAEventSelect to signal events when a SOCKET is readable).
+ *
+ * On Win32, fd can also be the special value G_WIN32_MSG_HANDLE to
+ * indicate polling for messages.
+ *
+ * But note that G_WIN32_MSG_HANDLE GPollFDs should not be used by GDK
+ * (GTK) programs, as GDK itself wants to read messages and convert them
+ * to GDK events.
+ *
+ * So, unless you really know what you are doing, it's best not to try
+ * to use the main loop polling stuff for your own needs on
+ * Windows.
+ */
+typedef struct _GPollFD GPollFD;
+
+/**
+ * GPollFunc:
+ * @ufds: an array of #GPollFD elements
+ * @nfsd: the number of elements in @ufds
+ * @timeout_: the maximum time to wait for an event of the file descriptors.
+ * A negative value indicates an infinite timeout.
+ *
+ * Specifies the type of function passed to g_main_context_set_poll_func().
+ * The semantics of the function should match those of the poll() system call.
+ *
+ * Returns: the number of #GPollFD elements which have events or errors
+ * reported, or -1 if an error occurred.
+ */
+typedef gint (*GPollFunc) (GPollFD *ufds,
+ guint nfsd,
+ gint timeout_);
+
+/**
+ * GPollFD:
+ * @fd: the file descriptor to poll (or a <type>HANDLE</type> on Win32)
+ * @events: a bitwise combination from #GIOCondition, specifying which
+ * events should be polled for. Typically for reading from a file
+ * descriptor you would use %G_IO_IN | %G_IO_HUP | %G_IO_ERR, and
+ * for writing you would use %G_IO_OUT | %G_IO_ERR.
+ * @revents: a bitwise combination of flags from #GIOCondition, returned
+ * from the poll() function to indicate which events occurred.
+ */
+struct _GPollFD
+{
+#if defined (G_OS_WIN32) && GLIB_SIZEOF_VOID_P == 8
+ gint64 fd;
+#else
+ gint fd;
+#endif
+ gushort events;
+ gushort revents;
+};
+
+#ifdef G_OS_WIN32
+#if GLIB_SIZEOF_VOID_P == 8
+#define G_POLLFD_FORMAT "%#I64x"
+#else
+#define G_POLLFD_FORMAT "%#x"
+#endif
+#else
+#define G_POLLFD_FORMAT "%d"
+#endif
+
+gint g_poll (GPollFD *fds,
+ guint nfds,
+ gint timeout);
+
+G_END_DECLS
+
+#endif /* __G_POLL_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gprimes.h b/protocols/Sametime/src/glib/include/glib/gprimes.h
new file mode 100644
index 0000000000..af5728602b
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gprimes.h
@@ -0,0 +1,51 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_PRIMES_H__
+#define __G_PRIMES_H__
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+/* Prime numbers.
+ */
+
+/* This function returns prime numbers spaced by approximately 1.5-2.0
+ * and is for use in resizing data structures which prefer
+ * prime-valued sizes. The closest spaced prime function returns the
+ * next largest prime, or the highest it knows about which is about
+ * MAXINT/4.
+ */
+guint g_spaced_primes_closest (guint num) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __G_PRIMES_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gqsort.h b/protocols/Sametime/src/glib/include/glib/gqsort.h
new file mode 100644
index 0000000000..3a47a584ee
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gqsort.h
@@ -0,0 +1,46 @@
+ /* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_QSORT_H__
+#define __G_QSORT_H__
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+void g_qsort_with_data (gconstpointer pbase,
+ gint total_elems,
+ gsize size,
+ GCompareDataFunc compare_func,
+ gpointer user_data);
+
+G_END_DECLS
+
+#endif /* __G_QSORT_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gquark.h b/protocols/Sametime/src/glib/include/glib/gquark.h
new file mode 100644
index 0000000000..a0cbe2fd72
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gquark.h
@@ -0,0 +1,52 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_QUARK_H__
+#define __G_QUARK_H__
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+typedef guint32 GQuark;
+
+/* Quarks (string<->id association)
+ */
+GQuark g_quark_try_string (const gchar *string);
+GQuark g_quark_from_static_string (const gchar *string);
+GQuark g_quark_from_string (const gchar *string);
+G_CONST_RETURN gchar* g_quark_to_string (GQuark quark) G_GNUC_CONST;
+
+G_CONST_RETURN gchar* g_intern_string (const gchar *string);
+G_CONST_RETURN gchar* g_intern_static_string (const gchar *string);
+
+G_END_DECLS
+
+#endif /* __G_QUARK_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gqueue.h b/protocols/Sametime/src/glib/include/glib/gqueue.h
new file mode 100644
index 0000000000..e78488fb65
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gqueue.h
@@ -0,0 +1,127 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_QUEUE_H__
+#define __G_QUEUE_H__
+
+#include <glib/glist.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GQueue GQueue;
+
+struct _GQueue
+{
+ GList *head;
+ GList *tail;
+ guint length;
+};
+
+#define G_QUEUE_INIT { NULL, NULL, 0 }
+
+/* Queues
+ */
+GQueue* g_queue_new (void);
+void g_queue_free (GQueue *queue);
+void g_queue_init (GQueue *queue);
+void g_queue_clear (GQueue *queue);
+gboolean g_queue_is_empty (GQueue *queue);
+guint g_queue_get_length (GQueue *queue);
+void g_queue_reverse (GQueue *queue);
+GQueue * g_queue_copy (GQueue *queue);
+void g_queue_foreach (GQueue *queue,
+ GFunc func,
+ gpointer user_data);
+GList * g_queue_find (GQueue *queue,
+ gconstpointer data);
+GList * g_queue_find_custom (GQueue *queue,
+ gconstpointer data,
+ GCompareFunc func);
+void g_queue_sort (GQueue *queue,
+ GCompareDataFunc compare_func,
+ gpointer user_data);
+
+void g_queue_push_head (GQueue *queue,
+ gpointer data);
+void g_queue_push_tail (GQueue *queue,
+ gpointer data);
+void g_queue_push_nth (GQueue *queue,
+ gpointer data,
+ gint n);
+gpointer g_queue_pop_head (GQueue *queue);
+gpointer g_queue_pop_tail (GQueue *queue);
+gpointer g_queue_pop_nth (GQueue *queue,
+ guint n);
+gpointer g_queue_peek_head (GQueue *queue);
+gpointer g_queue_peek_tail (GQueue *queue);
+gpointer g_queue_peek_nth (GQueue *queue,
+ guint n);
+gint g_queue_index (GQueue *queue,
+ gconstpointer data);
+void g_queue_remove (GQueue *queue,
+ gconstpointer data);
+void g_queue_remove_all (GQueue *queue,
+ gconstpointer data);
+void g_queue_insert_before (GQueue *queue,
+ GList *sibling,
+ gpointer data);
+void g_queue_insert_after (GQueue *queue,
+ GList *sibling,
+ gpointer data);
+void g_queue_insert_sorted (GQueue *queue,
+ gpointer data,
+ GCompareDataFunc func,
+ gpointer user_data);
+
+void g_queue_push_head_link (GQueue *queue,
+ GList *link_);
+void g_queue_push_tail_link (GQueue *queue,
+ GList *link_);
+void g_queue_push_nth_link (GQueue *queue,
+ gint n,
+ GList *link_);
+GList* g_queue_pop_head_link (GQueue *queue);
+GList* g_queue_pop_tail_link (GQueue *queue);
+GList* g_queue_pop_nth_link (GQueue *queue,
+ guint n);
+GList* g_queue_peek_head_link (GQueue *queue);
+GList* g_queue_peek_tail_link (GQueue *queue);
+GList* g_queue_peek_nth_link (GQueue *queue,
+ guint n);
+gint g_queue_link_index (GQueue *queue,
+ GList *link_);
+void g_queue_unlink (GQueue *queue,
+ GList *link_);
+void g_queue_delete_link (GQueue *queue,
+ GList *link_);
+
+G_END_DECLS
+
+#endif /* __G_QUEUE_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/grand.h b/protocols/Sametime/src/glib/include/glib/grand.h
new file mode 100644
index 0000000000..07907dfc17
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/grand.h
@@ -0,0 +1,85 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_RAND_H__
+#define __G_RAND_H__
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GRand GRand;
+
+/* GRand - a good and fast random number generator: Mersenne Twister
+ * see http://www.math.keio.ac.jp/~matumoto/emt.html for more info.
+ * The range functions return a value in the intervall [begin, end).
+ * int -> [0..2^32-1]
+ * int_range -> [begin..end-1]
+ * double -> [0..1)
+ * double_range -> [begin..end)
+ */
+
+GRand* g_rand_new_with_seed (guint32 seed);
+GRand* g_rand_new_with_seed_array (const guint32 *seed,
+ guint seed_length);
+GRand* g_rand_new (void);
+void g_rand_free (GRand *rand_);
+GRand* g_rand_copy (GRand *rand_);
+void g_rand_set_seed (GRand *rand_,
+ guint32 seed);
+void g_rand_set_seed_array (GRand *rand_,
+ const guint32 *seed,
+ guint seed_length);
+
+#define g_rand_boolean(rand_) ((g_rand_int (rand_) & (1 << 15)) != 0)
+
+guint32 g_rand_int (GRand *rand_);
+gint32 g_rand_int_range (GRand *rand_,
+ gint32 begin,
+ gint32 end);
+gdouble g_rand_double (GRand *rand_);
+gdouble g_rand_double_range (GRand *rand_,
+ gdouble begin,
+ gdouble end);
+void g_random_set_seed (guint32 seed);
+
+#define g_random_boolean() ((g_random_int () & (1 << 15)) != 0)
+
+guint32 g_random_int (void);
+gint32 g_random_int_range (gint32 begin,
+ gint32 end);
+gdouble g_random_double (void);
+gdouble g_random_double_range (gdouble begin,
+ gdouble end);
+
+
+G_END_DECLS
+
+#endif /* __G_RAND_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gregex.h b/protocols/Sametime/src/glib/include/glib/gregex.h
new file mode 100644
index 0000000000..ce1b44a972
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gregex.h
@@ -0,0 +1,471 @@
+/* GRegex -- regular expression API wrapper around PCRE.
+ *
+ * Copyright (C) 1999, 2000 Scott Wimer
+ * Copyright (C) 2004, Matthias Clasen <mclasen@redhat.com>
+ * Copyright (C) 2005 - 2007, Marco Barisione <marco@barisione.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_REGEX_H__
+#define __G_REGEX_H__
+
+#include <glib/gerror.h>
+#include <glib/gstring.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GRegexError:
+ * @G_REGEX_ERROR_COMPILE: Compilation of the regular expression failed.
+ * @G_REGEX_ERROR_OPTIMIZE: Optimization of the regular expression failed.
+ * @G_REGEX_ERROR_REPLACE: Replacement failed due to an ill-formed replacement
+ * string.
+ * @G_REGEX_ERROR_MATCH: The match process failed.
+ * @G_REGEX_ERROR_INTERNAL: Internal error of the regular expression engine.
+ * Since 2.16
+ * @G_REGEX_ERROR_STRAY_BACKSLASH: "\\" at end of pattern. Since 2.16
+ * @G_REGEX_ERROR_MISSING_CONTROL_CHAR: "\\c" at end of pattern. Since 2.16
+ * @G_REGEX_ERROR_UNRECOGNIZED_ESCAPE: Unrecognized character follows "\\".
+ * Since 2.16
+ * @G_REGEX_ERROR_QUANTIFIERS_OUT_OF_ORDER: Numbers out of order in "{}"
+ * quantifier. Since 2.16
+ * @G_REGEX_ERROR_QUANTIFIER_TOO_BIG: Number too big in "{}" quantifier.
+ * Since 2.16
+ * @G_REGEX_ERROR_UNTERMINATED_CHARACTER_CLASS: Missing terminating "]" for
+ * character class. Since 2.16
+ * @G_REGEX_ERROR_INVALID_ESCAPE_IN_CHARACTER_CLASS: Invalid escape sequence
+ * in character class. Since 2.16
+ * @G_REGEX_ERROR_RANGE_OUT_OF_ORDER: Range out of order in character class.
+ * Since 2.16
+ * @G_REGEX_ERROR_NOTHING_TO_REPEAT: Nothing to repeat. Since 2.16
+ * @G_REGEX_ERROR_UNRECOGNIZED_CHARACTER: Unrecognized character after "(?",
+ * "(?&lt;" or "(?P". Since 2.16
+ * @G_REGEX_ERROR_POSIX_NAMED_CLASS_OUTSIDE_CLASS: POSIX named classes are
+ * supported only within a class. Since 2.16
+ * @G_REGEX_ERROR_UNMATCHED_PARENTHESIS: Missing terminating ")" or ")"
+ * without opening "(". Since 2.16
+ * @G_REGEX_ERROR_INEXISTENT_SUBPATTERN_REFERENCE: Reference to non-existent
+ * subpattern. Since 2.16
+ * @G_REGEX_ERROR_UNTERMINATED_COMMENT: Missing terminating ")" after comment.
+ * Since 2.16
+ * @G_REGEX_ERROR_EXPRESSION_TOO_LARGE: Regular expression too large.
+ * Since 2.16
+ * @G_REGEX_ERROR_MEMORY_ERROR: Failed to get memory. Since 2.16
+ * @G_REGEX_ERROR_VARIABLE_LENGTH_LOOKBEHIND: Lookbehind assertion is not
+ * fixed length. Since 2.16
+ * @G_REGEX_ERROR_MALFORMED_CONDITION: Malformed number or name after "(?(".
+ * Since 2.16
+ * @G_REGEX_ERROR_TOO_MANY_CONDITIONAL_BRANCHES: Conditional group contains
+ * more than two branches. Since 2.16
+ * @G_REGEX_ERROR_ASSERTION_EXPECTED: Assertion expected after "(?(".
+ * Since 2.16
+ * @G_REGEX_ERROR_UNKNOWN_POSIX_CLASS_NAME: Unknown POSIX class name.
+ * Since 2.16
+ * @G_REGEX_ERROR_POSIX_COLLATING_ELEMENTS_NOT_SUPPORTED: POSIX collating
+ * elements are not supported. Since 2.16
+ * @G_REGEX_ERROR_HEX_CODE_TOO_LARGE: Character value in "\\x{...}" sequence
+ * is too large. Since 2.16
+ * @G_REGEX_ERROR_INVALID_CONDITION: Invalid condition "(?(0)". Since 2.16
+ * @G_REGEX_ERROR_SINGLE_BYTE_MATCH_IN_LOOKBEHIND: \\C not allowed in
+ * lookbehind assertion. Since 2.16
+ * @G_REGEX_ERROR_INFINITE_LOOP: Recursive call could loop indefinitely.
+ * Since 2.16
+ * @G_REGEX_ERROR_MISSING_SUBPATTERN_NAME_TERMINATOR: Missing terminator
+ * in subpattern name. Since 2.16
+ * @G_REGEX_ERROR_DUPLICATE_SUBPATTERN_NAME: Two named subpatterns have
+ * the same name. Since 2.16
+ * @G_REGEX_ERROR_MALFORMED_PROPERTY: Malformed "\\P" or "\\p" sequence.
+ * Since 2.16
+ * @G_REGEX_ERROR_UNKNOWN_PROPERTY: Unknown property name after "\\P" or
+ * "\\p". Since 2.16
+ * @G_REGEX_ERROR_SUBPATTERN_NAME_TOO_LONG: Subpattern name is too long
+ * (maximum 32 characters). Since 2.16
+ * @G_REGEX_ERROR_TOO_MANY_SUBPATTERNS: Too many named subpatterns (maximum
+ * 10,000). Since 2.16
+ * @G_REGEX_ERROR_INVALID_OCTAL_VALUE: Octal value is greater than "\\377".
+ * Since 2.16
+ * @G_REGEX_ERROR_TOO_MANY_BRANCHES_IN_DEFINE: "DEFINE" group contains more
+ * than one branch. Since 2.16
+ * @G_REGEX_ERROR_DEFINE_REPETION: Repeating a "DEFINE" group is not allowed.
+ * Since 2.16
+ * @G_REGEX_ERROR_INCONSISTENT_NEWLINE_OPTIONS: Inconsistent newline options.
+ * Since 2.16
+ * @G_REGEX_ERROR_MISSING_BACK_REFERENCE: "\\g" is not followed by a braced
+ * name or an optionally braced non-zero number. Since 2.16
+ *
+ * Error codes returned by regular expressions functions.
+ *
+ * Since: 2.14
+ */
+typedef enum
+{
+ G_REGEX_ERROR_COMPILE,
+ G_REGEX_ERROR_OPTIMIZE,
+ G_REGEX_ERROR_REPLACE,
+ G_REGEX_ERROR_MATCH,
+ G_REGEX_ERROR_INTERNAL,
+
+ /* These are the error codes from PCRE + 100 */
+ G_REGEX_ERROR_STRAY_BACKSLASH = 101,
+ G_REGEX_ERROR_MISSING_CONTROL_CHAR = 102,
+ G_REGEX_ERROR_UNRECOGNIZED_ESCAPE = 103,
+ G_REGEX_ERROR_QUANTIFIERS_OUT_OF_ORDER = 104,
+ G_REGEX_ERROR_QUANTIFIER_TOO_BIG = 105,
+ G_REGEX_ERROR_UNTERMINATED_CHARACTER_CLASS = 106,
+ G_REGEX_ERROR_INVALID_ESCAPE_IN_CHARACTER_CLASS = 107,
+ G_REGEX_ERROR_RANGE_OUT_OF_ORDER = 108,
+ G_REGEX_ERROR_NOTHING_TO_REPEAT = 109,
+ G_REGEX_ERROR_UNRECOGNIZED_CHARACTER = 112,
+ G_REGEX_ERROR_POSIX_NAMED_CLASS_OUTSIDE_CLASS = 113,
+ G_REGEX_ERROR_UNMATCHED_PARENTHESIS = 114,
+ G_REGEX_ERROR_INEXISTENT_SUBPATTERN_REFERENCE = 115,
+ G_REGEX_ERROR_UNTERMINATED_COMMENT = 118,
+ G_REGEX_ERROR_EXPRESSION_TOO_LARGE = 120,
+ G_REGEX_ERROR_MEMORY_ERROR = 121,
+ G_REGEX_ERROR_VARIABLE_LENGTH_LOOKBEHIND = 125,
+ G_REGEX_ERROR_MALFORMED_CONDITION = 126,
+ G_REGEX_ERROR_TOO_MANY_CONDITIONAL_BRANCHES = 127,
+ G_REGEX_ERROR_ASSERTION_EXPECTED = 128,
+ G_REGEX_ERROR_UNKNOWN_POSIX_CLASS_NAME = 130,
+ G_REGEX_ERROR_POSIX_COLLATING_ELEMENTS_NOT_SUPPORTED = 131,
+ G_REGEX_ERROR_HEX_CODE_TOO_LARGE = 134,
+ G_REGEX_ERROR_INVALID_CONDITION = 135,
+ G_REGEX_ERROR_SINGLE_BYTE_MATCH_IN_LOOKBEHIND = 136,
+ G_REGEX_ERROR_INFINITE_LOOP = 140,
+ G_REGEX_ERROR_MISSING_SUBPATTERN_NAME_TERMINATOR = 142,
+ G_REGEX_ERROR_DUPLICATE_SUBPATTERN_NAME = 143,
+ G_REGEX_ERROR_MALFORMED_PROPERTY = 146,
+ G_REGEX_ERROR_UNKNOWN_PROPERTY = 147,
+ G_REGEX_ERROR_SUBPATTERN_NAME_TOO_LONG = 148,
+ G_REGEX_ERROR_TOO_MANY_SUBPATTERNS = 149,
+ G_REGEX_ERROR_INVALID_OCTAL_VALUE = 151,
+ G_REGEX_ERROR_TOO_MANY_BRANCHES_IN_DEFINE = 154,
+ G_REGEX_ERROR_DEFINE_REPETION = 155,
+ G_REGEX_ERROR_INCONSISTENT_NEWLINE_OPTIONS = 156,
+ G_REGEX_ERROR_MISSING_BACK_REFERENCE = 157
+} GRegexError;
+
+/**
+ * G_REGEX_ERROR:
+ *
+ * Error domain for regular expressions. Errors in this domain will be
+ * from the #GRegexError enumeration. See #GError for information on
+ * error domains.
+ *
+ * Since: 2.14
+ */
+#define G_REGEX_ERROR g_regex_error_quark ()
+
+GQuark g_regex_error_quark (void);
+
+/**
+ * GRegexCompileFlags:
+ * @G_REGEX_CASELESS: Letters in the pattern match both upper- and
+ * lowercase letters. This option can be changed within a pattern
+ * by a "(?i)" option setting.
+ * @G_REGEX_MULTILINE: By default, GRegex treats the strings as consisting
+ * of a single line of characters (even if it actually contains
+ * newlines). The "start of line" metacharacter ("^") matches only
+ * at the start of the string, while the "end of line" metacharacter
+ * ("$") matches only at the end of the string, or before a terminating
+ * newline (unless #G_REGEX_DOLLAR_ENDONLY is set). When
+ * #G_REGEX_MULTILINE is set, the "start of line" and "end of line"
+ * constructs match immediately following or immediately before any
+ * newline in the string, respectively, as well as at the very start
+ * and end. This can be changed within a pattern by a "(?m)" option
+ * setting.
+ * @G_REGEX_DOTALL: A dot metacharater (".") in the pattern matches all
+ * characters, including newlines. Without it, newlines are excluded.
+ * This option can be changed within a pattern by a ("?s") option setting.
+ * @G_REGEX_EXTENDED: Whitespace data characters in the pattern are
+ * totally ignored except when escaped or inside a character class.
+ * Whitespace does not include the VT character (code 11). In addition,
+ * characters between an unescaped "#" outside a character class and
+ * the next newline character, inclusive, are also ignored. This can
+ * be changed within a pattern by a "(?x)" option setting.
+ * @G_REGEX_ANCHORED: The pattern is forced to be "anchored", that is,
+ * it is constrained to match only at the first matching point in the
+ * string that is being searched. This effect can also be achieved by
+ * appropriate constructs in the pattern itself such as the "^"
+ * metacharater.
+ * @G_REGEX_DOLLAR_ENDONLY: A dollar metacharacter ("$") in the pattern
+ * matches only at the end of the string. Without this option, a
+ * dollar also matches immediately before the final character if
+ * it is a newline (but not before any other newlines). This option
+ * is ignored if #G_REGEX_MULTILINE is set.
+ * @G_REGEX_UNGREEDY: Inverts the "greediness" of the quantifiers so that
+ * they are not greedy by default, but become greedy if followed by "?".
+ * It can also be set by a "(?U)" option setting within the pattern.
+ * @G_REGEX_RAW: Usually strings must be valid UTF-8 strings, using this
+ * flag they are considered as a raw sequence of bytes.
+ * @G_REGEX_NO_AUTO_CAPTURE: Disables the use of numbered capturing
+ * parentheses in the pattern. Any opening parenthesis that is not
+ * followed by "?" behaves as if it were followed by "?:" but named
+ * parentheses can still be used for capturing (and they acquire numbers
+ * in the usual way).
+ * @G_REGEX_OPTIMIZE: Optimize the regular expression. If the pattern will
+ * be used many times, then it may be worth the effort to optimize it
+ * to improve the speed of matches.
+ * @G_REGEX_DUPNAMES: Names used to identify capturing subpatterns need not
+ * be unique. This can be helpful for certain types of pattern when it
+ * is known that only one instance of the named subpattern can ever be
+ * matched.
+ * @G_REGEX_NEWLINE_CR: Usually any newline character is recognized, if this
+ * option is set, the only recognized newline character is '\r'.
+ * @G_REGEX_NEWLINE_LF: Usually any newline character is recognized, if this
+ * option is set, the only recognized newline character is '\n'.
+ * @G_REGEX_NEWLINE_CRLF: Usually any newline character is recognized, if this
+ * option is set, the only recognized newline character sequence is '\r\n'.
+ *
+ * Flags specifying compile-time options.
+ *
+ * Since: 2.14
+ */
+/* Remember to update G_REGEX_COMPILE_MASK in gregex.c after
+ * adding a new flag. */
+typedef enum
+{
+ G_REGEX_CASELESS = 1 << 0,
+ G_REGEX_MULTILINE = 1 << 1,
+ G_REGEX_DOTALL = 1 << 2,
+ G_REGEX_EXTENDED = 1 << 3,
+ G_REGEX_ANCHORED = 1 << 4,
+ G_REGEX_DOLLAR_ENDONLY = 1 << 5,
+ G_REGEX_UNGREEDY = 1 << 9,
+ G_REGEX_RAW = 1 << 11,
+ G_REGEX_NO_AUTO_CAPTURE = 1 << 12,
+ G_REGEX_OPTIMIZE = 1 << 13,
+ G_REGEX_DUPNAMES = 1 << 19,
+ G_REGEX_NEWLINE_CR = 1 << 20,
+ G_REGEX_NEWLINE_LF = 1 << 21,
+ G_REGEX_NEWLINE_CRLF = G_REGEX_NEWLINE_CR | G_REGEX_NEWLINE_LF
+} GRegexCompileFlags;
+
+/**
+ * GRegexMatchFlags:
+ * @G_REGEX_MATCH_ANCHORED: The pattern is forced to be "anchored", that is,
+ * it is constrained to match only at the first matching point in the
+ * string that is being searched. This effect can also be achieved by
+ * appropriate constructs in the pattern itself such as the "^"
+ * metacharater.
+ * @G_REGEX_MATCH_NOTBOL: Specifies that first character of the string is
+ * not the beginning of a line, so the circumflex metacharacter should
+ * not match before it. Setting this without #G_REGEX_MULTILINE (at
+ * compile time) causes circumflex never to match. This option affects
+ * only the behaviour of the circumflex metacharacter, it does not
+ * affect "\A".
+ * @G_REGEX_MATCH_NOTEOL: Specifies that the end of the subject string is
+ * not the end of a line, so the dollar metacharacter should not match
+ * it nor (except in multiline mode) a newline immediately before it.
+ * Setting this without #G_REGEX_MULTILINE (at compile time) causes
+ * dollar never to match. This option affects only the behaviour of
+ * the dollar metacharacter, it does not affect "\Z" or "\z".
+ * @G_REGEX_MATCH_NOTEMPTY: An empty string is not considered to be a valid
+ * match if this option is set. If there are alternatives in the pattern,
+ * they are tried. If all the alternatives match the empty string, the
+ * entire match fails. For example, if the pattern "a?b?" is applied to
+ * a string not beginning with "a" or "b", it matches the empty string
+ * at the start of the string. With this flag set, this match is not
+ * valid, so GRegex searches further into the string for occurrences
+ * of "a" or "b".
+ * @G_REGEX_MATCH_PARTIAL: Turns on the partial matching feature, for more
+ * documentation on partial matching see g_match_info_is_partial_match().
+ * @G_REGEX_MATCH_NEWLINE_CR: Overrides the newline definition set when
+ * creating a new #GRegex, setting the '\r' character as line terminator.
+ * @G_REGEX_MATCH_NEWLINE_LF: Overrides the newline definition set when
+ * creating a new #GRegex, setting the '\n' character as line terminator.
+ * @G_REGEX_MATCH_NEWLINE_CRLF: Overrides the newline definition set when
+ * creating a new #GRegex, setting the '\r\n' characters as line terminator.
+ * @G_REGEX_MATCH_NEWLINE_ANY: Overrides the newline definition set when
+ * creating a new #GRegex, any newline character or character sequence
+ * is recognized.
+ *
+ * Flags specifying match-time options.
+ *
+ * Since: 2.14
+ */
+/* Remember to update G_REGEX_MATCH_MASK in gregex.c after
+ * adding a new flag. */
+typedef enum
+{
+ G_REGEX_MATCH_ANCHORED = 1 << 4,
+ G_REGEX_MATCH_NOTBOL = 1 << 7,
+ G_REGEX_MATCH_NOTEOL = 1 << 8,
+ G_REGEX_MATCH_NOTEMPTY = 1 << 10,
+ G_REGEX_MATCH_PARTIAL = 1 << 15,
+ G_REGEX_MATCH_NEWLINE_CR = 1 << 20,
+ G_REGEX_MATCH_NEWLINE_LF = 1 << 21,
+ G_REGEX_MATCH_NEWLINE_CRLF = G_REGEX_MATCH_NEWLINE_CR | G_REGEX_MATCH_NEWLINE_LF,
+ G_REGEX_MATCH_NEWLINE_ANY = 1 << 22
+} GRegexMatchFlags;
+
+/**
+ * GRegex:
+ *
+ * A GRegex is the "compiled" form of a regular expression pattern. This
+ * structure is opaque and its fields cannot be accessed directly.
+ *
+ * Since: 2.14
+ */
+typedef struct _GRegex GRegex;
+
+
+typedef struct _GMatchInfo GMatchInfo;
+
+/**
+ * GRegexEvalCallback:
+ * @match_info: the #GMatchInfo generated by the match.
+ * Use g_match_info_get_regex() and g_match_info_get_string() if you
+ * need the #GRegex or the matched string.
+ * @result: a #GString containing the new string
+ * @user_data: user data passed to g_regex_replace_eval()
+ *
+ * Specifies the type of the function passed to g_regex_replace_eval().
+ * It is called for each occurance of the pattern in the string passed
+ * to g_regex_replace_eval(), and it should append the replacement to
+ * @result.
+ *
+ * Returns: %FALSE to continue the replacement process, %TRUE to stop it
+ *
+ * Since: 2.14
+ */
+typedef gboolean (*GRegexEvalCallback) (const GMatchInfo *match_info,
+ GString *result,
+ gpointer user_data);
+
+
+GRegex *g_regex_new (const gchar *pattern,
+ GRegexCompileFlags compile_options,
+ GRegexMatchFlags match_options,
+ GError **error);
+GRegex *g_regex_ref (GRegex *regex);
+void g_regex_unref (GRegex *regex);
+const gchar *g_regex_get_pattern (const GRegex *regex);
+gint g_regex_get_max_backref (const GRegex *regex);
+gint g_regex_get_capture_count (const GRegex *regex);
+gint g_regex_get_string_number (const GRegex *regex,
+ const gchar *name);
+gchar *g_regex_escape_string (const gchar *string,
+ gint length);
+
+GRegexCompileFlags g_regex_get_compile_flags (const GRegex *regex);
+GRegexMatchFlags g_regex_get_match_flags (const GRegex *regex);
+
+/* Matching. */
+gboolean g_regex_match_simple (const gchar *pattern,
+ const gchar *string,
+ GRegexCompileFlags compile_options,
+ GRegexMatchFlags match_options);
+gboolean g_regex_match (const GRegex *regex,
+ const gchar *string,
+ GRegexMatchFlags match_options,
+ GMatchInfo **match_info);
+gboolean g_regex_match_full (const GRegex *regex,
+ const gchar *string,
+ gssize string_len,
+ gint start_position,
+ GRegexMatchFlags match_options,
+ GMatchInfo **match_info,
+ GError **error);
+gboolean g_regex_match_all (const GRegex *regex,
+ const gchar *string,
+ GRegexMatchFlags match_options,
+ GMatchInfo **match_info);
+gboolean g_regex_match_all_full (const GRegex *regex,
+ const gchar *string,
+ gssize string_len,
+ gint start_position,
+ GRegexMatchFlags match_options,
+ GMatchInfo **match_info,
+ GError **error);
+
+/* String splitting. */
+gchar **g_regex_split_simple (const gchar *pattern,
+ const gchar *string,
+ GRegexCompileFlags compile_options,
+ GRegexMatchFlags match_options);
+gchar **g_regex_split (const GRegex *regex,
+ const gchar *string,
+ GRegexMatchFlags match_options);
+gchar **g_regex_split_full (const GRegex *regex,
+ const gchar *string,
+ gssize string_len,
+ gint start_position,
+ GRegexMatchFlags match_options,
+ gint max_tokens,
+ GError **error);
+
+/* String replacement. */
+gchar *g_regex_replace (const GRegex *regex,
+ const gchar *string,
+ gssize string_len,
+ gint start_position,
+ const gchar *replacement,
+ GRegexMatchFlags match_options,
+ GError **error);
+gchar *g_regex_replace_literal (const GRegex *regex,
+ const gchar *string,
+ gssize string_len,
+ gint start_position,
+ const gchar *replacement,
+ GRegexMatchFlags match_options,
+ GError **error);
+gchar *g_regex_replace_eval (const GRegex *regex,
+ const gchar *string,
+ gssize string_len,
+ gint start_position,
+ GRegexMatchFlags match_options,
+ GRegexEvalCallback eval,
+ gpointer user_data,
+ GError **error);
+gboolean g_regex_check_replacement (const gchar *replacement,
+ gboolean *has_references,
+ GError **error);
+
+/* Match info */
+GRegex *g_match_info_get_regex (const GMatchInfo *match_info);
+const gchar *g_match_info_get_string (const GMatchInfo *match_info);
+
+void g_match_info_free (GMatchInfo *match_info);
+gboolean g_match_info_next (GMatchInfo *match_info,
+ GError **error);
+gboolean g_match_info_matches (const GMatchInfo *match_info);
+gint g_match_info_get_match_count (const GMatchInfo *match_info);
+gboolean g_match_info_is_partial_match (const GMatchInfo *match_info);
+gchar *g_match_info_expand_references(const GMatchInfo *match_info,
+ const gchar *string_to_expand,
+ GError **error);
+gchar *g_match_info_fetch (const GMatchInfo *match_info,
+ gint match_num);
+gboolean g_match_info_fetch_pos (const GMatchInfo *match_info,
+ gint match_num,
+ gint *start_pos,
+ gint *end_pos);
+gchar *g_match_info_fetch_named (const GMatchInfo *match_info,
+ const gchar *name);
+gboolean g_match_info_fetch_named_pos (const GMatchInfo *match_info,
+ const gchar *name,
+ gint *start_pos,
+ gint *end_pos);
+gchar **g_match_info_fetch_all (const GMatchInfo *match_info);
+
+G_END_DECLS
+
+#endif /* __G_REGEX_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/grel.h b/protocols/Sametime/src/glib/include/glib/grel.h
new file mode 100644
index 0000000000..5cb8d09d4b
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/grel.h
@@ -0,0 +1,101 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_REL_H__
+#define __G_REL_H__
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GRelation GRelation;
+typedef struct _GTuples GTuples;
+
+struct _GTuples
+{
+ guint len;
+};
+
+/* GRelation
+ *
+ * Indexed Relations. Imagine a really simple table in a
+ * database. Relations are not ordered. This data type is meant for
+ * maintaining a N-way mapping.
+ *
+ * g_relation_new() creates a relation with FIELDS fields
+ *
+ * g_relation_destroy() frees all resources
+ * g_tuples_destroy() frees the result of g_relation_select()
+ *
+ * g_relation_index() indexes relation FIELD with the provided
+ * equality and hash functions. this must be done before any
+ * calls to insert are made.
+ *
+ * g_relation_insert() inserts a new tuple. you are expected to
+ * provide the right number of fields.
+ *
+ * g_relation_delete() deletes all relations with KEY in FIELD
+ * g_relation_select() returns ...
+ * g_relation_count() counts ...
+ */
+
+#ifndef G_DISABLE_DEPRECATED
+
+GRelation* g_relation_new (gint fields);
+void g_relation_destroy (GRelation *relation);
+void g_relation_index (GRelation *relation,
+ gint field,
+ GHashFunc hash_func,
+ GEqualFunc key_equal_func);
+void g_relation_insert (GRelation *relation,
+ ...);
+gint g_relation_delete (GRelation *relation,
+ gconstpointer key,
+ gint field);
+GTuples* g_relation_select (GRelation *relation,
+ gconstpointer key,
+ gint field);
+gint g_relation_count (GRelation *relation,
+ gconstpointer key,
+ gint field);
+gboolean g_relation_exists (GRelation *relation,
+ ...);
+void g_relation_print (GRelation *relation);
+
+void g_tuples_destroy (GTuples *tuples);
+gpointer g_tuples_index (GTuples *tuples,
+ gint index_,
+ gint field);
+
+#endif
+
+G_END_DECLS
+
+#endif /* __G_REL_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gscanner.h b/protocols/Sametime/src/glib/include/glib/gscanner.h
new file mode 100644
index 0000000000..3b7ad6fab0
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gscanner.h
@@ -0,0 +1,278 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_SCANNER_H__
+#define __G_SCANNER_H__
+
+#include <glib/gdataset.h>
+#include <glib/ghash.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GScanner GScanner;
+typedef struct _GScannerConfig GScannerConfig;
+typedef union _GTokenValue GTokenValue;
+
+typedef void (*GScannerMsgFunc) (GScanner *scanner,
+ gchar *message,
+ gboolean error);
+
+/* GScanner: Flexible lexical scanner for general purpose.
+ */
+
+/* Character sets */
+#define G_CSET_A_2_Z "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define G_CSET_a_2_z "abcdefghijklmnopqrstuvwxyz"
+#define G_CSET_DIGITS "0123456789"
+#define G_CSET_LATINC "\300\301\302\303\304\305\306"\
+ "\307\310\311\312\313\314\315\316\317\320"\
+ "\321\322\323\324\325\326"\
+ "\330\331\332\333\334\335\336"
+#define G_CSET_LATINS "\337\340\341\342\343\344\345\346"\
+ "\347\350\351\352\353\354\355\356\357\360"\
+ "\361\362\363\364\365\366"\
+ "\370\371\372\373\374\375\376\377"
+
+/* Error types */
+typedef enum
+{
+ G_ERR_UNKNOWN,
+ G_ERR_UNEXP_EOF,
+ G_ERR_UNEXP_EOF_IN_STRING,
+ G_ERR_UNEXP_EOF_IN_COMMENT,
+ G_ERR_NON_DIGIT_IN_CONST,
+ G_ERR_DIGIT_RADIX,
+ G_ERR_FLOAT_RADIX,
+ G_ERR_FLOAT_MALFORMED
+} GErrorType;
+
+/* Token types */
+typedef enum
+{
+ G_TOKEN_EOF = 0,
+
+ G_TOKEN_LEFT_PAREN = '(',
+ G_TOKEN_RIGHT_PAREN = ')',
+ G_TOKEN_LEFT_CURLY = '{',
+ G_TOKEN_RIGHT_CURLY = '}',
+ G_TOKEN_LEFT_BRACE = '[',
+ G_TOKEN_RIGHT_BRACE = ']',
+ G_TOKEN_EQUAL_SIGN = '=',
+ G_TOKEN_COMMA = ',',
+
+ G_TOKEN_NONE = 256,
+
+ G_TOKEN_ERROR,
+
+ G_TOKEN_CHAR,
+ G_TOKEN_BINARY,
+ G_TOKEN_OCTAL,
+ G_TOKEN_INT,
+ G_TOKEN_HEX,
+ G_TOKEN_FLOAT,
+ G_TOKEN_STRING,
+
+ G_TOKEN_SYMBOL,
+ G_TOKEN_IDENTIFIER,
+ G_TOKEN_IDENTIFIER_NULL,
+
+ G_TOKEN_COMMENT_SINGLE,
+ G_TOKEN_COMMENT_MULTI,
+ G_TOKEN_LAST
+} GTokenType;
+
+union _GTokenValue
+{
+ gpointer v_symbol;
+ gchar *v_identifier;
+ gulong v_binary;
+ gulong v_octal;
+ gulong v_int;
+ guint64 v_int64;
+ gdouble v_float;
+ gulong v_hex;
+ gchar *v_string;
+ gchar *v_comment;
+ guchar v_char;
+ guint v_error;
+};
+
+struct _GScannerConfig
+{
+ /* Character sets
+ */
+ gchar *cset_skip_characters; /* default: " \t\n" */
+ gchar *cset_identifier_first;
+ gchar *cset_identifier_nth;
+ gchar *cpair_comment_single; /* default: "#\n" */
+
+ /* Should symbol lookup work case sensitive?
+ */
+ guint case_sensitive : 1;
+
+ /* Boolean values to be adjusted "on the fly"
+ * to configure scanning behaviour.
+ */
+ guint skip_comment_multi : 1; /* C like comment */
+ guint skip_comment_single : 1; /* single line comment */
+ guint scan_comment_multi : 1; /* scan multi line comments? */
+ guint scan_identifier : 1;
+ guint scan_identifier_1char : 1;
+ guint scan_identifier_NULL : 1;
+ guint scan_symbols : 1;
+ guint scan_binary : 1;
+ guint scan_octal : 1;
+ guint scan_float : 1;
+ guint scan_hex : 1; /* `0x0ff0' */
+ guint scan_hex_dollar : 1; /* `$0ff0' */
+ guint scan_string_sq : 1; /* string: 'anything' */
+ guint scan_string_dq : 1; /* string: "\\-escapes!\n" */
+ guint numbers_2_int : 1; /* bin, octal, hex => int */
+ guint int_2_float : 1; /* int => G_TOKEN_FLOAT? */
+ guint identifier_2_string : 1;
+ guint char_2_token : 1; /* return G_TOKEN_CHAR? */
+ guint symbol_2_token : 1;
+ guint scope_0_fallback : 1; /* try scope 0 on lookups? */
+ guint store_int64 : 1; /* use value.v_int64 rather than v_int */
+ guint padding_dummy;
+};
+
+struct _GScanner
+{
+ /* unused fields */
+ gpointer user_data;
+ guint max_parse_errors;
+
+ /* g_scanner_error() increments this field */
+ guint parse_errors;
+
+ /* name of input stream, featured by the default message handler */
+ const gchar *input_name;
+
+ /* quarked data */
+ GData *qdata;
+
+ /* link into the scanner configuration */
+ GScannerConfig *config;
+
+ /* fields filled in after g_scanner_get_next_token() */
+ GTokenType token;
+ GTokenValue value;
+ guint line;
+ guint position;
+
+ /* fields filled in after g_scanner_peek_next_token() */
+ GTokenType next_token;
+ GTokenValue next_value;
+ guint next_line;
+ guint next_position;
+
+ /* to be considered private */
+ GHashTable *symbol_table;
+ gint input_fd;
+ const gchar *text;
+ const gchar *text_end;
+ gchar *buffer;
+ guint scope_id;
+
+ /* handler function for _warn and _error */
+ GScannerMsgFunc msg_handler;
+};
+
+GScanner* g_scanner_new (const GScannerConfig *config_templ);
+void g_scanner_destroy (GScanner *scanner);
+void g_scanner_input_file (GScanner *scanner,
+ gint input_fd);
+void g_scanner_sync_file_offset (GScanner *scanner);
+void g_scanner_input_text (GScanner *scanner,
+ const gchar *text,
+ guint text_len);
+GTokenType g_scanner_get_next_token (GScanner *scanner);
+GTokenType g_scanner_peek_next_token (GScanner *scanner);
+GTokenType g_scanner_cur_token (GScanner *scanner);
+GTokenValue g_scanner_cur_value (GScanner *scanner);
+guint g_scanner_cur_line (GScanner *scanner);
+guint g_scanner_cur_position (GScanner *scanner);
+gboolean g_scanner_eof (GScanner *scanner);
+guint g_scanner_set_scope (GScanner *scanner,
+ guint scope_id);
+void g_scanner_scope_add_symbol (GScanner *scanner,
+ guint scope_id,
+ const gchar *symbol,
+ gpointer value);
+void g_scanner_scope_remove_symbol (GScanner *scanner,
+ guint scope_id,
+ const gchar *symbol);
+gpointer g_scanner_scope_lookup_symbol (GScanner *scanner,
+ guint scope_id,
+ const gchar *symbol);
+void g_scanner_scope_foreach_symbol (GScanner *scanner,
+ guint scope_id,
+ GHFunc func,
+ gpointer user_data);
+gpointer g_scanner_lookup_symbol (GScanner *scanner,
+ const gchar *symbol);
+void g_scanner_unexp_token (GScanner *scanner,
+ GTokenType expected_token,
+ const gchar *identifier_spec,
+ const gchar *symbol_spec,
+ const gchar *symbol_name,
+ const gchar *message,
+ gint is_error);
+void g_scanner_error (GScanner *scanner,
+ const gchar *format,
+ ...) G_GNUC_PRINTF (2,3);
+void g_scanner_warn (GScanner *scanner,
+ const gchar *format,
+ ...) G_GNUC_PRINTF (2,3);
+
+#ifndef G_DISABLE_DEPRECATED
+
+/* keep downward source compatibility */
+#define g_scanner_add_symbol( scanner, symbol, value ) G_STMT_START { \
+ g_scanner_scope_add_symbol ((scanner), 0, (symbol), (value)); \
+} G_STMT_END
+#define g_scanner_remove_symbol( scanner, symbol ) G_STMT_START { \
+ g_scanner_scope_remove_symbol ((scanner), 0, (symbol)); \
+} G_STMT_END
+#define g_scanner_foreach_symbol( scanner, func, data ) G_STMT_START { \
+ g_scanner_scope_foreach_symbol ((scanner), 0, (func), (data)); \
+} G_STMT_END
+
+/* The following two functions are deprecated and will be removed in
+ * the next major release. They do no good. */
+#define g_scanner_freeze_symbol_table(scanner) ((void)0)
+#define g_scanner_thaw_symbol_table(scanner) ((void)0)
+
+#endif /* G_DISABLE_DEPRECATED */
+
+G_END_DECLS
+
+#endif /* __G_SCANNER_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gsequence.h b/protocols/Sametime/src/glib/include/glib/gsequence.h
new file mode 100644
index 0000000000..fa79066e06
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gsequence.h
@@ -0,0 +1,128 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007
+ * Soeren Sandmann (sandmann@daimi.au.dk)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_SEQUENCE_H__
+#define __G_SEQUENCE_H__
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GSequence GSequence;
+typedef struct _GSequenceNode GSequenceIter;
+
+typedef gint (* GSequenceIterCompareFunc) (GSequenceIter *a,
+ GSequenceIter *b,
+ gpointer data);
+
+
+/* GSequence */
+GSequence * g_sequence_new (GDestroyNotify data_destroy);
+void g_sequence_free (GSequence *seq);
+gint g_sequence_get_length (GSequence *seq);
+void g_sequence_foreach (GSequence *seq,
+ GFunc func,
+ gpointer user_data);
+void g_sequence_foreach_range (GSequenceIter *begin,
+ GSequenceIter *end,
+ GFunc func,
+ gpointer user_data);
+void g_sequence_sort (GSequence *seq,
+ GCompareDataFunc cmp_func,
+ gpointer cmp_data);
+void g_sequence_sort_iter (GSequence *seq,
+ GSequenceIterCompareFunc cmp_func,
+ gpointer cmp_data);
+
+
+/* Getting iters */
+GSequenceIter *g_sequence_get_begin_iter (GSequence *seq);
+GSequenceIter *g_sequence_get_end_iter (GSequence *seq);
+GSequenceIter *g_sequence_get_iter_at_pos (GSequence *seq,
+ gint pos);
+GSequenceIter *g_sequence_append (GSequence *seq,
+ gpointer data);
+GSequenceIter *g_sequence_prepend (GSequence *seq,
+ gpointer data);
+GSequenceIter *g_sequence_insert_before (GSequenceIter *iter,
+ gpointer data);
+void g_sequence_move (GSequenceIter *src,
+ GSequenceIter *dest);
+void g_sequence_swap (GSequenceIter *a,
+ GSequenceIter *b);
+GSequenceIter *g_sequence_insert_sorted (GSequence *seq,
+ gpointer data,
+ GCompareDataFunc cmp_func,
+ gpointer cmp_data);
+GSequenceIter *g_sequence_insert_sorted_iter (GSequence *seq,
+ gpointer data,
+ GSequenceIterCompareFunc iter_cmp,
+ gpointer cmp_data);
+void g_sequence_sort_changed (GSequenceIter *iter,
+ GCompareDataFunc cmp_func,
+ gpointer cmp_data);
+void g_sequence_sort_changed_iter (GSequenceIter *iter,
+ GSequenceIterCompareFunc iter_cmp,
+ gpointer cmp_data);
+void g_sequence_remove (GSequenceIter *iter);
+void g_sequence_remove_range (GSequenceIter *begin,
+ GSequenceIter *end);
+void g_sequence_move_range (GSequenceIter *dest,
+ GSequenceIter *begin,
+ GSequenceIter *end);
+GSequenceIter *g_sequence_search (GSequence *seq,
+ gpointer data,
+ GCompareDataFunc cmp_func,
+ gpointer cmp_data);
+GSequenceIter *g_sequence_search_iter (GSequence *seq,
+ gpointer data,
+ GSequenceIterCompareFunc iter_cmp,
+ gpointer cmp_data);
+
+
+/* Dereferencing */
+gpointer g_sequence_get (GSequenceIter *iter);
+void g_sequence_set (GSequenceIter *iter,
+ gpointer data);
+
+/* Operations on GSequenceIter * */
+gboolean g_sequence_iter_is_begin (GSequenceIter *iter);
+gboolean g_sequence_iter_is_end (GSequenceIter *iter);
+GSequenceIter *g_sequence_iter_next (GSequenceIter *iter);
+GSequenceIter *g_sequence_iter_prev (GSequenceIter *iter);
+gint g_sequence_iter_get_position (GSequenceIter *iter);
+GSequenceIter *g_sequence_iter_move (GSequenceIter *iter,
+ gint delta);
+GSequence * g_sequence_iter_get_sequence (GSequenceIter *iter);
+
+
+/* Search */
+gint g_sequence_iter_compare (GSequenceIter *a,
+ GSequenceIter *b);
+GSequenceIter *g_sequence_range_get_midpoint (GSequenceIter *begin,
+ GSequenceIter *end);
+
+G_END_DECLS
+
+#endif /* __G_SEQUENCE_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gshell.h b/protocols/Sametime/src/glib/include/glib/gshell.h
new file mode 100644
index 0000000000..130f1008c8
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gshell.h
@@ -0,0 +1,55 @@
+/* gshell.h - Shell-related utilities
+ *
+ * Copyright 2000 Red Hat, Inc.
+ *
+ * GLib is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * GLib is distributed in the hope that 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 GLib; see the file COPYING.LIB. If not, write
+ * to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_SHELL_H__
+#define __G_SHELL_H__
+
+#include <glib/gerror.h>
+
+G_BEGIN_DECLS
+
+#define G_SHELL_ERROR g_shell_error_quark ()
+
+typedef enum
+{
+ /* mismatched or otherwise mangled quoting */
+ G_SHELL_ERROR_BAD_QUOTING,
+ /* string to be parsed was empty */
+ G_SHELL_ERROR_EMPTY_STRING,
+ G_SHELL_ERROR_FAILED
+} GShellError;
+
+GQuark g_shell_error_quark (void);
+
+gchar* g_shell_quote (const gchar *unquoted_string);
+gchar* g_shell_unquote (const gchar *quoted_string,
+ GError **error);
+gboolean g_shell_parse_argv (const gchar *command_line,
+ gint *argcp,
+ gchar ***argvp,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __G_SHELL_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gslice.h b/protocols/Sametime/src/glib/include/glib/gslice.h
new file mode 100644
index 0000000000..962199e099
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gslice.h
@@ -0,0 +1,86 @@
+/* GLIB sliced memory - fast threaded memory chunk allocator
+ * Copyright (C) 2005 Tim Janik
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_SLICE_H__
+#define __G_SLICE_H__
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+/* slices - fast allocation/release of small memory blocks
+ */
+gpointer g_slice_alloc (gsize block_size) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
+gpointer g_slice_alloc0 (gsize block_size) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
+gpointer g_slice_copy (gsize block_size,
+ gconstpointer mem_block) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
+void g_slice_free1 (gsize block_size,
+ gpointer mem_block);
+void g_slice_free_chain_with_offset (gsize block_size,
+ gpointer mem_chain,
+ gsize next_offset);
+#define g_slice_new(type) ((type*) g_slice_alloc (sizeof (type)))
+#define g_slice_new0(type) ((type*) g_slice_alloc0 (sizeof (type)))
+/* MemoryBlockType *
+ * g_slice_dup (MemoryBlockType,
+ * MemoryBlockType *mem_block);
+ * g_slice_free (MemoryBlockType,
+ * MemoryBlockType *mem_block);
+ * g_slice_free_chain (MemoryBlockType,
+ * MemoryBlockType *first_chain_block,
+ * memory_block_next_field);
+ * pseudo prototypes for the macro
+ * definitions following below.
+ */
+
+/* we go through extra hoops to ensure type safety */
+#define g_slice_dup(type, mem) \
+ (1 ? (type*) g_slice_copy (sizeof (type), (mem)) \
+ : ((void) ((type*) 0 == (mem)), (type*) 0))
+#define g_slice_free(type, mem) do { \
+ if (1) g_slice_free1 (sizeof (type), (mem)); \
+ else (void) ((type*) 0 == (mem)); \
+} while (0)
+#define g_slice_free_chain(type, mem_chain, next) do { \
+ if (1) g_slice_free_chain_with_offset (sizeof (type), \
+ (mem_chain), G_STRUCT_OFFSET (type, next)); \
+ else (void) ((type*) 0 == (mem_chain)); \
+} while (0)
+
+
+/* --- internal debugging API --- */
+typedef enum {
+ G_SLICE_CONFIG_ALWAYS_MALLOC = 1,
+ G_SLICE_CONFIG_BYPASS_MAGAZINES,
+ G_SLICE_CONFIG_WORKING_SET_MSECS,
+ G_SLICE_CONFIG_COLOR_INCREMENT,
+ G_SLICE_CONFIG_CHUNK_SIZES,
+ G_SLICE_CONFIG_CONTENTION_COUNTER
+} GSliceConfig;
+void g_slice_set_config (GSliceConfig ckey, gint64 value);
+gint64 g_slice_get_config (GSliceConfig ckey);
+gint64* g_slice_get_config_state (GSliceConfig ckey, gint64 address, guint *n_values);
+
+G_END_DECLS
+
+#endif /* __G_SLICE_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gslist.h b/protocols/Sametime/src/glib/include/glib/gslist.h
new file mode 100644
index 0000000000..8b01faf5cd
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gslist.h
@@ -0,0 +1,114 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_SLIST_H__
+#define __G_SLIST_H__
+
+#include <glib/gmem.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GSList GSList;
+
+struct _GSList
+{
+ gpointer data;
+ GSList *next;
+};
+
+/* Singly linked lists
+ */
+GSList* g_slist_alloc (void) G_GNUC_WARN_UNUSED_RESULT;
+void g_slist_free (GSList *list);
+void g_slist_free_1 (GSList *list);
+#define g_slist_free1 g_slist_free_1
+GSList* g_slist_append (GSList *list,
+ gpointer data) G_GNUC_WARN_UNUSED_RESULT;
+GSList* g_slist_prepend (GSList *list,
+ gpointer data) G_GNUC_WARN_UNUSED_RESULT;
+GSList* g_slist_insert (GSList *list,
+ gpointer data,
+ gint position) G_GNUC_WARN_UNUSED_RESULT;
+GSList* g_slist_insert_sorted (GSList *list,
+ gpointer data,
+ GCompareFunc func) G_GNUC_WARN_UNUSED_RESULT;
+GSList* g_slist_insert_sorted_with_data (GSList *list,
+ gpointer data,
+ GCompareDataFunc func,
+ gpointer user_data) G_GNUC_WARN_UNUSED_RESULT;
+GSList* g_slist_insert_before (GSList *slist,
+ GSList *sibling,
+ gpointer data) G_GNUC_WARN_UNUSED_RESULT;
+GSList* g_slist_concat (GSList *list1,
+ GSList *list2) G_GNUC_WARN_UNUSED_RESULT;
+GSList* g_slist_remove (GSList *list,
+ gconstpointer data) G_GNUC_WARN_UNUSED_RESULT;
+GSList* g_slist_remove_all (GSList *list,
+ gconstpointer data) G_GNUC_WARN_UNUSED_RESULT;
+GSList* g_slist_remove_link (GSList *list,
+ GSList *link_) G_GNUC_WARN_UNUSED_RESULT;
+GSList* g_slist_delete_link (GSList *list,
+ GSList *link_) G_GNUC_WARN_UNUSED_RESULT;
+GSList* g_slist_reverse (GSList *list) G_GNUC_WARN_UNUSED_RESULT;
+GSList* g_slist_copy (GSList *list) G_GNUC_WARN_UNUSED_RESULT;
+GSList* g_slist_nth (GSList *list,
+ guint n);
+GSList* g_slist_find (GSList *list,
+ gconstpointer data);
+GSList* g_slist_find_custom (GSList *list,
+ gconstpointer data,
+ GCompareFunc func);
+gint g_slist_position (GSList *list,
+ GSList *llink);
+gint g_slist_index (GSList *list,
+ gconstpointer data);
+GSList* g_slist_last (GSList *list);
+guint g_slist_length (GSList *list);
+void g_slist_foreach (GSList *list,
+ GFunc func,
+ gpointer user_data);
+GSList* g_slist_sort (GSList *list,
+ GCompareFunc compare_func) G_GNUC_WARN_UNUSED_RESULT;
+GSList* g_slist_sort_with_data (GSList *list,
+ GCompareDataFunc compare_func,
+ gpointer user_data) G_GNUC_WARN_UNUSED_RESULT;
+gpointer g_slist_nth_data (GSList *list,
+ guint n);
+
+#define g_slist_next(slist) ((slist) ? (((GSList *)(slist))->next) : NULL)
+
+#ifndef G_DISABLE_DEPRECATED
+void g_slist_push_allocator (gpointer dummy);
+void g_slist_pop_allocator (void);
+#endif
+
+G_END_DECLS
+
+#endif /* __G_SLIST_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gspawn.h b/protocols/Sametime/src/glib/include/glib/gspawn.h
new file mode 100644
index 0000000000..9836b34242
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gspawn.h
@@ -0,0 +1,139 @@
+/* gspawn.h - Process launching
+ *
+ * Copyright 2000 Red Hat, Inc.
+ *
+ * GLib is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * GLib is distributed in the hope that 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 GLib; see the file COPYING.LIB. If not, write
+ * to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_SPAWN_H__
+#define __G_SPAWN_H__
+
+#include <glib/gerror.h>
+
+G_BEGIN_DECLS
+
+/* I'm not sure I remember our proposed naming convention here. */
+#define G_SPAWN_ERROR g_spawn_error_quark ()
+
+typedef enum
+{
+ G_SPAWN_ERROR_FORK, /* fork failed due to lack of memory */
+ G_SPAWN_ERROR_READ, /* read or select on pipes failed */
+ G_SPAWN_ERROR_CHDIR, /* changing to working dir failed */
+ G_SPAWN_ERROR_ACCES, /* execv() returned EACCES */
+ G_SPAWN_ERROR_PERM, /* execv() returned EPERM */
+ G_SPAWN_ERROR_2BIG, /* execv() returned E2BIG */
+ G_SPAWN_ERROR_NOEXEC, /* execv() returned ENOEXEC */
+ G_SPAWN_ERROR_NAMETOOLONG, /* "" "" ENAMETOOLONG */
+ G_SPAWN_ERROR_NOENT, /* "" "" ENOENT */
+ G_SPAWN_ERROR_NOMEM, /* "" "" ENOMEM */
+ G_SPAWN_ERROR_NOTDIR, /* "" "" ENOTDIR */
+ G_SPAWN_ERROR_LOOP, /* "" "" ELOOP */
+ G_SPAWN_ERROR_TXTBUSY, /* "" "" ETXTBUSY */
+ G_SPAWN_ERROR_IO, /* "" "" EIO */
+ G_SPAWN_ERROR_NFILE, /* "" "" ENFILE */
+ G_SPAWN_ERROR_MFILE, /* "" "" EMFLE */
+ G_SPAWN_ERROR_INVAL, /* "" "" EINVAL */
+ G_SPAWN_ERROR_ISDIR, /* "" "" EISDIR */
+ G_SPAWN_ERROR_LIBBAD, /* "" "" ELIBBAD */
+ G_SPAWN_ERROR_FAILED /* other fatal failure, error->message
+ * should explain
+ */
+} GSpawnError;
+
+typedef void (* GSpawnChildSetupFunc) (gpointer user_data);
+
+typedef enum
+{
+ G_SPAWN_LEAVE_DESCRIPTORS_OPEN = 1 << 0,
+ G_SPAWN_DO_NOT_REAP_CHILD = 1 << 1,
+ /* look for argv[0] in the path i.e. use execvp() */
+ G_SPAWN_SEARCH_PATH = 1 << 2,
+ /* Dump output to /dev/null */
+ G_SPAWN_STDOUT_TO_DEV_NULL = 1 << 3,
+ G_SPAWN_STDERR_TO_DEV_NULL = 1 << 4,
+ G_SPAWN_CHILD_INHERITS_STDIN = 1 << 5,
+ G_SPAWN_FILE_AND_ARGV_ZERO = 1 << 6
+} GSpawnFlags;
+
+GQuark g_spawn_error_quark (void);
+
+#ifdef G_OS_WIN32
+#define g_spawn_async g_spawn_async_utf8
+#define g_spawn_async_with_pipes g_spawn_async_with_pipes_utf8
+#define g_spawn_sync g_spawn_sync_utf8
+#define g_spawn_command_line_sync g_spawn_command_line_sync_utf8
+#define g_spawn_command_line_async g_spawn_command_line_async_utf8
+#endif
+
+gboolean g_spawn_async (const gchar *working_directory,
+ gchar **argv,
+ gchar **envp,
+ GSpawnFlags flags,
+ GSpawnChildSetupFunc child_setup,
+ gpointer user_data,
+ GPid *child_pid,
+ GError **error);
+
+
+/* Opens pipes for non-NULL standard_output, standard_input, standard_error,
+ * and returns the parent's end of the pipes.
+ */
+gboolean g_spawn_async_with_pipes (const gchar *working_directory,
+ gchar **argv,
+ gchar **envp,
+ GSpawnFlags flags,
+ GSpawnChildSetupFunc child_setup,
+ gpointer user_data,
+ GPid *child_pid,
+ gint *standard_input,
+ gint *standard_output,
+ gint *standard_error,
+ GError **error);
+
+
+/* If standard_output or standard_error are non-NULL, the full
+ * standard output or error of the command will be placed there.
+ */
+
+gboolean g_spawn_sync (const gchar *working_directory,
+ gchar **argv,
+ gchar **envp,
+ GSpawnFlags flags,
+ GSpawnChildSetupFunc child_setup,
+ gpointer user_data,
+ gchar **standard_output,
+ gchar **standard_error,
+ gint *exit_status,
+ GError **error);
+
+gboolean g_spawn_command_line_sync (const gchar *command_line,
+ gchar **standard_output,
+ gchar **standard_error,
+ gint *exit_status,
+ GError **error);
+gboolean g_spawn_command_line_async (const gchar *command_line,
+ GError **error);
+
+void g_spawn_close_pid (GPid pid);
+
+G_END_DECLS
+
+#endif /* __G_SPAWN_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gstrfuncs.h b/protocols/Sametime/src/glib/include/glib/gstrfuncs.h
new file mode 100644
index 0000000000..5c7332a3c4
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gstrfuncs.h
@@ -0,0 +1,269 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_STRFUNCS_H__
+#define __G_STRFUNCS_H__
+
+#include <stdarg.h>
+#include <glib/gmacros.h>
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+/* Functions like the ones in <ctype.h> that are not affected by locale. */
+typedef enum {
+ G_ASCII_ALNUM = 1 << 0,
+ G_ASCII_ALPHA = 1 << 1,
+ G_ASCII_CNTRL = 1 << 2,
+ G_ASCII_DIGIT = 1 << 3,
+ G_ASCII_GRAPH = 1 << 4,
+ G_ASCII_LOWER = 1 << 5,
+ G_ASCII_PRINT = 1 << 6,
+ G_ASCII_PUNCT = 1 << 7,
+ G_ASCII_SPACE = 1 << 8,
+ G_ASCII_UPPER = 1 << 9,
+ G_ASCII_XDIGIT = 1 << 10
+} GAsciiType;
+
+GLIB_VAR const guint16 * const g_ascii_table;
+
+#define g_ascii_isalnum(c) \
+ ((g_ascii_table[(guchar) (c)] & G_ASCII_ALNUM) != 0)
+
+#define g_ascii_isalpha(c) \
+ ((g_ascii_table[(guchar) (c)] & G_ASCII_ALPHA) != 0)
+
+#define g_ascii_iscntrl(c) \
+ ((g_ascii_table[(guchar) (c)] & G_ASCII_CNTRL) != 0)
+
+#define g_ascii_isdigit(c) \
+ ((g_ascii_table[(guchar) (c)] & G_ASCII_DIGIT) != 0)
+
+#define g_ascii_isgraph(c) \
+ ((g_ascii_table[(guchar) (c)] & G_ASCII_GRAPH) != 0)
+
+#define g_ascii_islower(c) \
+ ((g_ascii_table[(guchar) (c)] & G_ASCII_LOWER) != 0)
+
+#define g_ascii_isprint(c) \
+ ((g_ascii_table[(guchar) (c)] & G_ASCII_PRINT) != 0)
+
+#define g_ascii_ispunct(c) \
+ ((g_ascii_table[(guchar) (c)] & G_ASCII_PUNCT) != 0)
+
+#define g_ascii_isspace(c) \
+ ((g_ascii_table[(guchar) (c)] & G_ASCII_SPACE) != 0)
+
+#define g_ascii_isupper(c) \
+ ((g_ascii_table[(guchar) (c)] & G_ASCII_UPPER) != 0)
+
+#define g_ascii_isxdigit(c) \
+ ((g_ascii_table[(guchar) (c)] & G_ASCII_XDIGIT) != 0)
+
+gchar g_ascii_tolower (gchar c) G_GNUC_CONST;
+gchar g_ascii_toupper (gchar c) G_GNUC_CONST;
+
+gint g_ascii_digit_value (gchar c) G_GNUC_CONST;
+gint g_ascii_xdigit_value (gchar c) G_GNUC_CONST;
+
+/* String utility functions that modify a string argument or
+ * return a constant string that must not be freed.
+ */
+#define G_STR_DELIMITERS "_-|> <."
+gchar* g_strdelimit (gchar *string,
+ const gchar *delimiters,
+ gchar new_delimiter);
+gchar* g_strcanon (gchar *string,
+ const gchar *valid_chars,
+ gchar substitutor);
+G_CONST_RETURN gchar* g_strerror (gint errnum) G_GNUC_CONST;
+G_CONST_RETURN gchar* g_strsignal (gint signum) G_GNUC_CONST;
+gchar* g_strreverse (gchar *string);
+gsize g_strlcpy (gchar *dest,
+ const gchar *src,
+ gsize dest_size);
+gsize g_strlcat (gchar *dest,
+ const gchar *src,
+ gsize dest_size);
+gchar * g_strstr_len (const gchar *haystack,
+ gssize haystack_len,
+ const gchar *needle);
+gchar * g_strrstr (const gchar *haystack,
+ const gchar *needle);
+gchar * g_strrstr_len (const gchar *haystack,
+ gssize haystack_len,
+ const gchar *needle);
+
+gboolean g_str_has_suffix (const gchar *str,
+ const gchar *suffix);
+gboolean g_str_has_prefix (const gchar *str,
+ const gchar *prefix);
+
+/* String to/from double conversion functions */
+
+gdouble g_strtod (const gchar *nptr,
+ gchar **endptr);
+gdouble g_ascii_strtod (const gchar *nptr,
+ gchar **endptr);
+guint64 g_ascii_strtoull (const gchar *nptr,
+ gchar **endptr,
+ guint base);
+gint64 g_ascii_strtoll (const gchar *nptr,
+ gchar **endptr,
+ guint base);
+/* 29 bytes should enough for all possible values that
+ * g_ascii_dtostr can produce.
+ * Then add 10 for good measure */
+#define G_ASCII_DTOSTR_BUF_SIZE (29 + 10)
+gchar * g_ascii_dtostr (gchar *buffer,
+ gint buf_len,
+ gdouble d);
+gchar * g_ascii_formatd (gchar *buffer,
+ gint buf_len,
+ const gchar *format,
+ gdouble d);
+
+/* removes leading spaces */
+gchar* g_strchug (gchar *string);
+/* removes trailing spaces */
+gchar* g_strchomp (gchar *string);
+/* removes leading & trailing spaces */
+#define g_strstrip( string ) g_strchomp (g_strchug (string))
+
+gint g_ascii_strcasecmp (const gchar *s1,
+ const gchar *s2);
+gint g_ascii_strncasecmp (const gchar *s1,
+ const gchar *s2,
+ gsize n);
+gchar* g_ascii_strdown (const gchar *str,
+ gssize len) G_GNUC_MALLOC;
+gchar* g_ascii_strup (const gchar *str,
+ gssize len) G_GNUC_MALLOC;
+
+#ifndef G_DISABLE_DEPRECATED
+
+/* The following four functions are deprecated and will be removed in
+ * the next major release. They use the locale-specific tolower and
+ * toupper, which is almost never the right thing.
+ */
+
+gint g_strcasecmp (const gchar *s1,
+ const gchar *s2);
+gint g_strncasecmp (const gchar *s1,
+ const gchar *s2,
+ guint n);
+gchar* g_strdown (gchar *string);
+gchar* g_strup (gchar *string);
+
+#endif /* G_DISABLE_DEPRECATED */
+
+/* String utility functions that return a newly allocated string which
+ * ought to be freed with g_free from the caller at some point.
+ */
+gchar* g_strdup (const gchar *str) G_GNUC_MALLOC;
+gchar* g_strdup_printf (const gchar *format,
+ ...) G_GNUC_PRINTF (1, 2) G_GNUC_MALLOC;
+gchar* g_strdup_vprintf (const gchar *format,
+ va_list args) G_GNUC_MALLOC;
+gchar* g_strndup (const gchar *str,
+ gsize n) G_GNUC_MALLOC;
+gchar* g_strnfill (gsize length,
+ gchar fill_char) G_GNUC_MALLOC;
+gchar* g_strconcat (const gchar *string1,
+ ...) G_GNUC_MALLOC G_GNUC_NULL_TERMINATED;
+gchar* g_strjoin (const gchar *separator,
+ ...) G_GNUC_MALLOC G_GNUC_NULL_TERMINATED;
+
+/* Make a copy of a string interpreting C string -style escape
+ * sequences. Inverse of g_strescape. The recognized sequences are \b
+ * \f \n \r \t \\ \" and the octal format.
+ */
+gchar* g_strcompress (const gchar *source) G_GNUC_MALLOC;
+
+/* Copy a string escaping nonprintable characters like in C strings.
+ * Inverse of g_strcompress. The exceptions parameter, if non-NULL, points
+ * to a string containing characters that are not to be escaped.
+ *
+ * Deprecated API: gchar* g_strescape (const gchar *source);
+ * Luckily this function wasn't used much, using NULL as second parameter
+ * provides mostly identical semantics.
+ */
+gchar* g_strescape (const gchar *source,
+ const gchar *exceptions) G_GNUC_MALLOC;
+
+gpointer g_memdup (gconstpointer mem,
+ guint byte_size) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(2);
+
+/* NULL terminated string arrays.
+ * g_strsplit(), g_strsplit_set() split up string into max_tokens tokens
+ * at delim and return a newly allocated string array.
+ * g_strjoinv() concatenates all of str_array's strings, sliding in an
+ * optional separator, the returned string is newly allocated.
+ * g_strfreev() frees the array itself and all of its strings.
+ * g_strdupv() copies a NULL-terminated array of strings
+ * g_strv_length() returns the length of a NULL-terminated array of strings
+ */
+gchar** g_strsplit (const gchar *string,
+ const gchar *delimiter,
+ gint max_tokens) G_GNUC_MALLOC;
+gchar ** g_strsplit_set (const gchar *string,
+ const gchar *delimiters,
+ gint max_tokens) G_GNUC_MALLOC;
+gchar* g_strjoinv (const gchar *separator,
+ gchar **str_array) G_GNUC_MALLOC;
+void g_strfreev (gchar **str_array);
+gchar** g_strdupv (gchar **str_array) G_GNUC_MALLOC;
+guint g_strv_length (gchar **str_array);
+
+gchar* g_stpcpy (gchar *dest,
+ const char *src);
+
+G_CONST_RETURN gchar *g_strip_context (const gchar *msgid,
+ const gchar *msgval) G_GNUC_FORMAT(1);
+
+G_CONST_RETURN gchar *g_dgettext (const gchar *domain,
+ const gchar *msgid) G_GNUC_FORMAT(2);
+G_CONST_RETURN gchar *g_dcgettext (const gchar *domain,
+ const gchar *msgid,
+ int category) G_GNUC_FORMAT(2);
+G_CONST_RETURN gchar *g_dngettext (const gchar *domain,
+ const gchar *msgid,
+ const gchar *msgid_plural,
+ gulong n) G_GNUC_FORMAT(3);
+G_CONST_RETURN gchar *g_dpgettext (const gchar *domain,
+ const gchar *msgctxtid,
+ gsize msgidoffset) G_GNUC_FORMAT(2);
+G_CONST_RETURN gchar *g_dpgettext2 (const gchar *domain,
+ const gchar *context,
+ const gchar *msgid) G_GNUC_FORMAT(3);
+
+G_END_DECLS
+
+#endif /* __G_STRFUNCS_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gstring.h b/protocols/Sametime/src/glib/include/glib/gstring.h
new file mode 100644
index 0000000000..2b1dd6ece2
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gstring.h
@@ -0,0 +1,178 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_STRING_H__
+#define __G_STRING_H__
+
+#include <glib/gtypes.h>
+#include <glib/gunicode.h>
+#include <glib/gutils.h> /* for G_CAN_INLINE */
+
+G_BEGIN_DECLS
+
+typedef struct _GString GString;
+typedef struct _GStringChunk GStringChunk;
+
+struct _GString
+{
+ gchar *str;
+ gsize len;
+ gsize allocated_len;
+};
+
+/* String Chunks
+ */
+GStringChunk* g_string_chunk_new (gsize size);
+void g_string_chunk_free (GStringChunk *chunk);
+void g_string_chunk_clear (GStringChunk *chunk);
+gchar* g_string_chunk_insert (GStringChunk *chunk,
+ const gchar *string);
+gchar* g_string_chunk_insert_len (GStringChunk *chunk,
+ const gchar *string,
+ gssize len);
+gchar* g_string_chunk_insert_const (GStringChunk *chunk,
+ const gchar *string);
+
+
+/* Strings
+ */
+GString* g_string_new (const gchar *init);
+GString* g_string_new_len (const gchar *init,
+ gssize len);
+GString* g_string_sized_new (gsize dfl_size);
+gchar* g_string_free (GString *string,
+ gboolean free_segment);
+gboolean g_string_equal (const GString *v,
+ const GString *v2);
+guint g_string_hash (const GString *str);
+GString* g_string_assign (GString *string,
+ const gchar *rval);
+GString* g_string_truncate (GString *string,
+ gsize len);
+GString* g_string_set_size (GString *string,
+ gsize len);
+GString* g_string_insert_len (GString *string,
+ gssize pos,
+ const gchar *val,
+ gssize len);
+GString* g_string_append (GString *string,
+ const gchar *val);
+GString* g_string_append_len (GString *string,
+ const gchar *val,
+ gssize len);
+GString* g_string_append_c (GString *string,
+ gchar c);
+GString* g_string_append_unichar (GString *string,
+ gunichar wc);
+GString* g_string_prepend (GString *string,
+ const gchar *val);
+GString* g_string_prepend_c (GString *string,
+ gchar c);
+GString* g_string_prepend_unichar (GString *string,
+ gunichar wc);
+GString* g_string_prepend_len (GString *string,
+ const gchar *val,
+ gssize len);
+GString* g_string_insert (GString *string,
+ gssize pos,
+ const gchar *val);
+GString* g_string_insert_c (GString *string,
+ gssize pos,
+ gchar c);
+GString* g_string_insert_unichar (GString *string,
+ gssize pos,
+ gunichar wc);
+GString* g_string_overwrite (GString *string,
+ gsize pos,
+ const gchar *val);
+GString* g_string_overwrite_len (GString *string,
+ gsize pos,
+ const gchar *val,
+ gssize len);
+GString* g_string_erase (GString *string,
+ gssize pos,
+ gssize len);
+GString* g_string_ascii_down (GString *string);
+GString* g_string_ascii_up (GString *string);
+void g_string_vprintf (GString *string,
+ const gchar *format,
+ va_list args);
+void g_string_printf (GString *string,
+ const gchar *format,
+ ...) G_GNUC_PRINTF (2, 3);
+void g_string_append_vprintf (GString *string,
+ const gchar *format,
+ va_list args);
+void g_string_append_printf (GString *string,
+ const gchar *format,
+ ...) G_GNUC_PRINTF (2, 3);
+GString * g_string_append_uri_escaped(GString *string,
+ const char *unescaped,
+ const char *reserved_chars_allowed,
+ gboolean allow_utf8);
+
+/* -- optimize g_strig_append_c --- */
+#ifdef G_CAN_INLINE
+static inline GString*
+g_string_append_c_inline (GString *gstring,
+ gchar c)
+{
+ if (gstring->len + 1 < gstring->allocated_len)
+ {
+ gstring->str[gstring->len++] = c;
+ gstring->str[gstring->len] = 0;
+ }
+ else
+ g_string_insert_c (gstring, -1, c);
+ return gstring;
+}
+#define g_string_append_c(gstr,c) g_string_append_c_inline (gstr, c)
+#endif /* G_CAN_INLINE */
+
+
+#ifndef G_DISABLE_DEPRECATED
+
+/* The following two functions are deprecated and will be removed in
+ * the next major release. They use the locale-specific tolower and
+ * toupper, which is almost never the right thing.
+ */
+
+GString* g_string_down (GString *string);
+GString* g_string_up (GString *string);
+
+/* These aliases are included for compatibility. */
+#define g_string_sprintf g_string_printf
+#define g_string_sprintfa g_string_append_printf
+
+#endif /* G_DISABLE_DEPRECATED */
+
+G_END_DECLS
+
+#endif /* __G_STRING_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gtestutils.h b/protocols/Sametime/src/glib/include/glib/gtestutils.h
new file mode 100644
index 0000000000..b441fe08bc
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gtestutils.h
@@ -0,0 +1,297 @@
+/* GLib testing utilities
+ * Copyright (C) 2007 Imendio AB
+ * Authors: Tim Janik
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_TEST_UTILS_H__
+#define __G_TEST_UTILS_H__
+
+#include <glib/gmessages.h>
+#include <glib/gstring.h>
+#include <glib/gerror.h>
+#include <glib/gslist.h>
+
+G_BEGIN_DECLS
+
+typedef struct GTestCase GTestCase;
+typedef struct GTestSuite GTestSuite;
+typedef void (*GTestFunc) (void);
+typedef void (*GTestDataFunc) (gconstpointer user_data);
+typedef void (*GTestFixtureFunc) (gpointer fixture,
+ gconstpointer user_data);
+
+/* assertion API */
+#define g_assert_cmpstr(s1, cmp, s2) do { const char *__s1 = (s1), *__s2 = (s2); \
+ if (g_strcmp0 (__s1, __s2) cmp 0) ; else \
+ g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
+ #s1 " " #cmp " " #s2, __s1, #cmp, __s2); } while (0)
+#define g_assert_cmpint(n1, cmp, n2) do { gint64 __n1 = (n1), __n2 = (n2); \
+ if (__n1 cmp __n2) ; else \
+ g_assertion_message_cmpnum (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
+ #n1 " " #cmp " " #n2, __n1, #cmp, __n2, 'i'); } while (0)
+#define g_assert_cmpuint(n1, cmp, n2) do { guint64 __n1 = (n1), __n2 = (n2); \
+ if (__n1 cmp __n2) ; else \
+ g_assertion_message_cmpnum (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
+ #n1 " " #cmp " " #n2, __n1, #cmp, __n2, 'i'); } while (0)
+#define g_assert_cmphex(n1, cmp, n2) do { guint64 __n1 = (n1), __n2 = (n2); \
+ if (__n1 cmp __n2) ; else \
+ g_assertion_message_cmpnum (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
+ #n1 " " #cmp " " #n2, __n1, #cmp, __n2, 'x'); } while (0)
+#define g_assert_cmpfloat(n1,cmp,n2) do { long double __n1 = (n1), __n2 = (n2); \
+ if (__n1 cmp __n2) ; else \
+ g_assertion_message_cmpnum (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
+ #n1 " " #cmp " " #n2, __n1, #cmp, __n2, 'f'); } while (0)
+#define g_assert_no_error(err) do { if (err) \
+ g_assertion_message_error (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
+ #err, err, 0, 0); } while (0)
+#define g_assert_error(err, dom, c) do { if (!err || (err)->domain != dom || (err)->code != c) \
+ g_assertion_message_error (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
+ #err, err, dom, c); } while (0)
+#ifdef G_DISABLE_ASSERT
+#define g_assert_not_reached() do { (void) 0; } while (0)
+#define g_assert(expr) do { (void) 0; } while (0)
+#else /* !G_DISABLE_ASSERT */
+#define g_assert_not_reached() do { g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, NULL); } while (0)
+#define g_assert(expr) do { if G_LIKELY (expr) ; else \
+ g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
+ #expr); } while (0)
+#endif /* !G_DISABLE_ASSERT */
+
+int g_strcmp0 (const char *str1,
+ const char *str2);
+
+/* report performance results */
+void g_test_minimized_result (double minimized_quantity,
+ const char *format,
+ ...) G_GNUC_PRINTF (2, 3);
+void g_test_maximized_result (double maximized_quantity,
+ const char *format,
+ ...) G_GNUC_PRINTF (2, 3);
+
+/* initialize testing framework */
+void g_test_init (int *argc,
+ char ***argv,
+ ...);
+/* query testing framework config */
+#define g_test_quick() (g_test_config_vars->test_quick)
+#define g_test_slow() (!g_test_config_vars->test_quick)
+#define g_test_thorough() (!g_test_config_vars->test_quick)
+#define g_test_perf() (g_test_config_vars->test_perf)
+#define g_test_verbose() (g_test_config_vars->test_verbose)
+#define g_test_quiet() (g_test_config_vars->test_quiet)
+/* run all tests under toplevel suite (path: /) */
+int g_test_run (void);
+/* hook up a test functions under test path */
+void g_test_add_func (const char *testpath,
+ GTestFunc test_func);
+
+void g_test_add_data_func (const char *testpath,
+ gconstpointer test_data,
+ GTestDataFunc test_func);
+
+/* hook up a test with fixture under test path */
+#define g_test_add(testpath, Fixture, tdata, fsetup, ftest, fteardown) \
+ G_STMT_START { \
+ void (*add_vtable) (const char*, \
+ gsize, \
+ gconstpointer, \
+ void (*) (Fixture*, gconstpointer), \
+ void (*) (Fixture*, gconstpointer), \
+ void (*) (Fixture*, gconstpointer)) = (void (*) (const gchar *, gsize, gconstpointer, void (*) (Fixture*, gconstpointer), void (*) (Fixture*, gconstpointer), void (*) (Fixture*, gconstpointer))) g_test_add_vtable; \
+ add_vtable \
+ (testpath, sizeof (Fixture), tdata, fsetup, ftest, fteardown); \
+ } G_STMT_END
+
+/* add test messages to the test report */
+void g_test_message (const char *format,
+ ...) G_GNUC_PRINTF (1, 2);
+void g_test_bug_base (const char *uri_pattern);
+void g_test_bug (const char *bug_uri_snippet);
+/* measure test timings */
+void g_test_timer_start (void);
+double g_test_timer_elapsed (void); /* elapsed seconds */
+double g_test_timer_last (void); /* repeat last elapsed() result */
+
+/* automatically g_free or g_object_unref upon teardown */
+void g_test_queue_free (gpointer gfree_pointer);
+void g_test_queue_destroy (GDestroyNotify destroy_func,
+ gpointer destroy_data);
+#define g_test_queue_unref(gobject) g_test_queue_destroy (g_object_unref, gobject)
+
+/* test traps are guards used around forked tests */
+typedef enum {
+ G_TEST_TRAP_SILENCE_STDOUT = 1 << 7,
+ G_TEST_TRAP_SILENCE_STDERR = 1 << 8,
+ G_TEST_TRAP_INHERIT_STDIN = 1 << 9
+} GTestTrapFlags;
+gboolean g_test_trap_fork (guint64 usec_timeout,
+ GTestTrapFlags test_trap_flags);
+gboolean g_test_trap_has_passed (void);
+gboolean g_test_trap_reached_timeout (void);
+#define g_test_trap_assert_passed() g_test_trap_assertions (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, 0, 0)
+#define g_test_trap_assert_failed() g_test_trap_assertions (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, 1, 0)
+#define g_test_trap_assert_stdout(soutpattern) g_test_trap_assertions (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, 2, soutpattern)
+#define g_test_trap_assert_stdout_unmatched(soutpattern) g_test_trap_assertions (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, 3, soutpattern)
+#define g_test_trap_assert_stderr(serrpattern) g_test_trap_assertions (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, 4, serrpattern)
+#define g_test_trap_assert_stderr_unmatched(serrpattern) g_test_trap_assertions (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, 5, serrpattern)
+
+/* provide seed-able random numbers for tests */
+#define g_test_rand_bit() (0 != (g_test_rand_int() & (1 << 15)))
+gint32 g_test_rand_int (void);
+gint32 g_test_rand_int_range (gint32 begin,
+ gint32 end);
+double g_test_rand_double (void);
+double g_test_rand_double_range (double range_start,
+ double range_end);
+
+/* semi-internal API */
+GTestCase* g_test_create_case (const char *test_name,
+ gsize data_size,
+ gconstpointer test_data,
+ GTestFixtureFunc data_setup,
+ GTestFixtureFunc data_test,
+ GTestFixtureFunc data_teardown);
+GTestSuite* g_test_create_suite (const char *suite_name);
+GTestSuite* g_test_get_root (void);
+void g_test_suite_add (GTestSuite *suite,
+ GTestCase *test_case);
+void g_test_suite_add_suite (GTestSuite *suite,
+ GTestSuite *nestedsuite);
+int g_test_run_suite (GTestSuite *suite);
+
+/* internal ABI */
+void g_test_trap_assertions (const char *domain,
+ const char *file,
+ int line,
+ const char *func,
+ guint64 assertion_flags, /* 0-pass, 1-fail, 2-outpattern, 4-errpattern */
+ const char *pattern);
+void g_assertion_message (const char *domain,
+ const char *file,
+ int line,
+ const char *func,
+ const char *message) G_GNUC_NORETURN;
+void g_assertion_message_expr (const char *domain,
+ const char *file,
+ int line,
+ const char *func,
+ const char *expr) G_GNUC_NORETURN;
+void g_assertion_message_cmpstr (const char *domain,
+ const char *file,
+ int line,
+ const char *func,
+ const char *expr,
+ const char *arg1,
+ const char *cmp,
+ const char *arg2) G_GNUC_NORETURN;
+void g_assertion_message_cmpnum (const char *domain,
+ const char *file,
+ int line,
+ const char *func,
+ const char *expr,
+ long double arg1,
+ const char *cmp,
+ long double arg2,
+ char numtype) G_GNUC_NORETURN;
+void g_assertion_message_error (const char *domain,
+ const char *file,
+ int line,
+ const char *func,
+ const char *expr,
+ const GError *error,
+ GQuark error_domain,
+ int error_code) G_GNUC_NORETURN;
+void g_test_add_vtable (const char *testpath,
+ gsize data_size,
+ gconstpointer test_data,
+ GTestFixtureFunc data_setup,
+ GTestFixtureFunc data_test,
+ GTestFixtureFunc data_teardown);
+typedef struct {
+ gboolean test_initialized;
+ gboolean test_quick; /* disable thorough tests */
+ gboolean test_perf; /* run performance tests */
+ gboolean test_verbose; /* extra info */
+ gboolean test_quiet; /* reduce output */
+} GTestConfig;
+GLIB_VAR const GTestConfig * const g_test_config_vars;
+
+/* internal logging API */
+typedef enum {
+ G_TEST_LOG_NONE,
+ G_TEST_LOG_ERROR, /* s:msg */
+ G_TEST_LOG_START_BINARY, /* s:binaryname s:seed */
+ G_TEST_LOG_LIST_CASE, /* s:testpath */
+ G_TEST_LOG_SKIP_CASE, /* s:testpath */
+ G_TEST_LOG_START_CASE, /* s:testpath */
+ G_TEST_LOG_STOP_CASE, /* d:status d:nforks d:elapsed */
+ G_TEST_LOG_MIN_RESULT, /* s:blurb d:result */
+ G_TEST_LOG_MAX_RESULT, /* s:blurb d:result */
+ G_TEST_LOG_MESSAGE /* s:blurb */
+} GTestLogType;
+
+typedef struct {
+ GTestLogType log_type;
+ guint n_strings;
+ gchar **strings; /* NULL terminated */
+ guint n_nums;
+ long double *nums;
+} GTestLogMsg;
+typedef struct {
+ /*< private >*/
+ GString *data;
+ GSList *msgs;
+} GTestLogBuffer;
+
+const char* g_test_log_type_name (GTestLogType log_type);
+GTestLogBuffer* g_test_log_buffer_new (void);
+void g_test_log_buffer_free (GTestLogBuffer *tbuffer);
+void g_test_log_buffer_push (GTestLogBuffer *tbuffer,
+ guint n_bytes,
+ const guint8 *bytes);
+GTestLogMsg* g_test_log_buffer_pop (GTestLogBuffer *tbuffer);
+void g_test_log_msg_free (GTestLogMsg *tmsg);
+
+/**
+ * GTestLogFatalFunc:
+ * @log_domain: the log domain of the message
+ * @log_level: the log level of the message (including the fatal and recursion flags)
+ * @message: the message to process
+ * @user_data: user data, set in g_test_log_set_fatal_handler()
+ *
+ * Specifies the prototype of fatal log handler functions.
+ *
+ * Return value: %TRUE if the program should abort, %FALSE otherwise
+ *
+ * Since: 2.22
+ */
+typedef gboolean (*GTestLogFatalFunc) (const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *message,
+ gpointer user_data);
+void
+g_test_log_set_fatal_handler (GTestLogFatalFunc log_func,
+ gpointer user_data);
+
+G_END_DECLS
+
+#endif /* __G_TEST_UTILS_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gthread.h b/protocols/Sametime/src/glib/include/glib/gthread.h
new file mode 100644
index 0000000000..82d40c0b85
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gthread.h
@@ -0,0 +1,407 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_THREAD_H__
+#define __G_THREAD_H__
+
+#include <glib/gerror.h>
+#include <glib/gutils.h> /* for G_INLINE_FUNC */
+#include <glib/gatomic.h> /* for g_atomic_pointer_get */
+
+G_BEGIN_DECLS
+
+/* GLib Thread support
+ */
+
+extern GQuark g_thread_error_quark (void);
+#define G_THREAD_ERROR g_thread_error_quark ()
+
+typedef enum
+{
+ G_THREAD_ERROR_AGAIN /* Resource temporarily unavailable */
+} GThreadError;
+
+typedef gpointer (*GThreadFunc) (gpointer data);
+
+typedef enum
+{
+ G_THREAD_PRIORITY_LOW,
+ G_THREAD_PRIORITY_NORMAL,
+ G_THREAD_PRIORITY_HIGH,
+ G_THREAD_PRIORITY_URGENT
+} GThreadPriority;
+
+typedef struct _GThread GThread;
+struct _GThread
+{
+ /*< private >*/
+ GThreadFunc func;
+ gpointer data;
+ gboolean joinable;
+ GThreadPriority priority;
+};
+
+typedef struct _GMutex GMutex;
+typedef struct _GCond GCond;
+typedef struct _GPrivate GPrivate;
+typedef struct _GStaticPrivate GStaticPrivate;
+
+typedef struct _GThreadFunctions GThreadFunctions;
+struct _GThreadFunctions
+{
+ GMutex* (*mutex_new) (void);
+ void (*mutex_lock) (GMutex *mutex);
+ gboolean (*mutex_trylock) (GMutex *mutex);
+ void (*mutex_unlock) (GMutex *mutex);
+ void (*mutex_free) (GMutex *mutex);
+ GCond* (*cond_new) (void);
+ void (*cond_signal) (GCond *cond);
+ void (*cond_broadcast) (GCond *cond);
+ void (*cond_wait) (GCond *cond,
+ GMutex *mutex);
+ gboolean (*cond_timed_wait) (GCond *cond,
+ GMutex *mutex,
+ GTimeVal *end_time);
+ void (*cond_free) (GCond *cond);
+ GPrivate* (*private_new) (GDestroyNotify destructor);
+ gpointer (*private_get) (GPrivate *private_key);
+ void (*private_set) (GPrivate *private_key,
+ gpointer data);
+ void (*thread_create) (GThreadFunc func,
+ gpointer data,
+ gulong stack_size,
+ gboolean joinable,
+ gboolean bound,
+ GThreadPriority priority,
+ gpointer thread,
+ GError **error);
+ void (*thread_yield) (void);
+ void (*thread_join) (gpointer thread);
+ void (*thread_exit) (void);
+ void (*thread_set_priority)(gpointer thread,
+ GThreadPriority priority);
+ void (*thread_self) (gpointer thread);
+ gboolean (*thread_equal) (gpointer thread1,
+ gpointer thread2);
+};
+
+GLIB_VAR GThreadFunctions g_thread_functions_for_glib_use;
+GLIB_VAR gboolean g_thread_use_default_impl;
+GLIB_VAR gboolean g_threads_got_initialized;
+
+GLIB_VAR guint64 (*g_thread_gettime) (void);
+
+/* initializes the mutex/cond/private implementation for glib, might
+ * only be called once, and must not be called directly or indirectly
+ * from another glib-function, e.g. as a callback.
+ */
+void g_thread_init (GThreadFunctions *vtable);
+
+/* Errorcheck mutexes. If you define G_ERRORCHECK_MUTEXES, then all
+ * mutexes will check for re-locking and re-unlocking */
+
+/* Initialize thread system with errorcheck mutexes. vtable must be
+ * NULL. Do not call directly. Use #define G_ERRORCHECK_MUTEXES
+ * instead.
+ */
+void g_thread_init_with_errorcheck_mutexes (GThreadFunctions* vtable);
+
+/* Checks if thread support is initialized. Identical to the
+ * g_thread_supported macro but provided for language bindings.
+ */
+gboolean g_thread_get_initialized (void);
+
+/* A random number to recognize debug calls to g_mutex_... */
+#define G_MUTEX_DEBUG_MAGIC 0xf8e18ad7
+
+#ifdef G_ERRORCHECK_MUTEXES
+#define g_thread_init(vtable) g_thread_init_with_errorcheck_mutexes (vtable)
+#endif
+
+/* internal function for fallback static mutex implementation */
+GMutex* g_static_mutex_get_mutex_impl (GMutex **mutex);
+
+#define g_static_mutex_get_mutex_impl_shortcut(mutex) \
+ (g_atomic_pointer_get (mutex) ? *(mutex) : \
+ g_static_mutex_get_mutex_impl (mutex))
+
+/* shorthands for conditional and unconditional function calls */
+
+#define G_THREAD_UF(op, arglist) \
+ (*g_thread_functions_for_glib_use . op) arglist
+#define G_THREAD_CF(op, fail, arg) \
+ (g_thread_supported () ? G_THREAD_UF (op, arg) : (fail))
+#define G_THREAD_ECF(op, fail, mutex, type) \
+ (g_thread_supported () ? \
+ ((type(*)(GMutex*, const gulong, gchar const*)) \
+ (*g_thread_functions_for_glib_use . op)) \
+ (mutex, G_MUTEX_DEBUG_MAGIC, G_STRLOC) : (fail))
+
+#ifndef G_ERRORCHECK_MUTEXES
+# define g_mutex_lock(mutex) \
+ G_THREAD_CF (mutex_lock, (void)0, (mutex))
+# define g_mutex_trylock(mutex) \
+ G_THREAD_CF (mutex_trylock, TRUE, (mutex))
+# define g_mutex_unlock(mutex) \
+ G_THREAD_CF (mutex_unlock, (void)0, (mutex))
+# define g_mutex_free(mutex) \
+ G_THREAD_CF (mutex_free, (void)0, (mutex))
+# define g_cond_wait(cond, mutex) \
+ G_THREAD_CF (cond_wait, (void)0, (cond, mutex))
+# define g_cond_timed_wait(cond, mutex, abs_time) \
+ G_THREAD_CF (cond_timed_wait, TRUE, (cond, mutex, abs_time))
+#else /* G_ERRORCHECK_MUTEXES */
+# define g_mutex_lock(mutex) \
+ G_THREAD_ECF (mutex_lock, (void)0, (mutex), void)
+# define g_mutex_trylock(mutex) \
+ G_THREAD_ECF (mutex_trylock, TRUE, (mutex), gboolean)
+# define g_mutex_unlock(mutex) \
+ G_THREAD_ECF (mutex_unlock, (void)0, (mutex), void)
+# define g_mutex_free(mutex) \
+ G_THREAD_ECF (mutex_free, (void)0, (mutex), void)
+# define g_cond_wait(cond, mutex) \
+ (g_thread_supported () ? ((void(*)(GCond*, GMutex*, gulong, gchar*))\
+ g_thread_functions_for_glib_use.cond_wait) \
+ (cond, mutex, G_MUTEX_DEBUG_MAGIC, G_STRLOC) : (void) 0)
+# define g_cond_timed_wait(cond, mutex, abs_time) \
+ (g_thread_supported () ? \
+ ((gboolean(*)(GCond*, GMutex*, GTimeVal*, gulong, gchar*)) \
+ g_thread_functions_for_glib_use.cond_timed_wait) \
+ (cond, mutex, abs_time, G_MUTEX_DEBUG_MAGIC, G_STRLOC) : TRUE)
+#endif /* G_ERRORCHECK_MUTEXES */
+
+#if defined(G_THREADS_ENABLED) && defined(G_THREADS_MANDATORY)
+#define g_thread_supported() 1
+#else
+#define g_thread_supported() (g_threads_got_initialized)
+#endif
+#define g_mutex_new() G_THREAD_UF (mutex_new, ())
+#define g_cond_new() G_THREAD_UF (cond_new, ())
+#define g_cond_signal(cond) G_THREAD_CF (cond_signal, (void)0, (cond))
+#define g_cond_broadcast(cond) G_THREAD_CF (cond_broadcast, (void)0, (cond))
+#define g_cond_free(cond) G_THREAD_CF (cond_free, (void)0, (cond))
+#define g_private_new(destructor) G_THREAD_UF (private_new, (destructor))
+#define g_private_get(private_key) G_THREAD_CF (private_get, \
+ ((gpointer)private_key), \
+ (private_key))
+#define g_private_set(private_key, value) G_THREAD_CF (private_set, \
+ (void) (private_key = \
+ (GPrivate*) (value)), \
+ (private_key, value))
+#define g_thread_yield() G_THREAD_CF (thread_yield, (void)0, ())
+
+#define g_thread_create(func, data, joinable, error) \
+ (g_thread_create_full (func, data, 0, joinable, FALSE, \
+ G_THREAD_PRIORITY_NORMAL, error))
+
+GThread* g_thread_create_full (GThreadFunc func,
+ gpointer data,
+ gulong stack_size,
+ gboolean joinable,
+ gboolean bound,
+ GThreadPriority priority,
+ GError **error);
+GThread* g_thread_self (void);
+void g_thread_exit (gpointer retval);
+gpointer g_thread_join (GThread *thread);
+
+void g_thread_set_priority (GThread *thread,
+ GThreadPriority priority);
+
+/* GStaticMutexes can be statically initialized with the value
+ * G_STATIC_MUTEX_INIT, and then they can directly be used, that is
+ * much easier, than having to explicitly allocate the mutex before
+ * use
+ */
+#define g_static_mutex_lock(mutex) \
+ g_mutex_lock (g_static_mutex_get_mutex (mutex))
+#define g_static_mutex_trylock(mutex) \
+ g_mutex_trylock (g_static_mutex_get_mutex (mutex))
+#define g_static_mutex_unlock(mutex) \
+ g_mutex_unlock (g_static_mutex_get_mutex (mutex))
+void g_static_mutex_init (GStaticMutex *mutex);
+void g_static_mutex_free (GStaticMutex *mutex);
+
+struct _GStaticPrivate
+{
+ /*< private >*/
+ guint index;
+};
+#define G_STATIC_PRIVATE_INIT { 0 }
+void g_static_private_init (GStaticPrivate *private_key);
+gpointer g_static_private_get (GStaticPrivate *private_key);
+void g_static_private_set (GStaticPrivate *private_key,
+ gpointer data,
+ GDestroyNotify notify);
+void g_static_private_free (GStaticPrivate *private_key);
+
+typedef struct _GStaticRecMutex GStaticRecMutex;
+struct _GStaticRecMutex
+{
+ /*< private >*/
+ GStaticMutex mutex;
+ guint depth;
+ GSystemThread owner;
+};
+
+#define G_STATIC_REC_MUTEX_INIT { G_STATIC_MUTEX_INIT }
+void g_static_rec_mutex_init (GStaticRecMutex *mutex);
+void g_static_rec_mutex_lock (GStaticRecMutex *mutex);
+gboolean g_static_rec_mutex_trylock (GStaticRecMutex *mutex);
+void g_static_rec_mutex_unlock (GStaticRecMutex *mutex);
+void g_static_rec_mutex_lock_full (GStaticRecMutex *mutex,
+ guint depth);
+guint g_static_rec_mutex_unlock_full (GStaticRecMutex *mutex);
+void g_static_rec_mutex_free (GStaticRecMutex *mutex);
+
+typedef struct _GStaticRWLock GStaticRWLock;
+struct _GStaticRWLock
+{
+ /*< private >*/
+ GStaticMutex mutex;
+ GCond *read_cond;
+ GCond *write_cond;
+ guint read_counter;
+ gboolean have_writer;
+ guint want_to_read;
+ guint want_to_write;
+};
+
+#define G_STATIC_RW_LOCK_INIT { G_STATIC_MUTEX_INIT, NULL, NULL, 0, FALSE, 0, 0 }
+
+void g_static_rw_lock_init (GStaticRWLock* lock);
+void g_static_rw_lock_reader_lock (GStaticRWLock* lock);
+gboolean g_static_rw_lock_reader_trylock (GStaticRWLock* lock);
+void g_static_rw_lock_reader_unlock (GStaticRWLock* lock);
+void g_static_rw_lock_writer_lock (GStaticRWLock* lock);
+gboolean g_static_rw_lock_writer_trylock (GStaticRWLock* lock);
+void g_static_rw_lock_writer_unlock (GStaticRWLock* lock);
+void g_static_rw_lock_free (GStaticRWLock* lock);
+
+void g_thread_foreach (GFunc thread_func,
+ gpointer user_data);
+
+typedef enum
+{
+ G_ONCE_STATUS_NOTCALLED,
+ G_ONCE_STATUS_PROGRESS,
+ G_ONCE_STATUS_READY
+} GOnceStatus;
+
+typedef struct _GOnce GOnce;
+struct _GOnce
+{
+ volatile GOnceStatus status;
+ volatile gpointer retval;
+};
+
+#define G_ONCE_INIT { G_ONCE_STATUS_NOTCALLED, NULL }
+
+gpointer g_once_impl (GOnce *once, GThreadFunc func, gpointer arg);
+
+#ifdef G_ATOMIC_OP_MEMORY_BARRIER_NEEDED
+# define g_once(once, func, arg) g_once_impl ((once), (func), (arg))
+#else /* !G_ATOMIC_OP_MEMORY_BARRIER_NEEDED*/
+# define g_once(once, func, arg) \
+ (((once)->status == G_ONCE_STATUS_READY) ? \
+ (once)->retval : \
+ g_once_impl ((once), (func), (arg)))
+#endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */
+
+/* initialize-once guards, keyed by value_location */
+G_INLINE_FUNC gboolean g_once_init_enter (volatile gsize *value_location);
+gboolean g_once_init_enter_impl (volatile gsize *value_location);
+void g_once_init_leave (volatile gsize *value_location,
+ gsize initialization_value);
+#if defined (G_CAN_INLINE) || defined (__G_THREAD_C__)
+G_INLINE_FUNC gboolean
+g_once_init_enter (volatile gsize *value_location)
+{
+ if G_LIKELY ((gpointer) g_atomic_pointer_get (value_location) != NULL)
+ return FALSE;
+ else
+ return g_once_init_enter_impl (value_location);
+}
+#endif /* G_CAN_INLINE || __G_THREAD_C__ */
+
+/* these are some convenience macros that expand to nothing if GLib
+ * was configured with --disable-threads. for using StaticMutexes,
+ * you define them with G_LOCK_DEFINE_STATIC (name) or G_LOCK_DEFINE (name)
+ * if you need to export the mutex. With G_LOCK_EXTERN (name) you can
+ * declare such an globally defined lock. name is a unique identifier
+ * for the protected varibale or code portion. locking, testing and
+ * unlocking of such mutexes can be done with G_LOCK(), G_UNLOCK() and
+ * G_TRYLOCK() respectively.
+ */
+extern void glib_dummy_decl (void);
+#define G_LOCK_NAME(name) g__ ## name ## _lock
+#ifdef G_THREADS_ENABLED
+# define G_LOCK_DEFINE_STATIC(name) static G_LOCK_DEFINE (name)
+# define G_LOCK_DEFINE(name) \
+ GStaticMutex G_LOCK_NAME (name) = G_STATIC_MUTEX_INIT
+# define G_LOCK_EXTERN(name) extern GStaticMutex G_LOCK_NAME (name)
+
+# ifdef G_DEBUG_LOCKS
+# define G_LOCK(name) G_STMT_START{ \
+ g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \
+ "file %s: line %d (%s): locking: %s ", \
+ __FILE__, __LINE__, G_STRFUNC, \
+ #name); \
+ g_static_mutex_lock (&G_LOCK_NAME (name)); \
+ }G_STMT_END
+# define G_UNLOCK(name) G_STMT_START{ \
+ g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \
+ "file %s: line %d (%s): unlocking: %s ", \
+ __FILE__, __LINE__, G_STRFUNC, \
+ #name); \
+ g_static_mutex_unlock (&G_LOCK_NAME (name)); \
+ }G_STMT_END
+# define G_TRYLOCK(name) \
+ (g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \
+ "file %s: line %d (%s): try locking: %s ", \
+ __FILE__, __LINE__, G_STRFUNC, \
+ #name), g_static_mutex_trylock (&G_LOCK_NAME (name)))
+# else /* !G_DEBUG_LOCKS */
+# define G_LOCK(name) g_static_mutex_lock (&G_LOCK_NAME (name))
+# define G_UNLOCK(name) g_static_mutex_unlock (&G_LOCK_NAME (name))
+# define G_TRYLOCK(name) g_static_mutex_trylock (&G_LOCK_NAME (name))
+# endif /* !G_DEBUG_LOCKS */
+#else /* !G_THREADS_ENABLED */
+# define G_LOCK_DEFINE_STATIC(name) extern void glib_dummy_decl (void)
+# define G_LOCK_DEFINE(name) extern void glib_dummy_decl (void)
+# define G_LOCK_EXTERN(name) extern void glib_dummy_decl (void)
+# define G_LOCK(name)
+# define G_UNLOCK(name)
+# define G_TRYLOCK(name) (TRUE)
+#endif /* !G_THREADS_ENABLED */
+
+G_END_DECLS
+
+#endif /* __G_THREAD_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gthreadpool.h b/protocols/Sametime/src/glib/include/glib/gthreadpool.h
new file mode 100644
index 0000000000..d5864241e6
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gthreadpool.h
@@ -0,0 +1,114 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_THREADPOOL_H__
+#define __G_THREADPOOL_H__
+
+#include <glib/gthread.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GThreadPool GThreadPool;
+
+/* Thread Pools
+ */
+
+/* The real GThreadPool is bigger, so you may only create a thread
+ * pool with the constructor function */
+struct _GThreadPool
+{
+ GFunc func;
+ gpointer user_data;
+ gboolean exclusive;
+};
+
+/* Get a thread pool with the function func, at most max_threads may
+ * run at a time (max_threads == -1 means no limit), exclusive == TRUE
+ * means, that the threads shouldn't be shared and that they will be
+ * prestarted (otherwise they are started as needed) user_data is the
+ * 2nd argument to the func */
+GThreadPool* g_thread_pool_new (GFunc func,
+ gpointer user_data,
+ gint max_threads,
+ gboolean exclusive,
+ GError **error);
+
+/* Push new data into the thread pool. This task is assigned to a thread later
+ * (when the maximal number of threads is reached for that pool) or now
+ * (otherwise). If necessary a new thread will be started. The function
+ * returns immediatly */
+void g_thread_pool_push (GThreadPool *pool,
+ gpointer data,
+ GError **error);
+
+/* Set the number of threads, which can run concurrently for that pool, -1
+ * means no limit. 0 means has the effect, that the pool won't process
+ * requests until the limit is set higher again */
+void g_thread_pool_set_max_threads (GThreadPool *pool,
+ gint max_threads,
+ GError **error);
+gint g_thread_pool_get_max_threads (GThreadPool *pool);
+
+/* Get the number of threads assigned to that pool. This number doesn't
+ * necessarily represent the number of working threads in that pool */
+guint g_thread_pool_get_num_threads (GThreadPool *pool);
+
+/* Get the number of unprocessed items in the pool */
+guint g_thread_pool_unprocessed (GThreadPool *pool);
+
+/* Free the pool, immediate means, that all unprocessed items in the queue
+ * wont be processed, wait means, that the function doesn't return immediatly,
+ * but after all threads in the pool are ready processing items. immediate
+ * does however not mean, that threads are killed. */
+void g_thread_pool_free (GThreadPool *pool,
+ gboolean immediate,
+ gboolean wait_);
+
+/* Set the maximal number of unused threads before threads will be stopped by
+ * GLib, -1 means no limit */
+void g_thread_pool_set_max_unused_threads (gint max_threads);
+gint g_thread_pool_get_max_unused_threads (void);
+guint g_thread_pool_get_num_unused_threads (void);
+
+/* Stop all currently unused threads, but leave the limit untouched */
+void g_thread_pool_stop_unused_threads (void);
+
+/* Set sort function for priority threading */
+void g_thread_pool_set_sort_function (GThreadPool *pool,
+ GCompareDataFunc func,
+ gpointer user_data);
+
+/* Set maximum time a thread can be idle in the pool before it is stopped */
+void g_thread_pool_set_max_idle_time (guint interval);
+guint g_thread_pool_get_max_idle_time (void);
+
+G_END_DECLS
+
+#endif /* __G_THREADPOOL_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gtimer.h b/protocols/Sametime/src/glib/include/glib/gtimer.h
new file mode 100644
index 0000000000..743eed1f90
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gtimer.h
@@ -0,0 +1,65 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_TIMER_H__
+#define __G_TIMER_H__
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+/* Timer
+ */
+
+/* microseconds per second */
+typedef struct _GTimer GTimer;
+
+#define G_USEC_PER_SEC 1000000
+
+GTimer* g_timer_new (void);
+void g_timer_destroy (GTimer *timer);
+void g_timer_start (GTimer *timer);
+void g_timer_stop (GTimer *timer);
+void g_timer_reset (GTimer *timer);
+void g_timer_continue (GTimer *timer);
+gdouble g_timer_elapsed (GTimer *timer,
+ gulong *microseconds);
+
+void g_usleep (gulong microseconds);
+
+void g_time_val_add (GTimeVal *time_,
+ glong microseconds);
+gboolean g_time_val_from_iso8601 (const gchar *iso_date,
+ GTimeVal *time_);
+gchar* g_time_val_to_iso8601 (GTimeVal *time_) G_GNUC_MALLOC;
+
+G_END_DECLS
+
+#endif /* __G_TIMER_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gtimezone.h b/protocols/Sametime/src/glib/include/glib/gtimezone.h
new file mode 100644
index 0000000000..1032a3c09c
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gtimezone.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright © 2010 Codethink Limited
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * Author: Ryan Lortie <desrt@desrt.ca>
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_TIME_ZONE_H__
+#define __G_TIME_ZONE_H__
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GTimeZone GTimeZone;
+
+GTimeZone * g_time_zone_new (const gchar *identifier);
+GTimeZone * g_time_zone_new_utc (void);
+GTimeZone * g_time_zone_new_local (void);
+
+GTimeZone * g_time_zone_ref (GTimeZone *tz);
+void g_time_zone_unref (GTimeZone *tz);
+
+G_END_DECLS
+
+#endif /* __G_TIME_ZONE_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gtree.h b/protocols/Sametime/src/glib/include/glib/gtree.h
new file mode 100644
index 0000000000..db06ba3b82
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gtree.h
@@ -0,0 +1,91 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_TREE_H__
+#define __G_TREE_H__
+
+#include <glib/gnode.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GTree GTree;
+
+typedef gboolean (*GTraverseFunc) (gpointer key,
+ gpointer value,
+ gpointer data);
+
+/* Balanced binary trees
+ */
+GTree* g_tree_new (GCompareFunc key_compare_func);
+GTree* g_tree_new_with_data (GCompareDataFunc key_compare_func,
+ gpointer key_compare_data);
+GTree* g_tree_new_full (GCompareDataFunc key_compare_func,
+ gpointer key_compare_data,
+ GDestroyNotify key_destroy_func,
+ GDestroyNotify value_destroy_func);
+GTree* g_tree_ref (GTree *tree);
+void g_tree_unref (GTree *tree);
+void g_tree_destroy (GTree *tree);
+void g_tree_insert (GTree *tree,
+ gpointer key,
+ gpointer value);
+void g_tree_replace (GTree *tree,
+ gpointer key,
+ gpointer value);
+gboolean g_tree_remove (GTree *tree,
+ gconstpointer key);
+gboolean g_tree_steal (GTree *tree,
+ gconstpointer key);
+gpointer g_tree_lookup (GTree *tree,
+ gconstpointer key);
+gboolean g_tree_lookup_extended (GTree *tree,
+ gconstpointer lookup_key,
+ gpointer *orig_key,
+ gpointer *value);
+void g_tree_foreach (GTree *tree,
+ GTraverseFunc func,
+ gpointer user_data);
+
+#ifndef G_DISABLE_DEPRECATED
+void g_tree_traverse (GTree *tree,
+ GTraverseFunc traverse_func,
+ GTraverseType traverse_type,
+ gpointer user_data);
+#endif /* G_DISABLE_DEPRECATED */
+
+gpointer g_tree_search (GTree *tree,
+ GCompareFunc search_func,
+ gconstpointer user_data);
+gint g_tree_height (GTree *tree);
+gint g_tree_nnodes (GTree *tree);
+
+G_END_DECLS
+
+#endif /* __G_TREE_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gtypes.h b/protocols/Sametime/src/glib/include/glib/gtypes.h
new file mode 100644
index 0000000000..e616f9988c
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gtypes.h
@@ -0,0 +1,451 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_TYPES_H__
+#define __G_TYPES_H__
+
+#include <glibconfig.h>
+#include <glib/gmacros.h>
+
+G_BEGIN_DECLS
+
+/* Provide type definitions for commonly used types.
+ * These are useful because a "gint8" can be adjusted
+ * to be 1 byte (8 bits) on all platforms. Similarly and
+ * more importantly, "gint32" can be adjusted to be
+ * 4 bytes (32 bits) on all platforms.
+ */
+
+typedef char gchar;
+typedef short gshort;
+typedef long glong;
+typedef int gint;
+typedef gint gboolean;
+
+typedef unsigned char guchar;
+typedef unsigned short gushort;
+typedef unsigned long gulong;
+typedef unsigned int guint;
+
+typedef float gfloat;
+typedef double gdouble;
+
+/* Define min and max constants for the fixed size numerical types */
+#define G_MININT8 ((gint8) 0x80)
+#define G_MAXINT8 ((gint8) 0x7f)
+#define G_MAXUINT8 ((guint8) 0xff)
+
+#define G_MININT16 ((gint16) 0x8000)
+#define G_MAXINT16 ((gint16) 0x7fff)
+#define G_MAXUINT16 ((guint16) 0xffff)
+
+#define G_MININT32 ((gint32) 0x80000000)
+#define G_MAXINT32 ((gint32) 0x7fffffff)
+#define G_MAXUINT32 ((guint32) 0xffffffff)
+
+#define G_MININT64 ((gint64) G_GINT64_CONSTANT(0x8000000000000000))
+#define G_MAXINT64 G_GINT64_CONSTANT(0x7fffffffffffffff)
+#define G_MAXUINT64 G_GINT64_CONSTANT(0xffffffffffffffffU)
+
+typedef void* gpointer;
+typedef const void *gconstpointer;
+
+typedef gint (*GCompareFunc) (gconstpointer a,
+ gconstpointer b);
+typedef gint (*GCompareDataFunc) (gconstpointer a,
+ gconstpointer b,
+ gpointer user_data);
+typedef gboolean (*GEqualFunc) (gconstpointer a,
+ gconstpointer b);
+typedef void (*GDestroyNotify) (gpointer data);
+typedef void (*GFunc) (gpointer data,
+ gpointer user_data);
+typedef guint (*GHashFunc) (gconstpointer key);
+typedef void (*GHFunc) (gpointer key,
+ gpointer value,
+ gpointer user_data);
+typedef void (*GFreeFunc) (gpointer data);
+
+/**
+ * GTranslateFunc:
+ * @str: the untranslated string
+ * @data: user data specified when installing the function, e.g.
+ * in g_option_group_set_translate_func()
+ *
+ * The type of functions which are used to translate user-visible
+ * strings, for <option>--help</option> output.
+ *
+ * Returns: a translation of the string for the current locale.
+ * The returned string is owned by GLib and must not be freed.
+ */
+typedef const gchar * (*GTranslateFunc) (const gchar *str,
+ gpointer data);
+
+
+/* Define some mathematical constants that aren't available
+ * symbolically in some strict ISO C implementations.
+ *
+ * Note that the large number of digits used in these definitions
+ * doesn't imply that GLib or current computers in general would be
+ * able to handle floating point numbers with an accuracy like this.
+ * It's mostly an exercise in futility and future proofing. For
+ * extended precision floating point support, look somewhere else
+ * than GLib.
+ */
+#define G_E 2.7182818284590452353602874713526624977572470937000
+#define G_LN2 0.69314718055994530941723212145817656807550013436026
+#define G_LN10 2.3025850929940456840179914546843642076011014886288
+#define G_PI 3.1415926535897932384626433832795028841971693993751
+#define G_PI_2 1.5707963267948966192313216916397514420985846996876
+#define G_PI_4 0.78539816339744830961566084581987572104929234984378
+#define G_SQRT2 1.4142135623730950488016887242096980785696718753769
+
+/* Portable endian checks and conversions
+ *
+ * glibconfig.h defines G_BYTE_ORDER which expands to one of
+ * the below macros.
+ */
+#define G_LITTLE_ENDIAN 1234
+#define G_BIG_ENDIAN 4321
+#define G_PDP_ENDIAN 3412 /* unused, need specific PDP check */
+
+
+/* Basic bit swapping functions
+ */
+#define GUINT16_SWAP_LE_BE_CONSTANT(val) ((guint16) ( \
+ (guint16) ((guint16) (val) >> 8) | \
+ (guint16) ((guint16) (val) << 8)))
+
+#define GUINT32_SWAP_LE_BE_CONSTANT(val) ((guint32) ( \
+ (((guint32) (val) & (guint32) 0x000000ffU) << 24) | \
+ (((guint32) (val) & (guint32) 0x0000ff00U) << 8) | \
+ (((guint32) (val) & (guint32) 0x00ff0000U) >> 8) | \
+ (((guint32) (val) & (guint32) 0xff000000U) >> 24)))
+
+#define GUINT64_SWAP_LE_BE_CONSTANT(val) ((guint64) ( \
+ (((guint64) (val) & \
+ (guint64) G_GINT64_CONSTANT (0x00000000000000ffU)) << 56) | \
+ (((guint64) (val) & \
+ (guint64) G_GINT64_CONSTANT (0x000000000000ff00U)) << 40) | \
+ (((guint64) (val) & \
+ (guint64) G_GINT64_CONSTANT (0x0000000000ff0000U)) << 24) | \
+ (((guint64) (val) & \
+ (guint64) G_GINT64_CONSTANT (0x00000000ff000000U)) << 8) | \
+ (((guint64) (val) & \
+ (guint64) G_GINT64_CONSTANT (0x000000ff00000000U)) >> 8) | \
+ (((guint64) (val) & \
+ (guint64) G_GINT64_CONSTANT (0x0000ff0000000000U)) >> 24) | \
+ (((guint64) (val) & \
+ (guint64) G_GINT64_CONSTANT (0x00ff000000000000U)) >> 40) | \
+ (((guint64) (val) & \
+ (guint64) G_GINT64_CONSTANT (0xff00000000000000U)) >> 56)))
+
+/* Arch specific stuff for speed
+ */
+#if defined (__GNUC__) && (__GNUC__ >= 2) && defined (__OPTIMIZE__)
+# if defined (__i386__)
+# define GUINT16_SWAP_LE_BE_IA32(val) \
+ (__extension__ \
+ ({ register guint16 __v, __x = ((guint16) (val)); \
+ if (__builtin_constant_p (__x)) \
+ __v = GUINT16_SWAP_LE_BE_CONSTANT (__x); \
+ else \
+ __asm__ ("rorw $8, %w0" \
+ : "=r" (__v) \
+ : "0" (__x) \
+ : "cc"); \
+ __v; }))
+# if !defined (__i486__) && !defined (__i586__) \
+ && !defined (__pentium__) && !defined (__i686__) \
+ && !defined (__pentiumpro__) && !defined (__pentium4__)
+# define GUINT32_SWAP_LE_BE_IA32(val) \
+ (__extension__ \
+ ({ register guint32 __v, __x = ((guint32) (val)); \
+ if (__builtin_constant_p (__x)) \
+ __v = GUINT32_SWAP_LE_BE_CONSTANT (__x); \
+ else \
+ __asm__ ("rorw $8, %w0\n\t" \
+ "rorl $16, %0\n\t" \
+ "rorw $8, %w0" \
+ : "=r" (__v) \
+ : "0" (__x) \
+ : "cc"); \
+ __v; }))
+# else /* 486 and higher has bswap */
+# define GUINT32_SWAP_LE_BE_IA32(val) \
+ (__extension__ \
+ ({ register guint32 __v, __x = ((guint32) (val)); \
+ if (__builtin_constant_p (__x)) \
+ __v = GUINT32_SWAP_LE_BE_CONSTANT (__x); \
+ else \
+ __asm__ ("bswap %0" \
+ : "=r" (__v) \
+ : "0" (__x)); \
+ __v; }))
+# endif /* processor specific 32-bit stuff */
+# define GUINT64_SWAP_LE_BE_IA32(val) \
+ (__extension__ \
+ ({ union { guint64 __ll; \
+ guint32 __l[2]; } __w, __r; \
+ __w.__ll = ((guint64) (val)); \
+ if (__builtin_constant_p (__w.__ll)) \
+ __r.__ll = GUINT64_SWAP_LE_BE_CONSTANT (__w.__ll); \
+ else \
+ { \
+ __r.__l[0] = GUINT32_SWAP_LE_BE (__w.__l[1]); \
+ __r.__l[1] = GUINT32_SWAP_LE_BE (__w.__l[0]); \
+ } \
+ __r.__ll; }))
+ /* Possibly just use the constant version and let gcc figure it out? */
+# define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_IA32 (val))
+# define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_IA32 (val))
+# define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_IA32 (val))
+# elif defined (__ia64__)
+# define GUINT16_SWAP_LE_BE_IA64(val) \
+ (__extension__ \
+ ({ register guint16 __v, __x = ((guint16) (val)); \
+ if (__builtin_constant_p (__x)) \
+ __v = GUINT16_SWAP_LE_BE_CONSTANT (__x); \
+ else \
+ __asm__ __volatile__ ("shl %0 = %1, 48 ;;" \
+ "mux1 %0 = %0, @rev ;;" \
+ : "=r" (__v) \
+ : "r" (__x)); \
+ __v; }))
+# define GUINT32_SWAP_LE_BE_IA64(val) \
+ (__extension__ \
+ ({ register guint32 __v, __x = ((guint32) (val)); \
+ if (__builtin_constant_p (__x)) \
+ __v = GUINT32_SWAP_LE_BE_CONSTANT (__x); \
+ else \
+ __asm__ __volatile__ ("shl %0 = %1, 32 ;;" \
+ "mux1 %0 = %0, @rev ;;" \
+ : "=r" (__v) \
+ : "r" (__x)); \
+ __v; }))
+# define GUINT64_SWAP_LE_BE_IA64(val) \
+ (__extension__ \
+ ({ register guint64 __v, __x = ((guint64) (val)); \
+ if (__builtin_constant_p (__x)) \
+ __v = GUINT64_SWAP_LE_BE_CONSTANT (__x); \
+ else \
+ __asm__ __volatile__ ("mux1 %0 = %1, @rev ;;" \
+ : "=r" (__v) \
+ : "r" (__x)); \
+ __v; }))
+# define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_IA64 (val))
+# define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_IA64 (val))
+# define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_IA64 (val))
+# elif defined (__x86_64__)
+# define GUINT32_SWAP_LE_BE_X86_64(val) \
+ (__extension__ \
+ ({ register guint32 __v, __x = ((guint32) (val)); \
+ if (__builtin_constant_p (__x)) \
+ __v = GUINT32_SWAP_LE_BE_CONSTANT (__x); \
+ else \
+ __asm__ ("bswapl %0" \
+ : "=r" (__v) \
+ : "0" (__x)); \
+ __v; }))
+# define GUINT64_SWAP_LE_BE_X86_64(val) \
+ (__extension__ \
+ ({ register guint64 __v, __x = ((guint64) (val)); \
+ if (__builtin_constant_p (__x)) \
+ __v = GUINT64_SWAP_LE_BE_CONSTANT (__x); \
+ else \
+ __asm__ ("bswapq %0" \
+ : "=r" (__v) \
+ : "0" (__x)); \
+ __v; }))
+ /* gcc seems to figure out optimal code for this on its own */
+# define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_CONSTANT (val))
+# define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_X86_64 (val))
+# define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_X86_64 (val))
+# else /* generic gcc */
+# define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_CONSTANT (val))
+# define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_CONSTANT (val))
+# define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_CONSTANT (val))
+# endif
+#else /* generic */
+# define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_CONSTANT (val))
+# define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_CONSTANT (val))
+# define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_CONSTANT (val))
+#endif /* generic */
+
+#define GUINT16_SWAP_LE_PDP(val) ((guint16) (val))
+#define GUINT16_SWAP_BE_PDP(val) (GUINT16_SWAP_LE_BE (val))
+#define GUINT32_SWAP_LE_PDP(val) ((guint32) ( \
+ (((guint32) (val) & (guint32) 0x0000ffffU) << 16) | \
+ (((guint32) (val) & (guint32) 0xffff0000U) >> 16)))
+#define GUINT32_SWAP_BE_PDP(val) ((guint32) ( \
+ (((guint32) (val) & (guint32) 0x00ff00ffU) << 8) | \
+ (((guint32) (val) & (guint32) 0xff00ff00U) >> 8)))
+
+/* The G*_TO_?E() macros are defined in glibconfig.h.
+ * The transformation is symmetric, so the FROM just maps to the TO.
+ */
+#define GINT16_FROM_LE(val) (GINT16_TO_LE (val))
+#define GUINT16_FROM_LE(val) (GUINT16_TO_LE (val))
+#define GINT16_FROM_BE(val) (GINT16_TO_BE (val))
+#define GUINT16_FROM_BE(val) (GUINT16_TO_BE (val))
+#define GINT32_FROM_LE(val) (GINT32_TO_LE (val))
+#define GUINT32_FROM_LE(val) (GUINT32_TO_LE (val))
+#define GINT32_FROM_BE(val) (GINT32_TO_BE (val))
+#define GUINT32_FROM_BE(val) (GUINT32_TO_BE (val))
+
+#define GINT64_FROM_LE(val) (GINT64_TO_LE (val))
+#define GUINT64_FROM_LE(val) (GUINT64_TO_LE (val))
+#define GINT64_FROM_BE(val) (GINT64_TO_BE (val))
+#define GUINT64_FROM_BE(val) (GUINT64_TO_BE (val))
+
+#define GLONG_FROM_LE(val) (GLONG_TO_LE (val))
+#define GULONG_FROM_LE(val) (GULONG_TO_LE (val))
+#define GLONG_FROM_BE(val) (GLONG_TO_BE (val))
+#define GULONG_FROM_BE(val) (GULONG_TO_BE (val))
+
+#define GINT_FROM_LE(val) (GINT_TO_LE (val))
+#define GUINT_FROM_LE(val) (GUINT_TO_LE (val))
+#define GINT_FROM_BE(val) (GINT_TO_BE (val))
+#define GUINT_FROM_BE(val) (GUINT_TO_BE (val))
+
+#define GSIZE_FROM_LE(val) (GSIZE_TO_LE (val))
+#define GSSIZE_FROM_LE(val) (GSSIZE_TO_LE (val))
+#define GSIZE_FROM_BE(val) (GSIZE_TO_BE (val))
+#define GSSIZE_FROM_BE(val) (GSSIZE_TO_BE (val))
+
+
+/* Portable versions of host-network order stuff
+ */
+#define g_ntohl(val) (GUINT32_FROM_BE (val))
+#define g_ntohs(val) (GUINT16_FROM_BE (val))
+#define g_htonl(val) (GUINT32_TO_BE (val))
+#define g_htons(val) (GUINT16_TO_BE (val))
+
+/* IEEE Standard 754 Single Precision Storage Format (gfloat):
+ *
+ * 31 30 23 22 0
+ * +--------+---------------+---------------+
+ * | s 1bit | e[30:23] 8bit | f[22:0] 23bit |
+ * +--------+---------------+---------------+
+ * B0------------------->B1------->B2-->B3-->
+ *
+ * IEEE Standard 754 Double Precision Storage Format (gdouble):
+ *
+ * 63 62 52 51 32 31 0
+ * +--------+----------------+----------------+ +---------------+
+ * | s 1bit | e[62:52] 11bit | f[51:32] 20bit | | f[31:0] 32bit |
+ * +--------+----------------+----------------+ +---------------+
+ * B0--------------->B1---------->B2--->B3----> B4->B5->B6->B7->
+ */
+/* subtract from biased_exponent to form base2 exponent (normal numbers) */
+typedef union _GDoubleIEEE754 GDoubleIEEE754;
+typedef union _GFloatIEEE754 GFloatIEEE754;
+#define G_IEEE754_FLOAT_BIAS (127)
+#define G_IEEE754_DOUBLE_BIAS (1023)
+/* multiply with base2 exponent to get base10 exponent (normal numbers) */
+#define G_LOG_2_BASE_10 (0.30102999566398119521)
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+union _GFloatIEEE754
+{
+ gfloat v_float;
+ struct {
+ guint mantissa : 23;
+ guint biased_exponent : 8;
+ guint sign : 1;
+ } mpn;
+};
+union _GDoubleIEEE754
+{
+ gdouble v_double;
+ struct {
+ guint mantissa_low : 32;
+ guint mantissa_high : 20;
+ guint biased_exponent : 11;
+ guint sign : 1;
+ } mpn;
+};
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+union _GFloatIEEE754
+{
+ gfloat v_float;
+ struct {
+ guint sign : 1;
+ guint biased_exponent : 8;
+ guint mantissa : 23;
+ } mpn;
+};
+union _GDoubleIEEE754
+{
+ gdouble v_double;
+ struct {
+ guint sign : 1;
+ guint biased_exponent : 11;
+ guint mantissa_high : 20;
+ guint mantissa_low : 32;
+ } mpn;
+};
+#else /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
+#error unknown ENDIAN type
+#endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
+
+typedef struct _GTimeVal GTimeVal;
+
+struct _GTimeVal
+{
+ glong tv_sec;
+ glong tv_usec;
+};
+
+G_END_DECLS
+
+/* We prefix variable declarations so they can
+ * properly get exported in Windows DLLs.
+ */
+#ifndef GLIB_VAR
+# ifdef G_PLATFORM_WIN32
+# ifdef GLIB_STATIC_COMPILATION
+# define GLIB_VAR extern
+# else /* !GLIB_STATIC_COMPILATION */
+# ifdef GLIB_COMPILATION
+# ifdef DLL_EXPORT
+# define GLIB_VAR __declspec(dllexport)
+# else /* !DLL_EXPORT */
+# define GLIB_VAR extern
+# endif /* !DLL_EXPORT */
+# else /* !GLIB_COMPILATION */
+# define GLIB_VAR extern __declspec(dllimport)
+# endif /* !GLIB_COMPILATION */
+# endif /* !GLIB_STATIC_COMPILATION */
+# else /* !G_PLATFORM_WIN32 */
+# define GLIB_VAR extern
+# endif /* !G_PLATFORM_WIN32 */
+#endif /* GLIB_VAR */
+
+#endif /* __G_TYPES_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gunicode.h b/protocols/Sametime/src/glib/include/glib/gunicode.h
new file mode 100644
index 0000000000..4ca7bd3017
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gunicode.h
@@ -0,0 +1,421 @@
+/* gunicode.h - Unicode manipulation functions
+ *
+ * Copyright (C) 1999, 2000 Tom Tromey
+ * Copyright 2000, 2005 Red Hat, Inc.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome 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 Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_UNICODE_H__
+#define __G_UNICODE_H__
+
+#include <glib/gerror.h>
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+typedef guint32 gunichar;
+typedef guint16 gunichar2;
+
+/* These are the possible character classifications.
+ * See http://www.unicode.org/Public/UNIDATA/UCD.html#General_Category_Values
+ */
+typedef enum
+{
+ G_UNICODE_CONTROL,
+ G_UNICODE_FORMAT,
+ G_UNICODE_UNASSIGNED,
+ G_UNICODE_PRIVATE_USE,
+ G_UNICODE_SURROGATE,
+ G_UNICODE_LOWERCASE_LETTER,
+ G_UNICODE_MODIFIER_LETTER,
+ G_UNICODE_OTHER_LETTER,
+ G_UNICODE_TITLECASE_LETTER,
+ G_UNICODE_UPPERCASE_LETTER,
+ G_UNICODE_COMBINING_MARK,
+ G_UNICODE_ENCLOSING_MARK,
+ G_UNICODE_NON_SPACING_MARK,
+ G_UNICODE_DECIMAL_NUMBER,
+ G_UNICODE_LETTER_NUMBER,
+ G_UNICODE_OTHER_NUMBER,
+ G_UNICODE_CONNECT_PUNCTUATION,
+ G_UNICODE_DASH_PUNCTUATION,
+ G_UNICODE_CLOSE_PUNCTUATION,
+ G_UNICODE_FINAL_PUNCTUATION,
+ G_UNICODE_INITIAL_PUNCTUATION,
+ G_UNICODE_OTHER_PUNCTUATION,
+ G_UNICODE_OPEN_PUNCTUATION,
+ G_UNICODE_CURRENCY_SYMBOL,
+ G_UNICODE_MODIFIER_SYMBOL,
+ G_UNICODE_MATH_SYMBOL,
+ G_UNICODE_OTHER_SYMBOL,
+ G_UNICODE_LINE_SEPARATOR,
+ G_UNICODE_PARAGRAPH_SEPARATOR,
+ G_UNICODE_SPACE_SEPARATOR
+} GUnicodeType;
+
+/* These are the possible line break classifications.
+ * Note that new types may be added in the future.
+ * Implementations may regard unknown values like G_UNICODE_BREAK_UNKNOWN
+ * See http://www.unicode.org/unicode/reports/tr14/
+ */
+typedef enum
+{
+ G_UNICODE_BREAK_MANDATORY,
+ G_UNICODE_BREAK_CARRIAGE_RETURN,
+ G_UNICODE_BREAK_LINE_FEED,
+ G_UNICODE_BREAK_COMBINING_MARK,
+ G_UNICODE_BREAK_SURROGATE,
+ G_UNICODE_BREAK_ZERO_WIDTH_SPACE,
+ G_UNICODE_BREAK_INSEPARABLE,
+ G_UNICODE_BREAK_NON_BREAKING_GLUE,
+ G_UNICODE_BREAK_CONTINGENT,
+ G_UNICODE_BREAK_SPACE,
+ G_UNICODE_BREAK_AFTER,
+ G_UNICODE_BREAK_BEFORE,
+ G_UNICODE_BREAK_BEFORE_AND_AFTER,
+ G_UNICODE_BREAK_HYPHEN,
+ G_UNICODE_BREAK_NON_STARTER,
+ G_UNICODE_BREAK_OPEN_PUNCTUATION,
+ G_UNICODE_BREAK_CLOSE_PUNCTUATION,
+ G_UNICODE_BREAK_QUOTATION,
+ G_UNICODE_BREAK_EXCLAMATION,
+ G_UNICODE_BREAK_IDEOGRAPHIC,
+ G_UNICODE_BREAK_NUMERIC,
+ G_UNICODE_BREAK_INFIX_SEPARATOR,
+ G_UNICODE_BREAK_SYMBOL,
+ G_UNICODE_BREAK_ALPHABETIC,
+ G_UNICODE_BREAK_PREFIX,
+ G_UNICODE_BREAK_POSTFIX,
+ G_UNICODE_BREAK_COMPLEX_CONTEXT,
+ G_UNICODE_BREAK_AMBIGUOUS,
+ G_UNICODE_BREAK_UNKNOWN,
+ G_UNICODE_BREAK_NEXT_LINE,
+ G_UNICODE_BREAK_WORD_JOINER,
+ G_UNICODE_BREAK_HANGUL_L_JAMO,
+ G_UNICODE_BREAK_HANGUL_V_JAMO,
+ G_UNICODE_BREAK_HANGUL_T_JAMO,
+ G_UNICODE_BREAK_HANGUL_LV_SYLLABLE,
+ G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE
+} GUnicodeBreakType;
+
+typedef enum
+{ /* ISO 15924 code */
+ G_UNICODE_SCRIPT_INVALID_CODE = -1,
+ G_UNICODE_SCRIPT_COMMON = 0, /* Zyyy */
+ G_UNICODE_SCRIPT_INHERITED, /* Qaai */
+ G_UNICODE_SCRIPT_ARABIC, /* Arab */
+ G_UNICODE_SCRIPT_ARMENIAN, /* Armn */
+ G_UNICODE_SCRIPT_BENGALI, /* Beng */
+ G_UNICODE_SCRIPT_BOPOMOFO, /* Bopo */
+ G_UNICODE_SCRIPT_CHEROKEE, /* Cher */
+ G_UNICODE_SCRIPT_COPTIC, /* Qaac */
+ G_UNICODE_SCRIPT_CYRILLIC, /* Cyrl (Cyrs) */
+ G_UNICODE_SCRIPT_DESERET, /* Dsrt */
+ G_UNICODE_SCRIPT_DEVANAGARI, /* Deva */
+ G_UNICODE_SCRIPT_ETHIOPIC, /* Ethi */
+ G_UNICODE_SCRIPT_GEORGIAN, /* Geor (Geon, Geoa) */
+ G_UNICODE_SCRIPT_GOTHIC, /* Goth */
+ G_UNICODE_SCRIPT_GREEK, /* Grek */
+ G_UNICODE_SCRIPT_GUJARATI, /* Gujr */
+ G_UNICODE_SCRIPT_GURMUKHI, /* Guru */
+ G_UNICODE_SCRIPT_HAN, /* Hani */
+ G_UNICODE_SCRIPT_HANGUL, /* Hang */
+ G_UNICODE_SCRIPT_HEBREW, /* Hebr */
+ G_UNICODE_SCRIPT_HIRAGANA, /* Hira */
+ G_UNICODE_SCRIPT_KANNADA, /* Knda */
+ G_UNICODE_SCRIPT_KATAKANA, /* Kana */
+ G_UNICODE_SCRIPT_KHMER, /* Khmr */
+ G_UNICODE_SCRIPT_LAO, /* Laoo */
+ G_UNICODE_SCRIPT_LATIN, /* Latn (Latf, Latg) */
+ G_UNICODE_SCRIPT_MALAYALAM, /* Mlym */
+ G_UNICODE_SCRIPT_MONGOLIAN, /* Mong */
+ G_UNICODE_SCRIPT_MYANMAR, /* Mymr */
+ G_UNICODE_SCRIPT_OGHAM, /* Ogam */
+ G_UNICODE_SCRIPT_OLD_ITALIC, /* Ital */
+ G_UNICODE_SCRIPT_ORIYA, /* Orya */
+ G_UNICODE_SCRIPT_RUNIC, /* Runr */
+ G_UNICODE_SCRIPT_SINHALA, /* Sinh */
+ G_UNICODE_SCRIPT_SYRIAC, /* Syrc (Syrj, Syrn, Syre) */
+ G_UNICODE_SCRIPT_TAMIL, /* Taml */
+ G_UNICODE_SCRIPT_TELUGU, /* Telu */
+ G_UNICODE_SCRIPT_THAANA, /* Thaa */
+ G_UNICODE_SCRIPT_THAI, /* Thai */
+ G_UNICODE_SCRIPT_TIBETAN, /* Tibt */
+ G_UNICODE_SCRIPT_CANADIAN_ABORIGINAL, /* Cans */
+ G_UNICODE_SCRIPT_YI, /* Yiii */
+ G_UNICODE_SCRIPT_TAGALOG, /* Tglg */
+ G_UNICODE_SCRIPT_HANUNOO, /* Hano */
+ G_UNICODE_SCRIPT_BUHID, /* Buhd */
+ G_UNICODE_SCRIPT_TAGBANWA, /* Tagb */
+
+ /* Unicode-4.0 additions */
+ G_UNICODE_SCRIPT_BRAILLE, /* Brai */
+ G_UNICODE_SCRIPT_CYPRIOT, /* Cprt */
+ G_UNICODE_SCRIPT_LIMBU, /* Limb */
+ G_UNICODE_SCRIPT_OSMANYA, /* Osma */
+ G_UNICODE_SCRIPT_SHAVIAN, /* Shaw */
+ G_UNICODE_SCRIPT_LINEAR_B, /* Linb */
+ G_UNICODE_SCRIPT_TAI_LE, /* Tale */
+ G_UNICODE_SCRIPT_UGARITIC, /* Ugar */
+
+ /* Unicode-4.1 additions */
+ G_UNICODE_SCRIPT_NEW_TAI_LUE, /* Talu */
+ G_UNICODE_SCRIPT_BUGINESE, /* Bugi */
+ G_UNICODE_SCRIPT_GLAGOLITIC, /* Glag */
+ G_UNICODE_SCRIPT_TIFINAGH, /* Tfng */
+ G_UNICODE_SCRIPT_SYLOTI_NAGRI, /* Sylo */
+ G_UNICODE_SCRIPT_OLD_PERSIAN, /* Xpeo */
+ G_UNICODE_SCRIPT_KHAROSHTHI, /* Khar */
+
+ /* Unicode-5.0 additions */
+ G_UNICODE_SCRIPT_UNKNOWN, /* Zzzz */
+ G_UNICODE_SCRIPT_BALINESE, /* Bali */
+ G_UNICODE_SCRIPT_CUNEIFORM, /* Xsux */
+ G_UNICODE_SCRIPT_PHOENICIAN, /* Phnx */
+ G_UNICODE_SCRIPT_PHAGS_PA, /* Phag */
+ G_UNICODE_SCRIPT_NKO, /* Nkoo */
+
+ /* Unicode-5.1 additions */
+ G_UNICODE_SCRIPT_KAYAH_LI, /* Kali */
+ G_UNICODE_SCRIPT_LEPCHA, /* Lepc */
+ G_UNICODE_SCRIPT_REJANG, /* Rjng */
+ G_UNICODE_SCRIPT_SUNDANESE, /* Sund */
+ G_UNICODE_SCRIPT_SAURASHTRA, /* Saur */
+ G_UNICODE_SCRIPT_CHAM, /* Cham */
+ G_UNICODE_SCRIPT_OL_CHIKI, /* Olck */
+ G_UNICODE_SCRIPT_VAI, /* Vaii */
+ G_UNICODE_SCRIPT_CARIAN, /* Cari */
+ G_UNICODE_SCRIPT_LYCIAN, /* Lyci */
+ G_UNICODE_SCRIPT_LYDIAN, /* Lydi */
+
+ /* Unicode-5.2 additions */
+ G_UNICODE_SCRIPT_AVESTAN, /* Avestan */
+ G_UNICODE_SCRIPT_BAMUM, /* Bamum */
+ G_UNICODE_SCRIPT_EGYPTIAN_HIEROGLYPHS, /* Egyptian Hieroglyphs */
+ G_UNICODE_SCRIPT_IMPERIAL_ARAMAIC, /* Imperial Aramaic */
+ G_UNICODE_SCRIPT_INSCRIPTIONAL_PAHLAVI, /* Inscriptional Pahlavi */
+ G_UNICODE_SCRIPT_INSCRIPTIONAL_PARTHIAN, /* Inscriptional Parthian */
+ G_UNICODE_SCRIPT_JAVANESE, /* Javanese */
+ G_UNICODE_SCRIPT_KAITHI, /* Kaithi */
+ G_UNICODE_SCRIPT_LISU, /* Lisu */
+ G_UNICODE_SCRIPT_MEETEI_MAYEK, /* Meetei Mayek */
+ G_UNICODE_SCRIPT_OLD_SOUTH_ARABIAN, /* Old South Arabian */
+ G_UNICODE_SCRIPT_OLD_TURKISH, /* Old Turkish */
+ G_UNICODE_SCRIPT_SAMARITAN, /* Samaritan */
+ G_UNICODE_SCRIPT_TAI_THAM, /* Tai Tham */
+ G_UNICODE_SCRIPT_TAI_VIET /* Tai Viet */
+} GUnicodeScript;
+
+/* Returns TRUE if current locale uses UTF-8 charset. If CHARSET is
+ * not null, sets *CHARSET to the name of the current locale's
+ * charset. This value is statically allocated, and should be copied
+ * in case the locale's charset will be changed later using setlocale()
+ * or in some other way.
+ */
+gboolean g_get_charset (G_CONST_RETURN char **charset);
+
+/* These are all analogs of the <ctype.h> functions.
+ */
+gboolean g_unichar_isalnum (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_isalpha (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_iscntrl (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_isdigit (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_isgraph (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_islower (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_isprint (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_ispunct (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_isspace (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_isupper (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_isxdigit (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_istitle (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_isdefined (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_iswide (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_iswide_cjk(gunichar c) G_GNUC_CONST;
+gboolean g_unichar_iszerowidth(gunichar c) G_GNUC_CONST;
+gboolean g_unichar_ismark (gunichar c) G_GNUC_CONST;
+
+/* More <ctype.h> functions. These convert between the three cases.
+ * See the Unicode book to understand title case. */
+gunichar g_unichar_toupper (gunichar c) G_GNUC_CONST;
+gunichar g_unichar_tolower (gunichar c) G_GNUC_CONST;
+gunichar g_unichar_totitle (gunichar c) G_GNUC_CONST;
+
+/* If C is a digit (according to `g_unichar_isdigit'), then return its
+ numeric value. Otherwise return -1. */
+gint g_unichar_digit_value (gunichar c) G_GNUC_CONST;
+
+gint g_unichar_xdigit_value (gunichar c) G_GNUC_CONST;
+
+/* Return the Unicode character type of a given character. */
+GUnicodeType g_unichar_type (gunichar c) G_GNUC_CONST;
+
+/* Return the line break property for a given character */
+GUnicodeBreakType g_unichar_break_type (gunichar c) G_GNUC_CONST;
+
+/* Returns the combining class for a given character */
+gint g_unichar_combining_class (gunichar uc) G_GNUC_CONST;
+
+
+/* Compute canonical ordering of a string in-place. This rearranges
+ decomposed characters in the string according to their combining
+ classes. See the Unicode manual for more information. */
+void g_unicode_canonical_ordering (gunichar *string,
+ gsize len);
+
+/* Compute canonical decomposition of a character. Returns g_malloc()d
+ string of Unicode characters. RESULT_LEN is set to the resulting
+ length of the string. */
+gunichar *g_unicode_canonical_decomposition (gunichar ch,
+ gsize *result_len) G_GNUC_MALLOC;
+
+/* Array of skip-bytes-per-initial character.
+ */
+GLIB_VAR const gchar * const g_utf8_skip;
+
+#define g_utf8_next_char(p) (char *)((p) + g_utf8_skip[*(const guchar *)(p)])
+
+gunichar g_utf8_get_char (const gchar *p) G_GNUC_PURE;
+gunichar g_utf8_get_char_validated (const gchar *p,
+ gssize max_len) G_GNUC_PURE;
+
+gchar* g_utf8_offset_to_pointer (const gchar *str,
+ glong offset) G_GNUC_PURE;
+glong g_utf8_pointer_to_offset (const gchar *str,
+ const gchar *pos) G_GNUC_PURE;
+gchar* g_utf8_prev_char (const gchar *p) G_GNUC_PURE;
+gchar* g_utf8_find_next_char (const gchar *p,
+ const gchar *end) G_GNUC_PURE;
+gchar* g_utf8_find_prev_char (const gchar *str,
+ const gchar *p) G_GNUC_PURE;
+
+glong g_utf8_strlen (const gchar *p,
+ gssize max) G_GNUC_PURE;
+
+/* Copies n characters from src to dest */
+gchar* g_utf8_strncpy (gchar *dest,
+ const gchar *src,
+ gsize n);
+
+/* Find the UTF-8 character corresponding to ch, in string p. These
+ functions are equivalants to strchr and strrchr */
+gchar* g_utf8_strchr (const gchar *p,
+ gssize len,
+ gunichar c);
+gchar* g_utf8_strrchr (const gchar *p,
+ gssize len,
+ gunichar c);
+gchar* g_utf8_strreverse (const gchar *str,
+ gssize len);
+
+gunichar2 *g_utf8_to_utf16 (const gchar *str,
+ glong len,
+ glong *items_read,
+ glong *items_written,
+ GError **error) G_GNUC_MALLOC;
+gunichar * g_utf8_to_ucs4 (const gchar *str,
+ glong len,
+ glong *items_read,
+ glong *items_written,
+ GError **error) G_GNUC_MALLOC;
+gunichar * g_utf8_to_ucs4_fast (const gchar *str,
+ glong len,
+ glong *items_written) G_GNUC_MALLOC;
+gunichar * g_utf16_to_ucs4 (const gunichar2 *str,
+ glong len,
+ glong *items_read,
+ glong *items_written,
+ GError **error) G_GNUC_MALLOC;
+gchar* g_utf16_to_utf8 (const gunichar2 *str,
+ glong len,
+ glong *items_read,
+ glong *items_written,
+ GError **error) G_GNUC_MALLOC;
+gunichar2 *g_ucs4_to_utf16 (const gunichar *str,
+ glong len,
+ glong *items_read,
+ glong *items_written,
+ GError **error) G_GNUC_MALLOC;
+gchar* g_ucs4_to_utf8 (const gunichar *str,
+ glong len,
+ glong *items_read,
+ glong *items_written,
+ GError **error) G_GNUC_MALLOC;
+
+/* Convert a single character into UTF-8. outbuf must have at
+ * least 6 bytes of space. Returns the number of bytes in the
+ * result.
+ */
+gint g_unichar_to_utf8 (gunichar c,
+ gchar *outbuf);
+
+/* Validate a UTF8 string, return TRUE if valid, put pointer to
+ * first invalid char in **end
+ */
+
+gboolean g_utf8_validate (const gchar *str,
+ gssize max_len,
+ const gchar **end);
+
+/* Validate a Unicode character */
+gboolean g_unichar_validate (gunichar ch) G_GNUC_CONST;
+
+gchar *g_utf8_strup (const gchar *str,
+ gssize len) G_GNUC_MALLOC;
+gchar *g_utf8_strdown (const gchar *str,
+ gssize len) G_GNUC_MALLOC;
+gchar *g_utf8_casefold (const gchar *str,
+ gssize len) G_GNUC_MALLOC;
+
+typedef enum {
+ G_NORMALIZE_DEFAULT,
+ G_NORMALIZE_NFD = G_NORMALIZE_DEFAULT,
+ G_NORMALIZE_DEFAULT_COMPOSE,
+ G_NORMALIZE_NFC = G_NORMALIZE_DEFAULT_COMPOSE,
+ G_NORMALIZE_ALL,
+ G_NORMALIZE_NFKD = G_NORMALIZE_ALL,
+ G_NORMALIZE_ALL_COMPOSE,
+ G_NORMALIZE_NFKC = G_NORMALIZE_ALL_COMPOSE
+} GNormalizeMode;
+
+gchar *g_utf8_normalize (const gchar *str,
+ gssize len,
+ GNormalizeMode mode) G_GNUC_MALLOC;
+
+gint g_utf8_collate (const gchar *str1,
+ const gchar *str2) G_GNUC_PURE;
+gchar *g_utf8_collate_key (const gchar *str,
+ gssize len) G_GNUC_MALLOC;
+gchar *g_utf8_collate_key_for_filename (const gchar *str,
+ gssize len) G_GNUC_MALLOC;
+
+gboolean g_unichar_get_mirror_char (gunichar ch,
+ gunichar *mirrored_ch);
+
+GUnicodeScript g_unichar_get_script (gunichar ch) G_GNUC_CONST;
+
+
+/* private */
+
+gchar *_g_utf8_make_valid (const gchar *name);
+
+G_END_DECLS
+
+#endif /* __G_UNICODE_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gurifuncs.h b/protocols/Sametime/src/glib/include/glib/gurifuncs.h
new file mode 100644
index 0000000000..bbc8f8800a
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gurifuncs.h
@@ -0,0 +1,81 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Alexander Larsson <alexl@redhat.com>
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_URI_FUNCS_H__
+#define __G_URI_FUNCS_H__
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+/**
+ * G_URI_RESERVED_CHARS_GENERIC_DELIMITERS:
+ *
+ * Generic delimiters characters as defined in RFC 3986. Includes ":/?#[]@".
+ **/
+#define G_URI_RESERVED_CHARS_GENERIC_DELIMITERS ":/?#[]@"
+
+/**
+ * G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS
+ *
+ * Subcomponent delimiter characters as defined in RFC 3986. Includes "!$&'()*+,;=".
+ **/
+#define G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS "!$&'()*+,;="
+
+/**
+ * G_URI_RESERVED_CHARS_ALLOWED_IN_PATH_ELEMENT:
+ *
+ * Allowed characters in path elements. Includes "!$&'()*+,;=:@".
+ **/
+#define G_URI_RESERVED_CHARS_ALLOWED_IN_PATH_ELEMENT G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS ":@"
+
+/**
+ * G_URI_RESERVED_CHARS_ALLOWED_IN_PATH:
+ *
+ * Allowed characters in a path. Includes "!$&'()*+,;=:@/".
+ **/
+#define G_URI_RESERVED_CHARS_ALLOWED_IN_PATH G_URI_RESERVED_CHARS_ALLOWED_IN_PATH_ELEMENT "/"
+
+/**
+ * G_URI_RESERVED_CHARS_ALLOWED_IN_USERINFO:
+ *
+ * Allowed characters in userinfo as defined in RFC 3986. Includes "!$&'()*+,;=:".
+ **/
+#define G_URI_RESERVED_CHARS_ALLOWED_IN_USERINFO G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS ":"
+
+char * g_uri_unescape_string (const char *escaped_string,
+ const char *illegal_characters);
+char * g_uri_unescape_segment (const char *escaped_string,
+ const char *escaped_string_end,
+ const char *illegal_characters);
+char * g_uri_parse_scheme (const char *uri);
+char * g_uri_escape_string (const char *unescaped,
+ const char *reserved_chars_allowed,
+ gboolean allow_utf8);
+
+G_END_DECLS
+
+#endif /* __G_URI_FUNCS_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gutils.h b/protocols/Sametime/src/glib/include/glib/gutils.h
new file mode 100644
index 0000000000..90281579c6
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gutils.h
@@ -0,0 +1,490 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_UTILS_H__
+#define __G_UTILS_H__
+
+#include <glib/gtypes.h>
+#include <stdarg.h>
+
+G_BEGIN_DECLS
+
+#ifdef G_OS_WIN32
+
+/* On Win32, the canonical directory separator is the backslash, and
+ * the search path separator is the semicolon. Note that also the
+ * (forward) slash works as directory separator.
+ */
+#define G_DIR_SEPARATOR '\\'
+#define G_DIR_SEPARATOR_S "\\"
+#define G_IS_DIR_SEPARATOR(c) ((c) == G_DIR_SEPARATOR || (c) == '/')
+#define G_SEARCHPATH_SEPARATOR ';'
+#define G_SEARCHPATH_SEPARATOR_S ";"
+
+#else /* !G_OS_WIN32 */
+
+/* Unix */
+
+#define G_DIR_SEPARATOR '/'
+#define G_DIR_SEPARATOR_S "/"
+#define G_IS_DIR_SEPARATOR(c) ((c) == G_DIR_SEPARATOR)
+#define G_SEARCHPATH_SEPARATOR ':'
+#define G_SEARCHPATH_SEPARATOR_S ":"
+
+#endif /* !G_OS_WIN32 */
+
+/* Define G_VA_COPY() to do the right thing for copying va_list variables.
+ * glibconfig.h may have already defined G_VA_COPY as va_copy or __va_copy.
+ */
+#if !defined (G_VA_COPY)
+# if defined (__GNUC__) && defined (__PPC__) && (defined (_CALL_SYSV) || defined (_WIN32))
+# define G_VA_COPY(ap1, ap2) (*(ap1) = *(ap2))
+# elif defined (G_VA_COPY_AS_ARRAY)
+# define G_VA_COPY(ap1, ap2) g_memmove ((ap1), (ap2), sizeof (va_list))
+# else /* va_list is a pointer */
+# define G_VA_COPY(ap1, ap2) ((ap1) = (ap2))
+# endif /* va_list is a pointer */
+#endif /* !G_VA_COPY */
+
+/* inlining hassle. for compilers that don't allow the `inline' keyword,
+ * mostly because of strict ANSI C compliance or dumbness, we try to fall
+ * back to either `__inline__' or `__inline'.
+ * G_CAN_INLINE is defined in glibconfig.h if the compiler seems to be
+ * actually *capable* to do function inlining, in which case inline
+ * function bodies do make sense. we also define G_INLINE_FUNC to properly
+ * export the function prototypes if no inlining can be performed.
+ * inline function bodies have to be special cased with G_CAN_INLINE and a
+ * .c file specific macro to allow one compiled instance with extern linkage
+ * of the functions by defining G_IMPLEMENT_INLINES and the .c file macro.
+ */
+#if defined (G_HAVE_INLINE) && defined (__GNUC__) && defined (__STRICT_ANSI__)
+# undef inline
+# define inline __inline__
+#elif !defined (G_HAVE_INLINE)
+# undef inline
+# if defined (G_HAVE___INLINE__)
+# define inline __inline__
+# elif defined (G_HAVE___INLINE)
+# define inline __inline
+# else /* !inline && !__inline__ && !__inline */
+# define inline /* don't inline, then */
+# endif
+#endif
+#ifdef G_IMPLEMENT_INLINES
+# define G_INLINE_FUNC
+# undef G_CAN_INLINE
+#elif defined (__GNUC__)
+# define G_INLINE_FUNC static __inline __attribute__ ((unused))
+#elif defined (G_CAN_INLINE)
+# define G_INLINE_FUNC static inline
+#else /* can't inline */
+# define G_INLINE_FUNC
+#endif /* !G_INLINE_FUNC */
+
+/* Retrive static string info
+ */
+#ifdef G_OS_WIN32
+#define g_get_user_name g_get_user_name_utf8
+#define g_get_real_name g_get_real_name_utf8
+#define g_get_home_dir g_get_home_dir_utf8
+#define g_get_tmp_dir g_get_tmp_dir_utf8
+#endif
+
+G_CONST_RETURN gchar* g_get_user_name (void);
+G_CONST_RETURN gchar* g_get_real_name (void);
+G_CONST_RETURN gchar* g_get_home_dir (void);
+G_CONST_RETURN gchar* g_get_tmp_dir (void);
+G_CONST_RETURN gchar* g_get_host_name (void);
+gchar* g_get_prgname (void);
+void g_set_prgname (const gchar *prgname);
+G_CONST_RETURN gchar* g_get_application_name (void);
+void g_set_application_name (const gchar *application_name);
+
+void g_reload_user_special_dirs_cache (void);
+G_CONST_RETURN gchar* g_get_user_data_dir (void);
+G_CONST_RETURN gchar* g_get_user_config_dir (void);
+G_CONST_RETURN gchar* g_get_user_cache_dir (void);
+G_CONST_RETURN gchar* G_CONST_RETURN * g_get_system_data_dirs (void);
+
+#ifdef G_OS_WIN32
+/* This functions is not part of the public GLib API */
+G_CONST_RETURN gchar* G_CONST_RETURN * g_win32_get_system_data_dirs_for_module (void (*address_of_function)(void));
+#endif
+
+#if defined (G_OS_WIN32) && defined (G_CAN_INLINE) && !defined (__cplusplus)
+/* This function is not part of the public GLib API either. Just call
+ * g_get_system_data_dirs() in your code, never mind that that is
+ * actually a macro and you will in fact call this inline function.
+ */
+static inline G_CONST_RETURN gchar * G_CONST_RETURN *
+_g_win32_get_system_data_dirs (void)
+{
+ return g_win32_get_system_data_dirs_for_module ((void (*)(void)) &_g_win32_get_system_data_dirs);
+}
+#define g_get_system_data_dirs _g_win32_get_system_data_dirs
+#endif
+
+G_CONST_RETURN gchar* G_CONST_RETURN * g_get_system_config_dirs (void);
+
+G_CONST_RETURN gchar* G_CONST_RETURN * g_get_language_names (void);
+
+/**
+ * GUserDirectory:
+ * @G_USER_DIRECTORY_DESKTOP: the user's Desktop directory
+ * @G_USER_DIRECTORY_DOCUMENTS: the user's Documents directory
+ * @G_USER_DIRECTORY_DOWNLOAD: the user's Downloads directory
+ * @G_USER_DIRECTORY_MUSIC: the user's Music directory
+ * @G_USER_DIRECTORY_PICTURES: the user's Pictures directory
+ * @G_USER_DIRECTORY_PUBLIC_SHARE: the user's shared directory
+ * @G_USER_DIRECTORY_TEMPLATES: the user's Templates directory
+ * @G_USER_DIRECTORY_VIDEOS: the user's Movies directory
+ * @G_USER_N_DIRECTORIES: the number of enum values
+ *
+ * These are logical ids for special directories which are defined
+ * depending on the platform used. You should use g_get_user_special_dir()
+ * to retrieve the full path associated to the logical id.
+ *
+ * The #GUserDirectory enumeration can be extended at later date. Not
+ * every platform has a directory for every logical id in this
+ * enumeration.
+ *
+ * Since: 2.14
+ */
+typedef enum {
+ G_USER_DIRECTORY_DESKTOP,
+ G_USER_DIRECTORY_DOCUMENTS,
+ G_USER_DIRECTORY_DOWNLOAD,
+ G_USER_DIRECTORY_MUSIC,
+ G_USER_DIRECTORY_PICTURES,
+ G_USER_DIRECTORY_PUBLIC_SHARE,
+ G_USER_DIRECTORY_TEMPLATES,
+ G_USER_DIRECTORY_VIDEOS,
+
+ G_USER_N_DIRECTORIES
+} GUserDirectory;
+
+G_CONST_RETURN gchar* g_get_user_special_dir (GUserDirectory directory);
+
+typedef struct _GDebugKey GDebugKey;
+struct _GDebugKey
+{
+ const gchar *key;
+ guint value;
+};
+
+/* Miscellaneous utility functions
+ */
+guint g_parse_debug_string (const gchar *string,
+ const GDebugKey *keys,
+ guint nkeys);
+
+gint g_snprintf (gchar *string,
+ gulong n,
+ gchar const *format,
+ ...) G_GNUC_PRINTF (3, 4);
+gint g_vsnprintf (gchar *string,
+ gulong n,
+ gchar const *format,
+ va_list args);
+
+/* Check if a file name is an absolute path */
+gboolean g_path_is_absolute (const gchar *file_name);
+
+/* In case of absolute paths, skip the root part */
+G_CONST_RETURN gchar* g_path_skip_root (const gchar *file_name);
+
+#ifndef G_DISABLE_DEPRECATED
+
+/* These two functions are deprecated and will be removed in the next
+ * major release of GLib. Use g_path_get_dirname/g_path_get_basename
+ * instead. Whatch out! The string returned by g_path_get_basename
+ * must be g_freed, while the string returned by g_basename must not.*/
+G_CONST_RETURN gchar* g_basename (const gchar *file_name);
+#define g_dirname g_path_get_dirname
+
+#endif /* G_DISABLE_DEPRECATED */
+
+#ifdef G_OS_WIN32
+#define g_get_current_dir g_get_current_dir_utf8
+#endif
+
+/* The returned strings are newly allocated with g_malloc() */
+gchar* g_get_current_dir (void);
+gchar* g_path_get_basename (const gchar *file_name) G_GNUC_MALLOC;
+gchar* g_path_get_dirname (const gchar *file_name) G_GNUC_MALLOC;
+
+/* Set the pointer at the specified location to NULL */
+void g_nullify_pointer (gpointer *nullify_location);
+
+/* return the environment string for the variable. The returned memory
+ * must not be freed. */
+#ifdef G_OS_WIN32
+#define g_getenv g_getenv_utf8
+#define g_setenv g_setenv_utf8
+#define g_unsetenv g_unsetenv_utf8
+#define g_find_program_in_path g_find_program_in_path_utf8
+#endif
+
+G_CONST_RETURN gchar* g_getenv (const gchar *variable);
+gboolean g_setenv (const gchar *variable,
+ const gchar *value,
+ gboolean overwrite);
+void g_unsetenv (const gchar *variable);
+gchar** g_listenv (void);
+
+/* private */
+const gchar* _g_getenv_nomalloc (const gchar *variable,
+ gchar buffer[1024]);
+
+/* we try to provide a useful equivalent for ATEXIT if it is
+ * not defined, but use is actually abandoned. people should
+ * use g_atexit() instead.
+ */
+typedef void (*GVoidFunc) (void);
+#ifndef ATEXIT
+# define ATEXIT(proc) g_ATEXIT(proc)
+#else
+# define G_NATIVE_ATEXIT
+#endif /* ATEXIT */
+/* we use a GLib function as a replacement for ATEXIT, so
+ * the programmer is not required to check the return value
+ * (if there is any in the implementation) and doesn't encounter
+ * missing include files.
+ */
+void g_atexit (GVoidFunc func);
+
+#ifdef G_OS_WIN32
+/* It's a bad idea to wrap atexit() on Windows. If the GLib DLL calls
+ * atexit(), the function will be called when the GLib DLL is detached
+ * from the program, which is not what the caller wants. The caller
+ * wants the function to be called when it *itself* exits (or is
+ * detached, in case the caller, too, is a DLL).
+ */
+#if (defined(__MINGW_H) && !defined(_STDLIB_H_)) || (defined(_MSC_VER) && !defined(_INC_STDLIB))
+int atexit (void (*)(void));
+#endif
+#define g_atexit(func) atexit(func)
+#endif
+
+/* Look for an executable in PATH, following execvp() rules */
+gchar* g_find_program_in_path (const gchar *program);
+
+/* Bit tests
+ */
+G_INLINE_FUNC gint g_bit_nth_lsf (gulong mask,
+ gint nth_bit) G_GNUC_CONST;
+G_INLINE_FUNC gint g_bit_nth_msf (gulong mask,
+ gint nth_bit) G_GNUC_CONST;
+G_INLINE_FUNC guint g_bit_storage (gulong number) G_GNUC_CONST;
+
+/* Trash Stacks
+ * elements need to be >= sizeof (gpointer)
+ */
+typedef struct _GTrashStack GTrashStack;
+struct _GTrashStack
+{
+ GTrashStack *next;
+};
+
+G_INLINE_FUNC void g_trash_stack_push (GTrashStack **stack_p,
+ gpointer data_p);
+G_INLINE_FUNC gpointer g_trash_stack_pop (GTrashStack **stack_p);
+G_INLINE_FUNC gpointer g_trash_stack_peek (GTrashStack **stack_p);
+G_INLINE_FUNC guint g_trash_stack_height (GTrashStack **stack_p);
+
+/* inline function implementations
+ */
+#if defined (G_CAN_INLINE) || defined (__G_UTILS_C__)
+G_INLINE_FUNC gint
+g_bit_nth_lsf (gulong mask,
+ gint nth_bit)
+{
+ if (G_UNLIKELY (nth_bit < -1))
+ nth_bit = -1;
+ while (nth_bit < ((GLIB_SIZEOF_LONG * 8) - 1))
+ {
+ nth_bit++;
+ if (mask & (1UL << nth_bit))
+ return nth_bit;
+ }
+ return -1;
+}
+G_INLINE_FUNC gint
+g_bit_nth_msf (gulong mask,
+ gint nth_bit)
+{
+ if (nth_bit < 0 || G_UNLIKELY (nth_bit > GLIB_SIZEOF_LONG * 8))
+ nth_bit = GLIB_SIZEOF_LONG * 8;
+ while (nth_bit > 0)
+ {
+ nth_bit--;
+ if (mask & (1UL << nth_bit))
+ return nth_bit;
+ }
+ return -1;
+}
+G_INLINE_FUNC guint
+g_bit_storage (gulong number)
+{
+#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
+ return G_LIKELY (number) ?
+ ((GLIB_SIZEOF_LONG * 8U - 1) ^ __builtin_clzl(number)) + 1 : 1;
+#else
+ register guint n_bits = 0;
+
+ do
+ {
+ n_bits++;
+ number >>= 1;
+ }
+ while (number);
+ return n_bits;
+#endif
+}
+G_INLINE_FUNC void
+g_trash_stack_push (GTrashStack **stack_p,
+ gpointer data_p)
+{
+ GTrashStack *data = (GTrashStack *) data_p;
+
+ data->next = *stack_p;
+ *stack_p = data;
+}
+G_INLINE_FUNC gpointer
+g_trash_stack_pop (GTrashStack **stack_p)
+{
+ GTrashStack *data;
+
+ data = *stack_p;
+ if (data)
+ {
+ *stack_p = data->next;
+ /* NULLify private pointer here, most platforms store NULL as
+ * subsequent 0 bytes
+ */
+ data->next = NULL;
+ }
+
+ return data;
+}
+G_INLINE_FUNC gpointer
+g_trash_stack_peek (GTrashStack **stack_p)
+{
+ GTrashStack *data;
+
+ data = *stack_p;
+
+ return data;
+}
+G_INLINE_FUNC guint
+g_trash_stack_height (GTrashStack **stack_p)
+{
+ GTrashStack *data;
+ guint i = 0;
+
+ for (data = *stack_p; data; data = data->next)
+ i++;
+
+ return i;
+}
+#endif /* G_CAN_INLINE || __G_UTILS_C__ */
+
+/* Glib version.
+ * we prefix variable declarations so they can
+ * properly get exported in windows dlls.
+ */
+GLIB_VAR const guint glib_major_version;
+GLIB_VAR const guint glib_minor_version;
+GLIB_VAR const guint glib_micro_version;
+GLIB_VAR const guint glib_interface_age;
+GLIB_VAR const guint glib_binary_age;
+
+const gchar * glib_check_version (guint required_major,
+ guint required_minor,
+ guint required_micro);
+
+#define GLIB_CHECK_VERSION(major,minor,micro) \
+ (GLIB_MAJOR_VERSION > (major) || \
+ (GLIB_MAJOR_VERSION == (major) && GLIB_MINOR_VERSION > (minor)) || \
+ (GLIB_MAJOR_VERSION == (major) && GLIB_MINOR_VERSION == (minor) && \
+ GLIB_MICRO_VERSION >= (micro)))
+
+G_END_DECLS
+
+#ifndef G_DISABLE_DEPRECATED
+
+/*
+ * This macro is deprecated. This DllMain() is too complex. It is
+ * recommended to write an explicit minimal DLlMain() that just saves
+ * the handle to the DLL and then use that handle instead, for
+ * instance passing it to
+ * g_win32_get_package_installation_directory_of_module().
+ *
+ * On Windows, this macro defines a DllMain function that stores the
+ * actual DLL name that the code being compiled will be included in.
+ * STATIC should be empty or 'static'. DLL_NAME is the name of the
+ * (pointer to the) char array where the DLL name will be stored. If
+ * this is used, you must also include <windows.h>. If you need a more complex
+ * DLL entry point function, you cannot use this.
+ *
+ * On non-Windows platforms, expands to nothing.
+ */
+
+#ifndef G_PLATFORM_WIN32
+# define G_WIN32_DLLMAIN_FOR_DLL_NAME(static, dll_name)
+#else
+# define G_WIN32_DLLMAIN_FOR_DLL_NAME(static, dll_name) \
+static char *dll_name; \
+ \
+BOOL WINAPI \
+DllMain (HINSTANCE hinstDLL, \
+ DWORD fdwReason, \
+ LPVOID lpvReserved) \
+{ \
+ wchar_t wcbfr[1000]; \
+ char *tem; \
+ switch (fdwReason) \
+ { \
+ case DLL_PROCESS_ATTACH: \
+ GetModuleFileNameW ((HMODULE) hinstDLL, wcbfr, G_N_ELEMENTS (wcbfr)); \
+ tem = g_utf16_to_utf8 (wcbfr, -1, NULL, NULL, NULL); \
+ dll_name = g_path_get_basename (tem); \
+ g_free (tem); \
+ break; \
+ } \
+ \
+ return TRUE; \
+}
+
+#endif /* !G_DISABLE_DEPRECATED */
+
+#endif /* G_PLATFORM_WIN32 */
+
+#endif /* __G_UTILS_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gvariant.h b/protocols/Sametime/src/glib/include/glib/gvariant.h
new file mode 100644
index 0000000000..528492b685
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gvariant.h
@@ -0,0 +1,248 @@
+/*
+ * Copyright © 2007, 2008 Ryan Lortie
+ * Copyright © 2009, 2010 Codethink Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Ryan Lortie <desrt@desrt.ca>
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_VARIANT_H__
+#define __G_VARIANT_H__
+
+#include <glib/gvarianttype.h>
+#include <glib/gstring.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GVariant GVariant;
+
+typedef enum
+{
+ G_VARIANT_CLASS_BOOLEAN = 'b',
+ G_VARIANT_CLASS_BYTE = 'y',
+ G_VARIANT_CLASS_INT16 = 'n',
+ G_VARIANT_CLASS_UINT16 = 'q',
+ G_VARIANT_CLASS_INT32 = 'i',
+ G_VARIANT_CLASS_UINT32 = 'u',
+ G_VARIANT_CLASS_INT64 = 'x',
+ G_VARIANT_CLASS_UINT64 = 't',
+ G_VARIANT_CLASS_HANDLE = 'h',
+ G_VARIANT_CLASS_DOUBLE = 'd',
+ G_VARIANT_CLASS_STRING = 's',
+ G_VARIANT_CLASS_OBJECT_PATH = 'o',
+ G_VARIANT_CLASS_SIGNATURE = 'g',
+ G_VARIANT_CLASS_VARIANT = 'v',
+ G_VARIANT_CLASS_MAYBE = 'm',
+ G_VARIANT_CLASS_ARRAY = 'a',
+ G_VARIANT_CLASS_TUPLE = '(',
+ G_VARIANT_CLASS_DICT_ENTRY = '{'
+} GVariantClass;
+
+void g_variant_unref (GVariant *value);
+GVariant * g_variant_ref (GVariant *value);
+GVariant * g_variant_ref_sink (GVariant *value);
+gboolean g_variant_is_floating (GVariant *value);
+
+const GVariantType * g_variant_get_type (GVariant *value);
+const gchar * g_variant_get_type_string (GVariant *value);
+gboolean g_variant_is_of_type (GVariant *value,
+ const GVariantType *type);
+gboolean g_variant_is_container (GVariant *value);
+GVariantClass g_variant_classify (GVariant *value);
+GVariant * g_variant_new_boolean (gboolean boolean);
+GVariant * g_variant_new_byte (guchar byte);
+GVariant * g_variant_new_int16 (gint16 int16);
+GVariant * g_variant_new_uint16 (guint16 uint16);
+GVariant * g_variant_new_int32 (gint32 int32);
+GVariant * g_variant_new_uint32 (guint32 uint32);
+GVariant * g_variant_new_int64 (gint64 int64);
+GVariant * g_variant_new_uint64 (guint64 uint64);
+GVariant * g_variant_new_handle (gint32 handle);
+GVariant * g_variant_new_double (gdouble floating);
+GVariant * g_variant_new_string (const gchar *string);
+GVariant * g_variant_new_object_path (const gchar *object_path);
+gboolean g_variant_is_object_path (const gchar *string);
+GVariant * g_variant_new_signature (const gchar *signature);
+gboolean g_variant_is_signature (const gchar *string);
+GVariant * g_variant_new_variant (GVariant *value);
+GVariant * g_variant_new_strv (const gchar * const *strv,
+ gssize length);
+GVariant * g_variant_new_bytestring (const gchar *string);
+GVariant * g_variant_new_bytestring_array (const gchar * const *strv,
+ gssize length);
+
+gboolean g_variant_get_boolean (GVariant *value);
+guchar g_variant_get_byte (GVariant *value);
+gint16 g_variant_get_int16 (GVariant *value);
+guint16 g_variant_get_uint16 (GVariant *value);
+gint32 g_variant_get_int32 (GVariant *value);
+guint32 g_variant_get_uint32 (GVariant *value);
+gint64 g_variant_get_int64 (GVariant *value);
+guint64 g_variant_get_uint64 (GVariant *value);
+gint32 g_variant_get_handle (GVariant *value);
+gdouble g_variant_get_double (GVariant *value);
+GVariant * g_variant_get_variant (GVariant *value);
+const gchar * g_variant_get_string (GVariant *value,
+ gsize *length);
+gchar * g_variant_dup_string (GVariant *value,
+ gsize *length);
+const gchar ** g_variant_get_strv (GVariant *value,
+ gsize *length);
+gchar ** g_variant_dup_strv (GVariant *value,
+ gsize *length);
+const gchar * g_variant_get_bytestring (GVariant *value);
+gchar * g_variant_dup_bytestring (GVariant *value,
+ gsize *length);
+const gchar ** g_variant_get_bytestring_array (GVariant *value,
+ gsize *length);
+gchar ** g_variant_dup_bytestring_array (GVariant *value,
+ gsize *length);
+
+GVariant * g_variant_new_maybe (const GVariantType *child_type,
+ GVariant *child);
+GVariant * g_variant_new_array (const GVariantType *child_type,
+ GVariant * const *children,
+ gsize n_children);
+GVariant * g_variant_new_tuple (GVariant * const *children,
+ gsize n_children);
+GVariant * g_variant_new_dict_entry (GVariant *key,
+ GVariant *value);
+
+GVariant * g_variant_get_maybe (GVariant *value);
+gsize g_variant_n_children (GVariant *value);
+void g_variant_get_child (GVariant *value,
+ gsize index_,
+ const gchar *format_string,
+ ...);
+GVariant * g_variant_get_child_value (GVariant *value,
+ gsize index_);
+gconstpointer g_variant_get_fixed_array (GVariant *value,
+ gsize *n_elements,
+ gsize element_size);
+
+gsize g_variant_get_size (GVariant *value);
+gconstpointer g_variant_get_data (GVariant *value);
+void g_variant_store (GVariant *value,
+ gpointer data);
+
+gchar * g_variant_print (GVariant *value,
+ gboolean type_annotate);
+GString * g_variant_print_string (GVariant *value,
+ GString *string,
+ gboolean type_annotate);
+
+guint g_variant_hash (gconstpointer value);
+gboolean g_variant_equal (gconstpointer one,
+ gconstpointer two);
+
+GVariant * g_variant_get_normal_form (GVariant *value);
+gboolean g_variant_is_normal_form (GVariant *value);
+GVariant * g_variant_byteswap (GVariant *value);
+GVariant * g_variant_new_from_data (const GVariantType *type,
+ gconstpointer data,
+ gsize size,
+ gboolean trusted,
+ GDestroyNotify notify,
+ gpointer user_data);
+
+typedef struct _GVariantIter GVariantIter;
+struct _GVariantIter {
+ /*< private >*/
+ gsize x[16];
+};
+
+GVariantIter * g_variant_iter_new (GVariant *value);
+gsize g_variant_iter_init (GVariantIter *iter,
+ GVariant *value);
+GVariantIter * g_variant_iter_copy (GVariantIter *iter);
+gsize g_variant_iter_n_children (GVariantIter *iter);
+void g_variant_iter_free (GVariantIter *iter);
+GVariant * g_variant_iter_next_value (GVariantIter *iter);
+gboolean g_variant_iter_next (GVariantIter *iter,
+ const gchar *format_string,
+ ...);
+gboolean g_variant_iter_loop (GVariantIter *iter,
+ const gchar *format_string,
+ ...);
+
+
+typedef struct _GVariantBuilder GVariantBuilder;
+struct _GVariantBuilder {
+ /*< private >*/
+ gsize x[16];
+};
+
+typedef enum
+{
+ G_VARIANT_PARSE_ERROR_FAILED
+} GVariantParseError;
+#define G_VARIANT_PARSE_ERROR (g_variant_parser_get_error_quark ())
+
+GQuark g_variant_parser_get_error_quark (void);
+
+GVariantBuilder * g_variant_builder_new (const GVariantType *type);
+void g_variant_builder_unref (GVariantBuilder *builder);
+GVariantBuilder * g_variant_builder_ref (GVariantBuilder *builder);
+void g_variant_builder_init (GVariantBuilder *builder,
+ const GVariantType *type);
+GVariant * g_variant_builder_end (GVariantBuilder *builder);
+void g_variant_builder_clear (GVariantBuilder *builder);
+void g_variant_builder_open (GVariantBuilder *builder,
+ const GVariantType *type);
+void g_variant_builder_close (GVariantBuilder *builder);
+void g_variant_builder_add_value (GVariantBuilder *builder,
+ GVariant *value);
+void g_variant_builder_add (GVariantBuilder *builder,
+ const gchar *format_string,
+ ...);
+void g_variant_builder_add_parsed (GVariantBuilder *builder,
+ const gchar *format,
+ ...);
+
+GVariant * g_variant_new (const gchar *format_string,
+ ...);
+void g_variant_get (GVariant *value,
+ const gchar *format_string,
+ ...);
+GVariant * g_variant_new_va (const gchar *format_string,
+ const gchar **endptr,
+ va_list *app);
+void g_variant_get_va (GVariant *value,
+ const gchar *format_string,
+ const gchar **endptr,
+ va_list *app);
+
+
+GVariant * g_variant_parse (const GVariantType *type,
+ const gchar *text,
+ const gchar *limit,
+ const gchar **endptr,
+ GError **error);
+GVariant * g_variant_new_parsed (const gchar *format,
+ ...);
+GVariant * g_variant_new_parsed_va (const gchar *format,
+ va_list *app);
+
+gint g_variant_compare (gconstpointer one,
+ gconstpointer two);
+G_END_DECLS
+
+#endif /* __G_VARIANT_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gvarianttype.h b/protocols/Sametime/src/glib/include/glib/gvarianttype.h
new file mode 100644
index 0000000000..124fa46b59
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gvarianttype.h
@@ -0,0 +1,334 @@
+/*
+ * Copyright © 2007, 2008 Ryan Lortie
+ * Copyright © 2009, 2010 Codethink Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Ryan Lortie <desrt@desrt.ca>
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_VARIANT_TYPE_H__
+#define __G_VARIANT_TYPE_H__
+
+#include <glib/gmessages.h>
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GVariantType:
+ *
+ * A type in the GVariant type system.
+ *
+ * Two types may not be compared by value; use g_variant_type_equal() or
+ * g_variant_type_is_subtype(). May be copied using
+ * g_variant_type_copy() and freed using g_variant_type_free().
+ **/
+typedef struct _GVariantType GVariantType;
+
+/**
+ * G_VARIANT_TYPE_BOOLEAN:
+ *
+ * The type of a value that can be either %TRUE or %FALSE.
+ **/
+#define G_VARIANT_TYPE_BOOLEAN ((const GVariantType *) "b")
+
+/**
+ * G_VARIANT_TYPE_BYTE:
+ *
+ * The type of an integer value that can range from 0 to 255.
+ **/
+#define G_VARIANT_TYPE_BYTE ((const GVariantType *) "y")
+
+/**
+ * G_VARIANT_TYPE_INT16:
+ *
+ * The type of an integer value that can range from -32768 to 32767.
+ **/
+#define G_VARIANT_TYPE_INT16 ((const GVariantType *) "n")
+
+/**
+ * G_VARIANT_TYPE_UINT16:
+ *
+ * The type of an integer value that can range from 0 to 65535.
+ * There were about this many people living in Toronto in the 1870s.
+ **/
+#define G_VARIANT_TYPE_UINT16 ((const GVariantType *) "q")
+
+/**
+ * G_VARIANT_TYPE_INT32:
+ *
+ * The type of an integer value that can range from -2147483648 to
+ * 2147483647.
+ **/
+#define G_VARIANT_TYPE_INT32 ((const GVariantType *) "i")
+
+/**
+ * G_VARIANT_TYPE_UINT32:
+ *
+ * The type of an integer value that can range from 0 to 4294967295.
+ * That's one number for everyone who was around in the late 1970s.
+ **/
+#define G_VARIANT_TYPE_UINT32 ((const GVariantType *) "u")
+
+/**
+ * G_VARIANT_TYPE_INT64:
+ *
+ * The type of an integer value that can range from
+ * -9223372036854775808 to 9223372036854775807.
+ **/
+#define G_VARIANT_TYPE_INT64 ((const GVariantType *) "x")
+
+/**
+ * G_VARIANT_TYPE_UINT64:
+ *
+ * The type of an integer value that can range from 0 to
+ * 18446744073709551616. That's a really big number, but a Rubik's
+ * cube can have a bit more than twice as many possible positions.
+ **/
+#define G_VARIANT_TYPE_UINT64 ((const GVariantType *) "t")
+
+/**
+ * G_VARIANT_TYPE_DOUBLE:
+ *
+ * The type of a double precision IEEE754 floating point number.
+ * These guys go up to about 1.80e308 (plus and minus) but miss out on
+ * some numbers in between. In any case, that's far greater than the
+ * estimated number of fundamental particles in the observable
+ * universe.
+ **/
+#define G_VARIANT_TYPE_DOUBLE ((const GVariantType *) "d")
+
+/**
+ * G_VARIANT_TYPE_STRING:
+ *
+ * The type of a string. "" is a string. %NULL is not a string.
+ **/
+#define G_VARIANT_TYPE_STRING ((const GVariantType *) "s")
+
+/**
+ * G_VARIANT_TYPE_OBJECT_PATH:
+ *
+ * The type of a DBus object reference. These are strings of a
+ * specific format used to identify objects at a given destination on
+ * the bus.
+ *
+ * If you are not interacting with DBus, then there is no reason to make
+ * use of this type. If you are, then the DBus specification contains a
+ * precise description of valid object paths.
+ **/
+#define G_VARIANT_TYPE_OBJECT_PATH ((const GVariantType *) "o")
+
+/**
+ * G_VARIANT_TYPE_SIGNATURE:
+ *
+ * The type of a DBus type signature. These are strings of a specific
+ * format used as type signatures for DBus methods and messages.
+ *
+ * If you are not interacting with DBus, then there is no reason to make
+ * use of this type. If you are, then the DBus specification contains a
+ * precise description of valid signature strings.
+ **/
+#define G_VARIANT_TYPE_SIGNATURE ((const GVariantType *) "g")
+
+/**
+ * G_VARIANT_TYPE_VARIANT:
+ *
+ * The type of a box that contains any other value (including another
+ * variant).
+ **/
+#define G_VARIANT_TYPE_VARIANT ((const GVariantType *) "v")
+
+/**
+ * G_VARIANT_TYPE_HANDLE:
+ *
+ * The type of a 32bit signed integer value, that by convention, is used
+ * as an index into an array of file descriptors that are sent alongside
+ * a DBus message.
+ *
+ * If you are not interacting with DBus, then there is no reason to make
+ * use of this type.
+ **/
+#define G_VARIANT_TYPE_HANDLE ((const GVariantType *) "h")
+
+/**
+ * G_VARIANT_TYPE_UNIT:
+ *
+ * The empty tuple type. Has only one instance. Known also as "triv"
+ * or "void".
+ **/
+#define G_VARIANT_TYPE_UNIT ((const GVariantType *) "()")
+
+/**
+ * G_VARIANT_TYPE_ANY:
+ *
+ * An indefinite type that is a supertype of every type (including
+ * itself).
+ **/
+#define G_VARIANT_TYPE_ANY ((const GVariantType *) "*")
+
+/**
+ * G_VARIANT_TYPE_BASIC:
+ *
+ * An indefinite type that is a supertype of every basic (ie:
+ * non-container) type.
+ **/
+#define G_VARIANT_TYPE_BASIC ((const GVariantType *) "?")
+
+/**
+ * G_VARIANT_TYPE_MAYBE:
+ *
+ * An indefinite type that is a supertype of every maybe type.
+ **/
+#define G_VARIANT_TYPE_MAYBE ((const GVariantType *) "m*")
+
+/**
+ * G_VARIANT_TYPE_ARRAY:
+ *
+ * An indefinite type that is a supertype of every array type.
+ **/
+#define G_VARIANT_TYPE_ARRAY ((const GVariantType *) "a*")
+
+/**
+ * G_VARIANT_TYPE_TUPLE:
+ *
+ * An indefinite type that is a supertype of every tuple type,
+ * regardless of the number of items in the tuple.
+ **/
+#define G_VARIANT_TYPE_TUPLE ((const GVariantType *) "r")
+
+/**
+ * G_VARIANT_TYPE_DICT_ENTRY:
+ *
+ * An indefinite type that is a supertype of every dictionary entry
+ * type.
+ **/
+#define G_VARIANT_TYPE_DICT_ENTRY ((const GVariantType *) "{?*}")
+
+/**
+ * G_VARIANT_TYPE_DICTIONARY:
+ *
+ * An indefinite type that is a supertype of every dictionary type --
+ * that is, any array type that has an element type equal to any
+ * dictionary entry type.
+ **/
+#define G_VARIANT_TYPE_DICTIONARY ((const GVariantType *) "a{?*}")
+
+/**
+ * G_VARIANT_TYPE_STRING_ARRAY:
+ *
+ * The type of an array of strings.
+ **/
+#define G_VARIANT_TYPE_STRING_ARRAY ((const GVariantType *) "as")
+
+/**
+ * G_VARIANT_TYPE_BYTESTRING:
+ *
+ * The type of an array of bytes. This type is commonly used to pass
+ * around strings that may not be valid utf8. In that case, the
+ * convention is that the nul terminator character should be included as
+ * the last character in the array.
+ **/
+#define G_VARIANT_TYPE_BYTESTRING ((const GVariantType *) "ay")
+
+/**
+ * G_VARIANT_TYPE_BYTESTRING_ARRAY:
+ *
+ * The type of an array of byte strings (an array of arrays of bytes).
+ **/
+#define G_VARIANT_TYPE_BYTESTRING_ARRAY ((const GVariantType *) "aay")
+
+
+/**
+ * G_VARIANT_TYPE:
+ * @type_string: a well-formed #GVariantType type string
+ *
+ * Converts a string to a const #GVariantType. Depending on the
+ * current debugging level, this function may perform a runtime check
+ * to ensure that @string is a valid GVariant type string.
+ *
+ * It is always a programmer error to use this macro with an invalid
+ * type string.
+ *
+ * Since 2.24
+ **/
+#ifndef G_DISABLE_CHECKS
+# define G_VARIANT_TYPE(type_string) (g_variant_type_checked_ ((type_string)))
+#else
+# define G_VARIANT_TYPE(type_string) ((const GVariantType *) (type_string))
+#endif
+
+/* type string checking */
+gboolean g_variant_type_string_is_valid (const gchar *type_string);
+gboolean g_variant_type_string_scan (const gchar *string,
+ const gchar *limit,
+ const gchar **endptr);
+
+/* create/destroy */
+void g_variant_type_free (GVariantType *type);
+GVariantType * g_variant_type_copy (const GVariantType *type);
+GVariantType * g_variant_type_new (const gchar *type_string);
+
+/* getters */
+gsize g_variant_type_get_string_length (const GVariantType *type);
+const gchar * g_variant_type_peek_string (const GVariantType *type);
+gchar * g_variant_type_dup_string (const GVariantType *type);
+
+/* classification */
+gboolean g_variant_type_is_definite (const GVariantType *type);
+gboolean g_variant_type_is_container (const GVariantType *type);
+gboolean g_variant_type_is_basic (const GVariantType *type);
+gboolean g_variant_type_is_maybe (const GVariantType *type);
+gboolean g_variant_type_is_array (const GVariantType *type);
+gboolean g_variant_type_is_tuple (const GVariantType *type);
+gboolean g_variant_type_is_dict_entry (const GVariantType *type);
+gboolean g_variant_type_is_variant (const GVariantType *type);
+
+/* for hash tables */
+guint g_variant_type_hash (gconstpointer type);
+gboolean g_variant_type_equal (gconstpointer type1,
+ gconstpointer type2);
+
+/* subtypes */
+gboolean g_variant_type_is_subtype_of (const GVariantType *type,
+ const GVariantType *supertype);
+
+/* type iterator interface */
+const GVariantType * g_variant_type_element (const GVariantType *type);
+const GVariantType * g_variant_type_first (const GVariantType *type);
+const GVariantType * g_variant_type_next (const GVariantType *type);
+gsize g_variant_type_n_items (const GVariantType *type);
+const GVariantType * g_variant_type_key (const GVariantType *type);
+const GVariantType * g_variant_type_value (const GVariantType *type);
+
+/* constructors */
+GVariantType * g_variant_type_new_array (const GVariantType *element);
+GVariantType * g_variant_type_new_maybe (const GVariantType *element);
+GVariantType * g_variant_type_new_tuple (const GVariantType * const *items,
+ gint length);
+GVariantType * g_variant_type_new_dict_entry (const GVariantType *key,
+ const GVariantType *value);
+
+/*< private >*/
+const GVariantType * g_variant_type_checked_ (const gchar *);
+
+G_END_DECLS
+
+#endif /* __G_VARIANT_TYPE_H__ */
diff --git a/protocols/Sametime/src/glib/include/glib/gwin32.h b/protocols/Sametime/src/glib/include/glib/gwin32.h
new file mode 100644
index 0000000000..5793335478
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glib/gwin32.h
@@ -0,0 +1,114 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_WIN32_H__
+#define __G_WIN32_H__
+
+#include <glib/gtypes.h>
+
+#ifdef G_PLATFORM_WIN32
+
+G_BEGIN_DECLS
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+
+#ifdef G_OS_WIN32
+
+/*
+ * To get prototypes for the following POSIXish functions, you have to
+ * include the indicated non-POSIX headers. The functions are defined
+ * in OLDNAMES.LIB (MSVC) or -lmoldname-msvc (mingw32). But note that
+ * for POSIX functions that take or return file names in the system
+ * codepage, in many cases you would want to use the GLib wrappers in
+ * gstdio.h and UTF-8 instead.
+ *
+ * getcwd: <direct.h> (MSVC), <io.h> (mingw32)
+ * getpid: <process.h>
+ * access: <io.h>
+ * unlink: <stdio.h> or <io.h>
+ * open, read, write, lseek, close: <io.h>
+ * rmdir: <io.h>
+ * pipe: <io.h> (actually, _pipe())
+ */
+
+/* For some POSIX functions that are not provided by the MS runtime,
+ * we provide emulation functions in glib, which are prefixed with
+ * g_win32_. Or that was the idea at some time, but there is just one
+ * of those:
+ */
+gint g_win32_ftruncate (gint f,
+ guint size);
+#endif /* G_OS_WIN32 */
+
+/* The MS setlocale uses locale names of the form "English_United
+ * States.1252" etc. We want the Unixish standard form "en", "zh_TW"
+ * etc. This function gets the current thread locale from Windows and
+ * returns it as a string of the above form for use in forming file
+ * names etc. The returned string should be deallocated with g_free().
+ */
+gchar* g_win32_getlocale (void);
+
+/* Translate a Win32 error code (as returned by GetLastError()) into
+ * the corresponding message. The returned string should be deallocated
+ * with g_free().
+ */
+gchar* g_win32_error_message (gint error);
+
+#ifndef G_DISABLE_DEPRECATED
+
+#define g_win32_get_package_installation_directory g_win32_get_package_installation_directory_utf8
+#define g_win32_get_package_installation_subdirectory g_win32_get_package_installation_subdirectory_utf8
+
+gchar* g_win32_get_package_installation_directory (const gchar *package,
+ const gchar *dll_name);
+
+gchar* g_win32_get_package_installation_subdirectory (const gchar *package,
+ const gchar *dll_name,
+ const gchar *subdir);
+
+#endif
+
+gchar* g_win32_get_package_installation_directory_of_module (gpointer hmodule);
+
+guint g_win32_get_windows_version (void);
+
+gchar* g_win32_locale_filename_from_utf8 (const gchar *utf8filename);
+
+/* As of GLib 2.14 we only support NT-based Windows */
+#define G_WIN32_IS_NT_BASED() TRUE
+#define G_WIN32_HAVE_WIDECHAR_API() TRUE
+
+G_END_DECLS
+
+#endif /* G_PLATFORM_WIN32 */
+
+#endif /* __G_WIN32_H__ */
diff --git a/protocols/Sametime/src/glib/include/glibconfig.h b/protocols/Sametime/src/glib/include/glibconfig.h
new file mode 100644
index 0000000000..2fa4af628f
--- /dev/null
+++ b/protocols/Sametime/src/glib/include/glibconfig.h
@@ -0,0 +1,284 @@
+/* glibconfig.h.win32.in. Originally merged from two versions of
+ * glibconfig.h, generated by the GLib configure script, for gcc and
+ * MSVC.
+ */
+
+/* glibconfig.h
+ *
+ * This is a generated file. Please modify 'glibconfig.h.win32.in'
+ */
+
+#ifndef __G_LIBCONFIG_H__
+#define __G_LIBCONFIG_H__
+
+#include <glib/gmacros.h>
+
+#include <limits.h>
+#include <float.h>
+
+G_BEGIN_DECLS
+
+#define G_MINFLOAT FLT_MIN
+#define G_MAXFLOAT FLT_MAX
+#define G_MINDOUBLE DBL_MIN
+#define G_MAXDOUBLE DBL_MAX
+#define G_MINSHORT SHRT_MIN
+#define G_MAXSHORT SHRT_MAX
+#define G_MAXUSHORT USHRT_MAX
+#define G_MININT INT_MIN
+#define G_MAXINT INT_MAX
+#define G_MAXUINT UINT_MAX
+#define G_MINLONG LONG_MIN
+#define G_MAXLONG LONG_MAX
+#define G_MAXULONG ULONG_MAX
+
+typedef signed char gint8;
+typedef unsigned char guint8;
+typedef signed short gint16;
+typedef unsigned short guint16;
+#define G_GINT16_MODIFIER "h"
+#define G_GINT16_FORMAT "hi"
+#define G_GUINT16_FORMAT "hu"
+typedef signed int gint32;
+typedef unsigned int guint32;
+#define G_GINT32_MODIFIER ""
+#define G_GINT32_FORMAT "i"
+#define G_GUINT32_FORMAT "u"
+#define G_HAVE_GINT64 1 /* deprecated, always true */
+
+#ifndef _MSC_VER
+G_GNUC_EXTENSION typedef signed long long gint64;
+G_GNUC_EXTENSION typedef unsigned long long guint64;
+#else /* _MSC_VER */
+typedef signed __int64 gint64;
+typedef unsigned __int64 guint64;
+#endif /* _MSC_VER */
+
+#ifndef _MSC_VER
+#define G_GINT64_CONSTANT(val) (G_GNUC_EXTENSION (val##LL))
+#else /* _MSC_VER */
+#define G_GINT64_CONSTANT(val) (val##i64)
+#endif /* _MSC_VER */
+#ifndef _MSC_VER
+#define G_GUINT64_CONSTANT(val) (G_GNUC_EXTENSION (val##ULL))
+#else /* _MSC_VER */
+#define G_GUINT64_CONSTANT(val) (val##Ui64)
+#endif /* _MSC_VER */
+#define G_GINT64_MODIFIER "I64"
+#define G_GINT64_FORMAT "I64i"
+#define G_GUINT64_FORMAT "I64u"
+
+#if defined(_WIN64) || defined(_M_X64) || defined(_M_AMD64)
+
+#define GLIB_SIZEOF_VOID_P 8
+#define GLIB_SIZEOF_LONG 4
+#define GLIB_SIZEOF_SIZE_T 8
+
+typedef signed long long gssize;
+typedef unsigned long long gsize;
+#define G_GSIZE_MODIFIER "I64"
+#define G_GSSIZE_FORMAT "I64d"
+#define G_GSIZE_FORMAT "I64u"
+
+#define G_MAXSIZE G_MAXUINT64
+#define G_MINSSIZE G_MININT64
+#define G_MAXSSIZE G_MAXINT64
+
+#else
+
+#define GLIB_SIZEOF_VOID_P 4
+#define GLIB_SIZEOF_LONG 4
+#define GLIB_SIZEOF_SIZE_T 4
+
+typedef signed int gssize;
+typedef unsigned int gsize;
+#define G_GSIZE_MODIFIER ""
+#define G_GSSIZE_FORMAT "i"
+#define G_GSIZE_FORMAT "u"
+
+#define G_MAXSIZE G_MAXUINT
+#define G_MINSSIZE G_MININT
+#define G_MAXSSIZE G_MAXINT
+
+#endif
+
+typedef gint64 goffset;
+#define G_MINOFFSET G_MININT64
+#define G_MAXOFFSET G_MAXINT64
+
+#define G_GOFFSET_MODIFIER G_GINT64_MODIFIER
+#define G_GOFFSET_FORMAT G_GINT64_FORMAT
+#define G_GOFFSET_CONSTANT(val) G_GINT64_CONSTANT(val)
+
+
+#ifndef _WIN64
+
+#define GPOINTER_TO_INT(p) ((gint) (p))
+#define GPOINTER_TO_UINT(p) ((guint) (p))
+
+#define GINT_TO_POINTER(i) ((gpointer) (i))
+#define GUINT_TO_POINTER(u) ((gpointer) (u))
+
+typedef signed int gintptr;
+typedef unsigned int guintptr;
+
+#define G_GINTPTR_MODIFIER ""
+#define G_GINTPTR_FORMAT "i"
+#define G_GUINTPTR_FORMAT "u"
+
+#else
+
+#define GPOINTER_TO_INT(p) ((gint) (gint64) (p))
+#define GPOINTER_TO_UINT(p) ((guint) (guint64) (p))
+
+#define GINT_TO_POINTER(i) ((gpointer) (gint64) (i))
+#define GUINT_TO_POINTER(u) ((gpointer) (guint64) (u))
+
+#ifndef _MSC_VER
+typedef signed long long gintptr;
+typedef unsigned long long guintptr;
+#else
+typedef signed __int64 gintptr;
+typedef unsigned __int64 guintptr;
+#endif
+
+#define G_GINTPTR_MODIFIER "I64"
+#define G_GINTPTR_FORMAT "I64i"
+#define G_GUINTPTR_FORMAT "I64u"
+
+#endif
+
+#ifdef NeXT /* @#%@! NeXTStep */
+# define g_ATEXIT(proc) (!atexit (proc))
+#else
+# define g_ATEXIT(proc) (atexit (proc))
+#endif
+
+#define g_memmove(dest,src,len) G_STMT_START { memmove ((dest), (src), (len)); } G_STMT_END
+
+#define GLIB_MAJOR_VERSION 2
+#define GLIB_MINOR_VERSION 26
+#define GLIB_MICRO_VERSION 1
+
+#define G_OS_WIN32
+#define G_PLATFORM_WIN32
+
+
+#ifndef _MSC_VER
+#define G_VA_COPY va_copy
+#endif /* not _MSC_VER */
+
+#ifdef __cplusplus
+#define G_HAVE_INLINE 1
+#else /* !__cplusplus */
+#ifndef _MSC_VER
+#define G_HAVE_INLINE 1
+#endif /* _MSC_VER */
+#define G_HAVE___INLINE 1
+#if !defined(_MSC_VER) && !defined(__DMC__)
+#define G_HAVE___INLINE__ 1
+#endif /* !_MSC_VER and !__DMC__ */
+#endif /* !__cplusplus */
+
+#define G_CAN_INLINE 1
+
+#ifndef _MSC_VER
+#define G_HAVE_ISO_VARARGS 1
+
+/* gcc-2.95.x supports both gnu style and ISO varargs, but if -ansi
+ * is passed ISO vararg support is turned off, and there is no work
+ * around to turn it on, so we unconditionally turn it off.
+ */
+#if __GNUC__ == 2 && __GNUC_MINOR__ == 95
+# undef G_HAVE_ISO_VARARGS
+#endif
+
+#define G_HAVE_GNUC_VARARGS 1
+#else /* _MSC_VER */
+/* varargs macros available since msvc8 (vs2005) */
+# if _MSC_VER >= 1400
+# define G_HAVE_ISO_VARARGS 1
+# endif
+#endif /* not _MSC_VER */
+#define G_HAVE_GROWING_STACK 0
+
+#define G_GNUC_INTERNAL
+
+#define G_THREADS_ENABLED
+#define G_THREADS_IMPL_WIN32
+typedef struct _GMutex* GStaticMutex;
+#define G_STATIC_MUTEX_INIT NULL
+#define g_static_mutex_get_mutex(mutex) \
+ (g_static_mutex_get_mutex_impl_shortcut (mutex))
+/* This represents a system thread as used by the implementation. An
+ * alien implementaion, as loaded by g_thread_init can only count on
+ * "sizeof (gpointer)" bytes to store their info. We however need more
+ * for some of our native implementations. */
+typedef union _GSystemThread GSystemThread;
+union _GSystemThread
+{
+#ifndef _WIN64
+ char data[4];
+#else
+ char data[8];
+#endif
+ double dummy_double;
+ void *dummy_pointer;
+ long dummy_long;
+};
+
+#define GINT16_TO_LE(val) ((gint16) (val))
+#define GUINT16_TO_LE(val) ((guint16) (val))
+#define GINT16_TO_BE(val) ((gint16) GUINT16_SWAP_LE_BE (val))
+#define GUINT16_TO_BE(val) (GUINT16_SWAP_LE_BE (val))
+#define GINT32_TO_LE(val) ((gint32) (val))
+#define GUINT32_TO_LE(val) ((guint32) (val))
+#define GINT32_TO_BE(val) ((gint32) GUINT32_SWAP_LE_BE (val))
+#define GUINT32_TO_BE(val) (GUINT32_SWAP_LE_BE (val))
+#define GINT64_TO_LE(val) ((gint64) (val))
+#define GUINT64_TO_LE(val) ((guint64) (val))
+#define GINT64_TO_BE(val) ((gint64) GUINT64_SWAP_LE_BE (val))
+#define GUINT64_TO_BE(val) (GUINT64_SWAP_LE_BE (val))
+#define GLONG_TO_LE(val) ((glong) GINT32_TO_LE (val))
+#define GULONG_TO_LE(val) ((gulong) GUINT32_TO_LE (val))
+#define GLONG_TO_BE(val) ((glong) GINT32_TO_BE (val))
+#define GULONG_TO_BE(val) ((gulong) GUINT32_TO_BE (val))
+#define GINT_TO_LE(val) ((gint) GINT32_TO_LE (val))
+#define GUINT_TO_LE(val) ((guint) GUINT32_TO_LE (val))
+#define GINT_TO_BE(val) ((gint) GINT32_TO_BE (val))
+#define GUINT_TO_BE(val) ((guint) GUINT32_TO_BE (val))
+#define GSIZE_TO_LE(val) ((gsize) GUINT32_TO_LE (val))
+#define GSSIZE_TO_LE(val) ((gssize) GINT32_TO_LE (val))
+#define GSIZE_TO_BE(val) ((gsize) GUINT32_TO_BE (val))
+#define GSSIZE_TO_BE(val) ((gssize) GINT32_TO_BE (val))
+#define G_BYTE_ORDER G_LITTLE_ENDIAN
+
+#define GLIB_SYSDEF_POLLIN =1
+#define GLIB_SYSDEF_POLLOUT =4
+#define GLIB_SYSDEF_POLLPRI =2
+#define GLIB_SYSDEF_POLLHUP =16
+#define GLIB_SYSDEF_POLLERR =8
+#define GLIB_SYSDEF_POLLNVAL =32
+
+#define G_MODULE_SUFFIX "dll"
+
+/* A GPid is an abstraction for a process "handle". It is *not* an
+ * abstraction for a process identifier in general. GPid is used in
+ * GLib only for descendant processes spawned with the g_spawn*
+ * functions. On POSIX there is no "process handle" concept as such,
+ * but on Windows a GPid is a handle to a process, a kind of pointer,
+ * not a process identifier.
+ */
+typedef void * GPid;
+
+#define GLIB_SYSDEF_AF_UNIX 1
+#define GLIB_SYSDEF_AF_INET 2
+#define GLIB_SYSDEF_AF_INET6 23
+
+#define GLIB_SYSDEF_MSG_OOB 1
+#define GLIB_SYSDEF_MSG_PEEK 2
+#define GLIB_SYSDEF_MSG_DONTROUTE 4
+
+G_END_DECLS
+
+#endif /* GLIBCONFIG_H */
diff --git a/protocols/Sametime/src/glib/lib32/glib-2.0.lib b/protocols/Sametime/src/glib/lib32/glib-2.0.lib
new file mode 100644
index 0000000000..9ba0ee06e7
--- /dev/null
+++ b/protocols/Sametime/src/glib/lib32/glib-2.0.lib
Binary files differ
diff --git a/protocols/Sametime/src/glib/lib64/glib-2.0.lib b/protocols/Sametime/src/glib/lib64/glib-2.0.lib
new file mode 100644
index 0000000000..52616ec596
--- /dev/null
+++ b/protocols/Sametime/src/glib/lib64/glib-2.0.lib
Binary files differ
diff --git a/protocols/Sametime/src/meanwhile/AUTHORS b/protocols/Sametime/src/meanwhile/AUTHORS
new file mode 100644
index 0000000000..76f993f550
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/AUTHORS
@@ -0,0 +1,10 @@
+
+Maintainer:
+Christopher (siege) O'Brien <siege@preoccupied.net>
+
+Packager:
+Stepher Dawkins
+
+Patches:
+Chris Ross
+Jeremy Kerr
diff --git a/protocols/Sametime/src/meanwhile/LICENSE b/protocols/Sametime/src/meanwhile/LICENSE
new file mode 100644
index 0000000000..92b8903ff3
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/LICENSE
@@ -0,0 +1,481 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/protocols/Sametime/src/meanwhile/README b/protocols/Sametime/src/meanwhile/README
new file mode 100644
index 0000000000..fb83fec75e
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/README
@@ -0,0 +1,39 @@
+
+=====================
+The Meanwhile Project
+=====================
+
+http://meanwhile.sourceforge.net/
+Christopher (siege) O'Brien <siege@preoccupied.net>
+
+Meanwhile is a library for connecting to a LIM (Lotus Instant
+Messaging, formerly Lotus Sametime, formerly VPBuddy) community. It
+uses a protocol based in part off of the IMPP draft(*1), and in part
+off of traces of TCP sessions from existing clients.
+
+Meanwhile-python is a set of Python wrappers for the Meanwhile library
+
+The gaim-meanwhile plugin allows Gaim to connect to a Lotus Sametime
+(tm) community using a compiled-in version of libMeanwhile.
+
+See INSTALL for instructions on building and installing
+
+
+=======
+License
+=======
+
+Meanwhile and Meanwhile-python are released under the LGPL. See
+LICENSE for the full license text and terms.
+
+Meanwhile-gaim is released under the GPL
+
+
+=========
+Footnotes
+=========
+
+(*1) draft-houri-sametime-community-client-00.txt submitted to the
+IETF as a draft proposal for the IMPP working group charter.
+
+
diff --git a/protocols/Sametime/src/meanwhile/src/channel.c b/protocols/Sametime/src/meanwhile/src/channel.c
new file mode 100644
index 0000000000..a9dc2836be
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/channel.c
@@ -0,0 +1,972 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <glib.h>
+#include <glib/ghash.h>
+#include <glib/glist.h>
+#include <string.h>
+
+#include "mw_channel.h"
+#include "mw_cipher.h"
+#include "mw_debug.h"
+#include "mw_error.h"
+#include "mw_message.h"
+#include "mw_service.h"
+#include "mw_session.h"
+#include "mw_util.h"
+
+
+/** @todo reorganize this file, stuff is just strewn about */
+
+
+struct mwChannel {
+
+ /** session this channel belongs to */
+ struct mwSession *session;
+
+ enum mwChannelState state;
+
+ /** creator for incoming channel, target for outgoing channel */
+ struct mwLoginInfo user;
+
+ /* similar to data from the CreateCnl message in 8.4.1.7 */
+ guint32 reserved; /**< special, unknown meaning */
+ guint32 id; /**< channel ID */
+ guint32 service; /**< service ID */
+ guint32 proto_type; /**< service protocol type */
+ guint32 proto_ver; /**< service protocol version */
+ guint32 options; /**< channel options */
+
+ struct mwOpaque addtl_create;
+ struct mwOpaque addtl_accept;
+
+ /** all those supported ciphers */
+ GHashTable *supported;
+ guint16 offered_policy; /**< @see enum mwEncryptPolicy */
+ guint16 policy; /**< @see enum mwEncryptPolicy */
+
+ /** cipher information determined at channel acceptance */
+ struct mwCipherInstance *cipher;
+
+ /** statistics table */
+ GHashTable *stats;
+
+ GSList *outgoing_queue; /**< queued outgoing messages */
+ GSList *incoming_queue; /**< queued incoming messages */
+
+ struct mw_datum srvc_data; /**< service-specific data */
+};
+
+
+struct mwChannelSet {
+ struct mwSession *session; /**< owning session */
+ GHashTable *map; /**< map of all channels, by ID */
+ guint32 counter; /**< counter for outgoing ID */
+};
+
+
+static void flush_channel(struct mwChannel *);
+
+
+static const char *state_str(enum mwChannelState state) {
+ switch(state) {
+ case mwChannel_NEW: return "new";
+ case mwChannel_INIT: return "initializing";
+ case mwChannel_WAIT: return "waiting";
+ case mwChannel_OPEN: return "open";
+ case mwChannel_DESTROY: return "closing";
+ case mwChannel_ERROR: return "error";
+
+ case mwChannel_UNKNOWN: /* fall through */
+ default: return "UNKNOWN";
+ }
+}
+
+
+static void state(struct mwChannel *chan, enum mwChannelState state,
+ guint32 err_code) {
+
+ g_return_if_fail(chan != NULL);
+
+ if(chan->state == state) return;
+
+ chan->state = state;
+
+ if(err_code) {
+ g_message("channel 0x%08x state: %s (0x%08x)",
+ chan->id, state_str(state), err_code);
+ } else {
+ g_message("channel 0x%08x state: %s", chan->id, state_str(state));
+ }
+}
+
+
+static gpointer get_stat(struct mwChannel *chan,
+ enum mwChannelStatField field) {
+
+ return g_hash_table_lookup(chan->stats, (gpointer) field);
+}
+
+
+static void set_stat(struct mwChannel *chan, enum mwChannelStatField field,
+ gpointer val) {
+
+ g_hash_table_insert(chan->stats, (gpointer) field, val);
+}
+
+/// Miranda NG adaptation start - MSVC
+//#define incr_stat(chan, field, incr) \
+// set_stat(chan, field, get_stat(chan, field) + incr)
+#define incr_stat(chan, field, incr) \
+ set_stat(chan, field, (char*)get_stat(chan, field) + incr)
+/// Miranda NG adaptation end
+
+#define timestamp_stat(chan, field) \
+ set_stat(chan, field, (gpointer) time(NULL))
+
+
+static void sup_free(gpointer a) {
+ mwCipherInstance_free(a);
+}
+
+
+static struct mwCipherInstance *
+get_supported(struct mwChannel *chan, guint16 id) {
+
+ guint32 cid = (guint32) id;
+ return g_hash_table_lookup(chan->supported, GUINT_TO_POINTER(cid));
+}
+
+
+static void put_supported(struct mwChannel *chan,
+ struct mwCipherInstance *ci) {
+
+ struct mwCipher *cipher = mwCipherInstance_getCipher(ci);
+ guint32 cid = (guint32) mwCipher_getType(cipher);
+ g_hash_table_insert(chan->supported, GUINT_TO_POINTER(cid), ci);
+}
+
+
+struct mwChannel *mwChannel_newIncoming(struct mwChannelSet *cs, guint32 id) {
+ struct mwChannel *chan;
+
+ g_return_val_if_fail(cs != NULL, NULL);
+ g_return_val_if_fail(cs->session != NULL, NULL);
+
+ chan = g_new0(struct mwChannel, 1);
+ chan->state = mwChannel_NEW;
+ chan->session = cs->session;
+ chan->id = id;
+
+ chan->stats = g_hash_table_new(g_direct_hash, g_direct_equal);
+
+ chan->supported = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, sup_free);
+
+ g_hash_table_insert(cs->map, GUINT_TO_POINTER(id), chan);
+
+ state(chan, mwChannel_WAIT, 0);
+
+ return chan;
+}
+
+
+struct mwChannel *mwChannel_newOutgoing(struct mwChannelSet *cs) {
+ guint32 id;
+ struct mwChannel *chan;
+
+ g_return_val_if_fail(cs != NULL, NULL);
+ g_return_val_if_fail(cs->map != NULL, NULL);
+
+ /* grab the next id, and try to make sure there isn't already a
+ channel using it */
+ do {
+ id = ++cs->counter;
+ } while(g_hash_table_lookup(cs->map, GUINT_TO_POINTER(id)));
+
+ chan = mwChannel_newIncoming(cs, id);
+ state(chan, mwChannel_INIT, 0);
+
+ return chan;
+}
+
+
+guint32 mwChannel_getId(struct mwChannel *chan) {
+ g_return_val_if_fail(chan != NULL, 0);
+ return chan->id;
+}
+
+
+struct mwSession *mwChannel_getSession(struct mwChannel *chan) {
+ g_return_val_if_fail(chan != NULL, NULL);
+ return chan->session;
+}
+
+
+guint32 mwChannel_getServiceId(struct mwChannel *chan) {
+ g_return_val_if_fail(chan != NULL, 0);
+ return chan->service;
+}
+
+
+struct mwService *mwChannel_getService(struct mwChannel *chan) {
+ g_return_val_if_fail(chan != NULL, NULL);
+ return mwSession_getService(chan->session, chan->service);
+}
+
+
+void mwChannel_setService(struct mwChannel *chan, struct mwService *srvc) {
+ g_return_if_fail(chan != NULL);
+ g_return_if_fail(srvc != NULL);
+ g_return_if_fail(chan->state == mwChannel_INIT);
+ chan->service = mwService_getType(srvc);
+}
+
+
+gpointer mwChannel_getServiceData(struct mwChannel *chan) {
+ g_return_val_if_fail(chan != NULL, NULL);
+ return mw_datum_get(&chan->srvc_data);
+}
+
+
+void mwChannel_setServiceData(struct mwChannel *chan,
+ gpointer data, GDestroyNotify clean) {
+
+ g_return_if_fail(chan != NULL);
+ mw_datum_set(&chan->srvc_data, data, clean);
+}
+
+
+void mwChannel_removeServiceData(struct mwChannel *chan) {
+ g_return_if_fail(chan != NULL);
+ mw_datum_clear(&chan->srvc_data);
+}
+
+
+guint32 mwChannel_getProtoType(struct mwChannel *chan) {
+ g_return_val_if_fail(chan != NULL, 0x00);
+ return chan->proto_type;
+}
+
+
+void mwChannel_setProtoType(struct mwChannel *chan, guint32 proto_type) {
+ g_return_if_fail(chan != NULL);
+ g_return_if_fail(chan->state == mwChannel_INIT);
+ chan->proto_type = proto_type;
+}
+
+
+guint32 mwChannel_getProtoVer(struct mwChannel *chan) {
+ g_return_val_if_fail(chan != NULL, 0x00);
+ return chan->proto_ver;
+}
+
+
+void mwChannel_setProtoVer(struct mwChannel *chan, guint32 proto_ver) {
+ g_return_if_fail(chan != NULL);
+ g_return_if_fail(chan->state == mwChannel_INIT);
+ chan->proto_ver = proto_ver;
+}
+
+
+guint16 mwChannel_getEncryptPolicy(struct mwChannel *chan) {
+ g_return_val_if_fail(chan != NULL, 0x00);
+ return chan->policy;
+}
+
+
+guint32 mwChannel_getOptions(struct mwChannel *chan) {
+ g_return_val_if_fail(chan != NULL, 0x00);
+ return chan->options;
+}
+
+
+void mwChannel_setOptions(struct mwChannel *chan, guint32 options) {
+ g_return_if_fail(chan != NULL);
+ g_return_if_fail(chan->state == mwChannel_INIT);
+ chan->options = options;
+}
+
+
+struct mwLoginInfo *mwChannel_getUser(struct mwChannel *chan) {
+ g_return_val_if_fail(chan != NULL, NULL);
+ return &chan->user;
+}
+
+
+struct mwOpaque *mwChannel_getAddtlCreate(struct mwChannel *chan) {
+ g_return_val_if_fail(chan != NULL, NULL);
+ return &chan->addtl_create;
+}
+
+
+struct mwOpaque *mwChannel_getAddtlAccept(struct mwChannel *chan) {
+ g_return_val_if_fail(chan != NULL, NULL);
+ return &chan->addtl_accept;
+}
+
+
+struct mwCipherInstance *
+mwChannel_getCipherInstance(struct mwChannel *chan) {
+
+ g_return_val_if_fail(chan != NULL, NULL);
+ return chan->cipher;
+}
+
+
+enum mwChannelState mwChannel_getState(struct mwChannel *chan) {
+ g_return_val_if_fail(chan != NULL, mwChannel_UNKNOWN);
+ return chan->state;
+}
+
+
+gpointer mwChannel_getStatistic(struct mwChannel *chan,
+ enum mwChannelStatField stat) {
+
+ g_return_val_if_fail(chan != NULL, 0);
+ g_return_val_if_fail(chan->stats != NULL, 0);
+
+ return get_stat(chan, stat);
+}
+
+
+/* send a channel create message */
+int mwChannel_create(struct mwChannel *chan) {
+ struct mwMsgChannelCreate *msg;
+ GList *list, *l;
+ int ret;
+
+ g_return_val_if_fail(chan != NULL, -1);
+ g_return_val_if_fail(chan->state == mwChannel_INIT, -1);
+ g_return_val_if_fail(mwChannel_isOutgoing(chan), -1);
+
+ msg = (struct mwMsgChannelCreate *)
+ mwMessage_new(mwMessage_CHANNEL_CREATE);
+
+ msg->channel = chan->id;
+ msg->target.user = g_strdup(chan->user.user_id);
+ msg->target.community = g_strdup(chan->user.community);
+ msg->service = chan->service;
+ msg->proto_type = chan->proto_type;
+ msg->proto_ver = chan->proto_ver;
+ msg->options = chan->options;
+ mwOpaque_clone(&msg->addtl, &chan->addtl_create);
+
+ list = mwChannel_getSupportedCipherInstances(chan);
+ if(list) {
+ /* offer what we have */
+ for(l = list; l; l = l->next) {
+ struct mwEncryptItem *ei = mwCipherInstance_offer(l->data);
+ msg->encrypt.items = g_list_append(msg->encrypt.items, ei);
+ }
+
+ /* we're easy to get along with */
+ chan->offered_policy = mwEncrypt_WHATEVER;
+ g_list_free(list);
+
+ } else {
+ /* we apparently don't support anything */
+ chan->offered_policy = mwEncrypt_NONE;
+ }
+
+ msg->encrypt.mode = chan->offered_policy;
+ msg->encrypt.extra = chan->offered_policy;
+
+ ret = mwSession_send(chan->session, MW_MESSAGE(msg));
+ mwMessage_free(MW_MESSAGE(msg));
+
+ state(chan, (ret)? mwChannel_ERROR: mwChannel_WAIT, ret);
+
+ return ret;
+}
+
+
+static void channel_open(struct mwChannel *chan) {
+ state(chan, mwChannel_OPEN, 0);
+ timestamp_stat(chan, mwChannelStat_OPENED_AT);
+ flush_channel(chan);
+}
+
+
+int mwChannel_accept(struct mwChannel *chan) {
+ struct mwSession *session;
+ struct mwMsgChannelAccept *msg;
+ struct mwCipherInstance *ci;
+
+ int ret;
+
+ g_return_val_if_fail(chan != NULL, -1);
+ g_return_val_if_fail(mwChannel_isIncoming(chan), -1);
+ g_return_val_if_fail(chan->state == mwChannel_WAIT, -1);
+
+ session = chan->session;
+ g_return_val_if_fail(session != NULL, -1);
+
+ msg = (struct mwMsgChannelAccept *)
+ mwMessage_new(mwMessage_CHANNEL_ACCEPT);
+
+ msg->head.channel = chan->id;
+ msg->service = chan->service;
+ msg->proto_type = chan->proto_type;
+ msg->proto_ver = chan->proto_ver;
+ mwOpaque_clone(&msg->addtl, &chan->addtl_accept);
+
+ ci = chan->cipher;
+
+ if(! ci) {
+ /* automatically select a cipher if one hasn't been already */
+
+ switch(chan->offered_policy) {
+ case mwEncrypt_NONE:
+ mwChannel_selectCipherInstance(chan, NULL);
+ break;
+
+ case mwEncrypt_RC2_40:
+ ci = get_supported(chan, mwCipher_RC2_40);
+ mwChannel_selectCipherInstance(chan, ci);
+ break;
+
+ case mwEncrypt_RC2_128:
+ ci = get_supported(chan, mwCipher_RC2_128);
+ mwChannel_selectCipherInstance(chan, ci);
+ break;
+
+ case mwEncrypt_WHATEVER:
+ case mwEncrypt_ALL:
+ default:
+ {
+ GList *l, *ll;
+
+ l = mwChannel_getSupportedCipherInstances(chan);
+ if(l) {
+ /* nobody selected a cipher, so we'll just pick the last in
+ the list of available ones */
+ for(ll = l; ll->next; ll = ll->next);
+ ci = ll->data;
+ g_list_free(l);
+
+ mwChannel_selectCipherInstance(chan, ci);
+
+ } else {
+ /* this may cause breakage, but there's really nothing else
+ we can do. They want something we can't provide. If they
+ don't like it, then they'll error the channel out */
+ mwChannel_selectCipherInstance(chan, NULL);
+ }
+ }
+ }
+ }
+
+ msg->encrypt.mode = chan->policy; /* set in selectCipherInstance */
+ msg->encrypt.extra = chan->offered_policy;
+
+ if(chan->cipher) {
+ msg->encrypt.item = mwCipherInstance_accept(chan->cipher);
+ }
+
+ ret = mwSession_send(session, MW_MESSAGE(msg));
+ mwMessage_free(MW_MESSAGE(msg));
+
+ if(ret) {
+ state(chan, mwChannel_ERROR, ret);
+ } else {
+ channel_open(chan);
+ }
+
+ return ret;
+}
+
+
+static void channel_free(struct mwChannel *chan) {
+ struct mwSession *s;
+ struct mwMessage *msg;
+ GSList *l;
+
+ /* maybe no warning in the future */
+ g_return_if_fail(chan != NULL);
+
+ s = chan->session;
+
+ mwLoginInfo_clear(&chan->user);
+ mwOpaque_clear(&chan->addtl_create);
+ mwOpaque_clear(&chan->addtl_accept);
+
+ if(chan->supported) {
+ g_hash_table_destroy(chan->supported);
+ chan->supported = NULL;
+ }
+
+ if(chan->stats) {
+ g_hash_table_destroy(chan->stats);
+ chan->stats = NULL;
+ }
+
+ mwCipherInstance_free(chan->cipher);
+
+ /* clean up the outgoing queue */
+ for(l = chan->outgoing_queue; l; l = l->next) {
+ msg = (struct mwMessage *) l->data;
+ l->data = NULL;
+ mwMessage_free(msg);
+ }
+ g_slist_free(chan->outgoing_queue);
+
+ /* clean up the incoming queue */
+ for(l = chan->incoming_queue; l; l = l->next) {
+ msg = (struct mwMessage *) l->data;
+ l->data = NULL;
+ mwMessage_free(msg);
+ }
+ g_slist_free(chan->incoming_queue);
+
+ g_free(chan);
+}
+
+
+int mwChannel_destroy(struct mwChannel *chan,
+ guint32 reason, struct mwOpaque *info) {
+
+ struct mwMsgChannelDestroy *msg;
+ struct mwSession *session;
+ struct mwChannelSet *cs;
+ int ret;
+
+ /* may make this not a warning in the future */
+ g_return_val_if_fail(chan != NULL, 0);
+
+ state(chan, reason? mwChannel_ERROR: mwChannel_DESTROY, reason);
+
+ session = chan->session;
+ g_return_val_if_fail(session != NULL, -1);
+
+ cs = mwSession_getChannels(session);
+ g_return_val_if_fail(cs != NULL, -1);
+
+ /* compose the message */
+ msg = (struct mwMsgChannelDestroy *)
+ mwMessage_new(mwMessage_CHANNEL_DESTROY);
+ msg->head.channel = chan->id;
+ msg->reason = reason;
+ if(info) mwOpaque_clone(&msg->data, info);
+
+ /* remove the channel from the channel set */
+ g_hash_table_remove(cs->map, GUINT_TO_POINTER(chan->id));
+
+ /* send the message */
+ ret = mwSession_send(session, (struct mwMessage *) msg);
+ mwMessage_free(MW_MESSAGE(msg));
+
+ return ret;
+}
+
+
+static void queue_outgoing(struct mwChannel *chan,
+ struct mwMsgChannelSend *msg) {
+ // Miranda NG adaptation
+ //g_info("queue_outgoing, channel 0x%08x", chan->id);
+ g_message("queue_outgoing, channel 0x%08x", chan->id);
+ chan->outgoing_queue = g_slist_append(chan->outgoing_queue, msg);
+}
+
+
+static int channel_send(struct mwChannel *chan,
+ struct mwMsgChannelSend *msg) {
+
+ int ret = 0;
+
+ /* if the channel is open, send and free the message. Otherwise,
+ queue the message to be sent once the channel is finally
+ opened */
+
+ if(chan->state == mwChannel_OPEN) {
+ ret = mwSession_send(chan->session, (struct mwMessage *) msg);
+ mwMessage_free(MW_MESSAGE(msg));
+
+ } else {
+ queue_outgoing(chan, msg);
+ }
+
+ return ret;
+}
+
+
+int mwChannel_sendEncrypted(struct mwChannel *chan,
+ guint32 type, struct mwOpaque *data,
+ gboolean encrypt) {
+
+ struct mwMsgChannelSend *msg;
+
+ g_return_val_if_fail(chan != NULL, -1);
+
+ msg = (struct mwMsgChannelSend *) mwMessage_new(mwMessage_CHANNEL_SEND);
+ msg->head.channel = chan->id;
+ msg->type = type;
+
+ mwOpaque_clone(&msg->data, data);
+
+ if(encrypt && chan->cipher) {
+ msg->head.options = mwMessageOption_ENCRYPT;
+ mwCipherInstance_encrypt(chan->cipher, &msg->data);
+ }
+
+ return channel_send(chan, msg);
+}
+
+
+int mwChannel_send(struct mwChannel *chan, guint32 type,
+ struct mwOpaque *data) {
+
+ return mwChannel_sendEncrypted(chan, type, data, TRUE);
+}
+
+
+static void queue_incoming(struct mwChannel *chan,
+ struct mwMsgChannelSend *msg) {
+
+ /* we clone the message, because session_process will clear it once
+ we return */
+
+ struct mwMsgChannelSend *m = g_new0(struct mwMsgChannelSend, 1);
+ m->head.type = msg->head.type;
+ m->head.options = msg->head.options;
+ m->head.channel = msg->head.channel;
+ mwOpaque_clone(&m->head.attribs, &msg->head.attribs);
+
+ m->type = msg->type;
+ mwOpaque_clone(&m->data, &msg->data);
+
+ // Miranda NG adaptation
+ //g_info("queue_incoming, channel 0x%08x", chan->id);
+ g_message("queue_incoming, channel 0x%08x", chan->id);
+ chan->incoming_queue = g_slist_append(chan->incoming_queue, m);
+}
+
+
+static void channel_recv(struct mwChannel *chan,
+ struct mwMsgChannelSend *msg) {
+
+ struct mwService *srvc;
+
+ srvc = mwChannel_getService(chan);
+ incr_stat(chan, mwChannelStat_MSG_RECV, 1);
+
+ if(msg->head.options & mwMessageOption_ENCRYPT) {
+ struct mwOpaque data = { 0, 0 };
+ mwOpaque_clone(&data, &msg->data);
+
+ mwCipherInstance_decrypt(chan->cipher, &data);
+ mwService_recv(srvc, chan, msg->type, &data);
+ mwOpaque_clear(&data);
+
+ } else {
+ mwService_recv(srvc, chan, msg->type, &msg->data);
+ }
+}
+
+
+static void flush_channel(struct mwChannel *chan) {
+ GSList *l;
+
+ for(l = chan->incoming_queue; l; l = l->next) {
+ struct mwMsgChannelSend *msg = (struct mwMsgChannelSend *) l->data;
+ l->data = NULL;
+
+ channel_recv(chan, msg);
+ mwMessage_free(MW_MESSAGE(msg));
+ }
+ g_slist_free(chan->incoming_queue);
+ chan->incoming_queue = NULL;
+
+ for(l = chan->outgoing_queue; l; l = l->next) {
+ struct mwMessage *msg = (struct mwMessage *) l->data;
+ l->data = NULL;
+
+ mwSession_send(chan->session, msg);
+ mwMessage_free(msg);
+ }
+ g_slist_free(chan->outgoing_queue);
+ chan->outgoing_queue = NULL;
+}
+
+
+void mwChannel_recv(struct mwChannel *chan, struct mwMsgChannelSend *msg) {
+ if(chan->state == mwChannel_OPEN) {
+ channel_recv(chan, msg);
+
+ } else {
+ queue_incoming(chan, msg);
+ }
+}
+
+
+struct mwChannel *mwChannel_find(struct mwChannelSet *cs, guint32 chan) {
+ g_return_val_if_fail(cs != NULL, NULL);
+ g_return_val_if_fail(cs->map != NULL, NULL);
+ return g_hash_table_lookup(cs->map, GUINT_TO_POINTER(chan));
+}
+
+
+void mwChannelSet_free(struct mwChannelSet *cs) {
+ if(! cs) return;
+ if(cs->map) g_hash_table_destroy(cs->map);
+ g_free(cs);
+}
+
+
+struct mwChannelSet *mwChannelSet_new(struct mwSession *s) {
+ struct mwChannelSet *cs = g_new0(struct mwChannelSet, 1);
+ cs->session = s;
+
+ /* for some reason, g_int_hash/g_int_equal cause a SIGSEGV */
+ cs->map = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify) channel_free);
+ return cs;
+}
+
+
+void mwChannel_recvCreate(struct mwChannel *chan,
+ struct mwMsgChannelCreate *msg) {
+
+ struct mwSession *session;
+ GList *list;
+ struct mwService *srvc;
+
+ g_return_if_fail(chan != NULL);
+ g_return_if_fail(msg != NULL);
+ g_return_if_fail(chan->id == msg->channel);
+
+ session = chan->session;
+ g_return_if_fail(session != NULL);
+
+ if(mwChannel_isOutgoing(chan)) {
+ g_warning("channel 0x%08x not an incoming channel", chan->id);
+ mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL);
+ return;
+ }
+
+ chan->offered_policy = msg->encrypt.mode;
+ g_message("channel offered with encrypt policy 0x%04x", chan->policy);
+
+ for(list = msg->encrypt.items; list; list = list->next) {
+ struct mwEncryptItem *ei = list->data;
+ struct mwCipher *cipher;
+ struct mwCipherInstance *ci;
+
+ g_message("channel offered cipher id 0x%04x", ei->id);
+ cipher = mwSession_getCipher(session, ei->id);
+ if(! cipher) {
+ g_message("no such cipher found in session");
+ continue;
+ }
+
+ ci = mwCipher_newInstance(cipher, chan);
+ mwCipherInstance_offered(ci, ei);
+ mwChannel_addSupportedCipherInstance(chan, ci);
+ }
+
+ mwLoginInfo_clone(&chan->user, &msg->creator);
+ chan->service = msg->service;
+ chan->proto_type = msg->proto_type;
+ chan->proto_ver = msg->proto_ver;
+
+ srvc = mwSession_getService(session, msg->service);
+ if(srvc) {
+ mwService_recvCreate(srvc, chan, msg);
+
+ } else {
+ mwChannel_destroy(chan, ERR_SERVICE_NO_SUPPORT, NULL);
+ }
+}
+
+
+void mwChannel_recvAccept(struct mwChannel *chan,
+ struct mwMsgChannelAccept *msg) {
+
+ struct mwService *srvc;
+
+ g_return_if_fail(chan != NULL);
+ g_return_if_fail(msg != NULL);
+ g_return_if_fail(chan->id == msg->head.channel);
+
+ if(mwChannel_isIncoming(chan)) {
+ g_warning("channel 0x%08x not an outgoing channel", chan->id);
+ mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL);
+ return;
+ }
+
+ if(chan->state != mwChannel_WAIT) {
+ g_warning("channel 0x%08x state not WAIT: %s",
+ chan->id, state_str(chan->state));
+ mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL);
+ return;
+ }
+
+ mwLoginInfo_clone(&chan->user, &msg->acceptor);
+
+ srvc = mwSession_getService(chan->session, chan->service);
+ if(! srvc) {
+ g_warning("no service: 0x%08x", chan->service);
+ mwChannel_destroy(chan, ERR_SERVICE_NO_SUPPORT, NULL);
+ return;
+ }
+
+ chan->policy = msg->encrypt.mode;
+ g_message("channel accepted with encrypt policy 0x%04x", chan->policy);
+
+ if(! msg->encrypt.mode || ! msg->encrypt.item) {
+ /* no mode or no item means no encryption */
+ mwChannel_selectCipherInstance(chan, NULL);
+
+ } else {
+ guint16 cid = msg->encrypt.item->id;
+ struct mwCipherInstance *ci = get_supported(chan, cid);
+
+ if(! ci) {
+ g_warning("not an offered cipher: 0x%04x", cid);
+ mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL);
+ return;
+ }
+
+ mwCipherInstance_accepted(ci, msg->encrypt.item);
+ mwChannel_selectCipherInstance(chan, ci);
+ }
+
+ /* mark it as open for the service */
+ state(chan, mwChannel_OPEN, 0);
+
+ /* let the service know */
+ mwService_recvAccept(srvc, chan, msg);
+
+ /* flush it if the service didn't just immediately close it */
+ if(mwChannel_isState(chan, mwChannel_OPEN)) {
+ channel_open(chan);
+ }
+}
+
+
+void mwChannel_recvDestroy(struct mwChannel *chan,
+ struct mwMsgChannelDestroy *msg) {
+
+ struct mwChannelSet *cs;
+ struct mwService *srvc;
+
+ g_return_if_fail(chan != NULL);
+ g_return_if_fail(msg != NULL);
+ g_return_if_fail(chan->id == msg->head.channel);
+
+ state(chan, msg->reason? mwChannel_ERROR: mwChannel_DESTROY, msg->reason);
+
+ srvc = mwChannel_getService(chan);
+ if(srvc) mwService_recvDestroy(srvc, chan, msg);
+
+ cs = mwSession_getChannels(chan->session);
+ g_return_if_fail(cs != NULL);
+ g_return_if_fail(cs->map != NULL);
+
+ g_hash_table_remove(cs->map, GUINT_TO_POINTER(chan->id));
+}
+
+
+void mwChannel_populateSupportedCipherInstances(struct mwChannel *chan) {
+ struct mwSession *session;
+ GList *list;
+
+ g_return_if_fail(chan != NULL);
+
+ session = chan->session;
+ g_return_if_fail(session != NULL);
+
+ for(list = mwSession_getCiphers(session); list; list = list->next) {
+ struct mwCipherInstance *ci = mwCipher_newInstance(list->data, chan);
+ if(! ci) continue;
+ put_supported(chan, ci);
+ }
+}
+
+
+void mwChannel_addSupportedCipherInstance(struct mwChannel *chan,
+ struct mwCipherInstance *ci) {
+ g_return_if_fail(chan != NULL);
+ g_message("channel 0x%08x added cipher %s", chan->id,
+ NSTR(mwCipher_getName(mwCipherInstance_getCipher(ci))));
+ put_supported(chan, ci);
+}
+
+
+static void collect(gpointer a, gpointer b, gpointer c) {
+ GList **list = c;
+ *list = g_list_append(*list, b);
+}
+
+
+GList *mwChannel_getSupportedCipherInstances(struct mwChannel *chan) {
+ GList *list = NULL;
+
+ g_return_val_if_fail(chan != NULL, NULL);
+ g_hash_table_foreach(chan->supported, collect, &list);
+
+ return list;
+}
+
+
+void mwChannel_selectCipherInstance(struct mwChannel *chan,
+ struct mwCipherInstance *ci) {
+ struct mwCipher *c;
+
+ g_return_if_fail(chan != NULL);
+ g_return_if_fail(chan->supported != NULL);
+
+ chan->cipher = ci;
+ if(ci) {
+ guint cid;
+
+ c = mwCipherInstance_getCipher(ci);
+ cid = mwCipher_getType(c);
+
+ g_hash_table_steal(chan->supported, GUINT_TO_POINTER(cid));
+
+ switch(mwCipher_getType(c)) {
+ case mwCipher_RC2_40:
+ chan->policy = mwEncrypt_RC2_40;
+ break;
+
+ case mwCipher_RC2_128:
+ chan->policy = mwEncrypt_RC2_128;
+ break;
+
+ default:
+ /* unsure if this is bad */
+ chan->policy = mwEncrypt_WHATEVER;
+ }
+
+ g_message("channel 0x%08x selected cipher %s",
+ chan->id, NSTR(mwCipher_getName(c)));
+
+ } else {
+
+ chan->policy = mwEncrypt_NONE;
+ g_message("channel 0x%08x selected no cipher", chan->id);
+ }
+
+ g_hash_table_destroy(chan->supported);
+ chan->supported = NULL;
+}
+
+
diff --git a/protocols/Sametime/src/meanwhile/src/cipher.c b/protocols/Sametime/src/meanwhile/src/cipher.c
new file mode 100644
index 0000000000..8e5bd6f042
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/cipher.c
@@ -0,0 +1,982 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <stdlib.h>
+#include <time.h>
+
+#include "mpi/mpi.h"
+
+#include "mw_channel.h"
+#include "mw_cipher.h"
+#include "mw_debug.h"
+#include "mw_session.h"
+
+
+struct mwMpi {
+ mw_mp_int i;
+};
+
+
+/** From RFC2268 */
+static guchar PT[] = {
+ 0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED,
+ 0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D,
+ 0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E,
+ 0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2,
+ 0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13,
+ 0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32,
+ 0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B,
+ 0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82,
+ 0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C,
+ 0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC,
+ 0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1,
+ 0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26,
+ 0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57,
+ 0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03,
+ 0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7,
+ 0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7,
+ 0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7,
+ 0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A,
+ 0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74,
+ 0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC,
+ 0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC,
+ 0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39,
+ 0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A,
+ 0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31,
+ 0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE,
+ 0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9,
+ 0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C,
+ 0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9,
+ 0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0,
+ 0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E,
+ 0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77,
+ 0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD
+};
+
+
+/** prime number used in DH exchange */
+static guchar dh_prime[] = {
+ 0xCF, 0x84, 0xAF, 0xCE, 0x86, 0xDD, 0xFA, 0x52,
+ 0x7F, 0x13, 0x6D, 0x10, 0x35, 0x75, 0x28, 0xEE,
+ 0xFB, 0xA0, 0xAF, 0xEF, 0x80, 0x8F, 0x29, 0x17,
+ 0x4E, 0x3B, 0x6A, 0x9E, 0x97, 0x00, 0x01, 0x71,
+ 0x7C, 0x8F, 0x10, 0x6C, 0x41, 0xC1, 0x61, 0xA6,
+ 0xCE, 0x91, 0x05, 0x7B, 0x34, 0xDA, 0x62, 0xCB,
+ 0xB8, 0x7B, 0xFD, 0xC1, 0xB3, 0x5C, 0x1B, 0x91,
+ 0x0F, 0xEA, 0x72, 0x24, 0x9D, 0x56, 0x6B, 0x9F
+};
+
+
+/** base used in DH exchange */
+#define DH_BASE 3
+
+
+struct mwMpi *mwMpi_new() {
+ struct mwMpi *i;
+ i = g_new0(struct mwMpi, 1);
+ mw_mp_init(&i->i);
+ return i;
+}
+
+
+void mwMpi_free(struct mwMpi *i) {
+ if(! i) return;
+ mw_mp_clear(&i->i);
+ g_free(i);
+}
+
+
+static void mwInitDHPrime(mw_mp_int *i) {
+ mw_mp_init(i);
+ mw_mp_read_unsigned_bin(i, dh_prime, 64);
+}
+
+
+void mwMpi_setDHPrime(struct mwMpi *i) {
+ g_return_if_fail(i != NULL);
+ mw_mp_read_unsigned_bin(&i->i, dh_prime, 64);
+}
+
+
+static void mwInitDHBase(mw_mp_int *i) {
+ mw_mp_init(i);
+ mw_mp_set_int(i, DH_BASE);
+}
+
+
+void mwMpi_setDHBase(struct mwMpi *i) {
+ g_return_if_fail(i != NULL);
+ mw_mp_set_int(&i->i, DH_BASE);
+}
+
+
+static void mw_mp_set_rand(mw_mp_int *i, guint bits) {
+ size_t len, l;
+ guchar *buf;
+
+ l = len = (bits / 8) + 1;
+ buf = g_malloc(len);
+
+ /// Miranda NG adaptation start - MSVC
+ //srand(time(NULL));
+ srand((unsigned int)time(NULL));
+ /// Miranda NG adaptation end
+
+ while(l--) buf[l] = rand() & 0xff;
+
+ buf[0] &= (0xff >> (8 - (bits % 8)));
+
+ mw_mp_read_unsigned_bin(i, buf, len);
+ g_free(buf);
+}
+
+
+static void mwDHRandKeypair(mw_mp_int *private_key, mw_mp_int *public_key) {
+ mw_mp_int prime, base;
+
+ mwInitDHPrime(&prime);
+ mwInitDHBase(&base);
+
+ mw_mp_set_rand(private_key, 512);
+ mw_mp_exptmod(&base, private_key, &prime, public_key);
+
+ mw_mp_clear(&prime);
+ mw_mp_clear(&base);
+}
+
+
+void mwMpi_randDHKeypair(struct mwMpi *private_key, struct mwMpi *public_key) {
+ g_return_if_fail(private_key != NULL);
+ g_return_if_fail(public_key != NULL);
+
+ mwDHRandKeypair(&private_key->i, &public_key->i);
+}
+
+
+static void mwDHCalculateShared(mw_mp_int *shared_key, mw_mp_int *remote_key,
+ mw_mp_int *private_key) {
+ mw_mp_int prime;
+
+ mwInitDHPrime(&prime);
+ mw_mp_exptmod(remote_key, private_key, &prime, shared_key);
+ mw_mp_clear(&prime);
+}
+
+
+void mwMpi_calculateDHShared(struct mwMpi *shared_key, struct mwMpi *remote_key,
+ struct mwMpi *private_key) {
+
+ g_return_if_fail(shared_key != NULL);
+ g_return_if_fail(remote_key != NULL);
+ g_return_if_fail(private_key != NULL);
+
+ mwDHCalculateShared(&shared_key->i, &remote_key->i, &private_key->i);
+}
+
+
+static void mwDHImportKey(mw_mp_int *key, struct mwOpaque *o) {
+ mw_mp_read_unsigned_bin(key, o->data, o->len);
+}
+
+
+void mwMpi_import(struct mwMpi *i, struct mwOpaque *o) {
+ g_return_if_fail(i != NULL);
+ g_return_if_fail(o != NULL);
+
+ mwDHImportKey(&i->i, o);
+}
+
+
+static void mwDHExportKey(mw_mp_int *key, struct mwOpaque *o) {
+ o->len = mw_mp_unsigned_bin_size(key);
+ o->data = g_malloc0(o->len);
+ mw_mp_to_unsigned_bin(key, o->data);
+}
+
+
+void mwMpi_export(struct mwMpi *i, struct mwOpaque *o) {
+ g_return_if_fail(i != NULL);
+ g_return_if_fail(o != NULL);
+
+ mwDHExportKey(&i->i, o);
+}
+
+
+void mwKeyRandom(guchar *key, gsize keylen) {
+ g_return_if_fail(key != NULL);
+
+ /// Miranda NG adaptation start - MSVC
+ //srand(time(NULL));
+ srand((unsigned int)time(NULL));
+ /// Miranda NG adaptation end
+ while(keylen--) key[keylen] = rand() & 0xff;
+}
+
+
+void mwIV_init(guchar *iv) {
+ iv[0] = 0x01;
+ iv[1] = 0x23;
+ iv[2] = 0x45;
+ iv[3] = 0x67;
+ iv[4] = 0x89;
+ iv[5] = 0xab;
+ iv[6] = 0xcd;
+ iv[7] = 0xef;
+}
+
+
+/* This does not seem to produce the same results as normal RC2 key
+ expansion would, but it works, so eh. It might be smart to farm
+ this out to mozilla or openssl */
+void mwKeyExpand(int *ekey, const guchar *key, gsize keylen) {
+ guchar tmp[128];
+ int i, j;
+
+ g_return_if_fail(keylen > 0);
+ g_return_if_fail(key != NULL);
+
+ if(keylen > 128) keylen = 128;
+
+ /* fill the first chunk with what key bytes we have */
+ for(i = keylen; i--; tmp[i] = key[i]);
+ /* memcpy(tmp, key, keylen); */
+
+ /* build the remaining key from the given data */
+ for(i = 0; keylen < 128; i++) {
+ tmp[keylen] = PT[ (tmp[keylen - 1] + tmp[i]) & 0xff ];
+ keylen++;
+ }
+
+ tmp[0] = PT[ tmp[0] & 0xff ];
+
+ for(i = 0, j = 0; i < 64; i++) {
+ ekey[i] = (tmp[j] & 0xff) | (tmp[j+1] << 8);
+ j += 2;
+ }
+}
+
+
+/* normal RC2 encryption given a full 128-byte (as 64 ints) key */
+static void mwEncryptBlock(const int *ekey, guchar *out) {
+
+ int a, b, c, d;
+ int i, j;
+
+ a = (out[7] << 8) | (out[6] & 0xff);
+ b = (out[5] << 8) | (out[4] & 0xff);
+ c = (out[3] << 8) | (out[2] & 0xff);
+ d = (out[1] << 8) | (out[0] & 0xff);
+
+ for(i = 0; i < 16; i++) {
+ j = i * 4;
+
+ d += ((c & (a ^ 0xffff)) + (b & a) + ekey[j++]);
+ d = (d << 1) | (d >> 15 & 0x0001);
+
+ c += ((b & (d ^ 0xffff)) + (a & d) + ekey[j++]);
+ c = (c << 2) | (c >> 14 & 0x0003);
+
+ b += ((a & (c ^ 0xffff)) + (d & c) + ekey[j++]);
+ b = (b << 3) | (b >> 13 & 0x0007);
+
+ a += ((d & (b ^ 0xffff)) + (c & b) + ekey[j++]);
+ a = (a << 5) | (a >> 11 & 0x001f);
+
+ if(i == 4 || i == 10) {
+ d += ekey[a & 0x003f];
+ c += ekey[d & 0x003f];
+ b += ekey[c & 0x003f];
+ a += ekey[b & 0x003f];
+ }
+ }
+
+ *out++ = d & 0xff;
+ *out++ = (d >> 8) & 0xff;
+ *out++ = c & 0xff;
+ *out++ = (c >> 8) & 0xff;
+ *out++ = b & 0xff;
+ *out++ = (b >> 8) & 0xff;
+ *out++ = a & 0xff;
+ *out++ = (a >> 8) & 0xff;
+}
+
+
+void mwEncryptExpanded(const int *ekey, guchar *iv,
+ struct mwOpaque *in_data,
+ struct mwOpaque *out_data) {
+
+ guchar *i = in_data->data;
+ gsize i_len = in_data->len;
+
+ guchar *o;
+ gsize o_len;
+
+ /// Miranda NG adaptation start - MSVC
+ ///int x, y;
+ gsize x;
+ int y;
+ /// Miranda NG adaptation end
+
+ /* pad upwards to a multiple of 8 */
+ /* o_len = (i_len & -8) + 8; */
+ o_len = i_len + (8 - (i_len % 8));
+ o = g_malloc(o_len);
+
+ out_data->data = o;
+ out_data->len = o_len;
+
+ /* figure out the amount of padding */
+ y = o_len - i_len;
+
+ /* copy in to out, and write padding bytes */
+ for(x = i_len; x--; o[x] = i[x]);
+ for(x = i_len; x < o_len; o[x++] = y);
+ /* memcpy(o, i, i_len);
+ memset(o + i_len, y, y); */
+
+ /* encrypt in blocks */
+ for(x = o_len; x > 0; x -= 8) {
+ for(y = 8; y--; o[y] ^= iv[y]);
+ mwEncryptBlock(ekey, o);
+ for(y = 8; y--; iv[y] = o[y]);
+ /* memcpy(iv, o, 8); */
+ o += 8;
+ }
+}
+
+
+void mwEncrypt(const guchar *key, gsize keylen, guchar *iv,
+ struct mwOpaque *in, struct mwOpaque *out) {
+
+ int ekey[64];
+ mwKeyExpand(ekey, key, keylen);
+ mwEncryptExpanded(ekey, iv, in, out);
+}
+
+
+static void mwDecryptBlock(const int *ekey, guchar *out) {
+
+ int a, b, c, d;
+ int i, j;
+
+ a = (out[7] << 8) | (out[6] & 0xff);
+ b = (out[5] << 8) | (out[4] & 0xff);
+ c = (out[3] << 8) | (out[2] & 0xff);
+ d = (out[1] << 8) | (out[0] & 0xff);
+
+ for(i = 16; i--; ) {
+ j = i * 4 + 3;
+
+ a = (a << 11) | (a >> 5 & 0x07ff);
+ a -= ((d & (b ^ 0xffff)) + (c & b) + ekey[j--]);
+
+ b = (b << 13) | (b >> 3 & 0x1fff);
+ b -= ((a & (c ^ 0xffff)) + (d & c) + ekey[j--]);
+
+ c = (c << 14) | (c >> 2 & 0x3fff);
+ c -= ((b & (d ^ 0xffff)) + (a & d) + ekey[j--]);
+
+ d = (d << 15) | (d >> 1 & 0x7fff);
+ d -= ((c & (a ^ 0xffff)) + (b & a) + ekey[j--]);
+
+ if(i == 5 || i == 11) {
+ a -= ekey[b & 0x003f];
+ b -= ekey[c & 0x003f];
+ c -= ekey[d & 0x003f];
+ d -= ekey[a & 0x003f];
+ }
+ }
+
+ *out++ = d & 0xff;
+ *out++ = (d >> 8) & 0xff;
+ *out++ = c & 0xff;
+ *out++ = (c >> 8) & 0xff;
+ *out++ = b & 0xff;
+ *out++ = (b >> 8) & 0xff;
+ *out++ = a & 0xff;
+ *out++ = (a >> 8) & 0xff;
+}
+
+
+void mwDecryptExpanded(const int *ekey, guchar *iv,
+ struct mwOpaque *in_data,
+ struct mwOpaque *out_data) {
+
+ guchar *i = in_data->data;
+ gsize i_len = in_data->len;
+
+ guchar *o;
+ gsize o_len;
+
+ int x, y;
+
+ if(i_len % 8) {
+ /* this doesn't check to ensure that in_data->len is a multiple of
+ 8, which is damn well ought to be. */
+ g_warning("attempting decryption of mis-sized data, %u bytes",
+ (guint) i_len);
+ }
+
+ o = g_malloc(i_len);
+ o_len = i_len;
+ for(x = i_len; x--; o[x] = i[x]);
+ /* memcpy(o, i, i_len); */
+
+ out_data->data = o;
+ out_data->len = o_len;
+
+ for(x = o_len; x > 0; x -= 8) {
+ /* decrypt a block */
+ mwDecryptBlock(ekey, o);
+
+ /* modify the initialization vector */
+ for(y = 8; y--; o[y] ^= iv[y]);
+ for(y = 8; y--; iv[y] = i[y]);
+ /* memcpy(iv, i, 8); */
+ i += 8;
+ o += 8;
+ }
+
+ /* shorten the length by the value of the filler in the padding
+ bytes */
+ out_data->len -= *(o - 1);
+}
+
+
+void mwDecrypt(const guchar *key, gsize keylen, guchar *iv,
+ struct mwOpaque *in, struct mwOpaque *out) {
+
+ int ekey[64];
+ mwKeyExpand(ekey, key, keylen);
+ mwDecryptExpanded(ekey, iv, in, out);
+}
+
+
+
+struct mwCipher_RC2_40 {
+ struct mwCipher cipher;
+ int session_key[64];
+ gboolean ready;
+};
+
+
+struct mwCipherInstance_RC2_40 {
+ struct mwCipherInstance instance;
+ int incoming_key[64];
+ guchar outgoing_iv[8];
+ guchar incoming_iv[8];
+};
+
+
+static const char *get_name_RC2_40() {
+ return "RC2/40 Cipher";
+}
+
+
+static const char *get_desc_RC2_40() {
+ return "RC2, 40-bit effective key";
+}
+
+
+static int encrypt_RC2_40(struct mwCipherInstance *ci,
+ struct mwOpaque *data) {
+
+ struct mwCipherInstance_RC2_40 *cir;
+ struct mwCipher_RC2_40 *cr;
+ struct mwOpaque o = { 0, 0 };
+
+ cir = (struct mwCipherInstance_RC2_40 *) ci;
+ cr = (struct mwCipher_RC2_40 *) ci->cipher;
+
+ mwEncryptExpanded(cr->session_key, cir->outgoing_iv, data, &o);
+
+ mwOpaque_clear(data);
+ data->data = o.data;
+ data->len = o.len;
+
+ return 0;
+}
+
+
+static int decrypt_RC2_40(struct mwCipherInstance *ci,
+ struct mwOpaque *data) {
+
+ struct mwCipherInstance_RC2_40 *cir;
+ struct mwCipher_RC2_40 *cr;
+ struct mwOpaque o = { 0, 0 };
+
+ cir = (struct mwCipherInstance_RC2_40 *) ci;
+ cr = (struct mwCipher_RC2_40 *) ci->cipher;
+
+ mwDecryptExpanded(cir->incoming_key, cir->incoming_iv, data, &o);
+
+ mwOpaque_clear(data);
+ data->data = o.data;
+ data->len = o.len;
+
+ return 0;
+}
+
+
+static struct mwCipherInstance *
+new_instance_RC2_40(struct mwCipher *cipher,
+ struct mwChannel *chan) {
+
+ struct mwCipher_RC2_40 *cr;
+ struct mwCipherInstance_RC2_40 *cir;
+ struct mwCipherInstance *ci;
+
+ cr = (struct mwCipher_RC2_40 *) cipher;
+
+ /* a bit of lazy initialization here */
+ if(! cr->ready) {
+ struct mwLoginInfo *info = mwSession_getLoginInfo(cipher->session);
+ mwKeyExpand(cr->session_key, (guchar *) info->login_id, 5);
+ cr->ready = TRUE;
+ }
+
+ cir = g_new0(struct mwCipherInstance_RC2_40, 1);
+ ci = &cir->instance;
+
+ ci->cipher = cipher;
+ ci->channel = chan;
+
+ mwIV_init(cir->incoming_iv);
+ mwIV_init(cir->outgoing_iv);
+
+ return ci;
+}
+
+
+static struct mwEncryptItem *new_item_RC2_40(struct mwCipherInstance *ci) {
+ struct mwEncryptItem *e;
+
+ e = g_new0(struct mwEncryptItem, 1);
+ e->id = mwCipher_RC2_40;
+ return e;
+}
+
+
+static struct mwEncryptItem *
+offer_RC2_40(struct mwCipherInstance *ci) {
+ return new_item_RC2_40(ci);
+}
+
+
+static void accepted_RC2_40(struct mwCipherInstance *ci,
+ struct mwEncryptItem *item) {
+
+ struct mwCipherInstance_RC2_40 *cir;
+ struct mwLoginInfo *info;
+
+ cir = (struct mwCipherInstance_RC2_40 *) ci;
+ info = mwChannel_getUser(ci->channel);
+
+ if(info->login_id) {
+ mwKeyExpand(cir->incoming_key, (guchar *) info->login_id, 5);
+ }
+}
+
+
+static struct mwEncryptItem *
+accept_RC2_40(struct mwCipherInstance *ci) {
+
+ accepted_RC2_40(ci, NULL);
+ return new_item_RC2_40(ci);
+}
+
+
+struct mwCipher *mwCipher_new_RC2_40(struct mwSession *s) {
+ struct mwCipher_RC2_40 *cr = g_new0(struct mwCipher_RC2_40, 1);
+ struct mwCipher *c = &cr->cipher;
+
+ c->session = s;
+ c->type = mwCipher_RC2_40;
+ c->get_name = get_name_RC2_40;
+ c->get_desc = get_desc_RC2_40;
+ c->new_instance = new_instance_RC2_40;
+
+ c->offer = offer_RC2_40;
+
+ c->accepted = accepted_RC2_40;
+ c->accept = accept_RC2_40;
+
+ c->encrypt = encrypt_RC2_40;
+ c->decrypt = decrypt_RC2_40;
+
+ return c;
+}
+
+
+struct mwCipher_RC2_128 {
+ struct mwCipher cipher;
+ mw_mp_int private_key;
+ struct mwOpaque public_key;
+};
+
+
+struct mwCipherInstance_RC2_128 {
+ struct mwCipherInstance instance;
+ int shared[64]; /* shared secret determined via DH exchange */
+ guchar outgoing_iv[8];
+ guchar incoming_iv[8];
+};
+
+
+static const char *get_name_RC2_128() {
+ return "RC2/128 Cipher";
+}
+
+
+static const char *get_desc_RC2_128() {
+ return "RC2, DH shared secret key";
+}
+
+
+static struct mwCipherInstance *
+new_instance_RC2_128(struct mwCipher *cipher,
+ struct mwChannel *chan) {
+
+ struct mwCipher_RC2_128 *cr;
+ struct mwCipherInstance_RC2_128 *cir;
+ struct mwCipherInstance *ci;
+
+ cr = (struct mwCipher_RC2_128 *) cipher;
+
+ cir = g_new0(struct mwCipherInstance_RC2_128, 1);
+ ci = &cir->instance;
+
+ ci->cipher = cipher;
+ ci->channel = chan;
+
+ mwIV_init(cir->incoming_iv);
+ mwIV_init(cir->outgoing_iv);
+
+ return ci;
+}
+
+
+static void offered_RC2_128(struct mwCipherInstance *ci,
+ struct mwEncryptItem *item) {
+
+ mw_mp_int remote_key;
+ mw_mp_int shared;
+ struct mwOpaque sho = { 0, 0 };
+
+ struct mwCipher *c;
+ struct mwCipher_RC2_128 *cr;
+ struct mwCipherInstance_RC2_128 *cir;
+
+ c = ci->cipher;
+ cr = (struct mwCipher_RC2_128 *) c;
+ cir = (struct mwCipherInstance_RC2_128 *) ci;
+
+ mw_mp_init(&remote_key);
+ mw_mp_init(&shared);
+
+ mwDHImportKey(&remote_key, &item->info);
+ mwDHCalculateShared(&shared, &remote_key, &cr->private_key);
+ mwDHExportKey(&shared, &sho);
+
+ /* key expanded from the last 16 bytes of the DH shared secret. This
+ took me forever to figure out. 16 bytes is 128 bit. */
+ /* the sh_len-16 is important, because the key len could
+ hypothetically start with 8bits or more unset, meaning the
+ exported key might be less than 64 bytes in length */
+ mwKeyExpand(cir->shared, sho.data+(sho.len-16), 16);
+
+ mw_mp_clear(&remote_key);
+ mw_mp_clear(&shared);
+ mwOpaque_clear(&sho);
+}
+
+
+static struct mwEncryptItem *
+offer_RC2_128(struct mwCipherInstance *ci) {
+
+ struct mwCipher *c;
+ struct mwCipher_RC2_128 *cr;
+ struct mwEncryptItem *ei;
+
+ c = ci->cipher;
+ cr = (struct mwCipher_RC2_128 *) c;
+
+ ei = g_new0(struct mwEncryptItem, 1);
+ ei->id = mwCipher_RC2_128;
+ mwOpaque_clone(&ei->info, &cr->public_key);
+
+ return ei;
+}
+
+
+static void accepted_RC2_128(struct mwCipherInstance *ci,
+ struct mwEncryptItem *item) {
+
+ /// Miranda NG adaptation start - MSVC
+ ///return offered_RC2_128(ci, item);
+ offered_RC2_128(ci, item);
+ /// Miranda NG adaptation end
+}
+
+
+static struct mwEncryptItem *
+accept_RC2_128(struct mwCipherInstance *ci) {
+
+ return offer_RC2_128(ci);
+}
+
+
+static int encrypt_RC2_128(struct mwCipherInstance *ci,
+ struct mwOpaque *data) {
+
+ struct mwCipherInstance_RC2_128 *cir;
+ struct mwOpaque o = { 0, 0 };
+
+ cir = (struct mwCipherInstance_RC2_128 *) ci;
+
+ mwEncryptExpanded(cir->shared, cir->outgoing_iv, data, &o);
+
+ mwOpaque_clear(data);
+ data->data = o.data;
+ data->len = o.len;
+
+ return 0;
+}
+
+
+static int decrypt_RC2_128(struct mwCipherInstance *ci,
+ struct mwOpaque *data) {
+
+ struct mwCipherInstance_RC2_128 *cir;
+ struct mwOpaque o = { 0, 0 };
+
+ cir = (struct mwCipherInstance_RC2_128 *) ci;
+
+ mwDecryptExpanded(cir->shared, cir->incoming_iv, data, &o);
+
+ mwOpaque_clear(data);
+ data->data = o.data;
+ data->len = o.len;
+
+ return 0;
+}
+
+
+static void clear_RC2_128(struct mwCipher *c) {
+ struct mwCipher_RC2_128 *cr;
+ cr = (struct mwCipher_RC2_128 *) c;
+
+ mw_mp_clear(&cr->private_key);
+ mwOpaque_clear(&cr->public_key);
+}
+
+
+struct mwCipher *mwCipher_new_RC2_128(struct mwSession *s) {
+ struct mwCipher_RC2_128 *cr;
+ struct mwCipher *c;
+
+ mw_mp_int pubkey;
+
+ cr = g_new0(struct mwCipher_RC2_128, 1);
+ c = &cr->cipher;
+
+ c->session = s;
+ c->type = mwCipher_RC2_128;
+ c->get_name = get_name_RC2_128;
+ c->get_desc = get_desc_RC2_128;
+ c->new_instance = new_instance_RC2_128;
+
+ c->offered = offered_RC2_128;
+ c->offer = offer_RC2_128;
+
+ c->accepted = accepted_RC2_128;
+ c->accept = accept_RC2_128;
+
+ c->encrypt = encrypt_RC2_128;
+ c->decrypt = decrypt_RC2_128;
+
+ c->clear = clear_RC2_128;
+
+ mw_mp_init(&cr->private_key);
+ mw_mp_init(&pubkey);
+ mwDHRandKeypair(&cr->private_key, &pubkey);
+ mwDHExportKey(&pubkey, &cr->public_key);
+ mw_mp_clear(&pubkey);
+
+ return c;
+}
+
+
+struct mwSession *mwCipher_getSession(struct mwCipher *cipher) {
+ g_return_val_if_fail(cipher != NULL, NULL);
+ return cipher->session;
+}
+
+
+guint16 mwCipher_getType(struct mwCipher *cipher) {
+ /* oh man, this is a bad failover... who the hell decided to make
+ zero a real cipher id? */
+ g_return_val_if_fail(cipher != NULL, 0xffff);
+ return cipher->type;
+}
+
+
+const char *mwCipher_getName(struct mwCipher *cipher) {
+ g_return_val_if_fail(cipher != NULL, NULL);
+ g_return_val_if_fail(cipher->get_name != NULL, NULL);
+ return cipher->get_name();
+}
+
+
+const char *mwCipher_getDesc(struct mwCipher *cipher) {
+ g_return_val_if_fail(cipher != NULL, NULL);
+ g_return_val_if_fail(cipher->get_desc != NULL, NULL);
+ return cipher->get_desc();
+}
+
+
+void mwCipher_free(struct mwCipher *cipher) {
+ if(! cipher) return;
+
+ if(cipher->clear)
+ cipher->clear(cipher);
+
+ g_free(cipher);
+}
+
+
+struct mwCipherInstance *mwCipher_newInstance(struct mwCipher *cipher,
+ struct mwChannel *chan) {
+ g_return_val_if_fail(cipher != NULL, NULL);
+ g_return_val_if_fail(chan != NULL, NULL);
+ g_return_val_if_fail(cipher->new_instance != NULL, NULL);
+ return cipher->new_instance(cipher, chan);
+}
+
+
+struct mwCipher *mwCipherInstance_getCipher(struct mwCipherInstance *ci) {
+ g_return_val_if_fail(ci != NULL, NULL);
+ return ci->cipher;
+}
+
+
+struct mwChannel *mwCipherInstance_getChannel(struct mwCipherInstance *ci) {
+ g_return_val_if_fail(ci != NULL, NULL);
+ return ci->channel;
+}
+
+
+void mwCipherInstance_offered(struct mwCipherInstance *ci,
+ struct mwEncryptItem *item) {
+ struct mwCipher *cipher;
+
+ g_return_if_fail(ci != NULL);
+
+ cipher = ci->cipher;
+ g_return_if_fail(cipher != NULL);
+
+ if(cipher->offered) cipher->offered(ci, item);
+}
+
+
+struct mwEncryptItem *
+mwCipherInstance_offer(struct mwCipherInstance *ci) {
+ struct mwCipher *cipher;
+
+ g_return_val_if_fail(ci != NULL, NULL);
+
+ cipher = ci->cipher;
+ g_return_val_if_fail(cipher != NULL, NULL);
+
+ return cipher->offer(ci);
+}
+
+
+void mwCipherInstance_accepted(struct mwCipherInstance *ci,
+ struct mwEncryptItem *item) {
+ struct mwCipher *cipher;
+
+ g_return_if_fail(ci != NULL);
+
+ cipher = ci->cipher;
+ g_return_if_fail(cipher != NULL);
+
+ if(cipher->accepted) cipher->accepted(ci, item);
+}
+
+
+struct mwEncryptItem *
+mwCipherInstance_accept(struct mwCipherInstance *ci) {
+ struct mwCipher *cipher;
+
+ g_return_val_if_fail(ci != NULL, NULL);
+
+ cipher = ci->cipher;
+ g_return_val_if_fail(cipher != NULL, NULL);
+
+ return cipher->accept(ci);
+}
+
+
+int mwCipherInstance_encrypt(struct mwCipherInstance *ci,
+ struct mwOpaque *data) {
+ struct mwCipher *cipher;
+
+ g_return_val_if_fail(data != NULL, 0);
+
+ if(! ci) return 0;
+ cipher = ci->cipher;
+
+ g_return_val_if_fail(cipher != NULL, -1);
+
+ return (cipher->encrypt)?
+ cipher->encrypt(ci, data): 0;
+}
+
+
+int mwCipherInstance_decrypt(struct mwCipherInstance *ci,
+ struct mwOpaque *data) {
+ struct mwCipher *cipher;
+
+ g_return_val_if_fail(data != NULL, 0);
+
+ if(! ci) return 0;
+ cipher = ci->cipher;
+
+ g_return_val_if_fail(cipher != NULL, -1);
+
+ return (cipher->decrypt)?
+ cipher->decrypt(ci, data): 0;
+}
+
+
+void mwCipherInstance_free(struct mwCipherInstance *ci) {
+ struct mwCipher *cipher;
+
+ if(! ci) return;
+
+ cipher = ci->cipher;
+
+ if(cipher && cipher->clear_instance)
+ cipher->clear_instance(ci);
+
+ g_free(ci);
+}
+
diff --git a/protocols/Sametime/src/meanwhile/src/common.c b/protocols/Sametime/src/meanwhile/src/common.c
new file mode 100644
index 0000000000..555edd2c1c
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/common.c
@@ -0,0 +1,947 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <glib.h>
+#include <string.h>
+
+#include "mw_common.h"
+
+
+/** @todo the *_get functions should make sure to clear their
+ structures in the event of failure, to prevent memory leaks */
+
+
+#define MW16_PUT(b, val) \
+ *(b)++ = ((val) >> 0x08) & 0xff; \
+ *(b)++ = (val) & 0xff;
+
+
+#define MW16_GET(b, val) \
+ val = (*(b)++ & 0xff) << 8; \
+ val = val | (*(b)++ & 0xff);
+
+
+#define MW32_PUT(b, val) \
+ *(b)++ = ((val) >> 0x18) & 0xff; \
+ *(b)++ = ((val) >> 0x10) & 0xff; \
+ *(b)++ = ((val) >> 0x08) & 0xff; \
+ *(b)++ = (val) & 0xff;
+
+
+#define MW32_GET(b, val) \
+ val = (*(b)++ & 0xff) << 0x18; \
+ val = val | (*(b)++ & 0xff) << 0x10; \
+ val = val | (*(b)++ & 0xff) << 0x08; \
+ val = val | (*(b)++ & 0xff);
+
+
+struct mwPutBuffer {
+ guchar *buf; /**< head of buffer */
+ gsize len; /**< length of buffer */
+
+ guchar *ptr; /**< offset to first unused byte */
+ gsize rem; /**< count of unused bytes remaining */
+};
+
+
+struct mwGetBuffer {
+ guchar *buf; /**< head of buffer */
+ gsize len; /**< length of buffer */
+
+ guchar *ptr; /**< offset to first unused byte */
+ gsize rem; /**< count of unused bytes remaining */
+
+ gboolean wrap; /**< TRUE to indicate buf shouldn't be freed */
+ gboolean error; /**< TRUE to indicate an error */
+};
+
+
+#define BUFFER_USED(buffer) \
+ ((buffer)->len - (buffer)->rem)
+
+
+/** ensure that there's at least enough space remaining in the put
+ buffer to fit needed. */
+static void ensure_buffer(struct mwPutBuffer *b, gsize needed) {
+ if(b->rem < needed) {
+ gsize len = b->len, use = BUFFER_USED(b);
+ guchar *buf;
+
+ /* newly created buffers are empty until written to, and then they
+ have 1024 available */
+ if(! len) len = 1024;
+
+ /* double len until it's large enough to fit needed */
+ while( (len - use) < needed ) len = len << 1;
+
+ /* create the new buffer. if there was anything in the old buffer,
+ copy it into the new buffer and free the old copy */
+ buf = g_malloc(len);
+ if(b->buf) {
+ memcpy(buf, b->buf, use);
+ g_free(b->buf);
+ }
+
+ /* put the new buffer into b */
+ b->buf = buf;
+ b->len = len;
+ b->ptr = buf + use;
+ b->rem = len - use;
+ }
+}
+
+
+/** determine if there are at least needed bytes available in the
+ buffer. sets the error flag if there's not at least needed bytes
+ left in the buffer
+
+ @returns true if there's enough data, false if not */
+static gboolean check_buffer(struct mwGetBuffer *b, gsize needed) {
+ if(! b->error) b->error = (b->rem < needed);
+ return ! b->error;
+}
+
+
+struct mwPutBuffer *mwPutBuffer_new() {
+ return g_new0(struct mwPutBuffer, 1);
+}
+
+
+void mwPutBuffer_write(struct mwPutBuffer *b, gpointer data, gsize len) {
+ g_return_if_fail(b != NULL);
+ g_return_if_fail(data != NULL);
+
+ if(! len) return;
+
+ ensure_buffer(b, len);
+ memcpy(b->ptr, data, len);
+ b->ptr += len;
+ b->rem -= len;
+}
+
+
+void mwPutBuffer_free(struct mwPutBuffer *b) {
+ if(! b) return;
+ g_free(b->buf);
+ g_free(b);
+}
+
+
+void mwPutBuffer_finalize(struct mwOpaque *to, struct mwPutBuffer *from) {
+ g_return_if_fail(to != NULL);
+ g_return_if_fail(from != NULL);
+
+ to->len = BUFFER_USED(from);
+ to->data = from->buf;
+
+ g_free(from);
+}
+
+
+struct mwGetBuffer *mwGetBuffer_new(struct mwOpaque *o) {
+ struct mwGetBuffer *b = g_new0(struct mwGetBuffer, 1);
+
+ if(o && o->len) {
+ b->buf = b->ptr = g_memdup(o->data, o->len);
+ b->len = b->rem = o->len;
+ }
+
+ return b;
+}
+
+
+struct mwGetBuffer *mwGetBuffer_wrap(const struct mwOpaque *o) {
+ struct mwGetBuffer *b = g_new0(struct mwGetBuffer, 1);
+
+ if(o && o->len) {
+ b->buf = b->ptr = o->data;
+ b->len = b->rem = o->len;
+ }
+ b->wrap = TRUE;
+
+ return b;
+}
+
+
+gsize mwGetBuffer_read(struct mwGetBuffer *b, gpointer data, gsize len) {
+ g_return_val_if_fail(b != NULL, 0);
+ g_return_val_if_fail(data != NULL, 0);
+
+ if(b->error) return 0;
+ if(! len) return 0;
+
+ if(b->rem < len)
+ len = b->rem;
+
+ memcpy(data, b->ptr, len);
+ b->ptr += len;
+ b->rem -= len;
+
+ return len;
+}
+
+
+gsize mwGetBuffer_advance(struct mwGetBuffer *b, gsize len) {
+ g_return_val_if_fail(b != NULL, 0);
+
+ if(b->error) return 0;
+ if(! len) return 0;
+
+ if(b->rem < len)
+ len = b->rem;
+
+ b->ptr += len;
+ b->rem -= len;
+
+ return len;
+}
+
+
+void mwGetBuffer_reset(struct mwGetBuffer *b) {
+ g_return_if_fail(b != NULL);
+
+ b->rem = b->len;
+ b->ptr = b->buf;
+ b->error = FALSE;
+}
+
+
+gsize mwGetBuffer_remaining(struct mwGetBuffer *b) {
+ g_return_val_if_fail(b != NULL, 0);
+ return b->rem;
+}
+
+
+gboolean mwGetBuffer_error(struct mwGetBuffer *b) {
+ g_return_val_if_fail(b != NULL, TRUE);
+ return b->error;
+}
+
+
+void mwGetBuffer_free(struct mwGetBuffer *b) {
+ if(! b) return;
+ if(! b->wrap) g_free(b->buf);
+ g_free(b);
+}
+
+
+#define guint16_buflen() 2
+
+
+void guint16_put(struct mwPutBuffer *b, guint16 val) {
+ g_return_if_fail(b != NULL);
+
+ ensure_buffer(b, guint16_buflen());
+ MW16_PUT(b->ptr, val);
+ b->rem -= guint16_buflen();
+}
+
+
+void guint16_get(struct mwGetBuffer *b, guint16 *val) {
+ g_return_if_fail(b != NULL);
+
+ if(b->error) return;
+ g_return_if_fail(check_buffer(b, guint16_buflen()));
+
+ MW16_GET(b->ptr, *val);
+ b->rem -= guint16_buflen();
+}
+
+
+guint16 guint16_peek(struct mwGetBuffer *b) {
+ guchar *buf = b->buf;
+ guint16 r = 0;
+
+ if(b->rem >= guint16_buflen())
+ MW16_GET(buf, r);
+
+ return r;
+}
+
+
+#define guint32_buflen() 4
+
+
+void guint32_put(struct mwPutBuffer *b, guint32 val) {
+ g_return_if_fail(b != NULL);
+
+ ensure_buffer(b, guint32_buflen());
+ MW32_PUT(b->ptr, val);
+ b->rem -= guint32_buflen();
+}
+
+
+void guint32_get(struct mwGetBuffer *b, guint32 *val) {
+ g_return_if_fail(b != NULL);
+
+ if(b->error) return;
+ g_return_if_fail(check_buffer(b, guint32_buflen()));
+
+ MW32_GET(b->ptr, *val);
+ b->rem -= guint32_buflen();
+}
+
+
+guint32 guint32_peek(struct mwGetBuffer *b) {
+ guchar *buf = b->buf;
+ guint32 r = 0;
+
+ if(b->rem >= guint32_buflen())
+ MW32_GET(buf, r);
+
+ return r;
+}
+
+
+#define gboolean_buflen() 1
+
+
+void gboolean_put(struct mwPutBuffer *b, gboolean val) {
+ g_return_if_fail(b != NULL);
+
+ ensure_buffer(b, gboolean_buflen());
+ *(b->ptr) = !! val;
+ b->ptr++;
+ b->rem--;
+}
+
+
+void gboolean_get(struct mwGetBuffer *b, gboolean *val) {
+ g_return_if_fail(b != NULL);
+
+ if(b->error) return;
+ g_return_if_fail(check_buffer(b, gboolean_buflen()));
+
+ *val = !! *(b->ptr);
+ b->ptr++;
+ b->rem--;
+}
+
+
+gboolean gboolean_peek(struct mwGetBuffer *b) {
+ gboolean v = FALSE;
+
+ if(b->rem >= gboolean_buflen())
+ v = !! *(b->ptr);
+
+ return v;
+}
+
+
+static gboolean mw_streq(const char *a, const char *b) {
+ return (a == b) || (a && b && !strcmp(a, b));
+}
+
+
+void mwString_put(struct mwPutBuffer *b, const char *val) {
+ gsize len = 0;
+
+ g_return_if_fail(b != NULL);
+
+ if(val) len = strlen(val);
+
+ guint16_put(b, (guint16) len);
+
+ if(len) {
+ ensure_buffer(b, len);
+ memcpy(b->ptr, val, len);
+ b->ptr += len;
+ b->rem -= len;
+ }
+}
+
+
+void mwString_get(struct mwGetBuffer *b, char **val) {
+ guint16 len = 0;
+
+ g_return_if_fail(b != NULL);
+ g_return_if_fail(val != NULL);
+
+ *val = NULL;
+
+ if(b->error) return;
+ guint16_get(b, &len);
+
+ g_return_if_fail(check_buffer(b, (gsize) len));
+
+ if(len) {
+ *val = g_malloc0(len + 1);
+ memcpy(*val, b->ptr, len);
+ b->ptr += len;
+ b->rem -= len;
+ }
+}
+
+
+void mwOpaque_put(struct mwPutBuffer *b, const struct mwOpaque *o) {
+ gsize len;
+
+ g_return_if_fail(b != NULL);
+
+ if(! o) {
+ guint32_put(b, 0x00);
+ return;
+ }
+
+ len = o->len;
+ if(len)
+ g_return_if_fail(o->data != NULL);
+
+ guint32_put(b, (guint32) len);
+
+ if(len) {
+ ensure_buffer(b, len);
+ memcpy(b->ptr, o->data, len);
+ b->ptr += len;
+ b->rem -= len;
+ }
+}
+
+
+void mwOpaque_get(struct mwGetBuffer *b, struct mwOpaque *o) {
+ guint32 tmp = 0;
+
+ g_return_if_fail(b != NULL);
+ g_return_if_fail(o != NULL);
+
+ o->len = 0;
+ o->data = NULL;
+
+ if(b->error) return;
+ guint32_get(b, &tmp);
+
+ g_return_if_fail(check_buffer(b, (gsize) tmp));
+
+ o->len = (gsize) tmp;
+ if(tmp > 0) {
+ o->data = g_memdup(b->ptr, tmp);
+ b->ptr += tmp;
+ b->rem -= tmp;
+ }
+}
+
+
+void mwOpaque_clear(struct mwOpaque *o) {
+ if(! o) return;
+ g_free(o->data);
+ o->data = NULL;
+ o->len = 0;
+}
+
+
+void mwOpaque_free(struct mwOpaque *o) {
+ if(! o) return;
+ g_free(o->data);
+ g_free(o);
+}
+
+
+void mwOpaque_clone(struct mwOpaque *to, const struct mwOpaque *from) {
+ g_return_if_fail(to != NULL);
+
+ to->len = 0;
+ to->data = NULL;
+
+ if(from) {
+ to->len = from->len;
+ if(to->len)
+ to->data = g_memdup(from->data, to->len);
+ }
+}
+
+
+/* 8.2 Common Structures */
+/* 8.2.1 Login Info block */
+
+
+void mwLoginInfo_put(struct mwPutBuffer *b, const struct mwLoginInfo *login) {
+ g_return_if_fail(b != NULL);
+ g_return_if_fail(login != NULL);
+
+ mwString_put(b, login->login_id);
+ guint16_put(b, login->type);
+ mwString_put(b, login->user_id);
+ mwString_put(b, login->user_name);
+ mwString_put(b, login->community);
+ gboolean_put(b, login->full);
+
+ if(login->full) {
+ mwString_put(b, login->desc);
+ guint32_put(b, login->ip_addr);
+ mwString_put(b, login->server_id);
+ }
+}
+
+
+void mwLoginInfo_get(struct mwGetBuffer *b, struct mwLoginInfo *login) {
+ g_return_if_fail(b != NULL);
+ g_return_if_fail(login != NULL);
+
+ if(b->error) return;
+
+ mwString_get(b, &login->login_id);
+ guint16_get(b, &login->type);
+ mwString_get(b, &login->user_id);
+ mwString_get(b, &login->user_name);
+ mwString_get(b, &login->community);
+ gboolean_get(b, &login->full);
+
+ if(login->full) {
+ mwString_get(b, &login->desc);
+ guint32_get(b, &login->ip_addr);
+ mwString_get(b, &login->server_id);
+ }
+}
+
+
+void mwLoginInfo_clear(struct mwLoginInfo *login) {
+ if(! login) return;
+
+ g_free(login->login_id);
+ g_free(login->user_id);
+ g_free(login->user_name);
+ g_free(login->community);
+ g_free(login->desc);
+ g_free(login->server_id);
+
+ memset(login, 0x00, sizeof(struct mwLoginInfo));
+}
+
+
+void mwLoginInfo_clone(struct mwLoginInfo *to,
+ const struct mwLoginInfo *from) {
+
+ g_return_if_fail(to != NULL);
+ g_return_if_fail(from != NULL);
+
+ to->login_id= g_strdup(from->login_id);
+ to->type = from->type;
+ to->user_id = g_strdup(from->user_id);
+ to->user_name = g_strdup(from->user_name);
+ to->community = g_strdup(from->community);
+
+ if( (to->full = from->full) ) {
+ to->desc = g_strdup(from->desc);
+ to->ip_addr = from->ip_addr;
+ to->server_id = g_strdup(from->server_id);
+ }
+}
+
+
+/* 8.2.2 Private Info Block */
+
+
+void mwUserItem_put(struct mwPutBuffer *b, const struct mwUserItem *user) {
+ g_return_if_fail(b != NULL);
+ g_return_if_fail(user != NULL);
+
+ gboolean_put(b, user->full);
+ mwString_put(b, user->id);
+ mwString_put(b, user->community);
+
+ if(user->full)
+ mwString_put(b, user->name);
+}
+
+
+void mwUserItem_get(struct mwGetBuffer *b, struct mwUserItem *user) {
+ g_return_if_fail(b != NULL);
+ g_return_if_fail(user != NULL);
+
+ if(b->error) return;
+
+ gboolean_get(b, &user->full);
+ mwString_get(b, &user->id);
+ mwString_get(b, &user->community);
+
+ if(user->full)
+ mwString_get(b, &user->name);
+}
+
+
+void mwUserItem_clear(struct mwUserItem *user) {
+ if(! user) return;
+
+ g_free(user->id);
+ g_free(user->community);
+ g_free(user->name);
+
+ memset(user, 0x00, sizeof(struct mwUserItem));
+}
+
+
+void mwUserItem_clone(struct mwUserItem *to,
+ const struct mwUserItem *from) {
+
+ g_return_if_fail(to != NULL);
+ g_return_if_fail(from != NULL);
+
+ to->full = from->full;
+ to->id = g_strdup(from->id);
+ to->community = g_strdup(from->community);
+ to->name = (to->full)? g_strdup(from->name): NULL;
+}
+
+
+void mwPrivacyInfo_put(struct mwPutBuffer *b,
+ const struct mwPrivacyInfo *info) {
+ guint32 c;
+
+ g_return_if_fail(b != NULL);
+ g_return_if_fail(info != NULL);
+
+ gboolean_put(b, info->deny);
+ guint32_put(b, info->count);
+
+ for(c = info->count; c--; ) mwUserItem_put(b, info->users + c);
+}
+
+
+void mwPrivacyInfo_get(struct mwGetBuffer *b, struct mwPrivacyInfo *info) {
+ g_return_if_fail(b != NULL);
+ g_return_if_fail(info != NULL);
+
+ if(b->error) return;
+
+ gboolean_get(b, &info->deny);
+ guint32_get(b, &info->count);
+
+ if(info->count) {
+ guint32 c = info->count;
+ info->users = g_new0(struct mwUserItem, c);
+ while(c--) mwUserItem_get(b, info->users + c);
+ }
+}
+
+
+void mwPrivacyInfo_clone(struct mwPrivacyInfo *to,
+ const struct mwPrivacyInfo *from) {
+
+ guint32 c;
+
+ g_return_if_fail(to != NULL);
+ g_return_if_fail(from != NULL);
+
+ to->deny = from->deny;
+ c = to->count = from->count;
+
+ to->users = g_new0(struct mwUserItem, c);
+ while(c--) mwUserItem_clone(to->users+c, from->users+c);
+}
+
+
+void mwPrivacyInfo_clear(struct mwPrivacyInfo *info) {
+ struct mwUserItem *u;
+ guint32 c;
+
+ g_return_if_fail(info != NULL);
+
+ u = info->users;
+ c = info->count;
+
+ while(c--) mwUserItem_clear(u + c);
+ g_free(u);
+
+ info->count = 0;
+ info->users = NULL;
+}
+
+
+/* 8.2.3 User Status Block */
+
+
+void mwUserStatus_put(struct mwPutBuffer *b,
+ const struct mwUserStatus *stat) {
+
+ g_return_if_fail(b != NULL);
+ g_return_if_fail(stat != NULL);
+
+ guint16_put(b, stat->status);
+ guint32_put(b, stat->time);
+ mwString_put(b, stat->desc);
+}
+
+
+void mwUserStatus_get(struct mwGetBuffer *b, struct mwUserStatus *stat) {
+ g_return_if_fail(b != NULL);
+ g_return_if_fail(stat != NULL);
+
+ if(b->error) return;
+
+ guint16_get(b, &stat->status);
+ guint32_get(b, &stat->time);
+ mwString_get(b, &stat->desc);
+
+ /// Miranda NG adaptation - start - http://www.lilotux.net/~mikael/pub/meanwhile/status_timestamp_workaround.diff
+ // Quick'n ugly hack for recent Sametime clients
+ stat->time = 0;
+ /// Miranda NG adaptation - end
+}
+
+
+void mwUserStatus_clear(struct mwUserStatus *stat) {
+ if(! stat) return;
+ g_free(stat->desc);
+ memset(stat, 0x00, sizeof(struct mwUserStatus));
+}
+
+
+void mwUserStatus_clone(struct mwUserStatus *to,
+ const struct mwUserStatus *from) {
+
+ g_return_if_fail(to != NULL);
+ g_return_if_fail(from != NULL);
+
+ to->status = from->status;
+ to->time = from->time;
+ to->desc = g_strdup(from->desc);
+}
+
+
+/* 8.2.4 ID Block */
+
+
+void mwIdBlock_put(struct mwPutBuffer *b, const struct mwIdBlock *id) {
+ g_return_if_fail(b != NULL);
+ g_return_if_fail(id != NULL);
+
+ mwString_put(b, id->user);
+ mwString_put(b, id->community);
+}
+
+
+void mwIdBlock_get(struct mwGetBuffer *b, struct mwIdBlock *id) {
+ g_return_if_fail(b != NULL);
+ g_return_if_fail(id != NULL);
+
+ if(b->error) return;
+
+ mwString_get(b, &id->user);
+ mwString_get(b, &id->community);
+}
+
+
+void mwIdBlock_clear(struct mwIdBlock *id) {
+ if(! id) return;
+
+ g_free(id->user);
+ id->user = NULL;
+
+ g_free(id->community);
+ id->community = NULL;
+}
+
+
+void mwIdBlock_clone(struct mwIdBlock *to, const struct mwIdBlock *from) {
+ g_return_if_fail(to != NULL);
+ g_return_if_fail(from != NULL);
+
+ to->user = g_strdup(from->user);
+ to->community = g_strdup(from->community);
+}
+
+
+guint mwIdBlock_hash(const struct mwIdBlock *idb) {
+ return (idb)? g_str_hash(idb->user): 0;
+}
+
+
+gboolean mwIdBlock_equal(const struct mwIdBlock *a,
+ const struct mwIdBlock *b) {
+
+ g_return_val_if_fail(a != NULL, FALSE);
+ g_return_val_if_fail(b != NULL, FALSE);
+
+ return ( mw_streq(a->user, b->user) &&
+ mw_streq(a->community, b->community) );
+}
+
+
+/* 8.2.5 Encryption Block */
+
+/** @todo I think this can be put into cipher */
+
+void mwEncryptItem_put(struct mwPutBuffer *b,
+ const struct mwEncryptItem *ei) {
+
+ g_return_if_fail(b != NULL);
+ g_return_if_fail(ei != NULL);
+
+ guint16_put(b, ei->id);
+ mwOpaque_put(b, &ei->info);
+
+}
+
+
+void mwEncryptItem_get(struct mwGetBuffer *b, struct mwEncryptItem *ei) {
+ g_return_if_fail(b != NULL);
+ g_return_if_fail(ei != NULL);
+
+ if(b->error) return;
+
+ guint16_get(b, &ei->id);
+ mwOpaque_get(b, &ei->info);
+}
+
+
+void mwEncryptItem_clear(struct mwEncryptItem *ei) {
+ if(! ei) return;
+ ei->id = 0x0000;
+ mwOpaque_clear(&ei->info);
+}
+
+
+void mwEncryptItem_free(struct mwEncryptItem *ei) {
+ mwEncryptItem_clear(ei);
+ g_free(ei);
+}
+
+
+/* 8.4.2.1 Awareness ID Block */
+
+
+/** @todo move this into srvc_aware */
+
+void mwAwareIdBlock_put(struct mwPutBuffer *b,
+ const struct mwAwareIdBlock *idb) {
+
+ g_return_if_fail(b != NULL);
+ g_return_if_fail(idb != NULL);
+
+ guint16_put(b, idb->type);
+ mwString_put(b, idb->user);
+ mwString_put(b, idb->community);
+}
+
+
+void mwAwareIdBlock_get(struct mwGetBuffer *b, struct mwAwareIdBlock *idb) {
+ g_return_if_fail(b != NULL);
+ g_return_if_fail(idb != NULL);
+
+ if(b->error) return;
+
+ guint16_get(b, &idb->type);
+ mwString_get(b, &idb->user);
+ mwString_get(b, &idb->community);
+}
+
+
+void mwAwareIdBlock_clone(struct mwAwareIdBlock *to,
+ const struct mwAwareIdBlock *from) {
+
+ g_return_if_fail(to != NULL);
+ g_return_if_fail(from != NULL);
+
+ to->type = from->type;
+ to->user = g_strdup(from->user);
+ to->community = g_strdup(from->community);
+}
+
+
+void mwAwareIdBlock_clear(struct mwAwareIdBlock *idb) {
+ if(! idb) return;
+ g_free(idb->user);
+ g_free(idb->community);
+ memset(idb, 0x00, sizeof(struct mwAwareIdBlock));
+}
+
+
+guint mwAwareIdBlock_hash(const struct mwAwareIdBlock *a) {
+ return (a)? g_str_hash(a->user): 0;
+}
+
+
+gboolean mwAwareIdBlock_equal(const struct mwAwareIdBlock *a,
+ const struct mwAwareIdBlock *b) {
+
+ g_return_val_if_fail(a != NULL, FALSE);
+ g_return_val_if_fail(b != NULL, FALSE);
+
+ return ( (a->type == b->type) &&
+ mw_streq(a->user, b->user) &&
+ mw_streq(a->community, b->community) );
+}
+
+
+/* 8.4.2.4 Snapshot */
+
+void mwAwareSnapshot_get(struct mwGetBuffer *b, struct mwAwareSnapshot *idb) {
+
+ /// Miranda NG adaptation - start - http://www.lilotux.net/~mikael/pub/meanwhile/presence_fix_v2.diff
+ //guint32 junk;
+ //char *empty = NULL;
+ guint32 end_of_block;
+ /// Miranda NG adaptation - end
+
+ g_return_if_fail(b != NULL);
+ g_return_if_fail(idb != NULL);
+
+ /// Miranda NG adaptation - start - http://www.lilotux.net/~mikael/pub/meanwhile/presence_fix_v2.diff
+ //guint32_get(b, &junk);
+ guint32_get(b, &end_of_block);
+ /// Miranda NG adaptation - end
+ mwAwareIdBlock_get(b, &idb->id);
+ mwString_get(b, &idb->group);
+ gboolean_get(b, &idb->online);
+
+ /// Miranda NG adaptation - start - http://www.lilotux.net/~mikael/pub/meanwhile/presence_fix_v2.diff
+ //g_free(empty);
+ /// Miranda NG adaptation - end
+
+ if(idb->online) {
+ mwString_get(b, &idb->alt_id);
+ mwUserStatus_get(b, &idb->status);
+ mwString_get(b, &idb->name);
+ }
+
+ /// Miranda NG adaptation - start - http://www.lilotux.net/~mikael/pub/meanwhile/presence_fix_v2.diff
+ if(b->ptr < b->buf + end_of_block) {
+ mwGetBuffer_advance(b, b->buf + end_of_block - b->ptr);
+ }
+ /// Miranda NG adaptation - end
+}
+
+
+void mwAwareSnapshot_clone(struct mwAwareSnapshot *to,
+ const struct mwAwareSnapshot *from) {
+
+ g_return_if_fail(to != NULL);
+ g_return_if_fail(from != NULL);
+
+ mwAwareIdBlock_clone(&to->id, &from->id);
+ if( (to->online = from->online) ) {
+ to->alt_id = g_strdup(from->alt_id);
+ mwUserStatus_clone(&to->status, &from->status);
+ to->name = g_strdup(from->name);
+ to->group = g_strdup(from->group);
+ }
+}
+
+
+void mwAwareSnapshot_clear(struct mwAwareSnapshot *idb) {
+ if(! idb) return;
+ mwAwareIdBlock_clear(&idb->id);
+ mwUserStatus_clear(&idb->status);
+ g_free(idb->alt_id);
+ g_free(idb->name);
+ g_free(idb->group);
+ memset(idb, 0x00, sizeof(struct mwAwareSnapshot));
+}
+
diff --git a/protocols/Sametime/src/meanwhile/src/error.c b/protocols/Sametime/src/meanwhile/src/error.c
new file mode 100644
index 0000000000..23c9559802
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/error.c
@@ -0,0 +1,97 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "mw_error.h"
+
+
+static char *err_to_str(guint32 code) {
+ static char b[11]; /* 0x12345678 + NULL terminator */
+ sprintf((char *) b, "0x%08x", code);
+ b[10] = '\0';
+ return b;
+}
+
+
+#define CASE(val, str) \
+case val: \
+ m = str; \
+ break;
+
+
+char* mwError(guint32 code) {
+ const char *m;
+
+ switch(code) {
+
+ /* 8.3.1.1 General error/success codes */
+ CASE(ERR_SUCCESS, "Success");
+ CASE(ERR_FAILURE, "General failure");
+ CASE(ERR_REQUEST_DELAY, "Request delayed");
+ CASE(ERR_REQUEST_INVALID, "Request is invalid");
+ CASE(ERR_NOT_AUTHORIZED, "Not authorized");
+ CASE(ERR_NO_USER, "User is not online");
+ CASE(ERR_CHANNEL_NO_SUPPORT, "Requested channel is not supported");
+ CASE(ERR_CHANNEL_EXISTS, "Requested channel already exists");
+ CASE(ERR_SERVICE_NO_SUPPORT, "Requested service is not supported");
+ CASE(ERR_PROTOCOL_NO_SUPPORT, "Requested protocol is not supported");
+ CASE(ERR_VERSION_NO_SUPPORT, "Version is not supported");
+ CASE(ERR_USER_SKETCHY, "User is invalid or not trusted");
+ CASE(ERR_ALREADY_INITIALIZED, "Already initialized");
+ CASE(ERR_ENCRYPT_NO_SUPPORT, "Encryption method not supported");
+ CASE(ERR_NO_COMMON_ENCRYPT, "No common encryption method");
+
+ /* 8.3.1.2 Connection/disconnection errors */
+ CASE(VERSION_MISMATCH, "Version mismatch");
+ CASE(FAT_MESSAGE, "Message is too large");
+ CASE(CONNECTION_BROKEN, "Connection broken");
+ CASE(CONNECTION_ABORTED, "Connection aborted");
+ CASE(CONNECTION_REFUSED, "Connection refused");
+ CASE(CONNECTION_RESET, "Connection reset");
+ CASE(CONNECTION_TIMED, "Connection timed out");
+ CASE(CONNECTION_CLOSED, "Connection closed");
+ CASE(INCORRECT_LOGIN, "Incorrect Username/Password");
+ CASE(VERIFICATION_DOWN, "Login verification down or unavailable");
+ CASE(GUEST_IN_USE, "The guest name is currently being used");
+ CASE(MULTI_SERVER_LOGIN, "Login to two different servers concurrently");
+ CASE(MULTI_SERVER_LOGIN2, "Login to two different servers concurrently");
+ CASE(SERVER_BROKEN, "Server misconfiguration");
+
+ /* 8.3.1.3 Client error codes */
+ CASE(ERR_CLIENT_USER_GONE, "User is not online");
+ CASE(ERR_CLIENT_USER_DND, "User is in Do Not Disturb mode");
+ CASE(ERR_CLIENT_USER_ELSEWHERE, "Already logged in elsewhere");
+
+ /* 8.3.1.4 IM error codes */
+ CASE(ERR_IM_COULDNT_REGISTER, "Cannot register a reserved type");
+ CASE(ERR_IM_ALREADY_REGISTERED, "Requested type is already registered");
+ CASE(ERR_IM_NOT_REGISTERED, "Requested type is not registered");
+
+ default:
+ m = err_to_str(code);
+ }
+
+ return g_strdup(m);
+}
+
+
+#undef CASE
diff --git a/protocols/Sametime/src/meanwhile/src/message.c b/protocols/Sametime/src/meanwhile/src/message.c
new file mode 100644
index 0000000000..f9afec4c9b
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/message.c
@@ -0,0 +1,853 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <glib.h>
+
+#include "mw_debug.h"
+#include "mw_message.h"
+
+
+/* 7.1 Layering and message encapsulation */
+/* 7.1.1 The Sametime Message Header */
+
+
+static void mwMessageHead_put(struct mwPutBuffer *b, struct mwMessage *msg) {
+ guint16_put(b, msg->type);
+ guint16_put(b, msg->options);
+ guint32_put(b, msg->channel);
+
+ if(msg->options & mwMessageOption_HAS_ATTRIBS)
+ mwOpaque_put(b, &msg->attribs);
+}
+
+
+static void mwMessageHead_get(struct mwGetBuffer *b, struct mwMessage *msg) {
+
+ if(mwGetBuffer_error(b)) return;
+
+ guint16_get(b, &msg->type);
+ guint16_get(b, &msg->options);
+ guint32_get(b, &msg->channel);
+
+ if(msg->options & mwMessageOption_HAS_ATTRIBS)
+ mwOpaque_get(b, &msg->attribs);
+}
+
+
+static void mwMessageHead_clone(struct mwMessage *to,
+ struct mwMessage *from) {
+
+ to->type = from->type;
+ to->options = from->options;
+ to->channel = from->channel;
+ mwOpaque_clone(&to->attribs, &from->attribs);
+}
+
+
+static void mwMessageHead_clear(struct mwMessage *msg) {
+ mwOpaque_clear(&msg->attribs);
+}
+
+
+/* 8.4 Messages */
+/* 8.4.1 Basic Community Messages */
+/* 8.4.1.1 Handshake */
+
+
+static void HANDSHAKE_put(struct mwPutBuffer *b, struct mwMsgHandshake *msg) {
+ guint16_put(b, msg->major);
+ guint16_put(b, msg->minor);
+ guint32_put(b, msg->head.channel);
+ guint32_put(b, msg->srvrcalc_addr);
+ guint16_put(b, msg->login_type);
+ guint32_put(b, msg->loclcalc_addr);
+
+ if(msg->major >= 0x001e && msg->minor >= 0x001d) {
+ guint16_put(b, msg->unknown_a);
+ guint32_put(b, msg->unknown_b);
+ mwString_put(b, msg->local_host);
+ }
+}
+
+
+static void HANDSHAKE_get(struct mwGetBuffer *b, struct mwMsgHandshake *msg) {
+ if(mwGetBuffer_error(b)) return;
+
+ guint16_get(b, &msg->major);
+ guint16_get(b, &msg->minor);
+ guint32_get(b, &msg->head.channel);
+ guint32_get(b, &msg->srvrcalc_addr);
+ guint16_get(b, &msg->login_type);
+ guint32_get(b, &msg->loclcalc_addr);
+
+ if(msg->major >= 0x001e && msg->minor >= 0x001d) {
+ guint16_get(b, &msg->unknown_a);
+ guint32_get(b, &msg->unknown_b);
+ mwString_get(b, &msg->local_host);
+ }
+}
+
+
+static void HANDSHAKE_clear(struct mwMsgHandshake *msg) {
+ ; /* nothing to clean up */
+}
+
+
+/* 8.4.1.2 HandshakeAck */
+
+
+static void HANDSHAKE_ACK_get(struct mwGetBuffer *b,
+ struct mwMsgHandshakeAck *msg) {
+
+ if(mwGetBuffer_error(b)) return;
+
+ guint16_get(b, &msg->major);
+ guint16_get(b, &msg->minor);
+ guint32_get(b, &msg->srvrcalc_addr);
+
+ /** @todo: get a better handle on what versions support what parts
+ of this message. eg: minor version 0x0018 doesn't send the
+ following */
+ if(msg->major >= 0x1e && msg->minor > 0x18) {
+ guint32_get(b, &msg->magic);
+ mwOpaque_get(b, &msg->data);
+ }
+}
+
+
+static void HANDSHAKE_ACK_put(struct mwPutBuffer *b,
+ struct mwMsgHandshakeAck *msg) {
+
+ guint16_put(b, msg->major);
+ guint16_put(b, msg->minor);
+ guint32_put(b, msg->srvrcalc_addr);
+
+ if(msg->major >= 0x1e && msg->minor > 0x18) {
+ guint32_put(b, msg->magic);
+ mwOpaque_put(b, &msg->data);
+ }
+}
+
+
+static void HANDSHAKE_ACK_clear(struct mwMsgHandshakeAck *msg) {
+ mwOpaque_clear(&msg->data);
+}
+
+
+/* 8.4.1.3 Login */
+
+
+static void LOGIN_put(struct mwPutBuffer *b, struct mwMsgLogin *msg) {
+ guint16_put(b, msg->login_type);
+ mwString_put(b, msg->name);
+
+ /* ordering reversed from houri draft?? */
+ mwOpaque_put(b, &msg->auth_data);
+ guint16_put(b, msg->auth_type);
+
+ guint16_put(b, 0x0000); /* unknown */
+}
+
+
+static void LOGIN_get(struct mwGetBuffer *b, struct mwMsgLogin *msg) {
+ if(mwGetBuffer_error(b)) return;
+
+ guint16_get(b, &msg->login_type);
+ mwString_get(b, &msg->name);
+ mwOpaque_get(b, &msg->auth_data);
+ guint16_get(b, &msg->auth_type);
+}
+
+
+static void LOGIN_clear(struct mwMsgLogin *msg) {
+ g_free(msg->name); msg->name = NULL;
+ mwOpaque_clear(&msg->auth_data);
+}
+
+
+/* 8.4.1.4 LoginAck */
+
+
+static void LOGIN_ACK_get(struct mwGetBuffer *b, struct mwMsgLoginAck *msg) {
+ guint16 junk;
+
+ if(mwGetBuffer_error(b)) return;
+
+ mwLoginInfo_get(b, &msg->login);
+ guint16_get(b, &junk);
+ mwPrivacyInfo_get(b, &msg->privacy);
+ mwUserStatus_get(b, &msg->status);
+}
+
+
+static void LOGIN_ACK_clear(struct mwMsgLoginAck *msg) {
+ mwLoginInfo_clear(&msg->login);
+ mwPrivacyInfo_clear(&msg->privacy);
+ mwUserStatus_clear(&msg->status);
+}
+
+
+/* 8.4.1.5 LoginCont */
+
+
+static void LOGIN_CONTINUE_put(struct mwPutBuffer *b,
+ struct mwMsgLoginContinue *msg) {
+
+ ; /* nothing but a message header */
+}
+
+
+static void LOGIN_CONTINUE_get(struct mwGetBuffer *b,
+ struct mwMsgLoginContinue *msg) {
+
+ ; /* nothing but a message header */
+}
+
+
+static void LOGIN_CONTINUE_clear(struct mwMsgLoginContinue *msg) {
+ ; /* this is a very simple message */
+}
+
+
+/* 8.4.1.6 AuthPassed */
+
+
+static void LOGIN_REDIRECT_get(struct mwGetBuffer *b,
+ struct mwMsgLoginRedirect *msg) {
+
+ if(mwGetBuffer_error(b)) return;
+ mwString_get(b, &msg->host);
+ mwString_get(b, &msg->server_id);
+}
+
+
+static void LOGIN_REDIRECT_put(struct mwPutBuffer *b,
+ struct mwMsgLoginRedirect *msg) {
+ mwString_put(b, msg->host);
+ mwString_put(b, msg->server_id);
+}
+
+
+static void LOGIN_REDIRECT_clear(struct mwMsgLoginRedirect *msg) {
+ g_free(msg->host);
+ msg->host = NULL;
+
+ g_free(msg->server_id);
+ msg->server_id = NULL;
+}
+
+
+/* 8.4.1.7 CreateCnl */
+
+
+static void enc_offer_put(struct mwPutBuffer *b, struct mwEncryptOffer *enc) {
+ guint16_put(b, enc->mode);
+
+ if(enc->items) {
+ guint32 count;
+ struct mwPutBuffer *p;
+ struct mwOpaque o;
+ GList *list;
+
+ /* write the count, items, extra, and flag into a tmp buffer,
+ render that buffer into an opaque, and write it into b */
+
+ count = g_list_length(enc->items);
+ p = mwPutBuffer_new();
+
+ guint32_put(p, count);
+ for(list = enc->items; list; list = list->next) {
+ mwEncryptItem_put(p, list->data);
+ }
+
+ guint16_put(p, enc->extra);
+ gboolean_put(p, enc->flag);
+
+ mwPutBuffer_finalize(&o, p);
+ mwOpaque_put(b, &o);
+ mwOpaque_clear(&o);
+ }
+}
+
+
+static void CHANNEL_CREATE_put(struct mwPutBuffer *b,
+ struct mwMsgChannelCreate *msg) {
+
+ guint32_put(b, msg->reserved);
+ guint32_put(b, msg->channel);
+ mwIdBlock_put(b, &msg->target);
+ guint32_put(b, msg->service);
+ guint32_put(b, msg->proto_type);
+ guint32_put(b, msg->proto_ver);
+ guint32_put(b, msg->options);
+ mwOpaque_put(b, &msg->addtl);
+ gboolean_put(b, msg->creator_flag);
+
+ if(msg->creator_flag)
+ mwLoginInfo_put(b, &msg->creator);
+
+ enc_offer_put(b, &msg->encrypt);
+
+ guint32_put(b, 0x00);
+ guint32_put(b, 0x00);
+ guint16_put(b, 0x07);
+}
+
+
+static void enc_offer_get(struct mwGetBuffer *b,
+ struct mwEncryptOffer *enc) {
+ guint32 skip;
+
+ if(mwGetBuffer_error(b)) return;
+
+ guint16_get(b, &enc->mode);
+ guint32_get(b, &skip);
+
+ if(skip >= 7) {
+ guint32 count;
+
+ guint32_get(b, &count);
+
+ while(count-- && (! mwGetBuffer_error(b))) {
+ struct mwEncryptItem *ei = g_new0(struct mwEncryptItem, 1);
+ mwEncryptItem_get(b, ei);
+ enc->items = g_list_append(enc->items, ei);
+ }
+
+ guint16_get(b, &enc->extra);
+ gboolean_get(b, &enc->flag);
+ }
+}
+
+
+static void CHANNEL_CREATE_get(struct mwGetBuffer *b,
+ struct mwMsgChannelCreate *msg) {
+
+ if(mwGetBuffer_error(b)) return;
+
+ guint32_get(b, &msg->reserved);
+ guint32_get(b, &msg->channel);
+ mwIdBlock_get(b, &msg->target);
+ guint32_get(b, &msg->service);
+ guint32_get(b, &msg->proto_type);
+ guint32_get(b, &msg->proto_ver);
+ guint32_get(b, &msg->options);
+ mwOpaque_get(b, &msg->addtl);
+ gboolean_get(b, &msg->creator_flag);
+
+ if(msg->creator_flag)
+ mwLoginInfo_get(b, &msg->creator);
+
+ enc_offer_get(b, &msg->encrypt);
+}
+
+
+static void CHANNEL_CREATE_clear(struct mwMsgChannelCreate *msg) {
+ GList *list;
+
+ mwIdBlock_clear(&msg->target);
+ mwOpaque_clear(&msg->addtl);
+ mwLoginInfo_clear(&msg->creator);
+
+ for(list = msg->encrypt.items; list; list = list->next) {
+ mwEncryptItem_clear(list->data);
+ g_free(list->data);
+ }
+ g_list_free(msg->encrypt.items);
+}
+
+
+/* 8.4.1.8 AcceptCnl */
+
+
+static void enc_accept_put(struct mwPutBuffer *b,
+ struct mwEncryptAccept *enc) {
+
+ guint16_put(b, enc->mode);
+
+ if(enc->item) {
+ struct mwPutBuffer *p;
+ struct mwOpaque o;
+
+ p = mwPutBuffer_new();
+
+ mwEncryptItem_put(p, enc->item);
+ guint16_put(p, enc->extra);
+ gboolean_put(p, enc->flag);
+
+ mwPutBuffer_finalize(&o, p);
+ mwOpaque_put(b, &o);
+ mwOpaque_clear(&o);
+ }
+}
+
+
+static void CHANNEL_ACCEPT_put(struct mwPutBuffer *b,
+ struct mwMsgChannelAccept *msg) {
+
+ guint32_put(b, msg->service);
+ guint32_put(b, msg->proto_type);
+ guint32_put(b, msg->proto_ver);
+ mwOpaque_put(b, &msg->addtl);
+ gboolean_put(b, msg->acceptor_flag);
+
+ if(msg->acceptor_flag)
+ mwLoginInfo_put(b, &msg->acceptor);
+
+ enc_accept_put(b, &msg->encrypt);
+
+ guint32_put(b, 0x00);
+ guint32_put(b, 0x00);
+ guint16_put(b, 0x07);
+}
+
+
+static void enc_accept_get(struct mwGetBuffer *b,
+ struct mwEncryptAccept *enc) {
+ guint32 skip;
+
+ if(mwGetBuffer_error(b)) return;
+
+ guint16_get(b, &enc->mode);
+ guint32_get(b, &skip);
+
+ if(skip >= 6) {
+ enc->item = g_new0(struct mwEncryptItem, 1);
+ mwEncryptItem_get(b, enc->item);
+ }
+
+ if(skip >= 9) {
+ guint16_get(b, &enc->extra);
+ gboolean_get(b, &enc->flag);
+ }
+}
+
+
+static void CHANNEL_ACCEPT_get(struct mwGetBuffer *b,
+ struct mwMsgChannelAccept *msg) {
+
+ if(mwGetBuffer_error(b)) return;
+
+ guint32_get(b, &msg->service);
+ guint32_get(b, &msg->proto_type);
+ guint32_get(b, &msg->proto_ver);
+ mwOpaque_get(b, &msg->addtl);
+ gboolean_get(b, &msg->acceptor_flag);
+
+ if(msg->acceptor_flag)
+ mwLoginInfo_get(b, &msg->acceptor);
+
+ enc_accept_get(b, &msg->encrypt);
+}
+
+
+static void CHANNEL_ACCEPT_clear(struct mwMsgChannelAccept *msg) {
+ mwOpaque_clear(&msg->addtl);
+ mwLoginInfo_clear(&msg->acceptor);
+
+ if(msg->encrypt.item) {
+ mwEncryptItem_clear(msg->encrypt.item);
+ g_free(msg->encrypt.item);
+ }
+}
+
+
+/* 8.4.1.9 SendOnCnl */
+
+
+static void CHANNEL_SEND_put(struct mwPutBuffer *b,
+ struct mwMsgChannelSend *msg) {
+
+ guint16_put(b, msg->type);
+ mwOpaque_put(b, &msg->data);
+}
+
+
+static void CHANNEL_SEND_get(struct mwGetBuffer *b,
+ struct mwMsgChannelSend *msg) {
+
+ if(mwGetBuffer_error(b)) return;
+
+ guint16_get(b, &msg->type);
+ mwOpaque_get(b, &msg->data);
+}
+
+
+static void CHANNEL_SEND_clear(struct mwMsgChannelSend *msg) {
+ mwOpaque_clear(&msg->data);
+}
+
+
+/* 8.4.1.10 DestroyCnl */
+
+
+static void CHANNEL_DESTROY_put(struct mwPutBuffer *b,
+ struct mwMsgChannelDestroy *msg) {
+ guint32_put(b, msg->reason);
+ mwOpaque_put(b, &msg->data);
+}
+
+
+static void CHANNEL_DESTROY_get(struct mwGetBuffer *b,
+ struct mwMsgChannelDestroy *msg) {
+
+ if(mwGetBuffer_error(b)) return;
+
+ guint32_get(b, &msg->reason);
+ mwOpaque_get(b, &msg->data);
+}
+
+
+static void CHANNEL_DESTROY_clear(struct mwMsgChannelDestroy *msg) {
+ mwOpaque_clear(&msg->data);
+}
+
+
+/* 8.4.1.11 SetUserStatus */
+
+
+static void SET_USER_STATUS_put(struct mwPutBuffer *b,
+ struct mwMsgSetUserStatus *msg) {
+ mwUserStatus_put(b, &msg->status);
+}
+
+
+static void SET_USER_STATUS_get(struct mwGetBuffer *b,
+ struct mwMsgSetUserStatus *msg) {
+
+ if(mwGetBuffer_error(b)) return;
+ mwUserStatus_get(b, &msg->status);
+}
+
+
+static void SET_USER_STATUS_clear(struct mwMsgSetUserStatus *msg) {
+ mwUserStatus_clear(&msg->status);
+}
+
+
+/* 8.4.1.12 SetPrivacyList */
+
+
+static void SET_PRIVACY_LIST_put(struct mwPutBuffer *b,
+ struct mwMsgSetPrivacyList *msg) {
+ mwPrivacyInfo_put(b, &msg->privacy);
+}
+
+
+static void SET_PRIVACY_LIST_get(struct mwGetBuffer *b,
+ struct mwMsgSetPrivacyList *msg) {
+
+ if(mwGetBuffer_error(b)) return;
+ mwPrivacyInfo_get(b, &msg->privacy);
+}
+
+
+static void SET_PRIVACY_LIST_clear(struct mwMsgSetPrivacyList *msg) {
+ mwPrivacyInfo_clear(&msg->privacy);
+}
+
+
+/* Sense Service messages */
+
+
+static void SENSE_SERVICE_put(struct mwPutBuffer *b,
+ struct mwMsgSenseService *msg) {
+ guint32_put(b, msg->service);
+}
+
+
+static void SENSE_SERVICE_get(struct mwGetBuffer *b,
+ struct mwMsgSenseService *msg) {
+
+ if(mwGetBuffer_error(b)) return;
+ guint32_get(b, &msg->service);
+}
+
+
+static void SENSE_SERVICE_clear(struct mwMsgSenseService *msg) {
+ ;
+}
+
+
+/* Admin messages */
+
+
+static void ADMIN_get(struct mwGetBuffer *b, struct mwMsgAdmin *msg) {
+ mwString_get(b, &msg->text);
+}
+
+
+static void ADMIN_clear(struct mwMsgAdmin *msg) {
+ g_free(msg->text);
+ msg->text = NULL;
+}
+
+
+/* Announcement messages */
+
+
+static void ANNOUNCE_get(struct mwGetBuffer *b, struct mwMsgAnnounce *msg) {
+ struct mwOpaque o = { 0, 0 };
+ struct mwGetBuffer *gb;
+ guint32 count;
+
+ gboolean_get(b, &msg->sender_present);
+ if(msg->sender_present)
+ mwLoginInfo_get(b, &msg->sender);
+ guint16_get(b, &msg->unknown_a);
+
+ mwOpaque_get(b, &o);
+ gb = mwGetBuffer_wrap(&o);
+
+ gboolean_get(gb, &msg->may_reply);
+ mwString_get(gb, &msg->text);
+
+ mwGetBuffer_free(gb);
+ mwOpaque_clear(&o);
+
+ guint32_get(b, &count);
+ while(count--) {
+ char *r = NULL;
+ mwString_get(b, &r);
+ msg->recipients = g_list_prepend(msg->recipients, r);
+ }
+}
+
+
+static void ANNOUNCE_put(struct mwPutBuffer *b, struct mwMsgAnnounce *msg) {
+ struct mwOpaque o = { 0, 0 };
+ struct mwPutBuffer *pb;
+ GList *l;
+
+ gboolean_put(b, msg->sender_present);
+ if(msg->sender_present)
+ mwLoginInfo_put(b, &msg->sender);
+ guint16_put(b, msg->unknown_a);
+
+ pb = mwPutBuffer_new();
+
+ gboolean_put(pb, msg->may_reply);
+ mwString_put(pb, msg->text);
+
+ mwPutBuffer_finalize(&o, pb);
+ mwOpaque_put(b, &o);
+ mwOpaque_clear(&o);
+
+ guint32_put(b, g_list_length(msg->recipients));
+ for(l = msg->recipients; l; l = l->next) {
+ mwString_put(b, l->data);
+ }
+}
+
+
+static void ANNOUNCE_clear(struct mwMsgAnnounce *msg) {
+ mwLoginInfo_clear(&msg->sender);
+
+ g_free(msg->text);
+ msg->text = NULL;
+
+ while(msg->recipients) {
+ g_free(msg->recipients->data);
+ msg->recipients = g_list_delete_link(msg->recipients, msg->recipients);
+ }
+}
+
+
+/* general functions */
+
+
+#define CASE(v, t) \
+case mwMessage_ ## v: \
+ msg = (struct mwMessage *) g_new0(struct t, 1); \
+ msg->type = type; \
+ break;
+
+
+struct mwMessage *mwMessage_new(enum mwMessageType type) {
+ struct mwMessage *msg = NULL;
+
+ switch(type) {
+ CASE(HANDSHAKE, mwMsgHandshake);
+ CASE(HANDSHAKE_ACK, mwMsgHandshakeAck);
+ CASE(LOGIN, mwMsgLogin);
+ CASE(LOGIN_REDIRECT, mwMsgLoginRedirect);
+ CASE(LOGIN_CONTINUE, mwMsgLoginContinue);
+ CASE(LOGIN_ACK, mwMsgLoginAck);
+ CASE(CHANNEL_CREATE, mwMsgChannelCreate);
+ CASE(CHANNEL_DESTROY, mwMsgChannelDestroy);
+ CASE(CHANNEL_SEND, mwMsgChannelSend);
+ CASE(CHANNEL_ACCEPT, mwMsgChannelAccept);
+ CASE(SET_USER_STATUS, mwMsgSetUserStatus);
+ CASE(SET_PRIVACY_LIST, mwMsgSetPrivacyList);
+ CASE(SENSE_SERVICE, mwMsgSenseService);
+ CASE(ADMIN, mwMsgAdmin);
+ CASE(ANNOUNCE, mwMsgAnnounce);
+
+ default:
+ g_warning("unknown message type 0x%02x\n", type);
+ }
+
+ return msg;
+}
+
+
+#undef CASE
+
+
+/* each type needs to be passed to a specially named _get functions,
+ and cast to a specific subclass of mwMessage. */
+#define CASE(v, t) \
+case mwMessage_ ## v: \
+ msg = (struct mwMessage *) g_new0(struct t, 1); \
+ mwMessageHead_clone(msg, &head); \
+ v ## _get(b, (struct t *) msg); \
+ break;
+
+
+struct mwMessage *mwMessage_get(struct mwGetBuffer *b) {
+ struct mwMessage *msg = NULL;
+ struct mwMessage head;
+
+ g_return_val_if_fail(b != NULL, NULL);
+
+ head.attribs.len = 0;
+ head.attribs.data = NULL;
+
+ /* attempt to read the header first */
+ mwMessageHead_get(b, &head);
+
+ if(mwGetBuffer_error(b)) {
+ mwMessageHead_clear(&head);
+ g_warning("problem parsing message head from buffer");
+ return NULL;
+ }
+
+ /* load the rest of the message depending on the header type */
+ switch(head.type) {
+ CASE(HANDSHAKE, mwMsgHandshake);
+ CASE(HANDSHAKE_ACK, mwMsgHandshakeAck);
+ CASE(LOGIN, mwMsgLogin);
+ CASE(LOGIN_REDIRECT, mwMsgLoginRedirect);
+ CASE(LOGIN_CONTINUE, mwMsgLoginContinue);
+ CASE(LOGIN_ACK, mwMsgLoginAck);
+ CASE(CHANNEL_CREATE, mwMsgChannelCreate);
+ CASE(CHANNEL_DESTROY, mwMsgChannelDestroy);
+ CASE(CHANNEL_SEND, mwMsgChannelSend);
+ CASE(CHANNEL_ACCEPT, mwMsgChannelAccept);
+ CASE(SET_USER_STATUS, mwMsgSetUserStatus);
+ CASE(SET_PRIVACY_LIST, mwMsgSetPrivacyList);
+ CASE(SENSE_SERVICE, mwMsgSenseService);
+ CASE(ADMIN, mwMsgAdmin);
+ CASE(ANNOUNCE, mwMsgAnnounce);
+
+ default:
+ g_warning("unknown message type 0x%02x, no parse handler", head.type);
+ }
+
+ if(mwGetBuffer_error(b)) {
+ g_warning("problem parsing message type 0x%02x, not enough data",
+ head.type);
+ }
+
+ mwMessageHead_clear(&head);
+
+ return msg;
+}
+
+
+#undef CASE
+
+
+#define CASE(v, t) \
+case mwMessage_ ## v: \
+ v ## _put(b, (struct t *) msg); \
+ break;
+
+
+void mwMessage_put(struct mwPutBuffer *b, struct mwMessage *msg) {
+
+ g_return_if_fail(b != NULL);
+ g_return_if_fail(msg != NULL);
+
+ mwMessageHead_put(b, msg);
+
+ switch(msg->type) {
+ CASE(HANDSHAKE, mwMsgHandshake);
+ CASE(HANDSHAKE_ACK, mwMsgHandshakeAck);
+ CASE(LOGIN, mwMsgLogin);
+ CASE(LOGIN_REDIRECT, mwMsgLoginRedirect);
+ CASE(LOGIN_CONTINUE, mwMsgLoginContinue);
+ CASE(CHANNEL_CREATE, mwMsgChannelCreate);
+ CASE(CHANNEL_DESTROY, mwMsgChannelDestroy);
+ CASE(CHANNEL_SEND, mwMsgChannelSend);
+ CASE(CHANNEL_ACCEPT, mwMsgChannelAccept);
+ CASE(SET_USER_STATUS, mwMsgSetUserStatus);
+ CASE(SET_PRIVACY_LIST, mwMsgSetPrivacyList);
+ CASE(SENSE_SERVICE, mwMsgSenseService);
+ CASE(ANNOUNCE, mwMsgAnnounce);
+
+ default:
+ ; /* hrm. */
+ }
+}
+
+
+#undef CASE
+
+
+#define CASE(v, t) \
+case mwMessage_ ## v: \
+ v ## _clear((struct t *) msg); \
+ break;
+
+
+void mwMessage_free(struct mwMessage *msg) {
+ if(! msg) return;
+
+ mwMessageHead_clear(msg);
+
+ switch(msg->type) {
+ CASE(HANDSHAKE, mwMsgHandshake);
+ CASE(HANDSHAKE_ACK, mwMsgHandshakeAck);
+ CASE(LOGIN, mwMsgLogin);
+ CASE(LOGIN_REDIRECT, mwMsgLoginRedirect);
+ CASE(LOGIN_CONTINUE, mwMsgLoginContinue);
+ CASE(LOGIN_ACK, mwMsgLoginAck);
+ CASE(CHANNEL_CREATE, mwMsgChannelCreate);
+ CASE(CHANNEL_DESTROY, mwMsgChannelDestroy);
+ CASE(CHANNEL_SEND, mwMsgChannelSend);
+ CASE(CHANNEL_ACCEPT, mwMsgChannelAccept);
+ CASE(SET_USER_STATUS, mwMsgSetUserStatus);
+ CASE(SET_PRIVACY_LIST, mwMsgSetPrivacyList);
+ CASE(SENSE_SERVICE, mwMsgSenseService);
+ CASE(ADMIN, mwMsgAdmin);
+ CASE(ANNOUNCE, mwMsgAnnounce);
+
+ default:
+ ; /* hrm. */
+ }
+
+ g_free(msg);
+}
+
+
+#undef CASE
+
+
diff --git a/protocols/Sametime/src/meanwhile/src/mpi/mpi-config.h b/protocols/Sametime/src/meanwhile/src/mpi/mpi-config.h
new file mode 100644
index 0000000000..6972c8878d
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/mpi/mpi-config.h
@@ -0,0 +1,84 @@
+/* Default configuration for MPI library */
+
+#ifndef MPI_CONFIG_H_
+#define MPI_CONFIG_H_
+
+/*
+ For boolean options,
+ 0 = no
+ 1 = yes
+
+ Other options are documented individually.
+
+ */
+
+#ifndef MP_IOFUNC
+#define MP_IOFUNC 0 /* include mp_print() ? */
+#endif
+
+#ifndef MP_MODARITH
+#define MP_MODARITH 1 /* include modular arithmetic ? */
+#endif
+
+#ifndef MP_NUMTH
+#define MP_NUMTH 1 /* include number theoretic functions? */
+#endif
+
+#ifndef MP_LOGTAB
+#define MP_LOGTAB 0 /* use table of logs instead of log()? */
+#endif
+
+#ifndef MP_MEMSET
+#define MP_MEMSET 1 /* use memset() to zero buffers? */
+#endif
+
+#ifndef MP_MEMCPY
+#define MP_MEMCPY 1 /* use memcpy() to copy buffers? */
+#endif
+
+#ifndef MP_CRYPTO
+#define MP_CRYPTO 0 /* erase memory on free? */
+#endif
+
+#ifndef MP_ARGCHK
+/*
+ 0 = no parameter checks
+ 1 = runtime checks, continue execution and return an error to caller
+ 2 = assertions; dump core on parameter errors
+ */
+#define MP_ARGCHK 2 /* how to check input arguments */
+#endif
+
+#ifndef MP_DEBUG
+#define MP_DEBUG 0 /* print diagnostic output? */
+#endif
+
+#ifndef MP_DEFPREC
+#define MP_DEFPREC 32 /* default precision, in digits */
+#endif
+
+#ifndef MP_MACRO
+#define MP_MACRO 1 /* use macros for frequent calls? */
+#endif
+
+#ifndef MP_SQUARE
+#define MP_SQUARE 1 /* use separate squaring code? */
+#endif
+
+#ifndef MP_PTAB_SIZE
+/*
+ When building mpprime.c, we build in a table of small prime
+ values to use for primality testing. The more you include,
+ the more space they take up. See primes.c for the possible
+ values (currently 16, 32, 64, 128, 256, and 6542)
+ */
+#define MP_PTAB_SIZE 128 /* how many built-in primes? */
+#endif
+
+#ifndef MP_COMPAT_MACROS
+#define MP_COMPAT_MACROS 0 /* define compatibility macros? */
+#endif
+
+#endif /* ifndef MPI_CONFIG_H_ */
+
+
diff --git a/protocols/Sametime/src/meanwhile/src/mpi/mpi-types.h b/protocols/Sametime/src/meanwhile/src/mpi/mpi-types.h
new file mode 100644
index 0000000000..137047ca77
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/mpi/mpi-types.h
@@ -0,0 +1,18 @@
+
+#include <glib.h>
+
+typedef gchar mw_mp_sign;
+typedef guint16 mw_mp_digit; /* 2 byte type */
+typedef guint32 mw_mp_word; /* 4 byte type */
+typedef gsize mw_mp_size;
+typedef gint mw_mp_err;
+
+#define MP_DIGIT_BIT 16
+#define MP_DIGIT_MAX G_MAXUINT16
+#define MP_WORD_BIT 32
+#define MP_WORD_MAX G_MAXUINT32
+
+#define RADIX (MP_DIGIT_MAX+1)
+
+#define MP_DIGIT_SIZE 2
+#define DIGIT_FMT "%04X"
diff --git a/protocols/Sametime/src/meanwhile/src/mpi/mpi.c b/protocols/Sametime/src/meanwhile/src/mpi/mpi.c
new file mode 100644
index 0000000000..1a33e98525
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/mpi/mpi.c
@@ -0,0 +1,4022 @@
+/*
+ mpi.c
+
+ by Michael J. Fromberger <http://www.dartmouth.edu/~sting/>
+ Copyright (C) 1998 Michael J. Fromberger, All Rights Reserved
+
+ Arbitrary precision integer arithmetic library
+
+ modified for use in Meanwhile as a convenience library
+*/
+
+#include "mpi.h"
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#if MP_DEBUG
+#include <stdio.h>
+
+#define DIAG(T,V) {fprintf(stderr,T);mw_mp_print(V,stderr);fputc('\n',stderr);}
+#else
+#define DIAG(T,V)
+#endif
+
+/*
+ If MP_LOGTAB is not defined, use the math library to compute the
+ logarithms on the fly. Otherwise, use the static table below.
+ Pick which works best for your system.
+ */
+#if MP_LOGTAB
+
+/* {{{ s_logv_2[] - log table for 2 in various bases */
+
+/*
+ A table of the logs of 2 for various bases (the 0 and 1 entries of
+ this table are meaningless and should not be referenced).
+
+ This table is used to compute output lengths for the mw_mp_toradix()
+ function. Since a number n in radix r takes up about log_r(n)
+ digits, we estimate the output size by taking the least integer
+ greater than log_r(n), where:
+
+ log_r(n) = log_2(n) * log_r(2)
+
+ This table, therefore, is a table of log_r(2) for 2 <= r <= 36,
+ which are the output bases supported.
+ */
+
+#include "logtab.h"
+
+/* }}} */
+#define LOG_V_2(R) s_logv_2[(R)]
+
+#else
+
+#include <math.h>
+#define LOG_V_2(R) (log(2.0)/log(R))
+
+#endif
+
+/* Default precision for newly created mw_mp_int's */
+static unsigned int s_mw_mp_defprec = MP_DEFPREC;
+
+/* {{{ Digit arithmetic macros */
+
+/*
+ When adding and multiplying digits, the results can be larger than
+ can be contained in an mw_mp_digit. Thus, an mw_mp_word is used. These
+ macros mask off the upper and lower digits of the mw_mp_word (the
+ mw_mp_word may be more than 2 mw_mp_digits wide, but we only concern
+ ourselves with the low-order 2 mw_mp_digits)
+
+ If your mw_mp_word DOES have more than 2 mw_mp_digits, you need to
+ uncomment the first line, and comment out the second.
+ */
+
+/* #define CARRYOUT(W) (((W)>>DIGIT_BIT)&MP_DIGIT_MAX) */
+#define CARRYOUT(W) ((W)>>DIGIT_BIT)
+#define ACCUM(W) ((W)&MP_DIGIT_MAX)
+
+/* }}} */
+
+/* {{{ Comparison constants */
+
+#define MP_LT -1
+#define MP_EQ 0
+#define MP_GT 1
+
+/* }}} */
+
+/* {{{ Constant strings */
+
+/* Constant strings returned by mw_mp_strerror() */
+static const char *mw_mp_err_string[] = {
+ "unknown result code", /* say what? */
+ "boolean true", /* MP_OKAY, MP_YES */
+ "boolean false", /* MP_NO */
+ "out of memory", /* MP_MEM */
+ "argument out of range", /* MP_RANGE */
+ "invalid input parameter", /* MP_BADARG */
+ "result is undefined" /* MP_UNDEF */
+};
+
+/* Value to digit maps for radix conversion */
+
+/* s_dmap_1 - standard digits and letters */
+static const char *s_dmap_1 =
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
+
+#if 0
+/* s_dmap_2 - base64 ordering for digits */
+static const char *s_dmap_2 =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+#endif
+
+/* }}} */
+
+/* {{{ Static function declarations */
+
+/*
+ If MP_MACRO is false, these will be defined as actual functions;
+ otherwise, suitable macro definitions will be used. This works
+ around the fact that ANSI C89 doesn't support an 'inline' keyword
+ (although I hear C9x will ... about bloody time). At present, the
+ macro definitions are identical to the function bodies, but they'll
+ expand in place, instead of generating a function call.
+
+ I chose these particular functions to be made into macros because
+ some profiling showed they are called a lot on a typical workload,
+ and yet they are primarily housekeeping.
+ */
+#if MP_MACRO == 0
+ void s_mw_mp_setz(mw_mp_digit *dp, mw_mp_size count); /* zero digits */
+ void s_mw_mp_copy(mw_mp_digit *sp, mw_mp_digit *dp, mw_mp_size count); /* copy */
+ void *s_mw_mp_alloc(size_t nb, size_t ni); /* general allocator */
+ void s_mw_mp_free(void *ptr); /* general free function */
+#else
+
+ /* Even if these are defined as macros, we need to respect the settings
+ of the MP_MEMSET and MP_MEMCPY configuration options...
+ */
+ #if MP_MEMSET == 0
+ #define s_mw_mp_setz(dp, count) \
+ {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=0;}
+ #else
+ #define s_mw_mp_setz(dp, count) memset(dp, 0, (count) * sizeof(mw_mp_digit))
+ #endif /* MP_MEMSET */
+
+ #if MP_MEMCPY == 0
+ #define s_mw_mp_copy(sp, dp, count) \
+ {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=(sp)[ix];}
+ #else
+ #define s_mw_mp_copy(sp, dp, count) memcpy(dp, sp, (count) * sizeof(mw_mp_digit))
+ #endif /* MP_MEMCPY */
+
+ #define s_mw_mp_alloc(nb, ni) calloc(nb, ni)
+ #define s_mw_mp_free(ptr) {if(ptr) free(ptr);}
+#endif /* MP_MACRO */
+
+mw_mp_err s_mw_mp_grow(mw_mp_int *mp, mw_mp_size min); /* increase allocated size */
+mw_mp_err s_mw_mp_pad(mw_mp_int *mp, mw_mp_size min); /* left pad with zeroes */
+
+void s_mw_mp_clamp(mw_mp_int *mp); /* clip leading zeroes */
+
+void s_mw_mp_exch(mw_mp_int *a, mw_mp_int *b); /* swap a and b in place */
+
+mw_mp_err s_mw_mp_lshd(mw_mp_int *mp, mw_mp_size p); /* left-shift by p digits */
+void s_mw_mp_rshd(mw_mp_int *mp, mw_mp_size p); /* right-shift by p digits */
+void s_mw_mp_div_2d(mw_mp_int *mp, mw_mp_digit d); /* divide by 2^d in place */
+void s_mw_mp_mod_2d(mw_mp_int *mp, mw_mp_digit d); /* modulo 2^d in place */
+mw_mp_err s_mw_mp_mul_2d(mw_mp_int *mp, mw_mp_digit d); /* multiply by 2^d in place*/
+void s_mw_mp_div_2(mw_mp_int *mp); /* divide by 2 in place */
+mw_mp_err s_mw_mp_mul_2(mw_mp_int *mp); /* multiply by 2 in place */
+mw_mp_digit s_mw_mp_norm(mw_mp_int *a, mw_mp_int *b); /* normalize for division */
+mw_mp_err s_mw_mp_add_d(mw_mp_int *mp, mw_mp_digit d); /* unsigned digit addition */
+mw_mp_err s_mw_mp_sub_d(mw_mp_int *mp, mw_mp_digit d); /* unsigned digit subtract */
+mw_mp_err s_mw_mp_mul_d(mw_mp_int *mp, mw_mp_digit d); /* unsigned digit multiply */
+mw_mp_err s_mw_mp_div_d(mw_mp_int *mp, mw_mp_digit d, mw_mp_digit *r);
+ /* unsigned digit divide */
+mw_mp_err s_mw_mp_reduce(mw_mp_int *x, mw_mp_int *m, mw_mp_int *mu);
+ /* Barrett reduction */
+mw_mp_err s_mw_mp_add(mw_mp_int *a, mw_mp_int *b); /* magnitude addition */
+mw_mp_err s_mw_mp_sub(mw_mp_int *a, mw_mp_int *b); /* magnitude subtract */
+mw_mp_err s_mw_mp_mul(mw_mp_int *a, mw_mp_int *b); /* magnitude multiply */
+#if 0
+void s_mw_mp_kmul(mw_mp_digit *a, mw_mp_digit *b, mw_mp_digit *out, mw_mp_size len);
+ /* multiply buffers in place */
+#endif
+#if MP_SQUARE
+mw_mp_err s_mw_mp_sqr(mw_mp_int *a); /* magnitude square */
+#else
+#define s_mw_mp_sqr(a) s_mw_mp_mul(a, a)
+#endif
+mw_mp_err s_mw_mp_div(mw_mp_int *a, mw_mp_int *b); /* magnitude divide */
+mw_mp_err s_mw_mp_2expt(mw_mp_int *a, mw_mp_digit k); /* a = 2^k */
+int s_mw_mp_cmp(mw_mp_int *a, mw_mp_int *b); /* magnitude comparison */
+int s_mw_mp_cmw_mp_d(mw_mp_int *a, mw_mp_digit d); /* magnitude digit compare */
+int s_mw_mp_ispow2(mw_mp_int *v); /* is v a power of 2? */
+int s_mw_mp_ispow2d(mw_mp_digit d); /* is d a power of 2? */
+
+int s_mw_mp_tovalue(char ch, int r); /* convert ch to value */
+char s_mw_mp_todigit(int val, int r, int low); /* convert val to digit */
+int s_mw_mp_outlen(int bits, int r); /* output length in bytes */
+
+/* }}} */
+
+/* {{{ Default precision manipulation */
+
+unsigned int mw_mp_get_prec(void)
+{
+ return s_mw_mp_defprec;
+
+} /* end mw_mp_get_prec() */
+
+void mw_mp_set_prec(unsigned int prec)
+{
+ if(prec == 0)
+ s_mw_mp_defprec = MP_DEFPREC;
+ else
+ s_mw_mp_defprec = prec;
+
+} /* end mw_mp_set_prec() */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ mw_mp_init(mp) */
+
+/*
+ mw_mp_init(mp)
+
+ Initialize a new zero-valued mw_mp_int. Returns MP_OKAY if successful,
+ MP_MEM if memory could not be allocated for the structure.
+ */
+
+mw_mp_err mw_mp_init(mw_mp_int *mp)
+{
+ return mw_mp_init_size(mp, s_mw_mp_defprec);
+
+} /* end mw_mp_init() */
+
+/* }}} */
+
+/* {{{ mw_mp_init_array(mp[], count) */
+
+mw_mp_err mw_mp_init_array(mw_mp_int mp[], int count)
+{
+ mw_mp_err res;
+ int pos;
+
+ ARGCHK(mp !=NULL && count > 0, MP_BADARG);
+
+ for(pos = 0; pos < count; ++pos) {
+ if((res = mw_mp_init(&mp[pos])) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ return MP_OKAY;
+
+ CLEANUP:
+ while(--pos >= 0)
+ mw_mp_clear(&mp[pos]);
+
+ return res;
+
+} /* end mw_mp_init_array() */
+
+/* }}} */
+
+/* {{{ mw_mp_init_size(mp, prec) */
+
+/*
+ mw_mp_init_size(mp, prec)
+
+ Initialize a new zero-valued mw_mp_int with at least the given
+ precision; returns MP_OKAY if successful, or MP_MEM if memory could
+ not be allocated for the structure.
+ */
+
+mw_mp_err mw_mp_init_size(mw_mp_int *mp, mw_mp_size prec)
+{
+ ARGCHK(mp != NULL && prec > 0, MP_BADARG);
+
+ if((DIGITS(mp) = s_mw_mp_alloc(prec, sizeof(mw_mp_digit))) == NULL)
+ return MP_MEM;
+
+ SIGN(mp) = MP_ZPOS;
+ USED(mp) = 1;
+ ALLOC(mp) = prec;
+
+ return MP_OKAY;
+
+} /* end mw_mp_init_size() */
+
+/* }}} */
+
+/* {{{ mw_mp_init_copy(mp, from) */
+
+/*
+ mw_mp_init_copy(mp, from)
+
+ Initialize mp as an exact copy of from. Returns MP_OKAY if
+ successful, MP_MEM if memory could not be allocated for the new
+ structure.
+ */
+
+mw_mp_err mw_mp_init_copy(mw_mp_int *mp, mw_mp_int *from)
+{
+ ARGCHK(mp != NULL && from != NULL, MP_BADARG);
+
+ if(mp == from)
+ return MP_OKAY;
+
+ if((DIGITS(mp) = s_mw_mp_alloc(USED(from), sizeof(mw_mp_digit))) == NULL)
+ return MP_MEM;
+
+ s_mw_mp_copy(DIGITS(from), DIGITS(mp), USED(from));
+ USED(mp) = USED(from);
+ ALLOC(mp) = USED(from);
+ SIGN(mp) = SIGN(from);
+
+ return MP_OKAY;
+
+} /* end mw_mp_init_copy() */
+
+/* }}} */
+
+/* {{{ mw_mp_copy(from, to) */
+
+/*
+ mw_mp_copy(from, to)
+
+ Copies the mw_mp_int 'from' to the mw_mp_int 'to'. It is presumed that
+ 'to' has already been initialized (if not, use mw_mp_init_copy()
+ instead). If 'from' and 'to' are identical, nothing happens.
+ */
+
+mw_mp_err mw_mp_copy(mw_mp_int *from, mw_mp_int *to)
+{
+ ARGCHK(from != NULL && to != NULL, MP_BADARG);
+
+ if(from == to)
+ return MP_OKAY;
+
+ { /* copy */
+ mw_mp_digit *tmp;
+
+ /*
+ If the allocated buffer in 'to' already has enough space to hold
+ all the used digits of 'from', we'll re-use it to avoid hitting
+ the memory allocater more than necessary; otherwise, we'd have
+ to grow anyway, so we just allocate a hunk and make the copy as
+ usual
+ */
+ if(ALLOC(to) >= USED(from)) {
+ s_mw_mp_setz(DIGITS(to) + USED(from), ALLOC(to) - USED(from));
+ s_mw_mp_copy(DIGITS(from), DIGITS(to), USED(from));
+
+ } else {
+ if((tmp = s_mw_mp_alloc(USED(from), sizeof(mw_mp_digit))) == NULL)
+ return MP_MEM;
+
+ s_mw_mp_copy(DIGITS(from), tmp, USED(from));
+
+ if(DIGITS(to) != NULL) {
+#if MP_CRYPTO
+ s_mw_mp_setz(DIGITS(to), ALLOC(to));
+#endif
+ s_mw_mp_free(DIGITS(to));
+ }
+
+ DIGITS(to) = tmp;
+ ALLOC(to) = USED(from);
+ }
+
+ /* Copy the precision and sign from the original */
+ USED(to) = USED(from);
+ SIGN(to) = SIGN(from);
+ } /* end copy */
+
+ return MP_OKAY;
+
+} /* end mw_mp_copy() */
+
+/* }}} */
+
+/* {{{ mw_mp_exch(mp1, mp2) */
+
+/*
+ mw_mp_exch(mp1, mp2)
+
+ Exchange mp1 and mp2 without allocating any intermediate memory
+ (well, unless you count the stack space needed for this call and the
+ locals it creates...). This cannot fail.
+ */
+
+void mw_mp_exch(mw_mp_int *mp1, mw_mp_int *mp2)
+{
+#if MP_ARGCHK == 2
+ assert(mp1 != NULL && mp2 != NULL);
+#else
+ if(mp1 == NULL || mp2 == NULL)
+ return;
+#endif
+
+ s_mw_mp_exch(mp1, mp2);
+
+} /* end mw_mp_exch() */
+
+/* }}} */
+
+/* {{{ mw_mp_clear(mp) */
+
+/*
+ mw_mp_clear(mp)
+
+ Release the storage used by an mw_mp_int, and void its fields so that
+ if someone calls mw_mp_clear() again for the same int later, we won't
+ get tollchocked.
+ */
+
+void mw_mp_clear(mw_mp_int *mp)
+{
+ if(mp == NULL)
+ return;
+
+ if(DIGITS(mp) != NULL) {
+#if MP_CRYPTO
+ s_mw_mp_setz(DIGITS(mp), ALLOC(mp));
+#endif
+ s_mw_mp_free(DIGITS(mp));
+ DIGITS(mp) = NULL;
+ }
+
+ USED(mp) = 0;
+ ALLOC(mp) = 0;
+
+} /* end mw_mp_clear() */
+
+/* }}} */
+
+/* {{{ mw_mp_clear_array(mp[], count) */
+
+void mw_mp_clear_array(mw_mp_int mp[], int count)
+{
+ ARGCHK(mp != NULL && count > 0, MP_BADARG);
+
+ while(--count >= 0)
+ mw_mp_clear(&mp[count]);
+
+} /* end mw_mp_clear_array() */
+
+/* }}} */
+
+/* {{{ mw_mp_zero(mp) */
+
+/*
+ mw_mp_zero(mp)
+
+ Set mp to zero. Does not change the allocated size of the structure,
+ and therefore cannot fail (except on a bad argument, which we ignore)
+ */
+void mw_mp_zero(mw_mp_int *mp)
+{
+ if(mp == NULL)
+ return;
+
+ s_mw_mp_setz(DIGITS(mp), ALLOC(mp));
+ USED(mp) = 1;
+ SIGN(mp) = MP_ZPOS;
+
+} /* end mw_mp_zero() */
+
+/* }}} */
+
+/* {{{ mw_mp_set(mp, d) */
+
+void mw_mp_set(mw_mp_int *mp, mw_mp_digit d)
+{
+ if(mp == NULL)
+ return;
+
+ mw_mp_zero(mp);
+ DIGIT(mp, 0) = d;
+
+} /* end mw_mp_set() */
+
+/* }}} */
+
+/* {{{ mw_mp_set_int(mp, z) */
+
+mw_mp_err mw_mp_set_int(mw_mp_int *mp, long z)
+{
+ int ix;
+ unsigned long v = abs(z);
+ mw_mp_err res;
+
+ ARGCHK(mp != NULL, MP_BADARG);
+
+ mw_mp_zero(mp);
+ if(z == 0)
+ return MP_OKAY; /* shortcut for zero */
+
+ for(ix = sizeof(long) - 1; ix >= 0; ix--) {
+
+ if((res = s_mw_mp_mul_2d(mp, CHAR_BIT)) != MP_OKAY)
+ return res;
+
+ res = s_mw_mp_add_d(mp,
+ (mw_mp_digit)((v >> (ix * CHAR_BIT)) & UCHAR_MAX));
+ if(res != MP_OKAY)
+ return res;
+
+ }
+
+ if(z < 0)
+ SIGN(mp) = MP_NEG;
+
+ return MP_OKAY;
+
+} /* end mw_mp_set_int() */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ Digit arithmetic */
+
+/* {{{ mw_mp_add_d(a, d, b) */
+
+/*
+ mw_mp_add_d(a, d, b)
+
+ Compute the sum b = a + d, for a single digit d. Respects the sign of
+ its primary addend (single digits are unsigned anyway).
+ */
+
+mw_mp_err mw_mp_add_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *b)
+{
+ mw_mp_err res = MP_OKAY;
+
+ ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+ if((res = mw_mp_copy(a, b)) != MP_OKAY)
+ return res;
+
+ if(SIGN(b) == MP_ZPOS) {
+ res = s_mw_mp_add_d(b, d);
+ } else if(s_mw_mp_cmw_mp_d(b, d) >= 0) {
+ res = s_mw_mp_sub_d(b, d);
+ } else {
+ SIGN(b) = MP_ZPOS;
+
+ DIGIT(b, 0) = d - DIGIT(b, 0);
+ }
+
+ return res;
+
+} /* end mw_mp_add_d() */
+
+/* }}} */
+
+/* {{{ mw_mp_sub_d(a, d, b) */
+
+/*
+ mw_mp_sub_d(a, d, b)
+
+ Compute the difference b = a - d, for a single digit d. Respects the
+ sign of its subtrahend (single digits are unsigned anyway).
+ */
+
+mw_mp_err mw_mp_sub_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *b)
+{
+ mw_mp_err res;
+
+ ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+ if((res = mw_mp_copy(a, b)) != MP_OKAY)
+ return res;
+
+ if(SIGN(b) == MP_NEG) {
+ if((res = s_mw_mp_add_d(b, d)) != MP_OKAY)
+ return res;
+
+ } else if(s_mw_mp_cmw_mp_d(b, d) >= 0) {
+ if((res = s_mw_mp_sub_d(b, d)) != MP_OKAY)
+ return res;
+
+ } else {
+ mw_mp_neg(b, b);
+
+ DIGIT(b, 0) = d - DIGIT(b, 0);
+ SIGN(b) = MP_NEG;
+ }
+
+ if(s_mw_mp_cmw_mp_d(b, 0) == 0)
+ SIGN(b) = MP_ZPOS;
+
+ return MP_OKAY;
+
+} /* end mw_mp_sub_d() */
+
+/* }}} */
+
+/* {{{ mw_mp_mul_d(a, d, b) */
+
+/*
+ mw_mp_mul_d(a, d, b)
+
+ Compute the product b = a * d, for a single digit d. Respects the sign
+ of its multiplicand (single digits are unsigned anyway)
+ */
+
+mw_mp_err mw_mp_mul_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *b)
+{
+ mw_mp_err res;
+
+ ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+ if(d == 0) {
+ mw_mp_zero(b);
+ return MP_OKAY;
+ }
+
+ if((res = mw_mp_copy(a, b)) != MP_OKAY)
+ return res;
+
+ res = s_mw_mp_mul_d(b, d);
+
+ return res;
+
+} /* end mw_mp_mul_d() */
+
+/* }}} */
+
+/* {{{ mw_mp_mul_2(a, c) */
+
+mw_mp_err mw_mp_mul_2(mw_mp_int *a, mw_mp_int *c)
+{
+ mw_mp_err res;
+
+ ARGCHK(a != NULL && c != NULL, MP_BADARG);
+
+ if((res = mw_mp_copy(a, c)) != MP_OKAY)
+ return res;
+
+ return s_mw_mp_mul_2(c);
+
+} /* end mw_mp_mul_2() */
+
+/* }}} */
+
+/* {{{ mw_mp_div_d(a, d, q, r) */
+
+/*
+ mw_mp_div_d(a, d, q, r)
+
+ Compute the quotient q = a / d and remainder r = a mod d, for a
+ single digit d. Respects the sign of its divisor (single digits are
+ unsigned anyway).
+ */
+
+mw_mp_err mw_mp_div_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *q, mw_mp_digit *r)
+{
+ mw_mp_err res;
+ mw_mp_digit rem;
+ int pow;
+
+ ARGCHK(a != NULL, MP_BADARG);
+
+ if(d == 0)
+ return MP_RANGE;
+
+ /* Shortcut for powers of two ... */
+ if((pow = s_mw_mp_ispow2d(d)) >= 0) {
+ mw_mp_digit mask;
+
+ mask = (1 << pow) - 1;
+ rem = DIGIT(a, 0) & mask;
+
+ if(q) {
+ mw_mp_copy(a, q);
+ s_mw_mp_div_2d(q, pow);
+ }
+
+ if(r)
+ *r = rem;
+
+ return MP_OKAY;
+ }
+
+ /*
+ If the quotient is actually going to be returned, we'll try to
+ avoid hitting the memory allocator by copying the dividend into it
+ and doing the division there. This can't be any _worse_ than
+ always copying, and will sometimes be better (since it won't make
+ another copy)
+
+ If it's not going to be returned, we need to allocate a temporary
+ to hold the quotient, which will just be discarded.
+ */
+ if(q) {
+ if((res = mw_mp_copy(a, q)) != MP_OKAY)
+ return res;
+
+ res = s_mw_mp_div_d(q, d, &rem);
+ if(s_mw_mp_cmw_mp_d(q, 0) == MP_EQ)
+ SIGN(q) = MP_ZPOS;
+
+ } else {
+ mw_mp_int qp;
+
+ if((res = mw_mp_init_copy(&qp, a)) != MP_OKAY)
+ return res;
+
+ res = s_mw_mp_div_d(&qp, d, &rem);
+ if(s_mw_mp_cmw_mp_d(&qp, 0) == 0)
+ SIGN(&qp) = MP_ZPOS;
+
+ mw_mp_clear(&qp);
+ }
+
+ if(r)
+ *r = rem;
+
+ return res;
+
+} /* end mw_mp_div_d() */
+
+/* }}} */
+
+/* {{{ mw_mp_div_2(a, c) */
+
+/*
+ mw_mp_div_2(a, c)
+
+ Compute c = a / 2, disregarding the remainder.
+ */
+
+mw_mp_err mw_mp_div_2(mw_mp_int *a, mw_mp_int *c)
+{
+ mw_mp_err res;
+
+ ARGCHK(a != NULL && c != NULL, MP_BADARG);
+
+ if((res = mw_mp_copy(a, c)) != MP_OKAY)
+ return res;
+
+ s_mw_mp_div_2(c);
+
+ return MP_OKAY;
+
+} /* end mw_mp_div_2() */
+
+/* }}} */
+
+/* {{{ mw_mp_expt_d(a, d, b) */
+
+mw_mp_err mw_mp_expt_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *c)
+{
+ mw_mp_int s, x;
+ mw_mp_err res;
+ mw_mp_sign cs = MP_ZPOS;
+
+ ARGCHK(a != NULL && c != NULL, MP_BADARG);
+
+ if((res = mw_mp_init(&s)) != MP_OKAY)
+ return res;
+ if((res = mw_mp_init_copy(&x, a)) != MP_OKAY)
+ goto X;
+
+ DIGIT(&s, 0) = 1;
+
+ if((d % 2) == 1)
+ cs = SIGN(a);
+
+ while(d != 0) {
+ if(d & 1) {
+ if((res = s_mw_mp_mul(&s, &x)) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ d >>= 1;
+
+ if((res = s_mw_mp_sqr(&x)) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ SIGN(&s) = cs;
+
+ s_mw_mp_exch(&s, c);
+
+CLEANUP:
+ mw_mp_clear(&x);
+X:
+ mw_mp_clear(&s);
+
+ return res;
+
+} /* end mw_mp_expt_d() */
+
+/* }}} */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ Full arithmetic */
+
+/* {{{ mw_mp_abs(a, b) */
+
+/*
+ mw_mp_abs(a, b)
+
+ Compute b = |a|. 'a' and 'b' may be identical.
+ */
+
+mw_mp_err mw_mp_abs(mw_mp_int *a, mw_mp_int *b)
+{
+ mw_mp_err res;
+
+ ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+ if((res = mw_mp_copy(a, b)) != MP_OKAY)
+ return res;
+
+ SIGN(b) = MP_ZPOS;
+
+ return MP_OKAY;
+
+} /* end mw_mp_abs() */
+
+/* }}} */
+
+/* {{{ mw_mp_neg(a, b) */
+
+/*
+ mw_mp_neg(a, b)
+
+ Compute b = -a. 'a' and 'b' may be identical.
+ */
+
+mw_mp_err mw_mp_neg(mw_mp_int *a, mw_mp_int *b)
+{
+ mw_mp_err res;
+
+ ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+ if((res = mw_mp_copy(a, b)) != MP_OKAY)
+ return res;
+
+ if(s_mw_mp_cmw_mp_d(b, 0) == MP_EQ)
+ SIGN(b) = MP_ZPOS;
+ else
+ SIGN(b) = (SIGN(b) == MP_NEG) ? MP_ZPOS : MP_NEG;
+
+ return MP_OKAY;
+
+} /* end mw_mp_neg() */
+
+/* }}} */
+
+/* {{{ mw_mp_add(a, b, c) */
+
+/*
+ mw_mp_add(a, b, c)
+
+ Compute c = a + b. All parameters may be identical.
+ */
+
+mw_mp_err mw_mp_add(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c)
+{
+ mw_mp_err res;
+ int cmp;
+
+ ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+ if(SIGN(a) == SIGN(b)) { /* same sign: add values, keep sign */
+
+ /* Commutativity of addition lets us do this in either order,
+ so we avoid having to use a temporary even if the result
+ is supposed to replace the output
+ */
+ if(c == b) {
+ if((res = s_mw_mp_add(c, a)) != MP_OKAY)
+ return res;
+ } else {
+ if(c != a && (res = mw_mp_copy(a, c)) != MP_OKAY)
+ return res;
+
+ if((res = s_mw_mp_add(c, b)) != MP_OKAY)
+ return res;
+ }
+
+ } else if((cmp = s_mw_mp_cmp(a, b)) > 0) { /* different sign: a > b */
+
+ /* If the output is going to be clobbered, we will use a temporary
+ variable; otherwise, we'll do it without touching the memory
+ allocator at all, if possible
+ */
+ if(c == b) {
+ mw_mp_int tmp;
+
+ if((res = mw_mp_init_copy(&tmp, a)) != MP_OKAY)
+ return res;
+ if((res = s_mw_mp_sub(&tmp, b)) != MP_OKAY) {
+ mw_mp_clear(&tmp);
+ return res;
+ }
+
+ s_mw_mp_exch(&tmp, c);
+ mw_mp_clear(&tmp);
+
+ } else {
+
+ if(c != a && (res = mw_mp_copy(a, c)) != MP_OKAY)
+ return res;
+ if((res = s_mw_mp_sub(c, b)) != MP_OKAY)
+ return res;
+
+ }
+
+ } else if(cmp == 0) { /* different sign, a == b */
+
+ mw_mp_zero(c);
+ return MP_OKAY;
+
+ } else { /* different sign: a < b */
+
+ /* See above... */
+ if(c == a) {
+ mw_mp_int tmp;
+
+ if((res = mw_mp_init_copy(&tmp, b)) != MP_OKAY)
+ return res;
+ if((res = s_mw_mp_sub(&tmp, a)) != MP_OKAY) {
+ mw_mp_clear(&tmp);
+ return res;
+ }
+
+ s_mw_mp_exch(&tmp, c);
+ mw_mp_clear(&tmp);
+
+ } else {
+
+ if(c != b && (res = mw_mp_copy(b, c)) != MP_OKAY)
+ return res;
+ if((res = s_mw_mp_sub(c, a)) != MP_OKAY)
+ return res;
+
+ }
+ }
+
+ if(USED(c) == 1 && DIGIT(c, 0) == 0)
+ SIGN(c) = MP_ZPOS;
+
+ return MP_OKAY;
+
+} /* end mw_mp_add() */
+
+/* }}} */
+
+/* {{{ mw_mp_sub(a, b, c) */
+
+/*
+ mw_mp_sub(a, b, c)
+
+ Compute c = a - b. All parameters may be identical.
+ */
+
+mw_mp_err mw_mp_sub(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c)
+{
+ mw_mp_err res;
+ int cmp;
+
+ ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+ if(SIGN(a) != SIGN(b)) {
+ if(c == a) {
+ if((res = s_mw_mp_add(c, b)) != MP_OKAY)
+ return res;
+ } else {
+ if(c != b && ((res = mw_mp_copy(b, c)) != MP_OKAY))
+ return res;
+ if((res = s_mw_mp_add(c, a)) != MP_OKAY)
+ return res;
+ SIGN(c) = SIGN(a);
+ }
+
+ } else if((cmp = s_mw_mp_cmp(a, b)) > 0) { /* Same sign, a > b */
+ if(c == b) {
+ mw_mp_int tmp;
+
+ if((res = mw_mp_init_copy(&tmp, a)) != MP_OKAY)
+ return res;
+ if((res = s_mw_mp_sub(&tmp, b)) != MP_OKAY) {
+ mw_mp_clear(&tmp);
+ return res;
+ }
+ s_mw_mp_exch(&tmp, c);
+ mw_mp_clear(&tmp);
+
+ } else {
+ if(c != a && ((res = mw_mp_copy(a, c)) != MP_OKAY))
+ return res;
+
+ if((res = s_mw_mp_sub(c, b)) != MP_OKAY)
+ return res;
+ }
+
+ } else if(cmp == 0) { /* Same sign, equal magnitude */
+ mw_mp_zero(c);
+ return MP_OKAY;
+
+ } else { /* Same sign, b > a */
+ if(c == a) {
+ mw_mp_int tmp;
+
+ if((res = mw_mp_init_copy(&tmp, b)) != MP_OKAY)
+ return res;
+
+ if((res = s_mw_mp_sub(&tmp, a)) != MP_OKAY) {
+ mw_mp_clear(&tmp);
+ return res;
+ }
+ s_mw_mp_exch(&tmp, c);
+ mw_mp_clear(&tmp);
+
+ } else {
+ if(c != b && ((res = mw_mp_copy(b, c)) != MP_OKAY))
+ return res;
+
+ if((res = s_mw_mp_sub(c, a)) != MP_OKAY)
+ return res;
+ }
+
+ SIGN(c) = !SIGN(b);
+ }
+
+ if(USED(c) == 1 && DIGIT(c, 0) == 0)
+ SIGN(c) = MP_ZPOS;
+
+ return MP_OKAY;
+
+} /* end mw_mp_sub() */
+
+/* }}} */
+
+/* {{{ mw_mp_mul(a, b, c) */
+
+/*
+ mw_mp_mul(a, b, c)
+
+ Compute c = a * b. All parameters may be identical.
+ */
+
+mw_mp_err mw_mp_mul(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c)
+{
+ mw_mp_err res;
+ mw_mp_sign sgn;
+
+ ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+ sgn = (SIGN(a) == SIGN(b)) ? MP_ZPOS : MP_NEG;
+
+ if(c == b) {
+ if((res = s_mw_mp_mul(c, a)) != MP_OKAY)
+ return res;
+
+ } else {
+ if((res = mw_mp_copy(a, c)) != MP_OKAY)
+ return res;
+
+ if((res = s_mw_mp_mul(c, b)) != MP_OKAY)
+ return res;
+ }
+
+ if(sgn == MP_ZPOS || s_mw_mp_cmw_mp_d(c, 0) == MP_EQ)
+ SIGN(c) = MP_ZPOS;
+ else
+ SIGN(c) = sgn;
+
+ return MP_OKAY;
+
+} /* end mw_mp_mul() */
+
+/* }}} */
+
+/* {{{ mw_mp_mul_2d(a, d, c) */
+
+/*
+ mw_mp_mul_2d(a, d, c)
+
+ Compute c = a * 2^d. a may be the same as c.
+ */
+
+mw_mp_err mw_mp_mul_2d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *c)
+{
+ mw_mp_err res;
+
+ ARGCHK(a != NULL && c != NULL, MP_BADARG);
+
+ if((res = mw_mp_copy(a, c)) != MP_OKAY)
+ return res;
+
+ if(d == 0)
+ return MP_OKAY;
+
+ return s_mw_mp_mul_2d(c, d);
+
+} /* end mw_mp_mul() */
+
+/* }}} */
+
+/* {{{ mw_mp_sqr(a, b) */
+
+#if MP_SQUARE
+mw_mp_err mw_mp_sqr(mw_mp_int *a, mw_mp_int *b)
+{
+ mw_mp_err res;
+
+ ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+ if((res = mw_mp_copy(a, b)) != MP_OKAY)
+ return res;
+
+ if((res = s_mw_mp_sqr(b)) != MP_OKAY)
+ return res;
+
+ SIGN(b) = MP_ZPOS;
+
+ return MP_OKAY;
+
+} /* end mw_mp_sqr() */
+#endif
+
+/* }}} */
+
+/* {{{ mw_mp_div(a, b, q, r) */
+
+/*
+ mw_mp_div(a, b, q, r)
+
+ Compute q = a / b and r = a mod b. Input parameters may be re-used
+ as output parameters. If q or r is NULL, that portion of the
+ computation will be discarded (although it will still be computed)
+
+ Pay no attention to the hacker behind the curtain.
+ */
+
+mw_mp_err mw_mp_div(mw_mp_int *a, mw_mp_int *b, mw_mp_int *q, mw_mp_int *r)
+{
+ mw_mp_err res;
+ mw_mp_int qtmp, rtmp;
+ int cmp;
+
+ ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+ if(mw_mp_cmw_mp_z(b) == MP_EQ)
+ return MP_RANGE;
+
+ /* If a <= b, we can compute the solution without division, and
+ avoid any memory allocation
+ */
+ if((cmp = s_mw_mp_cmp(a, b)) < 0) {
+ if(r) {
+ if((res = mw_mp_copy(a, r)) != MP_OKAY)
+ return res;
+ }
+
+ if(q)
+ mw_mp_zero(q);
+
+ return MP_OKAY;
+
+ } else if(cmp == 0) {
+
+ /* Set quotient to 1, with appropriate sign */
+ if(q) {
+ int qneg = (SIGN(a) != SIGN(b));
+
+ mw_mp_set(q, 1);
+ if(qneg)
+ SIGN(q) = MP_NEG;
+ }
+
+ if(r)
+ mw_mp_zero(r);
+
+ return MP_OKAY;
+ }
+
+ /* If we get here, it means we actually have to do some division */
+
+ /* Set up some temporaries... */
+ if((res = mw_mp_init_copy(&qtmp, a)) != MP_OKAY)
+ return res;
+ if((res = mw_mp_init_copy(&rtmp, b)) != MP_OKAY)
+ goto CLEANUP;
+
+ if((res = s_mw_mp_div(&qtmp, &rtmp)) != MP_OKAY)
+ goto CLEANUP;
+
+ /* Compute the signs for the output */
+ SIGN(&rtmp) = SIGN(a); /* Sr = Sa */
+ if(SIGN(a) == SIGN(b))
+ SIGN(&qtmp) = MP_ZPOS; /* Sq = MP_ZPOS if Sa = Sb */
+ else
+ SIGN(&qtmp) = MP_NEG; /* Sq = MP_NEG if Sa != Sb */
+
+ if(s_mw_mp_cmw_mp_d(&qtmp, 0) == MP_EQ)
+ SIGN(&qtmp) = MP_ZPOS;
+ if(s_mw_mp_cmw_mp_d(&rtmp, 0) == MP_EQ)
+ SIGN(&rtmp) = MP_ZPOS;
+
+ /* Copy output, if it is needed */
+ if(q)
+ s_mw_mp_exch(&qtmp, q);
+
+ if(r)
+ s_mw_mp_exch(&rtmp, r);
+
+CLEANUP:
+ mw_mp_clear(&rtmp);
+ mw_mp_clear(&qtmp);
+
+ return res;
+
+} /* end mw_mp_div() */
+
+/* }}} */
+
+/* {{{ mw_mp_div_2d(a, d, q, r) */
+
+mw_mp_err mw_mp_div_2d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *q, mw_mp_int *r)
+{
+ mw_mp_err res;
+
+ ARGCHK(a != NULL, MP_BADARG);
+
+ if(q) {
+ if((res = mw_mp_copy(a, q)) != MP_OKAY)
+ return res;
+
+ s_mw_mp_div_2d(q, d);
+ }
+
+ if(r) {
+ if((res = mw_mp_copy(a, r)) != MP_OKAY)
+ return res;
+
+ s_mw_mp_mod_2d(r, d);
+ }
+
+ return MP_OKAY;
+
+} /* end mw_mp_div_2d() */
+
+/* }}} */
+
+/* {{{ mw_mp_expt(a, b, c) */
+
+/*
+ mw_mp_expt(a, b, c)
+
+ Compute c = a ** b, that is, raise a to the b power. Uses a
+ standard iterative square-and-multiply technique.
+ */
+
+mw_mp_err mw_mp_expt(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c)
+{
+ mw_mp_int s, x;
+ mw_mp_err res;
+ mw_mp_digit d;
+
+ /// Miranda NG adaptation start - MSVC
+ ///int dig, bit;
+ int bit;
+ mw_mp_size dig;
+ /// Miranda NG adaptation end
+
+ ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+ if(mw_mp_cmw_mp_z(b) < 0)
+ return MP_RANGE;
+
+ if((res = mw_mp_init(&s)) != MP_OKAY)
+ return res;
+
+ mw_mp_set(&s, 1);
+
+ if((res = mw_mp_init_copy(&x, a)) != MP_OKAY)
+ goto X;
+
+ /* Loop over low-order digits in ascending order */
+ for(dig = 0; dig < (USED(b) - 1); dig++) {
+ d = DIGIT(b, dig);
+
+ /* Loop over bits of each non-maximal digit */
+ for(bit = 0; bit < DIGIT_BIT; bit++) {
+ if(d & 1) {
+ if((res = s_mw_mp_mul(&s, &x)) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ d >>= 1;
+
+ if((res = s_mw_mp_sqr(&x)) != MP_OKAY)
+ goto CLEANUP;
+ }
+ }
+
+ /* Consider now the last digit... */
+ d = DIGIT(b, dig);
+
+ while(d) {
+ if(d & 1) {
+ if((res = s_mw_mp_mul(&s, &x)) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ d >>= 1;
+
+ if((res = s_mw_mp_sqr(&x)) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ if(mw_mp_iseven(b))
+ SIGN(&s) = SIGN(a);
+
+ res = mw_mp_copy(&s, c);
+
+CLEANUP:
+ mw_mp_clear(&x);
+X:
+ mw_mp_clear(&s);
+
+ return res;
+
+} /* end mw_mp_expt() */
+
+/* }}} */
+
+/* {{{ mw_mp_2expt(a, k) */
+
+/* Compute a = 2^k */
+
+mw_mp_err mw_mp_2expt(mw_mp_int *a, mw_mp_digit k)
+{
+ ARGCHK(a != NULL, MP_BADARG);
+
+ return s_mw_mp_2expt(a, k);
+
+} /* end mw_mp_2expt() */
+
+/* }}} */
+
+/* {{{ mw_mp_mod(a, m, c) */
+
+/*
+ mw_mp_mod(a, m, c)
+
+ Compute c = a (mod m). Result will always be 0 <= c < m.
+ */
+
+mw_mp_err mw_mp_mod(mw_mp_int *a, mw_mp_int *m, mw_mp_int *c)
+{
+ mw_mp_err res;
+ int mag;
+
+ ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG);
+
+ if(SIGN(m) == MP_NEG)
+ return MP_RANGE;
+
+ /*
+ If |a| > m, we need to divide to get the remainder and take the
+ absolute value.
+
+ If |a| < m, we don't need to do any division, just copy and adjust
+ the sign (if a is negative).
+
+ If |a| == m, we can simply set the result to zero.
+
+ This order is intended to minimize the average path length of the
+ comparison chain on common workloads -- the most frequent cases are
+ that |a| != m, so we do those first.
+ */
+ if((mag = s_mw_mp_cmp(a, m)) > 0) {
+ if((res = mw_mp_div(a, m, NULL, c)) != MP_OKAY)
+ return res;
+
+ if(SIGN(c) == MP_NEG) {
+ if((res = mw_mp_add(c, m, c)) != MP_OKAY)
+ return res;
+ }
+
+ } else if(mag < 0) {
+ if((res = mw_mp_copy(a, c)) != MP_OKAY)
+ return res;
+
+ if(mw_mp_cmw_mp_z(a) < 0) {
+ if((res = mw_mp_add(c, m, c)) != MP_OKAY)
+ return res;
+
+ }
+
+ } else {
+ mw_mp_zero(c);
+
+ }
+
+ return MP_OKAY;
+
+} /* end mw_mp_mod() */
+
+/* }}} */
+
+/* {{{ mw_mp_mod_d(a, d, c) */
+
+/*
+ mw_mp_mod_d(a, d, c)
+
+ Compute c = a (mod d). Result will always be 0 <= c < d
+ */
+mw_mp_err mw_mp_mod_d(mw_mp_int *a, mw_mp_digit d, mw_mp_digit *c)
+{
+ mw_mp_err res;
+ mw_mp_digit rem;
+
+ ARGCHK(a != NULL && c != NULL, MP_BADARG);
+
+ if(s_mw_mp_cmw_mp_d(a, d) > 0) {
+ if((res = mw_mp_div_d(a, d, NULL, &rem)) != MP_OKAY)
+ return res;
+
+ } else {
+ if(SIGN(a) == MP_NEG)
+ rem = d - DIGIT(a, 0);
+ else
+ rem = DIGIT(a, 0);
+ }
+
+ if(c)
+ *c = rem;
+
+ return MP_OKAY;
+
+} /* end mw_mp_mod_d() */
+
+/* }}} */
+
+/* {{{ mw_mp_sqrt(a, b) */
+
+/*
+ mw_mp_sqrt(a, b)
+
+ Compute the integer square root of a, and store the result in b.
+ Uses an integer-arithmetic version of Newton's iterative linear
+ approximation technique to determine this value; the result has the
+ following two properties:
+
+ b^2 <= a
+ (b+1)^2 >= a
+
+ It is a range error to pass a negative value.
+ */
+mw_mp_err mw_mp_sqrt(mw_mp_int *a, mw_mp_int *b)
+{
+ mw_mp_int x, t;
+ mw_mp_err res;
+
+ ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+ /* Cannot take square root of a negative value */
+ if(SIGN(a) == MP_NEG)
+ return MP_RANGE;
+
+ /* Special cases for zero and one, trivial */
+ if(mw_mp_cmw_mp_d(a, 0) == MP_EQ || mw_mp_cmw_mp_d(a, 1) == MP_EQ)
+ return mw_mp_copy(a, b);
+
+ /* Initialize the temporaries we'll use below */
+ if((res = mw_mp_init_size(&t, USED(a))) != MP_OKAY)
+ return res;
+
+ /* Compute an initial guess for the iteration as a itself */
+ if((res = mw_mp_init_copy(&x, a)) != MP_OKAY)
+ goto X;
+
+ for(;;) {
+ /* t = (x * x) - a */
+ mw_mp_copy(&x, &t); /* can't fail, t is big enough for original x */
+ if((res = mw_mp_sqr(&t, &t)) != MP_OKAY ||
+ (res = mw_mp_sub(&t, a, &t)) != MP_OKAY)
+ goto CLEANUP;
+
+ /* t = t / 2x */
+ s_mw_mp_mul_2(&x);
+ if((res = mw_mp_div(&t, &x, &t, NULL)) != MP_OKAY)
+ goto CLEANUP;
+ s_mw_mp_div_2(&x);
+
+ /* Terminate the loop, if the quotient is zero */
+ if(mw_mp_cmw_mp_z(&t) == MP_EQ)
+ break;
+
+ /* x = x - t */
+ if((res = mw_mp_sub(&x, &t, &x)) != MP_OKAY)
+ goto CLEANUP;
+
+ }
+
+ /* Copy result to output parameter */
+ mw_mp_sub_d(&x, 1, &x);
+ s_mw_mp_exch(&x, b);
+
+ CLEANUP:
+ mw_mp_clear(&x);
+ X:
+ mw_mp_clear(&t);
+
+ return res;
+
+} /* end mw_mp_sqrt() */
+
+/* }}} */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ Modular arithmetic */
+
+#if MP_MODARITH
+/* {{{ mw_mp_addmod(a, b, m, c) */
+
+/*
+ mw_mp_addmod(a, b, m, c)
+
+ Compute c = (a + b) mod m
+ */
+
+mw_mp_err mw_mp_addmod(mw_mp_int *a, mw_mp_int *b, mw_mp_int *m, mw_mp_int *c)
+{
+ mw_mp_err res;
+
+ ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
+
+ if((res = mw_mp_add(a, b, c)) != MP_OKAY)
+ return res;
+ if((res = mw_mp_mod(c, m, c)) != MP_OKAY)
+ return res;
+
+ return MP_OKAY;
+
+}
+
+/* }}} */
+
+/* {{{ mw_mp_submod(a, b, m, c) */
+
+/*
+ mw_mp_submod(a, b, m, c)
+
+ Compute c = (a - b) mod m
+ */
+
+mw_mp_err mw_mp_submod(mw_mp_int *a, mw_mp_int *b, mw_mp_int *m, mw_mp_int *c)
+{
+ mw_mp_err res;
+
+ ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
+
+ if((res = mw_mp_sub(a, b, c)) != MP_OKAY)
+ return res;
+ if((res = mw_mp_mod(c, m, c)) != MP_OKAY)
+ return res;
+
+ return MP_OKAY;
+
+}
+
+/* }}} */
+
+/* {{{ mw_mp_mulmod(a, b, m, c) */
+
+/*
+ mw_mp_mulmod(a, b, m, c)
+
+ Compute c = (a * b) mod m
+ */
+
+mw_mp_err mw_mp_mulmod(mw_mp_int *a, mw_mp_int *b, mw_mp_int *m, mw_mp_int *c)
+{
+ mw_mp_err res;
+
+ ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
+
+ if((res = mw_mp_mul(a, b, c)) != MP_OKAY)
+ return res;
+ if((res = mw_mp_mod(c, m, c)) != MP_OKAY)
+ return res;
+
+ return MP_OKAY;
+
+}
+
+/* }}} */
+
+/* {{{ mw_mp_sqrmod(a, m, c) */
+
+#if MP_SQUARE
+mw_mp_err mw_mp_sqrmod(mw_mp_int *a, mw_mp_int *m, mw_mp_int *c)
+{
+ mw_mp_err res;
+
+ ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG);
+
+ if((res = mw_mp_sqr(a, c)) != MP_OKAY)
+ return res;
+ if((res = mw_mp_mod(c, m, c)) != MP_OKAY)
+ return res;
+
+ return MP_OKAY;
+
+} /* end mw_mp_sqrmod() */
+#endif
+
+/* }}} */
+
+/* {{{ mw_mp_exptmod(a, b, m, c) */
+
+/*
+ mw_mp_exptmod(a, b, m, c)
+
+ Compute c = (a ** b) mod m. Uses a standard square-and-multiply
+ method with modular reductions at each step. (This is basically the
+ same code as mw_mp_expt(), except for the addition of the reductions)
+
+ The modular reductions are done using Barrett's algorithm (see
+ s_mw_mp_reduce() below for details)
+ */
+
+mw_mp_err mw_mp_exptmod(mw_mp_int *a, mw_mp_int *b, mw_mp_int *m, mw_mp_int *c)
+{
+ mw_mp_int s, x, mu;
+ mw_mp_err res;
+ mw_mp_digit d, *db = DIGITS(b);
+ mw_mp_size ub = USED(b);
+ /// Miranda NG adaptation start - MSVC
+ ///int dig, bit;
+ int bit;
+ mw_mp_size dig;
+ /// Miranda NG adaptation end
+
+ ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+ if(mw_mp_cmw_mp_z(b) < 0 || mw_mp_cmw_mp_z(m) <= 0)
+ return MP_RANGE;
+
+ if((res = mw_mp_init(&s)) != MP_OKAY)
+ return res;
+ if((res = mw_mp_init_copy(&x, a)) != MP_OKAY)
+ goto X;
+ if((res = mw_mp_mod(&x, m, &x)) != MP_OKAY ||
+ (res = mw_mp_init(&mu)) != MP_OKAY)
+ goto MU;
+
+ mw_mp_set(&s, 1);
+
+ /* mu = b^2k / m */
+ s_mw_mp_add_d(&mu, 1);
+ s_mw_mp_lshd(&mu, 2 * USED(m));
+ if((res = mw_mp_div(&mu, m, &mu, NULL)) != MP_OKAY)
+ goto CLEANUP;
+
+ /* Loop over digits of b in ascending order, except highest order */
+ for(dig = 0; dig < (ub - 1); dig++) {
+ d = *db++;
+
+ /* Loop over the bits of the lower-order digits */
+ for(bit = 0; bit < DIGIT_BIT; bit++) {
+ if(d & 1) {
+ if((res = s_mw_mp_mul(&s, &x)) != MP_OKAY)
+ goto CLEANUP;
+ if((res = s_mw_mp_reduce(&s, m, &mu)) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ d >>= 1;
+
+ if((res = s_mw_mp_sqr(&x)) != MP_OKAY)
+ goto CLEANUP;
+ if((res = s_mw_mp_reduce(&x, m, &mu)) != MP_OKAY)
+ goto CLEANUP;
+ }
+ }
+
+ /* Now do the last digit... */
+ d = *db;
+
+ while(d) {
+ if(d & 1) {
+ if((res = s_mw_mp_mul(&s, &x)) != MP_OKAY)
+ goto CLEANUP;
+ if((res = s_mw_mp_reduce(&s, m, &mu)) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ d >>= 1;
+
+ if((res = s_mw_mp_sqr(&x)) != MP_OKAY)
+ goto CLEANUP;
+ if((res = s_mw_mp_reduce(&x, m, &mu)) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ s_mw_mp_exch(&s, c);
+
+ CLEANUP:
+ mw_mp_clear(&mu);
+ MU:
+ mw_mp_clear(&x);
+ X:
+ mw_mp_clear(&s);
+
+ return res;
+
+} /* end mw_mp_exptmod() */
+
+/* }}} */
+
+/* {{{ mw_mp_exptmod_d(a, d, m, c) */
+
+mw_mp_err mw_mp_exptmod_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *m, mw_mp_int *c)
+{
+ mw_mp_int s, x;
+ mw_mp_err res;
+
+ ARGCHK(a != NULL && c != NULL, MP_BADARG);
+
+ if((res = mw_mp_init(&s)) != MP_OKAY)
+ return res;
+ if((res = mw_mp_init_copy(&x, a)) != MP_OKAY)
+ goto X;
+
+ mw_mp_set(&s, 1);
+
+ while(d != 0) {
+ if(d & 1) {
+ if((res = s_mw_mp_mul(&s, &x)) != MP_OKAY ||
+ (res = mw_mp_mod(&s, m, &s)) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ d /= 2;
+
+ if((res = s_mw_mp_sqr(&x)) != MP_OKAY ||
+ (res = mw_mp_mod(&x, m, &x)) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ s_mw_mp_exch(&s, c);
+
+CLEANUP:
+ mw_mp_clear(&x);
+X:
+ mw_mp_clear(&s);
+
+ return res;
+
+} /* end mw_mp_exptmod_d() */
+
+/* }}} */
+#endif /* if MP_MODARITH */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ Comparison functions */
+
+/* {{{ mw_mp_cmw_mp_z(a) */
+
+/*
+ mw_mp_cmw_mp_z(a)
+
+ Compare a <=> 0. Returns <0 if a<0, 0 if a=0, >0 if a>0.
+ */
+
+int mw_mp_cmw_mp_z(mw_mp_int *a)
+{
+ if(SIGN(a) == MP_NEG)
+ return MP_LT;
+ else if(USED(a) == 1 && DIGIT(a, 0) == 0)
+ return MP_EQ;
+ else
+ return MP_GT;
+
+} /* end mw_mp_cmw_mp_z() */
+
+/* }}} */
+
+/* {{{ mw_mp_cmw_mp_d(a, d) */
+
+/*
+ mw_mp_cmw_mp_d(a, d)
+
+ Compare a <=> d. Returns <0 if a<d, 0 if a=d, >0 if a>d
+ */
+
+int mw_mp_cmw_mp_d(mw_mp_int *a, mw_mp_digit d)
+{
+ ARGCHK(a != NULL, MP_EQ);
+
+ if(SIGN(a) == MP_NEG)
+ return MP_LT;
+
+ return s_mw_mp_cmw_mp_d(a, d);
+
+} /* end mw_mp_cmw_mp_d() */
+
+/* }}} */
+
+/* {{{ mw_mp_cmp(a, b) */
+
+int mw_mp_cmp(mw_mp_int *a, mw_mp_int *b)
+{
+ ARGCHK(a != NULL && b != NULL, MP_EQ);
+
+ if(SIGN(a) == SIGN(b)) {
+ int mag;
+
+ if((mag = s_mw_mp_cmp(a, b)) == MP_EQ)
+ return MP_EQ;
+
+ if(SIGN(a) == MP_ZPOS)
+ return mag;
+ else
+ return -mag;
+
+ } else if(SIGN(a) == MP_ZPOS) {
+ return MP_GT;
+ } else {
+ return MP_LT;
+ }
+
+} /* end mw_mp_cmp() */
+
+/* }}} */
+
+/* {{{ mw_mp_cmw_mp_mag(a, b) */
+
+/*
+ mw_mp_cmw_mp_mag(a, b)
+
+ Compares |a| <=> |b|, and returns an appropriate comparison result
+ */
+
+int mw_mp_cmw_mp_mag(mw_mp_int *a, mw_mp_int *b)
+{
+ ARGCHK(a != NULL && b != NULL, MP_EQ);
+
+ return s_mw_mp_cmp(a, b);
+
+} /* end mw_mp_cmw_mp_mag() */
+
+/* }}} */
+
+/* {{{ mw_mp_cmw_mp_int(a, z) */
+
+/*
+ This just converts z to an mw_mp_int, and uses the existing comparison
+ routines. This is sort of inefficient, but it's not clear to me how
+ frequently this wil get used anyway. For small positive constants,
+ you can always use mw_mp_cmw_mp_d(), and for zero, there is mw_mp_cmw_mp_z().
+ */
+int mw_mp_cmw_mp_int(mw_mp_int *a, long z)
+{
+ mw_mp_int tmp;
+ int out;
+
+ ARGCHK(a != NULL, MP_EQ);
+
+ mw_mp_init(&tmp); mw_mp_set_int(&tmp, z);
+ out = mw_mp_cmp(a, &tmp);
+ mw_mp_clear(&tmp);
+
+ return out;
+
+} /* end mw_mp_cmw_mp_int() */
+
+/* }}} */
+
+/* {{{ mw_mp_isodd(a) */
+
+/*
+ mw_mp_isodd(a)
+
+ Returns a true (non-zero) value if a is odd, false (zero) otherwise.
+ */
+int mw_mp_isodd(mw_mp_int *a)
+{
+ ARGCHK(a != NULL, 0);
+
+ return (DIGIT(a, 0) & 1);
+
+} /* end mw_mp_isodd() */
+
+/* }}} */
+
+/* {{{ mw_mp_iseven(a) */
+
+int mw_mp_iseven(mw_mp_int *a)
+{
+ return !mw_mp_isodd(a);
+
+} /* end mw_mp_iseven() */
+
+/* }}} */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ Number theoretic functions */
+
+#if MP_NUMTH
+/* {{{ mw_mp_gcd(a, b, c) */
+
+/*
+ Like the old mw_mp_gcd() function, except computes the GCD using the
+ binary algorithm due to Josef Stein in 1961 (via Knuth).
+ */
+mw_mp_err mw_mp_gcd(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c)
+{
+ mw_mp_err res;
+ mw_mp_int u, v, t;
+ mw_mp_size k = 0;
+
+ ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+ if(mw_mp_cmw_mp_z(a) == MP_EQ && mw_mp_cmw_mp_z(b) == MP_EQ)
+ return MP_RANGE;
+ if(mw_mp_cmw_mp_z(a) == MP_EQ) {
+ if((res = mw_mp_copy(b, c)) != MP_OKAY)
+ return res;
+ SIGN(c) = MP_ZPOS; return MP_OKAY;
+ } else if(mw_mp_cmw_mp_z(b) == MP_EQ) {
+ if((res = mw_mp_copy(a, c)) != MP_OKAY)
+ return res;
+ SIGN(c) = MP_ZPOS; return MP_OKAY;
+ }
+
+ if((res = mw_mp_init(&t)) != MP_OKAY)
+ return res;
+ if((res = mw_mp_init_copy(&u, a)) != MP_OKAY)
+ goto U;
+ if((res = mw_mp_init_copy(&v, b)) != MP_OKAY)
+ goto V;
+
+ SIGN(&u) = MP_ZPOS;
+ SIGN(&v) = MP_ZPOS;
+
+ /* Divide out common factors of 2 until at least 1 of a, b is even */
+ while(mw_mp_iseven(&u) && mw_mp_iseven(&v)) {
+ s_mw_mp_div_2(&u);
+ s_mw_mp_div_2(&v);
+ ++k;
+ }
+
+ /* Initialize t */
+ if(mw_mp_isodd(&u)) {
+ if((res = mw_mp_copy(&v, &t)) != MP_OKAY)
+ goto CLEANUP;
+
+ /* t = -v */
+ if(SIGN(&v) == MP_ZPOS)
+ SIGN(&t) = MP_NEG;
+ else
+ SIGN(&t) = MP_ZPOS;
+
+ } else {
+ if((res = mw_mp_copy(&u, &t)) != MP_OKAY)
+ goto CLEANUP;
+
+ }
+
+ for(;;) {
+ while(mw_mp_iseven(&t)) {
+ s_mw_mp_div_2(&t);
+ }
+
+ if(mw_mp_cmw_mp_z(&t) == MP_GT) {
+ if((res = mw_mp_copy(&t, &u)) != MP_OKAY)
+ goto CLEANUP;
+
+ } else {
+ if((res = mw_mp_copy(&t, &v)) != MP_OKAY)
+ goto CLEANUP;
+
+ /* v = -t */
+ if(SIGN(&t) == MP_ZPOS)
+ SIGN(&v) = MP_NEG;
+ else
+ SIGN(&v) = MP_ZPOS;
+ }
+
+ if((res = mw_mp_sub(&u, &v, &t)) != MP_OKAY)
+ goto CLEANUP;
+
+ if(s_mw_mp_cmw_mp_d(&t, 0) == MP_EQ)
+ break;
+ }
+
+ s_mw_mp_2expt(&v, k); /* v = 2^k */
+ res = mw_mp_mul(&u, &v, c); /* c = u * v */
+
+ CLEANUP:
+ mw_mp_clear(&v);
+ V:
+ mw_mp_clear(&u);
+ U:
+ mw_mp_clear(&t);
+
+ return res;
+
+} /* end mw_mp_bgcd() */
+
+/* }}} */
+
+/* {{{ mw_mp_lcm(a, b, c) */
+
+/* We compute the least common multiple using the rule:
+
+ ab = [a, b](a, b)
+
+ ... by computing the product, and dividing out the gcd.
+ */
+
+mw_mp_err mw_mp_lcm(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c)
+{
+ mw_mp_int gcd, prod;
+ mw_mp_err res;
+
+ ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+ /* Set up temporaries */
+ if((res = mw_mp_init(&gcd)) != MP_OKAY)
+ return res;
+ if((res = mw_mp_init(&prod)) != MP_OKAY)
+ goto GCD;
+
+ if((res = mw_mp_mul(a, b, &prod)) != MP_OKAY)
+ goto CLEANUP;
+ if((res = mw_mp_gcd(a, b, &gcd)) != MP_OKAY)
+ goto CLEANUP;
+
+ res = mw_mp_div(&prod, &gcd, c, NULL);
+
+ CLEANUP:
+ mw_mp_clear(&prod);
+ GCD:
+ mw_mp_clear(&gcd);
+
+ return res;
+
+} /* end mw_mp_lcm() */
+
+/* }}} */
+
+/* {{{ mw_mp_xgcd(a, b, g, x, y) */
+
+/*
+ mw_mp_xgcd(a, b, g, x, y)
+
+ Compute g = (a, b) and values x and y satisfying Bezout's identity
+ (that is, ax + by = g). This uses the extended binary GCD algorithm
+ based on the Stein algorithm used for mw_mp_gcd()
+ */
+
+mw_mp_err mw_mp_xgcd(mw_mp_int *a, mw_mp_int *b, mw_mp_int *g, mw_mp_int *x, mw_mp_int *y)
+{
+ mw_mp_int gx, xc, yc, u, v, A, B, C, D;
+ mw_mp_int *clean[9];
+ mw_mp_err res;
+ int last = -1;
+
+ if(mw_mp_cmw_mp_z(b) == 0)
+ return MP_RANGE;
+
+ /* Initialize all these variables we need */
+ if((res = mw_mp_init(&u)) != MP_OKAY) goto CLEANUP;
+ clean[++last] = &u;
+ if((res = mw_mp_init(&v)) != MP_OKAY) goto CLEANUP;
+ clean[++last] = &v;
+ if((res = mw_mp_init(&gx)) != MP_OKAY) goto CLEANUP;
+ clean[++last] = &gx;
+ if((res = mw_mp_init(&A)) != MP_OKAY) goto CLEANUP;
+ clean[++last] = &A;
+ if((res = mw_mp_init(&B)) != MP_OKAY) goto CLEANUP;
+ clean[++last] = &B;
+ if((res = mw_mp_init(&C)) != MP_OKAY) goto CLEANUP;
+ clean[++last] = &C;
+ if((res = mw_mp_init(&D)) != MP_OKAY) goto CLEANUP;
+ clean[++last] = &D;
+ if((res = mw_mp_init_copy(&xc, a)) != MP_OKAY) goto CLEANUP;
+ clean[++last] = &xc;
+ mw_mp_abs(&xc, &xc);
+ if((res = mw_mp_init_copy(&yc, b)) != MP_OKAY) goto CLEANUP;
+ clean[++last] = &yc;
+ mw_mp_abs(&yc, &yc);
+
+ mw_mp_set(&gx, 1);
+
+ /* Divide by two until at least one of them is even */
+ while(mw_mp_iseven(&xc) && mw_mp_iseven(&yc)) {
+ s_mw_mp_div_2(&xc);
+ s_mw_mp_div_2(&yc);
+ if((res = s_mw_mp_mul_2(&gx)) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ mw_mp_copy(&xc, &u);
+ mw_mp_copy(&yc, &v);
+ mw_mp_set(&A, 1); mw_mp_set(&D, 1);
+
+ /* Loop through binary GCD algorithm */
+ for(;;) {
+ while(mw_mp_iseven(&u)) {
+ s_mw_mp_div_2(&u);
+
+ if(mw_mp_iseven(&A) && mw_mp_iseven(&B)) {
+ s_mw_mp_div_2(&A); s_mw_mp_div_2(&B);
+ } else {
+ if((res = mw_mp_add(&A, &yc, &A)) != MP_OKAY) goto CLEANUP;
+ s_mw_mp_div_2(&A);
+ if((res = mw_mp_sub(&B, &xc, &B)) != MP_OKAY) goto CLEANUP;
+ s_mw_mp_div_2(&B);
+ }
+ }
+
+ while(mw_mp_iseven(&v)) {
+ s_mw_mp_div_2(&v);
+
+ if(mw_mp_iseven(&C) && mw_mp_iseven(&D)) {
+ s_mw_mp_div_2(&C); s_mw_mp_div_2(&D);
+ } else {
+ if((res = mw_mp_add(&C, &yc, &C)) != MP_OKAY) goto CLEANUP;
+ s_mw_mp_div_2(&C);
+ if((res = mw_mp_sub(&D, &xc, &D)) != MP_OKAY) goto CLEANUP;
+ s_mw_mp_div_2(&D);
+ }
+ }
+
+ if(mw_mp_cmp(&u, &v) >= 0) {
+ if((res = mw_mp_sub(&u, &v, &u)) != MP_OKAY) goto CLEANUP;
+ if((res = mw_mp_sub(&A, &C, &A)) != MP_OKAY) goto CLEANUP;
+ if((res = mw_mp_sub(&B, &D, &B)) != MP_OKAY) goto CLEANUP;
+
+ } else {
+ if((res = mw_mp_sub(&v, &u, &v)) != MP_OKAY) goto CLEANUP;
+ if((res = mw_mp_sub(&C, &A, &C)) != MP_OKAY) goto CLEANUP;
+ if((res = mw_mp_sub(&D, &B, &D)) != MP_OKAY) goto CLEANUP;
+
+ }
+
+ /* If we're done, copy results to output */
+ if(mw_mp_cmw_mp_z(&u) == 0) {
+ if(x)
+ if((res = mw_mp_copy(&C, x)) != MP_OKAY) goto CLEANUP;
+
+ if(y)
+ if((res = mw_mp_copy(&D, y)) != MP_OKAY) goto CLEANUP;
+
+ if(g)
+ if((res = mw_mp_mul(&gx, &v, g)) != MP_OKAY) goto CLEANUP;
+
+ break;
+ }
+ }
+
+ CLEANUP:
+ while(last >= 0)
+ mw_mp_clear(clean[last--]);
+
+ return res;
+
+} /* end mw_mp_xgcd() */
+
+/* }}} */
+
+/* {{{ mw_mp_invmod(a, m, c) */
+
+/*
+ mw_mp_invmod(a, m, c)
+
+ Compute c = a^-1 (mod m), if there is an inverse for a (mod m).
+ This is equivalent to the question of whether (a, m) = 1. If not,
+ MP_UNDEF is returned, and there is no inverse.
+ */
+
+mw_mp_err mw_mp_invmod(mw_mp_int *a, mw_mp_int *m, mw_mp_int *c)
+{
+ mw_mp_int g, x;
+ mw_mp_sign sa;
+ mw_mp_err res;
+
+ ARGCHK(a && m && c, MP_BADARG);
+
+ if(mw_mp_cmw_mp_z(a) == 0 || mw_mp_cmw_mp_z(m) == 0)
+ return MP_RANGE;
+
+ sa = SIGN(a);
+
+ if((res = mw_mp_init(&g)) != MP_OKAY)
+ return res;
+ if((res = mw_mp_init(&x)) != MP_OKAY)
+ goto X;
+
+ if((res = mw_mp_xgcd(a, m, &g, &x, NULL)) != MP_OKAY)
+ goto CLEANUP;
+
+ if(mw_mp_cmw_mp_d(&g, 1) != MP_EQ) {
+ res = MP_UNDEF;
+ goto CLEANUP;
+ }
+
+ res = mw_mp_mod(&x, m, c);
+ SIGN(c) = sa;
+
+CLEANUP:
+ mw_mp_clear(&x);
+X:
+ mw_mp_clear(&g);
+
+ return res;
+
+} /* end mw_mp_invmod() */
+
+/* }}} */
+#endif /* if MP_NUMTH */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ mw_mp_print(mp, ofp) */
+
+#if MP_IOFUNC
+/*
+ mw_mp_print(mp, ofp)
+
+ Print a textual representation of the given mw_mp_int on the output
+ stream 'ofp'. Output is generated using the internal radix.
+ */
+
+void mw_mp_print(mw_mp_int *mp, FILE *ofp)
+{
+ int ix;
+
+ if(mp == NULL || ofp == NULL)
+ return;
+
+ fputc((SIGN(mp) == MP_NEG) ? '-' : '+', ofp);
+
+ for(ix = USED(mp) - 1; ix >= 0; ix--) {
+ fprintf(ofp, DIGIT_FMT, DIGIT(mp, ix));
+ }
+
+} /* end mw_mp_print() */
+
+#endif /* if MP_IOFUNC */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ More I/O Functions */
+
+/* {{{ mw_mp_read_signed_bin(mp, str, len) */
+
+/*
+ mw_mp_read_signed_bin(mp, str, len)
+
+ Read in a raw value (base 256) into the given mw_mp_int
+ */
+
+mw_mp_err mw_mp_read_signed_bin(mw_mp_int *mp, unsigned char *str, int len)
+{
+ mw_mp_err res;
+
+ ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG);
+
+ if((res = mw_mp_read_unsigned_bin(mp, str + 1, len - 1)) == MP_OKAY) {
+ /* Get sign from first byte */
+ if(str[0])
+ SIGN(mp) = MP_NEG;
+ else
+ SIGN(mp) = MP_ZPOS;
+ }
+
+ return res;
+
+} /* end mw_mp_read_signed_bin() */
+
+/* }}} */
+
+/* {{{ mw_mp_signed_bin_size(mp) */
+
+int mw_mp_signed_bin_size(mw_mp_int *mp)
+{
+ ARGCHK(mp != NULL, 0);
+
+ return mw_mp_unsigned_bin_size(mp) + 1;
+
+} /* end mw_mp_signed_bin_size() */
+
+/* }}} */
+
+/* {{{ mw_mp_to_signed_bin(mp, str) */
+
+mw_mp_err mw_mp_to_signed_bin(mw_mp_int *mp, unsigned char *str)
+{
+ ARGCHK(mp != NULL && str != NULL, MP_BADARG);
+
+ /* Caller responsible for allocating enough memory (use mw_mp_raw_size(mp)) */
+ str[0] = (char)SIGN(mp);
+
+ return mw_mp_to_unsigned_bin(mp, str + 1);
+
+} /* end mw_mp_to_signed_bin() */
+
+/* }}} */
+
+/* {{{ mw_mp_read_unsigned_bin(mp, str, len) */
+
+/*
+ mw_mp_read_unsigned_bin(mp, str, len)
+
+ Read in an unsigned value (base 256) into the given mw_mp_int
+ */
+
+mw_mp_err mw_mp_read_unsigned_bin(mw_mp_int *mp, unsigned char *str, int len)
+{
+ int ix;
+ mw_mp_err res;
+
+ ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG);
+
+ mw_mp_zero(mp);
+
+ for(ix = 0; ix < len; ix++) {
+ if((res = s_mw_mp_mul_2d(mp, CHAR_BIT)) != MP_OKAY)
+ return res;
+
+ if((res = mw_mp_add_d(mp, str[ix], mp)) != MP_OKAY)
+ return res;
+ }
+
+ return MP_OKAY;
+
+} /* end mw_mp_read_unsigned_bin() */
+
+/* }}} */
+
+/* {{{ mw_mp_unsigned_bin_size(mp) */
+
+int mw_mp_unsigned_bin_size(mw_mp_int *mp)
+{
+ mw_mp_digit topdig;
+ int count;
+
+ ARGCHK(mp != NULL, 0);
+
+ /* Special case for the value zero */
+ if(USED(mp) == 1 && DIGIT(mp, 0) == 0)
+ return 1;
+
+ count = (USED(mp) - 1) * sizeof(mw_mp_digit);
+ topdig = DIGIT(mp, USED(mp) - 1);
+
+ while(topdig != 0) {
+ ++count;
+ topdig >>= CHAR_BIT;
+ }
+
+ return count;
+
+} /* end mw_mp_unsigned_bin_size() */
+
+/* }}} */
+
+/* {{{ mw_mp_to_unsigned_bin(mp, str) */
+
+mw_mp_err mw_mp_to_unsigned_bin(mw_mp_int *mp, unsigned char *str)
+{
+ mw_mp_digit *dp, *end, d;
+ unsigned char *spos;
+
+ ARGCHK(mp != NULL && str != NULL, MP_BADARG);
+
+ dp = DIGITS(mp);
+ end = dp + USED(mp) - 1;
+ spos = str;
+
+ /* Special case for zero, quick test */
+ if(dp == end && *dp == 0) {
+ *str = '\0';
+ return MP_OKAY;
+ }
+
+ /* Generate digits in reverse order */
+ while(dp < end) {
+ int ix;
+
+ d = *dp;
+ for(ix = 0; ix < sizeof(mw_mp_digit); ++ix) {
+ *spos = d & UCHAR_MAX;
+ d >>= CHAR_BIT;
+ ++spos;
+ }
+
+ ++dp;
+ }
+
+ /* Now handle last digit specially, high order zeroes are not written */
+ d = *end;
+ while(d != 0) {
+ *spos = d & UCHAR_MAX;
+ d >>= CHAR_BIT;
+ ++spos;
+ }
+
+ /* Reverse everything to get digits in the correct order */
+ while(--spos > str) {
+ unsigned char t = *str;
+ *str = *spos;
+ *spos = t;
+
+ ++str;
+ }
+
+ return MP_OKAY;
+
+} /* end mw_mp_to_unsigned_bin() */
+
+/* }}} */
+
+/* {{{ mw_mp_count_bits(mp) */
+
+int mw_mp_count_bits(mw_mp_int *mp)
+{
+ int len;
+ mw_mp_digit d;
+
+ ARGCHK(mp != NULL, MP_BADARG);
+
+ len = DIGIT_BIT * (USED(mp) - 1);
+ d = DIGIT(mp, USED(mp) - 1);
+
+ while(d != 0) {
+ ++len;
+ d >>= 1;
+ }
+
+ return len;
+
+} /* end mw_mp_count_bits() */
+
+/* }}} */
+
+/* {{{ mw_mp_read_radix(mp, str, radix) */
+
+/*
+ mw_mp_read_radix(mp, str, radix)
+
+ Read an integer from the given string, and set mp to the resulting
+ value. The input is presumed to be in base 10. Leading non-digit
+ characters are ignored, and the function reads until a non-digit
+ character or the end of the string.
+ */
+
+mw_mp_err mw_mp_read_radix(mw_mp_int *mp, unsigned char *str, int radix)
+{
+ int ix = 0, val = 0;
+ mw_mp_err res;
+ mw_mp_sign sig = MP_ZPOS;
+
+ ARGCHK(mp != NULL && str != NULL && radix >= 2 && radix <= MAX_RADIX,
+ MP_BADARG);
+
+ mw_mp_zero(mp);
+
+ /* Skip leading non-digit characters until a digit or '-' or '+' */
+ while(str[ix] &&
+ (s_mw_mp_tovalue(str[ix], radix) < 0) &&
+ str[ix] != '-' &&
+ str[ix] != '+') {
+ ++ix;
+ }
+
+ if(str[ix] == '-') {
+ sig = MP_NEG;
+ ++ix;
+ } else if(str[ix] == '+') {
+ sig = MP_ZPOS; /* this is the default anyway... */
+ ++ix;
+ }
+
+ while((val = s_mw_mp_tovalue(str[ix], radix)) >= 0) {
+ if((res = s_mw_mp_mul_d(mp, radix)) != MP_OKAY)
+ return res;
+ if((res = s_mw_mp_add_d(mp, val)) != MP_OKAY)
+ return res;
+ ++ix;
+ }
+
+ if(s_mw_mp_cmw_mp_d(mp, 0) == MP_EQ)
+ SIGN(mp) = MP_ZPOS;
+ else
+ SIGN(mp) = sig;
+
+ return MP_OKAY;
+
+} /* end mw_mp_read_radix() */
+
+/* }}} */
+
+/* {{{ mw_mp_radix_size(mp, radix) */
+
+int mw_mp_radix_size(mw_mp_int *mp, int radix)
+{
+ int len;
+ ARGCHK(mp != NULL, 0);
+
+ len = s_mw_mp_outlen(mw_mp_count_bits(mp), radix) + 1; /* for NUL terminator */
+
+ if(mw_mp_cmw_mp_z(mp) < 0)
+ ++len; /* for sign */
+
+ return len;
+
+} /* end mw_mp_radix_size() */
+
+/* }}} */
+
+/* {{{ mw_mp_value_radix_size(num, qty, radix) */
+
+/* num = number of digits
+ qty = number of bits per digit
+ radix = target base
+
+ Return the number of digits in the specified radix that would be
+ needed to express 'num' digits of 'qty' bits each.
+ */
+int mw_mp_value_radix_size(int num, int qty, int radix)
+{
+ ARGCHK(num >= 0 && qty > 0 && radix >= 2 && radix <= MAX_RADIX, 0);
+
+ return s_mw_mp_outlen(num * qty, radix);
+
+} /* end mw_mp_value_radix_size() */
+
+/* }}} */
+
+/* {{{ mw_mp_toradix(mp, str, radix) */
+
+mw_mp_err mw_mp_toradix(mw_mp_int *mp, unsigned char *str, int radix)
+{
+ int ix, pos = 0;
+
+ ARGCHK(mp != NULL && str != NULL, MP_BADARG);
+ ARGCHK(radix > 1 && radix <= MAX_RADIX, MP_RANGE);
+
+ if(mw_mp_cmw_mp_z(mp) == MP_EQ) {
+ str[0] = '0';
+ str[1] = '\0';
+ } else {
+ mw_mp_err res;
+ mw_mp_int tmp;
+ mw_mp_sign sgn;
+ mw_mp_digit rem, rdx = (mw_mp_digit)radix;
+ char ch;
+
+ if((res = mw_mp_init_copy(&tmp, mp)) != MP_OKAY)
+ return res;
+
+ /* Save sign for later, and take absolute value */
+ sgn = SIGN(&tmp); SIGN(&tmp) = MP_ZPOS;
+
+ /* Generate output digits in reverse order */
+ while(mw_mp_cmw_mp_z(&tmp) != 0) {
+ if((res = s_mw_mp_div_d(&tmp, rdx, &rem)) != MP_OKAY) {
+ mw_mp_clear(&tmp);
+ return res;
+ }
+
+ /* Generate digits, use capital letters */
+ ch = s_mw_mp_todigit(rem, radix, 0);
+
+ str[pos++] = ch;
+ }
+
+ /* Add - sign if original value was negative */
+ if(sgn == MP_NEG)
+ str[pos++] = '-';
+
+ /* Add trailing NUL to end the string */
+ str[pos--] = '\0';
+
+ /* Reverse the digits and sign indicator */
+ ix = 0;
+ while(ix < pos) {
+ char tmp = str[ix];
+
+ str[ix] = str[pos];
+ str[pos] = tmp;
+ ++ix;
+ --pos;
+ }
+
+ mw_mp_clear(&tmp);
+ }
+
+ return MP_OKAY;
+
+} /* end mw_mp_toradix() */
+
+/* }}} */
+
+/* {{{ mw_mp_char2value(ch, r) */
+
+int mw_mp_char2value(char ch, int r)
+{
+ return s_mw_mp_tovalue(ch, r);
+
+} /* end mw_mp_tovalue() */
+
+/* }}} */
+
+/* }}} */
+
+/* {{{ mw_mp_strerror(ec) */
+
+/*
+ mw_mp_strerror(ec)
+
+ Return a string describing the meaning of error code 'ec'. The
+ string returned is allocated in static memory, so the caller should
+ not attempt to modify or free the memory associated with this
+ string.
+ */
+const char *mw_mp_strerror(mw_mp_err ec)
+{
+ int aec = (ec < 0) ? -ec : ec;
+
+ /* Code values are negative, so the senses of these comparisons
+ are accurate */
+ if(ec < MP_LAST_CODE || ec > MP_OKAY) {
+ return mw_mp_err_string[0]; /* unknown error code */
+ } else {
+ return mw_mp_err_string[aec + 1];
+ }
+
+} /* end mw_mp_strerror() */
+
+/* }}} */
+
+/*========================================================================*/
+/*------------------------------------------------------------------------*/
+/* Static function definitions (internal use only) */
+
+/* {{{ Memory management */
+
+/* {{{ s_mw_mp_grow(mp, min) */
+
+/* Make sure there are at least 'min' digits allocated to mp */
+mw_mp_err s_mw_mp_grow(mw_mp_int *mp, mw_mp_size min)
+{
+ if(min > ALLOC(mp)) {
+ mw_mp_digit *tmp;
+
+ /* Set min to next nearest default precision block size */
+ min = ((min + (s_mw_mp_defprec - 1)) / s_mw_mp_defprec) * s_mw_mp_defprec;
+
+ if((tmp = s_mw_mp_alloc(min, sizeof(mw_mp_digit))) == NULL)
+ return MP_MEM;
+
+ s_mw_mp_copy(DIGITS(mp), tmp, USED(mp));
+
+#if MP_CRYPTO
+ s_mw_mp_setz(DIGITS(mp), ALLOC(mp));
+#endif
+ s_mw_mp_free(DIGITS(mp));
+ DIGITS(mp) = tmp;
+ ALLOC(mp) = min;
+ }
+
+ return MP_OKAY;
+
+} /* end s_mw_mp_grow() */
+
+/* }}} */
+
+/* {{{ s_mw_mp_pad(mp, min) */
+
+/* Make sure the used size of mp is at least 'min', growing if needed */
+mw_mp_err s_mw_mp_pad(mw_mp_int *mp, mw_mp_size min)
+{
+ if(min > USED(mp)) {
+ mw_mp_err res;
+
+ /* Make sure there is room to increase precision */
+ if(min > ALLOC(mp) && (res = s_mw_mp_grow(mp, min)) != MP_OKAY)
+ return res;
+
+ /* Increase precision; should already be 0-filled */
+ USED(mp) = min;
+ }
+
+ return MP_OKAY;
+
+} /* end s_mw_mp_pad() */
+
+/* }}} */
+
+/* {{{ s_mw_mp_setz(dp, count) */
+
+#if MP_MACRO == 0
+/* Set 'count' digits pointed to by dp to be zeroes */
+void s_mw_mp_setz(mw_mp_digit *dp, mw_mp_size count)
+{
+#if MP_MEMSET == 0
+ int ix;
+
+ for(ix = 0; ix < count; ix++)
+ dp[ix] = 0;
+#else
+ memset(dp, 0, count * sizeof(mw_mp_digit));
+#endif
+
+} /* end s_mw_mp_setz() */
+#endif
+
+/* }}} */
+
+/* {{{ s_mw_mp_copy(sp, dp, count) */
+
+#if MP_MACRO == 0
+/* Copy 'count' digits from sp to dp */
+void s_mw_mp_copy(mw_mp_digit *sp, mw_mp_digit *dp, mw_mp_size count)
+{
+#if MP_MEMCPY == 0
+ int ix;
+
+ for(ix = 0; ix < count; ix++)
+ dp[ix] = sp[ix];
+#else
+ memcpy(dp, sp, count * sizeof(mw_mp_digit));
+#endif
+
+} /* end s_mw_mp_copy() */
+#endif
+
+/* }}} */
+
+/* {{{ s_mw_mp_alloc(nb, ni) */
+
+#if MP_MACRO == 0
+/* Allocate ni records of nb bytes each, and return a pointer to that */
+void *s_mw_mp_alloc(size_t nb, size_t ni)
+{
+ return calloc(nb, ni);
+
+} /* end s_mw_mp_alloc() */
+#endif
+
+/* }}} */
+
+/* {{{ s_mw_mp_free(ptr) */
+
+#if MP_MACRO == 0
+/* Free the memory pointed to by ptr */
+void s_mw_mp_free(void *ptr)
+{
+ if(ptr)
+ free(ptr);
+
+} /* end s_mw_mp_free() */
+#endif
+
+/* }}} */
+
+/* {{{ s_mw_mp_clamp(mp) */
+
+/* Remove leading zeroes from the given value */
+void s_mw_mp_clamp(mw_mp_int *mp)
+{
+ mw_mp_size du = USED(mp);
+ mw_mp_digit *zp = DIGITS(mp) + du - 1;
+
+ while(du > 1 && !*zp--)
+ --du;
+
+ if(du == 1 && *zp == 0)
+ SIGN(mp) = MP_ZPOS;
+
+ USED(mp) = du;
+
+} /* end s_mw_mp_clamp() */
+
+
+/* }}} */
+
+/* {{{ s_mw_mp_exch(a, b) */
+
+/* Exchange the data for a and b; (b, a) = (a, b) */
+void s_mw_mp_exch(mw_mp_int *a, mw_mp_int *b)
+{
+ mw_mp_int tmp;
+
+ tmp = *a;
+ *a = *b;
+ *b = tmp;
+
+} /* end s_mw_mp_exch() */
+
+/* }}} */
+
+/* }}} */
+
+/* {{{ Arithmetic helpers */
+
+/* {{{ s_mw_mp_lshd(mp, p) */
+
+/*
+ Shift mp leftward by p digits, growing if needed, and zero-filling
+ the in-shifted digits at the right end. This is a convenient
+ alternative to multiplication by powers of the radix
+ */
+
+mw_mp_err s_mw_mp_lshd(mw_mp_int *mp, mw_mp_size p)
+{
+ mw_mp_err res;
+ mw_mp_size pos;
+ mw_mp_digit *dp;
+ int ix;
+
+ if(p == 0)
+ return MP_OKAY;
+
+ if((res = s_mw_mp_pad(mp, USED(mp) + p)) != MP_OKAY)
+ return res;
+
+ pos = USED(mp) - 1;
+ dp = DIGITS(mp);
+
+ /* Shift all the significant figures over as needed */
+ /// Miranda NG adaptation start - MSVC
+ ///for(ix = pos - p; ix >= 0; ix--)
+ for(ix = (int)(pos - p); ix >= 0; ix--)
+ /// Miranda NG adaptation end
+ dp[ix + p] = dp[ix];
+
+ /* Fill the bottom digits with zeroes */
+ /// Miranda NG adaptation start - MSVC
+ ///for(ix = 0; ix < p; ix++)
+ for(ix = 0; ix < (int)p; ix++)
+ /// Miranda NG adaptation end
+ dp[ix] = 0;
+
+ return MP_OKAY;
+
+} /* end s_mw_mp_lshd() */
+
+/* }}} */
+
+/* {{{ s_mw_mp_rshd(mp, p) */
+
+/*
+ Shift mp rightward by p digits. Maintains the invariant that
+ digits above the precision are all zero. Digits shifted off the
+ end are lost. Cannot fail.
+ */
+
+void s_mw_mp_rshd(mw_mp_int *mp, mw_mp_size p)
+{
+ mw_mp_size ix;
+ mw_mp_digit *dp;
+
+ if(p == 0)
+ return;
+
+ /* Shortcut when all digits are to be shifted off */
+ if(p >= USED(mp)) {
+ s_mw_mp_setz(DIGITS(mp), ALLOC(mp));
+ USED(mp) = 1;
+ SIGN(mp) = MP_ZPOS;
+ return;
+ }
+
+ /* Shift all the significant figures over as needed */
+ dp = DIGITS(mp);
+ for(ix = p; ix < USED(mp); ix++)
+ dp[ix - p] = dp[ix];
+
+ /* Fill the top digits with zeroes */
+ ix -= p;
+ while(ix < USED(mp))
+ dp[ix++] = 0;
+
+ /* Strip off any leading zeroes */
+ s_mw_mp_clamp(mp);
+
+} /* end s_mw_mp_rshd() */
+
+/* }}} */
+
+/* {{{ s_mw_mp_div_2(mp) */
+
+/* Divide by two -- take advantage of radix properties to do it fast */
+void s_mw_mp_div_2(mw_mp_int *mp)
+{
+ s_mw_mp_div_2d(mp, 1);
+
+} /* end s_mw_mp_div_2() */
+
+/* }}} */
+
+/* {{{ s_mw_mp_mul_2(mp) */
+
+mw_mp_err s_mw_mp_mul_2(mw_mp_int *mp)
+{
+ /// Miranda NG adaptation start - MSVC
+ //int ix;
+ mw_mp_size ix;
+ /// Miranda NG adaptation end
+ mw_mp_digit kin = 0, kout, *dp = DIGITS(mp);
+ mw_mp_err res;
+
+ /* Shift digits leftward by 1 bit */
+ for(ix = 0; ix < USED(mp); ix++) {
+ kout = (dp[ix] >> (DIGIT_BIT - 1)) & 1;
+ dp[ix] = (dp[ix] << 1) | kin;
+
+ kin = kout;
+ }
+
+ /* Deal with rollover from last digit */
+ if(kin) {
+ if(ix >= ALLOC(mp)) {
+ if((res = s_mw_mp_grow(mp, ALLOC(mp) + 1)) != MP_OKAY)
+ return res;
+ dp = DIGITS(mp);
+ }
+
+ dp[ix] = kin;
+ USED(mp) += 1;
+ }
+
+ return MP_OKAY;
+
+} /* end s_mw_mp_mul_2() */
+
+/* }}} */
+
+/* {{{ s_mw_mp_mod_2d(mp, d) */
+
+/*
+ Remainder the integer by 2^d, where d is a number of bits. This
+ amounts to a bitwise AND of the value, and does not require the full
+ division code
+ */
+void s_mw_mp_mod_2d(mw_mp_int *mp, mw_mp_digit d)
+{
+ unsigned int ndig = (d / DIGIT_BIT), nbit = (d % DIGIT_BIT);
+ unsigned int ix;
+ mw_mp_digit dmask, *dp = DIGITS(mp);
+
+ if(ndig >= USED(mp))
+ return;
+
+ /* Flush all the bits above 2^d in its digit */
+ dmask = (1 << nbit) - 1;
+ dp[ndig] &= dmask;
+
+ /* Flush all digits above the one with 2^d in it */
+ for(ix = ndig + 1; ix < USED(mp); ix++)
+ dp[ix] = 0;
+
+ s_mw_mp_clamp(mp);
+
+} /* end s_mw_mp_mod_2d() */
+
+/* }}} */
+
+/* {{{ s_mw_mp_mul_2d(mp, d) */
+
+/*
+ Multiply by the integer 2^d, where d is a number of bits. This
+ amounts to a bitwise shift of the value, and does not require the
+ full multiplication code.
+ */
+mw_mp_err s_mw_mp_mul_2d(mw_mp_int *mp, mw_mp_digit d)
+{
+ mw_mp_err res;
+ mw_mp_digit save, next, mask, *dp;
+ mw_mp_size used;
+ /// Miranda NG adaptation start - MSVC
+ ///int ix;
+ mw_mp_size ix;
+ /// Miranda NG adaptation end
+
+ if((res = s_mw_mp_lshd(mp, d / DIGIT_BIT)) != MP_OKAY)
+ return res;
+
+ dp = DIGITS(mp); used = USED(mp);
+ d %= DIGIT_BIT;
+
+ mask = (1 << d) - 1;
+
+ /* If the shift requires another digit, make sure we've got one to
+ work with */
+ if((dp[used - 1] >> (DIGIT_BIT - d)) & mask) {
+ if((res = s_mw_mp_grow(mp, used + 1)) != MP_OKAY)
+ return res;
+ dp = DIGITS(mp);
+ }
+
+ /* Do the shifting... */
+ save = 0;
+ for(ix = 0; ix < used; ix++) {
+ next = (dp[ix] >> (DIGIT_BIT - d)) & mask;
+ dp[ix] = (dp[ix] << d) | save;
+ save = next;
+ }
+
+ /* If, at this point, we have a nonzero carryout into the next
+ digit, we'll increase the size by one digit, and store it...
+ */
+ if(save) {
+ dp[used] = save;
+ USED(mp) += 1;
+ }
+
+ s_mw_mp_clamp(mp);
+ return MP_OKAY;
+
+} /* end s_mw_mp_mul_2d() */
+
+/* }}} */
+
+/* {{{ s_mw_mp_div_2d(mp, d) */
+
+/*
+ Divide the integer by 2^d, where d is a number of bits. This
+ amounts to a bitwise shift of the value, and does not require the
+ full division code (used in Barrett reduction, see below)
+ */
+void s_mw_mp_div_2d(mw_mp_int *mp, mw_mp_digit d)
+{
+ int ix;
+ mw_mp_digit save, next, mask, *dp = DIGITS(mp);
+
+ s_mw_mp_rshd(mp, d / DIGIT_BIT);
+ d %= DIGIT_BIT;
+
+ mask = (1 << d) - 1;
+
+ save = 0;
+ for(ix = USED(mp) - 1; ix >= 0; ix--) {
+ next = dp[ix] & mask;
+ dp[ix] = (dp[ix] >> d) | (save << (DIGIT_BIT - d));
+ save = next;
+ }
+
+ s_mw_mp_clamp(mp);
+
+} /* end s_mw_mp_div_2d() */
+
+/* }}} */
+
+/* {{{ s_mw_mp_norm(a, b) */
+
+/*
+ s_mw_mp_norm(a, b)
+
+ Normalize a and b for division, where b is the divisor. In order
+ that we might make good guesses for quotient digits, we want the
+ leading digit of b to be at least half the radix, which we
+ accomplish by multiplying a and b by a constant. This constant is
+ returned (so that it can be divided back out of the remainder at the
+ end of the division process).
+
+ We multiply by the smallest power of 2 that gives us a leading digit
+ at least half the radix. By choosing a power of 2, we simplify the
+ multiplication and division steps to simple shifts.
+ */
+mw_mp_digit s_mw_mp_norm(mw_mp_int *a, mw_mp_int *b)
+{
+ mw_mp_digit t, d = 0;
+
+ t = DIGIT(b, USED(b) - 1);
+ while(t < (RADIX / 2)) {
+ t <<= 1;
+ ++d;
+ }
+
+ if(d != 0) {
+ s_mw_mp_mul_2d(a, d);
+ s_mw_mp_mul_2d(b, d);
+ }
+
+ return d;
+
+} /* end s_mw_mp_norm() */
+
+/* }}} */
+
+/* }}} */
+
+/* {{{ Primitive digit arithmetic */
+
+/* {{{ s_mw_mp_add_d(mp, d) */
+
+/* Add d to |mp| in place */
+mw_mp_err s_mw_mp_add_d(mw_mp_int *mp, mw_mp_digit d) /* unsigned digit addition */
+{
+ mw_mp_word w, k = 0;
+ mw_mp_size ix = 1, used = USED(mp);
+ mw_mp_digit *dp = DIGITS(mp);
+
+ w = dp[0] + d;
+ dp[0] = ACCUM(w);
+ k = CARRYOUT(w);
+
+ while(ix < used && k) {
+ w = dp[ix] + k;
+ dp[ix] = ACCUM(w);
+ k = CARRYOUT(w);
+ ++ix;
+ }
+
+ if(k != 0) {
+ mw_mp_err res;
+
+ if((res = s_mw_mp_pad(mp, USED(mp) + 1)) != MP_OKAY)
+ return res;
+
+ DIGIT(mp, ix) = k;
+ }
+
+ return MP_OKAY;
+
+} /* end s_mw_mp_add_d() */
+
+/* }}} */
+
+/* {{{ s_mw_mp_sub_d(mp, d) */
+
+/* Subtract d from |mp| in place, assumes |mp| > d */
+mw_mp_err s_mw_mp_sub_d(mw_mp_int *mp, mw_mp_digit d) /* unsigned digit subtract */
+{
+ mw_mp_word w, b = 0;
+ mw_mp_size ix = 1, used = USED(mp);
+ mw_mp_digit *dp = DIGITS(mp);
+
+ /* Compute initial subtraction */
+ w = (RADIX + dp[0]) - d;
+ b = CARRYOUT(w) ? 0 : 1;
+ dp[0] = ACCUM(w);
+
+ /* Propagate borrows leftward */
+ while(b && ix < used) {
+ w = (RADIX + dp[ix]) - b;
+ b = CARRYOUT(w) ? 0 : 1;
+ dp[ix] = ACCUM(w);
+ ++ix;
+ }
+
+ /* Remove leading zeroes */
+ s_mw_mp_clamp(mp);
+
+ /* If we have a borrow out, it's a violation of the input invariant */
+ if(b)
+ return MP_RANGE;
+ else
+ return MP_OKAY;
+
+} /* end s_mw_mp_sub_d() */
+
+/* }}} */
+
+/* {{{ s_mw_mp_mul_d(a, d) */
+
+/* Compute a = a * d, single digit multiplication */
+mw_mp_err s_mw_mp_mul_d(mw_mp_int *a, mw_mp_digit d)
+{
+ mw_mp_word w, k = 0;
+ mw_mp_size ix, max;
+ mw_mp_err res;
+ mw_mp_digit *dp = DIGITS(a);
+
+ /*
+ Single-digit multiplication will increase the precision of the
+ output by at most one digit. However, we can detect when this
+ will happen -- if the high-order digit of a, times d, gives a
+ two-digit result, then the precision of the result will increase;
+ otherwise it won't. We use this fact to avoid calling s_mw_mp_pad()
+ unless absolutely necessary.
+ */
+ max = USED(a);
+ w = dp[max - 1] * d;
+ if(CARRYOUT(w) != 0) {
+ if((res = s_mw_mp_pad(a, max + 1)) != MP_OKAY)
+ return res;
+ dp = DIGITS(a);
+ }
+
+ for(ix = 0; ix < max; ix++) {
+ w = (dp[ix] * d) + k;
+ dp[ix] = ACCUM(w);
+ k = CARRYOUT(w);
+ }
+
+ /* If there is a precision increase, take care of it here; the above
+ test guarantees we have enough storage to do this safely.
+ */
+ if(k) {
+ dp[max] = k;
+ USED(a) = max + 1;
+ }
+
+ s_mw_mp_clamp(a);
+
+ return MP_OKAY;
+
+} /* end s_mw_mp_mul_d() */
+
+/* }}} */
+
+/* {{{ s_mw_mp_div_d(mp, d, r) */
+
+/*
+ s_mw_mp_div_d(mp, d, r)
+
+ Compute the quotient mp = mp / d and remainder r = mp mod d, for a
+ single digit d. If r is null, the remainder will be discarded.
+ */
+
+mw_mp_err s_mw_mp_div_d(mw_mp_int *mp, mw_mp_digit d, mw_mp_digit *r)
+{
+ mw_mp_word w = 0, t;
+ mw_mp_int quot;
+ mw_mp_err res;
+ mw_mp_digit *dp = DIGITS(mp), *qp;
+ int ix;
+
+ if(d == 0)
+ return MP_RANGE;
+
+ /* Make room for the quotient */
+ if((res = mw_mp_init_size(&quot, USED(mp))) != MP_OKAY)
+ return res;
+
+ USED(&quot) = USED(mp); /* so clamping will work below */
+ qp = DIGITS(&quot);
+
+ /* Divide without subtraction */
+ for(ix = USED(mp) - 1; ix >= 0; ix--) {
+ w = (w << DIGIT_BIT) | dp[ix];
+
+ if(w >= d) {
+ t = w / d;
+ w = w % d;
+ } else {
+ t = 0;
+ }
+
+ qp[ix] = t;
+ }
+
+ /* Deliver the remainder, if desired */
+ if(r)
+ *r = w;
+
+ s_mw_mp_clamp(&quot);
+ mw_mp_exch(&quot, mp);
+ mw_mp_clear(&quot);
+
+ return MP_OKAY;
+
+} /* end s_mw_mp_div_d() */
+
+/* }}} */
+
+/* }}} */
+
+/* {{{ Primitive full arithmetic */
+
+/* {{{ s_mw_mp_add(a, b) */
+
+/* Compute a = |a| + |b| */
+mw_mp_err s_mw_mp_add(mw_mp_int *a, mw_mp_int *b) /* magnitude addition */
+{
+ mw_mp_word w = 0;
+ mw_mp_digit *pa, *pb;
+ mw_mp_size ix, used = USED(b);
+ mw_mp_err res;
+
+ /* Make sure a has enough precision for the output value */
+ if((used > USED(a)) && (res = s_mw_mp_pad(a, used)) != MP_OKAY)
+ return res;
+
+ /*
+ Add up all digits up to the precision of b. If b had initially
+ the same precision as a, or greater, we took care of it by the
+ padding step above, so there is no problem. If b had initially
+ less precision, we'll have to make sure the carry out is duly
+ propagated upward among the higher-order digits of the sum.
+ */
+ pa = DIGITS(a);
+ pb = DIGITS(b);
+ for(ix = 0; ix < used; ++ix) {
+ w += *pa + *pb++;
+ *pa++ = ACCUM(w);
+ w = CARRYOUT(w);
+ }
+
+ /* If we run out of 'b' digits before we're actually done, make
+ sure the carries get propagated upward...
+ */
+ used = USED(a);
+ while(w && ix < used) {
+ w += *pa;
+ *pa++ = ACCUM(w);
+ w = CARRYOUT(w);
+ ++ix;
+ }
+
+ /* If there's an overall carry out, increase precision and include
+ it. We could have done this initially, but why touch the memory
+ allocator unless we're sure we have to?
+ */
+ if(w) {
+ if((res = s_mw_mp_pad(a, used + 1)) != MP_OKAY)
+ return res;
+
+ DIGIT(a, ix) = w; /* pa may not be valid after s_mw_mp_pad() call */
+ }
+
+ return MP_OKAY;
+
+} /* end s_mw_mp_add() */
+
+/* }}} */
+
+/* {{{ s_mw_mp_sub(a, b) */
+
+/* Compute a = |a| - |b|, assumes |a| >= |b| */
+mw_mp_err s_mw_mp_sub(mw_mp_int *a, mw_mp_int *b) /* magnitude subtract */
+{
+ mw_mp_word w = 0;
+ mw_mp_digit *pa, *pb;
+ mw_mp_size ix, used = USED(b);
+
+ /*
+ Subtract and propagate borrow. Up to the precision of b, this
+ accounts for the digits of b; after that, we just make sure the
+ carries get to the right place. This saves having to pad b out to
+ the precision of a just to make the loops work right...
+ */
+ pa = DIGITS(a);
+ pb = DIGITS(b);
+
+ for(ix = 0; ix < used; ++ix) {
+ w = (RADIX + *pa) - w - *pb++;
+ *pa++ = ACCUM(w);
+ w = CARRYOUT(w) ? 0 : 1;
+ }
+
+ used = USED(a);
+ while(ix < used) {
+ w = RADIX + *pa - w;
+ *pa++ = ACCUM(w);
+ w = CARRYOUT(w) ? 0 : 1;
+ ++ix;
+ }
+
+ /* Clobber any leading zeroes we created */
+ s_mw_mp_clamp(a);
+
+ /*
+ If there was a borrow out, then |b| > |a| in violation
+ of our input invariant. We've already done the work,
+ but we'll at least complain about it...
+ */
+ if(w)
+ return MP_RANGE;
+ else
+ return MP_OKAY;
+
+} /* end s_mw_mp_sub() */
+
+/* }}} */
+
+/* {{{ s_mw_mp_mul(a, b) */
+
+/* Compute a = |a| * |b| */
+mw_mp_err s_mw_mp_mul(mw_mp_int *a, mw_mp_int *b)
+{
+ mw_mp_word w, k = 0;
+ mw_mp_int tmp;
+ mw_mp_err res;
+ mw_mp_size ix, jx, ua = USED(a), ub = USED(b);
+ mw_mp_digit *pa, *pb, *pt, *pbt;
+
+ if((res = mw_mp_init_size(&tmp, ua + ub)) != MP_OKAY)
+ return res;
+
+ /* This has the effect of left-padding with zeroes... */
+ USED(&tmp) = ua + ub;
+
+ /* We're going to need the base value each iteration */
+ pbt = DIGITS(&tmp);
+
+ /* Outer loop: Digits of b */
+
+ pb = DIGITS(b);
+ for(ix = 0; ix < ub; ++ix, ++pb) {
+ if(*pb == 0)
+ continue;
+
+ /* Inner product: Digits of a */
+ pa = DIGITS(a);
+ for(jx = 0; jx < ua; ++jx, ++pa) {
+ pt = pbt + ix + jx;
+ w = *pb * *pa + k + *pt;
+ *pt = ACCUM(w);
+ k = CARRYOUT(w);
+ }
+
+ pbt[ix + jx] = k;
+ k = 0;
+ }
+
+ s_mw_mp_clamp(&tmp);
+ s_mw_mp_exch(&tmp, a);
+
+ mw_mp_clear(&tmp);
+
+ return MP_OKAY;
+
+} /* end s_mw_mp_mul() */
+
+/* }}} */
+
+/* {{{ s_mw_mp_kmul(a, b, out, len) */
+
+#if 0
+void s_mw_mp_kmul(mw_mp_digit *a, mw_mp_digit *b, mw_mp_digit *out, mw_mp_size len)
+{
+ mw_mp_word w, k = 0;
+ mw_mp_size ix, jx;
+ mw_mp_digit *pa, *pt;
+
+ for(ix = 0; ix < len; ++ix, ++b) {
+ if(*b == 0)
+ continue;
+
+ pa = a;
+ for(jx = 0; jx < len; ++jx, ++pa) {
+ pt = out + ix + jx;
+ w = *b * *pa + k + *pt;
+ *pt = ACCUM(w);
+ k = CARRYOUT(w);
+ }
+
+ out[ix + jx] = k;
+ k = 0;
+ }
+
+} /* end s_mw_mp_kmul() */
+#endif
+
+/* }}} */
+
+/* {{{ s_mw_mp_sqr(a) */
+
+/*
+ Computes the square of a, in place. This can be done more
+ efficiently than a general multiplication, because many of the
+ computation steps are redundant when squaring. The inner product
+ step is a bit more complicated, but we save a fair number of
+ iterations of the multiplication loop.
+ */
+#if MP_SQUARE
+mw_mp_err s_mw_mp_sqr(mw_mp_int *a)
+{
+ mw_mp_word w, k = 0;
+ mw_mp_int tmp;
+ mw_mp_err res;
+ mw_mp_size ix, jx, kx, used = USED(a);
+ mw_mp_digit *pa1, *pa2, *pt, *pbt;
+
+ if((res = mw_mp_init_size(&tmp, 2 * used)) != MP_OKAY)
+ return res;
+
+ /* Left-pad with zeroes */
+ USED(&tmp) = 2 * used;
+
+ /* We need the base value each time through the loop */
+ pbt = DIGITS(&tmp);
+
+ pa1 = DIGITS(a);
+ for(ix = 0; ix < used; ++ix, ++pa1) {
+ if(*pa1 == 0)
+ continue;
+
+ w = DIGIT(&tmp, ix + ix) + (*pa1 * *pa1);
+
+ pbt[ix + ix] = ACCUM(w);
+ k = CARRYOUT(w);
+
+ /*
+ The inner product is computed as:
+
+ (C, S) = t[i,j] + 2 a[i] a[j] + C
+
+ This can overflow what can be represented in an mw_mp_word, and
+ since C arithmetic does not provide any way to check for
+ overflow, we have to check explicitly for overflow conditions
+ before they happen.
+ */
+ for(jx = ix + 1, pa2 = DIGITS(a) + jx; jx < used; ++jx, ++pa2) {
+ mw_mp_word u = 0, v;
+
+ /* Store this in a temporary to avoid indirections later */
+ pt = pbt + ix + jx;
+
+ /* Compute the multiplicative step */
+ w = *pa1 * *pa2;
+
+ /* If w is more than half MP_WORD_MAX, the doubling will
+ overflow, and we need to record a carry out into the next
+ word */
+ u = (w >> (MP_WORD_BIT - 1)) & 1;
+
+ /* Double what we've got, overflow will be ignored as defined
+ for C arithmetic (we've already noted if it is to occur)
+ */
+ w *= 2;
+
+ /* Compute the additive step */
+ v = *pt + k;
+
+ /* If we do not already have an overflow carry, check to see
+ if the addition will cause one, and set the carry out if so
+ */
+ u |= ((MP_WORD_MAX - v) < w);
+
+ /* Add in the rest, again ignoring overflow */
+ w += v;
+
+ /* Set the i,j digit of the output */
+ *pt = ACCUM(w);
+
+ /* Save carry information for the next iteration of the loop.
+ This is why k must be an mw_mp_word, instead of an mw_mp_digit */
+ k = CARRYOUT(w) | (u << DIGIT_BIT);
+
+ } /* for(jx ...) */
+
+ /* Set the last digit in the cycle and reset the carry */
+ k = DIGIT(&tmp, ix + jx) + k;
+ pbt[ix + jx] = ACCUM(k);
+ k = CARRYOUT(k);
+
+ /* If we are carrying out, propagate the carry to the next digit
+ in the output. This may cascade, so we have to be somewhat
+ circumspect -- but we will have enough precision in the output
+ that we won't overflow
+ */
+ kx = 1;
+ while(k) {
+ k = pbt[ix + jx + kx] + 1;
+ pbt[ix + jx + kx] = ACCUM(k);
+ k = CARRYOUT(k);
+ ++kx;
+ }
+ } /* for(ix ...) */
+
+ s_mw_mp_clamp(&tmp);
+ s_mw_mp_exch(&tmp, a);
+
+ mw_mp_clear(&tmp);
+
+ return MP_OKAY;
+
+} /* end s_mw_mp_sqr() */
+#endif
+
+/* }}} */
+
+/* {{{ s_mw_mp_div(a, b) */
+
+/*
+ s_mw_mp_div(a, b)
+
+ Compute a = a / b and b = a mod b. Assumes b > a.
+ */
+
+mw_mp_err s_mw_mp_div(mw_mp_int *a, mw_mp_int *b)
+{
+ mw_mp_int quot, rem, t;
+ mw_mp_word q;
+ mw_mp_err res;
+ mw_mp_digit d;
+ int ix;
+
+ if(mw_mp_cmw_mp_z(b) == 0)
+ return MP_RANGE;
+
+ /* Shortcut if b is power of two */
+ if((ix = s_mw_mp_ispow2(b)) >= 0) {
+ mw_mp_copy(a, b); /* need this for remainder */
+ s_mw_mp_div_2d(a, (mw_mp_digit)ix);
+ s_mw_mp_mod_2d(b, (mw_mp_digit)ix);
+
+ return MP_OKAY;
+ }
+
+ /* Allocate space to store the quotient */
+ if((res = mw_mp_init_size(&quot, USED(a))) != MP_OKAY)
+ return res;
+
+ /* A working temporary for division */
+ if((res = mw_mp_init_size(&t, USED(a))) != MP_OKAY)
+ goto T;
+
+ /* Allocate space for the remainder */
+ if((res = mw_mp_init_size(&rem, USED(a))) != MP_OKAY)
+ goto REM;
+
+ /* Normalize to optimize guessing */
+ d = s_mw_mp_norm(a, b);
+
+ /* Perform the division itself...woo! */
+ ix = USED(a) - 1;
+
+ while(ix >= 0) {
+ /* Find a partial substring of a which is at least b */
+ while(s_mw_mp_cmp(&rem, b) < 0 && ix >= 0) {
+ if((res = s_mw_mp_lshd(&rem, 1)) != MP_OKAY)
+ goto CLEANUP;
+
+ if((res = s_mw_mp_lshd(&quot, 1)) != MP_OKAY)
+ goto CLEANUP;
+
+ DIGIT(&rem, 0) = DIGIT(a, ix);
+ s_mw_mp_clamp(&rem);
+ --ix;
+ }
+
+ /* If we didn't find one, we're finished dividing */
+ if(s_mw_mp_cmp(&rem, b) < 0)
+ break;
+
+ /* Compute a guess for the next quotient digit */
+ q = DIGIT(&rem, USED(&rem) - 1);
+ if(q <= DIGIT(b, USED(b) - 1) && USED(&rem) > 1)
+ q = (q << DIGIT_BIT) | DIGIT(&rem, USED(&rem) - 2);
+
+ q /= DIGIT(b, USED(b) - 1);
+
+ /* The guess can be as much as RADIX + 1 */
+ if(q >= RADIX)
+ q = RADIX - 1;
+
+ /* See what that multiplies out to */
+ mw_mp_copy(b, &t);
+ if((res = s_mw_mp_mul_d(&t, q)) != MP_OKAY)
+ goto CLEANUP;
+
+ /*
+ If it's too big, back it off. We should not have to do this
+ more than once, or, in rare cases, twice. Knuth describes a
+ method by which this could be reduced to a maximum of once, but
+ I didn't implement that here.
+ */
+ while(s_mw_mp_cmp(&t, &rem) > 0) {
+ --q;
+ s_mw_mp_sub(&t, b);
+ }
+
+ /* At this point, q should be the right next digit */
+ if((res = s_mw_mp_sub(&rem, &t)) != MP_OKAY)
+ goto CLEANUP;
+
+ /*
+ Include the digit in the quotient. We allocated enough memory
+ for any quotient we could ever possibly get, so we should not
+ have to check for failures here
+ */
+ DIGIT(&quot, 0) = q;
+ }
+
+ /* Denormalize remainder */
+ if(d != 0)
+ s_mw_mp_div_2d(&rem, d);
+
+ s_mw_mp_clamp(&quot);
+ s_mw_mp_clamp(&rem);
+
+ /* Copy quotient back to output */
+ s_mw_mp_exch(&quot, a);
+
+ /* Copy remainder back to output */
+ s_mw_mp_exch(&rem, b);
+
+CLEANUP:
+ mw_mp_clear(&rem);
+REM:
+ mw_mp_clear(&t);
+T:
+ mw_mp_clear(&quot);
+
+ return res;
+
+} /* end s_mw_mp_div() */
+
+/* }}} */
+
+/* {{{ s_mw_mp_2expt(a, k) */
+
+mw_mp_err s_mw_mp_2expt(mw_mp_int *a, mw_mp_digit k)
+{
+ mw_mp_err res;
+ mw_mp_size dig, bit;
+
+ dig = k / DIGIT_BIT;
+ bit = k % DIGIT_BIT;
+
+ mw_mp_zero(a);
+ if((res = s_mw_mp_pad(a, dig + 1)) != MP_OKAY)
+ return res;
+
+ DIGIT(a, dig) |= (1 << bit);
+
+ return MP_OKAY;
+
+} /* end s_mw_mp_2expt() */
+
+/* }}} */
+
+/* {{{ s_mw_mp_reduce(x, m, mu) */
+
+/*
+ Compute Barrett reduction, x (mod m), given a precomputed value for
+ mu = b^2k / m, where b = RADIX and k = #digits(m). This should be
+ faster than straight division, when many reductions by the same
+ value of m are required (such as in modular exponentiation). This
+ can nearly halve the time required to do modular exponentiation,
+ as compared to using the full integer divide to reduce.
+
+ This algorithm was derived from the _Handbook of Applied
+ Cryptography_ by Menezes, Oorschot and VanStone, Ch. 14,
+ pp. 603-604.
+ */
+
+mw_mp_err s_mw_mp_reduce(mw_mp_int *x, mw_mp_int *m, mw_mp_int *mu)
+{
+ mw_mp_int q;
+ mw_mp_err res;
+ mw_mp_size um = USED(m);
+
+ if((res = mw_mp_init_copy(&q, x)) != MP_OKAY)
+ return res;
+
+ s_mw_mp_rshd(&q, um - 1); /* q1 = x / b^(k-1) */
+ s_mw_mp_mul(&q, mu); /* q2 = q1 * mu */
+ s_mw_mp_rshd(&q, um + 1); /* q3 = q2 / b^(k+1) */
+
+ /* x = x mod b^(k+1), quick (no division) */
+ s_mw_mp_mod_2d(x, DIGIT_BIT * (um + 1));
+
+ /* q = q * m mod b^(k+1), quick (no division) */
+ s_mw_mp_mul(&q, m);
+ s_mw_mp_mod_2d(&q, DIGIT_BIT * (um + 1));
+
+ /* x = x - q */
+ if((res = mw_mp_sub(x, &q, x)) != MP_OKAY)
+ goto CLEANUP;
+
+ /* If x < 0, add b^(k+1) to it */
+ if(mw_mp_cmw_mp_z(x) < 0) {
+ mw_mp_set(&q, 1);
+ if((res = s_mw_mp_lshd(&q, um + 1)) != MP_OKAY)
+ goto CLEANUP;
+ if((res = mw_mp_add(x, &q, x)) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ /* Back off if it's too big */
+ while(mw_mp_cmp(x, m) >= 0) {
+ if((res = s_mw_mp_sub(x, m)) != MP_OKAY)
+ break;
+ }
+
+ CLEANUP:
+ mw_mp_clear(&q);
+
+ return res;
+
+} /* end s_mw_mp_reduce() */
+
+/* }}} */
+
+/* }}} */
+
+/* {{{ Primitive comparisons */
+
+/* {{{ s_mw_mp_cmp(a, b) */
+
+/* Compare |a| <=> |b|, return 0 if equal, <0 if a<b, >0 if a>b */
+int s_mw_mp_cmp(mw_mp_int *a, mw_mp_int *b)
+{
+ mw_mp_size ua = USED(a), ub = USED(b);
+
+ if(ua > ub)
+ return MP_GT;
+ else if(ua < ub)
+ return MP_LT;
+ else {
+ int ix = ua - 1;
+ mw_mp_digit *ap = DIGITS(a) + ix, *bp = DIGITS(b) + ix;
+
+ while(ix >= 0) {
+ if(*ap > *bp)
+ return MP_GT;
+ else if(*ap < *bp)
+ return MP_LT;
+
+ --ap; --bp; --ix;
+ }
+
+ return MP_EQ;
+ }
+
+} /* end s_mw_mp_cmp() */
+
+/* }}} */
+
+/* {{{ s_mw_mp_cmw_mp_d(a, d) */
+
+/* Compare |a| <=> d, return 0 if equal, <0 if a<d, >0 if a>d */
+int s_mw_mp_cmw_mp_d(mw_mp_int *a, mw_mp_digit d)
+{
+ mw_mp_size ua = USED(a);
+ mw_mp_digit *ap = DIGITS(a);
+
+ if(ua > 1)
+ return MP_GT;
+
+ if(*ap < d)
+ return MP_LT;
+ else if(*ap > d)
+ return MP_GT;
+ else
+ return MP_EQ;
+
+} /* end s_mw_mp_cmw_mp_d() */
+
+/* }}} */
+
+/* {{{ s_mw_mp_ispow2(v) */
+
+/*
+ Returns -1 if the value is not a power of two; otherwise, it returns
+ k such that v = 2^k, i.e. lg(v).
+ */
+int s_mw_mp_ispow2(mw_mp_int *v)
+{
+ mw_mp_digit d, *dp;
+ mw_mp_size uv = USED(v);
+ int extra = 0, ix;
+
+ d = DIGIT(v, uv - 1); /* most significant digit of v */
+
+ while(d && ((d & 1) == 0)) {
+ d >>= 1;
+ ++extra;
+ }
+
+ if(d == 1) {
+ ix = uv - 2;
+ dp = DIGITS(v) + ix;
+
+ while(ix >= 0) {
+ if(*dp)
+ return -1; /* not a power of two */
+
+ --dp; --ix;
+ }
+
+ return ((uv - 1) * DIGIT_BIT) + extra;
+ }
+
+ return -1;
+
+} /* end s_mw_mp_ispow2() */
+
+/* }}} */
+
+/* {{{ s_mw_mp_ispow2d(d) */
+
+int s_mw_mp_ispow2d(mw_mp_digit d)
+{
+ int pow = 0;
+
+ while((d & 1) == 0) {
+ ++pow; d >>= 1;
+ }
+
+ if(d == 1)
+ return pow;
+
+ return -1;
+
+} /* end s_mw_mp_ispow2d() */
+
+/* }}} */
+
+/* }}} */
+
+/* {{{ Primitive I/O helpers */
+
+/* {{{ s_mw_mp_tovalue(ch, r) */
+
+/*
+ Convert the given character to its digit value, in the given radix.
+ If the given character is not understood in the given radix, -1 is
+ returned. Otherwise the digit's numeric value is returned.
+
+ The results will be odd if you use a radix < 2 or > 62, you are
+ expected to know what you're up to.
+ */
+int s_mw_mp_tovalue(char ch, int r)
+{
+ int val, xch;
+
+ if(r > 36)
+ xch = ch;
+ else
+ xch = toupper(ch);
+
+ if(isdigit(xch))
+ val = xch - '0';
+ else if(isupper(xch))
+ val = xch - 'A' + 10;
+ else if(islower(xch))
+ val = xch - 'a' + 36;
+ else if(xch == '+')
+ val = 62;
+ else if(xch == '/')
+ val = 63;
+ else
+ return -1;
+
+ if(val < 0 || val >= r)
+ return -1;
+
+ return val;
+
+} /* end s_mw_mp_tovalue() */
+
+/* }}} */
+
+/* {{{ s_mw_mp_todigit(val, r, low) */
+
+/*
+ Convert val to a radix-r digit, if possible. If val is out of range
+ for r, returns zero. Otherwise, returns an ASCII character denoting
+ the value in the given radix.
+
+ The results may be odd if you use a radix < 2 or > 64, you are
+ expected to know what you're doing.
+ */
+
+char s_mw_mp_todigit(int val, int r, int low)
+{
+ char ch;
+
+ if(val < 0 || val >= r)
+ return 0;
+
+ ch = s_dmap_1[val];
+
+ if(r <= 36 && low)
+ ch = tolower(ch);
+
+ return ch;
+
+} /* end s_mw_mp_todigit() */
+
+/* }}} */
+
+/* {{{ s_mw_mp_outlen(bits, radix) */
+
+/*
+ Return an estimate for how long a string is needed to hold a radix
+ r representation of a number with 'bits' significant bits.
+
+ Does not include space for a sign or a NUL terminator.
+ */
+int s_mw_mp_outlen(int bits, int r)
+{
+ return (int)((double)bits * LOG_V_2(r) + 0.5);
+
+} /* end s_mw_mp_outlen() */
+
+/* }}} */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* HERE THERE BE DRAGONS */
diff --git a/protocols/Sametime/src/meanwhile/src/mpi/mpi.h b/protocols/Sametime/src/meanwhile/src/mpi/mpi.h
new file mode 100644
index 0000000000..0e7cc527a1
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/mpi/mpi.h
@@ -0,0 +1,221 @@
+/*
+ mpi.h
+
+ by Michael J. Fromberger <http://www.dartmouth.edu/~sting/>
+ Copyright (C) 1998 Michael J. Fromberger, All Rights Reserved
+
+ Arbitrary precision integer arithmetic library
+
+ modified for use in Meanwhile as a convenience library
+*/
+
+#ifndef _H_MPI_
+#define _H_MPI_
+
+#include "mpi-config.h"
+
+#if MP_DEBUG
+#undef MP_IOFUNC
+#define MP_IOFUNC 1
+#endif
+
+#if MP_IOFUNC
+#include <stdio.h>
+#include <ctype.h>
+#endif
+
+#include <limits.h>
+
+#define MP_NEG 1
+#define MP_ZPOS 0
+
+/* Included for compatibility... */
+#define NEG MP_NEG
+#define ZPOS MP_ZPOS
+
+#define MP_OKAY 0 /* no error, all is well */
+#define MP_YES 0 /* yes (boolean result) */
+#define MP_NO -1 /* no (boolean result) */
+#define MP_MEM -2 /* out of memory */
+#define MP_RANGE -3 /* argument out of range */
+#define MP_BADARG -4 /* invalid parameter */
+#define MP_UNDEF -5 /* answer is undefined */
+#define MP_LAST_CODE MP_UNDEF
+
+#include "mpi-types.h"
+
+/* Included for compatibility... */
+#define DIGIT_BIT MP_DIGIT_BIT
+#define DIGIT_MAX MP_DIGIT_MAX
+
+/* Macros for accessing the mw_mp_int internals */
+#define SIGN(MP) ((MP)->sign)
+#define USED(MP) ((MP)->used)
+#define ALLOC(MP) ((MP)->alloc)
+#define DIGITS(MP) ((MP)->dp)
+#define DIGIT(MP,N) (MP)->dp[(N)]
+
+#if MP_ARGCHK == 1
+#define ARGCHK(X,Y) {if(!(X)){return (Y);}}
+#elif MP_ARGCHK == 2
+#include <assert.h>
+#define ARGCHK(X,Y) assert(X)
+#else
+#define ARGCHK(X,Y) /* */
+#endif
+
+/* This defines the maximum I/O base (minimum is 2) */
+#define MAX_RADIX 64
+
+typedef struct {
+ mw_mp_sign sign; /* sign of this quantity */
+ mw_mp_size alloc; /* how many digits allocated */
+ mw_mp_size used; /* how many digits used */
+ mw_mp_digit *dp; /* the digits themselves */
+} mw_mp_int;
+
+/*------------------------------------------------------------------------*/
+/* Default precision */
+
+unsigned int mw_mp_get_prec(void);
+void mw_mp_set_prec(unsigned int prec);
+
+/*------------------------------------------------------------------------*/
+/* Memory management */
+
+mw_mp_err mw_mp_init(mw_mp_int *mp);
+mw_mp_err mw_mp_init_array(mw_mp_int mp[], int count);
+mw_mp_err mw_mp_init_size(mw_mp_int *mp, mw_mp_size prec);
+mw_mp_err mw_mp_init_copy(mw_mp_int *mp, mw_mp_int *from);
+mw_mp_err mw_mp_copy(mw_mp_int *from, mw_mp_int *to);
+void mw_mp_exch(mw_mp_int *mp1, mw_mp_int *mp2);
+void mw_mp_clear(mw_mp_int *mp);
+void mw_mp_clear_array(mw_mp_int mp[], int count);
+void mw_mp_zero(mw_mp_int *mp);
+void mw_mp_set(mw_mp_int *mp, mw_mp_digit d);
+mw_mp_err mw_mp_set_int(mw_mp_int *mp, long z);
+
+/*------------------------------------------------------------------------*/
+/* Single digit arithmetic */
+
+mw_mp_err mw_mp_add_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *b);
+mw_mp_err mw_mp_sub_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *b);
+mw_mp_err mw_mp_mul_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *b);
+mw_mp_err mw_mp_mul_2(mw_mp_int *a, mw_mp_int *c);
+mw_mp_err mw_mp_div_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *q, mw_mp_digit *r);
+mw_mp_err mw_mp_div_2(mw_mp_int *a, mw_mp_int *c);
+mw_mp_err mw_mp_expt_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *c);
+
+/*------------------------------------------------------------------------*/
+/* Sign manipulations */
+
+mw_mp_err mw_mp_abs(mw_mp_int *a, mw_mp_int *b);
+mw_mp_err mw_mp_neg(mw_mp_int *a, mw_mp_int *b);
+
+/*------------------------------------------------------------------------*/
+/* Full arithmetic */
+
+mw_mp_err mw_mp_add(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c);
+mw_mp_err mw_mp_sub(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c);
+mw_mp_err mw_mp_mul(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c);
+mw_mp_err mw_mp_mul_2d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *c);
+#if MP_SQUARE
+mw_mp_err mw_mp_sqr(mw_mp_int *a, mw_mp_int *b);
+#else
+#define mw_mp_sqr(a, b) mw_mp_mul(a, a, b)
+#endif
+mw_mp_err mw_mp_div(mw_mp_int *a, mw_mp_int *b, mw_mp_int *q, mw_mp_int *r);
+mw_mp_err mw_mp_div_2d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *q, mw_mp_int *r);
+mw_mp_err mw_mp_expt(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c);
+mw_mp_err mw_mp_2expt(mw_mp_int *a, mw_mp_digit k);
+mw_mp_err mw_mp_sqrt(mw_mp_int *a, mw_mp_int *b);
+
+/*------------------------------------------------------------------------*/
+/* Modular arithmetic */
+
+#if MP_MODARITH
+mw_mp_err mw_mp_mod(mw_mp_int *a, mw_mp_int *m, mw_mp_int *c);
+mw_mp_err mw_mp_mod_d(mw_mp_int *a, mw_mp_digit d, mw_mp_digit *c);
+mw_mp_err mw_mp_addmod(mw_mp_int *a, mw_mp_int *b, mw_mp_int *m, mw_mp_int *c);
+mw_mp_err mw_mp_submod(mw_mp_int *a, mw_mp_int *b, mw_mp_int *m, mw_mp_int *c);
+mw_mp_err mw_mp_mulmod(mw_mp_int *a, mw_mp_int *b, mw_mp_int *m, mw_mp_int *c);
+#if MP_SQUARE
+mw_mp_err mw_mp_sqrmod(mw_mp_int *a, mw_mp_int *m, mw_mp_int *c);
+#else
+#define mw_mp_sqrmod(a, m, c) mw_mp_mulmod(a, a, m, c)
+#endif
+mw_mp_err mw_mp_exptmod(mw_mp_int *a, mw_mp_int *b, mw_mp_int *m, mw_mp_int *c);
+mw_mp_err mw_mp_exptmod_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *m, mw_mp_int *c);
+#endif /* MP_MODARITH */
+
+/*------------------------------------------------------------------------*/
+/* Comparisons */
+
+int mw_mp_cmw_mp_z(mw_mp_int *a);
+int mw_mp_cmw_mp_d(mw_mp_int *a, mw_mp_digit d);
+int mw_mp_cmp(mw_mp_int *a, mw_mp_int *b);
+int mw_mp_cmw_mp_mag(mw_mp_int *a, mw_mp_int *b);
+int mw_mp_cmw_mp_int(mw_mp_int *a, long z);
+int mw_mp_isodd(mw_mp_int *a);
+int mw_mp_iseven(mw_mp_int *a);
+
+/*------------------------------------------------------------------------*/
+/* Number theoretic */
+
+#if MP_NUMTH
+mw_mp_err mw_mp_gcd(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c);
+mw_mp_err mw_mp_lcm(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c);
+mw_mp_err mw_mp_xgcd(mw_mp_int *a, mw_mp_int *b, mw_mp_int *g, mw_mp_int *x, mw_mp_int *y);
+mw_mp_err mw_mp_invmod(mw_mp_int *a, mw_mp_int *m, mw_mp_int *c);
+#endif /* end MP_NUMTH */
+
+/*------------------------------------------------------------------------*/
+/* Input and output */
+
+#if MP_IOFUNC
+void mw_mp_print(mw_mp_int *mp, FILE *ofp);
+#endif /* end MP_IOFUNC */
+
+/*------------------------------------------------------------------------*/
+/* Base conversion */
+
+#define BITS 1
+#define BYTES CHAR_BIT
+
+mw_mp_err mw_mp_read_signed_bin(mw_mp_int *mp, unsigned char *str, int len);
+int mw_mp_signed_bin_size(mw_mp_int *mp);
+mw_mp_err mw_mp_to_signed_bin(mw_mp_int *mp, unsigned char *str);
+
+mw_mp_err mw_mp_read_unsigned_bin(mw_mp_int *mp, unsigned char *str, int len);
+int mw_mp_unsigned_bin_size(mw_mp_int *mp);
+mw_mp_err mw_mp_to_unsigned_bin(mw_mp_int *mp, unsigned char *str);
+
+int mw_mp_count_bits(mw_mp_int *mp);
+
+#if MP_COMPAT_MACROS
+#define mw_mp_read_raw(mp, str, len) mw_mp_read_signed_bin((mp), (str), (len))
+#define mw_mp_raw_size(mp) mw_mp_signed_bin_size(mp)
+#define mw_mp_toraw(mp, str) mw_mp_to_signed_bin((mp), (str))
+#define mw_mp_read_mag(mp, str, len) mw_mp_read_unsigned_bin((mp), (str), (len))
+#define mw_mp_mag_size(mp) mw_mp_unsigned_bin_size(mp)
+#define mw_mp_tomag(mp, str) mw_mp_to_unsigned_bin((mp), (str))
+#endif
+
+mw_mp_err mw_mp_read_radix(mw_mp_int *mp, unsigned char *str, int radix);
+int mw_mp_radix_size(mw_mp_int *mp, int radix);
+int mw_mp_value_radix_size(int num, int qty, int radix);
+mw_mp_err mw_mp_toradix(mw_mp_int *mp, unsigned char *str, int radix);
+
+int mw_mp_char2value(char ch, int r);
+
+#define mw_mp_tobinary(M, S) mw_mp_toradix((M), (S), 2)
+#define mw_mp_tooctal(M, S) mw_mp_toradix((M), (S), 8)
+#define mw_mp_todecimal(M, S) mw_mp_toradix((M), (S), 10)
+#define mw_mp_tohex(M, S) mw_mp_toradix((M), (S), 16)
+
+/*------------------------------------------------------------------------*/
+/* Error strings */
+
+const char *mw_mp_strerror(mw_mp_err ec);
+
+#endif /* end _H_MPI_ */
diff --git a/protocols/Sametime/src/meanwhile/src/mw_channel.h b/protocols/Sametime/src/meanwhile/src/mw_channel.h
new file mode 100644
index 0000000000..7af5e22d86
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/mw_channel.h
@@ -0,0 +1,380 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _MW_CHANNEL_H
+#define _MW_CHANNEL_H
+
+
+/** @file mw_channel.h
+
+Life-cycle of an outgoing channel:
+
+1: mwChannel_new is called. If there is a channel in the outgoing
+collection in state NEW, then it is returned. Otherwise, a channel
+is allocated, assigned a unique outgoing id, marked as NEW, and
+returned.
+
+2: channel is set to INIT status (effectively earmarking it as in-
+use). fields on the channel can then be set as necessary to
+prepare it for creation.
+
+3: mwChannel_create is called. The channel is marked to WAIT status
+and a message is sent to the server. The channel is also marked as
+inactive as of that moment.
+
+4: the channel is accepted (step 5) or rejected (step 7)
+
+5: an accept message is received from the server, and the channel
+is marked as OPEN, and the inactive mark is removed. And messages
+in the in or out queues for that channel are processed. The channel
+is now ready to be used.
+
+6: data is sent and received over the channel
+
+7: the channel is closed either by receipt of a close message or by
+local action. If by local action, then a close message is sent to
+the server. The channel is cleaned up, its queues dumped, and it
+is set to NEW status to await re-use.
+
+Life-cycle of an incoming channel:
+
+1: a channel create message is received. A channel is allocated and
+given an id matching the message. It is placed in status WAIT, and
+marked as inactive as of that moment. The service matching that
+channel is alerted of the incoming creation request.
+
+2: the service can either accept (step 3) or reject (step 5) the
+channel
+
+3: mwChannel_accept is called. The channel is marked as OPEN, and
+an accept message is sent to the server. And messages in the in or
+out queues for that channel are processed. The channel is now ready
+to be used.
+
+4: data is sent and received over the channel
+
+5: The channel is closed either by receipt of a close message or by
+local action. If by local action, then a close message is sent to
+the server. The channel is cleaned up, its queues dumped, and it
+is deallocated. */
+
+
+#include <time.h>
+#include "mw_common.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* place-holders */
+struct mwCipherInstance;
+struct mwMsgChannelAccept;
+struct mwMsgChannelCreate;
+struct mwMsgChannelDestroy;
+struct mwMsgChannelSend;
+struct mwService;
+struct mwSession;
+
+
+
+/** @struct mwChannel
+ Represents a channel to a service */
+struct mwChannel;
+
+
+/** @struct mwChannelSet
+ Collection of channels */
+struct mwChannelSet;
+
+
+/** special ID indicating the master channel */
+#define MW_MASTER_CHANNEL_ID 0x00000000
+
+
+/** non-zero if a channel id appears to be that of an outgoing channel */
+#define mwChannel_idIsOutgoing(id) \
+ (! (0x80000000 & (id)))
+
+/** non-zero if a channel id appears to be that of an incoming channel */
+#define mwChannel_idIsIncoming(id) \
+ (! mwChannel_idIsOutgoing(id))
+
+/** non-zero if a channel appears to be an outgoing channel */
+#define mwChannel_isOutgoing(chan) \
+ mwChannel_idIsOutgoing(mwChannel_getId(chan))
+
+/** non-zero if a channel appears to be an incoming channel */
+#define mwChannel_isIncoming(chan) \
+ mwChannel_idIsIncoming(mwChannel_getId(chan))
+
+
+/** channel status */
+enum mwChannelState {
+ mwChannel_NEW, /**< channel is newly allocated, in the pool */
+ mwChannel_INIT, /**< channel is being prepared, out of the pool */
+ mwChannel_WAIT, /**< channel is waiting for accept */
+ mwChannel_OPEN, /**< channel is accepted and open */
+ mwChannel_DESTROY, /**< channel is being destroyed */
+ mwChannel_ERROR, /**< channel is being destroyed due to error */
+ mwChannel_UNKNOWN, /**< unknown state, or error determining state */
+};
+
+
+#define mwChannel_isState(chan, state) \
+ (mwChannel_getState(chan) == (state))
+
+
+/** channel statistic fields.
+ @see mwChannel_getStatistic */
+enum mwChannelStatField {
+ mwChannelStat_MSG_SENT, /**< total send-on-chan messages sent */
+ mwChannelStat_MSG_RECV, /**< total send-on-chan messages received */
+ mwChannelStat_U_BYTES_SENT, /**< total bytes sent, pre-encryption */
+ mwChannelStat_U_BYTES_RECV, /**< total bytes received, post-decryption */
+ mwChannelStat_OPENED_AT, /**< time when channel was opened */
+ mwChannelStat_CLOSED_AT, /**< time when channel was closed */
+};
+
+
+/** @enum mwEncryptPolicy
+
+ Policy for a channel, dictating what sort of encryption should be
+ used, if any, and when.
+*/
+enum mwEncryptPolicy {
+ mwEncrypt_NONE = 0x0000, /**< encrypt none */
+ mwEncrypt_WHATEVER = 0x0001, /**< encrypt whatever you want */
+ mwEncrypt_ALL = 0x0002, /**< encrypt all, any cipher */
+ mwEncrypt_RC2_40 = 0x1000, /**< encrypt all, RC2/40 cipher */
+ mwEncrypt_RC2_128 = 0x2000, /**< encrypt all, RC2/128 cipher */
+};
+
+
+/** Allocate and initialize a channel set for a session */
+struct mwChannelSet *mwChannelSet_new(struct mwSession *);
+
+
+/** Clear and deallocate a channel set. Closes, clears, and frees all
+ contained channels. */
+void mwChannelSet_free(struct mwChannelSet *);
+
+
+/** Create an incoming channel with the given channel id. Channel's state
+ will be set to WAIT. Primarily for use in mw_session */
+struct mwChannel *mwChannel_newIncoming(struct mwChannelSet *, guint32 id);
+
+
+/** Create an outgoing channel. Its channel ID will be generated by
+ the owning channel set. Channel's state will be set to INIT */
+struct mwChannel *mwChannel_newOutgoing(struct mwChannelSet *);
+
+
+/** Obtain a reference to a channel by its id.
+ @returns the channel matching chan, or NULL */
+struct mwChannel *mwChannel_find(struct mwChannelSet *cs, guint32 chan);
+
+
+/** get the ID for a channel. 0x00 indicates an error, as that is not
+ a permissible value */
+guint32 mwChannel_getId(struct mwChannel *);
+
+
+/** get the session for a channel. */
+struct mwSession *mwChannel_getSession(struct mwChannel *);
+
+
+/** get the ID of the service for a channel. This may be 0x00 for NEW
+ channels */
+guint32 mwChannel_getServiceId(struct mwChannel *);
+
+
+/** get the service for a channel. This may be NULL for NEW
+ channels */
+struct mwService *mwChannel_getService(struct mwChannel *);
+
+
+/** associate a channel with an owning service */
+void mwChannel_setService(struct mwChannel *chan, struct mwService *srvc);
+
+
+/** get service-specific data. This is for use by service
+ implementations to easily associate information with the
+ channel */
+gpointer mwChannel_getServiceData(struct mwChannel *chan);
+
+
+/** set service-specific data. This is for use by service
+ implementations to easily associate information with the
+ channel */
+void mwChannel_setServiceData(struct mwChannel *chan,
+ gpointer data, GDestroyNotify clean);
+
+
+void mwChannel_removeServiceData(struct mwChannel *chan);
+
+
+guint32 mwChannel_getProtoType(struct mwChannel *chan);
+
+
+void mwChannel_setProtoType(struct mwChannel *chan, guint32 proto_type);
+
+
+guint32 mwChannel_getProtoVer(struct mwChannel *chan);
+
+
+void mwChannel_setProtoVer(struct mwChannel *chan, guint32 proto_ver);
+
+
+/** Channel encryption policy.
+
+ Cannot currently be set, used internally to automatically
+ negotiate ciphers. Future revisions may allow this to be specified
+ in a new channel to dictate channel encryption.
+
+ @see enum mwEncryptPolicy
+*/
+guint16 mwChannel_getEncryptPolicy(struct mwChannel *chan);
+
+
+guint32 mwChannel_getOptions(struct mwChannel *chan);
+
+
+void mwChannel_setOptions(struct mwChannel *chan, guint32 options);
+
+
+/** User at the other end of the channel. The target user for outgoing
+ channels, the creator for incoming channels */
+struct mwLoginInfo *mwChannel_getUser(struct mwChannel *chan);
+
+
+/** direct reference to the create addtl information for a channel */
+struct mwOpaque *mwChannel_getAddtlCreate(struct mwChannel *);
+
+
+/** direct reference to the accept addtl information for a channel */
+struct mwOpaque *mwChannel_getAddtlAccept(struct mwChannel *);
+
+
+/** automatically adds instances of all ciphers in the session to the
+ list of supported ciphers for a channel */
+void mwChannel_populateSupportedCipherInstances(struct mwChannel *chan);
+
+
+/** add a cipher instance to a channel's list of supported
+ ciphers. Channel must be NEW. */
+void mwChannel_addSupportedCipherInstance(struct mwChannel *chan,
+ struct mwCipherInstance *ci);
+
+
+/** the list of supported ciphers for a channel. This list will be
+ empty once a cipher has been selected for the channel */
+GList *mwChannel_getSupportedCipherInstances(struct mwChannel *chan);
+
+
+/** select a cipher instance for a channel. A NULL instance indicates
+ that no encryption should be used. */
+void mwChannel_selectCipherInstance(struct mwChannel *chan,
+ struct mwCipherInstance *ci);
+
+
+struct mwCipherInstance *
+mwChannel_getCipherInstance(struct mwChannel *chan);
+
+
+/** get the state of a channel */
+enum mwChannelState mwChannel_getState(struct mwChannel *);
+
+
+/** obtain the value for a statistic field as a gpointer */
+gpointer mwChannel_getStatistic(struct mwChannel *chan,
+ enum mwChannelStatField stat);
+
+
+/** Formally open a channel.
+
+ For outgoing channels: instruct the session to send a channel
+ create message to the server, and to mark the channel (which must
+ be in INIT status) as being in WAIT status.
+
+ For incoming channels: configures the channel according to options
+ in the channel create message. Marks the channel as being in WAIT
+ status
+*/
+int mwChannel_create(struct mwChannel *chan);
+
+
+/** Formally accept an incoming channel. Instructs the session to send
+ a channel accept message to the server, and to mark the channel as
+ being OPEN. */
+int mwChannel_accept(struct mwChannel *chan);
+
+
+/** Destroy a channel. Sends a channel-destroy message to the server,
+ and perform cleanup to remove the channel.
+
+ @param chan the channel to destroy
+ @param reason the reason code for closing the channel
+ @param data optional additional information
+*/
+int mwChannel_destroy(struct mwChannel *chan, guint32 reason,
+ struct mwOpaque *data);
+
+
+/** Compose a send-on-channel message, encrypt it as per the channel's
+ specification, and send it */
+int mwChannel_send(struct mwChannel *chan, guint32 msg_type,
+ struct mwOpaque *msg);
+
+
+/** Compose a send-on-channel message, and if encrypt is TRUE, encrypt
+ it as per the channel's specification, and send it */
+int mwChannel_sendEncrypted(struct mwChannel *chan,
+ guint32 msg_type, struct mwOpaque *msg,
+ gboolean encrypt);
+
+
+/** pass a create message to a channel for handling */
+void mwChannel_recvCreate(struct mwChannel *chan,
+ struct mwMsgChannelCreate *msg);
+
+
+/** pass an accept message to a channel for handling */
+void mwChannel_recvAccept(struct mwChannel *chan,
+ struct mwMsgChannelAccept *msg);
+
+
+/** pass a destroy message to a channel for handling */
+void mwChannel_recvDestroy(struct mwChannel *chan,
+ struct mwMsgChannelDestroy *msg);
+
+
+/** Feed data into a channel. */
+void mwChannel_recv(struct mwChannel *chan, struct mwMsgChannelSend *msg);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _MW_CHANNEL_H */
+
diff --git a/protocols/Sametime/src/meanwhile/src/mw_cipher.h b/protocols/Sametime/src/meanwhile/src/mw_cipher.h
new file mode 100644
index 0000000000..a75781397e
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/mw_cipher.h
@@ -0,0 +1,297 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _MW_CIPHER_H
+#define _MW_CIPHER_H
+
+
+#include <glib.h>
+#include "mw_common.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* place-holders */
+struct mwChannel;
+struct mwSession;
+
+
+/** @enum mwCipherType
+ Common cipher types */
+enum mwCipherType {
+ mwCipher_RC2_40 = 0x0000,
+ mwCipher_RC2_128 = 0x0001,
+};
+
+
+struct mwCipher;
+struct mwCipherInstance;
+
+
+/** Obtain an instance of a given cipher, which can be used for the
+ processing of a single channel. */
+typedef struct mwCipherInstance *(*mwCipherInstantiator)
+ (struct mwCipher *cipher, struct mwChannel *chan);
+
+
+/** Process (encrypt or decrypt, depending) the given data. The passed
+ buffer may be freed in processing and be replaced with a freshly
+ allocated buffer. The post-processed buffer must in turn be freed
+ after use */
+typedef int (*mwCipherProcessor)
+ (struct mwCipherInstance *ci, struct mwOpaque *data);
+
+
+/** A cipher. Ciphers are primarily used to provide cipher instances
+ for bi-directional encryption on channels, but some may be used
+ for other activities. Expand upon this structure to create a
+ custom encryption provider.
+ @see mwCipherInstance */
+struct mwCipher {
+
+ /** service this cipher is providing for
+ @see mwCipher_getSession */
+ struct mwSession *session;
+
+ guint16 type; /**< @see mwCipher_getType */
+ const char *(*get_name)(); /**< @see mwCipher_getName */
+ const char *(*get_desc)(); /**< @see mwCipher_getDesc */
+
+ /** Generate a new Cipher Instance for use on a channel
+ @see mwCipher_newInstance */
+ mwCipherInstantiator new_instance;
+
+ void (*offered)(struct mwCipherInstance *ci, struct mwEncryptItem *item);
+ struct mwEncryptItem *(*offer)(struct mwCipherInstance *ci);
+ void (*accepted)(struct mwCipherInstance *ci, struct mwEncryptItem *item);
+ struct mwEncryptItem *(*accept)(struct mwCipherInstance *ci);
+
+ mwCipherProcessor encrypt; /**< @see mwCipherInstance_encrypt */
+ mwCipherProcessor decrypt; /**< @see mwCipherInstance_decrypt */
+
+ /** prepare this cipher for being free'd
+ @see mwCipher_free */
+ void (*clear)(struct mwCipher *c);
+
+ /** clean up a cipher instance before being free'd
+ @see mwCipherInstance_free */
+ void (*clear_instance)(struct mwCipherInstance *ci);
+};
+
+
+/** An instance of a cipher. Expand upon this structure to contain
+ necessary state data
+ @see mwCipher */
+struct mwCipherInstance {
+
+ /** the parent cipher.
+ @see mwCipherInstance_getCipher */
+ struct mwCipher *cipher;
+
+ /** the channel this instances processes
+ @see mwCipherInstance_getChannel */
+ struct mwChannel *channel;
+};
+
+
+struct mwCipher *mwCipher_new_RC2_40(struct mwSession *s);
+
+
+struct mwCipher *mwCipher_new_RC2_128(struct mwSession *s);
+
+
+struct mwSession *mwCipher_getSession(struct mwCipher *cipher);
+
+
+guint16 mwCipher_getType(struct mwCipher *cipher);
+
+
+const char *mwCipher_getName(struct mwCipher *cipher);
+
+
+const char *mwCipher_getDesc(struct mwCipher *cipher);
+
+
+struct mwCipherInstance *mwCipher_newInstance(struct mwCipher *cipher,
+ struct mwChannel *channel);
+
+
+/** destroy a cipher */
+void mwCipher_free(struct mwCipher* cipher);
+
+
+/** reference the parent cipher of an instance */
+struct mwCipher *mwCipherInstance_getCipher(struct mwCipherInstance *ci);
+
+
+/** reference the channel a cipher instance is attached to */
+struct mwChannel *mwCipherInstance_getChannel(struct mwCipherInstance *ci);
+
+
+/** Indicates a cipher has been offered to our channel */
+void mwCipherInstance_offered(struct mwCipherInstance *ci,
+ struct mwEncryptItem *item);
+
+
+/** Offer a cipher */
+struct mwEncryptItem *
+mwCipherInstance_offer(struct mwCipherInstance *ci);
+
+
+/** Indicates an offered cipher has been accepted */
+void mwCipherInstance_accepted(struct mwCipherInstance *ci,
+ struct mwEncryptItem *item);
+
+
+/** Accept a cipher offered to our channel */
+struct mwEncryptItem *
+mwCipherInstance_accept(struct mwCipherInstance *ci);
+
+
+/** encrypt data */
+int mwCipherInstance_encrypt(struct mwCipherInstance *ci,
+ struct mwOpaque *data);
+
+
+/** decrypt data */
+int mwCipherInstance_decrypt(struct mwCipherInstance *ci,
+ struct mwOpaque *data);
+
+
+/** destroy a cipher instance */
+void mwCipherInstance_free(struct mwCipherInstance *ci);
+
+
+/**
+ @section General Cipher Functions
+
+ These functions are reused where encryption is necessary outside of
+ a channel (eg. session authentication)
+*/
+/* @{ */
+
+
+/** generate some pseudo-random bytes
+ @param keylen count of bytes to write into key
+ @param key buffer to write keys into
+*/
+void mwKeyRandom(guchar *key, gsize keylen);
+
+
+/** Setup an Initialization Vector. IV must be at least 8 bytes */
+void mwIV_init(guchar *iv);
+
+
+/** Expand a variable-length key into a 128-byte key (represented as
+ an an array of 64 ints) */
+void mwKeyExpand(int *ekey, const guchar *key, gsize keylen);
+
+
+/** Encrypt data using an already-expanded key */
+void mwEncryptExpanded(const int *ekey, guchar *iv,
+ struct mwOpaque *in,
+ struct mwOpaque *out);
+
+
+/** Encrypt data using an expanded form of the given key */
+void mwEncrypt(const guchar *key, gsize keylen, guchar *iv,
+ struct mwOpaque *in, struct mwOpaque *out);
+
+
+/** Decrypt data using an already expanded key */
+void mwDecryptExpanded(const int *ekey, guchar *iv,
+ struct mwOpaque *in,
+ struct mwOpaque *out);
+
+
+/** Decrypt data using an expanded form of the given key */
+void mwDecrypt(const guchar *key, gsize keylen, guchar *iv,
+ struct mwOpaque *in, struct mwOpaque *out);
+
+
+/* @} */
+
+
+/**
+ @section Diffie-Hellman Functions
+
+ These functions are reused where DH Key negotiation is necessary
+ outside of a channel (eg. session authentication). These are
+ wrapping a full multiple-precision integer math library, but most of
+ the functionality there-of is not exposed. Currently, the math is
+ provided by a copy of the public domain libmpi.
+
+ for more information on the used MPI Library, visit
+ http://www.cs.dartmouth.edu/~sting/mpi/
+*/
+/* @{ */
+
+
+/** @struct mwMpi */
+struct mwMpi;
+
+
+/** prepare a new mpi value */
+struct mwMpi *mwMpi_new();
+
+
+/** destroy an mpi value */
+void mwMpi_free(struct mwMpi *i);
+
+
+/** Import a value from an opaque */
+void mwMpi_import(struct mwMpi *i, struct mwOpaque *o);
+
+
+/** Export a value into an opaque */
+void mwMpi_export(struct mwMpi *i, struct mwOpaque *o);
+
+
+/** set a big integer to the Sametime Prime value */
+void mwMpi_setDHPrime(struct mwMpi *i);
+
+
+/** set a big integer to the Sametime Base value */
+void mwMpi_setDHBase(struct mwMpi *i);
+
+
+/** sets private to a randomly generated value, and calculates public
+ using the Sametime Prime and Base */
+void mwMpi_randDHKeypair(struct mwMpi *private_key, struct mwMpi *public_key);
+
+
+/** sets the shared key value based on the remote and private keys,
+ using the Sametime Prime and Base */
+void mwMpi_calculateDHShared(struct mwMpi *shared_key, struct mwMpi *remote_key,
+ struct mwMpi *private_key);
+
+
+/* @} */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _MW_CIPHER_H */
diff --git a/protocols/Sametime/src/meanwhile/src/mw_common.h b/protocols/Sametime/src/meanwhile/src/mw_common.h
new file mode 100644
index 0000000000..1294da4959
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/mw_common.h
@@ -0,0 +1,437 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _MW_COMMON_H
+#define _MW_COMMON_H
+
+
+/** @file mw_common.h
+
+ Common data types and functions for handling those types.
+
+ Functions in this file all fit into similar naming conventions of
+ <code>TYPE_ACTION</code> as per the activity they perform. The
+ following actions are available:
+
+ <code>void TYPE_put(struct mwPutBuffer *b, TYPE *val)</code>
+ - marshalls val onto the buffer b. The buffer will grow as necessary
+ to fit all the data put into it. For guint16, guint32, and
+ gboolean, <code>TYPE val</code> is used instead of <code>TYPE
+ \*val</code>.
+
+ <code>void TYPE_get(struct mwGetBuffer *b, TYPE *val)</code>
+ - unmarshals val from the buffer b. Failure (due to lack of
+ insufficient remaining buffer) is indicated in the buffer's error
+ field. A call to a _get function with a buffer in an error state
+ has to effect.
+
+ <code>void TYPE_clear(TYPE *val)</code>
+ - zeros and frees internal members of val, but does not free val
+ itself. Needs to be called before free-ing any complex types which
+ have been unmarshalled from a TYPE_get or populated from a
+ TYPE_clone call to prevent memory leaks.
+
+ <code>void TYPE_clone(TYPE *to, TYPE *from)</code>
+ - copies/clones members of from into to. May result in memory
+ allocation for some types. Note that to is not cleared
+ before-hand, it must already be in a pristine condition.
+
+ <code>gboolean TYPE_equal(TYPE *y, TYPE *z)</code>
+ - simple equality test.
+*/
+
+
+#include <glib.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** @struct mwPutBuffer
+ buffer to be written to */
+struct mwPutBuffer;
+
+/** @struct mwGetBuffer
+ buffer to be read from */
+struct mwGetBuffer;
+
+
+/** A length of binary data, not null-terminated. */
+struct mwOpaque {
+ gsize len; /**< length of data. */
+ guchar *data; /**< data, normally with no NULL termination */
+};
+
+
+/* 8.3.6 Login Types */
+
+/** The type of login. Normally meaning the type of client code being
+ used to login with.
+
+ If you know of any additional client identifiers, please add them
+ below or submit an RFE to the meanwhile tracker.
+*/
+enum mwLoginType {
+ mwLogin_LIB = 0x1000, /**< official Lotus binary library */
+ mwLogin_JAVA_WEB = 0x1001, /**< official Lotus Java applet */
+ mwLogin_BINARY = 0x1002, /**< official Lotus binary application */
+ mwLogin_JAVA_APP = 0x1003, /**< official Lotus Java application */
+ mwLogin_LINKS = 0x100a, /**< official Sametime Links toolkit */
+
+ /* now we're getting crazy */
+ mwLogin_NOTES_6_5 = 0x1200,
+ mwLogin_NOTES_6_5_3 = 0x1203,
+ mwLogin_NOTES_7_0_beta = 0x1210,
+ mwLogin_NOTES_7_0 = 0x1214,
+ mwLogin_ICT = 0x1300,
+ mwLogin_ICT_1_7_8_2 = 0x1302,
+ mwLogin_ICT_SIP = 0x1303,
+ mwLogin_NOTESBUDDY_4_14 = 0x1400, /**< 0xff00 mask? */
+ mwLogin_NOTESBUDDY_4_15 = 0x1405,
+ mwLogin_NOTESBUDDY_4_16 = 0x1406,
+ mwLogin_SANITY = 0x1600,
+ mwLogin_ST_PERL = 0x1625,
+ mwLogin_PMR_ALERT = 0x1650,
+ mwLogin_TRILLIAN = 0x16aa, /**< http://sf.net/st-plugin/ */
+ mwLogin_TRILLIAN_IBM = 0x16bb,
+ mwLogin_MEANWHILE = 0x1700, /**< Meanwhile library */
+};
+
+
+/* 8.2 Common Structures */
+/* 8.2.1 Login Info block */
+
+struct mwLoginInfo {
+ char *login_id; /**< community-unique ID of the login */
+ guint16 type; /**< @see mwLoginType */
+ char *user_id; /**< community-unique ID of the user */
+ char *user_name; /**< name of user (nick name, full name, etc) */
+ char *community; /**< community name (usually domain name) */
+ gboolean full; /**< if FALSE, following fields non-existant */
+ char *desc; /**< implementation defined description */
+ guint32 ip_addr; /**< ip addr of the login */
+ char *server_id; /**< unique ID of login's server */
+};
+
+
+/* 8.2.2 Private Info Block */
+
+struct mwUserItem {
+ gboolean full; /**< if FALSE, don't include name */
+ char *id; /**< user id */
+ char *community; /**< community */
+ char *name; /**< user name */
+};
+
+
+struct mwPrivacyInfo {
+ gboolean deny; /**< deny (true) or allow (false) users */
+ guint32 count; /**< count of users */
+ struct mwUserItem *users; /**< the users list */
+};
+
+
+/* 8.3.5 User Status Types */
+
+enum mwStatusType {
+ mwStatus_ACTIVE = 0x0020,
+ mwStatus_IDLE = 0x0040,
+ mwStatus_AWAY = 0x0060,
+ mwStatus_BUSY = 0x0080,
+};
+
+
+/* 8.2.3 User Status Block */
+
+struct mwUserStatus {
+ guint16 status; /**< @see mwStatusType */
+ guint32 time; /**< last status change time in seconds */
+ char *desc; /**< status description */
+};
+
+
+/* 8.2.4 ID Block */
+
+struct mwIdBlock {
+ char *user; /**< user id (login id or empty for some services) */
+ char *community; /**< community id (NULL for same community) */
+};
+
+
+/* 8.3.8.2 Awareness Presence Types */
+
+/* @todo move mwAwareType, mwAwareIdBlock and mwAwareSnapshot into the
+ aware service and out of common */
+
+/** type codes for mwAwareIdBlock */
+enum mwAwareType {
+ mwAware_USER = 0x0002, /**< a single user */
+ mwAware_GROUP = 0x0003, /**< a group */
+ mwAware_SERVER = 0x0008, /**< a server */
+};
+
+
+/* 8.4.2 Awareness Messages */
+/* 8.4.2.1 Awareness ID Block */
+
+struct mwAwareIdBlock {
+ guint16 type; /**< @see mwAwareType */
+ char *user; /**< user id */
+ char *community; /**< community id (NULL for same community) */
+};
+
+
+/* 8.4.2.4 Snapshot */
+
+struct mwAwareSnapshot {
+ struct mwAwareIdBlock id;
+ char *group; /**< group this id belongs to */
+ gboolean online; /**< is this user online? */
+ char *alt_id; /**< alternate ID, often same as id.user */
+ struct mwUserStatus status; /**< status of this user */
+ char *name; /**< Formatted version of ID */
+};
+
+
+/** encryption blocks */
+struct mwEncryptItem {
+ guint16 id; /**< cipher identifier */
+ struct mwOpaque info; /**< cipher information */
+};
+
+
+/** @name buffer utility functions */
+/*@{*/
+
+
+/** allocate a new empty buffer */
+struct mwPutBuffer *mwPutBuffer_new();
+
+
+/** write raw data to the put buffer */
+void mwPutBuffer_write(struct mwPutBuffer *b, gpointer data, gsize len);
+
+
+/** destroy the buffer */
+void mwPutBuffer_free(struct mwPutBuffer *b);
+
+
+/** move the buffer's data into an opaque, destroy the buffer */
+void mwPutBuffer_finalize(struct mwOpaque *to, struct mwPutBuffer *from);
+
+
+/** allocate a new buffer with a copy of the given data */
+struct mwGetBuffer *mwGetBuffer_new(struct mwOpaque *data);
+
+
+/** read len bytes of raw data from the get buffer into mem. If len is
+ greater than the count of bytes remaining in the buffer, the
+ buffer's error flag will NOT be set.
+
+ @returns count of bytes successfully copied to mem */
+gsize mwGetBuffer_read(struct mwGetBuffer *b, gpointer mem, gsize len);
+
+
+/** skip len bytes in the get buffer. If len is greater than the count
+ of bytes remaining in the buffer, the buffer's error flag will NOT
+ be set.
+
+ @returns count of bytes successfully skipped */
+gsize mwGetBuffer_advance(struct mwGetBuffer *b, gsize len);
+
+
+/** allocate a new buffer backed by the given data. Calling
+ mwGetBuffer_free will not result in the underlying data being
+ freed */
+struct mwGetBuffer *mwGetBuffer_wrap(const struct mwOpaque *data);
+
+
+/** destroy the buffer */
+void mwGetBuffer_free(struct mwGetBuffer *b);
+
+
+/** reset the buffer to the very beginning. Also clears the buffer's
+ error flag. */
+void mwGetBuffer_reset(struct mwGetBuffer *b);
+
+
+/** count of remaining available bytes */
+gsize mwGetBuffer_remaining(struct mwGetBuffer *b);
+
+
+/** TRUE if an error occurred while reading a basic type from this
+ buffer */
+gboolean mwGetBuffer_error(struct mwGetBuffer *b);
+
+
+/*@}*/
+
+
+/** @name Basic Data Types
+ The basic types are combined to construct the compound types.
+ */
+/*@{*/
+
+
+void guint16_put(struct mwPutBuffer *b, guint16 val);
+
+void guint16_get(struct mwGetBuffer *b, guint16 *val);
+
+guint16 guint16_peek(struct mwGetBuffer *b);
+
+
+void guint32_put(struct mwPutBuffer *b, guint32 val);
+
+void guint32_get(struct mwGetBuffer *b, guint32 *val);
+
+guint32 guint32_peek(struct mwGetBuffer *b);
+
+
+void gboolean_put(struct mwPutBuffer *b, gboolean val);
+
+void gboolean_get(struct mwGetBuffer *b, gboolean *val);
+
+gboolean gboolean_peek(struct mwGetBuffer *b);
+
+
+void mwString_put(struct mwPutBuffer *b, const char *str);
+
+void mwString_get(struct mwGetBuffer *b, char **str);
+
+
+void mwOpaque_put(struct mwPutBuffer *b, const struct mwOpaque *o);
+
+void mwOpaque_get(struct mwGetBuffer *b, struct mwOpaque *o);
+
+void mwOpaque_clear(struct mwOpaque *o);
+
+void mwOpaque_free(struct mwOpaque *o);
+
+void mwOpaque_clone(struct mwOpaque *to, const struct mwOpaque *from);
+
+
+/*@}*/
+
+
+/** @name Compound Data Types */
+/*@{*/
+
+
+void mwLoginInfo_put(struct mwPutBuffer *b, const struct mwLoginInfo *info);
+
+void mwLoginInfo_get(struct mwGetBuffer *b, struct mwLoginInfo *info);
+
+void mwLoginInfo_clear(struct mwLoginInfo *info);
+
+void mwLoginInfo_clone(struct mwLoginInfo *to, const struct mwLoginInfo *from);
+
+
+void mwUserItem_put(struct mwPutBuffer *b, const struct mwUserItem *user);
+
+void mwUserItem_get(struct mwGetBuffer *b, struct mwUserItem *user);
+
+void mwUserItem_clear(struct mwUserItem *user);
+
+void mwUserItem_clone(struct mwUserItem *to, const struct mwUserItem *from);
+
+
+void mwPrivacyInfo_put(struct mwPutBuffer *b,
+ const struct mwPrivacyInfo *info);
+
+void mwPrivacyInfo_get(struct mwGetBuffer *b, struct mwPrivacyInfo *info);
+
+void mwPrivacyInfo_clear(struct mwPrivacyInfo *info);
+
+void mwPrivacyInfo_clone(struct mwPrivacyInfo *to,
+ const struct mwPrivacyInfo *from);
+
+
+void mwUserStatus_put(struct mwPutBuffer *b,
+ const struct mwUserStatus *stat);
+
+void mwUserStatus_get(struct mwGetBuffer *b, struct mwUserStatus *stat);
+
+void mwUserStatus_clear(struct mwUserStatus *stat);
+
+void mwUserStatus_clone(struct mwUserStatus *to,
+ const struct mwUserStatus *from);
+
+
+void mwIdBlock_put(struct mwPutBuffer *b, const struct mwIdBlock *id);
+
+void mwIdBlock_get(struct mwGetBuffer *b, struct mwIdBlock *id);
+
+void mwIdBlock_clear(struct mwIdBlock *id);
+
+void mwIdBlock_clone(struct mwIdBlock *to,
+ const struct mwIdBlock *from);
+
+guint mwIdBlock_hash(const struct mwIdBlock *idb);
+
+gboolean mwIdBlock_equal(const struct mwIdBlock *a,
+ const struct mwIdBlock *b);
+
+
+void mwAwareIdBlock_put(struct mwPutBuffer *b,
+ const struct mwAwareIdBlock *idb);
+
+void mwAwareIdBlock_get(struct mwGetBuffer *b, struct mwAwareIdBlock *idb);
+
+void mwAwareIdBlock_clear(struct mwAwareIdBlock *idb);
+
+void mwAwareIdBlock_clone(struct mwAwareIdBlock *to,
+ const struct mwAwareIdBlock *from);
+
+guint mwAwareIdBlock_hash(const struct mwAwareIdBlock *a);
+
+gboolean mwAwareIdBlock_equal(const struct mwAwareIdBlock *a,
+ const struct mwAwareIdBlock *b);
+
+
+void mwAwareSnapshot_get(struct mwGetBuffer *b,
+ struct mwAwareSnapshot *idb);
+
+void mwAwareSnapshot_clear(struct mwAwareSnapshot *idb);
+
+void mwAwareSnapshot_clone(struct mwAwareSnapshot *to,
+ const struct mwAwareSnapshot *from);
+
+
+void mwEncryptItem_put(struct mwPutBuffer *b,
+ const struct mwEncryptItem *item);
+
+void mwEncryptItem_get(struct mwGetBuffer *b, struct mwEncryptItem *item);
+
+void mwEncryptItem_clear(struct mwEncryptItem *item);
+
+void mwEncryptItem_free(struct mwEncryptItem *item);
+
+
+/*@}*/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _MW_COMMON_H */
diff --git a/protocols/Sametime/src/meanwhile/src/mw_debug.c b/protocols/Sametime/src/meanwhile/src/mw_debug.c
new file mode 100644
index 0000000000..cf47a38e38
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/mw_debug.c
@@ -0,0 +1,184 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#include <glib/gstring.h>
+
+#include "mw_debug.h"
+
+
+
+#define FRMT1 "%02x"
+#define FRMT2 FRMT1 FRMT1 " "
+#define FRMT4 FRMT2 FRMT2
+#define FRMT8 FRMT4 FRMT4
+#define FRMT16 FRMT8 FRMT8
+
+#define ADVANCE(b, n, c) {b += c; n -= c;}
+
+
+
+/** writes hex pairs of buf to str */
+static void pretty_print(GString *str, const guchar *buf, gsize len) {
+ while(len >= 16) {
+ /* write a complete line */
+ g_string_append_printf(str, FRMT16,
+ buf[0], buf[1], buf[2], buf[3],
+ buf[4], buf[5], buf[6], buf[7],
+ buf[8], buf[9], buf[10], buf[11],
+ buf[12], buf[13], buf[14], buf[15]);
+ ADVANCE(buf, len, 16);
+
+ /* append \n to each line but the last */
+ if(len) g_string_append(str, "\n");
+ }
+
+ /* write an incomplete line */
+ if(len >= 8) {
+ g_string_append_printf(str, FRMT8,
+ buf[0], buf[1], buf[2], buf[3],
+ buf[4], buf[5], buf[6], buf[7]);
+ ADVANCE(buf, len, 8);
+ }
+
+ if(len >= 4) {
+ g_string_append_printf(str, FRMT4,
+ buf[0], buf[1], buf[2], buf[3]);
+ ADVANCE(buf, len, 4);
+ }
+
+ if(len >= 2) {
+ g_string_append_printf(str, FRMT2, buf[0], buf[1]);
+ ADVANCE(buf, len, 2);
+ }
+
+ if(len >= 1) {
+ g_string_append_printf(str, FRMT1, buf[0]);
+ ADVANCE(buf, len, 1);
+ }
+}
+
+
+
+void mw_debug_datav(const guchar *buf, gsize len,
+ const char *msg, va_list args) {
+ GString *str;
+
+ g_return_if_fail(buf != NULL || len == 0);
+
+ str = g_string_new(NULL);
+
+ if(msg) {
+ char *txt = g_strdup_vprintf(msg, args);
+ g_string_append_printf(str, "%s\n", txt);
+ g_free(txt);
+ }
+ pretty_print(str, buf, len);
+
+ g_debug(str->str);
+ g_string_free(str, TRUE);
+}
+
+
+
+void mw_debug_data(const guchar *buf, gsize len,
+ const char *msg, ...) {
+ va_list args;
+
+ g_return_if_fail(buf != NULL || len == 0);
+
+ va_start(args, msg);
+ mw_debug_datav(buf, len, msg, args);
+ va_end(args);
+}
+
+
+
+void mw_debug_opaquev(struct mwOpaque *o, const char *txt, va_list args) {
+ g_return_if_fail(o != NULL);
+ mw_debug_datav(o->data, o->len, txt, args);
+}
+
+
+
+void mw_debug_opaque(struct mwOpaque *o, const char *txt, ...) {
+ va_list args;
+
+ g_return_if_fail(o != NULL);
+
+ va_start(args, txt);
+ mw_debug_opaquev(o, txt, args);
+ va_end(args);
+}
+
+
+void mw_mailme_datav(const guchar *buf, gsize len,
+ const char *info, va_list args) {
+
+#if MW_MAILME
+ GString *str;
+ char *txt;
+
+ str = g_string_new(MW_MAILME_MESSAGE "\n"
+ " Please send mail to: " MW_MAILME_ADDRESS "\n"
+ MW_MAILME_CUT_START "\n");
+ str = g_string_new(NULL);
+
+ txt = g_strdup_vprintf(info, args);
+ g_string_append_printf(str, "%s\n", txt);
+ g_free(txt);
+
+ if(buf && len) pretty_print(str, buf, len);
+
+ g_string_append(str, MW_MAILME_CUT_STOP);
+
+ g_debug(str->str);
+ g_string_free(str, TRUE);
+
+#else
+ mw_debug_datav(buf, len, info, args);
+
+#endif
+}
+
+
+
+void mw_mailme_data(const guchar *buf, gsize len,
+ const char *info, ...) {
+ va_list args;
+ va_start(args, info);
+ mw_mailme_datav(buf, len, info, args);
+ va_end(args);
+}
+
+
+
+void mw_mailme_opaquev(struct mwOpaque *o, const char *info, va_list args) {
+ mw_mailme_datav(o->data, o->len, info, args);
+}
+
+
+
+void mw_mailme_opaque(struct mwOpaque *o, const char *info, ...) {
+ va_list args;
+ va_start(args, info);
+ mw_mailme_opaquev(o, info, args);
+ va_end(args);
+}
diff --git a/protocols/Sametime/src/meanwhile/src/mw_debug.h b/protocols/Sametime/src/meanwhile/src/mw_debug.h
new file mode 100644
index 0000000000..acd7455eec
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/mw_debug.h
@@ -0,0 +1,130 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _MW_DEBUG_H
+#define _MW_DEBUG_H
+
+
+#include <stdarg.h>
+#include <glib.h>
+
+#include "mw_common.h"
+
+
+/** replaces NULL strings with "(null)". useful for printf where
+ you're unsure that the %s will be non-NULL. Note that while the
+ linux printf will do this automatically, not all will. The others
+ will instead segfault */
+#define NSTR(str) ((str)? (str): "(null)")
+
+
+// Miranda NG adaptation, MSVC
+// #ifndef g_debug
+// #define g_debug(format...) g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format)
+// #endif
+
+
+// Miranda NG adaptation, MSVC
+// #ifndef g_info
+// #define g_info(format...) g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
+// #endif
+
+
+#ifndef MW_MAILME_ADDRESS
+/** email address used in mw_debug_mailme. */
+#define MW_MAILME_ADDRESS "meanwhile-devel@lists.sourceforge.net"
+#endif
+
+
+#ifndef MW_MAILME_CUT_START
+#define MW_MAILME_CUT_START "-------- begin copy --------"
+#endif
+
+
+#ifndef MW_MAILME_CUT_STOP
+#define MW_MAILME_CUT_STOP "--------- end copy ---------"
+#endif
+
+
+#ifndef MW_MAILME_MESSAGE
+/** message used in mw_debug_mailme instructing user on what to do
+ with the debugging output produced from that function */
+#define MW_MAILME_MESSAGE "\n" \
+ " Greetings! It seems that you've run across protocol data that the\n" \
+ "Meanwhile library does not yet know about. As such, there may be\n" \
+ "some unexpected behaviour in this session. If you'd like to help\n" \
+ "resolve this issue, please copy and paste the following block into\n" \
+ "an email to the address listed below with a brief explanation of\n" \
+ "what you were doing at the time of this message. Thanks a lot!"
+#endif
+
+
+void mw_debug_datav(const guchar *buf, gsize len,
+ const char *info, va_list args);
+
+
+void mw_debug_data(const guchar *buf, gsize len,
+ const char *info, ...);
+
+
+void mw_debug_opaquev(struct mwOpaque *o, const char *info, va_list args);
+
+
+void mw_debug_opaque(struct mwOpaque *o, const char *info, ...);
+
+
+void mw_mailme_datav(const guchar *buf, gsize len,
+ const char *info, va_list args);
+
+void mw_mailme_data(const guchar *buf, gsize len,
+ const char *info, ...);
+
+
+/** Outputs a hex dump of a mwOpaque with debugging info and a
+ pre-defined message. Identical to mw_mailme_opaque, but taking a
+ va_list argument */
+void mw_mailme_opaquev(struct mwOpaque *o, const char *info, va_list args);
+
+
+
+/** Outputs a hex dump of a mwOpaque with debugging info and a
+ pre-defined message.
+
+ if MW_MAILME is undefined or false, this function acts the same as
+ mw_mailme_opaque.
+
+ @arg block data to be printed in a hex block
+ @arg info a printf-style format string
+
+ The resulting message is in the following format:
+ @code
+ MW_MAILME_MESSAGE
+ " Please send mail to: " MW_MAILME_ADDRESS
+ MW_MAILME_CUT_START
+ info
+ block
+ MW_MAILME_CUT_STOP
+ @endcode
+ */
+void mw_mailme_opaque(struct mwOpaque *o, const char *info, ...);
+
+
+#endif
+
diff --git a/protocols/Sametime/src/meanwhile/src/mw_error.h b/protocols/Sametime/src/meanwhile/src/mw_error.h
new file mode 100644
index 0000000000..6345358561
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/mw_error.h
@@ -0,0 +1,174 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _MW_ERROR_H
+#define _MW_ERROR_H
+
+
+/** @file mw_error.h
+
+ Common error code constants used by Meanwhile.
+
+ Not all of these error codes (or even many, really) will ever
+ actually appear from Meanwhile. These are taken directly from the
+ houri draft, along with the minimal explanation for each.
+*/
+
+
+#include <glib.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** reference to a new string appropriate for the given error code.*/
+char* mwError(guint32 code);
+
+
+/* 8.3 Constants */
+/* 8.3.1 Error Codes */
+/* 8.3.1.1 General error/success codes */
+
+/** @enum ERR_GENERAL
+ general error codes */
+enum ERR_GENERAL {
+ ERR_SUCCESS = 0x00000000,
+ ERR_FAILURE = 0x80000000,
+ ERR_REQUEST_DELAY = 0x00000001,
+ ERR_REQUEST_INVALID = 0x80000001,
+ ERR_NOT_LOGGED_IN = 0x80000002,
+ ERR_NOT_AUTHORIZED = 0x80000003,
+ ERR_ABORT = 0x80000004,
+ ERR_NO_ELEMENT = 0x80000005,
+ ERR_NO_USER = 0x80000006,
+ ERR_BAD_DATA = 0x80000007,
+ ERR_NOT_IMPLEMENTED = 0x80000008,
+ ERR_UNKNOWN_ERROR = 0x80000009, /* what is this? */
+ ERR_STARVING = 0x8000000a,
+ ERR_CHANNEL_NO_SUPPORT = 0x8000000b,
+ ERR_CHANNEL_EXISTS = 0x8000000c,
+ ERR_SERVICE_NO_SUPPORT = 0x8000000d,
+ ERR_PROTOCOL_NO_SUPPORT = 0x8000000e,
+ ERR_PROTOCOL_NO_SUPPORT2 = 0x8000000f, /* duplicate? */
+ ERR_VERSION_NO_SUPPORT = 0x80000010,
+ ERR_USER_SKETCHY = 0x80000011,
+ ERR_ALREADY_INITIALIZED = 0x80000013,
+ ERR_NOT_OWNER = 0x80000014,
+ ERR_TOKEN_INVALID = 0x80000015,
+ ERR_TOKEN_EXPIRED = 0x80000016,
+ ERR_TOKEN_IP_MISMATCH = 0x80000017,
+ ERR_PORT_IN_USE = 0x80000018,
+ ERR_NETWORK_DEAD = 0x80000019,
+ ERR_NO_MASTER_CHANNEL = 0x8000001a,
+ ERR_ALREADY_SUBSCRIBED = 0x8000001b,
+ ERR_NOT_SUBSCRIBED = 0x8000001c,
+ ERR_ENCRYPT_NO_SUPPORT = 0x8000001d,
+ ERR_ENCRYPT_UNINITIALIZED = 0x8000001e,
+ ERR_ENCRYPT_UNACCEPTABLE = 0x8000001f,
+ ERR_ENCRYPT_INVALID = 0x80000020,
+ ERR_NO_COMMON_ENCRYPT = 0x80000021,
+ ERR_CHANNEL_DESTROYED = 0x80000022,
+ ERR_CHANNEL_REDIRECTED = 0x80000023
+};
+
+
+/* 8.3.1.2 Connection/disconnection errors */
+
+#define VERSION_MISMATCH 0x80000200
+#define INSUF_BUFFER 0x80000201
+#define NOT_IN_USE 0x80000202
+#define INSUF_SOCKET 0x80000203
+#define HARDWARE_ERROR 0x80000204
+#define NETWORK_DOWN 0x80000205
+#define HOST_DOWN 0x80000206
+#define HOST_UNREACHABLE 0x80000207
+#define TCPIP_ERROR 0x80000208
+#define FAT_MESSAGE 0x80000209
+#define PROXY_ERROR 0x8000020A
+#define SERVER_FULL 0x8000020B
+#define SERVER_NORESPOND 0x8000020C
+#define CANT_CONNECT 0x8000020D
+#define USER_REMOVED 0x8000020E
+#define PROTOCOL_ERROR 0x8000020F
+#define USER_RESTRICTED 0x80000210
+#define INCORRECT_LOGIN 0x80000211
+#define ENCRYPT_MISMATCH 0x80000212
+#define USER_UNREGISTERED 0x80000213
+#define VERIFICATION_DOWN 0x80000214
+#define USER_TOO_IDLE 0x80000216
+#define GUEST_IN_USE 0x80000217
+#define USER_EXISTS 0x80000218
+#define USER_RE_LOGIN 0x80000219
+#define BAD_NAME 0x8000021A
+#define REG_MODE_NS 0x8000021B
+#define WRONG_USER_PRIV 0x8000021C
+#define NEED_EMAIL 0x8000021D
+#define DNS_ERROR 0x8000021E
+#define DNS_FATAL_ERROR 0x8000021F
+#define DNS_NOT_FOUND 0x80000220
+#define CONNECTION_BROKEN 0x80000221
+#define CONNECTION_ABORTED 0x80000222
+#define CONNECTION_REFUSED 0x80000223
+#define CONNECTION_RESET 0x80000224
+#define CONNECTION_TIMED 0x80000225
+#define CONNECTION_CLOSED 0x80000226
+#define MULTI_SERVER_LOGIN 0x80000227
+#define MULTI_SERVER_LOGIN2 0x80000228
+#define MULTI_LOGIN_COMP 0x80000229
+#define MUTLI_LOGIN_ALREADY 0x8000022A
+#define SERVER_BROKEN 0x8000022B
+#define SERVER_PATH_OLD 0x8000022C
+#define APPLET_LOGOUT 0x8000022D
+
+
+/* 8.3.1.3 Client error codes */
+
+/** @enum ERR_CLIENT
+ Client error codes */
+enum ERR_CLIENT {
+ ERR_CLIENT_USER_GONE = 0x80002000, /* user isn't here */
+ ERR_CLIENT_USER_DND = 0x80002001, /* user is DND */
+ ERR_CLIENT_USER_ELSEWHERE = 0x80002002, /* already logged in elsewhere */
+};
+
+
+/* 8.3.1.4 IM error codes */
+
+/** @enum ERR_IM
+ IM error codes */
+enum ERR_IM {
+ ERR_IM_COULDNT_REGISTER = 0x80002003,
+ ERR_IM_ALREADY_REGISTERED = 0x80002004,
+
+ /** apparently, this is used to mean that the requested feature (per
+ the channel create addtl data) is not supported by the client on
+ the other end of the IM channel */
+ ERR_IM_NOT_REGISTERED = 0x80002005,
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _MW_ERROR_H */
diff --git a/protocols/Sametime/src/meanwhile/src/mw_message.h b/protocols/Sametime/src/meanwhile/src/mw_message.h
new file mode 100644
index 0000000000..8402b8b7ee
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/mw_message.h
@@ -0,0 +1,305 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _MW_MESSAGE_H
+#define _MW_MESSAGE_H
+
+
+#include <glib/glist.h>
+#include "mw_common.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** Cast a pointer to a message subtype (eg, mwMsgHandshake,
+ mwMsgAdmin) into a pointer to a mwMessage */
+#define MW_MESSAGE(msg) (&msg->head)
+
+
+/** Indicates the type of a message. */
+enum mwMessageType {
+ mwMessage_HANDSHAKE = 0x0000, /**< mwMsgHandshake */
+ mwMessage_HANDSHAKE_ACK = 0x8000, /**< mwMsgHandshakeAck */
+ mwMessage_LOGIN = 0x0001, /**< mwMsgLogin */
+ mwMessage_LOGIN_ACK = 0x8001, /**< mwMsgLoginAck */
+ mwMessage_LOGIN_REDIRECT = 0x0018, /**< mwMsgLoginRedirect */
+ mwMessage_LOGIN_CONTINUE = 0x0016, /**< mwMsgLoginContinue */
+
+ mwMessage_CHANNEL_CREATE = 0x0002, /**< mwMsgChannelCreate */
+ mwMessage_CHANNEL_DESTROY = 0x0003, /**< mwMsgChannelDestroy */
+ mwMessage_CHANNEL_SEND = 0x0004, /**< mwMsgChannelSend */
+ mwMessage_CHANNEL_ACCEPT = 0x0006, /**< mwMsgChannelAccept */
+
+ mwMessage_SET_USER_STATUS = 0x0009, /**< mwMsgSetUserStatus */
+ mwMessage_SET_PRIVACY_LIST = 0x000b, /**< mwMsgSetPrivacyList */
+ mwMessage_SENSE_SERVICE = 0x0011, /**< mwMsgSenseService */
+ mwMessage_ADMIN = 0x0019, /**< mwMsgAdmin */
+ mwMessage_ANNOUNCE = 0x0022, /**< mwMsgAnnounce */
+};
+
+
+enum mwMessageOption {
+ mwMessageOption_ENCRYPT = 0x4000, /**< message data is encrypted */
+ mwMessageOption_HAS_ATTRIBS = 0x8000, /**< message has attributes */
+};
+
+
+/** @see mwMessageOption */
+#define MW_MESSAGE_HAS_OPTION(msg, opt) \
+ ((msg)->options & (opt))
+
+
+struct mwMessage {
+ guint16 type; /**< @see mwMessageType */
+ guint16 options; /**< @see mwMessageOption */
+ guint32 channel; /**< ID of channel message is intended for */
+ struct mwOpaque attribs; /**< optional message attributes */
+};
+
+
+
+/** Allocate and initialize a new message of the specified type */
+struct mwMessage *mwMessage_new(enum mwMessageType type);
+
+
+/** build a message from its representation */
+struct mwMessage *mwMessage_get(struct mwGetBuffer *b);
+
+
+void mwMessage_put(struct mwPutBuffer *b, struct mwMessage *msg);
+
+
+void mwMessage_free(struct mwMessage *msg);
+
+
+/* 8.4 Messages */
+/* 8.4.1 Basic Community Messages */
+/* 8.4.1.1 Handshake */
+
+struct mwMsgHandshake {
+ struct mwMessage head;
+ guint16 major; /**< client's major version number */
+ guint16 minor; /**< client's minor version number */
+ guint32 srvrcalc_addr; /**< 0.0.0.0 */
+ guint16 login_type; /**< @see mwLoginType */
+ guint32 loclcalc_addr; /**< local public IP */
+ guint16 unknown_a; /**< normally 0x0100 */
+ guint32 unknown_b; /**< normally 0x00000000 */
+ char *local_host; /**< name of client host */
+};
+
+
+/* 8.4.1.2 HandshakeAck */
+
+struct mwMsgHandshakeAck {
+ struct mwMessage head;
+ guint16 major; /**< server's major version number */
+ guint16 minor; /**< server's minor version number */
+ guint32 srvrcalc_addr; /**< server-calculated address */
+ guint32 magic; /**< four bytes of something */
+ struct mwOpaque data; /**< server's DH public key for auth */
+};
+
+
+/* 8.3.7 Authentication Types */
+
+enum mwAuthType {
+ mwAuthType_PLAIN = 0x0000,
+ mwAuthType_TOKEN = 0x0001,
+ mwAuthType_ENCRYPT = 0x0002, /**< @todo remove for 1.0 */
+ mwAuthType_RC2_40 = 0x0002,
+ mwAuthType_RC2_128 = 0x0004,
+};
+
+
+/* 8.4.1.3 Login */
+
+struct mwMsgLogin {
+ struct mwMessage head;
+ guint16 login_type; /**< @see mwLoginType */
+ char *name; /**< user identification */
+ guint16 auth_type; /**< @see mwAuthType */
+ struct mwOpaque auth_data; /**< authentication data */
+};
+
+
+/* 8.4.1.4 LoginAck */
+
+struct mwMsgLoginAck {
+ struct mwMessage head;
+ struct mwLoginInfo login;
+ struct mwPrivacyInfo privacy;
+ struct mwUserStatus status;
+};
+
+
+/* 8.4.1.5 LoginCont */
+
+struct mwMsgLoginContinue {
+ struct mwMessage head;
+};
+
+
+/* 8.4.1.6 AuthPassed */
+
+struct mwMsgLoginRedirect {
+ struct mwMessage head;
+ char *host;
+ char *server_id;
+};
+
+
+/* 8.4.1.7 CreateCnl */
+
+/** an offer of encryption items */
+struct mwEncryptOffer {
+ guint16 mode; /**< encryption mode */
+ GList *items; /**< list of mwEncryptItem offered */
+ guint16 extra; /**< encryption mode again? */
+ gboolean flag; /**< unknown flag */
+};
+
+
+struct mwMsgChannelCreate {
+ struct mwMessage head;
+ guint32 reserved; /**< unknown reserved data */
+ guint32 channel; /**< intended ID for new channel */
+ struct mwIdBlock target; /**< User ID. for service use */
+ guint32 service; /**< ID for the target service */
+ guint32 proto_type; /**< protocol type for the service */
+ guint32 proto_ver; /**< protocol version for the service */
+ guint32 options; /**< options */
+ struct mwOpaque addtl; /**< service-specific additional data */
+ gboolean creator_flag; /**< indicate presence of creator information */
+ struct mwLoginInfo creator;
+ struct mwEncryptOffer encrypt;
+};
+
+
+/* 8.4.1.8 AcceptCnl */
+
+/** a selected encryption item from those offered */
+struct mwEncryptAccept {
+ guint16 mode; /**< encryption mode */
+ struct mwEncryptItem *item; /**< chosen mwEncryptItem (optional) */
+ guint16 extra; /**< encryption mode again? */
+ gboolean flag; /**< unknown flag */
+};
+
+
+struct mwMsgChannelAccept {
+ struct mwMessage head;
+ guint32 service; /**< ID for the channel's service */
+ guint32 proto_type; /**< protocol type for the service */
+ guint32 proto_ver; /**< protocol version for the service */
+ struct mwOpaque addtl; /**< service-specific additional data */
+ gboolean acceptor_flag; /**< indicate presence of acceptor information */
+ struct mwLoginInfo acceptor;
+ struct mwEncryptAccept encrypt;
+};
+
+
+/* 8.4.1.9 SendOnCnl */
+
+struct mwMsgChannelSend {
+ struct mwMessage head;
+
+ /** message type. each service defines its own send types. Type IDs
+ are only necessarily unique within a given service. */
+ guint16 type;
+
+ /** protocol data to be interpreted by the handling service */
+ struct mwOpaque data;
+};
+
+
+/* 8.4.1.10 DestroyCnl */
+
+struct mwMsgChannelDestroy {
+ struct mwMessage head;
+ guint32 reason; /**< reason for closing the channel. */
+ struct mwOpaque data; /**< additional information */
+};
+
+
+/* 8.4.1.11 SetUserStatus */
+
+struct mwMsgSetUserStatus {
+ struct mwMessage head;
+ struct mwUserStatus status;
+};
+
+
+/* 8.4.1.12 SetPrivacyList */
+
+struct mwMsgSetPrivacyList {
+ struct mwMessage head;
+ struct mwPrivacyInfo privacy;
+};
+
+
+/* Sense Service */
+
+/** Sent to the server to request the presense of a service by its
+ ID. Sent to the client to indicate the presense of such a
+ service */
+struct mwMsgSenseService {
+ struct mwMessage head;
+ guint32 service;
+};
+
+
+/* Admin */
+
+/** An administrative broadcast message */
+struct mwMsgAdmin {
+ struct mwMessage head;
+ char *text;
+};
+
+
+/* Announce */
+
+/** An announcement between users */
+struct mwMsgAnnounce {
+ struct mwMessage head;
+ gboolean sender_present; /**< indicates presence of sender data */
+ struct mwLoginInfo sender; /**< who sent the announcement */
+ guint16 unknown_a; /**< unknown A. Usually 0x00 */
+ gboolean may_reply; /**< replies allowed */
+ char *text; /**< text of message */
+
+ /** list of (char *) indicating recipients. Recipient users are in
+ the format "@U username" and recipient NAB groups are in the
+ format "@G groupname" */
+ GList *recipients;
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _MW_MESSAGE_H */
+
diff --git a/protocols/Sametime/src/meanwhile/src/mw_service.h b/protocols/Sametime/src/meanwhile/src/mw_service.h
new file mode 100644
index 0000000000..9bcd6509db
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/mw_service.h
@@ -0,0 +1,370 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _MW_SERVICE_H
+#define _MW_SERVICE_H
+
+
+#include "mw_common.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* place-holders */
+struct mwChannel;
+struct mwService;
+struct mwSession;
+struct mwMsgChannelCreate;
+struct mwMsgChannelAccept;
+struct mwMsgChannelDestroy;
+
+
+/** State-tracking for a service */
+enum mwServiceState {
+ mwServiceState_STOPPED, /**< the service is not active */
+ mwServiceState_STOPPING, /**< the service is shutting down */
+ mwServiceState_STARTED, /**< the service is active */
+ mwServiceState_STARTING, /**< the service is starting up */
+ mwServiceState_ERROR, /**< error in service, shutting down */
+ mwServiceState_UNKNOWN, /**< error determining state */
+};
+
+
+/** Casts a concrete service (such as mwServiceAware) into a mwService */
+#define MW_SERVICE(srv) ((struct mwService *) srv)
+
+
+#define MW_SERVICE_IS_STATE(srvc, state) \
+ (mwService_getState(MW_SERVICE(srvc)) == (state))
+
+#define MW_SERVICE_IS_STOPPED(srvc) \
+ MW_SERVICE_IS_STATE(srvc, mwServiceState_STOPPED)
+
+#define MW_SERVICE_IS_STOPPING(srvc) \
+ MW_SERVICE_IS_STATE(srvc, mwServiceState_STOPPING)
+
+#define MW_SERVICE_IS_STARTED(srvc) \
+ MW_SERVICE_IS_STATE(srvc, mwServiceState_STARTED)
+
+#define MW_SERVICE_IS_STARTING(srvc) \
+ MW_SERVICE_IS_STATE(srvc, mwServiceState_STARTING)
+
+
+/** If a service is STARTING or STARTED, it's considered LIVE */
+#define MW_SERVICE_IS_LIVE(srvc) \
+ (MW_SERVICE_IS_STARTING(srvc) || MW_SERVICE_IS_STARTED(srvc))
+
+/** If a service is STOPPING or STOPPED, it's considered DEAD */
+#define MW_SERVICE_IS_DEAD(srvc) \
+ (MW_SERVICE_IS_STOPPING(srvc) || MW_SERVICE_IS_STOPPED(srvc))
+
+
+typedef void (*mwService_funcStart)(struct mwService *service);
+
+typedef void (*mwService_funcStop)(struct mwService *service);
+
+typedef void (*mwService_funcClear)(struct mwService *service);
+
+typedef const char *(*mwService_funcGetName)(struct mwService *service);
+
+typedef const char *(*mwService_funcGetDesc)(struct mwService *service);
+
+/** @todo remove msg and replace with appropriate additional parameters */
+typedef void (*mwService_funcRecvCreate)
+ (struct mwService *service,
+ struct mwChannel *channel,
+ struct mwMsgChannelCreate *msg);
+
+/** @todo remove msg and replace with appropriate additional parameters */
+typedef void (*mwService_funcRecvAccept)
+ (struct mwService *service,
+ struct mwChannel *channel,
+ struct mwMsgChannelAccept *msg);
+
+/** @todo remove msg and replace with appropriate additional parameters */
+typedef void (*mwService_funcRecvDestroy)
+ (struct mwService *service,
+ struct mwChannel *channel,
+ struct mwMsgChannelDestroy *msg);
+
+typedef void (*mwService_funcRecv)
+ (struct mwService *service,
+ struct mwChannel *channel,
+ guint16 msg_type,
+ struct mwOpaque *data);
+
+
+/** A service is the recipient of sendOnCnl messages sent over
+ channels marked with the corresponding service id. Services
+ provide functionality such as IM relaying, Awareness tracking and
+ notification, and Conference handling. It is a service's
+ responsibility to accept or destroy channels, and to process data
+ sent over those channels */
+struct mwService {
+
+ /** the unique identifier by which this service is registered. The
+ type value also relates to those channels which will be directed
+ to this service */
+ guint32 type;
+
+ /** the state of this service. Determines whether or not the session
+ should call the start function upon receipt of a service
+ available message. Should not be set or checked by hand.
+
+ @relates mwService_getState */
+ enum mwServiceState state;
+
+ /** session this service is attached to.
+ @relates mwService_getSession */
+ struct mwSession *session;
+
+ /** @return string short name of the service
+ @relates mwService_getName */
+ mwService_funcGetName get_name;
+
+ /** @return string short description of the service
+ @relates mwService_getDesc */
+ mwService_funcGetDesc get_desc;
+
+ /** The service's channel create handler. Called when the session
+ receives a channel create message with a service matching this
+ service's type.
+
+ @relates mwService_recvCreate */
+ mwService_funcRecvCreate recv_create;
+
+ /** The service's channel accept handler. Called when the session
+ receives a channel accept message for a channel with a service
+ matching this service's type.
+
+ @relates mwService_recvAccept */
+ mwService_funcRecvAccept recv_accept;
+
+ /** The service's channel destroy handler. Called when the session
+ receives a channel destroy message for a channel with a service
+ matching this service's type.
+
+ @relates mwService_recvDestroy */
+ mwService_funcRecvDestroy recv_destroy;
+
+ /** The service's input handler. Called when the session receives
+ data on a channel belonging to this service
+
+ @relates mwService_recv */
+ mwService_funcRecv recv;
+
+ /** The service's start handler. Called upon the receipt of a
+ service available message.
+
+ @relates mwService_start */
+ mwService_funcStart start;
+
+ /** The service's stop handler. Called when the session is shutting
+ down, or when the service is free'd.
+
+ @relates mwService_stop */
+ mwService_funcStop stop;
+
+ /** The service's cleanup handler. Service implementations should
+ presume that mwService::stop will be called first. The clear
+ handler is not for shutting down channels or generating
+ non-cleanup side-effects, it is only for handling tear-down of
+ the service, and will only be called once for any instance.
+
+ @relates mwService_free */
+ mwService_funcClear clear;
+
+ /** Optional client data, not for use by service implementations
+
+ @relates mwService_getClientData
+ @relates mwService_setClientData */
+ gpointer client_data;
+
+ /** Optional client data cleanup function. Called with client_data
+ from mwService_free
+
+ @relates mwService_getClientData
+ @relates mwService_setClientData */
+ GDestroyNotify client_cleanup;
+};
+
+
+/** @name Service Extension API
+
+ These functions are for use by service implementations */
+/*@{*/
+
+
+/** Prepares a newly allocated service for use.
+
+ Intended for use by service implementations, rather than by code
+ utilizing a service.
+
+ The service state will be initialized to STOPPED.
+
+ @param service the service to initialize
+ @param session the service's owning session
+ @param service_type the service ID number */
+void mwService_init(struct mwService *service,
+ struct mwSession *session,
+ guint32 service_type);
+
+
+/** Indicate that a service is started. To be used by service
+ implementations when the service is fully started. */
+void mwService_started(struct mwService *service);
+
+
+/** Indicate that a service is stopped. To be used by service
+ implementations when the service is fully stopped. */
+void mwService_stopped(struct mwService *service);
+
+
+/*@}*/
+
+
+/** @name General Services API
+
+ These functions provide unified access to the general functions of
+ a client service, with some simple sanity-checking. */
+/*@{*/
+
+
+/** Triggers the recv_create handler on the service.
+
+ @param service the service to handle the message
+ @param channel the channel being created
+ @param msg the channel create message */
+void mwService_recvCreate(struct mwService *service,
+ struct mwChannel *channel,
+ struct mwMsgChannelCreate *msg);
+
+
+/** Triggers the recv_accept handler on the service.
+
+ @param service the service to handle the message
+ @param channel the channel being accepted
+ @param msg the channel accept message */
+void mwService_recvAccept(struct mwService *service,
+ struct mwChannel *channel,
+ struct mwMsgChannelAccept *msg);
+
+
+/** Triggers the recv_destroy handler on the service.
+
+ @param service the service to handle the message
+ @param channel the channel being destroyed
+ @param msg the channel destroy message */
+void mwService_recvDestroy(struct mwService *service,
+ struct mwChannel *channel,
+ struct mwMsgChannelDestroy *msg);
+
+
+/** Triggers the input handler on the service
+
+ @param service the service to receive the input
+ @param channel the channel the input was received from
+ @param msg_type the service-dependant message type
+ @param data the message data */
+void mwService_recv(struct mwService *service,
+ struct mwChannel *channel,
+ guint16 msg_type,
+ struct mwOpaque *data);
+
+
+/** @return the appropriate type id for the service */
+guint32 mwService_getType(struct mwService *);
+
+
+/** @return string short name of the service */
+const char *mwService_getName(struct mwService *);
+
+
+/** @return string short description of the service */
+const char *mwService_getDesc(struct mwService *);
+
+
+/** @return the service's session */
+struct mwSession *mwService_getSession(struct mwService *service);
+
+
+/** @returns the service's state
+*/
+enum mwServiceState mwService_getState(struct mwService *service);
+
+
+/** Triggers the start handler for the service. Normally called from
+ the session upon receipt of a service available message. Service
+ implementations should use this handler to open any necessary
+ channels, etc. Checks that the service is STOPPED, or returns.
+
+ @param service The service to start
+*/
+void mwService_start(struct mwService *service);
+
+
+/** Triggers the stop handler for the service. Normally called from
+ the session before closing down the connection. Checks that the
+ service is STARTED or STARTING, or returns
+
+ @param service The service to stop
+*/
+void mwService_stop(struct mwService *service);
+
+
+/** Frees memory used by a service. Will trigger the stop handler if
+ the service is STARTED or STARTING. Triggers clear handler to allow
+ cleanup.
+
+ @param service The service to clear and free
+*/
+void mwService_free(struct mwService *service);
+
+
+/** Associates client data with service. If there is existing data, it
+ will not have its cleanup function called. Client data is not for
+ use by service implementations. Rather, it is for use by client
+ code which may later make use of those service implementations. */
+void mwService_setClientData(struct mwService *service,
+ gpointer data, GDestroyNotify cleanup);
+
+
+/** Reference associated client data */
+gpointer mwService_getClientData(struct mwService *service);
+
+
+/** Removes client data from service. If there is a cleanup function,
+ it will be called. */
+void mwService_removeClientData(struct mwService *service);
+
+
+/*@}*/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _MW_SERVICE_H */
+
diff --git a/protocols/Sametime/src/meanwhile/src/mw_session.h b/protocols/Sametime/src/meanwhile/src/mw_session.h
new file mode 100644
index 0000000000..e606e0ca98
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/mw_session.h
@@ -0,0 +1,397 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _MW_SESSION_H
+#define _MW_SESSION_H
+
+
+/** @file mw_session.h
+
+ A client session with a Sametime server is encapsulated in the
+ mwSession structure. The session controls channels, provides
+ encryption ciphers, and manages services using messages over the
+ Master channel.
+
+ A session does not directly communicate with a socket or stream,
+ instead the session is initialized from client code with an
+ instance of a mwSessionHandler structure. This session handler
+ provides functions as call-backs for common session events, and
+ provides functions for writing-to and closing the connection to
+ the server.
+
+ A session does not perform reads on a socket directly. Instead, it
+ must be fed from an outside source via the mwSession_recv
+ function. The session will buffer and merge data passed to this
+ function to build complete protocol messages, and will act upon
+ each complete message accordingly.
+*/
+
+
+#include "mw_common.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+struct mwChannelSet;
+struct mwCipher;
+struct mwMessage;
+struct mwService;
+
+
+/** default protocol major version */
+#define MW_PROTOCOL_VERSION_MAJOR 0x001e
+
+
+/** default protocol minor version */
+#define MW_PROTOCOL_VERSION_MINOR 0x001d
+
+
+/** @section Session Properties
+ for use with mwSession_setProperty, et al.
+*/
+/*@{*/
+
+/** char *, session user ID */
+#define mwSession_AUTH_USER_ID "session.auth.user"
+
+/** char *, plaintext password */
+#define mwSession_AUTH_PASSWORD "session.auth.password"
+
+/** struct mwOpaque *, authentication token */
+#define mwSession_AUTH_TOKEN "session.auth.token"
+
+/** char *, hostname of client */
+#define mwSession_CLIENT_HOST "client.host"
+
+/** guint32, local IP of client */
+#define mwSession_CLIENT_IP "client.ip"
+
+/** guint16, major version of client protocol */
+#define mwSession_CLIENT_VER_MAJOR "client.version.major"
+
+/** guint16, minor version of client protocol */
+#define mwSession_CLIENT_VER_MINOR "client.version.minor"
+
+/** guint16, client type identifier */
+#define mwSession_CLIENT_TYPE_ID "client.id"
+
+/** guint16, major version of server protocol */
+#define mwSession_SERVER_VER_MAJOR "server.version.major"
+
+/** guint16, minor version of server protocol */
+#define mwSession_SERVER_VER_MINOR "server.version.minor"
+
+/*@}*/
+
+
+enum mwSessionState {
+ mwSession_STARTING, /**< session is starting */
+ mwSession_HANDSHAKE, /**< session has sent handshake */
+ mwSession_HANDSHAKE_ACK, /**< session has received handshake ack */
+ mwSession_LOGIN, /**< session has sent login */
+ mwSession_LOGIN_REDIR, /**< session has been redirected */
+ mwSession_LOGIN_ACK, /**< session has received login ack */
+ mwSession_STARTED, /**< session is active */
+ mwSession_STOPPING, /**< session is shutting down */
+ mwSession_STOPPED, /**< session is stopped */
+ mwSession_UNKNOWN, /**< indicates an error determining state */
+ mwSession_LOGIN_CONT, /**< session has sent a login continue */
+};
+
+
+#define mwSession_isState(session, state) \
+ (mwSession_getState((session)) == (state))
+
+#define mwSession_isStarting(s) \
+ (mwSession_isState((s), mwSession_STARTING) || \
+ mwSession_isState((s), mwSession_HANDSHAKE) || \
+ mwSession_isState((s), mwSession_HANDSHAKE_ACK) || \
+ mwSession_isState((s), mwSession_LOGIN) || \
+ mwSession_isState((s), mwSession_LOGIN_ACK) || \
+ mwSession_isState((s), mwSession_LOGIN_REDIR) || \
+ mwSession_isState((s), mwSession_LOGIN_CONT))
+
+#define mwSession_isStarted(s) \
+ (mwSession_isState((s), mwSession_STARTED))
+
+#define mwSession_isStopping(s) \
+ (mwSession_isState((s), mwSession_STOPPING))
+
+#define mwSession_isStopped(s) \
+ (mwSession_isState((s), mwSession_STOPPED))
+
+
+/** @struct mwSession
+
+ Represents a Sametime client session */
+struct mwSession;
+
+
+/** @struct mwSessionHandler
+
+ session handler. Structure which interfaces a session with client
+ code to provide I/O and event handling */
+struct mwSessionHandler {
+
+ /** write data to the server connection. Required. Should return
+ zero for success, non-zero for error */
+ int (*io_write)(struct mwSession *, const guchar *buf, gsize len);
+
+ /** close the server connection. Required */
+ void (*io_close)(struct mwSession *);
+
+ /** triggered by mwSession_free. Optional. Put cleanup code here */
+ void (*clear)(struct mwSession *);
+
+ /** Called when the session has changed status.
+
+ @see mwSession_getStateInfo for uses of info field
+
+ @param s the session
+ @param state the session's state
+ @param info additional state information */
+ void (*on_stateChange)(struct mwSession *s,
+ enum mwSessionState state, gpointer info);
+
+ /** called when privacy information has been sent or received
+
+ @see mwSession_getPrivacyInfo
+ */
+ void (*on_setPrivacyInfo)(struct mwSession *);
+
+ /** called when user status has changed
+
+ @see mwSession_getUserStatus */
+ void (*on_setUserStatus)(struct mwSession *);
+
+ /** called when an admin messages has been received */
+ void (*on_admin)(struct mwSession *, const char *text);
+
+ /** called when an announcement arrives */
+ void (*on_announce)(struct mwSession *, struct mwLoginInfo *from,
+ gboolean may_reply, const char *text);
+
+};
+
+
+/** allocate a new session */
+struct mwSession *mwSession_new(struct mwSessionHandler *);
+
+
+/** stop, clear, free a session. Does not free contained ciphers or
+ services, these must be taken care of explicitly. */
+void mwSession_free(struct mwSession *);
+
+
+/** obtain a reference to the session's handler */
+struct mwSessionHandler *mwSession_getHandler(struct mwSession *);
+
+
+/** instruct the session to begin. This will result in the initial
+ handshake message being sent. */
+void mwSession_start(struct mwSession *);
+
+
+/** instruct the session to shut down with the following reason
+ code. */
+void mwSession_stop(struct mwSession *, guint32 reason);
+
+
+/** Data is buffered, unpacked, and parsed into a message, then
+ processed accordingly. */
+void mwSession_recv(struct mwSession *, const guchar *, gsize);
+
+
+/** primarily used by services to have messages serialized and sent
+ @param s session to send message over
+ @param msg message to serialize and send
+ @returns 0 for success */
+int mwSession_send(struct mwSession *s, struct mwMessage *msg);
+
+
+/** sends the keepalive byte */
+int mwSession_sendKeepalive(struct mwSession *s);
+
+
+/** respond to a login redirect message by forcing the login sequence
+ to continue through the immediate server. */
+int mwSession_forceLogin(struct mwSession *s);
+
+
+/** send an announcement to a list of users/groups. Targets of
+ announcement must be in the same community as the session.
+
+ @param s session to send announcement from
+ @param may_reply permit clients to reply. Not all clients honor this.
+ @param text text of announcement
+ @param recipients list of recipients. Each recipient is specified
+ by a single string, prefix with "@U " for users
+ and "@G " for Notes Address Book groups.
+*/
+int mwSession_sendAnnounce(struct mwSession *s, gboolean may_reply,
+ const char *text, const GList *recipients);
+
+
+/** set the internal privacy information, and inform the server as
+ necessary. Triggers the on_setPrivacyInfo call-back. */
+int mwSession_setPrivacyInfo(struct mwSession *, struct mwPrivacyInfo *);
+
+
+/** direct reference to the session's internal privacy structure */
+struct mwPrivacyInfo *mwSession_getPrivacyInfo(struct mwSession *);
+
+
+/** reference the login information for the session */
+struct mwLoginInfo *mwSession_getLoginInfo(struct mwSession *);
+
+
+/** set the internal user status state, and inform the server as
+ necessary. Triggers the on_setUserStatus call-back */
+int mwSession_setUserStatus(struct mwSession *, struct mwUserStatus *);
+
+
+struct mwUserStatus *mwSession_getUserStatus(struct mwSession *);
+
+
+/** current status of the session */
+enum mwSessionState mwSession_getState(struct mwSession *);
+
+
+/** additional status-specific information. Depending on the state of
+ the session, this value has different meaning.
+
+ @li @c mwSession_STOPPING guint32 error code causing
+ the session to shut down
+
+ @li @c mwSession_STOPPED guint32 error code causing
+ the session to shut down
+
+ @li @c mwSession_LOGIN_REDIR (char *) host to redirect
+ to
+*/
+gpointer mwSession_getStateInfo(struct mwSession *);
+
+
+struct mwChannelSet *mwSession_getChannels(struct mwSession *);
+
+
+/** adds a service to the session. If the session is started (or when
+ the session is successfully started) and the service has a start
+ function, the session will request service availability from the
+ server. On receipt of the service availability notification, the
+ session will call the service's start function.
+
+ @return TRUE if the session was added correctly */
+gboolean mwSession_addService(struct mwSession *, struct mwService *);
+
+
+/** find a service by its type identifier */
+struct mwService *mwSession_getService(struct mwSession *, guint32 type);
+
+
+/** removes a service from the session. If the session is started and
+ the service has a stop function, it will be called. Returns the
+ removed service */
+struct mwService *mwSession_removeService(struct mwSession *, guint32 type);
+
+
+/** a GList of services in this session. The GList needs to be freed
+ after use */
+GList *mwSession_getServices(struct mwSession *);
+
+
+/** instruct a STARTED session to check the server for the presense of
+ a given service. The service will be automatically started upon
+ receipt of an affirmative reply from the server. This function is
+ automatically called upon all services in a session when the
+ session is fully STARTED.
+
+ Services which terminate due to an error may call this on
+ themselves to re-initialize when their server-side counterpart is
+ made available again.
+
+ @param s owning session
+ @param type service type ID */
+void mwSession_senseService(struct mwSession *s, guint32 type);
+
+
+/** adds a cipher to the session. */
+gboolean mwSession_addCipher(struct mwSession *, struct mwCipher *);
+
+
+/** find a cipher by its type identifier */
+struct mwCipher *mwSession_getCipher(struct mwSession *, guint16 type);
+
+
+/** remove a cipher from the session */
+struct mwCipher *mwSession_removeCipher(struct mwSession *, guint16 type);
+
+
+/** a GList of ciphers in this session. The GList needs to be freed
+ after use */
+GList *mwSession_getCiphers(struct mwSession *);
+
+
+/** associate a key:value pair with the session. If an existing value is
+ associated with the same key, it will have its clear function called
+ and will be replaced with the new value */
+void mwSession_setProperty(struct mwSession *, const char *key,
+ gpointer val, GDestroyNotify clear);
+
+
+/** obtain the value of a previously set property, or NULL */
+gpointer mwSession_getProperty(struct mwSession *, const char *key);
+
+
+/** remove a property, calling the optional GDestroyNotify function
+ indicated in mwSession_setProperty if applicable */
+void mwSession_removeProperty(struct mwSession *, const char *key);
+
+
+/** associate arbitrary data with the session for use by the client
+ code. Only client applications should use this, never services.
+
+ @param session the session to associate the data with
+ @param data arbitrary client data
+ @param clear optional cleanup function called on data from
+ mwSession_removeClientData and mwSession_free
+*/
+void mwSession_setClientData(struct mwSession *session,
+ gpointer data, GDestroyNotify clear);
+
+
+gpointer mwSession_getClientData(struct mwSession *session);
+
+
+/** remove client data, calling the optional GDestroyNotify function
+ indicated in mwSession_setClientData if applicable */
+void mwSession_removeClientData(struct mwSession *session);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _MW_SESSION_H */
+
diff --git a/protocols/Sametime/src/meanwhile/src/mw_srvc_aware.h b/protocols/Sametime/src/meanwhile/src/mw_srvc_aware.h
new file mode 100644
index 0000000000..0d5090d258
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/mw_srvc_aware.h
@@ -0,0 +1,289 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _MW_SRVC_AWARE_H
+#define _MW_SRVC_AWARE_H
+
+
+/** @file mw_srvc_aware.h
+
+ The aware service...
+
+ @todo remove the whole idea of an instantiated mwAwareList and
+ instead use arbitrary pointers (including NULL) as keys to
+ internally stored lists. This removes the problem of the service
+ free'ing its lists and invalidating mwAwareList references from
+ client code.
+*/
+
+
+#include "mw_common.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** Type identifier for the aware service */
+#define mwService_AWARE 0x00000011
+
+
+/** @struct mwServiceAware
+
+ Instance of an Aware Service. The members of this structure are
+ not made available. Accessing the parts of an aware service should
+ be performed through the appropriate functions. Note that
+ instances of this structure can be safely cast to a mwService.
+*/
+struct mwServiceAware;
+
+
+/** @struct mwAwareList
+
+ Instance of an Aware List. The members of this structure are not
+ made available. Access to the parts of an aware list should be
+ handled through the appropriate functions.
+
+ Any references to an aware list are rendered invalid when the
+ parent service is free'd
+*/
+struct mwAwareList;
+
+
+/** @struct mwAwareAttribute
+
+ Key/Opaque pair indicating an identity's attribute.
+ */
+struct mwAwareAttribute;
+
+
+/** Predefined keys appropriate for a mwAwareAttribute
+ */
+enum mwAwareAttributeKeys {
+ mwAttribute_AV_PREFS_SET = 0x01, /**< A/V prefs specified, gboolean */
+ mwAttribute_MICROPHONE = 0x02, /**< has a microphone, gboolean */
+ mwAttribute_SPEAKERS = 0x03, /**< has speakers, gboolean */
+ mwAttribute_VIDEO_CAMERA = 0x04, /**< has a video camera, gboolean */
+ mwAttribute_FILE_TRANSFER = 0x06, /**< supports file transfers, gboolean */
+};
+
+
+typedef void (*mwAwareAttributeHandler)
+ (struct mwServiceAware *srvc,
+ struct mwAwareAttribute *attrib);
+
+
+struct mwAwareHandler {
+ mwAwareAttributeHandler on_attrib;
+ void (*clear)(struct mwServiceAware *srvc);
+};
+
+
+/** Appropriate function type for the on-aware signal
+
+ @param list mwAwareList emiting the signal
+ @param id awareness status information
+ @param data user-specified data
+*/
+typedef void (*mwAwareSnapshotHandler)
+ (struct mwAwareList *list,
+ struct mwAwareSnapshot *id);
+
+
+/** Appropriate function type for the on-option signal. The option's
+ value may need to be explicitly loaded in some instances,
+ resulting in this handler being triggered again.
+
+ @param list mwAwareList emiting the signal
+ @param id awareness the attribute belongs to
+ @param attrib attribute
+*/
+typedef void (*mwAwareIdAttributeHandler)
+ (struct mwAwareList *list,
+ struct mwAwareIdBlock *id,
+ struct mwAwareAttribute *attrib);
+
+
+struct mwAwareListHandler {
+ /** handle aware updates */
+ mwAwareSnapshotHandler on_aware;
+
+ /** handle attribute updates */
+ mwAwareIdAttributeHandler on_attrib;
+
+ /** optional. Called from mwAwareList_free */
+ void (*clear)(struct mwAwareList *list);
+};
+
+
+struct mwServiceAware *
+mwServiceAware_new(struct mwSession *session,
+ struct mwAwareHandler *handler);
+
+
+/** Set an attribute value for this session */
+int mwServiceAware_setAttribute(struct mwServiceAware *srvc,
+ guint32 key, struct mwOpaque *opaque);
+
+
+int mwServiceAware_setAttributeBoolean(struct mwServiceAware *srvc,
+ guint32 key, gboolean val);
+
+
+int mwServiceAware_setAttributeInteger(struct mwServiceAware *srvc,
+ guint32 key, guint32 val);
+
+
+int mwServiceAware_setAttributeString(struct mwServiceAware *srvc,
+ guint32 key, const char *str);
+
+
+/** Unset an attribute for this session */
+int mwServiceAware_unsetAttribute(struct mwServiceAware *srvc,
+ guint32 key);
+
+
+guint32 mwAwareAttribute_getKey(const struct mwAwareAttribute *attrib);
+
+
+gboolean mwAwareAttribute_asBoolean(const struct mwAwareAttribute *attrib);
+
+
+guint32 mwAwareAttribute_asInteger(const struct mwAwareAttribute *attrib);
+
+
+/** Copy of attribute string, must be g_free'd. If the attribute's
+ content cannot be loaded as a string, returns NULL */
+char *mwAwareAttribute_asString(const struct mwAwareAttribute *attrib);
+
+
+/** Direct access to an attribute's underlying opaque */
+const struct mwOpaque *
+mwAwareAttribute_asOpaque(const struct mwAwareAttribute *attrib);
+
+
+/** Allocate and initialize an aware list */
+struct mwAwareList *
+mwAwareList_new(struct mwServiceAware *srvc,
+ struct mwAwareListHandler *handler);
+
+
+/** Clean and free an aware list */
+void mwAwareList_free(struct mwAwareList *list);
+
+
+struct mwAwareListHandler *mwAwareList_getHandler(struct mwAwareList *list);
+
+
+/// Miranda NG adaptation start - new method
+struct mwServiceAware *mwAwareList_getServiceAware(struct mwAwareList *list);
+/// Miranda NG adaptation end
+
+
+/** Add a collection of user IDs to an aware list.
+ @param list mwAwareList to add user ID to
+ @param id_list mwAwareIdBlock list of user IDs to add
+ @return 0 for success, non-zero to indicate an error.
+*/
+int mwAwareList_addAware(struct mwAwareList *list, GList *id_list);
+
+
+/** Remove a collection of user IDs from an aware list.
+ @param list mwAwareList to remove user ID from
+ @param id_list mwAwareIdBlock list of user IDs to remove
+ @return 0 for success, non-zero to indicate an error.
+*/
+int mwAwareList_removeAware(struct mwAwareList *list, GList *id_list);
+
+
+int mwAwareList_removeAllAware(struct mwAwareList *list);
+
+
+/** watch an NULL terminated array of keys */
+int mwAwareList_watchAttributeArray(struct mwAwareList *list,
+ guint32 *keys);
+
+
+/** watch a NULL terminated list of keys */
+int mwAwareList_watchAttributes(struct mwAwareList *list,
+ guint32 key, ...);
+
+
+/** stop watching a NULL terminated array of keys */
+int mwAwareList_unwatchAttributeArray(struct mwAwareList *list,
+ guint32 *keys);
+
+
+/** stop watching a NULL terminated list of keys */
+int mwAwareList_unwatchAttributes(struct mwAwareList *list,
+ guint32 key, ...);
+
+
+/** remove all watched attributes */
+int mwAwareList_unwatchAllAttributes(struct mwAwareList *list);
+
+
+guint32 *mwAwareList_getWatchedAttributes(struct mwAwareList *list);
+
+
+void mwAwareList_setClientData(struct mwAwareList *list,
+ gpointer data, GDestroyNotify cleanup);
+
+
+void mwAwareList_removeClientData(struct mwAwareList *list);
+
+
+gpointer mwAwareList_getClientData(struct mwAwareList *list);
+
+
+/** trigger a got_aware event constructed from the passed user and
+ status information. Useful for adding false users and having the
+ getText function work for them */
+void mwServiceAware_setStatus(struct mwServiceAware *srvc,
+ struct mwAwareIdBlock *user,
+ struct mwUserStatus *stat);
+
+
+/** look up the status description for a user */
+const char *mwServiceAware_getText(struct mwServiceAware *srvc,
+ struct mwAwareIdBlock *user);
+
+
+/** look up the last known copy of an attribute for a user by the
+ attribute's key */
+const struct mwAwareAttribute *
+mwServiceAware_getAttribute(struct mwServiceAware *srvc,
+ struct mwAwareIdBlock *user,
+ guint32 key);
+
+
+/// Miranda NG adaptation start - new method
+struct mwService *mwServiceAware_getService(struct mwServiceAware *srvc);
+/// Miranda NG adaptation end
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _MW_SRVC_AWARE_H */
+
diff --git a/protocols/Sametime/src/meanwhile/src/mw_srvc_conf.h b/protocols/Sametime/src/meanwhile/src/mw_srvc_conf.h
new file mode 100644
index 0000000000..1447fd3830
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/mw_srvc_conf.h
@@ -0,0 +1,216 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _MW_SRVC_CONF_H
+#define _MW_SRVC_CONF_H
+
+
+#include <glib/glist.h>
+#include "mw_common.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** Type identifier for the conference service */
+#define mwService_CONFERENCE 0x80000010
+
+
+enum mwConferenceState {
+ mwConference_NEW, /**< new outgoing conference */
+ mwConference_PENDING, /**< outgoing conference pending creation */
+ mwConference_INVITED, /**< invited to incoming conference */
+ mwConference_OPEN, /**< conference open and active */
+ mwConference_CLOSING, /**< conference is closing */
+ mwConference_ERROR, /**< conference is closing due to error */
+ mwConference_UNKNOWN, /**< unable to determine conference state */
+};
+
+
+/** @struct mwServiceConference
+ Instance of the multi-user conference service */
+struct mwServiceConference;
+
+
+/** @struct mwConference
+ A multi-user chat */
+struct mwConference;
+
+
+/** Handler structure used to provide callbacks for an instance of the
+ conferencing service */
+struct mwConferenceHandler {
+
+ /** triggered when we receive a conference invitation. Call
+ mwConference_accept to accept the invitation and join the
+ conference, or mwConference_close to reject the invitation.
+
+ @param conf the newly created conference
+ @param inviter the indentity of the user who sent the invitation
+ @param invite the invitation text
+ */
+ void (*on_invited)(struct mwConference *conf,
+ struct mwLoginInfo *inviter, const char *invite);
+
+ /** triggered when we enter the conference. Provides the initial
+ conference membership list as a GList of mwLoginInfo structures
+
+ @param conf the conference just joined
+ @param members mwLoginInfo list of existing conference members
+ */
+ void (*conf_opened)(struct mwConference *conf, GList *members);
+
+ /** triggered when a conference is closed. This is typically when
+ we've left it */
+ void (*conf_closed)(struct mwConference *, guint32 reason);
+
+ /** triggered when someone joins the conference */
+ void (*on_peer_joined)(struct mwConference *, struct mwLoginInfo *);
+
+ /** triggered when someone leaves the conference */
+ void (*on_peer_parted)(struct mwConference *, struct mwLoginInfo *);
+
+ /** triggered when someone says something */
+ void (*on_text)(struct mwConference *conf,
+ struct mwLoginInfo *who, const char *what);
+
+ /** typing notification */
+ void (*on_typing)(struct mwConference *conf,
+ struct mwLoginInfo *who, gboolean typing);
+
+ /** optional. called from mwService_free */
+ void (*clear)(struct mwServiceConference *srvc);
+};
+
+
+/** Allocate a new conferencing service, attaching the given handler
+ @param sess owning session
+ @param handler handler providing call-back functions for the service
+ */
+struct mwServiceConference *
+mwServiceConference_new(struct mwSession *sess,
+ struct mwConferenceHandler *handler);
+
+
+/** @returns the conference handler for the service */
+struct mwConferenceHandler *
+mwServiceConference_getHandler(struct mwServiceConference *srvc);
+
+
+/** a mwConference list of the conferences in this service. The GList
+ will need to be destroyed with g_list_free after use */
+GList *mwServiceConference_getConferences(struct mwServiceConference *srvc);
+
+
+/** Allocate a new conference, in state NEW with the given title.
+ @see mwConference_create */
+struct mwConference *mwConference_new(struct mwServiceConference *srvc,
+ const char *title);
+
+
+/** @returns the owning service of a conference */
+/// Miranda NG adaptation start - renamed method
+struct mwServiceConference *mwConference_getServiceConference(struct mwConference *conf);
+/// Miranda NG adaptation end
+
+
+/// Miranda NG adaptation start - new method
+struct mwService *mwServiceConference_getService(struct mwServiceConference *srvc);
+/// Miranda NG adaptation end
+
+
+/** @returns unique conference name */
+const char *mwConference_getName(struct mwConference *conf);
+
+
+/** @returns conference title */
+const char *mwConference_getTitle(struct mwConference *conf);
+
+
+/** a mwIdBlock list of the members of the conference. The GList will
+ need to be free'd after use */
+GList *mwConference_getMembers(struct mwConference *conf);
+
+
+/** Initiate a conference. Conference must be in state NEW. If no name
+ or title for the conference has been set, they will be
+ generated. Conference will be placed into state PENDING. */
+int mwConference_open(struct mwConference *conf);
+
+
+/** Leave and close an existing conference, or reject an invitation.
+ Triggers mwServiceConfHandler::conf_closed and free's the
+ conference.
+ */
+int mwConference_destroy(struct mwConference *conf,
+ guint32 reason, const char *text);
+
+
+#define mwConference_reject(c,r,t) \
+ mwConference_destroy((c),(r),(t))
+
+
+/** accept a conference invitation. Conference must be in the state
+ INVITED. */
+int mwConference_accept(struct mwConference *conf);
+
+
+/** invite another user to an ACTIVE conference
+ @param conf conference
+ @param who user to invite
+ @param text invitation message
+ */
+int mwConference_invite(struct mwConference *conf,
+ struct mwIdBlock *who, const char *text);
+
+
+/** send a text message over an open conference */
+int mwConference_sendText(struct mwConference *conf, const char *text);
+
+
+/** send typing notification over an open conference */
+int mwConference_sendTyping(struct mwConference *conf, gboolean typing);
+
+
+/** associate arbitrary client data and an optional cleanup function
+ with a conference. If there is already client data with a clear
+ function, it will not be called. */
+void mwConference_setClientData(struct mwConference *conf,
+ gpointer data, GDestroyNotify clear);
+
+
+/** reference associated client data */
+gpointer mwConference_getClientData(struct mwConference *conf);
+
+
+/** remove associated client data if any, and call the cleanup
+ function on the data as necessary */
+void mwConference_removeClientData(struct mwConference *conf);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _MW_SRVC_CONF_H */
+
diff --git a/protocols/Sametime/src/meanwhile/src/mw_srvc_dir.h b/protocols/Sametime/src/meanwhile/src/mw_srvc_dir.h
new file mode 100644
index 0000000000..b9230bbf08
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/mw_srvc_dir.h
@@ -0,0 +1,212 @@
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _MW_SRVC_DIR_H
+#define _MW_SERV_DIR_H
+
+
+#include <glib.h>
+#include <glib/glist.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+struct mwSession;
+
+
+#define SERVICE_DIRECTORY 0x0000001a
+
+
+/** @struct mwServiceDirectory
+
+ the directory service. */
+struct mwServiceDirectory;
+
+
+/** @struct mwAddressBook
+
+ server-side collection of users and groups. Open a directory
+ based on an address book to search or list its contents */
+struct mwAddressBook;
+
+
+/** @struct mwDirectory
+
+ searchable directory, based off of an address book */
+struct mwDirectory;
+
+
+enum mwDirectoryState {
+ mwDirectory_NEW, /**< directory is created, but not open */
+ mwDirectory_PENDING, /**< directory has in the process of opening */
+ mwDirectory_OPEN, /**< directory is open */
+ mwDirectory_ERROR, /**< error opening or using directory */
+ mwDirectory_UNKNOWN, /**< error determining directory state */
+};
+
+
+/** return value of directory searches that fail */
+#define DIR_SEARCH_ERROR 0x00000000
+
+
+#define MW_DIRECTORY_IS_STATE(dir, state) \
+ (mwDirectory_getState(dir) == (state))
+
+#define MW_DIRECTORY_IS_NEW(dir) \
+ MW_DIRECTORY_IS_STATE((dir), mwDirectory_NEW)
+
+#define MW_DIRECTORY_IS_PENDING(dir) \
+ MW_DIRECTORY_IS_STATE((dir), mwDirectory_PENDING)
+
+#define MW_DIRECTORY_IS_OPEN(dir) \
+ MW_DIRECTORY_IS_STATE((dir), mwDirectory_OPEN)
+
+
+enum mwDirectoryMemberType {
+ mwDirectoryMember_USER = 0x0000,
+ mwDirectoryMember_GROUP = 0x0001,
+};
+
+
+struct mwDirectoryMember {
+ guint16 type; /**< @see mwDirectoryMemberType */
+ char *id; /**< proper ID for member */
+ char *long_name; /**< full name of member (USER type only) */
+ char *short_name; /**< short name of member */
+ guint16 foo; /**< unknown */
+};
+
+
+/** Appropriate function signature for handling directory search results */
+typedef void (*mwSearchHandler)
+ (struct mwDirectory *dir,
+ guint32 code, guint32 offset, GList *members);
+
+
+/** handles asynchronous events for a directory service instance */
+struct mwDirectoryHandler {
+
+ /** handle receipt of the address book list from the service.
+ Initially triggered by mwServiceDirectory_refreshAddressBooks
+ and at service startup */
+ void (*on_book_list)(struct mwServiceDirectory *srvc, GList *books);
+
+ /** triggered when a directory has been successfully opened */
+ void (*dir_opened)(struct mwDirectory *dir);
+
+ /** triggered when a directory has been closed */
+ void (*dir_closed)(struct mwDirectory *dir, guint32 reason);
+
+ /** optional. called from mwService_free */
+ void (*clear)(struct mwServiceDirectory *srvc);
+};
+
+
+/** Allocate a new directory service instance for use with session */
+struct mwServiceDirectory *
+mwServiceDirectory_new(struct mwSession *session,
+ struct mwDirectoryHandler *handler);
+
+
+/** the handler associated with the service at its creation */
+struct mwDirectoryHandler *
+mwServiceDirectory_getHandler(struct mwServiceDirectory *srvc);
+
+
+/** most recent list of address books available in service */
+GList *mwServiceDirectory_getAddressBooks(struct mwServiceDirectory *srvc);
+
+
+/** submit a request to obtain an updated list of address books from
+ service */
+int mwServiceDirectory_refreshAddressBooks(struct mwServiceDirectory *srvc);
+
+
+/** list of directories in the service */
+GList *mwServiceDirectory_getDirectories(struct mwServiceDirectory *srvc);
+
+
+/** list of directories associated with address book. Note that the
+ returned GList will need to be free'd after use */
+GList *mwAddressBook_getDirectories(struct mwAddressBook *book);
+
+
+/** the name of the address book */
+const char *mwAddressBook_getName(struct mwAddressBook *book);
+
+
+/** allocate a new directory based off the given address book */
+struct mwDirectory *mwDirectory_new(struct mwAddressBook *book);
+
+
+enum mwDirectoryState mwDirectory_getState(struct mwDirectory *dir);
+
+
+/** set client data. If there is an existing clear function, it will
+ not be called */
+void mwDirectory_setClientData(struct mwDirectory *dir,
+ gpointer data, GDestroyNotify clear);
+
+
+/** reference associated client data */
+gpointer mwDirectory_getClientData(struct mwDirectory *dir);
+
+
+/** remove and cleanup user data */
+void mwDirectory_removeClientData(struct mwDirectory *dir);
+
+
+/** reference owning service */
+struct mwServiceDirectory *mwDirectory_getService(struct mwDirectory *dir);
+
+
+/** reference owning address book */
+struct mwAddressBook *mwDirectory_getAddressBook(struct mwDirectory *dir);
+
+
+/** initialize a directory. */
+int mwDirectory_open(struct mwDirectory *dir, mwSearchHandler cb);
+
+
+/** continue a search into its next results */
+int mwDirectory_next(struct mwDirectory *dir);
+
+
+/** continue a search into its previous results */
+int mwDirectory_previous(struct mwDirectory *dir);
+
+
+/** initiate a search on an open directory */
+int mwDirectory_search(struct mwDirectory *dir, const char *query);
+
+
+/** close and free the directory, and unassociate it with its owning
+ address book and service */
+int mwDirectory_destroy(struct mwDirectory *dir);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _MW_SRVC_DIR_H */
diff --git a/protocols/Sametime/src/meanwhile/src/mw_srvc_ft.h b/protocols/Sametime/src/meanwhile/src/mw_srvc_ft.h
new file mode 100644
index 0000000000..aef7de886a
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/mw_srvc_ft.h
@@ -0,0 +1,255 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef _MW_SRVC_FT_H
+#define _MW_SRVC_FT_H
+
+
+/** @file mw_srvc_ft.h
+
+ A file transfer is a simple way to get large chunks of binary data
+ from one client to another.
+*/
+
+
+#include "mw_common.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** @struct mwServiceFileTransfer
+ File transfer service
+*/
+struct mwServiceFileTransfer;
+
+
+/** @struct mwFileTransfer
+ A single file trasfer session
+ */
+struct mwFileTransfer;
+
+
+#define mwService_FILE_TRANSFER 0x00000038
+
+
+enum mwFileTransferState {
+ mwFileTransfer_NEW, /**< file transfer is not open */
+ mwFileTransfer_PENDING, /**< file transfer is opening */
+ mwFileTransfer_OPEN, /**< file transfer is open */
+ mwFileTransfer_CANCEL_LOCAL,
+ mwFileTransfer_CANCEL_REMOTE,
+ mwFileTransfer_DONE,
+ mwFileTransfer_ERROR, /**< error in file transfer */
+ mwFileTransfer_UNKNOWN, /**< unknown state */
+};
+
+
+#define mwFileTransfer_isState(ft, state) \
+ (mwFileTransfer_getState(ft) == (state))
+
+#define mwFileTransfer_isNew(ft) \
+ mwFileTransfer_isState((ft), mwFileTransfer_NEW)
+
+#define mwFileTransfer_isPending(ft) \
+ mwFileTransfer_isState((ft), mwFileTransfer_PENDING)
+
+#define mwFileTransfer_isOpen(ft) \
+ mwFileTransfer_isState((ft), mwFileTransfer_OPEN)
+
+#define mwFileTransfer_isDone(ft) \
+ mwFileTransfer_isState((ft), mwFileTransfer_DONE)
+
+#define mwFileTransfer_isCancelLocal(ft) \
+ mwFileTransfer_isState((ft), mwFileTransfer_CANCEL_LOCAL)
+
+#define mwFileTransfer_isCancelRemote(ft) \
+ mwFileTransfer_isState((ft), mwFileTransfer_CANCEL_REMOTE)
+
+
+enum mwFileTranferCode {
+ mwFileTransfer_SUCCESS = 0x00000000,
+ mwFileTransfer_REJECTED = 0x08000606,
+};
+
+
+struct mwFileTransferHandler {
+
+ /** an incoming file transfer has been offered */
+ void (*ft_offered)(struct mwFileTransfer *ft);
+
+ /** a file transfer has been fully initiated */
+ void (*ft_opened)(struct mwFileTransfer *ft);
+
+ /** a file transfer has been closed. Check the status of the file
+ transfer to determine if the transfer was complete or if it had
+ been interrupted */
+ void (*ft_closed)(struct mwFileTransfer *ft, guint32 code);
+
+ /** receive a chunk of a file from an inbound file transfer. */
+ void (*ft_recv)(struct mwFileTransfer *ft, struct mwOpaque *data);
+
+ /** received an ack for a sent chunk on an outbound file transfer.
+ this indicates that a previous call to mwFileTransfer_send has
+ reached the target and that the target has responded. */
+ void (*ft_ack)(struct mwFileTransfer *ft);
+
+ /** optional. called from mwService_free */
+ void (*clear)(struct mwServiceFileTransfer *srvc);
+};
+
+
+struct mwServiceFileTransfer *
+mwServiceFileTransfer_new(struct mwSession *session,
+ struct mwFileTransferHandler *handler);
+
+
+struct mwFileTransferHandler *
+mwServiceFileTransfer_getHandler(struct mwServiceFileTransfer *srvc);
+
+
+const GList *
+mwServiceFileTransfer_getTransfers(struct mwServiceFileTransfer *srvc);
+
+
+/// Miranda NG adaptation start - new method
+struct mwService *
+mwServiceFileTransfer_getService(struct mwServiceFileTransfer *srvc);
+/// Miranda NG adaptation end
+
+
+struct mwFileTransfer *
+mwFileTransfer_new(struct mwServiceFileTransfer *srvc,
+ const struct mwIdBlock *who, const char *msg,
+ const char *filename, guint32 filesize);
+
+
+/** deallocate a file transfer. will call mwFileTransfer_close if
+ necessary */
+void
+mwFileTransfer_free(struct mwFileTransfer *ft);
+
+
+/** the status of this file transfer */
+enum mwFileTransferState
+mwFileTransfer_getState(struct mwFileTransfer *ft);
+
+
+struct mwServiceFileTransfer *
+mwFileTransfer_getService(struct mwFileTransfer *ft);
+
+
+/** the user on the other end of the file transfer */
+const struct mwIdBlock *
+mwFileTransfer_getUser(struct mwFileTransfer *ft);
+
+
+/** the message sent along with an offered file transfer */
+const char *
+mwFileTransfer_getMessage(struct mwFileTransfer *ft);
+
+
+/** the publicized file name. Not necessarily related to any actual
+ file on either system */
+const char *
+mwFileTransfer_getFileName(struct mwFileTransfer *ft);
+
+
+/** total bytes intended to be sent/received */
+guint32 mwFileTransfer_getFileSize(struct mwFileTransfer *ft);
+
+
+/** bytes remaining to be received/send */
+guint32 mwFileTransfer_getRemaining(struct mwFileTransfer *ft);
+
+
+/** count of bytes sent/received over this file transfer so far */
+#define mwFileTransfer_getSent(ft) \
+ (mwFileTransfer_getFileSize(ft) - mwFileTransfer_getRemaining(ft))
+
+
+/** initiate an outgoing file transfer */
+int mwFileTransfer_offer(struct mwFileTransfer *ft);
+
+
+/** accept an incoming file transfer */
+int mwFileTransfer_accept(struct mwFileTransfer *ft);
+
+
+/** reject an incoming file transfer */
+#define mwFileTransfer_reject(ft) \
+ mwFileTransfer_close((ft), mwFileTransfer_REJECTED)
+
+
+/** cancel an open file transfer */
+#define mwFileTransfer_cancel(ft) \
+ mwFileTransfer_close((ft), mwFileTransfer_SUCCESS);
+
+
+/** Close a file transfer. This will trigger the ft_close function of the
+ session's handler.
+
+ @see mwFileTransfer_reject
+ @see mwFileTransfer_cancel
+*/
+int mwFileTransfer_close(struct mwFileTransfer *ft, guint32 code);
+
+
+/** send a chunk of data over an outbound file transfer. The client at
+ the other end of the transfer should respond with an acknowledgement
+ message, which can be caught in the service's handler.
+
+ @see mwFileTransferHandler::ft_ack
+*/
+int mwFileTransfer_send(struct mwFileTransfer *ft,
+ struct mwOpaque *data);
+
+
+/** acknowledge the receipt of a chunk of data from an inbound file
+ transfer. This should be done after every received chunk, or the
+ transfer will stall. However, not all clients will wait for an ack
+ after sending a chunk before sending the next chunk, so it is
+ possible to have the handler's ft_recv function triggered again
+ even if no ack was sent.
+
+ @see mwFileTransferHandler::ft_recv
+*/
+int mwFileTransfer_ack(struct mwFileTransfer *ft);
+
+
+void mwFileTransfer_setClientData(struct mwFileTransfer *ft,
+ gpointer data, GDestroyNotify clean);
+
+
+gpointer mwFileTransfer_getClientData(struct mwFileTransfer *ft);
+
+
+void mwFileTransfer_removeClientData(struct mwFileTransfer *ft);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _MW_SRVC_FT_H */
diff --git a/protocols/Sametime/src/meanwhile/src/mw_srvc_im.h b/protocols/Sametime/src/meanwhile/src/mw_srvc_im.h
new file mode 100644
index 0000000000..adb710e32c
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/mw_srvc_im.h
@@ -0,0 +1,281 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _MW_SRVC_IM_H
+#define _MW_SRVC_IM_H
+
+
+/** @file mw_srvc_im.h
+
+ The IM service provides one-on-one communication between
+ users. Messages sent over conversations may relay different types
+ of information, in a variety of formats. The basic feature-set
+ provides plain-text chat with typing notification. More complex
+ features may be negotiated transparently by setting the IM Client
+ Type for a conversation, or for the service as a whole.
+*/
+
+
+#include <glib.h>
+#include "mw_common.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* identifier for the IM service */
+#define mwService_IM 0x00001000
+
+
+/** @struct mwServiceIm
+
+ An instance of the IM service. This service provides simple
+ instant messaging functionality */
+struct mwServiceIm;
+
+
+/** @struct mwConversation
+
+ A conversation between the local service and a single other user */
+struct mwConversation;
+
+
+enum mwImClientType {
+ mwImClient_PLAIN = 0x00000001, /**< text, typing */
+ mwImClient_NOTESBUDDY = 0x00033453, /**< adds html, subject, mime */
+ mwImClient_PRECONF = 0x00000019, /**< pre-conference, legacy */
+ mwImClient_UNKNOWN = 0xffffffff, /**< trouble determining type */
+};
+
+
+/**
+ Types of supported messages. When a conversation is created, the
+ least common denominator of features between either side of the
+ conversation (based on what features are available in the IM
+ service itself) becomes the set of supported features for that
+ conversation. At any point, the feature set for the service may
+ change, without affecting any existing conversations.
+
+ @see mwServiceIm_supports
+ @see mwServiceIm_setSupported
+ @see mwConversation_supports
+ @see mwConversation_send
+ @see mwServiceImHandler::conversation_recv
+ */
+enum mwImSendType {
+ mwImSend_PLAIN, /**< char *, plain-text message */
+ mwImSend_TYPING, /**< gboolean, typing status */
+ mwImSend_HTML, /**< char *, HTML formatted message (NOTESBUDDY) */
+ mwImSend_SUBJECT, /**< char *, conversation subject (NOTESBUDDY) */
+ mwImSend_MIME, /**< char *, MIME-encoded message (NOTESBUDDY) */
+ mwImSend_TIMESTAMP, /**< char *, YYYY:MM:DD:HH:mm:SS format (NOTESBUDDY) */
+};
+
+
+
+/** @see mwConversation_getState */
+enum mwConversationState {
+ mwConversation_CLOSED, /**< conversation is not open */
+ mwConversation_PENDING, /**< conversation is opening */
+ mwConversation_OPEN, /**< conversation is open */
+ mwConversation_UNKNOWN, /**< unknown state */
+};
+
+
+#define mwConversation_isState(conv, state) \
+ (mwConversation_getState(conv) == (state))
+
+#define mwConversation_isClosed(conv) \
+ mwConversation_isState((conv), mwConversation_CLOSED)
+
+#define mwConversation_isPending(conv) \
+ mwConversation_isState((conv), mwConversation_PENDING)
+
+#define mwConversation_isOpen(conv) \
+ mwConversation_isState((conv), mwConversation_OPEN)
+
+
+
+/** IM Service Handler. Provides functions for events triggered from an
+ IM service instance. */
+struct mwImHandler {
+
+ /** A conversation has been successfully opened */
+ void (*conversation_opened)(struct mwConversation *conv);
+
+ /** A conversation has been closed */
+ void (*conversation_closed)(struct mwConversation *conv, guint32 err);
+
+ /** A message has been received on a conversation */
+ void (*conversation_recv)(struct mwConversation *conv,
+ enum mwImSendType type, gconstpointer msg);
+
+ /** Handle a Place invitation. Set this to NULL and we should end up
+ receiving a conference invitation instead. */
+ void (*place_invite)(struct mwConversation *conv,
+ const char *message,
+ const char *title, const char *name);
+
+ /** optional. called from mwService_free */
+ void (*clear)(struct mwServiceIm *srvc);
+};
+
+
+struct mwServiceIm *mwServiceIm_new(struct mwSession *session,
+ struct mwImHandler *handler);
+
+
+struct mwImHandler *mwServiceIm_getHandler(struct mwServiceIm *srvc);
+
+
+/// Miranda NG adaptation start - new method
+struct mwService *mwServiceIm_getService(struct mwServiceIm *srvc);
+/// Miranda NG adaptation end
+
+
+/** reference an existing conversation to target, or create a new
+ conversation to target if one does not already exist */
+struct mwConversation *mwServiceIm_getConversation(struct mwServiceIm *srvc,
+ struct mwIdBlock *target);
+
+
+/** reference an existing conversation to target */
+struct mwConversation *mwServiceIm_findConversation(struct mwServiceIm *srvc,
+ struct mwIdBlock *target);
+
+
+/** determine if the conversations created from this service will
+ support a given send type */
+gboolean mwServiceIm_supports(struct mwServiceIm *srvc,
+ enum mwImSendType type);
+
+
+/** Set the default client type for the service. Newly created
+ conversations will attempt to meet this level of functionality
+ first.
+
+ @param srvc the IM service
+ @param type the send type to enable/disable
+*/
+void mwServiceIm_setClientType(struct mwServiceIm *srvc,
+ enum mwImClientType type);
+
+
+enum mwImClientType mwServiceIm_getClientType(struct mwServiceIm *srvc);
+
+
+/** attempt to open a conversation. If the conversation was not
+ already open and it is accepted,
+ mwServiceImHandler::conversation_opened will be triggered. Upon
+ failure, mwServiceImHandler::conversation_closed will be
+ triggered */
+void mwConversation_open(struct mwConversation *conv);
+
+
+/** close a conversation. If the conversation was not already closed,
+ mwServiceImHandler::conversation_closed will be triggered */
+void mwConversation_close(struct mwConversation *conv, guint32 err);
+
+
+/** determine whether a conversation supports the given message type */
+gboolean mwConversation_supports(struct mwConversation *conv,
+ enum mwImSendType type);
+
+
+enum mwImClientType mwConversation_getClientType(struct mwConversation *conv);
+
+
+/** get the state of a conversation
+
+ @see mwConversation_isOpen
+ @see mwConversation_isClosed
+ @see mwConversation_isPending
+*/
+enum mwConversationState mwConversation_getState(struct mwConversation *conv);
+
+
+/** send a message over an open conversation */
+int mwConversation_send(struct mwConversation *conv,
+ enum mwImSendType type, gconstpointer send);
+
+
+/** @returns owning service for a conversation */
+struct mwServiceIm *mwConversation_getService(struct mwConversation *conv);
+
+
+/** login information for conversation partner. returns NULL if conversation
+ is not OPEN */
+struct mwLoginInfo *mwConversation_getTargetInfo(struct mwConversation *conv);
+
+
+/** ID for conversation partner */
+struct mwIdBlock *mwConversation_getTarget(struct mwConversation *conv);
+
+
+/** set whether outgoing messages should be encrypted using the
+ negotiated cipher, if any */
+void mwConversation_setEncrypted(struct mwConversation *conv,
+ gboolean useCipher);
+
+
+/** determine whether outgoing messages are being encrypted */
+gboolean mwConversation_isEncrypted(struct mwConversation *conv);
+
+
+/** Associates client data with a conversation. If there is existing data,
+ it will not have its cleanup function called.
+
+ @see mwConversation_getClientData
+ @see mwConversation_removeClientData
+*/
+void mwConversation_setClientData(struct mwConversation *conv,
+ gpointer data, GDestroyNotify clean);
+
+
+/** Reference associated client data
+
+ @see mwConversation_setClientData
+ @see mwConversation_removeClientData
+ */
+gpointer mwConversation_getClientData(struct mwConversation *conv);
+
+
+/** Remove any associated client data, calling the optional cleanup
+ function if one was provided
+
+ @see mwConversation_setClientData
+ @see mwConversation_getClientData
+*/
+void mwConversation_removeClientData(struct mwConversation *conv);
+
+
+/** close and destroy the conversation and its backing channel, and
+ call the optional client data cleanup function */
+void mwConversation_free(struct mwConversation *conv);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _MW_SRVC_IM_H */
diff --git a/protocols/Sametime/src/meanwhile/src/mw_srvc_place.h b/protocols/Sametime/src/meanwhile/src/mw_srvc_place.h
new file mode 100644
index 0000000000..e17aa711c5
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/mw_srvc_place.h
@@ -0,0 +1,148 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _MW_SRVC_PLACE_H
+#define _MW_SRVC_PLACE_H
+
+
+#include <glib/glist.h>
+#include "mw_common.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** Type identifier for the place service */
+#define mwService_PLACE 0x80000022
+
+
+/** @struct mwServicePlace */
+struct mwServicePlace;
+
+
+/** @struct mwPlace */
+struct mwPlace;
+
+
+struct mwPlaceHandler {
+ void (*opened)(struct mwPlace *place);
+ void (*closed)(struct mwPlace *place, guint32 code);
+
+ void (*peerJoined)(struct mwPlace *place,
+ const struct mwIdBlock *peer);
+
+ void (*peerParted)(struct mwPlace *place,
+ const struct mwIdBlock *peer);
+
+ void (*peerSetAttribute)(struct mwPlace *place,
+ const struct mwIdBlock *peer,
+ guint32 attr, struct mwOpaque *o);
+
+ void (*peerUnsetAttribute)(struct mwPlace *place,
+ const struct mwIdBlock *peer,
+ guint32 attr);
+
+ void (*message)(struct mwPlace *place,
+ const struct mwIdBlock *who,
+ const char *msg);
+
+ void (*clear)(struct mwServicePlace *srvc);
+};
+
+
+enum mwPlacePeerAttribute {
+ mwPlacePeer_TYPING = 0x00000008,
+};
+
+
+struct mwServicePlace *
+mwServicePlace_new(struct mwSession *session,
+ struct mwPlaceHandler *handler);
+
+
+struct mwPlaceHandler *
+mwServicePlace_getHandler(struct mwServicePlace *srvc);
+
+
+const GList *mwServicePlace_getPlaces(struct mwServicePlace *srvc);
+
+
+struct mwPlace *mwPlace_new(struct mwServicePlace *srvc,
+ const char *name, const char *title);
+
+
+struct mwServicePlace *mwPlace_getService(struct mwPlace *place);
+
+
+const char *mwPlace_getName(struct mwPlace *place);
+
+
+const char *mwPlace_getTitle(struct mwPlace *place);
+
+
+int mwPlace_open(struct mwPlace *place);
+
+
+int mwPlace_destroy(struct mwPlace *place, guint32 code);
+
+
+/** returns a GList* of struct mwIdBlock*. The GList will need to be
+ freed after use, the mwIdBlock structures should not be modified
+ or freed */
+GList *mwPlace_getMembers(struct mwPlace *place);
+
+
+int mwPlace_sendText(struct mwPlace *place, const char *msg);
+
+
+/** send a legacy invitation for this place to a user. The user will
+ receive an apparent invitation from a Conference (rather than a
+ Place) */
+int mwPlace_legacyInvite(struct mwPlace *place,
+ struct mwIdBlock *idb,
+ const char *message);
+
+
+int mwPlace_setAttribute(struct mwPlace *place, guint32 attrib,
+ struct mwOpaque *data);
+
+
+int mwPlace_unsetAttribute(struct mwPlace *place, guint32 attrib);
+
+
+void mwPlace_setClientData(struct mwPlace *place,
+ gpointer data, GDestroyNotify clean);
+
+
+gpointer mwPlace_getClientData(struct mwPlace *place);
+
+
+void mwPlace_removeClientData(struct mwPlace *place);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _MW_SRVC_PLACE_H */
+
diff --git a/protocols/Sametime/src/meanwhile/src/mw_srvc_resolve.h b/protocols/Sametime/src/meanwhile/src/mw_srvc_resolve.h
new file mode 100644
index 0000000000..436b20a5d5
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/mw_srvc_resolve.h
@@ -0,0 +1,155 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _MW_SRVC_RESOLVE_H
+#define _MW_SRVC_RESOLVE_H
+
+
+#include <glib.h>
+#include <glib/glist.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** Type identifier for the conference service */
+#define mwService_RESOLVE 0x00000015
+
+
+/** Return value of mwServiceResolve_search indicating an error */
+#define SEARCH_ERROR 0x00
+
+
+/** @struct mwServiceResolve
+ User lookup service */
+struct mwServiceResolve;
+
+
+enum mwResolveFlag {
+ /** return unique results or none at all */
+ mwResolveFlag_UNIQUE = 0x00000001,
+
+ /** return only the first result */
+ mwResolveFlag_FIRST = 0x00000002,
+
+ /** search all directories, not just the first with a match */
+ mwResolveFlag_ALL_DIRS = 0x00000004,
+
+ /** search for users */
+ mwResolveFlag_USERS = 0x00000008,
+
+ /** search for groups */
+ mwResolveFlag_GROUPS = 0x00000010,
+};
+
+
+/** @see mwResolveResult */
+enum mwResolveCode {
+ /** successful search */
+ mwResolveCode_SUCCESS = 0x00000000,
+
+ /** only some of the nested searches were successful */
+ mwResolveCode_PARTIAL = 0x00010000,
+
+ /** more than one result (occurs when mwResolveFlag_UNIQUE is used
+ and more than one result would have been otherwise returned) */
+ mwResolveCode_MULTIPLE = 0x80020000,
+
+ /** the name is not resolvable due to its format */
+ mwResolveCode_BAD_FORMAT = 0x80030000,
+};
+
+
+enum mwResolveMatchType {
+ mwResolveMatch_USER = 0x00000001,
+ mwResolveMatch_GROUP = 0x00000002,
+};
+
+
+struct mwResolveMatch {
+ char *id; /**< user id */
+ char *name; /**< user name */
+ char *desc; /**< description */
+ guint32 type; /**< @see mwResolveMatchType */
+};
+
+
+struct mwResolveResult {
+ guint32 code; /**< @see mwResolveCode */
+ char *name; /**< name of the result */
+ GList *matches; /**< list of mwResolveMatch */
+};
+
+
+/** Handle the results of a resolve request. If there was a cleanup
+ function specified to mwServiceResolve_search, it will be called
+ upon the user data after this callback returns.
+
+ @param srvc the resolve service
+ @param id the resolve request ID
+ @param code return code
+ @param results list of mwResolveResult
+ @param data optional user data attached to the request
+*/
+typedef void (*mwResolveHandler)
+ (struct mwServiceResolve *srvc,
+ guint32 id, guint32 code, GList *results,
+ gpointer data);
+
+
+/** Allocate a new resolve service */
+struct mwServiceResolve *mwServiceResolve_new(struct mwSession *);
+
+
+/** Inisitate a resolve request.
+
+ @param srvc the resolve service
+ @param queries list query strings
+ @param flags search flags
+ @param handler result handling function
+ @param data optional user data attached to the request
+ @param cleanup optional function to clean up user data
+ @return generated ID for the search request, or SEARCH_ERROR
+*/
+guint32 mwServiceResolve_resolve(struct mwServiceResolve *srvc,
+ GList *queries, enum mwResolveFlag flags,
+ mwResolveHandler handler,
+ gpointer data, GDestroyNotify cleanup);
+
+
+/** Cancel a resolve request by its generated ID. The handler function
+ will not be called, and the optional cleanup function will be
+ called upon the optional user data for the request */
+void mwServiceResolve_cancelResolve(struct mwServiceResolve *, guint32);
+
+
+/// Miranda NG adaptation start - new method
+struct mwService *mwServiceResolve_getService(struct mwServiceResolve *srvc);
+/// Miranda NG adaptation end
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _MW_SRVC_RESOLVE_H */
diff --git a/protocols/Sametime/src/meanwhile/src/mw_srvc_store.h b/protocols/Sametime/src/meanwhile/src/mw_srvc_store.h
new file mode 100644
index 0000000000..b55ddf21fe
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/mw_srvc_store.h
@@ -0,0 +1,201 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _MW_SRVC_STORE_H
+#define _MW_SRVC_STORE_H
+
+
+#include <glib.h>
+#include "mw_common.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** Type identifier for the storage service */
+#define mwService_STORAGE 0x00000018
+
+
+/** @struct mwServiceStorage
+ @see mwServiceStorage_new
+
+ Instance of the storage service */
+struct mwServiceStorage;
+
+
+/** @struct mwStorage
+
+ Unit Represents information intended for loading from or saving to
+ the storage service */
+struct mwStorageUnit;
+
+
+/** The upper limit of reserved Lotus keys */
+#define LOTUS_RESERVED_LIMIT 0x186a0
+
+
+/** Check if a key is in the range of Lotus reserved keys */
+#define KEY_IS_LOTUS_RESERVED(key) \
+ (((guint32) key) <= (LOTUS_RESERVED_LIMIT))
+
+
+/** Some common keys storage keys. Anything in the range 0x00 to
+ 0x186a0 (100000) is reserved for use by the Lotus
+ clients. */
+enum mwStorageKey {
+
+ /** The buddy list, in the Sametime .dat file format. String */
+ mwStore_AWARE_LIST = 0x00000000,
+
+ /** Default text for chat invitations. String */
+ mwStore_INVITE_CHAT = 0x00000006,
+
+ /** Default text for meeting invitations. String */
+ mwStore_INVITE_MEETING = 0x0000000e,
+
+ /** Last five Away messages, separated by semicolon. String */
+ mwStore_AWAY_MESSAGES = 0x00000050,
+
+ /** Last five Busy (DND) messages, separated by semicolon. String */
+ mwStore_BUSY_MESSAGES = 0x0000005a,
+
+ /** Last five Active messages, separated by semicolon. String */
+ mwStore_ACTIVE_MESSAGES = 0x00000064,
+};
+
+
+/** Appropriate function type for load and store callbacks.
+ @param srvc the storage service
+ @param result the result value of the load or store call
+ @param item the storage unit loaded or saved
+ @param data optional user data
+*/
+typedef void (*mwStorageCallback)
+ (struct mwServiceStorage *srvc,
+ guint32 result, struct mwStorageUnit *item,
+ gpointer data);
+
+
+/** Allocates and initializes a storage service instance for use on
+ the passed session. */
+struct mwServiceStorage *mwServiceStorage_new(struct mwSession *);
+
+
+/** create an empty storage unit */
+struct mwStorageUnit *mwStorageUnit_new(guint32 key);
+
+
+/** creates a storage unit with the passed key, and a copy of data. */
+struct mwStorageUnit *mwStorageUnit_newOpaque(guint32 key,
+ struct mwOpaque *data);
+
+
+/** creates a storage unit with the passed key, and an encapsulated
+ boolean value */
+struct mwStorageUnit *mwStorageUnit_newBoolean(guint32 key,
+ gboolean val);
+
+
+struct mwStorageUnit *mwStorageUnit_newInteger(guint32 key,
+ guint32 val);
+
+
+/** creates a storage unit with the passed key, and an encapsulated
+ string value. */
+struct mwStorageUnit *mwStorageUnit_newString(guint32 key,
+ const char *str);
+
+
+/** get the key for the given storage unit */
+guint32 mwStorageUnit_getKey(struct mwStorageUnit *);
+
+
+/** attempts to obtain a boolean value from a storage unit. If the
+ unit is empty, or does not contain the type in a recongnizable
+ format, val is returned instead */
+gboolean mwStorageUnit_asBoolean(struct mwStorageUnit *, gboolean val);
+
+
+/** attempts to obtain a guint32 value from a storage unit. If the
+ unit is empty, or does not contain the type in a recognizable
+ format, val is returned instead */
+guint32 mwStorageUnit_asInteger(struct mwStorageUnit *, guint32 val);
+
+
+/** attempts to obtain a string value from a storage unit. If the unit
+ is empty, or does not contain the type in a recognizable format,
+ NULL is returned instead. Note that the string returned is a copy,
+ and will need to be deallocated at some point. */
+char *mwStorageUnit_asString(struct mwStorageUnit *);
+
+
+/** direct access to the opaque data backing the storage unit */
+struct mwOpaque *mwStorageUnit_asOpaque(struct mwStorageUnit *);
+
+
+/** clears and frees a storage unit */
+void mwStorageUnit_free(struct mwStorageUnit *);
+
+
+/** Initiates a load call to the storage service. If the service is
+ not currently available, the call will be cached and processed
+ when the service is started.
+
+ @param srvc the storage service
+ @param item storage unit to load
+ @param cb callback function when the load call completes
+ @param data user data for callback
+ @param data_free optional cleanup function for user data
+*/
+void mwServiceStorage_load(struct mwServiceStorage *srvc,
+ struct mwStorageUnit *item,
+ mwStorageCallback cb,
+ gpointer data, GDestroyNotify data_free);
+
+
+/** Initiates a store call to the storage service. If the service is
+ not currently available, the call will be cached and processed
+ when the service is started.
+
+ @param srvc the storage service
+ @param item storage unit to save
+ @param cb callback function when the load call completes
+ @param data optional user data for callback
+ @param data_free optional cleanup function for user data
+ */
+void mwServiceStorage_save(struct mwServiceStorage *srvc,
+ struct mwStorageUnit *item,
+ mwStorageCallback cb,
+ gpointer data, GDestroyNotify data_free);
+
+
+/// Miranda NG adaptation start - new method
+struct mwService *mwServiceStorage_getService(struct mwServiceStorage *srvc);
+/// Miranda NG adaptation end
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _MW_SRVC_STORE_H */
diff --git a/protocols/Sametime/src/meanwhile/src/mw_st_list.h b/protocols/Sametime/src/meanwhile/src/mw_st_list.h
new file mode 100644
index 0000000000..39e1cbf84b
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/mw_st_list.h
@@ -0,0 +1,218 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _MW_ST_LIST_H
+#define _MW_ST_LIST_H
+
+
+/** @file mw_st_list.h
+
+ Parse and compose buddy lists in the format commonly used by Sametime
+ Connect clients.
+*/
+
+
+#include <glib.h>
+#include <glib/glist.h>
+#include "mw_common.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define ST_LIST_MAJOR 3
+#define ST_LIST_MINOR 1
+#define ST_LIST_MICRO 3
+
+
+enum mwSametimeGroupType {
+ mwSametimeGroup_NORMAL = 1, /**< a normal group of users */
+ mwSametimeGroup_DYNAMIC = 2, /**< a server-side group */
+ mwSametimeGroup_UNKNOWN = 0, /**< error determining group type */
+};
+
+
+enum mwSametimeUserType {
+ mwSametimeUser_NORMAL = 1, /**< user on same community */
+ mwSametimeUser_EXTERNAL = 2, /**< external user */
+ mwSametimeUser_UNKNOWN = 0, /**< error determining user type */
+};
+
+
+/** @struct mwSametimeList
+
+ Represents a group-based buddy list. */
+struct mwSametimeList;
+
+
+/** @struct mwSametimeGroup
+
+ Represents a group in a buddy list */
+struct mwSametimeGroup;
+
+
+/** @struct mwSametimeUser
+
+ Represents a user in a group in a buddy list */
+struct mwSametimeUser;
+
+
+/** Create a new list */
+struct mwSametimeList *mwSametimeList_new();
+
+
+/** Free the list, all of its groups, and all of the groups' members */
+void mwSametimeList_free(struct mwSametimeList *l);
+
+
+/** Load a sametime list from a buffer. The list must be encapsulated
+ as a string (eg, the first two bytes in the buffer should be the
+ length of the string) */
+void mwSametimeList_get(struct mwGetBuffer *b, struct mwSametimeList *l);
+
+
+/** Write a sametime list onto a buffer. The list will be encapsulated
+ in a string (the first two bytes written will be the length of the
+ rest of the written list data) */
+void mwSametimeList_put(struct mwPutBuffer *b, struct mwSametimeList *l);
+
+
+/** convert a plain string into a sametime list */
+struct mwSametimeList *mwSametimeList_load(const char *str);
+
+
+/** convert a sametime list into a string */
+char *mwSametimeList_store(struct mwSametimeList *l);
+
+
+void mwSametimeList_setMajor(struct mwSametimeList *l, guint v);
+
+
+guint mwSametimeList_getMajor(struct mwSametimeList *l);
+
+
+void mwSametimeList_setMinor(struct mwSametimeList *l, guint v);
+
+
+guint mwSametimeList_getMinor(struct mwSametimeList *l);
+
+
+void mwSametimeList_setMicro(struct mwSametimeList *l, guint v);
+
+
+guint mwSametimeList_getMicro(struct mwSametimeList *l);
+
+
+/** Get a GList snapshot of the groups in a list */
+GList *mwSametimeList_getGroups(struct mwSametimeList *l);
+
+
+struct mwSametimeGroup *
+mwSametimeList_findGroup(struct mwSametimeList *l,
+ const char *name);
+
+
+/** Create a new group in a list */
+struct mwSametimeGroup *
+mwSametimeGroup_new(struct mwSametimeList *l,
+ enum mwSametimeGroupType type,
+ const char *name);
+
+
+/** Remove a group from its list, and free it. Also frees all users
+ contained in the group */
+void mwSametimeGroup_free(struct mwSametimeGroup *g);
+
+
+enum mwSametimeGroupType mwSametimeGroup_getType(struct mwSametimeGroup *g);
+
+
+const char *mwSametimeGroup_getName(struct mwSametimeGroup *g);
+
+
+void mwSametimeGroup_setAlias(struct mwSametimeGroup *g,
+ const char *alias);
+
+
+const char *mwSametimeGroup_getAlias(struct mwSametimeGroup *g);
+
+
+void mwSametimeGroup_setOpen(struct mwSametimeGroup *g, gboolean open);
+
+
+gboolean mwSametimeGroup_isOpen(struct mwSametimeGroup *g);
+
+
+struct mwSametimeList *mwSametimeGroup_getList(struct mwSametimeGroup *g);
+
+
+/** Get a GList snapshot of the users in a list */
+GList *mwSametimeGroup_getUsers(struct mwSametimeGroup *g);
+
+
+struct mwSametimeUser *
+mwSametimeGroup_findUser(struct mwSametimeGroup *g,
+ struct mwIdBlock *user);
+
+
+/** Create a user in a group */
+struct mwSametimeUser *
+mwSametimeUser_new(struct mwSametimeGroup *g,
+ enum mwSametimeUserType type,
+ struct mwIdBlock *user);
+
+
+/** Remove user from its group, and free it */
+void mwSametimeUser_free(struct mwSametimeUser *u);
+
+
+struct mwSametimeGroup *mwSametimeUser_getGroup(struct mwSametimeUser *u);
+
+
+enum mwSametimeUserType mwSametimeUser_getType(struct mwSametimeUser *u);
+
+
+const char *mwSametimeUser_getUser(struct mwSametimeUser *u);
+
+
+const char *mwSametimeUser_getCommunity(struct mwSametimeUser *u);
+
+
+void mwSametimeUser_setShortName(struct mwSametimeUser *u, const char *name);
+
+
+const char *mwSametimeUser_getShortName(struct mwSametimeUser *u);
+
+
+void mwSametimeUser_setAlias(struct mwSametimeUser *u, const char *alias);
+
+
+const char *mwSametimeUser_getAlias(struct mwSametimeUser *u);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _MW_ST_LIST_H */
diff --git a/protocols/Sametime/src/meanwhile/src/mw_util.c b/protocols/Sametime/src/meanwhile/src/mw_util.c
new file mode 100644
index 0000000000..57c1845b38
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/mw_util.c
@@ -0,0 +1,80 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "mw_util.h"
+
+
+static void collect_keys(gpointer key, gpointer val, gpointer data) {
+ GList **list = data;
+ *list = g_list_append(*list, key);
+}
+
+
+GList *map_collect_keys(GHashTable *ht) {
+ GList *ret = NULL;
+ g_hash_table_foreach(ht, collect_keys, &ret);
+ return ret;
+}
+
+
+static void collect_values(gpointer key, gpointer val, gpointer data) {
+ GList **list = data;
+ *list = g_list_append(*list, val);
+}
+
+
+GList *map_collect_values(GHashTable *ht) {
+ GList *ret = NULL;
+ g_hash_table_foreach(ht, collect_values, &ret);
+ return ret;
+}
+
+
+struct mw_datum *mw_datum_new(gpointer data, GDestroyNotify clear) {
+ struct mw_datum *d = g_new(struct mw_datum, 1);
+ mw_datum_set(d, data, clear);
+ return d;
+}
+
+
+void mw_datum_set(struct mw_datum *d, gpointer data, GDestroyNotify clear) {
+ d->data = data;
+ d->clear = clear;
+}
+
+
+gpointer mw_datum_get(struct mw_datum *d) {
+ return d->data;
+}
+
+
+void mw_datum_clear(struct mw_datum *d) {
+ if(d->clear) {
+ d->clear(d->data);
+ d->clear = NULL;
+ }
+ d->data = NULL;
+}
+
+
+void mw_datum_free(struct mw_datum *d) {
+ mw_datum_clear(d);
+ g_free(d);
+}
diff --git a/protocols/Sametime/src/meanwhile/src/mw_util.h b/protocols/Sametime/src/meanwhile/src/mw_util.h
new file mode 100644
index 0000000000..b8e0b7e968
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/mw_util.h
@@ -0,0 +1,85 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _MW_UTIL_H
+#define _MW_UTIL_H
+
+
+#include <glib.h>
+#include <glib/ghash.h>
+#include <glib/glist.h>
+
+
+#define map_guint_new() \
+ g_hash_table_new(g_direct_hash, g_direct_equal)
+
+
+#define map_guint_new_full(valfree) \
+ g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (valfree))
+
+
+#define map_guint_insert(ht, key, val) \
+ g_hash_table_insert((ht), GUINT_TO_POINTER((guint)(key)), (val))
+
+
+#define map_guint_replace(ht, key, val) \
+ g_hash_table_replace((ht), GUINT_TO_POINTER((guint)(key)), (val))
+
+
+#define map_guint_lookup(ht, key) \
+ g_hash_table_lookup((ht), GUINT_TO_POINTER((guint)(key)))
+
+
+#define map_guint_remove(ht, key) \
+ g_hash_table_remove((ht), GUINT_TO_POINTER((guint)(key)))
+
+
+#define map_guint_steal(ht, key) \
+ g_hash_table_steal((ht), GUINT_TO_POINTER((guint)(key)))
+
+
+GList *map_collect_keys(GHashTable *ht);
+
+
+GList *map_collect_values(GHashTable *ht);
+
+
+struct mw_datum {
+ gpointer data;
+ GDestroyNotify clear;
+};
+
+
+struct mw_datum *mw_datum_new(gpointer data, GDestroyNotify clear);
+
+
+void mw_datum_set(struct mw_datum *d, gpointer data, GDestroyNotify clear);
+
+
+gpointer mw_datum_get(struct mw_datum *d);
+
+
+void mw_datum_clear(struct mw_datum *d);
+
+
+void mw_datum_free(struct mw_datum *d);
+
+
+#endif
diff --git a/protocols/Sametime/src/meanwhile/src/service.c b/protocols/Sametime/src/meanwhile/src/service.c
new file mode 100644
index 0000000000..9ff8d8639f
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/service.c
@@ -0,0 +1,267 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "mw_channel.h"
+#include "mw_debug.h"
+#include "mw_error.h"
+#include "mw_message.h"
+#include "mw_service.h"
+
+
+/* I tried to be explicit with the g_return_* calls, to make the debug
+ logging a bit more sensible. Hence all the explicit "foo != NULL"
+ checks. */
+
+
+void mwService_recvCreate(struct mwService *s, struct mwChannel *chan,
+ struct mwMsgChannelCreate *msg) {
+
+ /* ensure none are null, ensure that the service and channel belong
+ to the same session, and ensure that the message belongs on the
+ channel */
+ g_return_if_fail(s != NULL);
+ g_return_if_fail(chan != NULL);
+ g_return_if_fail(msg != NULL);
+ g_return_if_fail(s->session == mwChannel_getSession(chan));
+ g_return_if_fail(mwChannel_getId(chan) == msg->channel);
+
+ if(s->recv_create) {
+ s->recv_create(s, chan, msg);
+ } else {
+ mwChannel_destroy(chan, ERR_FAILURE, NULL);
+ }
+}
+
+
+void mwService_recvAccept(struct mwService *s, struct mwChannel *chan,
+ struct mwMsgChannelAccept *msg) {
+
+ /* ensure none are null, ensure that the service and channel belong
+ to the same session, and ensure that the message belongs on the
+ channel */
+ g_return_if_fail(s != NULL);
+ g_return_if_fail(chan != NULL);
+ g_return_if_fail(msg != NULL);
+ g_return_if_fail(s->session == mwChannel_getSession(chan));
+ g_return_if_fail(mwChannel_getId(chan) == msg->head.channel);
+
+ if(s->recv_accept)
+ s->recv_accept(s, chan, msg);
+}
+
+
+void mwService_recvDestroy(struct mwService *s, struct mwChannel *chan,
+ struct mwMsgChannelDestroy *msg) {
+
+ /* ensure none are null, ensure that the service and channel belong
+ to the same session, and ensure that the message belongs on the
+ channel */
+ g_return_if_fail(s != NULL);
+ g_return_if_fail(chan != NULL);
+ g_return_if_fail(msg != NULL);
+ g_return_if_fail(s->session == mwChannel_getSession(chan));
+ g_return_if_fail(mwChannel_getId(chan) == msg->head.channel);
+
+ if(s->recv_destroy)
+ s->recv_destroy(s, chan, msg);
+}
+
+
+void mwService_recv(struct mwService *s, struct mwChannel *chan,
+ guint16 msg_type, struct mwOpaque *data) {
+
+ /* ensure that none are null. zero-length messages are acceptable */
+ g_return_if_fail(s != NULL);
+ g_return_if_fail(chan != NULL);
+ g_return_if_fail(data != NULL);
+ g_return_if_fail(s->session == mwChannel_getSession(chan));
+
+ /*
+ g_message("mwService_recv: session = %p, service = %p, b = %p, n = %u",
+ mwService_getSession(s), s, data->data, data->len);
+ */
+
+ if(s->recv)
+ s->recv(s, chan, msg_type, data);
+}
+
+
+guint32 mwService_getType(struct mwService *s) {
+ g_return_val_if_fail(s != NULL, 0x00);
+ return s->type;
+}
+
+
+const char *mwService_getName(struct mwService *s) {
+ g_return_val_if_fail(s != NULL, NULL);
+ g_return_val_if_fail(s->get_name != NULL, NULL);
+
+ return s->get_name(s);
+}
+
+
+const char *mwService_getDesc(struct mwService *s) {
+ g_return_val_if_fail(s != NULL, NULL);
+ g_return_val_if_fail(s->get_desc != NULL, NULL);
+
+ return s->get_desc(s);
+}
+
+
+struct mwSession *mwService_getSession(struct mwService *s) {
+ g_return_val_if_fail(s != NULL, NULL);
+ return s->session;
+}
+
+
+void mwService_init(struct mwService *srvc, struct mwSession *sess,
+ guint32 type) {
+
+ /* ensure nothing is null, and there's no such thing as a zero
+ service type */
+ g_return_if_fail(srvc != NULL);
+ g_return_if_fail(sess != NULL);
+ g_return_if_fail(type != 0x00);
+
+ srvc->session = sess;
+ srvc->type = type;
+ srvc->state = mwServiceState_STOPPED;
+}
+
+
+enum mwServiceState mwService_getState(struct mwService *srvc) {
+ g_return_val_if_fail(srvc != NULL, mwServiceState_STOPPED);
+ return srvc->state;
+}
+
+
+void mwService_start(struct mwService *srvc) {
+ g_return_if_fail(srvc != NULL);
+
+ if(! MW_SERVICE_IS_STOPPED(srvc))
+ return;
+
+ srvc->state = mwServiceState_STARTING;
+ g_message("starting service %s", NSTR(mwService_getName(srvc)));
+
+ if(srvc->start) {
+ srvc->start(srvc);
+ } else {
+ mwService_started(srvc);
+ }
+}
+
+
+void mwService_started(struct mwService *srvc) {
+ g_return_if_fail(srvc != NULL);
+
+ srvc->state = mwServiceState_STARTED;
+ g_message("started service %s", NSTR(mwService_getName(srvc)));
+}
+
+
+void mwService_error(struct mwService *srvc) {
+ g_return_if_fail(srvc != NULL);
+
+ if(MW_SERVICE_IS_DEAD(srvc))
+ return;
+
+ srvc->state = mwServiceState_ERROR;
+ g_message("error in service %s", NSTR(mwService_getName(srvc)));
+
+ if(srvc->stop) {
+ srvc->stop(srvc);
+ } else {
+ mwService_stopped(srvc);
+ }
+}
+
+
+void mwService_stop(struct mwService *srvc) {
+ g_return_if_fail(srvc != NULL);
+
+ if(MW_SERVICE_IS_DEAD(srvc))
+ return;
+
+ srvc->state = mwServiceState_STOPPING;
+ g_message("stopping service %s", NSTR(mwService_getName(srvc)));
+
+ if(srvc->stop) {
+ srvc->stop(srvc);
+ } else {
+ mwService_stopped(srvc);
+ }
+}
+
+
+void mwService_stopped(struct mwService *srvc) {
+ g_return_if_fail(srvc != NULL);
+
+ if(srvc->state != mwServiceState_STOPPED) {
+ srvc->state = mwServiceState_STOPPED;
+ g_message("stopped service %s", NSTR(mwService_getName(srvc)));
+ }
+}
+
+
+void mwService_free(struct mwService *srvc) {
+ g_return_if_fail(srvc != NULL);
+
+ mwService_stop(srvc);
+
+ if(srvc->clear)
+ srvc->clear(srvc);
+
+ if(srvc->client_cleanup)
+ srvc->client_cleanup(srvc->client_data);
+
+ g_free(srvc);
+}
+
+
+/** @todo switch the following to using mw_datum */
+
+void mwService_setClientData(struct mwService *srvc,
+ gpointer data, GDestroyNotify cleanup) {
+
+ g_return_if_fail(srvc != NULL);
+
+ srvc->client_data = data;
+ srvc->client_cleanup = cleanup;
+}
+
+
+gpointer mwService_getClientData(struct mwService *srvc) {
+ g_return_val_if_fail(srvc != NULL, NULL);
+ return srvc->client_data;
+}
+
+
+void mwService_removeClientData(struct mwService *srvc) {
+ g_return_if_fail(srvc != NULL);
+
+ if(srvc->client_cleanup) {
+ srvc->client_cleanup(srvc->client_data);
+ srvc->client_cleanup = NULL;
+ }
+
+ srvc->client_data = NULL;
+}
+
diff --git a/protocols/Sametime/src/meanwhile/src/session.c b/protocols/Sametime/src/meanwhile/src/session.c
new file mode 100644
index 0000000000..6c116b7a58
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/session.c
@@ -0,0 +1,1220 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <glib.h>
+#include <string.h>
+
+#include "mw_channel.h"
+#include "mw_cipher.h"
+#include "mw_debug.h"
+#include "mw_error.h"
+#include "mw_message.h"
+#include "mw_service.h"
+#include "mw_session.h"
+#include "mw_util.h"
+
+
+/** the hash table key for a service, for mwSession::services */
+#define SERVICE_KEY(srvc) mwService_getType(srvc)
+
+/** the hash table key for a cipher, for mwSession::ciphers */
+#define CIPHER_KEY(ciph) mwCipher_getType(ciph)
+
+
+#define GPOINTER(val) (GUINT_TO_POINTER((guint) (val)))
+#define GUINT(val) (GPOINTER_TO_UINT((val)))
+
+
+struct mwSession {
+
+ /** provides I/O and callback functions */
+ struct mwSessionHandler *handler;
+
+ enum mwSessionState state; /**< session state */
+ gpointer state_info; /**< additional state info */
+
+ /* input buffering for an incoming message */
+ guchar *buf; /**< buffer for incoming message data */
+ gsize buf_len; /**< length of buf */
+ gsize buf_used; /**< offset to last-used byte of buf */
+
+ struct mwLoginInfo login; /**< login information */
+ struct mwUserStatus status; /**< user status */
+ struct mwPrivacyInfo privacy; /**< privacy list */
+
+ /** the collection of channels */
+ struct mwChannelSet *channels;
+
+ /** the collection of services, keyed to guint32 service id */
+ GHashTable *services;
+
+ /** the collection of ciphers, keyed to guint16 cipher type */
+ GHashTable *ciphers;
+
+ /** arbitrary key:value pairs */
+ GHashTable *attributes;
+
+ /** optional user data */
+ struct mw_datum client_data;
+};
+
+
+static void property_set(struct mwSession *s, const char *key,
+ gpointer val, GDestroyNotify clean) {
+
+ g_hash_table_insert(s->attributes, g_strdup(key),
+ mw_datum_new(val, clean));
+}
+
+
+static gpointer property_get(struct mwSession *s, const char *key) {
+ struct mw_datum *p = g_hash_table_lookup(s->attributes, key);
+ return p? p->data: NULL;
+}
+
+
+static void property_del(struct mwSession *s, const char *key) {
+ g_hash_table_remove(s->attributes, key);
+}
+
+
+/**
+ set up the default properties for a newly created session
+*/
+static void session_defaults(struct mwSession *s) {
+ property_set(s, mwSession_CLIENT_VER_MAJOR,
+ GPOINTER(MW_PROTOCOL_VERSION_MAJOR), NULL);
+
+ property_set(s, mwSession_CLIENT_VER_MINOR,
+ GPOINTER(MW_PROTOCOL_VERSION_MINOR), NULL);
+
+ property_set(s, mwSession_CLIENT_TYPE_ID,
+ GPOINTER(mwLogin_MEANWHILE), NULL);
+}
+
+
+struct mwSession *mwSession_new(struct mwSessionHandler *handler) {
+ struct mwSession *s;
+
+ g_return_val_if_fail(handler != NULL, NULL);
+
+ /* consider io_write and io_close to be absolute necessities */
+ g_return_val_if_fail(handler->io_write != NULL, NULL);
+ g_return_val_if_fail(handler->io_close != NULL, NULL);
+
+ s = g_new0(struct mwSession, 1);
+
+ s->state = mwSession_STOPPED;
+
+ s->handler = handler;
+
+ s->channels = mwChannelSet_new(s);
+ s->services = map_guint_new();
+ s->ciphers = map_guint_new();
+
+ s->attributes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+ (GDestroyNotify) mw_datum_free);
+
+ session_defaults(s);
+
+ return s;
+}
+
+
+/** free and reset the session buffer */
+static void session_buf_free(struct mwSession *s) {
+ g_return_if_fail(s != NULL);
+
+ g_free(s->buf);
+ s->buf = NULL;
+ s->buf_len = 0;
+ s->buf_used = 0;
+}
+
+
+/** a polite string version of the session state enum */
+static const char *state_str(enum mwSessionState state) {
+ switch(state) {
+ case mwSession_STARTING: return "starting";
+ case mwSession_HANDSHAKE: return "handshake sent";
+ case mwSession_HANDSHAKE_ACK: return "handshake acknowledged";
+ case mwSession_LOGIN: return "login sent";
+ case mwSession_LOGIN_REDIR: return "login redirected";
+ case mwSession_LOGIN_CONT: return "forcing login";
+ case mwSession_LOGIN_ACK: return "login acknowledged";
+ case mwSession_STARTED: return "started";
+ case mwSession_STOPPING: return "stopping";
+ case mwSession_STOPPED: return "stopped";
+
+ case mwSession_UNKNOWN: /* fall-through */
+ default: return "UNKNOWN";
+ }
+}
+
+
+void mwSession_free(struct mwSession *s) {
+ struct mwSessionHandler *h;
+
+ g_return_if_fail(s != NULL);
+
+ if(! mwSession_isStopped(s)) {
+ g_debug("session is not stopped (state: %s), proceeding with free",
+ state_str(s->state));
+ }
+
+ h = s->handler;
+ if(h && h->clear) h->clear(s);
+ s->handler = NULL;
+
+ session_buf_free(s);
+
+ mwChannelSet_free(s->channels);
+ g_hash_table_destroy(s->services);
+ g_hash_table_destroy(s->ciphers);
+ g_hash_table_destroy(s->attributes);
+
+ mwLoginInfo_clear(&s->login);
+ mwUserStatus_clear(&s->status);
+ mwPrivacyInfo_clear(&s->privacy);
+
+ g_free(s);
+}
+
+
+/** write data to the session handler */
+static int io_write(struct mwSession *s, const guchar *buf, gsize len) {
+ g_return_val_if_fail(s != NULL, -1);
+ g_return_val_if_fail(s->handler != NULL, -1);
+ g_return_val_if_fail(s->handler->io_write != NULL, -1);
+
+ return s->handler->io_write(s, buf, len);
+}
+
+
+/** close the session handler */
+static void io_close(struct mwSession *s) {
+ g_return_if_fail(s != NULL);
+ g_return_if_fail(s->handler != NULL);
+ g_return_if_fail(s->handler->io_close != NULL);
+
+ s->handler->io_close(s);
+}
+
+
+static void state(struct mwSession *s, enum mwSessionState state,
+ gpointer info) {
+
+ struct mwSessionHandler *sh;
+
+ g_return_if_fail(s != NULL);
+ g_return_if_fail(s->handler != NULL);
+
+ if(mwSession_isState(s, state)) return;
+
+ s->state = state;
+ s->state_info = info;
+
+ switch(state) {
+ case mwSession_STOPPING:
+ case mwSession_STOPPED:
+ g_message("session state: %s (0x%08x)", state_str(state),
+ GPOINTER_TO_UINT(info));
+ break;
+
+ case mwSession_LOGIN_REDIR:
+ /// Miranda NG adaptation - start - https://developer.pidgin.im/ticket/7563#comment:4
+ //g_message("session state: %s (%s)", state_str(state), (char *)info);
+ g_message("session state: %s (%s)", state_str(state), NSTR((char *)info));
+ /// Miranda NG adaptation - end
+ break;
+
+ default:
+ g_message("session state: %s", state_str(state));
+ }
+
+ sh = s->handler;
+ if(sh && sh->on_stateChange)
+ sh->on_stateChange(s, state, info);
+}
+
+
+void mwSession_start(struct mwSession *s) {
+ struct mwMsgHandshake *msg;
+ int ret;
+
+ g_return_if_fail(s != NULL);
+ g_return_if_fail(mwSession_isStopped(s));
+
+ if(mwSession_isStarted(s) || mwSession_isStarting(s)) {
+ g_debug("attempted to start session that is already started/starting");
+ return;
+ }
+
+ state(s, mwSession_STARTING, 0);
+
+ msg = (struct mwMsgHandshake *) mwMessage_new(mwMessage_HANDSHAKE);
+ msg->major = GUINT(property_get(s, mwSession_CLIENT_VER_MAJOR));
+ msg->minor = GUINT(property_get(s, mwSession_CLIENT_VER_MINOR));
+ msg->login_type = GUINT(property_get(s, mwSession_CLIENT_TYPE_ID));
+
+ msg->loclcalc_addr = GUINT(property_get(s, mwSession_CLIENT_IP));
+
+ if(msg->major >= 0x001e && msg->minor >= 0x001d) {
+ msg->unknown_a = 0x0100;
+ msg->local_host = property_get(s, mwSession_CLIENT_HOST);
+ }
+
+ ret = mwSession_send(s, MW_MESSAGE(msg));
+ mwMessage_free(MW_MESSAGE(msg));
+
+ if(ret) {
+ mwSession_stop(s, CONNECTION_BROKEN);
+ } else {
+ state(s, mwSession_HANDSHAKE, 0);
+ }
+}
+
+
+void mwSession_stop(struct mwSession *s, guint32 reason) {
+ GList *list, *l = NULL;
+ struct mwMsgChannelDestroy *msg;
+
+ g_return_if_fail(s != NULL);
+
+ if(mwSession_isStopped(s) || mwSession_isStopping(s)) {
+ g_debug("attempted to stop session that is already stopped/stopping");
+ return;
+ }
+
+ state(s, mwSession_STOPPING, GUINT_TO_POINTER(reason));
+
+ for(list = l = mwSession_getServices(s); l; l = l->next)
+ mwService_stop(MW_SERVICE(l->data));
+ g_list_free(list);
+
+ msg = (struct mwMsgChannelDestroy *)
+ mwMessage_new(mwMessage_CHANNEL_DESTROY);
+
+ msg->head.channel = MW_MASTER_CHANNEL_ID;
+ msg->reason = reason;
+
+ /* don't care if this fails, we're closing the connection anyway */
+ mwSession_send(s, MW_MESSAGE(msg));
+ mwMessage_free(MW_MESSAGE(msg));
+
+ session_buf_free(s);
+
+ /* close the connection */
+ io_close(s);
+
+ state(s, mwSession_STOPPED, GUINT_TO_POINTER(reason));
+}
+
+
+/** compose authentication information into an opaque based on the
+ password, encrypted via RC2/40 */
+static void compose_auth_rc2_40(struct mwOpaque *auth, const char *pass) {
+ guchar iv[8], key[5];
+ struct mwOpaque a, b, z;
+ struct mwPutBuffer *p;
+
+ /* get an IV and a random five-byte key */
+ mwIV_init(iv);
+ mwKeyRandom(key, 5);
+
+ /* the opaque with the key */
+ a.len = 5;
+ a.data = key;
+
+ /* the opaque to receive the encrypted pass */
+ b.len = 0;
+ b.data = NULL;
+
+ /* the plain-text pass dressed up as an opaque */
+ z.len = strlen(pass);
+ z.data = (guchar *) pass;
+
+ /* the opaque with the encrypted pass */
+ mwEncrypt(a.data, a.len, iv, &z, &b);
+
+ /* an opaque containing the other two opaques */
+ p = mwPutBuffer_new();
+ mwOpaque_put(p, &a);
+ mwOpaque_put(p, &b);
+ mwPutBuffer_finalize(auth, p);
+
+ /* this is the only one to clear, as the other uses a static buffer */
+ mwOpaque_clear(&b);
+}
+
+
+static void compose_auth_rc2_128(struct mwOpaque *auth, const char *pass,
+ guint32 magic, struct mwOpaque *rkey) {
+
+ guchar iv[8];
+ struct mwOpaque a, b, c;
+ struct mwPutBuffer *p;
+
+ struct mwMpi *private, *public;
+ struct mwMpi *remote;
+ struct mwMpi *shared;
+
+ private = mwMpi_new();
+ public = mwMpi_new();
+ remote = mwMpi_new();
+ shared = mwMpi_new();
+
+ mwIV_init(iv);
+
+ mwMpi_randDHKeypair(private, public);
+ mwMpi_import(remote, rkey);
+ mwMpi_calculateDHShared(shared, remote, private);
+
+ /* put the password in opaque a */
+ p = mwPutBuffer_new();
+ guint32_put(p, magic);
+ mwString_put(p, pass);
+ mwPutBuffer_finalize(&a, p);
+
+ /* put the shared key in opaque b */
+ mwMpi_export(shared, &b);
+
+ /* encrypt the password (a) using the shared key (b), put the result
+ in opaque c */
+ mwEncrypt(b.data+(b.len-16), 16, iv, &a, &c);
+
+ /* don't need the shared key anymore, re-use opaque (b) as the
+ export of the public key */
+ mwOpaque_clear(&b);
+ mwMpi_export(public, &b);
+
+ p = mwPutBuffer_new();
+ guint16_put(p, 0x0001); /* XXX: unknown */
+ mwOpaque_put(p, &b);
+ mwOpaque_put(p, &c);
+ mwPutBuffer_finalize(auth, p);
+
+ mwOpaque_clear(&a);
+ mwOpaque_clear(&b);
+ mwOpaque_clear(&c);
+
+ mwMpi_free(private);
+ mwMpi_free(public);
+ mwMpi_free(remote);
+ mwMpi_free(shared);
+}
+
+
+/** handle the receipt of a handshake_ack message by sending the login
+ message */
+static void HANDSHAKE_ACK_recv(struct mwSession *s,
+ struct mwMsgHandshakeAck *msg) {
+ struct mwMsgLogin *log;
+ int ret;
+
+ g_return_if_fail(s != NULL);
+ g_return_if_fail(msg != NULL);
+ g_return_if_fail(mwSession_isState(s, mwSession_HANDSHAKE) ||
+ mwSession_isState(s, mwSession_LOGIN_CONT));
+
+ if(mwSession_isState(s, mwSession_LOGIN_CONT)) {
+ /* this is a login continuation, don't re-send the login. We
+ should receive a login ack in a moment */
+
+ state(s, mwSession_HANDSHAKE_ACK, 0);
+ state(s, mwSession_LOGIN, 0);
+ return;
+
+ } else {
+ state(s, mwSession_HANDSHAKE_ACK, 0);
+ }
+
+ /* record the major/minor versions from the server */
+ property_set(s, mwSession_SERVER_VER_MAJOR, GPOINTER(msg->major), NULL);
+ property_set(s, mwSession_SERVER_VER_MINOR, GPOINTER(msg->minor), NULL);
+
+ /* compose the login message */
+ log = (struct mwMsgLogin *) mwMessage_new(mwMessage_LOGIN);
+ log->login_type = GUINT(property_get(s, mwSession_CLIENT_TYPE_ID));
+ log->name = g_strdup(property_get(s, mwSession_AUTH_USER_ID));
+
+ /** @todo default to password for now. later use token optionally */
+ {
+ const char *pw;
+ pw = property_get(s, mwSession_AUTH_PASSWORD);
+
+ if(msg->data.len >= 64) {
+ /* good login encryption */
+ log->auth_type = mwAuthType_RC2_128;
+ compose_auth_rc2_128(&log->auth_data, pw, msg->magic, &msg->data);
+
+ } else {
+ /* BAD login encryption */
+ log->auth_type = mwAuthType_RC2_40;
+ compose_auth_rc2_40(&log->auth_data, pw);
+ }
+ }
+
+ /* send the login message */
+ ret = mwSession_send(s, MW_MESSAGE(log));
+ mwMessage_free(MW_MESSAGE(log));
+
+ if(! ret) {
+ /* sent login OK, set state appropriately */
+ state(s, mwSession_LOGIN, 0);
+ }
+}
+
+
+/** handle the receipt of a login_ack message. This completes the
+ startup sequence for the session */
+static void LOGIN_ACK_recv(struct mwSession *s,
+ struct mwMsgLoginAck *msg) {
+ GList *ll, *l;
+
+ g_return_if_fail(s != NULL);
+ g_return_if_fail(msg != NULL);
+ g_return_if_fail(mwSession_isState(s, mwSession_LOGIN));
+
+ /* store the login information in the session */
+ mwLoginInfo_clear(&s->login);
+ mwLoginInfo_clone(&s->login, &msg->login);
+
+ state(s, mwSession_LOGIN_ACK, 0);
+
+ /* start up our services */
+ for(ll = l = mwSession_getServices(s); l; l = l->next) {
+ mwService_start(l->data);
+ }
+ g_list_free(ll);
+
+ /* @todo any further startup stuff? */
+
+ state(s, mwSession_STARTED, 0);
+}
+
+
+static void CHANNEL_CREATE_recv(struct mwSession *s,
+ struct mwMsgChannelCreate *msg) {
+ struct mwChannel *chan;
+ chan = mwChannel_newIncoming(s->channels, msg->channel);
+
+ /* hand off to channel */
+ mwChannel_recvCreate(chan, msg);
+}
+
+
+static void CHANNEL_ACCEPT_recv(struct mwSession *s,
+ struct mwMsgChannelAccept *msg) {
+ struct mwChannel *chan;
+ chan = mwChannel_find(s->channels, msg->head.channel);
+
+ g_return_if_fail(chan != NULL);
+
+ /* hand off to channel */
+ mwChannel_recvAccept(chan, msg);
+}
+
+
+static void CHANNEL_DESTROY_recv(struct mwSession *s,
+ struct mwMsgChannelDestroy *msg) {
+
+ /* the server can indicate that we should close the session by
+ destroying the zero channel */
+ if(msg->head.channel == MW_MASTER_CHANNEL_ID) {
+ mwSession_stop(s, msg->reason);
+
+ } else {
+ struct mwChannel *chan;
+ chan = mwChannel_find(s->channels, msg->head.channel);
+
+ /* we don't have any such channel... so I guess we destroyed it.
+ This is to remove a warning from timing errors when two clients
+ both try to close a channel at about the same time. */
+ if(! chan) return;
+
+ /* hand off to channel */
+ mwChannel_recvDestroy(chan, msg);
+ }
+}
+
+
+static void CHANNEL_SEND_recv(struct mwSession *s,
+ struct mwMsgChannelSend *msg) {
+ struct mwChannel *chan;
+ chan = mwChannel_find(s->channels, msg->head.channel);
+
+ /* if we don't have any such channel, we're certainly not going to
+ accept data from it */
+ if(! chan) return;
+
+ /* hand off to channel */
+ mwChannel_recv(chan, msg);
+}
+
+
+static void SET_PRIVACY_LIST_recv(struct mwSession *s,
+ struct mwMsgSetPrivacyList *msg) {
+ struct mwSessionHandler *sh = s->handler;
+
+ /// Miranda NG adaptation start - MSVC
+ ///g_info("SET_PRIVACY_LIST");
+ g_message("SET_PRIVACY_LIST");
+ /// Miranda NG adaptation end
+
+ mwPrivacyInfo_clear(&s->privacy);
+ mwPrivacyInfo_clone(&s->privacy, &msg->privacy);
+
+ if(sh && sh->on_setPrivacyInfo)
+ sh->on_setPrivacyInfo(s);
+}
+
+
+static void SET_USER_STATUS_recv(struct mwSession *s,
+ struct mwMsgSetUserStatus *msg) {
+ struct mwSessionHandler *sh = s->handler;
+
+ mwUserStatus_clear(&s->status);
+ mwUserStatus_clone(&s->status, &msg->status);
+
+ if(sh && sh->on_setUserStatus)
+ sh->on_setUserStatus(s);
+}
+
+
+static void SENSE_SERVICE_recv(struct mwSession *s,
+ struct mwMsgSenseService *msg) {
+ struct mwService *srvc;
+
+ srvc = mwSession_getService(s, msg->service);
+ if(srvc) mwService_start(srvc);
+}
+
+
+static void ADMIN_recv(struct mwSession *s, struct mwMsgAdmin *msg) {
+ struct mwSessionHandler *sh = s->handler;
+
+ if(sh && sh->on_admin)
+ sh->on_admin(s, msg->text);
+}
+
+
+static void ANNOUNCE_recv(struct mwSession *s, struct mwMsgAnnounce *msg) {
+ struct mwSessionHandler *sh = s->handler;
+
+ if(sh && sh->on_announce)
+ sh->on_announce(s, &msg->sender, msg->may_reply, msg->text);
+}
+
+
+static void LOGIN_REDIRECT_recv(struct mwSession *s,
+ struct mwMsgLoginRedirect *msg) {
+
+ state(s, mwSession_LOGIN_REDIR, msg->host);
+}
+
+
+#define CASE(var, type) \
+case mwMessage_ ## var: \
+ var ## _recv(s, (struct type *) msg); \
+ break;
+
+
+static void session_process(struct mwSession *s,
+ const guchar *buf, gsize len) {
+
+ /// Miranda NG adaptation start - MSVC
+ /// struct mwOpaque o = { .len = len, .data = (guchar *) buf };
+ struct mwOpaque o;
+ /// Miranda NG adaptation end
+
+ struct mwGetBuffer *b;
+ struct mwMessage *msg;
+
+ /// Miranda NG adaptation start - MSVC
+ o.len = len;
+ o.data = (guchar*) buf;
+ /// Miranda NG adaptation end
+
+ g_return_if_fail(s != NULL);
+ g_return_if_fail(buf != NULL);
+
+ /* ignore zero-length messages */
+ if(len == 0) return;
+
+ /* wrap up buf */
+ b = mwGetBuffer_wrap(&o);
+
+ /* attempt to parse the message. */
+ msg = mwMessage_get(b);
+
+ if(mwGetBuffer_error(b)) {
+ mw_mailme_opaque(&o, "parsing of message failed");
+ }
+
+ mwGetBuffer_free(b);
+
+ g_return_if_fail(msg != NULL);
+
+ /* handle each of the appropriate incoming types of mwMessage */
+ switch(msg->type) {
+ CASE(HANDSHAKE_ACK, mwMsgHandshakeAck);
+ CASE(LOGIN_REDIRECT, mwMsgLoginRedirect);
+ CASE(LOGIN_ACK, mwMsgLoginAck);
+ CASE(CHANNEL_CREATE, mwMsgChannelCreate);
+ CASE(CHANNEL_DESTROY, mwMsgChannelDestroy);
+ CASE(CHANNEL_SEND, mwMsgChannelSend);
+ CASE(CHANNEL_ACCEPT, mwMsgChannelAccept);
+ CASE(SET_PRIVACY_LIST, mwMsgSetPrivacyList);
+ CASE(SET_USER_STATUS, mwMsgSetUserStatus);
+ CASE(SENSE_SERVICE, mwMsgSenseService);
+ CASE(ADMIN, mwMsgAdmin);
+ CASE(ANNOUNCE, mwMsgAnnounce);
+
+ default:
+ g_warning("unknown message type 0x%04x, no handler", msg->type);
+ }
+
+ mwMessage_free(msg);
+}
+
+
+#undef CASE
+
+
+#define ADVANCE(b, n, count) { b += count; n -= count; }
+
+
+/* handle input to complete an existing buffer */
+static gsize session_recv_cont(struct mwSession *s,
+ const guchar *b, gsize n) {
+
+ /* determine how many bytes still required */
+ gsize x = s->buf_len - s->buf_used;
+
+ /* g_message(" session_recv_cont: session = %p, b = %p, n = %u",
+ s, b, n); */
+
+ if(n < x) {
+ /* not quite enough; still need some more */
+ memcpy(s->buf+s->buf_used, b, n);
+ s->buf_used += n;
+ return 0;
+
+ } else {
+ /* enough to finish the buffer, at least */
+ memcpy(s->buf+s->buf_used, b, x);
+ ADVANCE(b, n, x);
+
+ if(s->buf_len == 4) {
+ /* if only the length bytes were being buffered, we'll now try
+ to complete an actual message */
+
+ struct mwOpaque o = { 4, s->buf };
+ struct mwGetBuffer *gb = mwGetBuffer_wrap(&o);
+ x = guint32_peek(gb);
+ mwGetBuffer_free(gb);
+
+ if(n < x) {
+ /* there isn't enough to meet the demands of the length, so
+ we'll buffer it for next time */
+
+ guchar *t;
+ x += 4;
+ t = (guchar *) g_malloc(x);
+ memcpy(t, s->buf, 4);
+ memcpy(t+4, b, n);
+
+ session_buf_free(s);
+
+ s->buf = t;
+ s->buf_len = x;
+ s->buf_used = n + 4;
+ return 0;
+
+ } else {
+ /* there's enough (maybe more) for a full message. don't need
+ the old session buffer (which recall, was only the length
+ bytes) any more */
+
+ session_buf_free(s);
+ session_process(s, b, x);
+ ADVANCE(b, n, x);
+ }
+
+ } else {
+ /* process the now-complete buffer. remember to skip the first
+ four bytes, since they're just the size count */
+ session_process(s, s->buf+4, s->buf_len-4);
+ session_buf_free(s);
+ }
+ }
+
+ return n;
+}
+
+
+/* handle input when there's nothing previously buffered */
+static gsize session_recv_empty(struct mwSession *s,
+ const guchar *b, gsize n) {
+
+ struct mwOpaque o = { n, (guchar *) b };
+ struct mwGetBuffer *gb;
+ gsize x;
+
+ if(n < 4) {
+ /* uh oh. less than four bytes means we've got an incomplete
+ length indicator. Have to buffer to get the rest of it. */
+ s->buf = (guchar *) g_malloc0(4);
+ memcpy(s->buf, b, n);
+ s->buf_len = 4;
+ s->buf_used = n;
+ return 0;
+ }
+
+ /* peek at the length indicator. if it's a zero length message,
+ don't process, just skip it */
+ gb = mwGetBuffer_wrap(&o);
+ x = guint32_peek(gb);
+ mwGetBuffer_free(gb);
+ if(! x) return n - 4;
+
+ if(n < (x + 4)) {
+ /* if the total amount of data isn't enough to cover the length
+ bytes and the length indicated by those bytes, then we'll need
+ to buffer. This is where the DOS mentioned below in
+ session_recv takes place */
+
+ x += 4;
+ s->buf = (guchar *) g_malloc(x);
+ memcpy(s->buf, b, n);
+ s->buf_len = x;
+ s->buf_used = n;
+ return 0;
+
+ } else {
+ /* advance past length bytes */
+ ADVANCE(b, n, 4);
+
+ /* process and advance */
+ session_process(s, b, x);
+ ADVANCE(b, n, x);
+
+ /* return left-over count */
+ return n;
+ }
+}
+
+
+static gsize session_recv(struct mwSession *s,
+ const guchar *b, gsize n) {
+
+ /* This is messy and kind of confusing. I'd like to simplify it at
+ some point, but the constraints are as follows:
+
+ - buffer up to a single full message on the session buffer
+ - buffer must contain the four length bytes
+ - the four length bytes indicate how much we'll need to buffer
+ - the four length bytes might not arrive all at once, so it's
+ possible that we'll need to buffer to get them.
+ - since our buffering includes the length bytes, we know we
+ still have an incomplete length if the buffer length is only
+ four. */
+
+ /** @todo we should allow a compiled-in upper limit to message
+ sizes, and just drop messages over that size. However, to do that
+ we'd need to keep track of the size of a message and keep
+ dropping bytes until we'd fulfilled the entire length. eg: if we
+ receive a message size of 10MB, we need to pass up exactly 10MB
+ before it's safe to start processing the rest as a new
+ message. As it stands, a malicious packet from the server can run
+ us out of memory by indicating it's going to send us some
+ obscenely long message (even if it never actually sends it) */
+
+ /* g_message(" session_recv: session = %p, b = %p, n = %u",
+ s, b, n); */
+
+ if(s->buf_len == 0) {
+ while(n && (*b & 0x80)) {
+ /* keep-alive and series bytes are ignored */
+ ADVANCE(b, n, 1);
+ }
+ }
+
+ if(n == 0) {
+ return 0;
+
+ } else if(s->buf_len > 0) {
+ return session_recv_cont(s, b, n);
+
+ } else {
+ return session_recv_empty(s, b, n);
+ }
+}
+
+
+#undef ADVANCE
+
+
+void mwSession_recv(struct mwSession *s, const guchar *buf, gsize n) {
+ guchar *b = (guchar *) buf;
+ gsize remain = 0;
+
+ g_return_if_fail(s != NULL);
+
+ while(n > 0) {
+ remain = session_recv(s, b, n);
+ b += (n - remain);
+ n = remain;
+ }
+}
+
+
+int mwSession_send(struct mwSession *s, struct mwMessage *msg) {
+ struct mwPutBuffer *b;
+ struct mwOpaque o;
+ int ret = 0;
+
+ g_return_val_if_fail(s != NULL, -1);
+
+ /* writing nothing is easy */
+ if(! msg) return 0;
+
+ /* first we render the message into an opaque */
+ b = mwPutBuffer_new();
+ mwMessage_put(b, msg);
+ mwPutBuffer_finalize(&o, b);
+
+ /* then we render the opaque into... another opaque! */
+ b = mwPutBuffer_new();
+ mwOpaque_put(b, &o);
+ mwOpaque_clear(&o);
+ mwPutBuffer_finalize(&o, b);
+
+ /* then we use that opaque's data and length to write to the socket */
+ ret = io_write(s, o.data, o.len);
+ mwOpaque_clear(&o);
+
+ /* ensure we could actually write the message */
+ if(! ret) {
+
+ /* special case, as the server doesn't always respond to user
+ status messages. Thus, we trigger the event when we send the
+ messages as well as when we receive them */
+ if(msg->type == mwMessage_SET_USER_STATUS) {
+ SET_USER_STATUS_recv(s, (struct mwMsgSetUserStatus *) msg);
+ }
+ }
+
+ return ret;
+}
+
+
+int mwSession_sendKeepalive(struct mwSession *s) {
+ const guchar b = 0x80;
+
+ g_return_val_if_fail(s != NULL, -1);
+ return io_write(s, &b, 1);
+}
+
+
+int mwSession_forceLogin(struct mwSession *s) {
+ struct mwMsgLoginContinue *msg;
+ int ret;
+
+ g_return_val_if_fail(s != NULL, -1);
+ g_return_val_if_fail(mwSession_isState(s, mwSession_LOGIN_REDIR), -1);
+
+ state(s, mwSession_LOGIN_CONT, 0x00);
+
+ msg = (struct mwMsgLoginContinue *)
+ mwMessage_new(mwMessage_LOGIN_CONTINUE);
+
+ ret = mwSession_send(s, MW_MESSAGE(msg));
+ mwMessage_free(MW_MESSAGE(msg));
+
+ return ret;
+}
+
+
+int mwSession_sendAnnounce(struct mwSession *s, gboolean may_reply,
+ const char *text, const GList *recipients) {
+
+ struct mwMsgAnnounce *msg;
+ int ret;
+
+ g_return_val_if_fail(s != NULL, -1);
+ g_return_val_if_fail(mwSession_isStarted(s), -1);
+
+ msg = (struct mwMsgAnnounce *) mwMessage_new(mwMessage_ANNOUNCE);
+
+ msg->recipients = (GList *) recipients;
+ msg->may_reply = may_reply;
+ msg->text = g_strdup(text);
+
+ ret = mwSession_send(s, MW_MESSAGE(msg));
+
+ msg->recipients = NULL; /* don't kill our recipients param */
+ mwMessage_free(MW_MESSAGE(msg));
+
+ return ret;
+}
+
+
+struct mwSessionHandler *mwSession_getHandler(struct mwSession *s) {
+ g_return_val_if_fail(s != NULL, NULL);
+ return s->handler;
+}
+
+
+struct mwLoginInfo *mwSession_getLoginInfo(struct mwSession *s) {
+ g_return_val_if_fail(s != NULL, NULL);
+ return &s->login;
+}
+
+
+int mwSession_setPrivacyInfo(struct mwSession *s,
+ struct mwPrivacyInfo *privacy) {
+
+ struct mwMsgSetPrivacyList *msg;
+ int ret;
+
+ g_return_val_if_fail(s != NULL, -1);
+ g_return_val_if_fail(privacy != NULL, -1);
+
+ msg = (struct mwMsgSetPrivacyList *)
+ mwMessage_new(mwMessage_SET_PRIVACY_LIST);
+
+ mwPrivacyInfo_clone(&msg->privacy, privacy);
+
+ ret = mwSession_send(s, MW_MESSAGE(msg));
+ mwMessage_free(MW_MESSAGE(msg));
+
+ return ret;
+}
+
+
+struct mwPrivacyInfo *mwSession_getPrivacyInfo(struct mwSession *s) {
+ g_return_val_if_fail(s != NULL, NULL);
+ return &s->privacy;
+}
+
+
+int mwSession_setUserStatus(struct mwSession *s,
+ struct mwUserStatus *stat) {
+
+ struct mwMsgSetUserStatus *msg;
+ int ret;
+
+ g_return_val_if_fail(s != NULL, -1);
+ g_return_val_if_fail(stat != NULL, -1);
+
+ msg = (struct mwMsgSetUserStatus *)
+ mwMessage_new(mwMessage_SET_USER_STATUS);
+
+ mwUserStatus_clone(&msg->status, stat);
+
+ ret = mwSession_send(s, MW_MESSAGE(msg));
+ mwMessage_free(MW_MESSAGE(msg));
+
+ return ret;
+}
+
+
+struct mwUserStatus *mwSession_getUserStatus(struct mwSession *s) {
+ g_return_val_if_fail(s != NULL, NULL);
+ return &s->status;
+}
+
+
+enum mwSessionState mwSession_getState(struct mwSession *s) {
+ g_return_val_if_fail(s != NULL, mwSession_UNKNOWN);
+ return s->state;
+}
+
+
+gpointer mwSession_getStateInfo(struct mwSession *s) {
+ g_return_val_if_fail(s != NULL, 0);
+ return s->state_info;
+}
+
+
+struct mwChannelSet *mwSession_getChannels(struct mwSession *session) {
+ g_return_val_if_fail(session != NULL, NULL);
+ return session->channels;
+}
+
+
+gboolean mwSession_addService(struct mwSession *s, struct mwService *srv) {
+ g_return_val_if_fail(s != NULL, FALSE);
+ g_return_val_if_fail(srv != NULL, FALSE);
+ g_return_val_if_fail(s->services != NULL, FALSE);
+
+ if(map_guint_lookup(s->services, SERVICE_KEY(srv))) {
+ return FALSE;
+
+ } else {
+ map_guint_insert(s->services, SERVICE_KEY(srv), srv);
+ if(mwSession_isState(s, mwSession_STARTED))
+ mwSession_senseService(s, mwService_getType(srv));
+ return TRUE;
+ }
+}
+
+
+struct mwService *mwSession_getService(struct mwSession *s, guint32 srv) {
+ g_return_val_if_fail(s != NULL, NULL);
+ g_return_val_if_fail(s->services != NULL, NULL);
+
+ return map_guint_lookup(s->services, srv);
+}
+
+
+struct mwService *mwSession_removeService(struct mwSession *s, guint32 srv) {
+ struct mwService *svc;
+
+ g_return_val_if_fail(s != NULL, NULL);
+ g_return_val_if_fail(s->services != NULL, NULL);
+
+ svc = map_guint_lookup(s->services, srv);
+ if(svc) map_guint_remove(s->services, srv);
+ return svc;
+}
+
+
+GList *mwSession_getServices(struct mwSession *s) {
+ g_return_val_if_fail(s != NULL, NULL);
+ g_return_val_if_fail(s->services != NULL, NULL);
+
+ return map_collect_values(s->services);
+}
+
+
+void mwSession_senseService(struct mwSession *s, guint32 srvc) {
+ struct mwMsgSenseService *msg;
+
+ g_return_if_fail(s != NULL);
+ g_return_if_fail(srvc != 0x00);
+ g_return_if_fail(mwSession_isStarted(s));
+
+ msg = (struct mwMsgSenseService *)
+ mwMessage_new(mwMessage_SENSE_SERVICE);
+ msg->service = srvc;
+
+ mwSession_send(s, MW_MESSAGE(msg));
+ mwMessage_free(MW_MESSAGE(msg));
+}
+
+
+gboolean mwSession_addCipher(struct mwSession *s, struct mwCipher *c) {
+ g_return_val_if_fail(s != NULL, FALSE);
+ g_return_val_if_fail(c != NULL, FALSE);
+ g_return_val_if_fail(s->ciphers != NULL, FALSE);
+
+ if(map_guint_lookup(s->ciphers, mwCipher_getType(c))) {
+ g_message("cipher %s is already added, apparently",
+ NSTR(mwCipher_getName(c)));
+ return FALSE;
+
+ } else {
+ g_message("adding cipher %s", NSTR(mwCipher_getName(c)));
+ map_guint_insert(s->ciphers, mwCipher_getType(c), c);
+ return TRUE;
+ }
+}
+
+
+struct mwCipher *mwSession_getCipher(struct mwSession *s, guint16 c) {
+ g_return_val_if_fail(s != NULL, NULL);
+ g_return_val_if_fail(s->ciphers != NULL, NULL);
+
+ return map_guint_lookup(s->ciphers, c);
+}
+
+
+struct mwCipher *mwSession_removeCipher(struct mwSession *s, guint16 c) {
+ struct mwCipher *ciph;
+
+ g_return_val_if_fail(s != NULL, NULL);
+ g_return_val_if_fail(s->ciphers != NULL, NULL);
+
+ ciph = map_guint_lookup(s->ciphers, c);
+ if(ciph) map_guint_remove(s->ciphers, c);
+ return ciph;
+}
+
+
+GList *mwSession_getCiphers(struct mwSession *s) {
+ g_return_val_if_fail(s != NULL, NULL);
+ g_return_val_if_fail(s->ciphers != NULL, NULL);
+
+ return map_collect_values(s->ciphers);
+}
+
+
+void mwSession_setProperty(struct mwSession *s, const char *key,
+ gpointer val, GDestroyNotify clean) {
+
+ g_return_if_fail(s != NULL);
+ g_return_if_fail(s->attributes != NULL);
+ g_return_if_fail(key != NULL);
+
+ property_set(s, key, val, clean);
+}
+
+
+gpointer mwSession_getProperty(struct mwSession *s, const char *key) {
+
+ g_return_val_if_fail(s != NULL, NULL);
+ g_return_val_if_fail(s->attributes != NULL, NULL);
+ g_return_val_if_fail(key != NULL, NULL);
+
+ return property_get(s, key);
+}
+
+
+void mwSession_removeProperty(struct mwSession *s, const char *key) {
+ g_return_if_fail(s != NULL);
+ g_return_if_fail(s->attributes != NULL);
+ g_return_if_fail(key != NULL);
+
+ property_del(s, key);
+}
+
+
+void mwSession_setClientData(struct mwSession *session,
+ gpointer data, GDestroyNotify clear) {
+
+ g_return_if_fail(session != NULL);
+ mw_datum_set(&session->client_data, data, clear);
+}
+
+
+gpointer mwSession_getClientData(struct mwSession *session) {
+ g_return_val_if_fail(session != NULL, NULL);
+ return mw_datum_get(&session->client_data);
+}
+
+
+void mwSession_removeClientData(struct mwSession *session) {
+ g_return_if_fail(session != NULL);
+ mw_datum_clear(&session->client_data);
+}
+
diff --git a/protocols/Sametime/src/meanwhile/src/srvc_aware.c b/protocols/Sametime/src/meanwhile/src/srvc_aware.c
new file mode 100644
index 0000000000..8c11be229f
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/srvc_aware.c
@@ -0,0 +1,1341 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <glib.h>
+#include <glib/ghash.h>
+#include <glib/glist.h>
+#include <string.h>
+
+#include "mw_channel.h"
+#include "mw_debug.h"
+#include "mw_error.h"
+#include "mw_message.h"
+#include "mw_service.h"
+#include "mw_session.h"
+#include "mw_srvc_aware.h"
+#include "mw_util.h"
+
+
+struct mwServiceAware {
+ struct mwService service;
+
+ struct mwAwareHandler *handler;
+
+ /** map of ENTRY_KEY(aware_entry):aware_entry */
+ GHashTable *entries;
+
+ /** set of guint32:attrib_watch_entry attribute keys */
+ GHashTable *attribs;
+
+ /** collection of lists of awareness for this service. Each item is
+ a mwAwareList */
+ GList *lists;
+
+ /** the buddy list channel */
+ struct mwChannel *channel;
+};
+
+
+struct mwAwareList {
+
+ /** the owning service */
+ struct mwServiceAware *service;
+
+ /** map of ENTRY_KEY(aware_entry):aware_entry */
+ GHashTable *entries;
+
+ /** set of guint32:attrib_watch_entry attribute keys */
+ GHashTable *attribs;
+
+ struct mwAwareListHandler *handler;
+ struct mw_datum client_data;
+};
+
+
+struct mwAwareAttribute {
+ guint32 key;
+ struct mwOpaque data;
+};
+
+
+struct attrib_entry {
+ guint32 key;
+ GList *membership;
+};
+
+
+/** an actual awareness entry, belonging to any number of aware lists */
+struct aware_entry {
+ struct mwAwareSnapshot aware;
+
+ /** list of mwAwareList containing this entry */
+ GList *membership;
+
+ /** collection of attribute values for this entry.
+ map of ATTRIB_KEY(mwAwareAttribute):mwAwareAttribute */
+ GHashTable *attribs;
+};
+
+
+#define ENTRY_KEY(entry) &entry->aware.id
+
+
+/** the channel send types used by this service */
+enum msg_types {
+ msg_AWARE_ADD = 0x0068, /**< remove an aware */
+ msg_AWARE_REMOVE = 0x0069, /**< add an aware */
+
+ msg_OPT_DO_SET = 0x00c9, /**< set an attribute */
+ msg_OPT_DO_UNSET = 0x00ca, /**< unset an attribute */
+ msg_OPT_WATCH = 0x00cb, /**< set the attribute watch list */
+
+ msg_AWARE_SNAPSHOT = 0x01f4, /**< recv aware snapshot */
+ msg_AWARE_UPDATE = 0x01f5, /**< recv aware update */
+ msg_AWARE_GROUP = 0x01f6, /**< recv group aware */
+
+ msg_OPT_GOT_SET = 0x0259, /**< recv attribute set update */
+ msg_OPT_GOT_UNSET = 0x025a, /**< recv attribute unset update */
+
+ msg_OPT_GOT_UNKNOWN = 0x025b, /**< UNKNOWN */
+
+ msg_OPT_DID_SET = 0x025d, /**< attribute set response */
+ msg_OPT_DID_UNSET = 0x025e, /**< attribute unset response */
+ msg_OPT_DID_ERROR = 0x025f, /**< attribute set/unset error */
+};
+
+
+static void aware_entry_free(struct aware_entry *ae) {
+ mwAwareSnapshot_clear(&ae->aware);
+ g_list_free(ae->membership);
+ g_hash_table_destroy(ae->attribs);
+ g_free(ae);
+}
+
+
+static void attrib_entry_free(struct attrib_entry *ae) {
+ g_list_free(ae->membership);
+ g_free(ae);
+}
+
+
+static void attrib_free(struct mwAwareAttribute *attrib) {
+ mwOpaque_clear(&attrib->data);
+ g_free(attrib);
+}
+
+
+static struct aware_entry *aware_find(struct mwServiceAware *srvc,
+ struct mwAwareIdBlock *srch) {
+ g_return_val_if_fail(srvc != NULL, NULL);
+ g_return_val_if_fail(srvc->entries != NULL, NULL);
+ g_return_val_if_fail(srch != NULL, NULL);
+
+ return g_hash_table_lookup(srvc->entries, srch);
+}
+
+
+static struct aware_entry *list_aware_find(struct mwAwareList *list,
+ struct mwAwareIdBlock *srch) {
+ g_return_val_if_fail(list != NULL, NULL);
+ g_return_val_if_fail(list->entries != NULL, NULL);
+ g_return_val_if_fail(srch != NULL, NULL);
+
+ return g_hash_table_lookup(list->entries, srch);
+}
+
+
+static void compose_list(struct mwPutBuffer *b, GList *id_list) {
+ guint32_put(b, g_list_length(id_list));
+ for(; id_list; id_list = id_list->next)
+ mwAwareIdBlock_put(b, id_list->data);
+}
+
+
+static int send_add(struct mwChannel *chan, GList *id_list) {
+ struct mwPutBuffer *b = mwPutBuffer_new();
+ struct mwOpaque o;
+ int ret;
+
+ g_return_val_if_fail(chan != NULL, 0);
+
+ compose_list(b, id_list);
+
+ mwPutBuffer_finalize(&o, b);
+
+ ret = mwChannel_send(chan, msg_AWARE_ADD, &o);
+ mwOpaque_clear(&o);
+
+ return ret;
+}
+
+
+static int send_rem(struct mwChannel *chan, GList *id_list) {
+ struct mwPutBuffer *b = mwPutBuffer_new();
+ struct mwOpaque o;
+ int ret;
+
+ g_return_val_if_fail(chan != NULL, 0);
+
+ compose_list(b, id_list);
+ mwPutBuffer_finalize(&o, b);
+
+ ret = mwChannel_send(chan, msg_AWARE_REMOVE, &o);
+ mwOpaque_clear(&o);
+
+ return ret;
+}
+
+
+static gboolean collect_dead(gpointer key, gpointer val, gpointer data) {
+ struct aware_entry *aware = val;
+ GList **dead = data;
+
+ if(aware->membership == NULL) {
+ // Miranda NG adaptation
+ //g_info(" removing %s, %s",
+ // NSTR(aware->aware.id.user), NSTR(aware->aware.id.community));
+ g_message(" removing %s, %s", NSTR(aware->aware.id.user), NSTR(aware->aware.id.community));
+ *dead = g_list_append(*dead, aware);
+ return TRUE;
+
+ } else {
+ return FALSE;
+ }
+}
+
+
+static int remove_unused(struct mwServiceAware *srvc) {
+ /* - create a GList of all the unused aware entries
+ - remove each unused aware from the service
+ - if the service is alive, send a removal message for the collected
+ unused.
+ */
+
+ int ret = 0;
+ GList *dead = NULL, *l;
+
+ if(srvc->entries) {
+ // Miranda NG adaptation
+ //g_info("bring out your dead *clang*");
+ g_message("bring out your dead *clang*");
+ g_hash_table_foreach_steal(srvc->entries, collect_dead, &dead);
+ }
+
+ if(dead) {
+ if(MW_SERVICE_IS_LIVE(srvc))
+ ret = send_rem(srvc->channel, dead) || ret;
+
+ for(l = dead; l; l = l->next)
+ aware_entry_free(l->data);
+
+ g_list_free(dead);
+ }
+
+ return ret;
+}
+
+
+static int send_attrib_list(struct mwServiceAware *srvc) {
+ struct mwPutBuffer *b;
+ struct mwOpaque o;
+
+ int tmp;
+ GList *l;
+
+ g_return_val_if_fail(srvc != NULL, -1);
+ g_return_val_if_fail(srvc->channel != NULL, 0);
+
+ l = map_collect_keys(srvc->attribs);
+ tmp = g_list_length(l);
+
+ b = mwPutBuffer_new();
+ guint32_put(b, 0x00);
+ guint32_put(b, tmp);
+
+ for(; l; l = g_list_delete_link(l, l)) {
+ guint32_put(b, GPOINTER_TO_UINT(l->data));
+ }
+
+ mwPutBuffer_finalize(&o, b);
+ tmp = mwChannel_send(srvc->channel, msg_OPT_WATCH, &o);
+ mwOpaque_clear(&o);
+
+ return tmp;
+}
+
+
+static gboolean collect_attrib_dead(gpointer key, gpointer val,
+ gpointer data) {
+
+ struct attrib_entry *attrib = val;
+ GList **dead = data;
+
+ if(attrib->membership == NULL) {
+ // Miranda NG adaptation
+ //g_info(" removing 0x%08x", GPOINTER_TO_UINT(key));
+ g_message(" removing 0x%08x", GPOINTER_TO_UINT(key));
+ *dead = g_list_append(*dead, attrib);
+ return TRUE;
+
+ } else {
+ return FALSE;
+ }
+}
+
+
+static int remove_unused_attrib(struct mwServiceAware *srvc) {
+ GList *dead = NULL;
+
+ if(srvc->attribs) {
+ // Miranda NG adaptation
+ //g_info("collecting dead attributes");
+ g_message("collecting dead attributes");
+ g_hash_table_foreach_steal(srvc->attribs, collect_attrib_dead, &dead);
+ }
+
+ /* since we stole them, we'll have to clean 'em up manually */
+ for(; dead; dead = g_list_delete_link(dead, dead)) {
+ attrib_entry_free(dead->data);
+ }
+
+ return MW_SERVICE_IS_LIVE(srvc)? send_attrib_list(srvc): 0;
+}
+
+
+static void recv_accept(struct mwServiceAware *srvc,
+ struct mwChannel *chan,
+ struct mwMsgChannelAccept *msg) {
+
+ g_return_if_fail(srvc->channel != NULL);
+ g_return_if_fail(srvc->channel == chan);
+
+ if(MW_SERVICE_IS_STARTING(MW_SERVICE(srvc))) {
+ GList *list = NULL;
+
+ list = map_collect_values(srvc->entries);
+ send_add(chan, list);
+ g_list_free(list);
+
+ send_attrib_list(srvc);
+
+ mwService_started(MW_SERVICE(srvc));
+
+ } else {
+ mwChannel_destroy(chan, ERR_FAILURE, NULL);
+ }
+}
+
+
+static void recv_destroy(struct mwServiceAware *srvc,
+ struct mwChannel *chan,
+ struct mwMsgChannelDestroy *msg) {
+
+ srvc->channel = NULL;
+ mwService_stop(MW_SERVICE(srvc));
+
+ /** @todo session sense service and mwService_start */
+}
+
+
+/** called from SNAPSHOT_recv, UPDATE_recv, and
+ mwServiceAware_setStatus */
+static void status_recv(struct mwServiceAware *srvc,
+ struct mwAwareSnapshot *idb) {
+
+ struct aware_entry *aware;
+ GList *l;
+
+ aware = aware_find(srvc, &idb->id);
+
+ if(! aware) {
+ /* we don't deal with receiving status for something we're not
+ monitoring, but it will happen sometimes, eg from manually set
+ status */
+ return;
+ }
+
+ /* clear the existing status, then clone in the new status */
+ mwAwareSnapshot_clear(&aware->aware);
+ mwAwareSnapshot_clone(&aware->aware, idb);
+
+ /* trigger each of the entry's lists */
+ for(l = aware->membership; l; l = l->next) {
+ struct mwAwareList *alist = l->data;
+ struct mwAwareListHandler *handler = alist->handler;
+
+ if(handler && handler->on_aware)
+ handler->on_aware(alist, idb);
+ }
+}
+
+
+static void attrib_recv(struct mwServiceAware *srvc,
+ struct mwAwareIdBlock *idb,
+ struct mwAwareAttribute *attrib) {
+
+ struct aware_entry *aware;
+ struct mwAwareAttribute *old_attrib = NULL;
+ GList *l;
+ guint32 key;
+ gpointer k;
+
+ aware = aware_find(srvc, idb);
+ g_return_if_fail(aware != NULL);
+
+ key = attrib->key;
+ k = GUINT_TO_POINTER(key);
+
+ if(aware->attribs)
+ old_attrib = g_hash_table_lookup(aware->attribs, k);
+
+ if(! old_attrib) {
+ old_attrib = g_new0(struct mwAwareAttribute, 1);
+ old_attrib->key = key;
+ g_hash_table_insert(aware->attribs, k, old_attrib);
+ }
+
+ mwOpaque_clear(&old_attrib->data);
+ mwOpaque_clone(&old_attrib->data, &attrib->data);
+
+ for(l = aware->membership; l; l = l->next) {
+ struct mwAwareList *list = l->data;
+ struct mwAwareListHandler *h = list->handler;
+
+ if(h && h->on_attrib &&
+ list->attribs && g_hash_table_lookup(list->attribs, k))
+
+ h->on_attrib(list, idb, old_attrib);
+ }
+}
+
+
+static gboolean list_add(struct mwAwareList *list,
+ struct mwAwareIdBlock *id) {
+
+ struct mwServiceAware *srvc = list->service;
+ struct aware_entry *aware;
+
+ g_return_val_if_fail(id->user != NULL, FALSE);
+ g_return_val_if_fail(strlen(id->user) > 0, FALSE);
+
+ if(! list->entries)
+ list->entries = g_hash_table_new((GHashFunc) mwAwareIdBlock_hash,
+ (GEqualFunc) mwAwareIdBlock_equal);
+
+ aware = list_aware_find(list, id);
+ if(aware) return FALSE;
+
+ aware = aware_find(srvc, id);
+ if(! aware) {
+ aware = g_new0(struct aware_entry, 1);
+ aware->attribs = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
+ (GDestroyNotify) attrib_free);
+ mwAwareIdBlock_clone(ENTRY_KEY(aware), id);
+
+ g_hash_table_insert(srvc->entries, ENTRY_KEY(aware), aware);
+ }
+
+ aware->membership = g_list_append(aware->membership, list);
+
+ g_hash_table_insert(list->entries, ENTRY_KEY(aware), aware);
+
+ return TRUE;
+}
+
+
+static void group_member_recv(struct mwServiceAware *srvc,
+ struct mwAwareSnapshot *idb) {
+ /* @todo
+ - look up group by id
+ - find each list group belongs to
+ - add user to lists
+ */
+
+ struct mwAwareIdBlock gsrch = { mwAware_GROUP, idb->group, NULL };
+ struct aware_entry *grp;
+ GList *l, *m;
+
+ grp = aware_find(srvc, &gsrch);
+ g_return_if_fail(grp != NULL); /* this could happen, with timing. */
+
+ l = g_list_prepend(NULL, &idb->id);
+
+ for(m = grp->membership; m; m = m->next) {
+
+ /* if we just list_add, we won't receive updates for attributes,
+ so annoyingly we have to turn around and send out an add aware
+ message for each incoming group member */
+
+ /* list_add(m->data, &idb->id); */
+ mwAwareList_addAware(m->data, l);
+ }
+
+ g_list_free(l);
+}
+
+
+static void recv_SNAPSHOT(struct mwServiceAware *srvc,
+ struct mwGetBuffer *b) {
+
+ guint32 count;
+
+ struct mwAwareSnapshot *snap;
+ snap = g_new0(struct mwAwareSnapshot, 1);
+
+ guint32_get(b, &count);
+
+ while(count--) {
+ mwAwareSnapshot_get(b, snap);
+
+ if(mwGetBuffer_error(b)) {
+ mwAwareSnapshot_clear(snap);
+ break;
+ }
+
+ if(snap->group)
+ group_member_recv(srvc, snap);
+
+ status_recv(srvc, snap);
+ mwAwareSnapshot_clear(snap);
+ }
+
+ g_free(snap);
+}
+
+
+static void recv_UPDATE(struct mwServiceAware *srvc,
+ struct mwGetBuffer *b) {
+
+ struct mwAwareSnapshot *snap;
+
+ snap = g_new0(struct mwAwareSnapshot, 1);
+ mwAwareSnapshot_get(b, snap);
+
+ if(snap->group)
+ group_member_recv(srvc, snap);
+
+ if(! mwGetBuffer_error(b))
+ status_recv(srvc, snap);
+
+ mwAwareSnapshot_clear(snap);
+ g_free(snap);
+}
+
+
+static void recv_GROUP(struct mwServiceAware *srvc,
+ struct mwGetBuffer *b) {
+
+ struct mwAwareIdBlock idb = { 0, 0, 0 };
+
+ /* really nothing to be done with this. The group should have
+ already been added to the list and service, and is now simply
+ awaiting a snapshot/update with users listed as belonging in said
+ group. */
+
+ mwAwareIdBlock_get(b, &idb);
+ mwAwareIdBlock_clear(&idb);
+}
+
+
+static void recv_OPT_GOT_SET(struct mwServiceAware *srvc,
+ struct mwGetBuffer *b) {
+
+ struct mwAwareAttribute attrib;
+ struct mwAwareIdBlock idb;
+ guint32 junk, check;
+
+ guint32_get(b, &junk);
+ mwAwareIdBlock_get(b, &idb);
+ guint32_get(b, &junk);
+ guint32_get(b, &check);
+ guint32_get(b, &junk);
+ guint32_get(b, &attrib.key);
+
+ if(check) {
+ mwOpaque_get(b, &attrib.data);
+ } else {
+ attrib.data.len = 0;
+ attrib.data.data = NULL;
+ }
+
+ attrib_recv(srvc, &idb, &attrib);
+
+ mwAwareIdBlock_clear(&idb);
+ mwOpaque_clear(&attrib.data);
+}
+
+
+static void recv_OPT_GOT_UNSET(struct mwServiceAware *srvc,
+ struct mwGetBuffer *b) {
+
+ struct mwAwareAttribute attrib;
+ struct mwAwareIdBlock idb;
+ guint32 junk;
+
+ attrib.key = 0;
+ attrib.data.len = 0;
+ attrib.data.data = NULL;
+
+ guint32_get(b, &junk);
+ mwAwareIdBlock_get(b, &idb);
+ guint32_get(b, &attrib.key);
+
+ attrib_recv(srvc, &idb, &attrib);
+
+ mwAwareIdBlock_clear(&idb);
+}
+
+
+static void recv(struct mwService *srvc, struct mwChannel *chan,
+ guint16 type, struct mwOpaque *data) {
+
+ struct mwServiceAware *srvc_aware = (struct mwServiceAware *) srvc;
+ struct mwGetBuffer *b;
+
+ g_return_if_fail(srvc_aware->channel == chan);
+ g_return_if_fail(srvc->session == mwChannel_getSession(chan));
+ g_return_if_fail(data != NULL);
+
+ b = mwGetBuffer_wrap(data);
+
+ switch(type) {
+ case msg_AWARE_SNAPSHOT:
+ recv_SNAPSHOT(srvc_aware, b);
+ break;
+
+ case msg_AWARE_UPDATE:
+ recv_UPDATE(srvc_aware, b);
+ break;
+
+ case msg_AWARE_GROUP:
+ recv_GROUP(srvc_aware, b);
+ break;
+
+ case msg_OPT_GOT_SET:
+ recv_OPT_GOT_SET(srvc_aware, b);
+ break;
+
+ case msg_OPT_GOT_UNSET:
+ recv_OPT_GOT_UNSET(srvc_aware, b);
+ break;
+
+ case msg_OPT_GOT_UNKNOWN:
+ case msg_OPT_DID_SET:
+ case msg_OPT_DID_UNSET:
+ case msg_OPT_DID_ERROR:
+ break;
+
+ default:
+ mw_mailme_opaque(data, "unknown message in aware service: 0x%04x", type);
+ }
+
+ mwGetBuffer_free(b);
+}
+
+
+static void clear(struct mwService *srvc) {
+ struct mwServiceAware *srvc_aware = (struct mwServiceAware *) srvc;
+
+ g_return_if_fail(srvc != NULL);
+
+ while(srvc_aware->lists)
+ mwAwareList_free( (struct mwAwareList *) srvc_aware->lists->data );
+
+ g_hash_table_destroy(srvc_aware->entries);
+ srvc_aware->entries = NULL;
+
+ g_hash_table_destroy(srvc_aware->attribs);
+ srvc_aware->attribs = NULL;
+}
+
+
+static const char *name(struct mwService *srvc) {
+ return "Presence Awareness";
+}
+
+
+static const char *desc(struct mwService *srvc) {
+ return "Buddy list service with support for server-side groups";
+}
+
+
+static struct mwChannel *make_blist(struct mwServiceAware *srvc,
+ struct mwChannelSet *cs) {
+
+ struct mwChannel *chan = mwChannel_newOutgoing(cs);
+
+ mwChannel_setService(chan, MW_SERVICE(srvc));
+ mwChannel_setProtoType(chan, 0x00000011);
+ mwChannel_setProtoVer(chan, 0x00030005);
+
+ return mwChannel_create(chan)? NULL: chan;
+}
+
+
+static void start(struct mwService *srvc) {
+ struct mwServiceAware *srvc_aware;
+ struct mwChannel *chan = NULL;
+
+ srvc_aware = (struct mwServiceAware *) srvc;
+ chan = make_blist(srvc_aware, mwSession_getChannels(srvc->session));
+
+ if(chan != NULL) {
+ srvc_aware->channel = chan;
+ } else {
+ mwService_stopped(srvc);
+ }
+}
+
+
+static void stop(struct mwService *srvc) {
+ struct mwServiceAware *srvc_aware;
+
+ srvc_aware = (struct mwServiceAware *) srvc;
+
+ if(srvc_aware->channel) {
+ mwChannel_destroy(srvc_aware->channel, ERR_SUCCESS, NULL);
+ srvc_aware->channel = NULL;
+ }
+
+ mwService_stopped(srvc);
+}
+
+
+struct mwServiceAware *
+mwServiceAware_new(struct mwSession *session,
+ struct mwAwareHandler *handler) {
+
+ struct mwService *service;
+ struct mwServiceAware *srvc;
+
+ g_return_val_if_fail(session != NULL, NULL);
+ g_return_val_if_fail(handler != NULL, NULL);
+
+ srvc = g_new0(struct mwServiceAware, 1);
+ srvc->handler = handler;
+ srvc->entries = g_hash_table_new_full((GHashFunc) mwAwareIdBlock_hash,
+ (GEqualFunc) mwAwareIdBlock_equal,
+ NULL,
+ (GDestroyNotify) aware_entry_free);
+
+ srvc->attribs = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
+ (GDestroyNotify) attrib_entry_free);
+
+ service = MW_SERVICE(srvc);
+ mwService_init(service, session, mwService_AWARE);
+
+ service->recv_accept = (mwService_funcRecvAccept) recv_accept;
+ service->recv_destroy = (mwService_funcRecvDestroy) recv_destroy;
+ service->recv = recv;
+ service->start = start;
+ service->stop = stop;
+ service->clear = clear;
+ service->get_name = name;
+ service->get_desc = desc;
+
+ return srvc;
+}
+
+
+int mwServiceAware_setAttribute(struct mwServiceAware *srvc,
+ guint32 key, struct mwOpaque *data) {
+ struct mwPutBuffer *b;
+ struct mwOpaque o;
+ int ret;
+
+ b = mwPutBuffer_new();
+
+ guint32_put(b, 0x00);
+ guint32_put(b, data->len);
+ guint32_put(b, 0x00);
+ guint32_put(b, key);
+ mwOpaque_put(b, data);
+
+ mwPutBuffer_finalize(&o, b);
+ ret = mwChannel_send(srvc->channel, msg_OPT_DO_SET, &o);
+ mwOpaque_clear(&o);
+
+ return ret;
+}
+
+
+int mwServiceAware_setAttributeBoolean(struct mwServiceAware *srvc,
+ guint32 key, gboolean val) {
+ int ret;
+ struct mwPutBuffer *b;
+ struct mwOpaque o;
+
+ b = mwPutBuffer_new();
+
+ gboolean_put(b, FALSE);
+ gboolean_put(b, val);
+
+ mwPutBuffer_finalize(&o, b);
+
+ ret = mwServiceAware_setAttribute(srvc, key, &o);
+ mwOpaque_clear(&o);
+
+ return ret;
+}
+
+
+int mwServiceAware_setAttributeInteger(struct mwServiceAware *srvc,
+ guint32 key, guint32 val) {
+ int ret;
+ struct mwPutBuffer *b;
+ struct mwOpaque o;
+
+ b = mwPutBuffer_new();
+ guint32_put(b, val);
+
+ mwPutBuffer_finalize(&o, b);
+
+ ret = mwServiceAware_setAttribute(srvc, key, &o);
+ mwOpaque_clear(&o);
+
+ return ret;
+}
+
+
+int mwServiceAware_setAttributeString(struct mwServiceAware *srvc,
+ guint32 key, const char *str) {
+ int ret;
+ struct mwPutBuffer *b;
+ struct mwOpaque o;
+
+ b = mwPutBuffer_new();
+ mwString_put(b, str);
+
+ mwPutBuffer_finalize(&o, b);
+
+ ret = mwServiceAware_setAttribute(srvc, key, &o);
+ mwOpaque_clear(&o);
+
+ return ret;
+}
+
+
+int mwServiceAware_unsetAttribute(struct mwServiceAware *srvc,
+ guint32 key) {
+ struct mwPutBuffer *b;
+ struct mwOpaque o;
+ int ret;
+
+ b = mwPutBuffer_new();
+
+ guint32_put(b, 0x00);
+ guint32_put(b, key);
+
+ mwPutBuffer_finalize(&o, b);
+ ret = mwChannel_send(srvc->channel, msg_OPT_DO_UNSET, &o);
+ mwOpaque_clear(&o);
+
+ return ret;
+}
+
+
+guint32 mwAwareAttribute_getKey(const struct mwAwareAttribute *attrib) {
+ g_return_val_if_fail(attrib != NULL, 0x00);
+ return attrib->key;
+}
+
+
+gboolean mwAwareAttribute_asBoolean(const struct mwAwareAttribute *attrib) {
+ struct mwGetBuffer *b;
+ gboolean ret;
+
+ if(! attrib) return FALSE;
+
+ b = mwGetBuffer_wrap(&attrib->data);
+ if(attrib->data.len >= 4) {
+ guint32 r32 = 0x00;
+ guint32_get(b, &r32);
+ ret = !! r32;
+
+ } else if(attrib->data.len >= 2) {
+ guint16 r16 = 0x00;
+ guint16_get(b, &r16);
+ ret = !! r16;
+
+ } else if(attrib->data.len) {
+ gboolean_get(b, &ret);
+ }
+
+ mwGetBuffer_free(b);
+
+ return ret;
+}
+
+
+guint32 mwAwareAttribute_asInteger(const struct mwAwareAttribute *attrib) {
+ struct mwGetBuffer *b;
+ guint32 r32 = 0x00;
+
+ if(! attrib) return 0x00;
+
+ b = mwGetBuffer_wrap(&attrib->data);
+ if(attrib->data.len >= 4) {
+ guint32_get(b, &r32);
+
+ } else if(attrib->data.len == 3) {
+ gboolean rb = FALSE;
+ guint16 r16 = 0x00;
+ gboolean_get(b, &rb);
+ guint16_get(b, &r16);
+ r32 = (guint32) r16;
+
+ } else if(attrib->data.len == 2) {
+ guint16 r16 = 0x00;
+ guint16_get(b, &r16);
+ r32 = (guint32) r16;
+
+ } else if(attrib->data.len) {
+ gboolean rb = FALSE;
+ gboolean_get(b, &rb);
+ r32 = (guint32) rb;
+ }
+
+ mwGetBuffer_free(b);
+
+ return r32;
+}
+
+
+char *mwAwareAttribute_asString(const struct mwAwareAttribute *attrib) {
+ struct mwGetBuffer *b;
+ char *ret = NULL;
+
+ if(! attrib) return NULL;
+
+ b = mwGetBuffer_wrap(&attrib->data);
+ mwString_get(b, &ret);
+ mwGetBuffer_free(b);
+
+ return ret;
+}
+
+
+const struct mwOpaque *
+mwAwareAttribute_asOpaque(const struct mwAwareAttribute *attrib) {
+ g_return_val_if_fail(attrib != NULL, NULL);
+ return &attrib->data;
+}
+
+
+struct mwAwareList *
+mwAwareList_new(struct mwServiceAware *srvc,
+ struct mwAwareListHandler *handler) {
+
+ struct mwAwareList *al;
+
+ g_return_val_if_fail(srvc != NULL, NULL);
+ g_return_val_if_fail(handler != NULL, NULL);
+
+ al = g_new0(struct mwAwareList, 1);
+ al->service = srvc;
+ al->handler = handler;
+
+ srvc->lists = g_list_prepend(srvc->lists, al);
+
+ return al;
+}
+
+
+void mwAwareList_free(struct mwAwareList *list) {
+ struct mwServiceAware *srvc;
+ struct mwAwareListHandler *handler;
+
+ g_return_if_fail(list != NULL);
+ g_return_if_fail(list->service != NULL);
+
+ srvc = list->service;
+ srvc->lists = g_list_remove_all(srvc->lists, list);
+
+ handler = list->handler;
+ if(handler && handler->clear) {
+ handler->clear(list);
+ list->handler = NULL;
+ }
+
+ mw_datum_clear(&list->client_data);
+
+ mwAwareList_unwatchAllAttributes(list);
+ mwAwareList_removeAllAware(list);
+
+ list->service = NULL;
+
+ g_free(list);
+}
+
+
+struct mwAwareListHandler *mwAwareList_getHandler(struct mwAwareList *list) {
+ g_return_val_if_fail(list != NULL, NULL);
+ return list->handler;
+}
+
+
+/// Miranda NG adaptation start - new method
+struct mwServiceAware *mwAwareList_getServiceAware(struct mwAwareList *list) {
+ g_return_val_if_fail(list != NULL, NULL);
+ return list->service;
+}
+/// Miranda NG adaptation end
+
+
+static void watch_add(struct mwAwareList *list, guint32 key) {
+ struct mwServiceAware *srvc;
+ struct attrib_entry *watch;
+ gpointer k = GUINT_TO_POINTER(key);
+
+ if(! list->attribs)
+ list->attribs = g_hash_table_new(g_direct_hash, g_direct_equal);
+
+ if(g_hash_table_lookup(list->attribs, k))
+ return;
+
+ srvc = list->service;
+
+ watch = g_hash_table_lookup(srvc->attribs, k);
+ if(! watch) {
+ watch = g_new0(struct attrib_entry, 1);
+ watch->key = key;
+ g_hash_table_insert(srvc->attribs, k, watch);
+ }
+
+ g_hash_table_insert(list->attribs, k, watch);
+
+ watch->membership = g_list_prepend(watch->membership, list);
+}
+
+
+static void watch_remove(struct mwAwareList *list, guint32 key) {
+ struct attrib_entry *watch = NULL;
+ gpointer k = GUINT_TO_POINTER(key);
+
+ if(list->attribs)
+ watch = g_hash_table_lookup(list->attribs, k);
+
+ g_return_if_fail(watch != NULL);
+
+ g_hash_table_remove(list->attribs, k);
+ watch->membership = g_list_remove(watch->membership, list);
+}
+
+
+int mwAwareList_watchAttributeArray(struct mwAwareList *list,
+ guint32 *keys) {
+ guint32 k;
+
+ g_return_val_if_fail(list != NULL, -1);
+ g_return_val_if_fail(list->service != NULL, -1);
+
+ if(! keys) return 0;
+
+ for(k = *keys; k; keys++)
+ watch_add(list, k);
+
+ return send_attrib_list(list->service);
+}
+
+
+int mwAwareList_watchAttributes(struct mwAwareList *list,
+ guint32 key, ...) {
+ guint32 k;
+ va_list args;
+
+ g_return_val_if_fail(list != NULL, -1);
+ g_return_val_if_fail(list->service != NULL, -1);
+
+ va_start(args, key);
+ for(k = key; k; k = va_arg(args, guint32))
+ watch_add(list, k);
+ va_end(args);
+
+ return send_attrib_list(list->service);
+}
+
+
+int mwAwareList_unwatchAttributeArray(struct mwAwareList *list,
+ guint32 *keys) {
+ guint32 k;
+
+ g_return_val_if_fail(list != NULL, -1);
+ g_return_val_if_fail(list->service != NULL, -1);
+
+ if(! keys) return 0;
+
+ for(k = *keys; k; keys++)
+ watch_add(list, k);
+
+ return remove_unused_attrib(list->service);
+}
+
+
+int mwAwareList_unwatchAttributes(struct mwAwareList *list,
+ guint32 key, ...) {
+ guint32 k;
+ va_list args;
+
+ g_return_val_if_fail(list != NULL, -1);
+ g_return_val_if_fail(list->service != NULL, -1);
+
+ va_start(args, key);
+ for(k = key; k; k = va_arg(args, guint32))
+ watch_remove(list, k);
+ va_end(args);
+
+ return remove_unused_attrib(list->service);
+}
+
+
+static void dismember_attrib(gpointer k, struct attrib_entry *watch,
+ struct mwAwareList *list) {
+
+ watch->membership = g_list_remove(watch->membership, list);
+}
+
+
+int mwAwareList_unwatchAllAttributes(struct mwAwareList *list) {
+
+ struct mwServiceAware *srvc;
+
+ g_return_val_if_fail(list != NULL, -1);
+ srvc = list->service;
+
+ if(list->attribs) {
+ g_hash_table_foreach(list->attribs, (GHFunc) dismember_attrib, list);
+ g_hash_table_destroy(list->attribs);
+ }
+
+ return remove_unused_attrib(srvc);
+}
+
+
+static void collect_attrib_keys(gpointer key, struct attrib_entry *attrib,
+ guint32 **ck) {
+ guint32 *keys = (*ck)++;
+ *keys = GPOINTER_TO_UINT(key);
+}
+
+
+guint32 *mwAwareList_getWatchedAttributes(struct mwAwareList *list) {
+ guint32 *keys, **ck;
+ guint count;
+
+ g_return_val_if_fail(list != NULL, NULL);
+ g_return_val_if_fail(list->attribs != NULL, NULL);
+
+ count = g_hash_table_size(list->attribs);
+ keys = g_new0(guint32, count + 1);
+
+ ck = &keys;
+ g_hash_table_foreach(list->attribs, (GHFunc) collect_attrib_keys, ck);
+
+ return keys;
+}
+
+
+int mwAwareList_addAware(struct mwAwareList *list, GList *id_list) {
+
+ /* for each awareness id:
+ - if it's already in the list, continue
+ - if it's not in the service list:
+ - create an awareness
+ - add it to the service list
+ - add this list to the membership
+ - add to the list
+ */
+
+ struct mwServiceAware *srvc;
+ GList *additions = NULL;
+ int ret = 0;
+
+ g_return_val_if_fail(list != NULL, -1);
+
+ srvc = list->service;
+ g_return_val_if_fail(srvc != NULL, -1);
+
+ for(; id_list; id_list = id_list->next) {
+ if(list_add(list, id_list->data))
+ additions = g_list_prepend(additions, id_list->data);
+ }
+
+ /* if the service is alive-- or getting there-- we'll need to send
+ these additions upstream */
+ if(MW_SERVICE_IS_LIVE(srvc) && additions)
+ ret = send_add(srvc->channel, additions);
+
+ g_list_free(additions);
+ return ret;
+}
+
+
+int mwAwareList_removeAware(struct mwAwareList *list, GList *id_list) {
+
+ /* for each awareness id:
+ - if it's not in the list, forget it
+ - remove from the list
+ - remove list from the membership
+
+ - call remove round
+ */
+
+ struct mwServiceAware *srvc;
+ struct mwAwareIdBlock *id;
+ struct aware_entry *aware;
+
+ g_return_val_if_fail(list != NULL, -1);
+
+ srvc = list->service;
+ g_return_val_if_fail(srvc != NULL, -1);
+
+ for(; id_list; id_list = id_list->next) {
+ id = id_list->data;
+ aware = list_aware_find(list, id);
+
+ if(! aware) {
+ g_warning("buddy %s, %s not in list",
+ NSTR(id->user),
+ NSTR(id->community));
+ continue;
+ }
+
+ aware->membership = g_list_remove(aware->membership, list);
+ g_hash_table_remove(list->entries, id);
+ }
+
+ return remove_unused(srvc);
+}
+
+
+static void dismember_aware(gpointer k, struct aware_entry *aware,
+ struct mwAwareList *list) {
+
+ aware->membership = g_list_remove(aware->membership, list);
+}
+
+
+int mwAwareList_removeAllAware(struct mwAwareList *list) {
+ struct mwServiceAware *srvc;
+
+ g_return_val_if_fail(list != NULL, -1);
+ srvc = list->service;
+
+ g_return_val_if_fail(srvc != NULL, -1);
+
+ /* for each entry, remove the aware list from the service entry's
+ membership collection */
+ if(list->entries) {
+ g_hash_table_foreach(list->entries, (GHFunc) dismember_aware, list);
+ g_hash_table_destroy(list->entries);
+ }
+
+ return remove_unused(srvc);
+}
+
+
+void mwAwareList_setClientData(struct mwAwareList *list,
+ gpointer data, GDestroyNotify clear) {
+
+ g_return_if_fail(list != NULL);
+ mw_datum_set(&list->client_data, data, clear);
+}
+
+
+gpointer mwAwareList_getClientData(struct mwAwareList *list) {
+ g_return_val_if_fail(list != NULL, NULL);
+ return mw_datum_get(&list->client_data);
+}
+
+
+void mwAwareList_removeClientData(struct mwAwareList *list) {
+ g_return_if_fail(list != NULL);
+ mw_datum_clear(&list->client_data);
+}
+
+
+void mwServiceAware_setStatus(struct mwServiceAware *srvc,
+ struct mwAwareIdBlock *user,
+ struct mwUserStatus *stat) {
+
+ struct mwAwareSnapshot idb;
+
+ g_return_if_fail(srvc != NULL);
+ g_return_if_fail(user != NULL);
+ g_return_if_fail(stat != NULL);
+
+ /* just reference the strings. then we don't need to free them */
+ idb.id.type = user->type;
+ idb.id.user = user->user;
+ idb.id.community = user->community;
+
+ idb.group = NULL;
+ idb.online = TRUE;
+ idb.alt_id = NULL;
+
+ idb.status.status = stat->status;
+ idb.status.time = stat->time;
+ idb.status.desc = stat->desc;
+
+ idb.name = NULL;
+
+ status_recv(srvc, &idb);
+}
+
+
+const struct mwAwareAttribute *
+mwServiceAware_getAttribute(struct mwServiceAware *srvc,
+ struct mwAwareIdBlock *user,
+ guint32 key) {
+
+ struct aware_entry *aware;
+
+ g_return_val_if_fail(srvc != NULL, NULL);
+ g_return_val_if_fail(user != NULL, NULL);
+ g_return_val_if_fail(key != 0x00, NULL);
+
+ aware = aware_find(srvc, user);
+ g_return_val_if_fail(aware != NULL, NULL);
+
+ return g_hash_table_lookup(aware->attribs, GUINT_TO_POINTER(key));
+}
+
+
+const char *mwServiceAware_getText(struct mwServiceAware *srvc,
+ struct mwAwareIdBlock *user) {
+
+ struct aware_entry *aware;
+
+ g_return_val_if_fail(srvc != NULL, NULL);
+ g_return_val_if_fail(user != NULL, NULL);
+
+ aware = aware_find(srvc, user);
+ if(! aware) return NULL;
+
+ return aware->aware.status.desc;
+}
+
+
+/// Miranda NG adaptation start - new method
+struct mwService *mwServiceAware_getService(struct mwServiceAware *srvc) {
+ g_return_val_if_fail(srvc != NULL, NULL);
+ return &(srvc->service);
+}
+/// Miranda NG adaptation end
diff --git a/protocols/Sametime/src/meanwhile/src/srvc_conf.c b/protocols/Sametime/src/meanwhile/src/srvc_conf.c
new file mode 100644
index 0000000000..f302a706f8
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/srvc_conf.c
@@ -0,0 +1,884 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <glib.h>
+#include <glib/ghash.h>
+#include <glib/glist.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "mw_channel.h"
+#include "mw_debug.h"
+#include "mw_error.h"
+#include "mw_message.h"
+#include "mw_service.h"
+#include "mw_session.h"
+#include "mw_srvc_conf.h"
+#include "mw_util.h"
+
+
+/* This thing needs a re-write. More than anything else, I need to
+ re-examine the conferencing service protocol from more modern
+ clients */
+
+
+#define PROTOCOL_TYPE 0x00000010
+#define PROTOCOL_VER 0x00000002
+
+
+/** @see mwMsgChannelSend::type
+ @see recv */
+enum msg_type {
+ msg_WELCOME = 0x0000, /**< welcome message */
+ msg_INVITE = 0x0001, /**< outgoing invitation */
+ msg_JOIN = 0x0002, /**< someone joined */
+ msg_PART = 0x0003, /**< someone left */
+ msg_MESSAGE = 0x0004, /**< conference message */
+};
+
+
+/** the conferencing service */
+struct mwServiceConference {
+ struct mwService service;
+
+ /** call-back handler for this service */
+ struct mwConferenceHandler *handler;
+
+ /** collection of conferences in this service */
+ GList *confs;
+};
+
+
+/** a conference and its members */
+struct mwConference {
+ enum mwConferenceState state; /**< state of the conference */
+ struct mwServiceConference *service; /**< owning service */
+ struct mwChannel *channel; /**< conference's channel */
+
+ char *name; /**< server identifier for the conference */
+ char *title; /**< topic for the conference */
+
+ struct mwLoginInfo owner; /**< person who created this conference */
+ GHashTable *members; /**< mapping guint16:mwLoginInfo */
+ struct mw_datum client_data;
+};
+
+
+#define MEMBER_FIND(conf, id) \
+ g_hash_table_lookup(conf->members, GUINT_TO_POINTER((guint) id))
+
+
+#define MEMBER_ADD(conf, id, member) \
+ g_hash_table_insert(conf->members, GUINT_TO_POINTER((guint) id), member)
+
+
+#define MEMBER_REM(conf, id) \
+ g_hash_table_remove(conf->members, GUINT_TO_POINTER((guint) id));
+
+
+/** clear and free a login info block */
+static void login_free(struct mwLoginInfo *li) {
+ mwLoginInfo_clear(li);
+ g_free(li);
+}
+
+
+/** generates a random conference name built around a user name */
+static char *conf_generate_name(const char *user) {
+ /// Miranda NG adaptation start - MSVC
+ ///guint a, b;
+ guint a;
+ guint64 b;
+ /// Miranda NG adaptation end
+ char *ret;
+
+ user = user? user: "";
+
+ srand(clock() + rand());
+ a = ((rand() & 0xff) << 8) | (rand() & 0xff);
+ b = time(NULL);
+
+ /// Miranda NG adaptation start - MSVC
+ ///ret = g_strdup_printf("%s(%08x,%04x)", user, b, a);
+ ret = g_strdup_printf("%s(%I64u,%04x)", user, b, a);
+ /// Miranda NG adaptation end
+ g_debug("generated random conference name: '%s'", ret);
+ return ret;
+}
+
+
+
+
+
+static struct mwConference *conf_new(struct mwServiceConference *srvc) {
+
+ struct mwConference *conf;
+ struct mwSession *session;
+ const char *user;
+
+ conf = g_new0(struct mwConference, 1);
+ conf->state = mwConference_NEW;
+ conf->service = srvc;
+ conf->members = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
+ (GDestroyNotify) login_free);
+
+ session = mwService_getSession(MW_SERVICE(srvc));
+ user = mwSession_getProperty(session, mwSession_AUTH_USER_ID);
+
+ srvc->confs = g_list_prepend(srvc->confs, conf);
+
+ return conf;
+}
+
+
+/** clean and free a conference structure */
+static void conf_free(struct mwConference *conf) {
+ struct mwServiceConference *srvc;
+
+ /* this shouldn't ever happen, but just to be sure */
+ g_return_if_fail(conf != NULL);
+
+ srvc = conf->service;
+
+ if(conf->members)
+ g_hash_table_destroy(conf->members);
+
+ g_list_remove_all(srvc->confs, conf);
+
+ mw_datum_clear(&conf->client_data);
+
+ g_free(conf->name);
+ g_free(conf->title);
+ g_free(conf);
+}
+
+
+static struct mwConference *conf_find(struct mwServiceConference *srvc,
+ struct mwChannel *chan) {
+ GList *l;
+
+ g_return_val_if_fail(srvc != NULL, NULL);
+ g_return_val_if_fail(chan != NULL, NULL);
+
+ for(l = srvc->confs; l; l = l->next) {
+ struct mwConference *conf = l->data;
+ if(conf->channel == chan) return conf;
+ }
+
+ return NULL;
+}
+
+
+static const char *conf_state_str(enum mwConferenceState state) {
+ switch(state) {
+ case mwConference_NEW: return "new";
+ case mwConference_PENDING: return "pending";
+ case mwConference_INVITED: return "invited";
+ case mwConference_OPEN: return "open";
+ case mwConference_CLOSING: return "closing";
+ case mwConference_ERROR: return "error";
+
+ case mwConference_UNKNOWN: /* fall through */
+ default: return "UNKNOWN";
+ }
+}
+
+
+static void conf_state(struct mwConference *conf,
+ enum mwConferenceState state) {
+ g_return_if_fail(conf != NULL);
+
+ if(conf->state == state) return;
+
+ conf->state = state;
+ g_message("conference %s state: %s",
+ NSTR(conf->name), conf_state_str(state));
+}
+
+
+static void recv_channelCreate(struct mwService *srvc,
+ struct mwChannel *chan,
+ struct mwMsgChannelCreate *msg) {
+
+ /* - this is how we really receive invitations
+ - create a conference and associate it with the channel
+ - obtain the invite data from the msg addtl info
+ - mark the conference as INVITED
+ - trigger the got_invite event
+ */
+
+ struct mwServiceConference *srvc_conf = (struct mwServiceConference *) srvc;
+ struct mwConference *conf;
+
+ struct mwGetBuffer *b;
+
+ char *invite = NULL;
+ guint tmp;
+
+ conf = conf_new(srvc_conf);
+ conf->channel = chan;
+
+ b = mwGetBuffer_wrap(&msg->addtl);
+
+ guint32_get(b, &tmp);
+ mwString_get(b, &conf->name);
+ mwString_get(b, &conf->title);
+ guint32_get(b, &tmp);
+ mwLoginInfo_get(b, &conf->owner);
+ guint32_get(b, &tmp);
+ mwString_get(b, &invite);
+
+ if(mwGetBuffer_error(b)) {
+ g_warning("failure parsing addtl for conference invite");
+ mwConference_destroy(conf, ERR_FAILURE, NULL);
+
+ } else {
+ struct mwConferenceHandler *h = srvc_conf->handler;
+ conf_state(conf, mwConference_INVITED);
+ if(h->on_invited)
+ h->on_invited(conf, &conf->owner, invite);
+ }
+
+ mwGetBuffer_free(b);
+ g_free(invite);
+}
+
+
+static void recv_channelAccept(struct mwService *srvc,
+ struct mwChannel *chan,
+ struct mwMsgChannelAccept *msg) {
+
+ ;
+}
+
+
+static void recv_channelDestroy(struct mwService *srvc,
+ struct mwChannel *chan,
+ struct mwMsgChannelDestroy *msg) {
+
+ /* - find conference from channel
+ - trigger got_closed
+ - remove conference, dealloc
+ */
+
+ struct mwServiceConference *srvc_conf = (struct mwServiceConference *) srvc;
+ struct mwConference *conf = conf_find(srvc_conf, chan);
+ struct mwConferenceHandler *h = srvc_conf->handler;
+
+ /* if there's no such conference, then I guess there's nothing to worry
+ about. Except of course for the fact that we should never receive a
+ channel destroy for a conference that doesn't exist. */
+ if(! conf) return;
+
+ conf->channel = NULL;
+
+ conf_state(conf, msg->reason? mwConference_ERROR: mwConference_CLOSING);
+
+ if(h->conf_closed)
+ h->conf_closed(conf, msg->reason);
+
+ mwConference_destroy(conf, ERR_SUCCESS, NULL);
+}
+
+
+static void WELCOME_recv(struct mwServiceConference *srvc,
+ struct mwConference *conf,
+ struct mwGetBuffer *b) {
+
+ struct mwConferenceHandler *h;
+ guint16 tmp16;
+ guint32 tmp32;
+ guint32 count;
+ GList *l = NULL;
+
+ /* re-read name and title */
+ g_free(conf->name);
+ g_free(conf->title);
+ conf->name = NULL;
+ conf->title = NULL;
+ mwString_get(b, &conf->name);
+ mwString_get(b, &conf->title);
+
+ /* some numbers we don't care about, then a count of members */
+ guint16_get(b, &tmp16);
+ guint32_get(b, &tmp32);
+ guint32_get(b, &count);
+
+ if(mwGetBuffer_error(b)) {
+ g_warning("error parsing welcome message for conference");
+ mwConference_destroy(conf, ERR_FAILURE, NULL);
+ return;
+ }
+
+ while(count--) {
+ guint16 member_id;
+ struct mwLoginInfo *member = g_new0(struct mwLoginInfo, 1);
+
+ guint16_get(b, &member_id);
+ mwLoginInfo_get(b, member);
+
+ if(mwGetBuffer_error(b)) {
+ login_free(member);
+ break;
+ }
+
+ MEMBER_ADD(conf, member_id, member);
+ l = g_list_append(l, member);
+ }
+
+ conf_state(conf, mwConference_OPEN);
+
+ h = srvc->handler;
+ if(h->conf_opened)
+ h->conf_opened(conf, l);
+
+ /* get rid of the GList, but not its contents */
+ g_list_free(l);
+}
+
+
+static void JOIN_recv(struct mwServiceConference *srvc,
+ struct mwConference *conf,
+ struct mwGetBuffer *b) {
+
+ struct mwConferenceHandler *h;
+ guint16 m_id;
+ struct mwLoginInfo *m;
+
+ /* for some inane reason, conferences we create will send a join
+ message for ourselves before the welcome message. Since the
+ welcome message will list our ID among those in the channel,
+ we're going to just pretend that these join messages don't
+ exist */
+ if(conf->state == mwConference_PENDING)
+ return;
+
+ m = g_new0(struct mwLoginInfo, 1);
+
+ guint16_get(b, &m_id);
+ mwLoginInfo_get(b, m);
+
+ if(mwGetBuffer_error(b)) {
+ g_warning("failed parsing JOIN message in conference");
+ login_free(m);
+ return;
+ }
+
+ MEMBER_ADD(conf, m_id, m);
+
+ h = srvc->handler;
+ if(h->on_peer_joined)
+ h->on_peer_joined(conf, m);
+}
+
+
+static void PART_recv(struct mwServiceConference *srvc,
+ struct mwConference *conf,
+ struct mwGetBuffer *b) {
+
+ /* - parse who left
+ - look up their membership
+ - remove them from the members list
+ - trigger the event
+ */
+
+ struct mwConferenceHandler *h;
+ guint16 id = 0;
+ struct mwLoginInfo *m;
+
+ guint16_get(b, &id);
+
+ if(mwGetBuffer_error(b)) return;
+
+ m = MEMBER_FIND(conf, id);
+ if(! m) return;
+
+ h = srvc->handler;
+ if(h->on_peer_parted)
+ h->on_peer_parted(conf, m);
+
+ MEMBER_REM(conf, id);
+}
+
+
+static void text_recv(struct mwServiceConference *srvc,
+ struct mwConference *conf,
+ struct mwLoginInfo *m,
+ struct mwGetBuffer *b) {
+
+ /* this function acts a lot like receiving an IM Text message. The text
+ message contains only a string */
+
+ char *text = NULL;
+ struct mwConferenceHandler *h;
+
+ mwString_get(b, &text);
+
+ if(mwGetBuffer_error(b)) {
+ g_warning("failed to parse text message in conference");
+ g_free(text);
+ return;
+ }
+
+ h = srvc->handler;
+ if(text && h->on_text) {
+ h->on_text(conf, m, text);
+ }
+
+ g_free(text);
+}
+
+
+static void data_recv(struct mwServiceConference *srvc,
+ struct mwConference *conf,
+ struct mwLoginInfo *m,
+ struct mwGetBuffer *b) {
+
+ /* this function acts a lot like receiving an IM Data message. The
+ data message has a type, a subtype, and an opaque. We only
+ support typing notification though. */
+
+ /** @todo it's possible that some clients send text in a data
+ message, as we've seen rarely in the IM service. Have to add
+ support for that here */
+
+ guint32 type, subtype;
+ struct mwConferenceHandler *h;
+
+ guint32_get(b, &type);
+ guint32_get(b, &subtype);
+
+ if(mwGetBuffer_error(b)) return;
+
+ /* don't know how to deal with any others yet */
+ if(type != 0x01) {
+ g_message("unknown data message type (0x%08x, 0x%08x)", type, subtype);
+ return;
+ }
+
+ h = srvc->handler;
+ if(h->on_typing) {
+ h->on_typing(conf, m, !subtype);
+ }
+}
+
+
+static void MESSAGE_recv(struct mwServiceConference *srvc,
+ struct mwConference *conf,
+ struct mwGetBuffer *b) {
+
+ /* - look up who send the message by their id
+ - trigger the event
+ */
+
+ guint16 id;
+ guint32 type;
+ struct mwLoginInfo *m;
+
+ /* an empty buffer isn't an error, just ignored */
+ if(! mwGetBuffer_remaining(b)) return;
+
+ guint16_get(b, &id);
+ guint32_get(b, &type); /* reuse type variable */
+ guint32_get(b, &type);
+
+ if(mwGetBuffer_error(b)) return;
+
+ m = MEMBER_FIND(conf, id);
+ if(! m) {
+ g_warning("received message type 0x%04x from"
+ " unknown conference member %u", type, id);
+ return;
+ }
+
+ switch(type) {
+ case 0x01: /* type is text */
+ text_recv(srvc, conf, m, b);
+ break;
+
+ case 0x02: /* type is data */
+ data_recv(srvc, conf, m, b);
+ break;
+
+ default:
+ g_warning("unknown message type 0x%4x received in conference", type);
+ }
+}
+
+
+static void recv(struct mwService *srvc, struct mwChannel *chan,
+ guint16 type, struct mwOpaque *data) {
+
+ struct mwServiceConference *srvc_conf = (struct mwServiceConference *) srvc;
+ struct mwConference *conf = conf_find(srvc_conf, chan);
+ struct mwGetBuffer *b;
+
+ g_return_if_fail(conf != NULL);
+
+ b = mwGetBuffer_wrap(data);
+
+ switch(type) {
+ case msg_WELCOME:
+ WELCOME_recv(srvc_conf, conf, b);
+ break;
+
+ case msg_JOIN:
+ JOIN_recv(srvc_conf, conf, b);
+ break;
+
+ case msg_PART:
+ PART_recv(srvc_conf, conf, b);
+ break;
+
+ case msg_MESSAGE:
+ MESSAGE_recv(srvc_conf, conf, b);
+ break;
+
+ default:
+ ; /* hrm. should log this. TODO */
+ }
+}
+
+
+static void clear(struct mwServiceConference *srvc) {
+ struct mwConferenceHandler *h;
+
+ while(srvc->confs)
+ conf_free(srvc->confs->data);
+
+ h = srvc->handler;
+ if(h && h->clear)
+ h->clear(srvc);
+ srvc->handler = NULL;
+}
+
+
+static const char *name(struct mwService *srvc) {
+ return "Basic Conferencing";
+}
+
+
+static const char *desc(struct mwService *srvc) {
+ return "Multi-user plain-text conferencing";
+}
+
+
+static void start(struct mwService *srvc) {
+ mwService_started(srvc);
+}
+
+
+static void stop(struct mwServiceConference *srvc) {
+ while(srvc->confs)
+ mwConference_destroy(srvc->confs->data, ERR_SUCCESS, NULL);
+
+ mwService_stopped(MW_SERVICE(srvc));
+}
+
+
+struct mwServiceConference *
+mwServiceConference_new(struct mwSession *session,
+ struct mwConferenceHandler *handler) {
+
+ struct mwServiceConference *srvc_conf;
+ struct mwService *srvc;
+
+ g_return_val_if_fail(session != NULL, NULL);
+ g_return_val_if_fail(handler != NULL, NULL);
+
+ srvc_conf = g_new0(struct mwServiceConference, 1);
+ srvc = &srvc_conf->service;
+
+ mwService_init(srvc, session, mwService_CONFERENCE);
+ srvc->start = start;
+ srvc->stop = (mwService_funcStop) stop;
+ srvc->recv_create = recv_channelCreate;
+ srvc->recv_accept = recv_channelAccept;
+ srvc->recv_destroy = recv_channelDestroy;
+ srvc->recv = recv;
+ srvc->clear = (mwService_funcClear) clear;
+ srvc->get_name = name;
+ srvc->get_desc = desc;
+
+ srvc_conf->handler = handler;
+
+ return srvc_conf;
+}
+
+
+struct mwConference *mwConference_new(struct mwServiceConference *srvc,
+ const char *title) {
+ struct mwConference *conf;
+
+ g_return_val_if_fail(srvc != NULL, NULL);
+
+ conf = conf_new(srvc);
+ conf->title = g_strdup(title);
+
+ return conf;
+}
+
+
+/// Miranda NG adaptation start - renamed method
+struct mwServiceConference *
+mwConference_getServiceConference(struct mwConference *conf) {
+ g_return_val_if_fail(conf != NULL, NULL);
+ return conf->service;
+}
+/// Miranda NG adaptation end
+
+
+/// Miranda NG adaptation start - new method
+struct mwService *mwServiceConference_getService(struct mwServiceConference *srvc) {
+ g_return_val_if_fail(srvc != NULL, NULL);
+ return &(srvc->service);
+}
+/// Miranda NG adaptation end
+
+
+const char *mwConference_getName(struct mwConference *conf) {
+ g_return_val_if_fail(conf != NULL, NULL);
+ return conf->name;
+}
+
+
+const char *mwConference_getTitle(struct mwConference *conf) {
+ g_return_val_if_fail(conf != NULL, NULL);
+ return conf->title;
+}
+
+
+GList *mwConference_getMembers(struct mwConference *conf) {
+ g_return_val_if_fail(conf != NULL, NULL);
+ g_return_val_if_fail(conf->members != NULL, NULL);
+
+ return map_collect_values(conf->members);
+}
+
+
+int mwConference_open(struct mwConference *conf) {
+ struct mwSession *session;
+ struct mwChannel *chan;
+ struct mwPutBuffer *b;
+ int ret;
+
+ g_return_val_if_fail(conf != NULL, -1);
+ g_return_val_if_fail(conf->service != NULL, -1);
+ g_return_val_if_fail(conf->state == mwConference_NEW, -1);
+ g_return_val_if_fail(conf->channel == NULL, -1);
+
+ session = mwService_getSession(MW_SERVICE(conf->service));
+ g_return_val_if_fail(session != NULL, -1);
+
+ if(! conf->name) {
+ char *user = mwSession_getProperty(session, mwSession_AUTH_USER_ID);
+ conf->name = conf_generate_name(user? user: "meanwhile");
+ }
+
+ chan = mwChannel_newOutgoing(mwSession_getChannels(session));
+ mwChannel_setService(chan, MW_SERVICE(conf->service));
+ mwChannel_setProtoType(chan, PROTOCOL_TYPE);
+ mwChannel_setProtoVer(chan, PROTOCOL_VER);
+
+#if 0
+ /* offer all known ciphers */
+ mwChannel_populateSupportedCipherInstances(chan);
+#endif
+
+ b = mwPutBuffer_new();
+ mwString_put(b, conf->name);
+ mwString_put(b, conf->title);
+ guint32_put(b, 0x00);
+ mwPutBuffer_finalize(mwChannel_getAddtlCreate(chan), b);
+
+ ret = mwChannel_create(chan);
+ if(ret) {
+ conf_state(conf, mwConference_ERROR);
+ } else {
+ conf_state(conf, mwConference_PENDING);
+ conf->channel = chan;
+ }
+
+ return ret;
+}
+
+
+int mwConference_destroy(struct mwConference *conf,
+ guint32 reason, const char *text) {
+
+ struct mwServiceConference *srvc;
+ struct mwOpaque info = { 0, 0 };
+ int ret = 0;
+
+ g_return_val_if_fail(conf != NULL, -1);
+
+ srvc = conf->service;
+ g_return_val_if_fail(srvc != NULL, -1);
+
+ /* remove conference from the service */
+ srvc->confs = g_list_remove_all(srvc->confs, conf);
+
+ /* close the channel if applicable */
+ if(conf->channel) {
+ if(text && *text) {
+ info.len = strlen(text);
+ info.data = (guchar *) text;
+ }
+
+ ret = mwChannel_destroy(conf->channel, reason, &info);
+ }
+
+ /* free the conference */
+ conf_free(conf);
+
+ return ret;
+}
+
+
+int mwConference_accept(struct mwConference *conf) {
+ /* - if conference is not INVITED, return -1
+ - accept the conference channel
+ - send an empty JOIN message
+ */
+
+ struct mwChannel *chan;
+ int ret;
+
+ g_return_val_if_fail(conf != NULL, -1);
+ g_return_val_if_fail(conf->state == mwConference_INVITED, -1);
+
+ chan = conf->channel;
+ ret = mwChannel_accept(chan);
+
+ if(! ret)
+ ret = mwChannel_sendEncrypted(chan, msg_JOIN, NULL, FALSE);
+
+ return ret;
+}
+
+
+int mwConference_invite(struct mwConference *conf,
+ struct mwIdBlock *who,
+ const char *text) {
+
+ struct mwPutBuffer *b;
+ struct mwOpaque o;
+ int ret;
+
+ g_return_val_if_fail(conf != NULL, -1);
+ g_return_val_if_fail(conf->channel != NULL, -1);
+ g_return_val_if_fail(who != NULL, -1);
+
+ b = mwPutBuffer_new();
+
+ mwIdBlock_put(b, who);
+ guint16_put(b, 0x00);
+ guint32_put(b, 0x00);
+ mwString_put(b, text);
+ mwString_put(b, who->user);
+
+ mwPutBuffer_finalize(&o, b);
+ ret = mwChannel_sendEncrypted(conf->channel, msg_INVITE, &o, FALSE);
+ mwOpaque_clear(&o);
+
+ return ret;
+}
+
+
+int mwConference_sendText(struct mwConference *conf, const char *text) {
+ struct mwPutBuffer *b;
+ struct mwOpaque o;
+ int ret;
+
+ g_return_val_if_fail(conf != NULL, -1);
+ g_return_val_if_fail(conf->channel != NULL, -1);
+
+ b = mwPutBuffer_new();
+
+ guint32_put(b, 0x01);
+ mwString_put(b, text);
+
+ mwPutBuffer_finalize(&o, b);
+ ret = mwChannel_sendEncrypted(conf->channel, msg_MESSAGE, &o, FALSE);
+ mwOpaque_clear(&o);
+
+ return ret;
+}
+
+
+int mwConference_sendTyping(struct mwConference *conf, gboolean typing) {
+ struct mwPutBuffer *b;
+ struct mwOpaque o;
+ int ret;
+
+ g_return_val_if_fail(conf != NULL, -1);
+ g_return_val_if_fail(conf->channel != NULL, -1);
+ g_return_val_if_fail(conf->state == mwConference_OPEN, -1);
+
+ b = mwPutBuffer_new();
+
+ guint32_put(b, 0x02);
+ guint32_put(b, 0x01);
+ guint32_put(b, !typing);
+ mwOpaque_put(b, NULL);
+
+ mwPutBuffer_finalize(&o, b);
+ ret = mwChannel_sendEncrypted(conf->channel, msg_MESSAGE, &o, FALSE);
+ mwOpaque_clear(&o);
+
+ return ret;
+}
+
+
+void mwConference_setClientData(struct mwConference *conference,
+ gpointer data, GDestroyNotify clear) {
+
+ g_return_if_fail(conference != NULL);
+ mw_datum_set(&conference->client_data, data, clear);
+}
+
+
+gpointer mwConference_getClientData(struct mwConference *conference) {
+ g_return_val_if_fail(conference != NULL, NULL);
+ return mw_datum_get(&conference->client_data);
+}
+
+
+void mwConference_removeClientData(struct mwConference *conference) {
+ g_return_if_fail(conference != NULL);
+ mw_datum_clear(&conference->client_data);
+}
+
+
+struct mwConferenceHandler *
+mwServiceConference_getHandler(struct mwServiceConference *srvc) {
+ g_return_val_if_fail(srvc != NULL, NULL);
+ return srvc->handler;
+}
+
+
+GList *mwServiceConference_getConferences(struct mwServiceConference *srvc) {
+ g_return_val_if_fail(srvc != NULL, NULL);
+ return g_list_copy(srvc->confs);
+}
+
diff --git a/protocols/Sametime/src/meanwhile/src/srvc_dir.c b/protocols/Sametime/src/meanwhile/src/srvc_dir.c
new file mode 100644
index 0000000000..1505f69c53
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/srvc_dir.c
@@ -0,0 +1,664 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <glib/ghash.h>
+
+#include "mw_channel.h"
+#include "mw_common.h"
+#include "mw_debug.h"
+#include "mw_error.h"
+#include "mw_message.h"
+#include "mw_service.h"
+#include "mw_session.h"
+#include "mw_srvc_dir.h"
+#include "mw_util.h"
+
+
+#define PROTOCOL_TYPE 0x0000001c
+#define PROTOCOL_VER 0x00000005
+
+
+enum dir_action {
+ action_list = 0x0000, /**< list address books */
+ action_open = 0x0001, /**< open an addressbook as a directory */
+ action_close = 0x0002, /**< close a directory */
+ action_search = 0x0003, /**< search an open directory */
+};
+
+
+struct mwServiceDirectory {
+ struct mwService service;
+
+ struct mwDirectoryHandler *handler;
+
+ struct mwChannel *channel;
+
+ guint32 counter; /**< counter of request IDs */
+ GHashTable *requests; /**< map of request ID:directory */
+ GHashTable *books; /**< book->name:mwAddressBook */
+};
+
+
+struct mwAddressBook {
+ struct mwServiceDirectory *service;
+
+ guint32 id; /**< id or type or something */
+ char *name; /**< name of address book */
+ GHashTable *dirs; /**< dir->id:mwDirectory */
+};
+
+
+struct mwDirectory {
+ struct mwServiceDirectory *service;
+ struct mwAddressBook *book;
+
+ enum mwDirectoryState state;
+
+ guint32 id; /**< id of directory, assigned by server */
+ guint32 search_id; /**< id of current search, from srvc->counter++ */
+
+ mwSearchHandler handler;
+ struct mw_datum client_data;
+};
+
+
+#define next_request_id(srvc) ( ++((srvc)->counter) )
+
+
+static guint32 map_request(struct mwDirectory *dir) {
+ struct mwServiceDirectory *srvc = dir->service;
+ guint32 id = next_request_id(srvc);
+
+ dir->search_id = id;
+ map_guint_insert(srvc->requests, id, dir);
+
+ return id;
+}
+
+
+/** called when directory is removed from the service directory map */
+static void dir_free(struct mwDirectory *dir) {
+ map_guint_remove(dir->service->requests, dir->search_id);
+ g_free(dir);
+}
+
+
+/** remove the directory from the service list and its owning address
+ book, then frees the directory */
+static void dir_remove(struct mwDirectory *dir) {
+ struct mwAddressBook *book = dir->book;
+ map_guint_remove(book->dirs, dir->id);
+}
+
+
+/// __attribute__((used)) ///Miranda NG adaptation, MSVC
+static struct mwDirectory *dir_new(struct mwAddressBook *book, guint32 id) {
+ struct mwDirectory *dir = g_new0(struct mwDirectory, 1);
+ dir->service = book->service;
+ dir->book = book;
+ dir->id = id;
+ map_guint_insert(book->dirs, id, dir);
+ return dir;
+}
+
+
+/** called when book is removed from the service book map. Removed all
+ directories as well */
+static void book_free(struct mwAddressBook *book) {
+ g_hash_table_destroy(book->dirs);
+ g_free(book->name);
+}
+
+
+/// __attribute__((used)) ///Miranda NG adaptation, MSVC
+static void book_remove(struct mwAddressBook *book) {
+ struct mwServiceDirectory *srvc = book->service;
+ g_hash_table_remove(srvc->books, book->name);
+}
+
+
+static struct mwAddressBook *book_new(struct mwServiceDirectory *srvc,
+ const char *name, guint32 id) {
+ struct mwAddressBook *book = g_new0(struct mwAddressBook, 1);
+ book->service = srvc;
+ book->id = id;
+ book->name = g_strdup(name);
+ book->dirs = map_guint_new_full((GDestroyNotify) dir_free);
+ g_hash_table_insert(srvc->books, book->name, book);
+ return book;
+}
+
+
+static const char *getName(struct mwService *srvc) {
+ return "Address Book and Directory";
+}
+
+
+static const char *getDesc(struct mwService *srvc) {
+ return "Address book directory service for user and group lookups";
+}
+
+
+static struct mwChannel *make_channel(struct mwServiceDirectory *srvc) {
+ struct mwSession *session;
+ struct mwChannelSet *cs;
+ struct mwChannel *chan;
+
+ session = mwService_getSession(MW_SERVICE(srvc));
+ cs = mwSession_getChannels(session);
+ chan = mwChannel_newOutgoing(cs);
+
+ mwChannel_setService(chan, MW_SERVICE(srvc));
+ mwChannel_setProtoType(chan, PROTOCOL_TYPE);
+ mwChannel_setProtoVer(chan, PROTOCOL_VER);
+
+ return mwChannel_create(chan)? NULL: chan;
+}
+
+
+static void start(struct mwServiceDirectory *srvc) {
+ struct mwChannel *chan;
+
+ chan = make_channel(srvc);
+ if(chan) {
+ srvc->channel = chan;
+ } else {
+ mwService_stopped(MW_SERVICE(srvc));
+ return;
+ }
+}
+
+
+static void stop(struct mwServiceDirectory *srvc) {
+ /* XXX */
+
+ if(srvc->channel) {
+ mwChannel_destroy(srvc->channel, ERR_SUCCESS, NULL);
+ srvc->channel = NULL;
+ }
+}
+
+
+static void clear(struct mwServiceDirectory *srvc) {
+ struct mwDirectoryHandler *handler;
+
+ if(srvc->books) {
+ g_hash_table_destroy(srvc->books);
+ srvc->books = NULL;
+ }
+
+ /* clear the handler */
+ handler = srvc->handler;
+ if(handler && handler->clear)
+ handler->clear(srvc);
+ srvc->handler = NULL;
+}
+
+
+static void recv_create(struct mwServiceDirectory *srvc,
+ struct mwChannel *chan,
+ struct mwMsgChannelCreate *msg) {
+
+ /* no way man, we call the shots around here */
+ mwChannel_destroy(chan, ERR_FAILURE, NULL);
+}
+
+
+static void recv_accept(struct mwServiceDirectory *srvc,
+ struct mwChannel *chan,
+ struct mwMsgChannelAccept *msg) {
+
+ g_return_if_fail(srvc->channel != NULL);
+ g_return_if_fail(srvc->channel == chan);
+
+ if(MW_SERVICE_IS_STARTING(srvc)) {
+ mwService_started(MW_SERVICE(srvc));
+
+ } else {
+ mwChannel_destroy(chan, ERR_FAILURE, NULL);
+ }
+}
+
+
+static void recv_destroy(struct mwServiceDirectory *srvc,
+ struct mwChannel *chan,
+ struct mwMsgChannelDestroy *msg) {
+
+ srvc->channel = NULL;
+ mwService_stop(MW_SERVICE(srvc));
+ /** @todo session sense service */
+}
+
+
+static void recv_list(struct mwServiceDirectory *srvc,
+ struct mwOpaque *data) {
+
+ struct mwGetBuffer *b;
+ guint32 request, code, count;
+ gboolean foo_1;
+ guint16 foo_2;
+
+ b = mwGetBuffer_wrap(data);
+
+ guint32_get(b, &request);
+ guint32_get(b, &code);
+ guint32_get(b, &count);
+
+ gboolean_get(b, &foo_1);
+ guint16_get(b, &foo_2);
+
+ if(foo_1 || foo_2) {
+ mw_mailme_opaque(data, "received strange address book list");
+ mwGetBuffer_free(b);
+ return;
+ }
+
+ while(!mwGetBuffer_error(b) && count--) {
+ guint32 id;
+ char *name = NULL;
+
+ guint32_get(b, &id);
+ mwString_get(b, &name);
+
+ book_new(srvc, name, id);
+ g_free(name);
+ }
+}
+
+
+static void recv_open(struct mwServiceDirectory *srvc,
+ struct mwOpaque *data) {
+
+ /* look up the directory associated with this request id,
+ mark it as open, and trigger the event */
+}
+
+
+static void recv_search(struct mwServiceDirectory *srvc,
+ struct mwOpaque *data) {
+
+ /* look up the directory associated with this request id,
+ trigger the event */
+}
+
+
+static void recv(struct mwServiceDirectory *srvc,
+ struct mwChannel *chan,
+ guint16 msg_type, struct mwOpaque *data) {
+
+ g_return_if_fail(srvc != NULL);
+ g_return_if_fail(chan != NULL);
+ g_return_if_fail(chan == srvc->channel);
+ g_return_if_fail(data != NULL);
+
+ switch(msg_type) {
+ case action_list:
+ recv_list(srvc, data);
+ break;
+
+ case action_open:
+ recv_open(srvc, data);
+ break;
+
+ case action_close:
+ ; /* I don't think we should receive these */
+ break;
+
+ case action_search:
+ recv_search(srvc, data);
+ break;
+
+ default:
+ mw_mailme_opaque(data, "msg type 0x%04x in directory service", msg_type);
+ }
+}
+
+
+struct mwServiceDirectory *
+mwServiceDirectory_new(struct mwSession *session,
+ struct mwDirectoryHandler *handler) {
+
+ struct mwServiceDirectory *srvc;
+ struct mwService *service;
+
+ g_return_val_if_fail(session != NULL, NULL);
+ g_return_val_if_fail(handler != NULL, NULL);
+
+ srvc = g_new0(struct mwServiceDirectory, 1);
+ service = MW_SERVICE(srvc);
+
+ mwService_init(service, session, SERVICE_DIRECTORY);
+ service->get_name = getName;
+ service->get_desc = getDesc;
+ service->start = (mwService_funcStart) start;
+ service->stop = (mwService_funcStop) stop;
+ service->clear = (mwService_funcClear) clear;
+ service->recv_create = (mwService_funcRecvCreate) recv_create;
+ service->recv_accept = (mwService_funcRecvAccept) recv_accept;
+ service->recv_destroy = (mwService_funcRecvDestroy) recv_destroy;
+ service->recv = (mwService_funcRecv) recv;
+
+ srvc->handler = handler;
+ srvc->requests = map_guint_new();
+ srvc->books = g_hash_table_new_full(g_str_hash, g_str_equal,
+ NULL, (GDestroyNotify) book_free);
+ return srvc;
+}
+
+
+struct mwDirectoryHandler *
+mwServiceDirectory_getHandler(struct mwServiceDirectory *srvc) {
+ g_return_val_if_fail(srvc != NULL, NULL);
+ return srvc->handler;
+}
+
+
+int mwServiceDirectory_refreshAddressBooks(struct mwServiceDirectory *srvc) {
+ struct mwChannel *chan;
+ struct mwPutBuffer *b;
+ struct mwOpaque o;
+ int ret;
+
+ g_return_val_if_fail(srvc != NULL, -1);
+
+ chan = srvc->channel;
+ g_return_val_if_fail(chan != NULL, -1);
+
+ b = mwPutBuffer_new();
+ guint32_put(b, next_request_id(srvc));
+
+ mwPutBuffer_finalize(&o, b);
+ ret = mwChannel_send(chan, action_list, &o);
+ mwOpaque_clear(&o);
+
+ return ret;
+}
+
+
+GList *mwServiceDirectory_getAddressBooks(struct mwServiceDirectory *srvc) {
+ g_return_val_if_fail(srvc != NULL, NULL);
+ g_return_val_if_fail(srvc->books != NULL, NULL);
+
+ return map_collect_values(srvc->books);
+}
+
+
+GList *mwServiceDirectory_getDirectories(struct mwServiceDirectory *srvc) {
+ GList *bl, *ret = NULL;
+
+ g_return_val_if_fail(srvc != NULL, NULL);
+ g_return_val_if_fail(srvc->books != NULL, NULL);
+
+ bl = map_collect_values(srvc->books);
+ for( ; bl; bl = g_list_delete_link(bl, bl)) {
+ struct mwAddressBook *book = bl->data;
+ ret = g_list_concat(ret, map_collect_values(book->dirs));
+ }
+
+ return ret;
+}
+
+
+GList *mwAddressBook_getDirectories(struct mwAddressBook *book) {
+ g_return_val_if_fail(book != NULL, NULL);
+ g_return_val_if_fail(book->dirs != NULL, NULL);
+
+ return map_collect_values(book->dirs);
+}
+
+
+const char *mwAddressBook_getName(struct mwAddressBook *book) {
+ g_return_val_if_fail(book != NULL, NULL);
+ return book->name;
+}
+
+
+struct mwDirectory *mwDirectory_new(struct mwAddressBook *book) {
+ struct mwDirectory *dir;
+
+ g_return_val_if_fail(book != NULL, NULL);
+ g_return_val_if_fail(book->service != NULL, NULL);
+
+ dir = g_new0(struct mwDirectory, 1);
+ dir->service = book->service;
+ dir->book = book;
+ dir->state = mwDirectory_NEW;
+
+ return dir;
+}
+
+
+enum mwDirectoryState mwDirectory_getState(struct mwDirectory *dir) {
+ g_return_val_if_fail(dir != NULL, mwDirectory_UNKNOWN);
+ return dir->state;
+}
+
+
+void mwDirectory_setClientData(struct mwDirectory *dir,
+ gpointer data, GDestroyNotify clear) {
+
+ g_return_if_fail(dir != NULL);
+ mw_datum_set(&dir->client_data, data, clear);
+}
+
+
+gpointer mwDirectory_getClientData(struct mwDirectory *dir) {
+ g_return_val_if_fail(dir != NULL, NULL);
+ return mw_datum_get(&dir->client_data);
+}
+
+
+void mwDirectory_removeClientData(struct mwDirectory *dir) {
+ g_return_if_fail(dir != NULL);
+ mw_datum_clear(&dir->client_data);
+}
+
+
+struct mwServiceDirectory *mwDirectory_getService(struct mwDirectory *dir) {
+ g_return_val_if_fail(dir != NULL, NULL);
+ g_return_val_if_fail(dir->book != NULL, NULL);
+ return dir->book->service;
+}
+
+
+struct mwAddressBook *mwDirectory_getAddressBook(struct mwDirectory *dir) {
+ g_return_val_if_fail(dir != NULL, NULL);
+ return dir->book;
+}
+
+
+static int dir_open(struct mwDirectory *dir) {
+ struct mwServiceDirectory *srvc;
+ struct mwChannel *chan;
+ struct mwPutBuffer *b;
+ struct mwOpaque o;
+ int ret;
+
+ g_return_val_if_fail(dir != NULL, -1);
+
+ srvc = dir->service;
+ g_return_val_if_fail(srvc != NULL, -1);
+
+ chan = srvc->channel;
+ g_return_val_if_fail(chan != NULL, -1);
+
+ b = mwPutBuffer_new();
+ guint32_put(b, map_request(dir));
+
+ /* unsure about these three bytes */
+ gboolean_put(b, FALSE);
+ guint16_put(b, 0x0000);
+
+ guint32_put(b, dir->book->id);
+ mwString_put(b, dir->book->name);
+
+ mwPutBuffer_finalize(&o, b);
+ ret = mwChannel_send(chan, action_open, &o);
+ mwOpaque_clear(&o);
+
+ return ret;
+}
+
+
+int mwDirectory_open(struct mwDirectory *dir, mwSearchHandler cb) {
+ g_return_val_if_fail(dir != NULL, -1);
+ g_return_val_if_fail(cb != NULL, -1);
+ g_return_val_if_fail(MW_DIRECTORY_IS_NEW(dir), -1);
+
+ dir->state = mwDirectory_PENDING;
+ dir->handler = cb;
+
+ return dir_open(dir);
+}
+
+
+int mwDirectory_next(struct mwDirectory *dir) {
+ struct mwServiceDirectory *srvc;
+ struct mwChannel *chan;
+ struct mwPutBuffer *b;
+ struct mwOpaque o;
+ int ret;
+
+ g_return_val_if_fail(dir != NULL, -1);
+ g_return_val_if_fail(MW_DIRECTORY_IS_OPEN(dir), -1);
+
+ srvc = dir->service;
+ g_return_val_if_fail(srvc != NULL, -1);
+
+ chan = srvc->channel;
+ g_return_val_if_fail(chan != NULL, -1);
+
+ b = mwPutBuffer_new();
+ guint32_put(b, map_request(dir));
+ guint32_put(b, dir->id);
+ guint16_put(b, 0xffff); /* some magic? */
+ guint32_put(b, 0x00000000); /* next results */
+
+ mwPutBuffer_finalize(&o, b);
+ ret = mwChannel_send(chan, action_search, &o);
+ mwOpaque_clear(&o);
+
+ return ret;
+}
+
+
+int mwDirectory_previous(struct mwDirectory *dir) {
+ struct mwServiceDirectory *srvc;
+ struct mwChannel *chan;
+ struct mwPutBuffer *b;
+ struct mwOpaque o;
+ int ret;
+
+ g_return_val_if_fail(dir != NULL, -1);
+ g_return_val_if_fail(MW_DIRECTORY_IS_OPEN(dir), -1);
+
+ srvc = dir->service;
+ g_return_val_if_fail(srvc != NULL, -1);
+
+ chan = srvc->channel;
+ g_return_val_if_fail(chan != NULL, -1);
+
+ b = mwPutBuffer_new();
+ guint32_put(b, map_request(dir));
+ guint32_put(b, dir->id);
+ guint16_put(b, 0x0061); /* some magic? */
+ guint32_put(b, 0x00000001); /* prev results */
+
+ mwPutBuffer_finalize(&o, b);
+ ret = mwChannel_send(chan, action_search, &o);
+ mwOpaque_clear(&o);
+
+ return ret;
+}
+
+
+int mwDirectory_search(struct mwDirectory *dir, const char *query) {
+ struct mwServiceDirectory *srvc;
+ struct mwChannel *chan;
+ struct mwPutBuffer *b;
+ struct mwOpaque o;
+ int ret;
+
+ g_return_val_if_fail(dir != NULL, -1);
+ g_return_val_if_fail(MW_DIRECTORY_IS_OPEN(dir), -1);
+ g_return_val_if_fail(query != NULL, -1);
+ g_return_val_if_fail(*query != '\0', -1);
+
+ srvc = dir->service;
+ g_return_val_if_fail(srvc != NULL, -1);
+
+ chan = srvc->channel;
+ g_return_val_if_fail(chan != NULL, -1);
+
+ b = mwPutBuffer_new();
+ guint32_put(b, map_request(dir));
+ guint32_put(b, dir->id);
+ guint16_put(b, 0x0061); /* some magic? */
+ guint32_put(b, 0x00000008); /* seek results */
+ mwString_put(b, query);
+
+ mwPutBuffer_finalize(&o, b);
+ ret = mwChannel_send(chan, action_search, &o);
+ mwOpaque_clear(&o);
+
+ return ret;
+}
+
+
+static int dir_close(struct mwDirectory *dir) {
+ struct mwServiceDirectory *srvc;
+ struct mwChannel *chan;
+ struct mwPutBuffer *b;
+ struct mwOpaque o;
+ int ret;
+
+ g_return_val_if_fail(dir != NULL, -1);
+
+ srvc = dir->service;
+ g_return_val_if_fail(srvc != NULL, -1);
+
+ chan = srvc->channel;
+ g_return_val_if_fail(chan != NULL, -1);
+
+ b = mwPutBuffer_new();
+ guint32_put(b, next_request_id(dir->service));
+ guint32_put(b, dir->id);
+
+ mwPutBuffer_finalize(&o, b);
+ ret = mwChannel_send(chan, action_close, &o);
+ mwOpaque_clear(&o);
+
+ return ret;
+}
+
+
+int mwDirectory_destroy(struct mwDirectory *dir) {
+ int ret = 0;
+
+ g_return_val_if_fail(dir != NULL, -1);
+
+ if(MW_DIRECTORY_IS_OPEN(dir) || MW_DIRECTORY_IS_PENDING(dir)) {
+ ret = dir_close(dir);
+ }
+ dir_remove(dir);
+
+ return ret;
+}
+
diff --git a/protocols/Sametime/src/meanwhile/src/srvc_ft.c b/protocols/Sametime/src/meanwhile/src/srvc_ft.c
new file mode 100644
index 0000000000..38479e3452
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/srvc_ft.c
@@ -0,0 +1,667 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#include <glib/glist.h>
+
+#include "mw_channel.h"
+#include "mw_common.h"
+#include "mw_debug.h"
+#include "mw_error.h"
+#include "mw_message.h"
+#include "mw_service.h"
+#include "mw_session.h"
+#include "mw_srvc_ft.h"
+#include "mw_util.h"
+
+
+#define PROTOCOL_TYPE 0x00000000
+#define PROTOCOL_VER 0x00000001
+
+
+/** send-on-channel type: FT transfer data */
+#define msg_TRANSFER 0x0001
+
+
+/** ack received transfer data */
+#define msg_RECEIVED 0x0002
+
+
+struct mwServiceFileTransfer {
+ struct mwService service;
+
+ struct mwFileTransferHandler *handler;
+ GList *transfers;
+};
+
+
+struct mwFileTransfer {
+ struct mwServiceFileTransfer *service;
+
+ struct mwChannel *channel;
+ struct mwIdBlock who;
+
+ enum mwFileTransferState state;
+
+ char *filename;
+ char *message;
+
+ guint32 size;
+ guint32 remaining;
+
+ struct mw_datum client_data;
+};
+
+
+/** momentarily places a mwLoginInfo into a mwIdBlock */
+static void login_into_id(struct mwIdBlock *to, struct mwLoginInfo *from) {
+ to->user = from->user_id;
+ to->community = from->community;
+}
+
+
+static const char *ft_state_str(enum mwFileTransferState state) {
+ switch(state) {
+ case mwFileTransfer_NEW:
+ return "new";
+
+ case mwFileTransfer_PENDING:
+ return "pending";
+
+ case mwFileTransfer_OPEN:
+ return "open";
+
+ case mwFileTransfer_CANCEL_LOCAL:
+ return "cancelled locally";
+
+ case mwFileTransfer_CANCEL_REMOTE:
+ return "cancelled remotely";
+
+ case mwFileTransfer_DONE:
+ return "done";
+
+ case mwFileTransfer_ERROR:
+ return "error";
+
+ case mwFileTransfer_UNKNOWN:
+ default:
+ return "UNKNOWN";
+ }
+}
+
+
+static void ft_state(struct mwFileTransfer *ft,
+ enum mwFileTransferState state) {
+
+ g_return_if_fail(ft != NULL);
+
+ if(ft->state == state) return;
+
+ // Miranda NG adaptation
+ //g_info("setting ft (%s, %s) state: %s",
+ // NSTR(ft->who.user), NSTR(ft->who.community),
+ // ft_state_str(state));
+ g_message("setting ft (%s, %s) state: %s", NSTR(ft->who.user), NSTR(ft->who.community), ft_state_str(state));
+
+ ft->state = state;
+}
+
+
+static void recv_channelCreate(struct mwServiceFileTransfer *srvc,
+ struct mwChannel *chan,
+ struct mwMsgChannelCreate *msg) {
+
+ struct mwFileTransferHandler *handler;
+ struct mwGetBuffer *b;
+
+ char *fnm, *txt;
+ guint32 size, junk;
+ gboolean b_err;
+
+ g_return_if_fail(srvc->handler != NULL);
+ handler = srvc->handler;
+
+ b = mwGetBuffer_wrap(&msg->addtl);
+
+ guint32_get(b, &junk); /* unknown */
+ mwString_get(b, &fnm); /* offered filename */
+ mwString_get(b, &txt); /* offering message */
+ guint32_get(b, &size); /* size of offered file */
+ /// Miranda NG adaptation - start - http://www.lilotux.net/~mikael/pub/meanwhile/ft_fix.diff
+ /* guint32_get(b, &junk); */ /* unknown */
+ /// Miranda NG adaptation - end
+ /* and we just skip an unknown guint16 at the end */
+
+ b_err = mwGetBuffer_error(b);
+ mwGetBuffer_free(b);
+
+ if(b_err) {
+ g_warning("bad/malformed addtl in File Transfer service");
+ mwChannel_destroy(chan, ERR_FAILURE, NULL);
+
+ } else {
+ struct mwIdBlock idb;
+ struct mwFileTransfer *ft;
+
+ login_into_id(&idb, mwChannel_getUser(chan));
+ ft = mwFileTransfer_new(srvc, &idb, txt, fnm, size);
+ ft->channel = chan;
+ ft_state(ft, mwFileTransfer_PENDING);
+
+ mwChannel_setServiceData(chan, ft, NULL);
+
+ if(handler->ft_offered)
+ handler->ft_offered(ft);
+ }
+
+ g_free(fnm);
+ g_free(txt);
+}
+
+
+static void recv_channelAccept(struct mwServiceFileTransfer *srvc,
+ struct mwChannel *chan,
+ struct mwMsgChannelAccept *msg) {
+
+ struct mwFileTransferHandler *handler;
+ struct mwFileTransfer *ft;
+
+ g_return_if_fail(srvc->handler != NULL);
+ handler = srvc->handler;
+
+ ft = mwChannel_getServiceData(chan);
+ g_return_if_fail(ft != NULL);
+
+ ft_state(ft, mwFileTransfer_OPEN);
+
+ if(handler->ft_opened)
+ handler->ft_opened(ft);
+}
+
+
+static void recv_channelDestroy(struct mwServiceFileTransfer *srvc,
+ struct mwChannel *chan,
+ struct mwMsgChannelDestroy *msg) {
+
+ struct mwFileTransferHandler *handler;
+ struct mwFileTransfer *ft;
+ guint32 code;
+
+ code = msg->reason;
+
+ g_return_if_fail(srvc->handler != NULL);
+ handler = srvc->handler;
+
+ ft = mwChannel_getServiceData(chan);
+ g_return_if_fail(ft != NULL);
+
+ ft->channel = NULL;
+
+ if(! mwFileTransfer_isDone(ft))
+ ft_state(ft, mwFileTransfer_CANCEL_REMOTE);
+
+ mwFileTransfer_close(ft, code);
+}
+
+
+static void recv_TRANSFER(struct mwFileTransfer *ft,
+ struct mwOpaque *data) {
+
+ struct mwServiceFileTransfer *srvc;
+ struct mwFileTransferHandler *handler;
+
+ srvc = ft->service;
+ handler = srvc->handler;
+
+ g_return_if_fail(mwFileTransfer_isOpen(ft));
+
+ if(data->len > ft->remaining) {
+ /* @todo handle error */
+
+ } else {
+ ft->remaining -= data->len;
+
+ if(! ft->remaining)
+ ft_state(ft, mwFileTransfer_DONE);
+
+ if(handler->ft_recv)
+ handler->ft_recv(ft, data);
+ }
+}
+
+
+static void recv_RECEIVED(struct mwFileTransfer *ft,
+ struct mwOpaque *data) {
+
+ struct mwServiceFileTransfer *srvc;
+ struct mwFileTransferHandler *handler;
+
+ srvc = ft->service;
+ handler = srvc->handler;
+
+ if(! ft->remaining)
+ ft_state(ft, mwFileTransfer_DONE);
+
+ if(handler->ft_ack)
+ handler->ft_ack(ft);
+
+ if(! ft->remaining)
+ mwFileTransfer_close(ft, mwFileTransfer_SUCCESS);
+}
+
+
+static void recv(struct mwService *srvc, struct mwChannel *chan,
+ guint16 type, struct mwOpaque *data) {
+
+ struct mwFileTransfer *ft;
+
+ ft = mwChannel_getServiceData(chan);
+ g_return_if_fail(ft != NULL);
+
+ switch(type) {
+ case msg_TRANSFER:
+ recv_TRANSFER(ft, data);
+ break;
+
+ case msg_RECEIVED:
+ recv_RECEIVED(ft, data);
+ break;
+
+ default:
+ mw_mailme_opaque(data, "unknown message in ft service: 0x%04x", type);
+ }
+}
+
+
+static void clear(struct mwServiceFileTransfer *srvc) {
+ struct mwFileTransferHandler *h;
+
+ h = srvc->handler;
+ if(h && h->clear)
+ h->clear(srvc);
+ srvc->handler = NULL;
+}
+
+
+static const char *name(struct mwService *srvc) {
+ return "File Transfer";
+}
+
+
+static const char *desc(struct mwService *srvc) {
+ return "Provides file transfer capabilities through the community server";
+}
+
+
+static void start(struct mwService *srvc) {
+ mwService_started(srvc);
+}
+
+
+static void stop(struct mwServiceFileTransfer *srvc) {
+ while(srvc->transfers) {
+ mwFileTransfer_free(srvc->transfers->data);
+ }
+
+ mwService_stopped(MW_SERVICE(srvc));
+}
+
+
+struct mwServiceFileTransfer *
+mwServiceFileTransfer_new(struct mwSession *session,
+ struct mwFileTransferHandler *handler) {
+
+ struct mwServiceFileTransfer *srvc_ft;
+ struct mwService *srvc;
+
+ g_return_val_if_fail(session != NULL, NULL);
+ g_return_val_if_fail(handler != NULL, NULL);
+
+ srvc_ft = g_new0(struct mwServiceFileTransfer, 1);
+ srvc = MW_SERVICE(srvc_ft);
+
+ mwService_init(srvc, session, mwService_FILE_TRANSFER);
+ srvc->recv_create = (mwService_funcRecvCreate) recv_channelCreate;
+ srvc->recv_accept = (mwService_funcRecvAccept) recv_channelAccept;
+ srvc->recv_destroy = (mwService_funcRecvDestroy) recv_channelDestroy;
+ srvc->recv = recv;
+ srvc->clear = (mwService_funcClear) clear;
+ srvc->get_name = name;
+ srvc->get_desc = desc;
+ srvc->start = start;
+ srvc->stop = (mwService_funcStop) stop;
+
+ srvc_ft->handler = handler;
+
+ return srvc_ft;
+}
+
+
+struct mwFileTransferHandler *
+mwServiceFileTransfer_getHandler(struct mwServiceFileTransfer *srvc) {
+ g_return_val_if_fail(srvc != NULL, NULL);
+ return srvc->handler;
+}
+
+
+const GList *
+mwServiceFileTransfer_getTransfers(struct mwServiceFileTransfer *srvc) {
+ g_return_val_if_fail(srvc != NULL, NULL);
+ return srvc->transfers;
+}
+
+
+/// Miranda NG adaptation start - new method
+struct mwService *
+mwServiceFileTransfer_getService(struct mwServiceFileTransfer *srvc) {
+ g_return_val_if_fail(srvc != NULL, NULL);
+ return &(srvc->service);
+}
+/// Miranda NG adaptation end
+
+
+struct mwFileTransfer *
+mwFileTransfer_new(struct mwServiceFileTransfer *srvc,
+ const struct mwIdBlock *who, const char *msg,
+ const char *filename, guint32 filesize) {
+
+ struct mwFileTransfer *ft;
+
+ g_return_val_if_fail(srvc != NULL, NULL);
+ g_return_val_if_fail(who != NULL, NULL);
+
+ ft = g_new0(struct mwFileTransfer, 1);
+ ft->service = srvc;
+ mwIdBlock_clone(&ft->who, who);
+ ft->filename = g_strdup(filename);
+ ft->message = g_strdup(msg);
+ ft->size = ft->remaining = filesize;
+
+ ft_state(ft, mwFileTransfer_NEW);
+
+ /* stick a reference in the service */
+ srvc->transfers = g_list_prepend(srvc->transfers, ft);
+
+ return ft;
+}
+
+
+struct mwServiceFileTransfer *
+mwFileTransfer_getService(struct mwFileTransfer *ft) {
+ g_return_val_if_fail(ft != NULL, NULL);
+ return ft->service;
+}
+
+
+enum mwFileTransferState
+mwFileTransfer_getState(struct mwFileTransfer *ft) {
+ g_return_val_if_fail(ft != NULL, mwFileTransfer_UNKNOWN);
+ return ft->state;
+}
+
+
+const struct mwIdBlock *
+mwFileTransfer_getUser(struct mwFileTransfer *ft) {
+ g_return_val_if_fail(ft != NULL, NULL);
+ return &ft->who;
+}
+
+
+const char *
+mwFileTransfer_getMessage(struct mwFileTransfer *ft) {
+ g_return_val_if_fail(ft != NULL, NULL);
+ return ft->message;
+}
+
+
+const char *
+mwFileTransfer_getFileName(struct mwFileTransfer *ft) {
+ g_return_val_if_fail(ft != NULL, NULL);
+ return ft->filename;
+}
+
+
+guint32 mwFileTransfer_getFileSize(struct mwFileTransfer *ft) {
+ g_return_val_if_fail(ft != NULL, 0);
+ return ft->size;
+}
+
+
+guint32 mwFileTransfer_getRemaining(struct mwFileTransfer *ft) {
+ g_return_val_if_fail(ft != NULL, 0);
+ return ft->remaining;
+}
+
+
+int mwFileTransfer_accept(struct mwFileTransfer *ft) {
+ struct mwServiceFileTransfer *srvc;
+ struct mwFileTransferHandler *handler;
+ int ret;
+
+ g_return_val_if_fail(ft != NULL, -1);
+ g_return_val_if_fail(ft->channel != NULL, -1);
+ g_return_val_if_fail(mwFileTransfer_isPending(ft), -1);
+ g_return_val_if_fail(mwChannel_isIncoming(ft->channel), -1);
+ g_return_val_if_fail(mwChannel_isState(ft->channel, mwChannel_WAIT), -1);
+
+ g_return_val_if_fail(ft->service != NULL, -1);
+ srvc = ft->service;
+
+ g_return_val_if_fail(srvc->handler != NULL, -1);
+ handler = srvc->handler;
+
+ ret = mwChannel_accept(ft->channel);
+
+ if(ret) {
+ mwFileTransfer_close(ft, ERR_FAILURE);
+
+ } else {
+ ft_state(ft, mwFileTransfer_OPEN);
+ if(handler->ft_opened)
+ handler->ft_opened(ft);
+ }
+
+ return ret;
+}
+
+
+static void ft_create_chan(struct mwFileTransfer *ft) {
+ struct mwSession *s;
+ struct mwChannelSet *cs;
+ struct mwChannel *chan;
+ struct mwLoginInfo *login;
+ struct mwPutBuffer *b;
+
+ /* we only should be calling this if there isn't a channel already
+ associated with the conversation */
+ g_return_if_fail(ft != NULL);
+ g_return_if_fail(mwFileTransfer_isNew(ft));
+ g_return_if_fail(ft->channel == NULL);
+
+ s = mwService_getSession(MW_SERVICE(ft->service));
+ cs = mwSession_getChannels(s);
+
+ chan = mwChannel_newOutgoing(cs);
+ mwChannel_setService(chan, MW_SERVICE(ft->service));
+ mwChannel_setProtoType(chan, PROTOCOL_TYPE);
+ mwChannel_setProtoVer(chan, PROTOCOL_VER);
+
+ /* offer all known ciphers */
+ mwChannel_populateSupportedCipherInstances(chan);
+
+ /* set the target */
+ login = mwChannel_getUser(chan);
+ login->user_id = g_strdup(ft->who.user);
+ login->community = g_strdup(ft->who.community);
+
+ /* compose the addtl create */
+ b = mwPutBuffer_new();
+ guint32_put(b, 0x00);
+ mwString_put(b, ft->filename);
+ mwString_put(b, ft->message);
+ guint32_put(b, ft->size);
+ guint32_put(b, 0x00);
+ guint16_put(b, 0x00);
+
+ mwPutBuffer_finalize(mwChannel_getAddtlCreate(chan), b);
+
+ ft->channel = mwChannel_create(chan)? NULL: chan;
+ if(ft->channel) {
+ mwChannel_setServiceData(ft->channel, ft, NULL);
+ }
+}
+
+
+int mwFileTransfer_offer(struct mwFileTransfer *ft) {
+ struct mwServiceFileTransfer *srvc;
+ struct mwFileTransferHandler *handler;
+
+ g_return_val_if_fail(ft != NULL, -1);
+ g_return_val_if_fail(ft->channel == NULL, -1);
+ g_return_val_if_fail(mwFileTransfer_isNew(ft), -1);
+
+ g_return_val_if_fail(ft->service != NULL, -1);
+ srvc = ft->service;
+
+ g_return_val_if_fail(srvc->handler != NULL, -1);
+ handler = srvc->handler;
+
+ ft_create_chan(ft);
+ if(ft->channel) {
+ ft_state(ft, mwFileTransfer_PENDING);
+ } else {
+ ft_state(ft, mwFileTransfer_ERROR);
+ mwFileTransfer_close(ft, ERR_FAILURE);
+ }
+
+ return 0;
+}
+
+
+int mwFileTransfer_close(struct mwFileTransfer *ft, guint32 code) {
+ struct mwServiceFileTransfer *srvc;
+ struct mwFileTransferHandler *handler;
+ int ret = 0;
+
+ g_return_val_if_fail(ft != NULL, -1);
+
+ if(mwFileTransfer_isOpen(ft))
+ ft_state(ft, mwFileTransfer_CANCEL_LOCAL);
+
+ if(ft->channel) {
+ ret = mwChannel_destroy(ft->channel, code, NULL);
+ ft->channel = NULL;
+ }
+
+ srvc = ft->service;
+ g_return_val_if_fail(srvc != NULL, ret);
+
+ handler = srvc->handler;
+ g_return_val_if_fail(handler != NULL, ret);
+
+ if(handler->ft_closed)
+ handler->ft_closed(ft, code);
+
+ return ret;
+}
+
+
+void mwFileTransfer_free(struct mwFileTransfer *ft) {
+ struct mwServiceFileTransfer *srvc;
+
+ if(! ft) return;
+
+ srvc = ft->service;
+ if(srvc)
+ srvc->transfers = g_list_remove(srvc->transfers, ft);
+
+ if(ft->channel) {
+ mwChannel_destroy(ft->channel, mwFileTransfer_SUCCESS, NULL);
+ ft->channel = NULL;
+ }
+
+ mwFileTransfer_removeClientData(ft);
+
+ mwIdBlock_clear(&ft->who);
+ g_free(ft->filename);
+ g_free(ft->message);
+ g_free(ft);
+}
+
+
+int mwFileTransfer_send(struct mwFileTransfer *ft,
+ struct mwOpaque *data) {
+
+ struct mwChannel *chan;
+ int ret;
+
+ g_return_val_if_fail(ft != NULL, -1);
+ g_return_val_if_fail(mwFileTransfer_isOpen(ft), -1);
+ g_return_val_if_fail(ft->channel != NULL, -1);
+ chan = ft->channel;
+
+ g_return_val_if_fail(mwChannel_isOutgoing(chan), -1);
+
+ if(data->len > ft->remaining) {
+ /* @todo handle error */
+ return -1;
+ }
+
+ ret = mwChannel_send(chan, msg_TRANSFER, data);
+ if(! ret) ft->remaining -= data->len;
+
+ /* we're not done until we receive an ACK for the last piece of
+ outgoing data */
+
+ return ret;
+}
+
+
+int mwFileTransfer_ack(struct mwFileTransfer *ft) {
+ struct mwChannel *chan;
+
+ g_return_val_if_fail(ft != NULL, -1);
+
+ chan = ft->channel;
+ g_return_val_if_fail(chan != NULL, -1);
+ g_return_val_if_fail(mwChannel_isIncoming(chan), -1);
+
+ return mwChannel_sendEncrypted(chan, msg_RECEIVED, NULL, FALSE);
+}
+
+
+void mwFileTransfer_setClientData(struct mwFileTransfer *ft,
+ gpointer data, GDestroyNotify clean) {
+ g_return_if_fail(ft != NULL);
+ mw_datum_set(&ft->client_data, data, clean);
+}
+
+
+gpointer mwFileTransfer_getClientData(struct mwFileTransfer *ft) {
+ g_return_val_if_fail(ft != NULL, NULL);
+ return mw_datum_get(&ft->client_data);
+}
+
+
+void mwFileTransfer_removeClientData(struct mwFileTransfer *ft) {
+ g_return_if_fail(ft != NULL);
+ mw_datum_clear(&ft->client_data);
+}
+
diff --git a/protocols/Sametime/src/meanwhile/src/srvc_im.c b/protocols/Sametime/src/meanwhile/src/srvc_im.c
new file mode 100644
index 0000000000..b03991d3b9
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/srvc_im.c
@@ -0,0 +1,1095 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <glib.h>
+#include <glib/glist.h>
+#include <string.h>
+
+#include "mw_channel.h"
+#include "mw_debug.h"
+#include "mw_error.h"
+#include "mw_message.h"
+#include "mw_service.h"
+#include "mw_session.h"
+#include "mw_srvc_im.h"
+#include "mw_util.h"
+
+
+#define PROTOCOL_TYPE 0x00001000
+#define PROTOCOL_VER 0x00000003
+
+
+/* data for the addtl blocks of channel creation */
+#define mwImAddtlA_NORMAL 0x00000001
+
+#define mwImAddtlB_NORMAL 0x00000001 /**< standard */
+#define mwImAddtlB_PRECONF 0x00000019 /**< pre-conference chat */
+#define mwImAddtlB_NOTESBUDDY 0x00033453 /**< notesbuddy */
+
+#define mwImAddtlC_NORMAL 0x00000002
+
+
+/* send-on-channel message type */
+#define msg_MESSAGE 0x0064 /**< IM message */
+
+
+#define BREAKUP 2048
+
+
+/* which type of im? */
+enum mwImType {
+ mwIm_TEXT = 0x00000001, /**< text message */
+ mwIm_DATA = 0x00000002, /**< status message (usually) */
+};
+
+
+/* which type of data im? */
+enum mwImDataType {
+ mwImData_TYPING = 0x00000001, /**< common use typing indicator */
+ mwImData_SUBJECT = 0x00000003, /**< notesbuddy IM topic */
+ mwImData_HTML = 0x00000004, /**< notesbuddy HTML message */
+ mwImData_MIME = 0x00000005, /**< notesbuddy MIME message, w/image */
+ mwImData_TIMESTAMP = 0x00000006, /**< notesbuddy timestamp */
+
+ mwImData_INVITE = 0x0000000a, /**< Places invitation */
+
+ mwImData_MULTI_START = 0x00001388,
+ mwImData_MULTI_STOP = 0x00001389,
+};
+
+
+/** @todo might be appropriate to make a couple of hashtables to
+ reference conversations by channel and target */
+struct mwServiceIm {
+ struct mwService service;
+
+ enum mwImClientType features;
+
+ struct mwImHandler *handler;
+ GList *convs; /**< list of struct im_convo */
+};
+
+
+struct mwConversation {
+ struct mwServiceIm *service; /**< owning service */
+ struct mwChannel *channel; /**< channel */
+ struct mwIdBlock target; /**< conversation target */
+
+ gboolean ext_id; /**< special treatment, external ID */
+
+ /** state of the conversation, based loosely on the state of its
+ underlying channel */
+ enum mwConversationState state;
+
+ enum mwImClientType features;
+
+ GString *multi; /**< buffer for multi-chunk message */
+ enum mwImSendType multi_type; /**< type of incoming multi-chunk message */
+
+ struct mw_datum client_data;
+};
+
+
+/** momentarily places a mwLoginInfo into a mwIdBlock */
+static void login_into_id(struct mwIdBlock *to, struct mwLoginInfo *from) {
+ to->user = from->user_id;
+ to->community = from->community;
+}
+
+
+static struct mwConversation *convo_find_by_user(struct mwServiceIm *srvc,
+ struct mwIdBlock *to) {
+ GList *l;
+
+ for(l = srvc->convs; l; l = l->next) {
+ struct mwConversation *c = l->data;
+ if(mwIdBlock_equal(&c->target, to))
+ return c;
+ }
+
+ return NULL;
+}
+
+
+static const char *conv_state_str(enum mwConversationState state) {
+ switch(state) {
+ case mwConversation_CLOSED:
+ return "closed";
+
+ case mwConversation_OPEN:
+ return "open";
+
+ case mwConversation_PENDING:
+ return "pending";
+
+ case mwConversation_UNKNOWN:
+ default:
+ return "UNKNOWN";
+ }
+}
+
+
+static void convo_set_state(struct mwConversation *conv,
+ enum mwConversationState state) {
+
+ g_return_if_fail(conv != NULL);
+
+ if(conv->state != state) {
+ // Miranda NG adaptation
+ //g_info("setting conversation (%s, %s) state: %s",
+ // NSTR(conv->target.user), NSTR(conv->target.community),
+ // conv_state_str(state));
+ g_message("setting conversation (%s, %s) state: %s", NSTR(conv->target.user), NSTR(conv->target.community), conv_state_str(state));
+ conv->state = state;
+ }
+}
+
+
+struct mwConversation *mwServiceIm_findConversation(struct mwServiceIm *srvc,
+ struct mwIdBlock *to) {
+ g_return_val_if_fail(srvc != NULL, NULL);
+ g_return_val_if_fail(to != NULL, NULL);
+
+ return convo_find_by_user(srvc, to);
+}
+
+
+struct mwConversation *mwServiceIm_getConversation(struct mwServiceIm *srvc,
+ struct mwIdBlock *to) {
+ struct mwConversation *c;
+
+ g_return_val_if_fail(srvc != NULL, NULL);
+ g_return_val_if_fail(to != NULL, NULL);
+
+ c = convo_find_by_user(srvc, to);
+ if(! c) {
+ c = g_new0(struct mwConversation, 1);
+ c->service = srvc;
+ mwIdBlock_clone(&c->target, to);
+ c->state = mwConversation_CLOSED;
+ c->features = srvc->features;
+
+ /* mark external users */
+ /* c->ext_id = g_str_has_prefix(to->user, "@E "); */
+
+ srvc->convs = g_list_prepend(srvc->convs, c);
+ }
+
+ return c;
+}
+
+
+static void convo_create_chan(struct mwConversation *c) {
+ struct mwSession *s;
+ struct mwChannelSet *cs;
+ struct mwChannel *chan;
+ struct mwLoginInfo *login;
+ struct mwPutBuffer *b;
+
+ /* we only should be calling this if there isn't a channel already
+ associated with the conversation */
+ g_return_if_fail(c != NULL);
+ g_return_if_fail(mwConversation_isPending(c));
+ g_return_if_fail(c->channel == NULL);
+
+ s = mwService_getSession(MW_SERVICE(c->service));
+ cs = mwSession_getChannels(s);
+
+ chan = mwChannel_newOutgoing(cs);
+ mwChannel_setService(chan, MW_SERVICE(c->service));
+ mwChannel_setProtoType(chan, PROTOCOL_TYPE);
+ mwChannel_setProtoVer(chan, PROTOCOL_VER);
+
+ /* offer all known ciphers */
+ mwChannel_populateSupportedCipherInstances(chan);
+
+ /* set the target */
+ login = mwChannel_getUser(chan);
+ login->user_id = g_strdup(c->target.user);
+ login->community = g_strdup(c->target.community);
+
+ /* compose the addtl create, with optional FANCY HTML! */
+ b = mwPutBuffer_new();
+ guint32_put(b, mwImAddtlA_NORMAL);
+ guint32_put(b, c->features);
+ mwPutBuffer_finalize(mwChannel_getAddtlCreate(chan), b);
+
+ c->channel = mwChannel_create(chan)? NULL: chan;
+ if(c->channel) {
+ mwChannel_setServiceData(c->channel, c, NULL);
+ }
+}
+
+
+void mwConversation_open(struct mwConversation *conv) {
+ g_return_if_fail(conv != NULL);
+ g_return_if_fail(mwConversation_isClosed(conv));
+
+ convo_set_state(conv, mwConversation_PENDING);
+ convo_create_chan(conv);
+}
+
+
+static void convo_opened(struct mwConversation *conv) {
+ struct mwImHandler *h = NULL;
+
+ g_return_if_fail(conv != NULL);
+ g_return_if_fail(conv->service != NULL);
+
+ convo_set_state(conv, mwConversation_OPEN);
+ h = conv->service->handler;
+
+ g_return_if_fail(h != NULL);
+
+ if(h->conversation_opened)
+ h->conversation_opened(conv);
+}
+
+
+static void convo_free(struct mwConversation *conv) {
+ struct mwServiceIm *srvc;
+
+ mwConversation_removeClientData(conv);
+
+ srvc = conv->service;
+ srvc->convs = g_list_remove_all(srvc->convs, conv);
+
+ mwIdBlock_clear(&conv->target);
+ g_free(conv);
+}
+
+
+static int send_accept(struct mwConversation *c) {
+
+ struct mwChannel *chan = c->channel;
+ struct mwSession *s = mwChannel_getSession(chan);
+ struct mwUserStatus *stat = mwSession_getUserStatus(s);
+
+ struct mwPutBuffer *b;
+ struct mwOpaque *o;
+
+ b = mwPutBuffer_new();
+ guint32_put(b, mwImAddtlA_NORMAL);
+ guint32_put(b, c->features);
+ guint32_put(b, mwImAddtlC_NORMAL);
+ mwUserStatus_put(b, stat);
+
+ o = mwChannel_getAddtlAccept(chan);
+ mwOpaque_clear(o);
+ mwPutBuffer_finalize(o, b);
+
+ return mwChannel_accept(chan);
+}
+
+
+static void recv_channelCreate(struct mwService *srvc,
+ struct mwChannel *chan,
+ struct mwMsgChannelCreate *msg) {
+
+ /* - ensure it's the right service,proto,and proto ver
+ - check the opaque for the right opaque junk
+ - if not, close channel
+ - compose & send a channel accept
+ */
+
+ struct mwServiceIm *srvc_im = (struct mwServiceIm *) srvc;
+ struct mwImHandler *handler;
+ struct mwSession *s;
+ struct mwUserStatus *stat;
+ guint32 x, y, z;
+ struct mwGetBuffer *b;
+ struct mwConversation *c = NULL;
+ struct mwIdBlock idb;
+
+ handler = srvc_im->handler;
+ s = mwChannel_getSession(chan);
+ stat = mwSession_getUserStatus(s);
+
+ /* ensure the appropriate service/proto/ver */
+ x = mwChannel_getServiceId(chan);
+ y = mwChannel_getProtoType(chan);
+ z = mwChannel_getProtoVer(chan);
+
+ if( (x != mwService_IM) || (y != PROTOCOL_TYPE) || (z != PROTOCOL_VER) ) {
+ g_warning("unacceptable service, proto, ver:"
+ " 0x%08x, 0x%08x, 0x%08x", x, y, z);
+ mwChannel_destroy(chan, ERR_SERVICE_NO_SUPPORT, NULL);
+ return;
+ }
+
+ /* act upon the values in the addtl block */
+ b = mwGetBuffer_wrap(&msg->addtl);
+ guint32_get(b, &x);
+ guint32_get(b, &y);
+ z = (guint) mwGetBuffer_error(b);
+ mwGetBuffer_free(b);
+
+ if(z /* buffer error, BOOM! */ ) {
+ g_warning("bad/malformed addtl in IM service");
+ mwChannel_destroy(chan, ERR_FAILURE, NULL);
+ return;
+
+ } else if(x != mwImAddtlA_NORMAL) {
+ g_message("unknown params: 0x%08x, 0x%08x", x, y);
+ mwChannel_destroy(chan, ERR_IM_NOT_REGISTERED, NULL);
+ return;
+
+ } else if(y == mwImAddtlB_PRECONF) {
+ if(! handler->place_invite) {
+ // Miranda NG adaptation
+ //g_info("rejecting place-invite channel");
+ g_message("rejecting place-invite channel");
+ mwChannel_destroy(chan, ERR_IM_NOT_REGISTERED, NULL);
+ return;
+
+ } else {
+ // Miranda NG adaptation
+ //g_info("accepting place-invite channel");
+ g_message("accepting place-invite channel");
+ }
+
+ } else if(y != mwImClient_PLAIN && y != srvc_im->features) {
+ /** reject what we do not understand */
+ mwChannel_destroy(chan, ERR_IM_NOT_REGISTERED, NULL);
+ return;
+
+ } else if(stat->status == mwStatus_BUSY) {
+ // Miranda NG adaptation
+ //g_info("rejecting IM channel due to DND status");
+ g_message("rejecting IM channel due to DND status");
+ mwChannel_destroy(chan, ERR_CLIENT_USER_DND, NULL);
+ return;
+ }
+
+ login_into_id(&idb, mwChannel_getUser(chan));
+
+#if 0
+ c = convo_find_by_user(srvc_im, &idb);
+#endif
+
+ if(! c) {
+ c = g_new0(struct mwConversation, 1);
+ c->service = srvc_im;
+ srvc_im->convs = g_list_prepend(srvc_im->convs, c);
+ }
+
+#if 0
+ /* we're going to re-associate any existing conversations with this
+ new channel. That means closing any existing ones */
+ if(c->channel) {
+ // Miranda NG adaptation
+ //g_info("closing existing IM channel 0x%08x", mwChannel_getId(c->channel));
+ g_message("closing existing IM channel 0x%08x", mwChannel_getId(c->channel));
+ mwConversation_close(c, ERR_SUCCESS);
+ }
+#endif
+
+ /* set up the conversation with this channel, target, and be fancy
+ if the other side requested it */
+ c->channel = chan;
+ mwIdBlock_clone(&c->target, &idb);
+ c->features = y;
+ convo_set_state(c, mwConversation_PENDING);
+ mwChannel_setServiceData(c->channel, c, NULL);
+
+ if(send_accept(c)) {
+ g_warning("sending IM channel accept failed");
+ mwConversation_free(c);
+
+ } else {
+ convo_opened(c);
+ }
+}
+
+
+static void recv_channelAccept(struct mwService *srvc, struct mwChannel *chan,
+ struct mwMsgChannelAccept *msg) {
+
+ struct mwConversation *conv;
+
+ conv = mwChannel_getServiceData(chan);
+ if(! conv) {
+ g_warning("received channel accept for non-existant conversation");
+ mwChannel_destroy(chan, ERR_FAILURE, NULL);
+ return;
+ }
+
+ convo_opened(conv);
+}
+
+
+static void recv_channelDestroy(struct mwService *srvc, struct mwChannel *chan,
+ struct mwMsgChannelDestroy *msg) {
+
+ struct mwConversation *c;
+
+ c = mwChannel_getServiceData(chan);
+ g_return_if_fail(c != NULL);
+
+ c->channel = NULL;
+
+ if(mwChannel_isState(chan, mwChannel_ERROR)) {
+
+ /* checking for failure on the receiving end to accept html
+ messages. Fail-over to a non-html format on a new channel for
+ the convo */
+ if(c->features != mwImClient_PLAIN
+ && (msg->reason == ERR_IM_NOT_REGISTERED ||
+ msg->reason == ERR_SERVICE_NO_SUPPORT)) {
+
+ g_debug("falling back on a plaintext conversation");
+ c->features = mwImClient_PLAIN;
+ convo_create_chan(c);
+ return;
+ }
+ }
+
+ mwConversation_close(c, msg->reason);
+}
+
+
+static void convo_recv(struct mwConversation *conv, enum mwImSendType type,
+ gconstpointer msg) {
+
+ struct mwServiceIm *srvc;
+ struct mwImHandler *handler;
+
+ g_return_if_fail(conv != NULL);
+
+ srvc = conv->service;
+ g_return_if_fail(srvc != NULL);
+
+ handler = srvc->handler;
+ if(handler && handler->conversation_recv)
+ handler->conversation_recv(conv, type, msg);
+}
+
+
+static void convo_multi_start(struct mwConversation *conv) {
+ g_return_if_fail(conv->multi == NULL);
+ conv->multi = g_string_new(NULL);
+}
+
+
+static void convo_multi_stop(struct mwConversation *conv) {
+
+ g_return_if_fail(conv->multi != NULL);
+
+ /* actually send it */
+ convo_recv(conv, conv->multi_type, conv->multi->str);
+
+ /* clear up the multi buffer */
+ g_string_free(conv->multi, TRUE);
+ conv->multi = NULL;
+}
+
+
+static void recv_text(struct mwServiceIm *srvc, struct mwChannel *chan,
+ struct mwGetBuffer *b) {
+
+ struct mwConversation *c;
+ char *text = NULL;
+
+ mwString_get(b, &text);
+
+ if(! text) return;
+
+ c = mwChannel_getServiceData(chan);
+ if(c) {
+ if(c->multi) {
+ g_string_append(c->multi, text);
+
+ } else {
+ convo_recv(c, mwImSend_PLAIN, text);
+ }
+ }
+
+ g_free(text);
+}
+
+
+static void convo_invite(struct mwConversation *conv,
+ struct mwOpaque *o) {
+
+ struct mwServiceIm *srvc;
+ struct mwImHandler *handler;
+
+ struct mwGetBuffer *b;
+ char *title, *name, *msg;
+ char *unkn, *host;
+ guint16 with_who;
+
+ // Miranda NG adaptation
+ //g_info("convo_invite");
+ g_message("convo_invite");
+
+ srvc = conv->service;
+ handler = srvc->handler;
+
+ g_return_if_fail(handler != NULL);
+ g_return_if_fail(handler->place_invite != NULL);
+
+ b = mwGetBuffer_wrap(o);
+ mwGetBuffer_advance(b, 4);
+ mwString_get(b, &title);
+ mwString_get(b, &msg);
+ mwGetBuffer_advance(b, 19);
+ mwString_get(b, &name);
+
+ /* todo: add a mwString_skip */
+ mwString_get(b, &unkn);
+ mwString_get(b, &host);
+ g_free(unkn);
+ g_free(host);
+
+ /* hack. Sometimes incoming convo invitation channels won't have the
+ owner id block filled in */
+ guint16_get(b, &with_who);
+ if(with_who && !conv->target.user) {
+ char *login;
+ mwString_get(b, &conv->target.user);
+ mwString_get(b, &login); g_free(login);
+ mwString_get(b, &conv->target.community);
+ }
+
+ if(mwGetBuffer_error(b)) {
+ mw_mailme_opaque(o, "problem with place invite over IM service");
+ } else {
+ handler->place_invite(conv, msg, title, name);
+ }
+
+ mwGetBuffer_free(b);
+ g_free(msg);
+ g_free(title);
+ g_free(name);
+}
+
+
+static void recv_data(struct mwServiceIm *srvc, struct mwChannel *chan,
+ struct mwGetBuffer *b) {
+
+ struct mwConversation *conv;
+ guint32 type, subtype;
+ struct mwOpaque o = { 0, 0 };
+ char *x;
+
+ guint32_get(b, &type);
+ guint32_get(b, &subtype);
+ mwOpaque_get(b, &o);
+
+ if(mwGetBuffer_error(b)) {
+ mwOpaque_clear(&o);
+ return;
+ }
+
+ conv = mwChannel_getServiceData(chan);
+ if(! conv) return;
+
+ switch(type) {
+ case mwImData_TYPING:
+ convo_recv(conv, mwImSend_TYPING, GINT_TO_POINTER(! subtype));
+ break;
+
+ case mwImData_HTML:
+ if(o.len) {
+ if(conv->multi) {
+ g_string_append_len(conv->multi, (char *) o.data, o.len);
+ conv->multi_type = mwImSend_HTML;
+
+ } else {
+ x = g_strndup((char *) o.data, o.len);
+ convo_recv(conv, mwImSend_HTML, x);
+ g_free(x);
+ }
+ }
+ break;
+
+ case mwImData_SUBJECT:
+ x = g_strndup((char *) o.data, o.len);
+ convo_recv(conv, mwImSend_SUBJECT, x);
+ g_free(x);
+ break;
+
+ case mwImData_MIME:
+ if(conv->multi) {
+ g_string_append_len(conv->multi, (char *) o.data, o.len);
+ conv->multi_type = mwImSend_MIME;
+
+ } else {
+ x = g_strndup((char *) o.data, o.len);
+ convo_recv(conv, mwImSend_MIME, x);
+ g_free(x);
+ }
+ break;
+
+ case mwImData_TIMESTAMP:
+ /* todo */
+ break;
+
+ case mwImData_INVITE:
+ convo_invite(conv, &o);
+ break;
+
+ case mwImData_MULTI_START:
+ convo_multi_start(conv);
+ break;
+
+ case mwImData_MULTI_STOP:
+ convo_multi_stop(conv);
+ break;
+
+ default:
+
+ mw_mailme_opaque(&o, "unknown data message type in IM service:"
+ " (0x%08x, 0x%08x)", type, subtype);
+ }
+
+ mwOpaque_clear(&o);
+}
+
+
+static void recv(struct mwService *srvc, struct mwChannel *chan,
+ guint16 type, struct mwOpaque *data) {
+
+ /* - ensure message type is something we want
+ - parse message type into either mwIMText or mwIMData
+ - handle
+ */
+
+ struct mwGetBuffer *b;
+ guint32 mt;
+
+ g_return_if_fail(type == msg_MESSAGE);
+
+ b = mwGetBuffer_wrap(data);
+ guint32_get(b, &mt);
+
+ if(mwGetBuffer_error(b)) {
+ g_warning("failed to parse message for IM service");
+ mwGetBuffer_free(b);
+ return;
+ }
+
+ switch(mt) {
+ case mwIm_TEXT:
+ recv_text((struct mwServiceIm *) srvc, chan, b);
+ break;
+
+ case mwIm_DATA:
+ recv_data((struct mwServiceIm *) srvc, chan, b);
+ break;
+
+ default:
+ g_warning("unknown message type 0x%08x for IM service", mt);
+ }
+
+ if(mwGetBuffer_error(b))
+ g_warning("failed to parse message type 0x%08x for IM service", mt);
+
+ mwGetBuffer_free(b);
+}
+
+
+static void clear(struct mwServiceIm *srvc) {
+ struct mwImHandler *h;
+
+ while(srvc->convs)
+ convo_free(srvc->convs->data);
+
+ h = srvc->handler;
+ if(h && h->clear)
+ h->clear(srvc);
+ srvc->handler = NULL;
+}
+
+
+static const char *name(struct mwService *srvc) {
+ return "Instant Messaging";
+}
+
+
+static const char *desc(struct mwService *srvc) {
+ return "IM service with Standard and NotesBuddy features";
+}
+
+
+static void start(struct mwService *srvc) {
+ mwService_started(srvc);
+}
+
+
+static void stop(struct mwServiceIm *srvc) {
+
+ while(srvc->convs)
+ mwConversation_free(srvc->convs->data);
+
+ mwService_stopped(MW_SERVICE(srvc));
+}
+
+
+struct mwServiceIm *mwServiceIm_new(struct mwSession *session,
+ struct mwImHandler *hndl) {
+
+ struct mwServiceIm *srvc_im;
+ struct mwService *srvc;
+
+ g_return_val_if_fail(session != NULL, NULL);
+ g_return_val_if_fail(hndl != NULL, NULL);
+
+ srvc_im = g_new0(struct mwServiceIm, 1);
+ srvc = MW_SERVICE(srvc_im);
+
+ mwService_init(srvc, session, mwService_IM);
+ srvc->recv_create = recv_channelCreate;
+ srvc->recv_accept = recv_channelAccept;
+ srvc->recv_destroy = recv_channelDestroy;
+ srvc->recv = recv;
+ srvc->clear = (mwService_funcClear) clear;
+ srvc->get_name = name;
+ srvc->get_desc = desc;
+ srvc->start = start;
+ srvc->stop = (mwService_funcStop) stop;
+
+ srvc_im->features = mwImClient_PLAIN;
+ srvc_im->handler = hndl;
+
+ return srvc_im;
+}
+
+
+struct mwImHandler *mwServiceIm_getHandler(struct mwServiceIm *srvc) {
+ g_return_val_if_fail(srvc != NULL, NULL);
+ return srvc->handler;
+}
+
+
+/// Miranda NG adaptation start - new method
+struct mwService *mwServiceIm_getService(struct mwServiceIm *srvc) {
+ g_return_val_if_fail(srvc != NULL, NULL);
+ return &(srvc->service);
+}
+/// Miranda NG adaptation end
+
+
+gboolean mwServiceIm_supports(struct mwServiceIm *srvc,
+ enum mwImSendType type) {
+
+ g_return_val_if_fail(srvc != NULL, FALSE);
+
+ switch(type) {
+ case mwImSend_PLAIN:
+ case mwImSend_TYPING:
+ return TRUE;
+
+ case mwImSend_SUBJECT:
+ case mwImSend_HTML:
+ case mwImSend_MIME:
+ case mwImSend_TIMESTAMP:
+ return srvc->features == mwImClient_NOTESBUDDY;
+
+ default:
+ return FALSE;
+ }
+}
+
+
+void mwServiceIm_setClientType(struct mwServiceIm *srvc,
+ enum mwImClientType type) {
+
+ g_return_if_fail(srvc != NULL);
+ srvc->features = type;
+}
+
+
+enum mwImClientType mwServiceIm_getClientType(struct mwServiceIm *srvc) {
+ g_return_val_if_fail(srvc != NULL, mwImClient_UNKNOWN);
+ return srvc->features;
+}
+
+
+static int convo_send_data(struct mwConversation *conv,
+ guint32 type, guint32 subtype,
+ struct mwOpaque *data) {
+ struct mwPutBuffer *b;
+ struct mwOpaque o;
+ struct mwChannel *chan;
+ int ret;
+
+ chan = conv->channel;
+ g_return_val_if_fail(chan != NULL, -1);
+
+ b = mwPutBuffer_new();
+
+ guint32_put(b, mwIm_DATA);
+ guint32_put(b, type);
+ guint32_put(b, subtype);
+ mwOpaque_put(b, data);
+
+ mwPutBuffer_finalize(&o, b);
+
+ ret = mwChannel_sendEncrypted(chan, msg_MESSAGE, &o, !conv->ext_id);
+ mwOpaque_clear(&o);
+
+ return ret;
+}
+
+
+static int convo_send_multi_start(struct mwConversation *conv) {
+ return convo_send_data(conv, mwImData_MULTI_START, 0x00, NULL);
+}
+
+
+static int convo_send_multi_stop(struct mwConversation *conv) {
+ return convo_send_data(conv, mwImData_MULTI_STOP, 0x00, NULL);
+}
+
+
+/* breaks up a large message into segments, sends a start_segment
+ message, then sends each segment in turn, then sends a stop_segment
+ message */
+static int
+convo_sendSegmented(struct mwConversation *conv, const char *message,
+ int (*send)(struct mwConversation *conv,
+ const char *msg)) {
+ char *buf = (char *) message;
+ gsize len;
+ int ret = 0;
+
+ len = strlen(buf);
+ ret = convo_send_multi_start(conv);
+
+ while(len && !ret) {
+ char tail;
+ gsize seg;
+
+ seg = BREAKUP;
+ if(len < BREAKUP)
+ seg = len;
+
+ /* temporarily NUL-terminate this segment */
+ tail = buf[seg];
+ buf[seg] = 0x00;
+
+ ret = send(conv, buf);
+
+ /* restore this segment */
+ buf[seg] = tail;
+
+ buf += seg;
+ len -= seg;
+ }
+
+ if(! ret)
+ ret = convo_send_multi_stop(conv);
+
+ return ret;
+}
+
+
+static int convo_sendText(struct mwConversation *conv, const char *text) {
+ struct mwPutBuffer *b;
+ struct mwOpaque o;
+ int ret;
+
+ b = mwPutBuffer_new();
+
+ guint32_put(b, mwIm_TEXT);
+ mwString_put(b, text);
+
+ mwPutBuffer_finalize(&o, b);
+ ret = mwChannel_sendEncrypted(conv->channel, msg_MESSAGE, &o, !conv->ext_id);
+ mwOpaque_clear(&o);
+
+ return ret;
+}
+
+
+static int convo_sendTyping(struct mwConversation *conv, gboolean typing) {
+ return convo_send_data(conv, mwImData_TYPING, !typing, NULL);
+}
+
+
+static int convo_sendSubject(struct mwConversation *conv,
+ const char *subject) {
+ struct mwOpaque o;
+
+ o.len = strlen(subject);
+ o.data = (guchar *) subject;
+
+ return convo_send_data(conv, mwImData_SUBJECT, 0x00, &o);
+}
+
+
+static int convo_sendHtml(struct mwConversation *conv, const char *html) {
+ struct mwOpaque o;
+
+ o.len = strlen(html);
+ o.data = (guchar *) html;
+
+ if(o.len > BREAKUP) {
+ return convo_sendSegmented(conv, html, convo_sendHtml);
+ } else {
+ return convo_send_data(conv, mwImData_HTML, 0x00, &o);
+ }
+}
+
+
+static int convo_sendMime(struct mwConversation *conv, const char *mime) {
+ struct mwOpaque o;
+
+ o.len = strlen(mime);
+ o.data = (guchar *) mime;
+
+ if(o.len > BREAKUP) {
+ return convo_sendSegmented(conv, mime, convo_sendMime);
+ } else {
+ return convo_send_data(conv, mwImData_MIME, 0x00, &o);
+ }
+}
+
+
+int mwConversation_send(struct mwConversation *conv, enum mwImSendType type,
+ gconstpointer msg) {
+
+ g_return_val_if_fail(conv != NULL, -1);
+ g_return_val_if_fail(mwConversation_isOpen(conv), -1);
+ g_return_val_if_fail(conv->channel != NULL, -1);
+
+ switch(type) {
+ case mwImSend_PLAIN:
+ return convo_sendText(conv, msg);
+ case mwImSend_TYPING:
+ return convo_sendTyping(conv, GPOINTER_TO_INT(msg));
+ case mwImSend_SUBJECT:
+ return convo_sendSubject(conv, msg);
+ case mwImSend_HTML:
+ return convo_sendHtml(conv, msg);
+ case mwImSend_MIME:
+ return convo_sendMime(conv, msg);
+
+ default:
+ g_warning("unsupported IM Send Type, 0x%x", type);
+ return -1;
+ }
+}
+
+
+enum mwConversationState mwConversation_getState(struct mwConversation *conv) {
+ g_return_val_if_fail(conv != NULL, mwConversation_UNKNOWN);
+ return conv->state;
+}
+
+
+struct mwServiceIm *mwConversation_getService(struct mwConversation *conv) {
+ g_return_val_if_fail(conv != NULL, NULL);
+ return conv->service;
+}
+
+
+gboolean mwConversation_supports(struct mwConversation *conv,
+ enum mwImSendType type) {
+ g_return_val_if_fail(conv != NULL, FALSE);
+
+ switch(type) {
+ case mwImSend_PLAIN:
+ case mwImSend_TYPING:
+ return TRUE;
+
+ case mwImSend_SUBJECT:
+ case mwImSend_HTML:
+ case mwImSend_MIME:
+ return conv->features == mwImClient_NOTESBUDDY;
+
+ default:
+ return FALSE;
+ }
+}
+
+
+enum mwImClientType
+mwConversation_getClientType(struct mwConversation *conv) {
+ g_return_val_if_fail(conv != NULL, mwImClient_UNKNOWN);
+ return conv->features;
+}
+
+
+struct mwIdBlock *mwConversation_getTarget(struct mwConversation *conv) {
+ g_return_val_if_fail(conv != NULL, NULL);
+ return &conv->target;
+}
+
+
+struct mwLoginInfo *mwConversation_getTargetInfo(struct mwConversation *conv) {
+ g_return_val_if_fail(conv != NULL, NULL);
+ g_return_val_if_fail(conv->channel != NULL, NULL);
+ return mwChannel_getUser(conv->channel);
+}
+
+
+void mwConversation_setClientData(struct mwConversation *conv,
+ gpointer data, GDestroyNotify clean) {
+ g_return_if_fail(conv != NULL);
+ mw_datum_set(&conv->client_data, data, clean);
+}
+
+
+gpointer mwConversation_getClientData(struct mwConversation *conv) {
+ g_return_val_if_fail(conv != NULL, NULL);
+ return mw_datum_get(&conv->client_data);
+}
+
+
+void mwConversation_removeClientData(struct mwConversation *conv) {
+ g_return_if_fail(conv != NULL);
+ mw_datum_clear(&conv->client_data);
+}
+
+
+void mwConversation_close(struct mwConversation *conv, guint32 reason) {
+ struct mwServiceIm *srvc;
+ struct mwImHandler *h;
+
+ g_return_if_fail(conv != NULL);
+
+ convo_set_state(conv, mwConversation_CLOSED);
+
+ srvc = conv->service;
+ g_return_if_fail(srvc != NULL);
+
+ h = srvc->handler;
+ if(h && h->conversation_closed)
+ h->conversation_closed(conv, reason);
+
+ if(conv->channel) {
+ mwChannel_destroy(conv->channel, reason, NULL);
+ conv->channel = NULL;
+ }
+}
+
+
+void mwConversation_free(struct mwConversation *conv) {
+ g_return_if_fail(conv != NULL);
+
+ if(! mwConversation_isClosed(conv))
+ mwConversation_close(conv, ERR_SUCCESS);
+
+ convo_free(conv);
+}
+
diff --git a/protocols/Sametime/src/meanwhile/src/srvc_place.c b/protocols/Sametime/src/meanwhile/src/srvc_place.c
new file mode 100644
index 0000000000..5029dffbb8
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/srvc_place.c
@@ -0,0 +1,1089 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <glib.h>
+#include <glib/ghash.h>
+#include <glib/glist.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mw_channel.h"
+#include "mw_common.h"
+#include "mw_debug.h"
+#include "mw_error.h"
+#include "mw_message.h"
+#include "mw_service.h"
+#include "mw_session.h"
+#include "mw_srvc_place.h"
+#include "mw_util.h"
+
+
+#define PROTOCOL_TYPE 0x00
+#define PROTOCOL_VER 0x05
+
+
+enum incoming_msg {
+ msg_in_JOIN_RESPONSE = 0x0000, /* ? */
+ msg_in_INFO = 0x0002,
+ msg_in_MESSAGE = 0x0004,
+ msg_in_SECTION = 0x0014, /* see in_section_subtype */
+ msg_in_UNKNOWNa = 0x0015,
+};
+
+
+enum in_section_subtype {
+ msg_in_SECTION_LIST = 0x0000, /* list of section members */
+ msg_in_SECTION_PEER = 0x0001, /* see in_section_peer_subtye */
+ msg_in_SECTION_PART = 0x0003,
+};
+
+
+enum in_section_peer_subtype {
+ msg_in_SECTION_PEER_JOIN = 0x0000,
+ msg_in_SECTION_PEER_PART = 0x0001, /* after msg_in_SECTION_PART */
+ msg_in_SECTION_PEER_CLEAR_ATTR = 0x0003,
+ msg_in_SECTION_PEER_SET_ATTR = 0x0004,
+};
+
+
+enum outgoing_msg {
+ msg_out_JOIN_PLACE = 0x0000, /* ? */
+ msg_out_PEER_INFO = 0x0002, /* ? */
+ msg_out_MESSAGE = 0x0003,
+ msg_out_OLD_INVITE = 0x0005, /* old-style conf. invitation */
+ msg_out_SET_ATTR = 0x000a,
+ msg_out_CLEAR_ATTR = 0x000b,
+ msg_out_SECTION = 0x0014, /* see out_section_subtype */
+ msg_out_UNKNOWNb = 0x001e, /* ? maybe enter stage ? */
+};
+
+
+enum out_section_subtype {
+ msg_out_SECTION_LIST = 0x0002, /* req list of members */
+ msg_out_SECTION_PART = 0x0003,
+};
+
+
+/*
+ : allocate section
+ : state = NEW
+
+ : create channel
+ : state = PENDING
+
+ : channel accepted
+ : msg_out_JOIN_PLACE (maybe create?)
+ : state = JOINING
+
+ : msg_in_JOIN_RESPONSE (contains our place member ID and section ID)
+ : msg_in_INFO (for place, not peer)
+ : state = JOINED
+
+ : msg_out_SECTION_LIST (asking for all sections) (optional)
+ : msg_in_SECTION_LIST (listing all sections, as requested above)
+
+ : msg_out_PEER_INFO (with our place member ID) (optional)
+ : msg_in_INFO (peer info as requested above)
+
+ : msg_out_SECTION_LIST (with our section ID) (sorta optional)
+ : msg_in_SECTION_LIST (section listing as requested above)
+
+ : msg_out_UNKNOWNb
+ : msg_in_SECTION_PEER_JOINED (empty, with our place member ID)
+ : state = OPEN
+
+ : stuff... (invites, joins, parts, messages, attr)
+
+ : state = CLOSING
+ : msg_out_SECTION_PART
+ : destroy channel
+ : deallocate section
+*/
+
+
+struct mwServicePlace {
+ struct mwService service;
+ struct mwPlaceHandler *handler;
+ GList *places;
+};
+
+
+enum mwPlaceState {
+ mwPlace_NEW,
+ mwPlace_PENDING,
+ mwPlace_JOINING,
+ mwPlace_JOINED,
+ mwPlace_OPEN,
+ mwPlace_CLOSING,
+ mwPlace_ERROR,
+ mwPlace_UNKNOWN,
+};
+
+
+struct mwPlace {
+ struct mwServicePlace *service;
+
+ enum mwPlaceState state;
+ struct mwChannel *channel;
+
+ char *name;
+ char *title;
+ GHashTable *members; /* mapping of member ID: place_member */
+ guint32 our_id; /* our member ID */
+ guint32 section; /* the section we're using */
+
+ guint32 requests; /* counter for requests */
+
+ struct mw_datum client_data;
+};
+
+
+struct place_member {
+ guint32 place_id;
+ guint16 member_type;
+ struct mwIdBlock idb;
+ char *login_id;
+ char *name;
+ guint16 login_type;
+ guint32 unknown_a;
+ guint32 unknown_b;
+};
+
+
+#define GET_MEMBER(place, id) \
+ (g_hash_table_lookup(place->members, GUINT_TO_POINTER(id)))
+
+
+#define PUT_MEMBER(place, member) \
+ (g_hash_table_insert(place->members, \
+ GUINT_TO_POINTER(member->place_id), member))
+
+
+#define REMOVE_MEMBER_ID(place, id) \
+ (g_hash_table_remove(place->members, GUINT_TO_POINTER(id)))
+
+
+#define REMOVE_MEMBER(place, member) \
+ REMOVE_MEMBER_ID(place, member->place_id)
+
+
+static void member_free(struct place_member *p) {
+ mwIdBlock_clear(&p->idb);
+ g_free(p->login_id);
+ g_free(p->name);
+ g_free(p);
+}
+
+/// Miranda NG adaptation start - MSVC
+/// __attribute__((used))
+/// Miranda NG adaptation end
+static const struct mwLoginInfo *
+member_as_login_info(struct place_member *p) {
+ static struct mwLoginInfo li;
+
+ li.login_id = p->login_id;
+ li.type = p->login_type;
+ li.user_id = p->idb.user;
+ li.user_name = p->name;
+ li.community = p->idb.community;
+ li.full = FALSE;
+
+ return &li;
+}
+
+
+static const char *place_state_str(enum mwPlaceState s) {
+ switch(s) {
+ case mwPlace_NEW: return "new";
+ case mwPlace_PENDING: return "pending";
+ case mwPlace_JOINING: return "joining";
+ case mwPlace_JOINED: return "joined";
+ case mwPlace_OPEN: return "open";
+ case mwPlace_CLOSING: return "closing";
+ case mwPlace_ERROR: return "error";
+
+ case mwPlace_UNKNOWN: /* fall-through */
+ default: return "UNKNOWN";
+ }
+}
+
+
+static void place_state(struct mwPlace *place, enum mwPlaceState s) {
+ g_return_if_fail(place != NULL);
+
+ if(place->state == s) return;
+
+ place->state = s;
+ g_message("place %s state: %s", NSTR(place->name), place_state_str(s));
+}
+
+
+static void place_free(struct mwPlace *place) {
+ struct mwServicePlace *srvc;
+
+ if(! place) return;
+
+ srvc = place->service;
+ g_return_if_fail(srvc != NULL);
+
+ srvc->places = g_list_remove_all(srvc->places, place);
+
+ mw_datum_clear(&place->client_data);
+
+ g_hash_table_destroy(place->members);
+
+ g_free(place->name);
+ g_free(place->title);
+ g_free(place);
+}
+
+
+static int recv_JOIN_RESPONSE(struct mwPlace *place,
+ struct mwGetBuffer *b) {
+
+ int ret = 0;
+ guint32 our_id, section;
+
+ guint32_get(b, &our_id);
+ guint32_get(b, &section);
+
+ place->our_id = our_id;
+ place->section = section;
+
+ return ret;
+}
+
+
+static int send_SECTION_LIST(struct mwPlace *place, guint32 section) {
+ int ret = 0;
+ struct mwOpaque o = {0, 0};
+ struct mwPutBuffer *b;
+
+ b = mwPutBuffer_new();
+ guint16_put(b, msg_out_SECTION_LIST);
+ guint32_put(b, section);
+ gboolean_put(b, FALSE);
+ guint32_put(b, ++place->requests);
+ mwPutBuffer_finalize(&o, b);
+
+ ret = mwChannel_send(place->channel, msg_out_SECTION, &o);
+ mwOpaque_clear(&o);
+
+ return ret;
+}
+
+
+static int recv_INFO(struct mwPlace *place,
+ struct mwGetBuffer *b) {
+
+ int ret = 0;
+ guint32 skip = 0;
+ guint32 section = 0;
+
+ guint32_get(b, &skip);
+ guint32_get(b, &section);
+ mwGetBuffer_advance(b, skip);
+
+ if(! section) {
+ /* this is a place info rather than member info */
+ if(place->title) g_free(place->title);
+ mwGetBuffer_advance(b, 2);
+ mwString_get(b, &place->title);
+
+ place_state(place, mwPlace_JOINED);
+ ret = send_SECTION_LIST(place, place->section);
+ }
+
+ return ret;
+}
+
+
+static int recv_MESSAGE(struct mwPlace *place,
+ struct mwGetBuffer *b) {
+
+ struct mwServicePlace *srvc;
+ guint32 pm_id;
+ guint32 unkn_a, unkn_b, ign;
+ struct place_member *pm;
+ char *msg = NULL;
+ int ret = 0;
+
+ srvc = place->service;
+
+ /* no messages before becoming fully open, please */
+ g_return_val_if_fail(place->state == mwPlace_OPEN, -1);
+
+ /* regarding unkn_a and unkn_b:
+
+ they're probably a section indicator and a message count, I'm
+ just not sure which is which. Until this implementation supports
+ place sections in the API, it really doesn't matter. */
+
+ guint32_get(b, &pm_id);
+ pm = GET_MEMBER(place, pm_id);
+ g_return_val_if_fail(pm != NULL, -1);
+
+ guint32_get(b, &unkn_a);
+ guint32_get(b, &ign); /* actually an opaque length */
+
+ if(! ign) return ret;
+
+ guint32_get(b, &unkn_b);
+ mwString_get(b, &msg);
+
+ if(srvc->handler && srvc->handler->message)
+ srvc->handler->message(place, &pm->idb, msg);
+
+ g_free(msg);
+
+ return ret;
+}
+
+
+static void place_opened(struct mwPlace *place) {
+ struct mwServicePlace *srvc;
+
+ place_state(place, mwPlace_OPEN);
+
+ srvc = place->service;
+ if(srvc->handler && srvc->handler->opened)
+ srvc->handler->opened(place);
+}
+
+
+static int recv_SECTION_PEER_JOIN(struct mwPlace *place,
+ struct mwGetBuffer *b) {
+ struct mwServicePlace *srvc;
+ struct place_member *pm;
+ guint32 section;
+ int ret = 0;
+
+ srvc = place->service;
+
+ guint32_get(b, &section);
+ if(! section) {
+ /// Miranda NG adaptation start - MSVC
+ ///g_info("SECTION_PEER_JOIN with section 0x00");
+ g_message("SECTION_PEER_JOIN with section 0x00");
+ /// Miranda NG adaptation end
+ return 0;
+ }
+
+ mwGetBuffer_advance(b, 4);
+
+ pm = g_new0(struct place_member, 1);
+ guint32_get(b, &pm->place_id);
+ guint16_get(b, &pm->member_type);
+ mwIdBlock_get(b, &pm->idb);
+ mwString_get(b, &pm->login_id);
+ mwString_get(b, &pm->name);
+ guint16_get(b, &pm->login_type);
+ guint32_get(b, &pm->unknown_a);
+ guint32_get(b, &pm->unknown_b);
+
+ PUT_MEMBER(place, pm);
+ if(srvc->handler && srvc->handler->peerJoined)
+ srvc->handler->peerJoined(place, &pm->idb);
+
+ if(pm->place_id == place->our_id)
+ place_opened(place);
+
+ return ret;
+}
+
+
+static int recv_SECTION_PEER_PART(struct mwPlace *place,
+ struct mwGetBuffer *b) {
+ struct mwServicePlace *srvc;
+ int ret = 0;
+ guint32 section, id;
+ struct place_member *pm;
+
+ srvc = place->service;
+
+ guint32_get(b, &section);
+ g_return_val_if_fail(section == place->section, 0);
+
+ guint32_get(b, &id);
+ pm = GET_MEMBER(place, id);
+
+ /* SECTION_PART may have been called already */
+ if(! pm) return 0;
+
+ if(srvc->handler && srvc->handler->peerParted)
+ srvc->handler->peerParted(place, &pm->idb);
+
+ REMOVE_MEMBER(place, pm);
+
+ return ret;
+}
+
+
+static int recv_SECTION_PEER_CLEAR_ATTR(struct mwPlace *place,
+ struct mwGetBuffer *b) {
+ struct mwServicePlace *srvc;
+ int ret = 0;
+ guint32 id, attr;
+ struct place_member *pm;
+
+ srvc = place->service;
+
+ guint32_get(b, &id);
+ guint32_get(b, &attr);
+
+ pm = GET_MEMBER(place, id);
+ g_return_val_if_fail(pm != NULL, -1);
+
+ if(srvc->handler && srvc->handler->peerUnsetAttribute)
+ srvc->handler->peerUnsetAttribute(place, &pm->idb, attr);
+
+ return ret;
+}
+
+
+static int recv_SECTION_PEER_SET_ATTR(struct mwPlace *place,
+ struct mwGetBuffer *b) {
+ struct mwServicePlace *srvc;
+ int ret = 0;
+ guint32 id, attr;
+ struct mwOpaque o = {0,0};
+ struct place_member *pm;
+
+ srvc = place->service;
+
+ guint32_get(b, &id);
+ mwGetBuffer_advance(b, 4);
+ mwOpaque_get(b, &o);
+ mwGetBuffer_advance(b, 4);
+ guint32_get(b, &attr);
+
+ pm = GET_MEMBER(place, id);
+ g_return_val_if_fail(pm != NULL, -1);
+
+ if(srvc->handler && srvc->handler->peerSetAttribute)
+ srvc->handler->peerSetAttribute(place, &pm->idb, attr, &o);
+
+ mwOpaque_clear(&o);
+
+ return ret;
+}
+
+
+static int recv_SECTION_PEER(struct mwPlace *place,
+ struct mwGetBuffer *b) {
+ guint16 subtype;
+ int res;
+
+ guint16_get(b, &subtype);
+
+ g_return_val_if_fail(! mwGetBuffer_error(b), -1);
+
+ switch(subtype) {
+ case msg_in_SECTION_PEER_JOIN:
+ res = recv_SECTION_PEER_JOIN(place, b);
+ break;
+
+ case msg_in_SECTION_PEER_PART:
+ res = recv_SECTION_PEER_PART(place, b);
+ break;
+
+ case msg_in_SECTION_PEER_CLEAR_ATTR:
+ res = recv_SECTION_PEER_CLEAR_ATTR(place, b);
+ break;
+
+ case msg_in_SECTION_PEER_SET_ATTR:
+ res = recv_SECTION_PEER_SET_ATTR(place, b);
+ break;
+
+ default:
+ res = -1;
+ }
+
+ return res;
+}
+
+
+static int recv_SECTION_LIST(struct mwPlace *place,
+ struct mwGetBuffer *b) {
+ int ret = 0;
+ guint32 sec, count;
+
+ mwGetBuffer_advance(b, 4);
+ guint32_get(b, &sec);
+
+ g_return_val_if_fail(sec == place->section, -1);
+
+ mwGetBuffer_advance(b, 8);
+ guint32_get(b, &count);
+ mwGetBuffer_advance(b, 8);
+
+ while(count--) {
+ struct place_member *m;
+
+ m = g_new0(struct place_member, 1);
+ mwGetBuffer_advance(b, 4);
+ guint32_get(b, &m->place_id);
+ guint16_get(b, &m->member_type);
+ mwIdBlock_get(b, &m->idb);
+ mwString_get(b, &m->login_id);
+ mwString_get(b, &m->name);
+ guint16_get(b, &m->login_type);
+ guint32_get(b, &m->unknown_a);
+ guint32_get(b, &m->unknown_b);
+
+ PUT_MEMBER(place, m);
+ }
+
+ if(place->state != mwPlace_OPEN)
+ place_opened(place);
+
+ return ret;
+}
+
+
+static int recv_SECTION_PART(struct mwPlace *place,
+ struct mwGetBuffer *b) {
+ /* look up user in place
+ remove user from place
+ trigger event */
+
+ struct mwServicePlace *srvc;
+ guint32 pm_id;
+ struct place_member *pm;
+
+ srvc = place->service;
+
+ guint32_get(b, &pm_id);
+ pm = GET_MEMBER(place, pm_id);
+
+ /* SECTION_PEER_PART may have been called already */
+ if(! pm) return 0;
+
+ if(srvc->handler && srvc->handler->peerParted)
+ srvc->handler->peerParted(place, &pm->idb);
+
+ REMOVE_MEMBER(place, pm);
+
+ return 0;
+}
+
+
+static int recv_SECTION(struct mwPlace *place, struct mwGetBuffer *b) {
+ guint16 subtype;
+ int res;
+
+ guint16_get(b, &subtype);
+
+ g_return_val_if_fail(! mwGetBuffer_error(b), -1);
+
+ switch(subtype) {
+ case msg_in_SECTION_LIST:
+ res = recv_SECTION_LIST(place, b);
+ break;
+
+ case msg_in_SECTION_PEER:
+ res = recv_SECTION_PEER(place, b);
+ break;
+
+ case msg_in_SECTION_PART:
+ res = recv_SECTION_PART(place, b);
+ break;
+
+ default:
+ res = -1;
+ }
+
+ return res;
+}
+
+
+static int recv_UNKNOWNa(struct mwPlace *place, struct mwGetBuffer *b) {
+ int res = 0;
+
+ if(place->state == mwPlace_JOINING) {
+ ;
+ /* place_state(place, mwPlace_JOINED);
+ res = send_SECTION_LIST(place, place->section); */
+
+ } else if(place->state == mwPlace_JOINED) {
+ ;
+ /* if(GET_MEMBER(place, place->our_id))
+ place_opened(place); */
+ }
+
+ return res;
+}
+
+
+static void recv(struct mwService *service, struct mwChannel *chan,
+ guint16 type, struct mwOpaque *data) {
+
+ struct mwPlace *place;
+ struct mwGetBuffer *b;
+ int res = 0;
+
+ place = mwChannel_getServiceData(chan);
+ g_return_if_fail(place != NULL);
+
+ b = mwGetBuffer_wrap(data);
+ switch(type) {
+ case msg_in_JOIN_RESPONSE:
+ res = recv_JOIN_RESPONSE(place, b);
+ break;
+
+ case msg_in_INFO:
+ res = recv_INFO(place, b);
+ break;
+
+ case msg_in_MESSAGE:
+ res = recv_MESSAGE(place, b);
+ break;
+
+ case msg_in_SECTION:
+ res = recv_SECTION(place, b);
+ break;
+
+ case msg_in_UNKNOWNa:
+ res = recv_UNKNOWNa(place, b);
+ break;
+
+ default:
+ mw_mailme_opaque(data, "Received unknown message type 0x%x on place %s",
+ type, NSTR(place->name));
+ }
+
+ if(res) {
+ mw_mailme_opaque(data, "Troubling parsing message type 0x0%x on place %s",
+ type, NSTR(place->name));
+ }
+
+ mwGetBuffer_free(b);
+}
+
+
+static void stop(struct mwServicePlace *srvc) {
+ while(srvc->places)
+ mwPlace_destroy(srvc->places->data, ERR_SUCCESS);
+
+ mwService_stopped(MW_SERVICE(srvc));
+}
+
+
+static int send_JOIN_PLACE(struct mwPlace *place) {
+ struct mwOpaque o = {0, 0};
+ struct mwPutBuffer *b;
+ int ret;
+
+ b = mwPutBuffer_new();
+ gboolean_put(b, FALSE);
+ guint16_put(b, 0x01);
+ guint16_put(b, 0x02); /* 0x01 */
+ guint16_put(b, 0x01); /* 0x00 */
+
+ mwPutBuffer_finalize(&o, b);
+
+ ret = mwChannel_send(place->channel, msg_out_JOIN_PLACE, &o);
+
+ mwOpaque_clear(&o);
+
+ if(ret) {
+ place_state(place, mwPlace_ERROR);
+ } else {
+ place_state(place, mwPlace_JOINING);
+ }
+
+ return ret;
+}
+
+
+static void recv_channelAccept(struct mwService *service,
+ struct mwChannel *chan,
+ struct mwMsgChannelAccept *msg) {
+ struct mwServicePlace *srvc;
+ struct mwPlace *place;
+ int res;
+
+ srvc = (struct mwServicePlace *) service;
+ g_return_if_fail(srvc != NULL);
+
+ place = mwChannel_getServiceData(chan);
+ g_return_if_fail(place != NULL);
+
+ res = send_JOIN_PLACE(place);
+}
+
+
+static void recv_channelDestroy(struct mwService *service,
+ struct mwChannel *chan,
+ struct mwMsgChannelDestroy *msg) {
+ struct mwServicePlace *srvc;
+ struct mwPlace *place;
+
+ srvc = (struct mwServicePlace *) service;
+ g_return_if_fail(srvc != NULL);
+
+ place = mwChannel_getServiceData(chan);
+ g_return_if_fail(place != NULL);
+
+ place_state(place, mwPlace_ERROR);
+
+ place->channel = NULL;
+
+ if(srvc->handler && srvc->handler->closed)
+ srvc->handler->closed(place, msg->reason);
+
+ mwPlace_destroy(place, msg->reason);
+}
+
+
+static void clear(struct mwServicePlace *srvc) {
+
+ if(srvc->handler && srvc->handler->clear)
+ srvc->handler->clear(srvc);
+
+ while(srvc->places)
+ place_free(srvc->places->data);
+}
+
+
+static const char *get_name(struct mwService *srvc) {
+ return "Places Conferencing";
+}
+
+
+static const char *get_desc(struct mwService *srvc) {
+ return "Barebones conferencing via Places";
+}
+
+
+struct mwServicePlace *
+mwServicePlace_new(struct mwSession *session,
+ struct mwPlaceHandler *handler) {
+
+ struct mwServicePlace *srvc_place;
+ struct mwService *srvc;
+
+ g_return_val_if_fail(session != NULL, NULL);
+ g_return_val_if_fail(handler != NULL, NULL);
+
+ srvc_place = g_new0(struct mwServicePlace, 1);
+ srvc_place->handler = handler;
+
+ srvc = MW_SERVICE(srvc_place);
+ mwService_init(srvc, session, mwService_PLACE);
+ srvc->start = NULL;
+ srvc->stop = (mwService_funcStop) stop;
+ srvc->recv_create = NULL;
+ srvc->recv_accept = recv_channelAccept;
+ srvc->recv_destroy = recv_channelDestroy;
+ srvc->recv = recv;
+ srvc->clear = (mwService_funcClear) clear;
+ srvc->get_name = get_name;
+ srvc->get_desc = get_desc;
+
+ return srvc_place;
+}
+
+
+struct mwPlaceHandler *
+mwServicePlace_getHandler(struct mwServicePlace *srvc) {
+ g_return_val_if_fail(srvc != NULL, NULL);
+ return srvc->handler;
+}
+
+
+const GList *mwServicePlace_getPlaces(struct mwServicePlace *srvc) {
+ g_return_val_if_fail(srvc != NULL, NULL);
+ return srvc->places;
+}
+
+
+struct mwPlace *mwPlace_new(struct mwServicePlace *srvc,
+ const char *name, const char *title) {
+ struct mwPlace *place;
+
+ g_return_val_if_fail(srvc != NULL, NULL);
+
+ place = g_new0(struct mwPlace, 1);
+ place->service = srvc;
+ place->name = g_strdup(name);
+ place->title = g_strdup(title);
+ place->state = mwPlace_NEW;
+
+ place->members = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify) member_free);
+
+ srvc->places = g_list_prepend(srvc->places, place);
+
+ return place;
+}
+
+
+struct mwServicePlace *mwPlace_getService(struct mwPlace *place) {
+ g_return_val_if_fail(place != NULL, NULL);
+ return place->service;
+}
+
+
+static char *place_generate_name(const char *user) {
+ /// Miranda NG adaptation start - MSVC
+ ///guint a, b;
+ guint a;
+ guint64 b;
+ /// Miranda NG adaptation end
+ char *ret;
+
+ user = user? user: "meanwhile";
+
+ srand(clock() + rand());
+ a = ((rand() & 0xff) << 8) | (rand() & 0xff);
+ b = time(NULL);
+
+ /// Miranda NG adaptation start - MSVC
+ ///ret = g_strdup_printf("%s(%08x,%04x)", user, b, a);
+ ret = g_strdup_printf("%s(%I64u,%04x)", user, b, a);
+ /// Miranda NG adaptation end
+ g_debug("generated random conference name: '%s'", ret);
+ return ret;
+}
+
+
+const char *mwPlace_getName(struct mwPlace *place) {
+ g_return_val_if_fail(place != NULL, NULL);
+
+ if(! place->name) {
+ struct mwSession *session;
+ struct mwLoginInfo *li;
+
+ session = mwService_getSession(MW_SERVICE(place->service));
+ li = mwSession_getLoginInfo(session);
+
+ place->name = place_generate_name(li? li->user_id: NULL);
+ }
+
+ return place->name;
+}
+
+
+static char *place_generate_title(const char *user) {
+ char *ret;
+
+ user = user? user: "Meanwhile";
+ ret = g_strdup_printf("%s's Conference", user);
+ g_debug("generated conference title: %s", ret);
+
+ return ret;
+}
+
+
+const char *mwPlace_getTitle(struct mwPlace *place) {
+ g_return_val_if_fail(place != NULL, NULL);
+
+ if(! place->title) {
+ struct mwSession *session;
+ struct mwLoginInfo *li;
+
+ session = mwService_getSession(MW_SERVICE(place->service));
+ li = mwSession_getLoginInfo(session);
+
+ place->title = place_generate_title(li? li->user_name: NULL);
+ }
+
+ return place->title;
+}
+
+
+int mwPlace_open(struct mwPlace *p) {
+ struct mwSession *session;
+ struct mwChannelSet *cs;
+ struct mwChannel *chan;
+ struct mwPutBuffer *b;
+ int ret;
+
+ g_return_val_if_fail(p != NULL, -1);
+ g_return_val_if_fail(p->service != NULL, -1);
+
+ session = mwService_getSession(MW_SERVICE(p->service));
+ g_return_val_if_fail(session != NULL, -1);
+
+ cs = mwSession_getChannels(session);
+ g_return_val_if_fail(cs != NULL, -1);
+
+ chan = mwChannel_newOutgoing(cs);
+ mwChannel_setService(chan, MW_SERVICE(p->service));
+ mwChannel_setProtoType(chan, PROTOCOL_TYPE);
+ mwChannel_setProtoVer(chan, PROTOCOL_VER);
+
+ mwChannel_populateSupportedCipherInstances(chan);
+
+ b = mwPutBuffer_new();
+ mwString_put(b, mwPlace_getName(p));
+ mwString_put(b, mwPlace_getTitle(p));
+ guint32_put(b, 0x00); /* ? */
+
+ mwPutBuffer_finalize(mwChannel_getAddtlCreate(chan), b);
+
+ ret = mwChannel_create(chan);
+ if(ret) {
+ place_state(p, mwPlace_ERROR);
+ } else {
+ place_state(p, mwPlace_PENDING);
+ p->channel = chan;
+ mwChannel_setServiceData(chan, p, NULL);
+ }
+
+ return ret;
+}
+
+
+int mwPlace_destroy(struct mwPlace *p, guint32 code) {
+ int ret = 0;
+
+ place_state(p, mwPlace_CLOSING);
+
+ if(p->channel) {
+ ret = mwChannel_destroy(p->channel, code, NULL);
+ p->channel = NULL;
+ }
+
+ place_free(p);
+
+ return ret;
+}
+
+
+GList *mwPlace_getMembers(struct mwPlace *place) {
+ GList *l, *ll;
+
+ g_return_val_if_fail(place != NULL, NULL);
+ g_return_val_if_fail(place->members != NULL, NULL);
+
+ ll = map_collect_values(place->members);
+ for(l = ll; l; l = l->next) {
+ struct place_member *pm = l->data;
+ l->data = &pm->idb;
+ /// Miranda NG adaptation start - MSVC
+ //g_info("collected member %u: %s, %s", pm->place_id,
+ // NSTR(pm->idb.user), NSTR(pm->idb.community));
+ g_message("collected member %u: %s, %s", pm->place_id, NSTR(pm->idb.user), NSTR(pm->idb.community));
+ /// Miranda NG adaptation end
+ }
+
+ return ll;
+}
+
+
+int mwPlace_sendText(struct mwPlace *place, const char *msg) {
+ struct mwOpaque o = {0,0};
+ struct mwPutBuffer *b;
+ int ret;
+
+ b = mwPutBuffer_new();
+ guint32_put(b, 0x01); /* probably a message type */
+ mwString_put(b, msg);
+ mwPutBuffer_finalize(&o, b);
+
+ b = mwPutBuffer_new();
+ guint32_put(b, place->section);
+ mwOpaque_put(b, &o);
+ mwOpaque_clear(&o);
+ mwPutBuffer_finalize(&o, b);
+
+ ret = mwChannel_send(place->channel, msg_out_MESSAGE, &o);
+ mwOpaque_clear(&o);
+ return ret;
+}
+
+
+int mwPlace_legacyInvite(struct mwPlace *place,
+ struct mwIdBlock *idb,
+ const char *message) {
+
+ struct mwOpaque o = {0,0};
+ struct mwPutBuffer *b;
+ int ret;
+
+ b = mwPutBuffer_new();
+ mwIdBlock_put(b, idb);
+ mwString_put(b, idb->user);
+ mwString_put(b, idb->user);
+ mwString_put(b, message);
+ gboolean_put(b, FALSE);
+ mwPutBuffer_finalize(&o, b);
+
+ ret = mwChannel_send(place->channel, msg_out_OLD_INVITE, &o);
+ mwOpaque_clear(&o);
+ return ret;
+}
+
+
+int mwPlace_setAttribute(struct mwPlace *place, guint32 attrib,
+ struct mwOpaque *data) {
+
+ struct mwOpaque o = {0,0};
+ struct mwPutBuffer *b;
+ int ret;
+
+ b = mwPutBuffer_new();
+ guint32_put(b, place->our_id);
+ guint32_put(b, 0x00);
+ guint32_put(b, attrib);
+ mwOpaque_put(b, data);
+
+ ret = mwChannel_send(place->channel, msg_out_SET_ATTR, &o);
+ mwOpaque_clear(&o);
+ return ret;
+}
+
+
+int mwPlace_unsetAttribute(struct mwPlace *place, guint32 attrib) {
+ struct mwOpaque o = {0,0};
+ struct mwPutBuffer *b;
+ int ret;
+
+ b = mwPutBuffer_new();
+ guint32_put(b, place->our_id);
+ guint32_put(b, attrib);
+
+ ret = mwChannel_send(place->channel, msg_out_SET_ATTR, &o);
+ mwOpaque_clear(&o);
+ return ret;
+}
+
+
+void mwPlace_setClientData(struct mwPlace *place,
+ gpointer data, GDestroyNotify clear) {
+
+ g_return_if_fail(place != NULL);
+ mw_datum_set(&place->client_data, data, clear);
+}
+
+
+gpointer mwPlace_getClientData(struct mwPlace *place) {
+ g_return_val_if_fail(place != NULL, NULL);
+ return mw_datum_get(&place->client_data);
+}
+
+
+void mwPlace_removeClientData(struct mwPlace *place) {
+ g_return_if_fail(place != NULL);
+ mw_datum_clear(&place->client_data);
+}
diff --git a/protocols/Sametime/src/meanwhile/src/srvc_resolve.c b/protocols/Sametime/src/meanwhile/src/srvc_resolve.c
new file mode 100644
index 0000000000..bb4c536be8
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/srvc_resolve.c
@@ -0,0 +1,396 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <glib/ghash.h>
+
+#include "mw_channel.h"
+#include "mw_common.h"
+#include "mw_debug.h"
+#include "mw_error.h"
+#include "mw_service.h"
+#include "mw_session.h"
+#include "mw_srvc_resolve.h"
+
+
+#define PROTOCOL_TYPE 0x00000015
+#define PROTOCOL_VER 0x00000000
+
+
+/** oddly, there is only one message type in this service */
+#define RESOLVE_ACTION 0x02
+
+
+struct mwServiceResolve {
+ struct mwService service;
+
+ struct mwChannel *channel; /**< channel for this service */
+ GHashTable *searches; /**< guint32:struct mw_search */
+ guint32 counter; /**< incremented to provide searche IDs */
+};
+
+
+/** structure representing an active search. keeps track of the ID,
+ the handler, and the optional user data and cleanup */
+struct mw_search {
+ struct mwServiceResolve *service;
+ guint32 id;
+ mwResolveHandler handler;
+ gpointer data;
+ GDestroyNotify cleanup;
+};
+
+
+static struct mw_search *search_new(struct mwServiceResolve *srvc,
+ mwResolveHandler handler,
+ gpointer data, GDestroyNotify cleanup) {
+
+ struct mw_search *search = g_new0(struct mw_search, 1);
+
+ search->service = srvc;
+ search->handler = handler;
+
+ /* we want search IDs that aren't SEARCH_ERROR */
+ do {
+ search->id = srvc->counter++;
+ } while(search->id == SEARCH_ERROR);
+
+ search->data = data;
+ search->cleanup = cleanup;
+
+ return search;
+}
+
+
+/** called whenever a mw_search is removed from the searches table of
+ the service */
+static void search_free(struct mw_search *search) {
+ g_return_if_fail(search != NULL);
+
+ if(search->cleanup)
+ search->cleanup(search->data);
+
+ g_free(search);
+}
+
+
+static const char *get_name(struct mwService *srvc) {
+ return "Identity Resolution";
+}
+
+
+static const char *get_desc(struct mwService *srvc) {
+ return "Resolves short IDs to full IDs";
+}
+
+
+static struct mwChannel *make_channel(struct mwServiceResolve *srvc) {
+ struct mwSession *session;
+ struct mwChannelSet *cs;
+ struct mwChannel *chan;
+
+ session = mwService_getSession(MW_SERVICE(srvc));
+ cs = mwSession_getChannels(session);
+ chan = mwChannel_newOutgoing(cs);
+
+ mwChannel_setService(chan, MW_SERVICE(srvc));
+ mwChannel_setProtoType(chan, PROTOCOL_TYPE);
+ mwChannel_setProtoVer(chan, PROTOCOL_VER);
+
+ return mwChannel_create(chan)? NULL: chan;
+}
+
+
+static void start(struct mwServiceResolve *srvc) {
+ struct mwChannel *chan;
+
+ g_return_if_fail(srvc != NULL);
+
+ chan = make_channel(srvc);
+ if(chan) {
+ srvc->channel = chan;
+ } else {
+ mwService_stopped(MW_SERVICE(srvc));
+ return;
+ }
+
+ /* semi-lazily create the searches table */
+ srvc->searches = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify) search_free);
+}
+
+
+static void stop(struct mwServiceResolve *srvc) {
+ g_return_if_fail(srvc != NULL);
+
+ if(srvc->channel) {
+ mwChannel_destroy(srvc->channel, ERR_SUCCESS, NULL);
+ srvc->channel = NULL;
+ }
+
+ /* destroy all the pending requests. */
+ g_hash_table_destroy(srvc->searches);
+ srvc->searches = NULL;
+
+ mwService_stopped(MW_SERVICE(srvc));
+}
+
+
+static void clear(struct mwServiceResolve *srvc) {
+ if(srvc->searches) {
+ g_hash_table_destroy(srvc->searches);
+ srvc->searches = NULL;
+ }
+}
+
+
+static void recv_create(struct mwServiceResolve *srvc,
+ struct mwChannel *chan,
+ struct mwMsgChannelCreate *msg) {
+
+ /* you serve me, not the other way around */
+ mwChannel_destroy(chan, ERR_FAILURE, NULL);
+}
+
+
+static void recv_accept(struct mwServiceResolve *srvc,
+ struct mwChannel *chan,
+ struct mwMsgChannelAccept *msg) {
+
+ g_return_if_fail(srvc != NULL);
+ g_return_if_fail(chan != NULL);
+ g_return_if_fail(chan == srvc->channel);
+
+ mwService_started(MW_SERVICE(srvc));
+}
+
+
+static void recv_destroy(struct mwServiceResolve *srvc,
+ struct mwChannel *chan,
+ struct mwMsgChannelDestroy *msg) {
+
+ struct mwSession *session;
+
+ g_return_if_fail(srvc != NULL);
+ g_return_if_fail(chan != NULL);
+ g_return_if_fail(chan == srvc->channel);
+
+ srvc->channel = NULL;
+ mwService_stop(MW_SERVICE(srvc));
+
+ session = mwService_getSession(MW_SERVICE(srvc));
+ g_return_if_fail(session != NULL);
+
+ mwSession_senseService(session, mwService_getType(MW_SERVICE(srvc)));
+}
+
+
+static GList *load_matches(struct mwGetBuffer *b, guint32 count) {
+ GList *matches = NULL;
+
+ while(count--) {
+ struct mwResolveMatch *m = g_new0(struct mwResolveMatch, 1);
+
+ mwString_get(b, &m->id);
+ mwString_get(b, &m->name);
+ mwString_get(b, &m->desc);
+ guint32_get(b, &m->type);
+
+ matches = g_list_append(matches, m);
+ }
+
+ return matches;
+}
+
+
+static GList *load_results(struct mwGetBuffer *b, guint32 count) {
+ GList *results = NULL;
+
+ while(count--) {
+ struct mwResolveResult *r = g_new0(struct mwResolveResult, 1);
+ guint32 junk, matches;
+
+ guint32_get(b, &junk);
+ guint32_get(b, &r->code);
+ mwString_get(b, &r->name);
+
+ guint32_get(b, &matches);
+ r->matches = load_matches(b, matches);
+
+ results = g_list_append(results, r);
+ }
+
+ return results;
+}
+
+
+static void free_matches(GList *matches) {
+ for(; matches; matches = g_list_delete_link(matches, matches)) {
+ struct mwResolveMatch *m = matches->data;
+ g_free(m->id);
+ g_free(m->name);
+ g_free(m->desc);
+ g_free(m);
+ }
+}
+
+
+static void free_results(GList *results) {
+ for(; results; results = g_list_delete_link(results, results)) {
+ struct mwResolveResult *r = results->data;
+ g_free(r->name);
+ free_matches(r->matches);
+ g_free(r);
+ }
+}
+
+
+static void recv(struct mwServiceResolve *srvc,
+ struct mwChannel *chan,
+ guint16 type, struct mwOpaque *data) {
+
+ struct mwGetBuffer *b;
+ guint32 junk, id, code, count;
+ struct mw_search *search;
+
+ g_return_if_fail(srvc != NULL);
+ g_return_if_fail(chan != NULL);
+ g_return_if_fail(chan == srvc->channel);
+ g_return_if_fail(data != NULL);
+
+ if(type != RESOLVE_ACTION) {
+ mw_mailme_opaque(data, "unknown message in resolve service: 0x%04x", type);
+ return;
+ }
+
+ b = mwGetBuffer_wrap(data);
+ guint32_get(b, &junk);
+ guint32_get(b, &id);
+ guint32_get(b, &code);
+ guint32_get(b, &count);
+
+ if(mwGetBuffer_error(b)) {
+ g_warning("error parsing search result");
+ mwGetBuffer_free(b);
+ return;
+ }
+
+ search = g_hash_table_lookup(srvc->searches, GUINT_TO_POINTER(id));
+
+ if(search) {
+ GList *results = load_results(b, count);
+ if(mwGetBuffer_error(b)) {
+ g_warning("error parsing search results");
+ } else {
+ g_debug("triggering handler");
+ search->handler(srvc, id, code, results, search->data);
+ }
+ free_results(results);
+ g_hash_table_remove(srvc->searches, GUINT_TO_POINTER(id));
+
+ } else {
+ g_debug("no search found: 0x%x", id);
+ }
+
+ mwGetBuffer_free(b);
+}
+
+
+struct mwServiceResolve *mwServiceResolve_new(struct mwSession *session) {
+ struct mwServiceResolve *srvc_resolve;
+ struct mwService *srvc;
+
+ g_return_val_if_fail(session != NULL, NULL);
+
+ srvc_resolve = g_new0(struct mwServiceResolve, 1);
+
+ srvc = MW_SERVICE(srvc_resolve);
+
+ mwService_init(srvc, session, mwService_RESOLVE);
+ srvc->get_name = get_name;
+ srvc->get_desc = get_desc;
+ srvc->recv_create = (mwService_funcRecvCreate) recv_create;
+ srvc->recv_accept = (mwService_funcRecvAccept) recv_accept;
+ srvc->recv_destroy = (mwService_funcRecvDestroy) recv_destroy;
+ srvc->recv = (mwService_funcRecv) recv;
+ srvc->start = (mwService_funcStart) start;
+ srvc->stop = (mwService_funcStop) stop;
+ srvc->clear = (mwService_funcClear) clear;
+
+ return srvc_resolve;
+}
+
+
+guint32 mwServiceResolve_resolve(struct mwServiceResolve *srvc,
+ GList *queries, enum mwResolveFlag flags,
+ mwResolveHandler handler,
+ gpointer data, GDestroyNotify cleanup) {
+
+ struct mw_search *search;
+ struct mwPutBuffer *b;
+ struct mwOpaque o = { 0, 0 };
+ int ret, count = 0;
+
+ g_return_val_if_fail(srvc != NULL, SEARCH_ERROR);
+ g_return_val_if_fail(handler != NULL, SEARCH_ERROR);
+
+ count = g_list_length(queries);
+ g_return_val_if_fail(count > 0, SEARCH_ERROR);
+
+ search = search_new(srvc, handler, data, cleanup);
+
+ b = mwPutBuffer_new();
+ guint32_put(b, 0x00); /* to be overwritten */
+ guint32_put(b, search->id);
+ guint32_put(b, count);
+ for(; queries; queries = queries->next)
+ mwString_put(b, queries->data);
+ guint32_put(b, flags);
+
+ mwPutBuffer_finalize(&o, b);
+
+ ret = mwChannel_send(srvc->channel, RESOLVE_ACTION, &o);
+ if(ret) {
+ search_free(search);
+ return SEARCH_ERROR;
+
+ } else {
+ g_hash_table_insert(srvc->searches,
+ GUINT_TO_POINTER(search->id), search);
+ return search->id;
+ }
+}
+
+
+void mwServiceResolve_cancelResolve(struct mwServiceResolve *srvc,
+ guint32 id) {
+
+ g_return_if_fail(srvc != NULL);
+ g_return_if_fail(srvc->searches != NULL);
+
+ g_hash_table_remove(srvc->searches, GUINT_TO_POINTER(id));
+}
+
+
+/// Miranda NG adaptation start - new method
+struct mwService *mwServiceResolve_getService(struct mwServiceResolve *srvc) {
+ g_return_val_if_fail(srvc != NULL, NULL);
+ return &(srvc->service);
+}
+/// Miranda NG adaptation end
diff --git a/protocols/Sametime/src/meanwhile/src/srvc_store.c b/protocols/Sametime/src/meanwhile/src/srvc_store.c
new file mode 100644
index 0000000000..f537195e08
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/srvc_store.c
@@ -0,0 +1,615 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <glib/glist.h>
+
+#include "mw_channel.h"
+#include "mw_debug.h"
+#include "mw_error.h"
+#include "mw_message.h"
+#include "mw_service.h"
+#include "mw_session.h"
+#include "mw_srvc_store.h"
+
+
+#define PROTOCOL_TYPE 0x00000025
+#define PROTOCOL_VER 0x00000001
+
+
+enum storage_action {
+ action_load = 0x0004,
+ action_loaded = 0x0005,
+ action_save = 0x0006,
+ action_saved = 0x0007,
+};
+
+
+struct mwStorageUnit {
+ /** key by which data is referenced in service
+ @see mwStorageKey */
+ guint32 key;
+
+ /** Data associated with key in service */
+ struct mwOpaque data;
+};
+
+
+struct mwStorageReq {
+ guint32 id; /**< unique id for this request */
+ guint32 result_code; /**< result code for completed request */
+ enum storage_action action; /**< load or save */
+ struct mwStorageUnit *item; /**< the key/data pair */
+ mwStorageCallback cb; /**< callback to notify upon completion */
+ gpointer data; /**< user data to pass with callback */
+ GDestroyNotify data_free; /**< optionally frees user data */
+};
+
+
+struct mwServiceStorage {
+ struct mwService service;
+
+ /** collection of mwStorageReq */
+ GList *pending;
+
+ /** current service channel */
+ struct mwChannel *channel;
+
+ /** keep track of the counter */
+ guint32 id_counter;
+};
+
+
+static void request_get(struct mwGetBuffer *b, struct mwStorageReq *req) {
+ guint32 id, count, junk;
+
+ if(mwGetBuffer_error(b)) return;
+
+ guint32_get(b, &id);
+ guint32_get(b, &req->result_code);
+
+ if(req->action == action_loaded) {
+ guint32_get(b, &count);
+
+ if(count > 0) {
+ guint32_get(b, &junk);
+ guint32_get(b, &req->item->key);
+
+ mwOpaque_clear(&req->item->data);
+ mwOpaque_get(b, &req->item->data);
+ }
+ }
+}
+
+
+static void request_put(struct mwPutBuffer *b, struct mwStorageReq *req) {
+
+ guint32_put(b, req->id);
+ guint32_put(b, 1);
+
+ if(req->action == action_save) {
+ guint32_put(b, 20 + req->item->data.len); /* ugh, offset garbage */
+ guint32_put(b, req->item->key);
+ mwOpaque_put(b, &req->item->data);
+
+ } else {
+ guint32_put(b, req->item->key);
+ }
+}
+
+
+static int request_send(struct mwChannel *chan, struct mwStorageReq *req) {
+ struct mwPutBuffer *b;
+ struct mwOpaque o = { 0, 0 };
+ int ret;
+
+ b = mwPutBuffer_new();
+ request_put(b, req);
+
+ mwPutBuffer_finalize(&o, b);
+ ret = mwChannel_send(chan, req->action, &o);
+ mwOpaque_clear(&o);
+
+ if(! ret) {
+ if(req->action == action_save) {
+ req->action = action_saved;
+ } else if(req->action == action_load) {
+ req->action = action_loaded;
+ }
+ }
+
+ return ret;
+}
+
+
+static struct mwStorageReq *request_find(struct mwServiceStorage *srvc,
+ guint32 id) {
+ GList *l;
+
+ for(l = srvc->pending; l; l = l->next) {
+ struct mwStorageReq *r = l->data;
+ if(r->id == id) return r;
+ }
+
+ return NULL;
+}
+
+
+static const char *action_str(enum storage_action act) {
+ switch(act) {
+ case action_load: return "load";
+ case action_loaded: return "loaded";
+ case action_save: return "save";
+ case action_saved: return "saved";
+ default: return "UNKNOWN";
+ }
+}
+
+
+static void request_trigger(struct mwServiceStorage *srvc,
+ struct mwStorageReq *req) {
+
+ struct mwStorageUnit *item = req->item;
+
+ g_message("storage request %s: key = 0x%x, result = 0x%x, length = %u",
+ action_str(req->action),
+ item->key, req->result_code, (guint) item->data.len);
+
+ if(req->cb)
+ req->cb(srvc, req->result_code, item, req->data);
+}
+
+
+static void request_free(struct mwStorageReq *req) {
+ if(req->data_free) {
+ req->data_free(req->data);
+ req->data = NULL;
+ req->data_free = NULL;
+ }
+
+ mwStorageUnit_free(req->item);
+ g_free(req);
+}
+
+
+static void request_remove(struct mwServiceStorage *srvc,
+ struct mwStorageReq *req) {
+
+ srvc->pending = g_list_remove_all(srvc->pending, req);
+ request_free(req);
+}
+
+
+static const char *get_name(struct mwService *srvc) {
+ return "User Storage";
+}
+
+
+static const char *get_desc(struct mwService *srvc) {
+ return "Stores user data and settings on the server";
+}
+
+
+static struct mwChannel *make_channel(struct mwServiceStorage *srvc) {
+ struct mwSession *session;
+ struct mwChannelSet *cs;
+ struct mwChannel *chan;
+
+ session = mwService_getSession(MW_SERVICE(srvc));
+ cs = mwSession_getChannels(session);
+ chan = mwChannel_newOutgoing(cs);
+
+ mwChannel_setService(chan, MW_SERVICE(srvc));
+ mwChannel_setProtoType(chan, PROTOCOL_TYPE);
+ mwChannel_setProtoVer(chan, PROTOCOL_VER);
+
+ return mwChannel_create(chan)? NULL: chan;
+}
+
+
+static void start(struct mwService *srvc) {
+ struct mwServiceStorage *srvc_store;
+ struct mwChannel *chan;
+
+ g_return_if_fail(srvc != NULL);
+ srvc_store = (struct mwServiceStorage *) srvc;
+
+ chan = make_channel(srvc_store);
+ if(chan) {
+ srvc_store->channel = chan;
+ } else {
+ mwService_stopped(srvc);
+ }
+}
+
+
+static void stop(struct mwService *srvc) {
+
+ struct mwServiceStorage *srvc_store;
+ GList *l;
+
+ g_return_if_fail(srvc != NULL);
+ srvc_store = (struct mwServiceStorage *) srvc;
+
+ if(srvc_store->channel) {
+ mwChannel_destroy(srvc_store->channel, ERR_SUCCESS, NULL);
+ srvc_store->channel = NULL;
+ }
+
+#if 1
+ /* the new way */
+ /* remove pending requests. Sometimes we can crash the storage
+ service, and when that happens, we end up resending the killer
+ request over and over again, and the service never stays up */
+ for(l = srvc_store->pending; l; l = l->next)
+ request_free(l->data);
+
+ g_list_free(srvc_store->pending);
+ srvc_store->pending = NULL;
+
+ srvc_store->id_counter = 0;
+
+#else
+ /* the old way */
+ /* reset all of the started requests to their unstarted states */
+ for(l = srvc_store->pending; l; l = l->next) {
+ struct mwStorageReq *req = l->data;
+
+ if(req->action == action_loaded) {
+ req->action = action_load;
+ } else if(req->action == action_saved) {
+ req->action = action_save;
+ }
+ }
+#endif
+
+ mwService_stopped(srvc);
+}
+
+
+static void recv_channelAccept(struct mwService *srvc,
+ struct mwChannel *chan,
+ struct mwMsgChannelAccept *msg) {
+
+ struct mwServiceStorage *srvc_stor;
+ GList *l;
+
+ g_return_if_fail(srvc != NULL);
+ srvc_stor = (struct mwServiceStorage *) srvc;
+
+ g_return_if_fail(chan != NULL);
+ g_return_if_fail(chan == srvc_stor->channel);
+
+ /* send all pending requests */
+ for(l = srvc_stor->pending; l; l = l->next) {
+ struct mwStorageReq *req = l->data;
+
+ if(req->action == action_save || req->action == action_load) {
+ request_send(chan, req);
+ }
+ }
+
+ mwService_started(srvc);
+}
+
+
+static void recv_channelDestroy(struct mwService *srvc,
+ struct mwChannel *chan,
+ struct mwMsgChannelDestroy *msg) {
+
+ struct mwSession *session;
+ struct mwServiceStorage *srvc_stor;
+
+ g_return_if_fail(srvc != NULL);
+ g_return_if_fail(chan != NULL);
+
+ session = mwService_getSession(srvc);
+ g_return_if_fail(session != NULL);
+
+ srvc_stor = (struct mwServiceStorage *) srvc;
+ srvc_stor->channel = NULL;
+
+ mwService_stop(srvc);
+ mwSession_senseService(session, mwService_getType(srvc));
+}
+
+
+static void recv(struct mwService *srvc, struct mwChannel *chan,
+ guint16 type, struct mwOpaque *data) {
+
+ /* process into results, trigger callbacks */
+
+ struct mwGetBuffer *b;
+ struct mwServiceStorage *srvc_stor;
+ struct mwStorageReq *req;
+ guint32 id;
+
+ g_return_if_fail(srvc != NULL);
+ srvc_stor = (struct mwServiceStorage *) srvc;
+
+ g_return_if_fail(chan != NULL);
+ g_return_if_fail(chan == srvc_stor->channel);
+ g_return_if_fail(data != NULL);
+
+ b = mwGetBuffer_wrap(data);
+
+ id = guint32_peek(b);
+ req = request_find(srvc_stor, id);
+
+ if(! req) {
+ g_warning("couldn't find request 0x%x in storage service", id);
+ mwGetBuffer_free(b);
+ return;
+ }
+
+ g_return_if_fail(req->action == type);
+ request_get(b, req);
+
+ if(mwGetBuffer_error(b)) {
+ mw_mailme_opaque(data, "storage request 0x%x, type: 0x%x", id, type);
+
+ } else {
+ request_trigger(srvc_stor, req);
+ }
+
+ mwGetBuffer_free(b);
+ request_remove(srvc_stor, req);
+}
+
+
+static void clear(struct mwService *srvc) {
+ struct mwServiceStorage *srvc_stor;
+ GList *l;
+
+ srvc_stor = (struct mwServiceStorage *) srvc;
+
+ for(l = srvc_stor->pending; l; l = l->next)
+ request_free(l->data);
+
+ g_list_free(srvc_stor->pending);
+ srvc_stor->pending = NULL;
+
+ srvc_stor->id_counter = 0;
+}
+
+
+struct mwServiceStorage *mwServiceStorage_new(struct mwSession *session) {
+ struct mwServiceStorage *srvc_store;
+ struct mwService *srvc;
+
+ srvc_store = g_new0(struct mwServiceStorage, 1);
+ srvc = MW_SERVICE(srvc_store);
+
+ mwService_init(srvc, session, mwService_STORAGE);
+ srvc->get_name = get_name;
+ srvc->get_desc = get_desc;
+ srvc->recv_accept = recv_channelAccept;
+ srvc->recv_destroy = recv_channelDestroy;
+ srvc->recv = recv;
+ srvc->start = start;
+ srvc->stop = stop;
+ srvc->clear = clear;
+
+ return srvc_store;
+}
+
+
+struct mwStorageUnit *mwStorageUnit_new(guint32 key) {
+ struct mwStorageUnit *u;
+
+ u = g_new0(struct mwStorageUnit, 1);
+ u->key = key;
+
+ return u;
+}
+
+
+struct mwStorageUnit *mwStorageUnit_newOpaque(guint32 key,
+ struct mwOpaque *data) {
+ struct mwStorageUnit *u;
+
+ u = g_new0(struct mwStorageUnit, 1);
+ u->key = key;
+
+ if(data)
+ mwOpaque_clone(&u->data, data);
+
+ return u;
+}
+
+
+struct mwStorageUnit *mwStorageUnit_newBoolean(guint32 key,
+ gboolean val) {
+
+ return mwStorageUnit_newInteger(key, (guint32) val);
+}
+
+
+struct mwStorageUnit *mwStorageUnit_newInteger(guint32 key,
+ guint32 val) {
+ struct mwStorageUnit *u;
+ struct mwPutBuffer *b;
+
+ u = g_new0(struct mwStorageUnit, 1);
+ u->key = key;
+
+ b = mwPutBuffer_new();
+ guint32_put(b, val);
+ mwPutBuffer_finalize(&u->data, b);
+
+ return u;
+}
+
+
+struct mwStorageUnit *mwStorageUnit_newString(guint32 key,
+ const char *str) {
+ struct mwStorageUnit *u;
+ struct mwPutBuffer *b;
+
+ u = g_new0(struct mwStorageUnit, 1);
+ u->key = key;
+
+ b = mwPutBuffer_new();
+ mwString_put(b, str);
+ mwPutBuffer_finalize(&u->data, b);
+
+ return u;
+}
+
+
+guint32 mwStorageUnit_getKey(struct mwStorageUnit *item) {
+ g_return_val_if_fail(item != NULL, 0x00); /* feh, unsafe */
+ return item->key;
+}
+
+
+gboolean mwStorageUnit_asBoolean(struct mwStorageUnit *item,
+ gboolean val) {
+
+ return !! mwStorageUnit_asInteger(item, (guint32) val);
+}
+
+
+guint32 mwStorageUnit_asInteger(struct mwStorageUnit *item,
+ guint32 val) {
+ struct mwGetBuffer *b;
+ guint32 v;
+
+ g_return_val_if_fail(item != NULL, val);
+
+ b = mwGetBuffer_wrap(&item->data);
+
+ guint32_get(b, &v);
+ if(! mwGetBuffer_error(b)) val = v;
+ mwGetBuffer_free(b);
+
+ return val;
+}
+
+
+char *mwStorageUnit_asString(struct mwStorageUnit *item) {
+ struct mwGetBuffer *b;
+ char *c = NULL;
+
+ g_return_val_if_fail(item != NULL, NULL);
+
+ b = mwGetBuffer_wrap(&item->data);
+
+ mwString_get(b, &c);
+
+ if(mwGetBuffer_error(b))
+ g_debug("error obtaining string value from opaque");
+
+ mwGetBuffer_free(b);
+
+ return c;
+}
+
+
+struct mwOpaque *mwStorageUnit_asOpaque(struct mwStorageUnit *item) {
+ g_return_val_if_fail(item != NULL, NULL);
+ return &item->data;
+}
+
+
+void mwStorageUnit_free(struct mwStorageUnit *item) {
+ if(! item) return;
+
+ mwOpaque_clear(&item->data);
+ g_free(item);
+}
+
+
+static struct mwStorageReq *request_new(struct mwServiceStorage *srvc,
+ struct mwStorageUnit *item,
+ mwStorageCallback cb,
+ gpointer data, GDestroyNotify df) {
+
+ struct mwStorageReq *req = g_new0(struct mwStorageReq, 1);
+
+ req->id = ++srvc->id_counter;
+ req->item = item;
+ req->cb = cb;
+ req->data = data;
+ req->data_free = df;
+
+ return req;
+}
+
+
+void mwServiceStorage_load(struct mwServiceStorage *srvc,
+ struct mwStorageUnit *item,
+ mwStorageCallback cb,
+ gpointer data, GDestroyNotify d_free) {
+
+ /* - construct a request
+ - put request at end of pending
+ - if channel is open and connected
+ - compose the load message
+ - send message
+ - set request to sent
+ - else
+ - start service
+ */
+
+ struct mwStorageReq *req;
+
+ req = request_new(srvc, item, cb, data, d_free);
+ req->action = action_load;
+
+ srvc->pending = g_list_append(srvc->pending, req);
+
+ if(MW_SERVICE_IS_STARTED(MW_SERVICE(srvc)))
+ request_send(srvc->channel, req);
+}
+
+
+void mwServiceStorage_save(struct mwServiceStorage *srvc,
+ struct mwStorageUnit *item,
+ mwStorageCallback cb,
+ gpointer data, GDestroyNotify d_free) {
+
+ /* - construct a request
+ - put request at end of pending
+ - if channel is open and connected
+ - compose the save message
+ - send message
+ - set request to sent
+ - else
+ - start service
+ */
+
+ struct mwStorageReq *req;
+
+ req = request_new(srvc, item, cb, data, d_free);
+ req->action = action_save;
+
+ srvc->pending = g_list_append(srvc->pending, req);
+
+ if(MW_SERVICE_IS_STARTED(MW_SERVICE(srvc)))
+ request_send(srvc->channel, req);
+}
+
+
+/// Miranda NG adaptation start - new method
+struct mwService *mwServiceStorage_getService(struct mwServiceStorage *srvc) {
+ g_return_val_if_fail(srvc != NULL, NULL);
+ return &(srvc->service);
+}
+/// Miranda NG adaptation end
diff --git a/protocols/Sametime/src/meanwhile/src/st_list.c b/protocols/Sametime/src/meanwhile/src/st_list.c
new file mode 100644
index 0000000000..949696a4a1
--- /dev/null
+++ b/protocols/Sametime/src/meanwhile/src/st_list.c
@@ -0,0 +1,668 @@
+
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <glib/gstring.h>
+
+#include "mw_debug.h"
+#include "mw_util.h"
+#include "mw_st_list.h"
+
+
+struct mwSametimeList {
+ guint ver_major;
+ guint ver_minor;
+ guint ver_micro;
+
+ GList *groups;
+};
+
+
+struct mwSametimeGroup {
+ struct mwSametimeList *list;
+
+ enum mwSametimeGroupType type;
+ char *name;
+ char *alias;
+ gboolean open;
+
+ GList *users;
+};
+
+
+struct mwSametimeUser {
+ struct mwSametimeGroup *group;
+
+ enum mwSametimeUserType type;
+ struct mwIdBlock id;
+ char *name;
+ char *alias;
+};
+
+
+static void user_free(struct mwSametimeUser *u) {
+ struct mwSametimeGroup *g;
+
+ g = u->group;
+ g->users = g_list_remove(g->users, u);
+
+ mwIdBlock_clear(&u->id);
+ g_free(u->name);
+ g_free(u->alias);
+ g_free(u);
+}
+
+
+static void group_free(struct mwSametimeGroup *g) {
+ struct mwSametimeList *l;
+
+ l = g->list;
+ l->groups = g_list_remove(l->groups, g);
+
+ while(g->users)
+ mwSametimeUser_free(g->users->data);
+
+ g_free(g->name);
+ g_free(g->alias);
+ g_free(g);
+}
+
+
+static void list_free(struct mwSametimeList *l) {
+ while(l->groups)
+ mwSametimeGroup_free(l->groups->data);
+
+ g_free(l);
+}
+
+
+struct mwSametimeList *
+mwSametimeList_new() {
+
+ struct mwSametimeList *stl;
+
+ stl = g_new0(struct mwSametimeList, 1);
+ stl->ver_major = ST_LIST_MAJOR;
+ stl->ver_minor = ST_LIST_MINOR;
+ stl->ver_micro = ST_LIST_MICRO;
+
+ return stl;
+}
+
+
+void mwSametimeList_setMajor(struct mwSametimeList *l, guint v) {
+ g_return_if_fail(l != NULL);
+ l->ver_major = v;
+}
+
+
+guint mwSametimeList_getMajor(struct mwSametimeList *l) {
+ g_return_val_if_fail(l != NULL, 0);
+ return l->ver_major;
+}
+
+
+void mwSametimeList_setMinor(struct mwSametimeList *l, guint v) {
+ g_return_if_fail(l != NULL);
+ l->ver_minor = v;
+}
+
+
+guint mwSametimeList_getMinor(struct mwSametimeList *l) {
+ g_return_val_if_fail(l != NULL, 0);
+ return l->ver_minor;
+}
+
+
+void mwSametimeList_setMicro(struct mwSametimeList *l, guint v) {
+ g_return_if_fail(l != NULL);
+ l->ver_micro = v;
+}
+
+
+guint mwSametimeList_getMicro(struct mwSametimeList *l) {
+ g_return_val_if_fail(l != NULL, 0);
+ return l->ver_micro;
+}
+
+
+GList *mwSametimeList_getGroups(struct mwSametimeList *l) {
+ g_return_val_if_fail(l != NULL, NULL);
+ return g_list_copy(l->groups);
+}
+
+
+struct mwSametimeGroup *
+mwSametimeList_findGroup(struct mwSametimeList *l,
+ const char *name) {
+ GList *s;
+
+ g_return_val_if_fail(l != NULL, NULL);
+ g_return_val_if_fail(name != NULL, NULL);
+ g_return_val_if_fail(*name != '\0', NULL);
+
+ for(s = l->groups; s; s = s->next) {
+ struct mwSametimeGroup *g = s->data;
+ if(! strcmp(g->name, name)) return g;
+ }
+
+ return NULL;
+}
+
+
+void mwSametimeList_free(struct mwSametimeList *l) {
+ g_return_if_fail(l != NULL);
+ list_free(l);
+}
+
+
+struct mwSametimeGroup *
+mwSametimeGroup_new(struct mwSametimeList *list,
+ enum mwSametimeGroupType type,
+ const char *name) {
+
+ struct mwSametimeGroup *stg;
+
+ g_return_val_if_fail(list != NULL, NULL);
+ g_return_val_if_fail(name != NULL, NULL);
+ g_return_val_if_fail(*name != '\0', NULL);
+
+ stg = g_new0(struct mwSametimeGroup, 1);
+ stg->list = list;
+ stg->type = type;
+ stg->name = g_strdup(name);
+
+ list->groups = g_list_append(list->groups, stg);
+
+ return stg;
+}
+
+
+enum mwSametimeGroupType mwSametimeGroup_getType(struct mwSametimeGroup *g) {
+ g_return_val_if_fail(g != NULL, mwSametimeGroup_UNKNOWN);
+ return g->type;
+}
+
+
+const char *mwSametimeGroup_getName(struct mwSametimeGroup *g) {
+ g_return_val_if_fail(g != NULL, NULL);
+ return g->name;
+}
+
+
+void mwSametimeGroup_setAlias(struct mwSametimeGroup *g,
+ const char *alias) {
+ g_return_if_fail(g != NULL);
+
+ g_free(g->alias);
+ g->alias = g_strdup(alias);
+}
+
+
+const char *mwSametimeGroup_getAlias(struct mwSametimeGroup *g) {
+ g_return_val_if_fail(g != NULL, NULL);
+ return g->alias;
+}
+
+
+void mwSametimeGroup_setOpen(struct mwSametimeGroup *g, gboolean open) {
+ g_return_if_fail(g != NULL);
+ g->open = open;
+}
+
+
+gboolean mwSametimeGroup_isOpen(struct mwSametimeGroup *g) {
+ g_return_val_if_fail(g != NULL, FALSE);
+ return g->open;
+}
+
+
+struct mwSametimeList *mwSametimeGroup_getList(struct mwSametimeGroup *g) {
+ g_return_val_if_fail(g != NULL, NULL);
+ return g->list;
+}
+
+
+GList *mwSametimeGroup_getUsers(struct mwSametimeGroup *g) {
+ g_return_val_if_fail(g != NULL, NULL);
+ return g_list_copy(g->users);
+}
+
+
+struct mwSametimeUser *
+mwSametimeGroup_findUser(struct mwSametimeGroup *g,
+ struct mwIdBlock *user) {
+ GList *s;
+
+ g_return_val_if_fail(g != NULL, NULL);
+ g_return_val_if_fail(user != NULL, NULL);
+
+ for(s = g->users; s; s = s->next) {
+ struct mwSametimeUser *u = s->data;
+ if(mwIdBlock_equal(user, &u->id)) return u;
+ }
+
+ return NULL;
+}
+
+
+void mwSametimeGroup_free(struct mwSametimeGroup *g) {
+ g_return_if_fail(g != NULL);
+ g_return_if_fail(g->list != NULL);
+ group_free(g);
+}
+
+
+struct mwSametimeUser *
+mwSametimeUser_new(struct mwSametimeGroup *group,
+ enum mwSametimeUserType type,
+ struct mwIdBlock *id) {
+
+ struct mwSametimeUser *stu;
+
+ g_return_val_if_fail(group != NULL, NULL);
+ g_return_val_if_fail(id != NULL, NULL);
+
+ stu = g_new0(struct mwSametimeUser, 1);
+ stu->group = group;
+ stu->type = type;
+ mwIdBlock_clone(&stu->id, id);
+
+ group->users = g_list_append(group->users, stu);
+
+ return stu;
+}
+
+
+struct mwSametimeGroup *mwSametimeUser_getGroup(struct mwSametimeUser *u) {
+ g_return_val_if_fail(u != NULL, NULL);
+ return u->group;
+}
+
+
+enum mwSametimeUserType mwSametimeUser_getType(struct mwSametimeUser *u) {
+ g_return_val_if_fail(u != NULL, mwSametimeUser_UNKNOWN);
+ return u->type;
+}
+
+
+const char *mwSametimeUser_getUser(struct mwSametimeUser *u) {
+ g_return_val_if_fail(u != NULL, NULL);
+ return u->id.user;
+}
+
+
+const char *mwSametimeUser_getCommunity(struct mwSametimeUser *u) {
+ g_return_val_if_fail(u != NULL, NULL);
+ return u->id.community;
+}
+
+
+void mwSametimeUser_setShortName(struct mwSametimeUser *u, const char *name) {
+ g_return_if_fail(u != NULL);
+ g_free(u->name);
+ u->name = g_strdup(name);
+}
+
+
+const char *mwSametimeUser_getShortName(struct mwSametimeUser *u) {
+ g_return_val_if_fail(u != NULL, NULL);
+ return u->name;
+}
+
+
+void mwSametimeUser_setAlias(struct mwSametimeUser *u, const char *alias) {
+ g_return_if_fail(u != NULL);
+ g_free(u->alias);
+ u->alias = g_strdup(alias);
+}
+
+
+const char *mwSametimeUser_getAlias(struct mwSametimeUser *u) {
+ g_return_val_if_fail(u != NULL, NULL);
+ return u->alias;
+}
+
+
+void mwSametimeUser_free(struct mwSametimeUser *u) {
+ g_return_if_fail(u != NULL);
+ g_return_if_fail(u->group != NULL);
+ user_free(u);
+}
+
+
+static void str_replace(char *str, char from, char to) {
+ if(! str) return;
+ for(; *str; str++) if(*str == from) *str = to;
+}
+
+
+static char user_type_to_char(enum mwSametimeUserType type) {
+ switch(type) {
+ case mwSametimeUser_NORMAL: return '1';
+ case mwSametimeUser_EXTERNAL: return '2';
+ case mwSametimeUser_UNKNOWN:
+ default: return '9';
+ }
+}
+
+
+static enum mwSametimeUserType user_char_to_type(char type) {
+ switch(type) {
+ case '1': return mwSametimeUser_NORMAL;
+ case '2': return mwSametimeUser_EXTERNAL;
+ default: return mwSametimeUser_UNKNOWN;
+ }
+}
+
+
+static void user_put(GString *str, struct mwSametimeUser *u) {
+ char *id, *name, *alias;
+ char type;
+
+ id = g_strdup(u->id.user);
+ name = g_strdup(u->name);
+ alias = g_strdup(u->alias);
+ type = user_type_to_char(u->type);
+
+ if(id) str_replace(id, ' ', ';');
+ if(name) str_replace(name, ' ', ';');
+ if(alias) str_replace(alias, ' ', ';');
+
+ if(!name && alias) {
+ name = alias;
+ alias = NULL;
+ }
+
+ g_string_append_printf(str, "U %s%c:: %s,%s\r\n",
+ id, type, (name? name: ""), (alias? alias: ""));
+
+ g_free(id);
+ g_free(name);
+ g_free(alias);
+}
+
+
+static char group_type_to_char(enum mwSametimeGroupType type) {
+ switch(type) {
+ case mwSametimeGroup_NORMAL: return '2';
+ case mwSametimeGroup_DYNAMIC: return '3';
+ case mwSametimeGroup_UNKNOWN:
+ default: return '9';
+ }
+}
+
+
+static enum mwSametimeGroupType group_char_to_type(char type) {
+ switch(type) {
+ case '2': return mwSametimeGroup_NORMAL;
+ case '3': return mwSametimeGroup_DYNAMIC;
+ default: return mwSametimeGroup_UNKNOWN;
+ }
+}
+
+
+static void group_put(GString *str, struct mwSametimeGroup *g) {
+ char *name, *alias;
+ char type;
+ GList *gl;
+
+ name = g_strdup(g->name);
+ alias = g_strdup((g->alias)? g->alias: name);
+ type = group_type_to_char(g->type);
+
+ str_replace(name, ' ', ';');
+ str_replace(alias, ' ', ';');
+
+ g_string_append_printf(str, "G %s%c %s %c\r\n",
+ name, type, alias, (g->open? 'O':'C'));
+
+ for(gl = g->users; gl; gl = gl->next) {
+ user_put(str, gl->data);
+ }
+
+ g_free(name);
+ g_free(alias);
+}
+
+
+/** composes a GString with the written contents of a sametime list */
+static GString *list_store(struct mwSametimeList *l) {
+ GString *str;
+ GList *gl;
+
+ g_return_val_if_fail(l != NULL, NULL);
+
+ str = g_string_new(NULL);
+ g_string_append_printf(str, "Version=%u.%u.%u\r\n",
+ l->ver_major, l->ver_minor, l->ver_micro);
+
+ for(gl = l->groups; gl; gl = gl->next) {
+ group_put(str, gl->data);
+ }
+
+ return str;
+}
+
+
+char *mwSametimeList_store(struct mwSametimeList *l) {
+ GString *str;
+ char *s;
+
+ g_return_val_if_fail(l != NULL, NULL);
+
+ str = list_store(l);
+ s = str->str;
+ g_string_free(str, FALSE);
+ return s;
+}
+
+
+void mwSametimeList_put(struct mwPutBuffer *b, struct mwSametimeList *l) {
+ GString *str;
+ guint16 len;
+
+ g_return_if_fail(l != NULL);
+ g_return_if_fail(b != NULL);
+
+ str = list_store(l);
+ len = (guint16) str->len;
+ guint16_put(b, len);
+ mwPutBuffer_write(b, str->str, len);
+
+ g_string_free(str, TRUE);
+}
+
+
+static void get_version(const char *line, struct mwSametimeList *l) {
+ guint major = 0, minor = 0, micro = 0;
+ int ret;
+
+ ret = sscanf(line, "Version=%u.%u.%u\n", &major, &minor, &micro);
+ if(ret != 3) {
+ g_warning("strange sametime list version line:\n%s", line);
+ }
+
+ l->ver_major = major;
+ l->ver_minor = minor;
+ l->ver_micro = micro;
+}
+
+
+static struct mwSametimeGroup *get_group(const char *line,
+ struct mwSametimeList *l) {
+ struct mwSametimeGroup *group;
+ char *name, *alias;
+ char type = '2', open = 'O';
+ int ret;
+
+ ret = strlen(line);
+ name = g_malloc0(ret);
+ alias = g_malloc0(ret);
+
+ ret = sscanf(line, "G %s %s %c\n",
+ name, alias, &open);
+
+ if(ret < 3) {
+ g_warning("strange sametime list group line:\n%s", line);
+ }
+
+ str_replace(name, ';', ' ');
+ str_replace(alias, ';', ' ');
+
+ if(name && *name) {
+ int l = strlen(name)-1;
+ type = name[l];
+ name[l] = '\0';
+ }
+
+ group = g_new0(struct mwSametimeGroup, 1);
+ group->list = l;
+ group->name = name;
+ group->type = group_char_to_type(type);
+ group->alias = alias;
+ group->open = (open == 'O');
+
+ l->groups = g_list_append(l->groups, group);
+
+ return group;
+}
+
+
+static void get_user(const char *line, struct mwSametimeGroup *g) {
+ struct mwSametimeUser *user;
+ struct mwIdBlock idb = { 0, 0 };
+ char *name, *alias = NULL;
+ char type = '1';
+ int ret;
+
+ ret = strlen(line);
+ idb.user = g_malloc0(ret);
+ name = g_malloc0(ret);
+
+ ret = sscanf(line, "U %s %s",
+ idb.user, name);
+
+ if(ret < 2) {
+ g_warning("strange sametime list user line:\n%s", line);
+ }
+
+ str_replace(idb.user, ';', ' ');
+ str_replace(name, ';', ' ');
+
+ if(idb.user && *idb.user) {
+ char *tmp = strstr(idb.user, "::");
+ if(tmp--) {
+ type = *(tmp);
+ *tmp = '\0';
+ }
+ }
+
+ if(name && *name) {
+ char *tmp = strrchr(name, ',');
+ if(tmp) {
+ *tmp++ = '\0';
+ if(*tmp) alias = tmp;
+ }
+ }
+
+ user = g_new0(struct mwSametimeUser, 1);
+ user->group = g;
+ user->id.user = idb.user;
+ user->type = user_char_to_type(type);
+ user->name = name;
+ user->alias = g_strdup(alias);
+
+ g->users = g_list_append(g->users, user);
+}
+
+
+/** returns a line from str, and advances str */
+static char *fetch_line(char **str) {
+ char *start = *str;
+ char *end;
+
+ /* move to first non-whitespace character */
+ while(*start && g_ascii_isspace(*start)) start++;
+ if(! *start) return NULL;
+
+ for(end = start + 1; *end; end++) {
+ if(*end == '\n' || *end == '\r') {
+ *(end++) = '\0';
+ break;
+ }
+ }
+
+ *str = end;
+ return start;
+}
+
+
+static void list_get(const char *lines, struct mwSametimeList *l) {
+ char *s = (char *) lines;
+ char *line;
+
+ struct mwSametimeGroup *g = NULL;
+
+ while( (line = fetch_line(&s)) ) {
+ switch(*line) {
+ case 'V':
+ get_version(line, l);
+ break;
+
+ case 'G':
+ g = get_group(line, l);
+ break;
+
+ case 'U':
+ get_user(line, g);
+ break;
+
+ default:
+ g_warning("unknown sametime list data line:\n%s", line);
+ }
+ }
+}
+
+
+struct mwSametimeList *mwSametimeList_load(const char *data) {
+ struct mwSametimeList *l;
+
+ g_return_val_if_fail(data != NULL, NULL);
+
+ l = mwSametimeList_new();
+ list_get(data, l);
+
+ return l;
+}
+
+
+void mwSametimeList_get(struct mwGetBuffer *b, struct mwSametimeList *l) {
+ char *str = NULL;
+
+ g_return_if_fail(l != NULL);
+ g_return_if_fail(b != NULL);
+
+ mwString_get(b, &str);
+ list_get(str, l);
+ g_free(str);
+}
+
diff --git a/protocols/Sametime/src/messaging.cpp b/protocols/Sametime/src/messaging.cpp
new file mode 100644
index 0000000000..58cc83b600
--- /dev/null
+++ b/protocols/Sametime/src/messaging.cpp
@@ -0,0 +1,222 @@
+#include "StdAfx.h"
+#include "sametime.h"
+
+
+CSametimeProto* getProtoFromMwConversation(mwConversation* conv)
+{
+ mwServiceIm* serviceIM = mwConversation_getService(conv);
+ mwService* service = mwServiceIm_getService(serviceIM);
+ mwSession* session = mwService_getSession(service);
+ return (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
+}
+
+
+void mwIm_conversation_opened(mwConversation* conv)
+{
+ CSametimeProto* proto = getProtoFromMwConversation(conv);
+ proto->debugLog(_T("mwIm_conversation_opened() start"));
+
+ mwIdBlock* idb = mwConversation_getTarget(conv);
+ MCONTACT hContact = proto->FindContactByUserId(idb->user);
+
+ if (!hContact) {
+ proto->debugLog(_T("mwIm_conversation_opened() !hContact"));
+ mwSametimeList* user_list = mwSametimeList_new();
+ mwSametimeGroup* stgroup = mwSametimeGroup_new(user_list, mwSametimeGroup_NORMAL, Translate("None"));
+ mwSametimeUser* stuser = mwSametimeUser_new(stgroup, mwSametimeUser_NORMAL, idb);
+
+ proto->AddContact(stuser, (proto->options.add_contacts ? false : true));
+ proto->GetMoreDetails(idb->user);
+ }
+
+ ContactMessageQueue::iterator i;
+ EnterCriticalSection(&proto->q_cs);
+ if ((i = proto->contact_message_queue.find(hContact)) != proto->contact_message_queue.end()) {
+ while(i->second.size()) {
+ mwConversation_send(conv, mwImSend_PLAIN, (gconstpointer)i->second.front().c_str());
+ i->second.pop();
+ }
+ proto->contact_message_queue.erase(i);
+ }
+ LeaveCriticalSection(&proto->q_cs);
+
+ // gives linker error 'unresolved external symbol' :( So instead we will either add ciphers to the session or not (see session.cpp)
+ //mwConversation_setEncrypted(conv, options.encrypt_session);
+}
+
+/** A conversation has been closed */
+void mwIm_conversation_closed(mwConversation* conv, guint32 err)
+{
+ CSametimeProto* proto = getProtoFromMwConversation(conv);
+ proto->debugLog(_T("mwIm_conversation_closed() start err=[%d]"),err);
+
+ if (err & ERR_FAILURE && err != CONNECTION_RESET) {
+ char* msg = mwError(err);
+ proto->showPopup(TranslateTS(_A2T(msg)), SAMETIME_POPUP_ERROR);
+ g_free(msg);
+ if (err == ERR_NO_COMMON_ENCRYPT && !(proto->options.encrypt_session)) {
+ proto->showPopup(TranslateT("No common encryption method. Try to enable encryption in protocol options."), SAMETIME_POPUP_INFO);
+ }
+ }
+
+ mwIdBlock* idb = mwConversation_getTarget(conv);
+ MCONTACT hContact = proto->FindContactByUserId(idb->user);
+ if (hContact) {
+ ContactMessageQueue::iterator i;
+ EnterCriticalSection(&proto->q_cs);
+ if ((i = proto->contact_message_queue.find(hContact)) != proto->contact_message_queue.end()) {
+ proto->contact_message_queue.erase(i);
+ }
+ LeaveCriticalSection(&proto->q_cs);
+ }
+}
+
+/** A message has been received on a conversation */
+void mwIm_conversation_recv(mwConversation* conv, mwImSendType type, gconstpointer msg)
+{
+ CSametimeProto* proto = getProtoFromMwConversation(conv);
+ proto->debugLog(_T("mwIm_conversation_recv() start"));
+
+ mwIdBlock* idb = mwConversation_getTarget(conv);
+ MCONTACT hContact = proto->FindContactByUserId(idb->user);
+ proto->debugLog(_T("mwIm_conversation_recv() type=[%d] hContact=[%x]"), type, hContact);
+
+ if (type == mwImSend_TYPING) {
+ CallService(MS_PROTO_CONTACTISTYPING, hContact, (LPARAM)(GPOINTER_TO_UINT(msg) == 0 ? 0 : 2));
+ return;
+ }
+
+ if (type != mwImSend_PLAIN) return;
+
+ PROTORECVEVENT pre = {0};
+ time_t t = time(NULL);
+ pre.timestamp = t;
+ pre.flags = PREF_UTF;
+ pre.szMessage = (char*)msg;
+ ProtoChainRecvMsg(hContact, &pre);
+
+}
+
+
+void mwIm_place_invite(struct mwConversation* conv, const char* message, const char* title, const char* name)
+{
+ CSametimeProto* proto = getProtoFromMwConversation(conv);
+ proto->debugLog(_T("mwIm_place_invite() start"));
+
+ ///TODO unimplemented
+
+ TCHAR* tszMessage = mir_utf8decodeT(message);
+
+ TCHAR msg[512];
+ mir_sntprintf(msg, SIZEOF(msg), TranslateT("SERVICE UNIMPLEMENTED. %s"), tszMessage);
+ proto->showPopup(msg, SAMETIME_POPUP_INFO);
+
+ mir_free(tszMessage);
+}
+
+
+mwImHandler mwIm_handler = {
+ mwIm_conversation_opened,
+ mwIm_conversation_closed,
+ mwIm_conversation_recv,
+ mwIm_place_invite,
+ NULL
+};
+
+
+HANDLE CSametimeProto::SendMessageToUser(MCONTACT hContact, char* msg_utf8)
+{
+ debugLog(_T("CSametimeProto::SendMessageToUser() hContact=[%x]"), hContact);
+
+ mwAwareIdBlock id_block;
+ if (GetAwareIdFromContact(hContact, &id_block)) {
+
+ mwIdBlock idb;
+ idb.user = id_block.user;
+ idb.community = id_block.community;
+
+ mwConversation* conv = mwServiceIm_getConversation(service_im, &idb);
+ if (conv) {
+ if (!mwConversation_isOpen(conv)) {
+ debugLog(_T("CSametimeProto::SendMessageToUser() mwConversation_isOpen"));
+ EnterCriticalSection(&q_cs);
+ contact_message_queue[hContact].push(msg_utf8);
+ LeaveCriticalSection(&q_cs);
+ mwConversation_open(conv);
+ } else {
+ debugLog(_T("CSametimeProto::SendMessageToUser() !mwConversation_isOpen"));
+ mwConversation_send(conv, mwImSend_PLAIN, (gconstpointer)msg_utf8);
+ }
+
+ free(id_block.user);
+ return (HANDLE)conv;
+ }
+
+ free(id_block.user);
+ }
+
+ return 0;
+}
+
+
+void CSametimeProto::SendTyping(MCONTACT hContact, bool typing)
+{
+ debugLog(_T("CSametimeProto::SendTyping() hContact=[%x] type=[%d]"), hContact, typing);
+
+ mwAwareIdBlock id_block;
+ if (GetAwareIdFromContact(hContact, &id_block)) {
+ mwIdBlock idb;
+ idb.user = id_block.user;
+ idb.community = id_block.community;
+
+ mwConversation* conv = mwServiceIm_getConversation(service_im, &idb);
+ if (conv) {
+ if (mwConversation_isOpen(conv)){
+ debugLog(_T("CSametimeProto::SendTyping() send"));
+ mwConversation_send(conv, mwImSend_TYPING, (gconstpointer)GUINT_TO_POINTER(typing ? 1 : 0));
+ }
+ }
+
+ free(id_block.user);
+ }
+}
+
+
+void CSametimeProto::CloseIm(MCONTACT hContact)
+{
+ debugLog(_T("CSametimeProto::CloseIm() hContact=[%x]"), hContact);
+
+ mwAwareIdBlock id_block;
+ if (GetAwareIdFromContact(hContact, &id_block)) {
+ mwIdBlock idb;
+ idb.user = id_block.user;
+ idb.community = id_block.community;
+
+ mwConversation* conv = mwServiceIm_getConversation(service_im, &idb);
+ if (conv) {
+ if (mwConversation_isOpen(conv)){
+ debugLog(_T("CSametimeProto::CloseIm() mwConversation_close"));
+ mwConversation_close(conv, 0);
+ }
+ }
+ free(id_block.user);
+ }
+}
+
+void CSametimeProto::InitMessaging()
+{
+ debugLog(_T("CSametimeProto::InitMessaging()"));
+ InitializeCriticalSection(&q_cs);
+ mwSession_addService(session, (mwService*)(service_im = mwServiceIm_new(session, &mwIm_handler)));
+ mwServiceIm_setClientType(service_im, mwImClient_PLAIN);
+}
+
+void CSametimeProto::DeinitMessaging()
+{
+ debugLog(_T("CSametimeProto::DeinitMessaging()"));
+ mwSession_removeService(session, mwService_IM);
+ mwService_free((mwService*)service_im);
+ service_im = 0;
+ DeleteCriticalSection(&q_cs);
+}
+
diff --git a/protocols/Sametime/src/options.cpp b/protocols/Sametime/src/options.cpp
new file mode 100644
index 0000000000..d882233f48
--- /dev/null
+++ b/protocols/Sametime/src/options.cpp
@@ -0,0 +1,369 @@
+#include "StdAfx.h"
+#include "sametime.h"
+
+
+#define DEFAULT_ID (0x1800)
+
+#define NUM_IDS 20
+TCHAR* client_names[NUM_IDS] = {
+ _T("Official Binary Library"),
+ _T("Official Java Applet"),
+ _T("Official Binary Application"),
+ _T("Official Java Application"),
+ _T("Notes v6.5"),
+ _T("Notes v7.0"),
+ _T("ICT"),
+ _T("NotesBuddy"),
+ _T("NotesBuddy v4.15"),
+ _T("Sanity"),
+ _T("Perl"),
+ _T("PMR Alert"),
+ _T("Trillian (SourceForge)"),
+ _T("Trillian (IBM)"),
+ _T("Meanwhile Library"),
+ _T("Meanwhile (Python)"),
+ _T("Meanwhile (Gaim)"),
+ _T("Meanwhile (Adium)"),
+ _T("Meanwhile (Kopete)"),
+ _T("Custom")
+};
+int client_ids[NUM_IDS] = {
+ 0x1000,
+ 0x1001,
+ 0x1002,
+ 0x1003,
+ 0x1200,
+ 0x1210,
+ 0x1300,
+ 0x1400,
+ 0x1405,
+ 0x1600,
+ 0x1625,
+ 0x1650,
+ 0x16aa,
+ 0x16bb,
+ 0x1700,
+ 0x1701,
+ 0x1702,
+ 0x1703,
+ 0x1704,
+ 0xFFFF
+};
+
+
+static INT_PTR CALLBACK DlgProcOptNet(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ CSametimeProto* proto = (CSametimeProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ switch ( msg ) {
+ case WM_INITDIALOG: {
+
+ TranslateDialogDefault(hwndDlg);
+
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
+ proto = (CSametimeProto*)lParam;
+
+ {
+ TCHAR verbuf[100];
+ WORD client_ver = proto->GetClientVersion();
+ WORD server_ver = proto->GetServerVersion();
+ if (client_ver)
+ mir_sntprintf(verbuf, SIZEOF(verbuf), _T("Client proto version: %03d.%03d"), (client_ver & 0xFF00) >> 8, client_ver & 0xFF);
+ else
+ mir_sntprintf(verbuf, SIZEOF(verbuf), _T("Disconnected"));
+ SetDlgItemText(hwndDlg, IDC_ST_CLIENTVER, verbuf);
+ if (server_ver)
+ mir_sntprintf(verbuf, SIZEOF(verbuf), _T("Server proto version: %03d.%03d"), (server_ver & 0xFF00) >> 8, server_ver & 0xFF);
+ else
+ mir_sntprintf(verbuf, SIZEOF(verbuf), _T("Disconnected"));
+ SetDlgItemText(hwndDlg, IDC_ST_SERVERVER, verbuf);
+ }
+
+ TCHAR* s;
+ s = mir_utf8decodeT(proto->options.server_name); SetDlgItemText(hwndDlg, IDC_ED_SNAME, s); mir_free(s);
+ s = mir_utf8decodeT(proto->options.id); SetDlgItemText(hwndDlg, IDC_ED_NAME, s); mir_free(s);
+ s = mir_utf8decodeT(proto->options.pword); SetDlgItemText(hwndDlg, IDC_ED_PWORD, s); mir_free(s);
+
+ SetDlgItemInt(hwndDlg, IDC_ED_PORT, proto->options.port, FALSE);
+ CheckDlgButton(hwndDlg, IDC_CHK_GETSERVERCONTACTS, proto->options.get_server_contacts ? TRUE : FALSE);
+ CheckDlgButton(hwndDlg, IDC_CHK_ADDCONTACTS, proto->options.add_contacts ? TRUE : FALSE);
+ CheckDlgButton(hwndDlg, IDC_CHK_IDLEAWAY, proto->options.idle_as_away ? TRUE : FALSE);
+ CheckDlgButton(hwndDlg, IDC_CHK_OLDDEFAULTVER, proto->options.use_old_default_client_ver ? TRUE : FALSE);
+
+ SendDlgItemMessage(hwndDlg, IDC_CMB_CLIENT, CB_RESETCONTENT, 0, 0);
+ int pos = 0;
+ bool found = false;
+
+ for (int i = 0; i < NUM_IDS; i++) {
+ pos = SendDlgItemMessage(hwndDlg, IDC_CMB_CLIENT, CB_ADDSTRING, -1, (LPARAM)client_names[i]);
+ SendDlgItemMessage(hwndDlg, IDC_CMB_CLIENT, CB_SETITEMDATA, pos, client_ids[i]);
+ if (client_ids[i] == proto->options.client_id) {
+ found = true;
+ SendDlgItemMessage(hwndDlg, IDC_CMB_CLIENT, CB_SETCURSEL, pos, 0);
+ SetDlgItemInt(hwndDlg, IDC_ED_CLIENTID, client_ids[i], FALSE);
+ if (i != sizeof(client_ids) / sizeof(int) - 1) {
+ HWND hw = GetDlgItem(hwndDlg, IDC_ED_CLIENTID);
+ EnableWindow(hw, false);
+ }
+ }
+ }
+
+ if (!found) {
+ SendDlgItemMessage(hwndDlg, IDC_CMB_CLIENT, CB_SETCURSEL, pos, 0); // pos is last item, i.e. custom
+ SetDlgItemInt(hwndDlg, IDC_ED_CLIENTID, proto->options.client_id, FALSE);
+ }
+
+ if (!ServiceExists(MS_POPUP_ADDPOPUP)) {
+ HWND hw = GetDlgItem(hwndDlg, IDC_RAD_ERRPOP);
+ EnableWindow(hw, FALSE);
+ }
+
+ if (!ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) {
+ HWND hw = GetDlgItem(hwndDlg, IDC_RAD_ERRBAL);
+ EnableWindow(hw, FALSE);
+ }
+
+ switch (proto->options.err_method) {
+ case ED_POP: CheckDlgButton(hwndDlg, IDC_RAD_ERRPOP, TRUE); break;
+ case ED_MB: CheckDlgButton(hwndDlg, IDC_RAD_ERRMB, TRUE); break;
+ case ED_BAL: CheckDlgButton(hwndDlg, IDC_RAD_ERRBAL, TRUE); break;
+ }
+
+ if (proto->options.encrypt_session)
+ CheckDlgButton(hwndDlg, IDC_RAD_ENC, TRUE);
+ else
+ CheckDlgButton(hwndDlg, IDC_RAD_NOENC, TRUE);
+
+ return FALSE;
+ }
+
+ case WM_COMMAND:
+ if (HIWORD(wParam) == EN_CHANGE && (HWND)lParam == GetFocus()) {
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ if (HIWORD(wParam) == CBN_SELCHANGE) {
+ int sel = SendDlgItemMessage(hwndDlg, IDC_CMB_CLIENT, CB_GETCURSEL, 0, 0);
+ int id = SendDlgItemMessage(hwndDlg, IDC_CMB_CLIENT, CB_GETITEMDATA, sel, 0);
+ bool custom = (id == client_ids[sizeof(client_ids) / sizeof(int) - 1]);
+
+ if (!custom)
+ SetDlgItemInt(hwndDlg, IDC_ED_CLIENTID, id, FALSE);
+ else
+ SetDlgItemInt(hwndDlg, IDC_ED_CLIENTID, DEFAULT_ID, FALSE);
+
+ HWND hw = GetDlgItem(hwndDlg, IDC_ED_CLIENTID);
+ EnableWindow(hw, custom);
+
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+
+ if (HIWORD(wParam) == BN_CLICKED ) {
+ switch (LOWORD(wParam)) {
+ case IDC_BTN_UPLOADCONTACTS:
+ {
+ HWND hBut = GetDlgItem(hwndDlg, IDC_BTN_UPLOADCONTACTS);
+ EnableWindow(hBut, FALSE);
+ hBut = GetDlgItem(hwndDlg, IDC_BTN_IMPORTCONTACTS);
+ EnableWindow(hBut, FALSE);
+
+ proto->ExportContactsToServer();
+
+ SendMessage(hwndDlg, WMU_STORECOMPLETE, 0, 0);
+ }
+ return TRUE;
+ case IDC_BTN_IMPORTCONTACTS:
+ {
+ OPENFILENAME ofn = {0};
+ TCHAR import_filename[MAX_PATH];
+ import_filename[0] = 0;
+
+ ofn.lStructSize = sizeof(ofn);
+ ofn.lpstrFile = import_filename;
+ ofn.hwndOwner = hwndDlg;
+ ofn.Flags = CC_FULLOPEN;
+ ofn.nMaxFile = MAX_PATH;
+ ofn.lpstrFilter = _T("All\0*.*\0");
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFileTitle = NULL;
+ ofn.nMaxFileTitle = 0;
+ ofn.lpstrInitialDir = NULL;
+ ofn.Flags = OFN_PATHMUSTEXIST;
+
+ if (GetOpenFileName(&ofn) == TRUE) {
+ HWND hBut = GetDlgItem(hwndDlg, IDC_BTN_UPLOADCONTACTS);
+ EnableWindow(hBut, FALSE);
+ hBut = GetDlgItem(hwndDlg, IDC_BTN_IMPORTCONTACTS);
+ EnableWindow(hBut, FALSE);
+
+ proto->ImportContactsFromFile(ofn.lpstrFile);
+
+ SendMessage(hwndDlg, WMU_STORECOMPLETE, 0, 0);
+ }
+ }
+ return TRUE;
+ case IDC_CHK_GETSERVERCONTACTS:
+ case IDC_CHK_ENCMESSAGES:
+ case IDC_RAD_ERRMB:
+ case IDC_RAD_ERRBAL:
+ case IDC_RAD_ERRPOP:
+ case IDC_CHK_USERCP:
+ case IDC_CHK_ADDCONTACTS:
+ case IDC_CHK_IDLEAWAY:
+ case IDC_CHK_OLDDEFAULTVER:
+ case IDC_RAD_ENC:
+ case IDC_RAD_NOENC:
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ return TRUE;
+ case IDC_RAD_ANSI:
+ case IDC_RAD_UTF8:
+ case IDC_RAD_OEM:
+ case IDC_RAD_UTF7:
+ case IDC_RAD_USERCP:
+ {
+ HWND hw = GetDlgItem(hwndDlg, IDC_CHK_USERCP);
+ EnableWindow(hw, !IsDlgButtonChecked(hwndDlg, IDC_RAD_USERCP));
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ return TRUE;
+ }
+ }
+ break;
+
+ case WMU_STORECOMPLETE:
+ {
+ HWND hBut = GetDlgItem(hwndDlg, IDC_BTN_UPLOADCONTACTS);
+ EnableWindow(hBut, TRUE);
+ hBut = GetDlgItem(hwndDlg, IDC_BTN_IMPORTCONTACTS);
+ EnableWindow(hBut, TRUE);
+ }
+ return TRUE;
+
+ case WM_NOTIFY:
+ if (((LPNMHDR)lParam)->code == PSN_APPLY) {
+ TCHAR ws[2048];
+ char* utf;
+
+ GetDlgItemText(hwndDlg, IDC_ED_SNAME, ws, LSTRINGLEN);
+ strcpy(proto->options.server_name, utf = mir_utf8encodeT(ws)); mir_free(utf);
+ GetDlgItemText(hwndDlg, IDC_ED_NAME, ws, LSTRINGLEN);
+ strcpy(proto->options.id, utf = mir_utf8encodeT(ws)); mir_free(utf);
+ GetDlgItemText(hwndDlg, IDC_ED_PWORD, ws, LSTRINGLEN);
+ strcpy(proto->options.pword, utf = mir_utf8encodeT(ws)); mir_free(utf);
+
+ BOOL translated;
+ int port = GetDlgItemInt(hwndDlg, IDC_ED_PORT, &translated, FALSE);
+ if (translated)
+ proto->options.port = port;
+
+ proto->options.get_server_contacts = (IsDlgButtonChecked(hwndDlg, IDC_CHK_GETSERVERCONTACTS) != FALSE);
+
+ int sel = SendDlgItemMessage(hwndDlg, IDC_CMB_CLIENT, CB_GETCURSEL, 0, 0);
+ int id = SendDlgItemMessage(hwndDlg, IDC_CMB_CLIENT, CB_GETITEMDATA, sel, 0);
+
+ if (id == client_ids[sizeof(client_ids) / sizeof(int) - 1]) {
+ BOOL trans;
+ id = GetDlgItemInt(hwndDlg, IDC_ED_CLIENTID, &trans, FALSE);
+ if (trans)
+ proto->options.client_id = id;
+ } else
+ proto->options.client_id = id;
+
+ if (IsDlgButtonChecked(hwndDlg, IDC_RAD_ERRMB)) proto->options.err_method = ED_MB;
+ else if (IsDlgButtonChecked(hwndDlg, IDC_RAD_ERRBAL)) proto->options.err_method = ED_BAL;
+ else if (IsDlgButtonChecked(hwndDlg, IDC_RAD_ERRPOP)) proto->options.err_method = ED_POP;
+
+ proto->options.add_contacts = (IsDlgButtonChecked(hwndDlg, IDC_CHK_ADDCONTACTS) != FALSE);
+ proto->options.encrypt_session = (IsDlgButtonChecked(hwndDlg, IDC_RAD_ENC) != FALSE);
+ proto->options.idle_as_away = (IsDlgButtonChecked(hwndDlg, IDC_CHK_IDLEAWAY) != FALSE);
+
+ proto->options.use_old_default_client_ver = (IsDlgButtonChecked(hwndDlg, IDC_CHK_OLDDEFAULTVER) != FALSE);
+
+ proto->SaveOptions();
+
+ return TRUE;
+ }
+ break;
+
+ case WM_DESTROY:
+ break;
+ }
+
+ return FALSE;
+}
+
+int CSametimeProto::OptInit(WPARAM wParam, LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = { sizeof(odp) };
+ odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR;
+ odp.hInstance = hInst;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTNET);
+ odp.ptszTitle = m_tszUserName;
+ odp.ptszGroup = LPGENT("Network");
+ odp.pfnDlgProc = DlgProcOptNet;
+ odp.dwInitParam = (LPARAM)this;
+ Options_AddPage(wParam, &odp);
+ return 0;
+}
+
+void CSametimeProto::LoadOptions()
+{
+ DBVARIANT dbv;
+
+ if (!db_get_utf(0, m_szModuleName, "ServerName", &dbv)) {
+ strncpy(options.server_name, dbv.pszVal, LSTRINGLEN);
+ db_free(&dbv);
+ }
+ if (!db_get_utf(0, m_szModuleName, "stid", &dbv)) {
+ strncpy(options.id, dbv.pszVal, LSTRINGLEN);
+ db_free(&dbv);
+ }
+ if (!db_get_utf(0, m_szModuleName, "Password", &dbv)) {
+ strncpy(options.pword, dbv.pszVal, LSTRINGLEN);
+ db_free(&dbv);
+ }
+
+ options.port = db_get_dw(0, m_szModuleName, "ServerPort", DEFAULT_PORT);
+ options.encrypt_session = (db_get_b(0, m_szModuleName, "EncryptSession", 0) == 1);
+
+ options.client_id = db_get_dw(0, m_szModuleName, "ClientID", DEFAULT_ID);
+ options.use_old_default_client_ver = (db_get_b(0, m_szModuleName, "UseOldClientVer", 0) == 1);
+
+ options.get_server_contacts = (db_get_b(0, m_szModuleName, "GetServerContacts", 1) == 1);
+ options.add_contacts = (db_get_b(0, m_szModuleName, "AutoAddContacts", 0) == 1);
+ options.idle_as_away = (db_get_b(0, m_szModuleName, "IdleAsAway", 1) == 1);
+
+ // if popups not installed, will be changed to 'ED_BAL' (balloons) in main.cpp, modules loaded
+ options.err_method = (ErrorDisplay)db_get_b(0, m_szModuleName, "ErrorDisplay", ED_POP);
+ // funny logic :) ... try to avoid message boxes
+ // if want baloons but no balloons, try popups
+ // if want popups but no popups, try baloons
+ // if, after that, you want balloons but no balloons, revert to message boxes
+ if (options.err_method == ED_BAL && !ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) options.err_method = ED_POP;
+ if (options.err_method == ED_POP && !ServiceExists(MS_POPUP_SHOWMESSAGE)) options.err_method = ED_BAL;
+ if (options.err_method == ED_BAL && !ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) options.err_method = ED_MB;
+
+ debugLog(_T("LoadOptions() loaded: ServerName:len=[%d], id:len=[%d], pword:len=[%d]"), options.server_name == NULL ? -1 : strlen(options.server_name), options.id == NULL ? -1 : strlen(options.id), options.pword == NULL ? -1 : strlen(options.pword));
+ debugLog(_T("LoadOptions() loaded: port=[%d], encrypt_session=[%d], client_id=[%d], use_old_default_client_ver=[%d]"), options.port, options.encrypt_session, options.client_id, options.use_old_default_client_ver);
+ debugLog(_T("LoadOptions() loaded: get_server_contacts=[%d], add_contacts=[%d], idle_as_away=[%d], err_method=[%d]"), options.get_server_contacts, options.add_contacts, options.idle_as_away, options.err_method);
+
+}
+
+void CSametimeProto::SaveOptions()
+{
+ db_set_utf(0, m_szModuleName, "ServerName", options.server_name);
+
+ db_set_utf(0, m_szModuleName, "stid", options.id);
+ //db_set_s(0, m_szModuleName, "Nick", options.id);
+ db_set_utf(0, m_szModuleName, "Password", options.pword);
+
+ db_set_dw(0, m_szModuleName, "ServerPort", options.port);
+ db_set_b(0, m_szModuleName, "GetServerContacts", options.get_server_contacts ? 1 : 0);
+ db_set_dw(0, m_szModuleName, "ClientID", options.client_id);
+ db_set_b(0, m_szModuleName, "ErrorDisplay", options.err_method);
+
+ db_set_b(0, m_szModuleName, "AutoAddContacts", options.add_contacts ? 1 : 0);
+ db_set_b(0, m_szModuleName, "EncryptSession", options.encrypt_session ? 1 : 0);
+ db_set_b(0, m_szModuleName, "IdleAsAway", options.idle_as_away ? 1 : 0);
+
+ db_set_b(0, m_szModuleName, "UseOldClientVer", options.use_old_default_client_ver ? 1 : 0);
+}
diff --git a/protocols/Sametime/src/places.cpp b/protocols/Sametime/src/places.cpp
new file mode 100644
index 0000000000..c7c0a19adf
--- /dev/null
+++ b/protocols/Sametime/src/places.cpp
@@ -0,0 +1,67 @@
+#include "StdAfx.h"
+#include "sametime.h"
+
+/* Stubs, NOT IMPLEMENTED NOW */
+
+void mwServicePlace_opened(struct mwPlace* place)
+{
+}
+
+void mwServicePlace_closed(struct mwPlace* place, guint32 code)
+{
+}
+
+void mwServicePlace_peerJoined(struct mwPlace* place, const struct mwIdBlock* peer)
+{
+}
+
+
+void mwServicePlace_peerParted(struct mwPlace* place, const struct mwIdBlock* peer)
+{
+}
+
+
+void mwServicePlace_peerSetAttribute(struct mwPlace* place, const struct mwIdBlock* peer, guint32 attr, struct mwOpaque* o)
+{
+}
+
+
+void mwServicePlace_peerUnsetAttribute(struct mwPlace* place, const struct mwIdBlock* peer, guint32 attr)
+{
+}
+
+
+void mwServicePlace_message(struct mwPlace* place, const struct mwIdBlock* who, const char* msg)
+{
+}
+
+
+void mwServicePlace_clear(struct mwServicePlace* srvc)
+{
+}
+
+
+mwPlaceHandler mwPlace_handler = {
+ mwServicePlace_opened,
+ mwServicePlace_closed,
+ mwServicePlace_peerJoined,
+ mwServicePlace_peerParted,
+ mwServicePlace_peerSetAttribute,
+ mwServicePlace_peerUnsetAttribute,
+ mwServicePlace_message,
+ mwServicePlace_clear
+};
+
+void CSametimeProto::InitPlaces(mwSession* session)
+{
+ debugLog(_T("CSametimeProto::InitPlaces()"));
+ mwSession_addService(session, (mwService*)(service_places = mwServicePlace_new(session, &mwPlace_handler)));
+}
+
+void CSametimeProto::DeinitPlaces(mwSession* session)
+{
+ debugLog(_T("CSametimeProto::DeinitPlaces()"));
+ mwSession_removeService(session, mwService_PLACE);
+ mwService_free((mwService*)service_places);
+ service_places = 0;
+}
diff --git a/protocols/Sametime/src/resource.h b/protocols/Sametime/src/resource.h
new file mode 100644
index 0000000000..3ca8cba566
--- /dev/null
+++ b/protocols/Sametime/src/resource.h
@@ -0,0 +1,59 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by resource.rc
+//
+#define IDD_DIALOG1 101
+#define IDD_OPTNET 101
+#define IDI_ICON_PROTO 102
+#define IDI_ICON_LEAVE 104
+#define IDI_ICON_INVITE 105
+#define IDI_ICON_ANNOUNCE 107
+#define IDI_ICON_NOTIFY 108
+#define IDI_ICON_ERROR 109
+#define IDD_SESSIONANNOUNCE 208
+#define IDD_USERSEARCH 209
+#define IDC_ED_SNAME 1000
+#define IDC_ED_NAME 1001
+#define IDC_ED_PWORD 1002
+#define IDC_ED_PORT 1003
+#define IDC_CHK_GETSERVERCONTACTS 1004
+#define IDC_BTN_UPLOADCONTACTS 1005
+#define IDC_CHK_ENCMESSAGES 1006
+#define IDC_BTN_IMPORTCONTACTS 1007
+#define IDC_CHK_UTF8 1008
+#define IDC_CHK_ADDCONTACTS 1008
+#define IDC_CHK_IDLEAWAY 1009
+#define IDC_CMB_CLIENT 1010
+#define IDC_ED_CLIENTID 1011
+#define IDC_RAD_ERRMB 1012
+#define IDC_RAD_ERRPOP 1013
+#define IDC_RAD_ERRBAL 1014
+#define IDC_RAD_ANSI 1015
+#define IDC_CHK_OLDDEFAULTVER 1016
+#define IDC_RAD_UTF8 1017
+#define IDC_CHK_USERCP 1018
+#define IDC_RAD_OEM 1019
+#define IDC_RAD_ENC 1020
+#define IDC_RAD_UTF7 1021
+#define IDC_RAD_NOENC 1022
+#define IDC_RAD_ANSI2 1023
+#define IDC_RAD_USERCP 1024
+#define IDC_ED_ANMSG 1025
+#define IDC_LST_ANTO 1026
+#define IDC_BUT_SELALL 1027
+#define IDC_BUT_SELINV 1028
+#define IDC_ST_CLIENTVER 1029
+#define IDC_ST_SERVERVER 1030
+#define IDC_EDIT1 1031
+#define IDC_ST_LIBVER 1032
+
+// 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 1033
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/protocols/Sametime/src/sametime.cpp b/protocols/Sametime/src/sametime.cpp
new file mode 100644
index 0000000000..5cec8f873a
--- /dev/null
+++ b/protocols/Sametime/src/sametime.cpp
@@ -0,0 +1,296 @@
+#include "StdAfx.h"
+#include "sametime.h"
+#include "version.h"
+
+// plugin stuff
+PLUGININFOEX pluginInfo={
+ sizeof(PLUGININFOEX),
+ __PLUGIN_NAME,
+ PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
+ __DESCRIPTION,
+ __AUTHOR,
+ __AUTHOREMAIL,
+ __COPYRIGHT,
+ __AUTHORWEB,
+ UNICODE_AWARE,
+ { 0xf1b0ba1b, 0xc91, 0x4313, { 0x85, 0xeb, 0x22, 0x50, 0x69, 0xd4, 0x4d, 0x1 } } // {F1B0BA1B-0C91-4313-85EB-225069D44D01}
+};
+
+
+HINSTANCE hInst;
+LIST<CSametimeProto> g_Instances(1, PtrKeySortT);
+int hLangpack;
+
+
+// sametime.cpp: Defines the entry point for the DLL application.
+extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ hInst = hinstDLL;
+ return TRUE;
+}
+
+extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion)
+{
+ return &pluginInfo;
+}
+
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_PROTOCOL, MIID_LAST};
+
+
+
+// protocol related services
+
+
+/** Copy the name of the protocole into lParam
+* @param wParam : max size of the name
+* @param lParam : reference to a char *, which will hold the name
+*/
+INT_PTR CSametimeProto::GetName(WPARAM wParam, LPARAM lParam)
+{
+ strncpy((char*)lParam, m_szModuleName, wParam);
+ return 0;
+}
+
+/*
+ * Returns the current status
+ */
+INT_PTR CSametimeProto::GetStatus(WPARAM wParam, LPARAM lParam)
+{
+ return m_iStatus;
+}
+
+
+/** Loads the icon corresponding to the status
+* Called by the CList when the status changes.
+* @param wParam : one of the following values : \n
+ <tt>PLI_PROTOCOL | PLI_ONLINE | PLI_OFFLINE</tt>
+* @return an \c HICON in which the icon has been loaded.
+*/
+INT_PTR CSametimeProto::SametimeLoadIcon(WPARAM wParam, LPARAM lParam)
+{
+
+ UINT id;
+ switch (wParam & 0xFFFF)
+ {
+ case PLI_PROTOCOL:
+ id = IDI_ICON_PROTO;
+ break;
+ default:
+ return (int) (HICON) NULL;
+ }
+
+ 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);
+ return 0;
+}
+
+
+//icolib stuff
+static IconItem iconList[] =
+{
+ { LPGEN("Protocol icon"), "protoicon", IDI_ICON_PROTO, 0 }
+ , { LPGEN("Start Conference"), "leaveconference", IDI_ICON_INVITE, 0 }
+ , { LPGEN("Leave Conference"), "startconference", IDI_ICON_LEAVE, 0 }
+ , { LPGEN("Announce"), "announce", IDI_ICON_ANNOUNCE, 0 }
+ , { LPGEN("Notification"), "notify", IDI_ICON_NOTIFY, 0 }
+ , { LPGEN("Error"), "error", IDI_ICON_ERROR, 0 }
+};
+
+void SametimeInitIcons(void)
+{
+ Icon_Register(hInst, "Protocols/Sametime", iconList, SIZEOF(iconList), "SAMETIME");
+}
+
+HANDLE GetIconHandle(int iconId)
+{
+ for (int i = 0; i < SIZEOF(iconList); i++)
+ if (iconList[i].defIconID == iconId)
+ return iconList[i].hIcolib;
+ return NULL;
+}
+
+HICON LoadIconEx(const char* name, BOOL big)
+{
+ char szSettingName[100];
+ mir_snprintf(szSettingName, sizeof(szSettingName), "%s_%s", "SAMETIME", name);
+ return Skin_GetIcon(szSettingName, big);
+}
+
+void ReleaseIconEx(const char* name, BOOL big)
+{
+ char szSettingName[100];
+ mir_snprintf(szSettingName, sizeof(szSettingName), "%s_%s", "SAMETIME", name);
+ Skin_ReleaseIcon(szSettingName, big);
+}
+
+
+// Copied from MSN plugin - sent acks need to be from different thread
+void __cdecl sttFakeAckInfoSuccessThread(void* param)
+{
+ TFakeAckParams* tParam = (TFakeAckParams*)param;
+ CSametimeProto* proto = tParam->proto;
+ proto->debugLog(_T("sttFakeAckInfoSuccessThread() start"));
+
+ Sleep(100);
+ proto->ProtoBroadcastAck(tParam->hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE)1, 0);
+
+ proto->debugLog(_T("sttFakeAckInfoSuccessThread() end"));
+ mir_free(tParam);
+ return;
+}
+
+void __cdecl sttFakeAckMessageSuccessThread(void* param)
+{
+ TFakeAckParams* tParam = (TFakeAckParams*)param;
+ CSametimeProto* proto = tParam->proto;
+ proto->debugLog(_T("sttFakeAckMessageSuccessThread() start"));
+
+ Sleep(100);
+ proto->ProtoBroadcastAck(tParam->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)tParam->lParam, 0 );
+
+ proto->debugLog(_T("sttFakeAckMessageSuccessThread() end"));
+ mir_free(tParam);
+ return;
+}
+
+void __cdecl sttFakeAckMessageFailedThread(void* param)
+{
+ TFakeAckParams* tParam = (TFakeAckParams*)param;
+ CSametimeProto* proto = tParam->proto;
+ proto->debugLog(_T("sttFakeAckMessageFailedThread() start"));
+
+ Sleep(100);
+ proto->ProtoBroadcastAck(tParam->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, NULL, tParam->lParam); ///TODO tParam->lParam: add error message
+
+ proto->debugLog(_T("sttFakeAckMessageFailedThread() end"));
+ mir_free(tParam);
+ return;
+}
+
+void __cdecl sttRecvAwayThread(void* param)
+{
+ TFakeAckParams* tParam = (TFakeAckParams*)param;
+ CSametimeProto* proto = tParam->proto;
+ proto->debugLog(_T("sttRecvAwayThread() start"));
+
+ Sleep(100);
+ proto->UserRecvAwayMessage(tParam->hContact);
+
+ proto->debugLog(_T("sttRecvAwayThread() end"));
+ free(tParam);
+ return;
+}
+
+
+int CSametimeProto::OnWindowEvent(WPARAM wParam, LPARAM lParam)
+{
+ MessageWindowEventData* mwed = (MessageWindowEventData*)lParam;
+
+ if (db_get_b(mwed->hContact, m_szModuleName, "ChatRoom", 0))
+ return 0;
+
+ if (mwed && (mwed->uType == MSG_WINDOW_EVT_CLOSING || mwed->uType == MSG_WINDOW_EVT_CLOSE))
+ CloseIm(mwed->hContact);
+
+ return 0;
+}
+
+int CSametimeProto::OnIdleChanged(WPARAM wParam, LPARAM lParam)
+{
+ if (!(lParam & IDF_PRIVACY)) {
+ is_idle = lParam & IDF_ISIDLE ? true : false;
+ SetIdle(is_idle);
+ }
+
+ return 0;
+}
+
+
+int CSametimeProto::OnPreShutdown(WPARAM wParam, LPARAM lParam)
+{
+ if (m_iStatus != ID_STATUS_OFFLINE){
+ LogOut();
+ }
+
+ return 0;
+}
+
+
+int CSametimeProto::OnSametimeContactDeleted(WPARAM wParam, LPARAM lParam)
+{
+ MCONTACT hContact = wParam;
+ ContactDeleted(hContact);
+ ChatDeleted(hContact);
+ return 0;
+}
+
+
+void CSametimeProto::SetAllOffline()
+{
+ debugLog(_T("SetAllOffline() start"));
+
+ for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName)) {
+ if (db_get_b(hContact, m_szModuleName, "ChatRoom", 0)) {
+ CallService(MS_DB_CONTACT_DELETE, (WPARAM)hContact, 0);
+ continue;
+ } else {
+ db_set_w(hContact, m_szModuleName, "Status", ID_STATUS_OFFLINE);
+ db_set_dw(hContact, m_szModuleName, "IdleTS", 0);
+ }
+ }
+
+}
+
+
+void CSametimeProto::BroadcastNewStatus(int iNewStatus)
+{
+ if (m_iStatus == iNewStatus){
+ return;
+ }
+
+ debugLog(_T("BroadcastNewStatus() m_iStatus=[%d], iNewStatus=[%d]"), m_iStatus, iNewStatus);
+
+ previous_status = m_iStatus;
+ m_iStatus = iNewStatus;
+ ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)previous_status, m_iStatus);
+}
+
+
+static CSametimeProto* sametime_proto_init(const char* pszProtoName, const TCHAR* tszUserName)
+{
+ CSametimeProto* proto = new CSametimeProto(pszProtoName, tszUserName);
+ g_Instances.insert(proto);
+ return proto;
+}
+
+static int sametime_proto_uninit(PROTO_INTERFACE* ppro)
+{
+ CSametimeProto* proto = (CSametimeProto*)ppro;
+ g_Instances.remove(proto);
+ delete proto;
+ return 0;
+}
+
+extern "C" int __declspec(dllexport) Load(void)
+{
+
+ PROTOCOLDESCRIPTOR pd = { sizeof(pd) };
+ pd.type = PROTOTYPE_PROTOCOL;
+ pd.szName = "Sametime";
+ pd.fnInit = (pfnInitProto)sametime_proto_init;
+ pd.fnUninit = (pfnUninitProto)sametime_proto_uninit;
+ CallService(MS_PROTO_REGISTERMODULE, 0, (LPARAM)&pd);
+
+ return 0;
+}
+
+extern "C" int __declspec(dllexport) Unload()
+{
+
+ g_Instances.destroy();
+
+ return 0;
+
+}
+
diff --git a/protocols/Sametime/src/sametime.h b/protocols/Sametime/src/sametime.h
new file mode 100644
index 0000000000..7554a5d78d
--- /dev/null
+++ b/protocols/Sametime/src/sametime.h
@@ -0,0 +1,121 @@
+#ifndef _SAMETIME_H
+#define _SAMETIME_H
+
+
+//sametime defines
+
+#define FILE_BUFF_SIZE (1024 * 32)
+
+#define MS_SAMETIME_MENULEAVECHAT "/LeaveChat"
+#define MS_SAMETIME_MENUCREATECHAT "/CreateChat"
+
+#define MAX_MESSAGE_SIZE (10 * 1024) // verified limit in official client, thx Periferral
+
+#define LSTRINGLEN 256
+
+#define DEFAULT_PORT 1533
+
+#define WMU_STORECOMPLETE (WM_USER + 110)
+
+
+
+typedef enum {SAMETIME_POPUP_ERROR = 1, SAMETIME_POPUP_INFO = 2 } SametimePopupEnum;
+typedef enum {ED_MB = 1, ED_POP = 2, ED_BAL = 3} ErrorDisplay;
+typedef enum {CPT_USER, CPT_ANSI, CPT_UTF8, CPT_OEM, CPT_UTF7} CodePageType;
+
+
+
+//stl typedef's
+typedef std::queue<std::string> InviteQueue; ///for conference.cpp
+typedef std::queue<std::string> MessageQueue; ///for messaging.cpp
+typedef std::map<MCONTACT, MessageQueue> ContactMessageQueue; ///for messaging.cpp
+
+
+//protocol includes
+#include "resource.h"
+
+
+//methods
+INT_PTR CALLBACK SessionAnnounceDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK CALLBACK SearchDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+void mwResolve_handler_callback(mwServiceResolve* srvc, guint32 id, guint32 code, GList* results, gpointer data);
+
+void SametimeInitIcons(void);
+HANDLE GetIconHandle(int iconId);
+HICON LoadIconEx(const char* name, BOOL big);
+void ReleaseIconEx(const char* name, BOOL big);
+
+
+// services (async thread functions)
+void __cdecl sttFakeAckInfoSuccessThread(void* param);
+void __cdecl sttFakeAckMessageFailedThread(void* param);
+void __cdecl sttFakeAckMessageSuccessThread(void* param);
+void __cdecl sttRecvAwayThread(void* param);
+
+
+//sametime structs
+
+typedef struct Options_tag {
+ char server_name[LSTRINGLEN]; // utf8
+ char id[LSTRINGLEN]; // utf8
+ char pword[LSTRINGLEN]; // utf8
+ int port;
+ bool get_server_contacts;
+ int client_id;
+ ErrorDisplay err_method;
+ bool add_contacts;
+ bool encrypt_session;
+ bool idle_as_away;
+ bool use_old_default_client_ver;
+} SametimeOptions;
+
+typedef struct {
+ int cbSize;
+ char* nick;
+ char* firstName;
+ char* lastName;
+ char* email;
+ char reserved[16];
+ char name[256];
+ char stid[256];
+ bool group;
+} MYPROTOSEARCHRESULT;
+
+typedef struct {
+ size_t nSize;
+ int nFieldCount;
+ TCHAR** pszFields;
+ MYPROTOSEARCHRESULT psr;
+} MYCUSTOMSEARCHRESULTS;
+
+typedef struct FileTransferClientData_tag {
+ char* save_path;
+ HANDLE hFile;
+ bool sending;
+ MCONTACT hContact;
+ struct FileTransferClientData_tag* first;
+ struct FileTransferClientData_tag* next;
+ HANDLE hFt;
+ char* buffer;
+ int ft_number;
+ int ft_count; // number of nodes in list - only valid in first node
+ int totalSize; // total for all files in the list - only valid in first node
+ int sizeToHere; // in a link list of file transfers, the sum of the filesizes of all prior nodes in the list
+ mwFileTransfer* ft;
+} FileTransferClientData;
+
+
+
+// Global variables
+struct CSametimeProto;
+
+extern HINSTANCE hInst;
+extern PLUGININFOEX pluginInfo;
+extern LIST<CSametimeProto> g_Instances;
+
+
+#include "sametime_proto.h"
+
+
+#endif //#ifndef _SAMETIME_H
+
diff --git a/protocols/Sametime/src/sametime_proto.cpp b/protocols/Sametime/src/sametime_proto.cpp
new file mode 100644
index 0000000000..eb1839dc3a
--- /dev/null
+++ b/protocols/Sametime/src/sametime_proto.cpp
@@ -0,0 +1,430 @@
+#include "StdAfx.h"
+#include "sametime.h"
+
+
+CSametimeProto::CSametimeProto(const char* pszProtoName, const TCHAR* tszUserName)
+ : PROTO<CSametimeProto>(pszProtoName, tszUserName)
+ , is_idle(false)
+ , idle_status(false)
+ , first_online(true)
+ , idle_timerid(0)
+ , session(NULL)
+ , my_login_info(NULL)
+ , my_conference(NULL)
+ , service_places(NULL)
+ , service_conference(NULL)
+ , server_connection(0)
+{
+
+ // Register m_hNetlibUser user
+ TCHAR name[128];
+ mir_sntprintf(name, SIZEOF(name), TranslateT("%s connection"), m_tszUserName);
+ NETLIBUSER nlu = { 0 };
+ nlu.cbSize = sizeof(nlu);
+ nlu.flags = NUF_TCHAR | NUF_OUTGOING | NUF_INCOMING | NUF_HTTPCONNS;
+ nlu.szSettingsModule = m_szModuleName;
+ nlu.ptszDescriptiveName = name;
+ m_hNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu);
+
+ RegisterGLibLogger();
+ debugLog(_T("CSametimeProto::CSametimeProto() start m_szModuleName=[%s], m_tszUserName=[%s]"), _A2T(m_szModuleName), m_tszUserName);
+
+ SametimeInitIcons();
+ InitCritSection();
+
+ CreateProtoService(PS_GETNAME, &CSametimeProto::GetName);
+ CreateProtoService(PS_GETSTATUS, &CSametimeProto::GetStatus);
+ CreateProtoService(PS_LOADICON, &CSametimeProto::SametimeLoadIcon);
+
+ HookProtoEvent(ME_SYSTEM_PRESHUTDOWN, &CSametimeProto::OnPreShutdown);
+ HookProtoEvent(ME_MSG_WINDOWEVENT, &CSametimeProto::OnWindowEvent);
+ HookProtoEvent(ME_IDLE_CHANGED, &CSametimeProto::OnIdleChanged);
+ HookProtoEvent(ME_DB_CONTACT_DELETED, &CSametimeProto::OnSametimeContactDeleted);
+ HookProtoEvent(ME_OPT_INITIALISE, &CSametimeProto::OptInit);
+
+ // Initialize temporary DB settings
+ db_set_resident(m_szModuleName, "Status");
+ db_set_resident(m_szModuleName, "IdleTS");
+
+ RegisterPopups();
+ InitAwayMsg();
+
+ mir_snprintf(szProtoGroups, SIZEOF(szProtoGroups), "%s_GROUPS", m_szModuleName);
+
+ m_iStatus = ID_STATUS_OFFLINE;
+ previous_status = ID_STATUS_OFFLINE;
+ SetAllOffline();
+
+ DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &mainThread, THREAD_SET_CONTEXT, FALSE, 0 );
+
+ InitConferenceMenu();
+ InitSessionMenu();
+ InitGroupChats();
+
+ LoadOptions();
+
+ debugLog(_T("CSametimeProto::CSametimeProto() end"));
+}
+
+CSametimeProto::~CSametimeProto()
+{
+
+ debugLog(_T("CSametimeProto::~CSametimeProto() start"));
+
+ DeinitSessionMenu();
+ DeinitConferenceMenu();
+
+ DeinitAwayMsg();
+ UnregisterPopups();
+ DeinitCritSection();
+
+ debugLog(_T("CSametimeProto::~CSametimeProto() end"));
+
+ UnRegisterGLibLogger();
+ Netlib_CloseHandle(m_hNetlibUser);
+
+}
+
+
+MCONTACT CSametimeProto::AddToList(int flags, PROTOSEARCHRESULT* psr)
+{
+ MYPROTOSEARCHRESULT* sr = (MYPROTOSEARCHRESULT*)psr;
+ debugLog(_T("CSametimeProto::AddToList() flags=[%d]"), flags);
+ return AddSearchedUser(sr, flags & PALF_TEMPORARY);
+}
+
+MCONTACT CSametimeProto::AddToListByEvent(int flags, int iContact, HANDLE hDbEvent)
+{
+ debugLog(_T("CSametimeProto::AddToListByEvent() flags=[%d]"), flags);
+ return 0;
+}
+
+
+int CSametimeProto::Authorize(HANDLE hDbEvent)
+{
+ debugLog(_T("CSametimeProto::Authorize()"));
+ return 1;
+}
+
+int CSametimeProto::AuthDeny(HANDLE hDbEvent, const PROTOCHAR* szReason)
+{
+ debugLog(_T("CSametimeProto::AuthDeny()"));
+ return 1;
+}
+
+
+int CSametimeProto::AuthRecv(MCONTACT hContact, PROTORECVEVENT*)
+{
+ debugLog(_T("CSametimeProto::AuthRecv()"));
+ return 1;
+}
+
+int CSametimeProto::AuthRequest(MCONTACT hContact, const PROTOCHAR* szMessage)
+{
+ debugLog(_T("CSametimeProto::AuthRequest()"));
+ return 1;
+}
+
+
+HANDLE CSametimeProto::FileAllow(MCONTACT hContact, HANDLE hTransfer, const PROTOCHAR* szPath)
+{
+ debugLog(_T("CSametimeProto::FileAllow() hContact=[%x], szPath=[%s]"), hContact, szPath);
+ char* szPathA = mir_t2a(szPath);
+ HANDLE res = AcceptFileTransfer(hContact, hTransfer, szPathA);
+ mir_free(szPathA);
+ return res;
+}
+
+int CSametimeProto::FileCancel(MCONTACT hContact, HANDLE hTransfer)
+{
+ debugLog(_T("CSametimeProto::FileCancel() hContact=[%x]"), hContact);
+ CancelFileTransfer(hTransfer);
+ return 0;
+}
+
+int CSametimeProto::FileDeny(MCONTACT hContact, HANDLE hTransfer, const PROTOCHAR* szReason)
+{
+ debugLog(_T("CSametimeProto::FileDeny() hContact=[%x], szReason=[%s]"), hContact, szReason);
+ RejectFileTransfer(hTransfer);
+ return 0;
+}
+
+int CSametimeProto::FileResume(HANDLE hTransfer, int* action, const PROTOCHAR** szFilename)
+{
+ debugLog(_T("CSametimeProto::FileResume() action=[%d]"), &action);
+ return 0;
+}
+
+
+DWORD_PTR CSametimeProto::GetCaps(int type, MCONTACT hContact)
+{
+ int ret = 0;
+ switch (type) {
+ case PFLAGNUM_1:
+ ret = PF1_IM | PF1_BASICSEARCH | PF1_EXTSEARCHUI | PF1_ADDSEARCHRES | PF1_MODEMSG | PF1_FILE | PF1_CHAT;
+ break;
+ case PFLAGNUM_2:
+ ret = PF2_ONLINE | PF2_SHORTAWAY | PF2_HEAVYDND | PF2_LIGHTDND;
+ break;
+ case PFLAGNUM_3:
+ ret = PF2_ONLINE | PF2_SHORTAWAY | PF2_HEAVYDND;
+ break;
+ case PFLAGNUM_4:
+ ret = PF4_SUPPORTTYPING | PF4_IMSENDUTF;
+ break;
+ case PFLAGNUM_5:
+ ret = PF2_LIGHTDND;
+ break;
+ case PFLAG_UNIQUEIDTEXT:
+ ret = (DWORD_PTR) Translate("Id");
+ break;
+ case PFLAG_MAXLENOFMESSAGE:
+ ret = MAX_MESSAGE_SIZE;
+ break;
+ case PFLAG_UNIQUEIDSETTING:
+ ret = (DWORD_PTR) "stid";
+ break;
+ }
+ return ret;
+}
+
+int CSametimeProto::GetInfo(MCONTACT hContact, int infoType)
+{
+ // GetInfo - retrieves a contact info
+ debugLog(_T("CSametimeProto::GetInfo() hContact=[%x], infoType=[%d]"), hContact, infoType);
+
+ if (getByte(hContact, "ChatRoom", 0))
+ return 1;
+
+ if (!session)
+ return 1;
+
+ ///TODO unimplemented - getting contact info
+
+ TFakeAckParams* tfap = (TFakeAckParams*)mir_alloc(sizeof(TFakeAckParams));
+ tfap->proto = this;
+ tfap->hContact = hContact;
+ tfap->lParam = NULL;
+ mir_forkthread(sttFakeAckInfoSuccessThread, (void*)tfap);
+
+ return 0;
+}
+
+
+HANDLE CSametimeProto::SearchBasic(const PROTOCHAR* id)
+{
+ debugLog(_T("CSametimeProto::SearchBasic() id:len=[%d]"), id == NULL ? -1 : _tcslen(id));
+ char* id_utf8 = mir_utf8encodeT(id);
+ int ret = SearchForUser(id_utf8, FALSE);
+ mir_free(id_utf8);
+ return (HANDLE)ret;
+ ///TODO - add timeout (like at GGPROTO::searchthread)
+}
+
+HANDLE CSametimeProto::SearchByEmail(const PROTOCHAR* email)
+{
+ return 0;
+}
+
+HANDLE CSametimeProto::SearchByName(const PROTOCHAR* nick, const PROTOCHAR* firstName, const PROTOCHAR* lastName)
+{
+ return 0;
+}
+
+HWND CSametimeProto::SearchAdvanced(HWND owner)
+{
+ TCHAR buf[512];
+ int ret = 0;
+ if (GetDlgItemText(owner, IDC_EDIT1, buf, 512)) {
+ debugLog(_T("CSametimeProto::SearchAdvanced() buf:len=[%d]"), buf == NULL ? -1 : _tcslen(buf));
+ char* buf_utf8 = mir_utf8encodeT(buf);
+ ret = SearchForUser(buf_utf8, TRUE);
+ mir_free(buf_utf8);
+ }
+ return (HWND)ret;
+}
+
+HWND CSametimeProto::CreateExtendedSearchUI(HWND owner)
+{
+ debugLog(_T("CSametimeProto::CreateExtendedSearchUI() start"));
+ return CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_USERSEARCH), owner, SearchDialogFunc, (LPARAM)this);
+}
+
+
+int CSametimeProto::RecvContacts(MCONTACT hContact, PROTORECVEVENT*)
+{
+ debugLog(_T("CSametimeProto::RecvContacts()"));
+ return 1;
+}
+
+int CSametimeProto::RecvFile(MCONTACT hContact, PROTOFILEEVENT* pre)
+{
+ debugLog(_T("CSametimeProto::RecvFile() hContact=[%x]"), hContact);
+
+ db_unset(hContact, "CList", "Hidden");
+ db_unset(hContact, "CList", "NotOnList");
+
+ return Proto_RecvFile(hContact, pre);
+}
+
+int CSametimeProto::RecvMsg(MCONTACT hContact, PROTORECVEVENT* pre)
+{
+ debugLog(_T("CSametimeProto::RecvMsg() hContact=[%x]"), hContact);
+
+ db_unset(hContact, "CList", "Hidden");
+ db_unset(hContact, "CList", "NotOnList");
+
+ return Proto_RecvMessage(hContact, pre);
+}
+
+int CSametimeProto::RecvUrl(MCONTACT hContact, PROTORECVEVENT*)
+{
+ debugLog(_T("CSametimeProto::RecvUrl()"));
+ return 1;
+}
+
+int CSametimeProto::SendContacts(MCONTACT hContact, int flags, int nContacts, MCONTACT* hContactsList)
+{
+ debugLog(_T("CSametimeProto::SendContacts() flags=[%d], nContacts=[%d]"), flags, nContacts);
+ return 1;
+}
+
+HANDLE CSametimeProto::SendFile(MCONTACT hContact, const PROTOCHAR* szDescription, PROTOCHAR** ppszFiles)
+{
+ debugLog(_T("CSametimeProto::SendFile() hContact=[%x]"), hContact);
+ if (m_iStatus != ID_STATUS_OFFLINE) {
+ if (hContact && ppszFiles && szDescription) {
+ if (db_get_w(hContact, m_szModuleName, "Status", ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE) {
+ return SendFilesToUser(hContact, ppszFiles, szDescription);
+ }
+ }
+ }
+ return 0; // failure
+}
+
+int CSametimeProto::SendMsg(MCONTACT hContact, int flags, const char* msg)
+{
+
+ debugLog(_T("CSametimeProto::SendMsg() hContact=[%x], flags=[%d]"), hContact, flags);
+ char* proto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ int ret;
+
+ if (!proto || strcmp(proto, m_szModuleName) != 0 || db_get_w(hContact, m_szModuleName, "Status", ID_STATUS_OFFLINE) == ID_STATUS_OFFLINE) {
+ TFakeAckParams* tfap = (TFakeAckParams*)mir_alloc(sizeof(TFakeAckParams));
+ tfap->proto = this;
+ tfap->hContact = hContact;
+ tfap->lParam = 0;
+ mir_forkthread(sttFakeAckMessageFailedThread, (void*)tfap);
+ return 0;
+ }
+
+ char* msg_utf8;
+ if (flags & PREF_UNICODE)
+ msg_utf8 = mir_utf8encodeW((wchar_t*)&msg[ strlen( msg )+1 ] );
+ else if (flags & PREF_UTF)
+ msg_utf8 = mir_strdup(msg);
+ else
+ msg_utf8 = mir_utf8encode(msg);
+
+ if (!msg_utf8)
+ return 0;
+
+ ret = (int)SendMessageToUser(hContact, msg_utf8);
+ mir_free(msg_utf8);
+
+ TFakeAckParams* tfap = (TFakeAckParams*)mir_alloc(sizeof(TFakeAckParams));
+ tfap->proto = this;
+ tfap->hContact = hContact;
+ tfap->lParam = (LPARAM)ret;
+ mir_forkthread(sttFakeAckMessageSuccessThread, (void*)tfap);
+
+ return ret;
+}
+
+int CSametimeProto::SendUrl(MCONTACT hContact, int flags, const char* url)
+{
+ debugLog(_T("CSametimeProto::SendUrl()"));
+ return 1;
+}
+
+
+int CSametimeProto::SetApparentMode(MCONTACT hContact, int mode)
+{
+ debugLog(_T("CSametimeProto::SetApparentMode() mode=[%d]"), mode);
+ return 1;
+}
+
+int CSametimeProto::SetStatus(int iNewStatus)
+{
+ debugLog(_T("CSametimeProto::SetStatus() m_iStatus=[%d], m_iDesiredStatus=[%d], iNewStatus=[%d]"), m_iStatus, m_iDesiredStatus, iNewStatus);
+ m_iDesiredStatus = iNewStatus;
+ if (iNewStatus != ID_STATUS_OFFLINE) {
+ if (m_iStatus == ID_STATUS_OFFLINE)
+ LogIn(iNewStatus, m_hNetlibUser);
+ else
+ SetSessionStatus(iNewStatus);
+ } else if (m_iStatus != ID_STATUS_OFFLINE && iNewStatus == ID_STATUS_OFFLINE) {
+ LogOut();
+ }
+
+ return 0;
+}
+
+HANDLE CSametimeProto::GetAwayMsg(MCONTACT hContact)
+{
+ debugLog(_T("CSametimeProto::GetInfo() hContact=[%x], m_iStatus=[%d]"), hContact, m_iStatus);
+ if (hContact && m_iStatus != ID_STATUS_OFFLINE) {
+ TFakeAckParams* tfap;
+ tfap = (TFakeAckParams*)malloc(sizeof(TFakeAckParams));
+ tfap->proto = this;
+ tfap->hContact = hContact;
+ mir_forkthread(sttRecvAwayThread, (void*)tfap);
+ return (HANDLE)1;
+ }
+ return (HANDLE)0;
+}
+
+int CSametimeProto::RecvAwayMsg(MCONTACT hContact, int mode, PROTORECVEVENT* evt)
+{
+ debugLog(_T("CSametimeProto::RecvAwayMsg() hContact=[%x], mode=[%d]"), hContact, mode);
+
+ if (evt->flags & PREF_UTF) {
+ TCHAR* pszMsg = mir_utf8decodeT(evt->szMessage);
+ ProtoBroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)evt->lParam, (LPARAM)pszMsg);
+ mir_free(pszMsg);
+ } else {
+ ProtoBroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)evt->lParam, (LPARAM)(TCHAR*)_A2T(evt->szMessage));
+ }
+
+ return 0;
+}
+
+int CSametimeProto::SetAwayMsg(int iStatus, const PROTOCHAR* msg)
+{
+ debugLog(_T("CSametimeProto::SetAwayMsg() iStatus=[%d], msg:len=[%d]"), iStatus, msg == NULL ? -1 :_tcslen(msg));
+ SetSessionAwayMessage(iStatus, msg);
+ return 0;
+}
+
+
+int CSametimeProto::UserIsTyping(MCONTACT hContact, int type)
+{
+ debugLog(_T("CSametimeProto::UserIsTyping() hContact=[%x], type=[%d]"), hContact, type);
+ SendTyping(hContact, type == PROTOTYPE_SELFTYPING_ON);
+ return 0;
+}
+
+
+int CSametimeProto::OnEvent(PROTOEVENTTYPE iEventType, WPARAM wParam, LPARAM lParam)
+{
+ switch(iEventType) {
+ case EV_PROTO_ONOPTIONS: {
+ debugLog(_T("CSametimeProto::OnEvent() EV_PROTO_ONOPTIONS"));
+ OptInit(wParam, lParam);
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
diff --git a/protocols/Sametime/src/sametime_proto.h b/protocols/Sametime/src/sametime_proto.h
new file mode 100644
index 0000000000..16cbeb17b0
--- /dev/null
+++ b/protocols/Sametime/src/sametime_proto.h
@@ -0,0 +1,248 @@
+
+#ifndef _SAMETIME_PROTO_H
+#define _SAMETIME_PROTO_H
+
+
+
+struct CSametimeProto : public PROTO<CSametimeProto>
+{
+
+ CSametimeProto(const char*, const TCHAR* );
+ ~CSametimeProto();
+
+ //====================================================================================
+ // PROTO_INTERFACE
+ //====================================================================================
+
+
+ virtual MCONTACT __cdecl AddToList(int flags, PROTOSEARCHRESULT* psr);
+ virtual MCONTACT __cdecl AddToListByEvent(int flags, int iContact, HANDLE hDbEvent);
+
+ virtual int __cdecl Authorize(HANDLE hDbEvent);
+ virtual int __cdecl AuthDeny(HANDLE hDbEvent, const PROTOCHAR* szReason);
+ virtual int __cdecl AuthRecv(MCONTACT hContact, PROTORECVEVENT*);
+ virtual int __cdecl AuthRequest(MCONTACT hContact, const PROTOCHAR* szMessage);
+
+ virtual HANDLE __cdecl FileAllow(MCONTACT hContact, HANDLE hTransfer, const PROTOCHAR* szPath);
+ virtual int __cdecl FileCancel(MCONTACT hContact, HANDLE hTransfer);
+ virtual int __cdecl FileDeny(MCONTACT hContact, HANDLE hTransfer, const PROTOCHAR* szReason);
+ virtual int __cdecl FileResume(HANDLE hTransfer, int* action, const PROTOCHAR** szFilename);
+
+ virtual DWORD_PTR __cdecl GetCaps(int type, MCONTACT hContact = NULL);
+ virtual int __cdecl GetInfo(MCONTACT hContact, int infoType);
+
+ virtual HANDLE __cdecl SearchBasic(const PROTOCHAR* id);
+ virtual HANDLE __cdecl SearchByEmail(const PROTOCHAR* email);
+ virtual HANDLE __cdecl SearchByName(const PROTOCHAR* nick, const PROTOCHAR* firstName, const PROTOCHAR* lastName);
+ virtual HWND __cdecl SearchAdvanced(HWND owner);
+ virtual HWND __cdecl CreateExtendedSearchUI(HWND owner);
+
+ virtual int __cdecl RecvContacts(MCONTACT hContact, PROTORECVEVENT*);
+ virtual int __cdecl RecvFile(MCONTACT hContact, PROTOFILEEVENT*);
+ virtual int __cdecl RecvMsg(MCONTACT hContact, PROTORECVEVENT*);
+ virtual int __cdecl RecvUrl(MCONTACT hContact, PROTORECVEVENT*);
+
+ virtual int __cdecl SendContacts(MCONTACT hContact, int flags, int nContacts, MCONTACT* hContactsList);
+ virtual HANDLE __cdecl SendFile(MCONTACT hContact, const PROTOCHAR* szDescription, PROTOCHAR** ppszFiles);
+ virtual int __cdecl SendMsg(MCONTACT hContact, int flags, const char* msg);
+ virtual int __cdecl SendUrl(MCONTACT hContact, int flags, const char* url);
+
+ virtual int __cdecl SetApparentMode(MCONTACT hContact, int mode);
+ virtual int __cdecl SetStatus(int iNewStatus);
+
+ virtual HANDLE __cdecl GetAwayMsg(MCONTACT hContact);
+ virtual int __cdecl RecvAwayMsg(MCONTACT hContact, int mode, PROTORECVEVENT* evt);
+ virtual int __cdecl SetAwayMsg(int iStatus, const PROTOCHAR* msg);
+
+ virtual int __cdecl UserIsTyping(MCONTACT hContact, int type);
+
+ virtual int __cdecl OnEvent(PROTOEVENTTYPE iEventType, WPARAM wParam, LPARAM lParam);
+
+
+
+ // sametime.cpp
+ int __cdecl OnSametimeContactDeleted(WPARAM wParam, LPARAM lParam);
+ INT_PTR __cdecl GetName(WPARAM wParam, LPARAM lParam);
+ INT_PTR __cdecl GetStatus(WPARAM wParam, LPARAM lParam);
+ INT_PTR __cdecl SametimeLoadIcon(WPARAM wParam, LPARAM lParam);
+ int __cdecl OnWindowEvent(WPARAM wParam, LPARAM lParam);
+ int __cdecl OnPreShutdown(WPARAM wParam, LPARAM lParam);
+ int __cdecl OnIdleChanged(WPARAM wParam, LPARAM lParam);
+ void SetAllOffline();
+ void BroadcastNewStatus(int iNewStatus);
+
+ // messaging.cpp
+ void InitMessaging();
+ void DeinitMessaging();
+ void SendTyping(MCONTACT hContact, bool typing);
+ HANDLE SendMessageToUser(MCONTACT hContact, char* msg_utf8);
+ void CloseIm(MCONTACT hContact);
+
+ // userlist.cpp
+ int SearchForUser(const char* name, BOOLEAN advanced);
+ MCONTACT AddSearchedUser(MYPROTOSEARCHRESULT* mpsr, bool temporary);
+ MCONTACT AddContact(mwSametimeUser* user, bool temporary);
+ bool GetAwareIdFromContact(MCONTACT hContact, mwAwareIdBlock* id_block);
+ MCONTACT FindContactByUserId(const char* id);
+ void ImportContactsFromList(mwSametimeList* user_list, bool temporary);
+ void ImportContactsFromFile(TCHAR* filename);
+ void ExportContactsToList(mwSametimeList* user_list);
+ void ExportContactsToServer();
+ void UserListAddStored();
+ void InitUserList();
+ void DeinitUserList();
+ void SetContactGroup(MCONTACT hContact, const char* name);
+ void AddGroup(const char* name, bool expanded);
+ void UserListCreate();
+ void UserListDestroy();
+ int GetMoreDetails(const char* name);
+ void UserRecvAwayMessage(MCONTACT hContact);
+ int ContactDeleted(MCONTACT hContact);
+
+ // files.cpp
+ void InitFiles();
+ void DeinitFiles();
+ HANDLE AcceptFileTransfer(MCONTACT hContact, HANDLE hFt, char* save_path);
+ void RejectFileTransfer(HANDLE hFt);
+ void CancelFileTransfer(HANDLE hFt);
+ HANDLE SendFilesToUser(MCONTACT hContact, PROTOCHAR** files, const PROTOCHAR* pszDesc);
+
+ // conference.cpp
+ void InitConference();
+ void InitConferenceMenu();
+ void DeinitConference();
+ void DeinitConferenceMenu();
+ void ClearInviteQueue();
+ void TerminateConference(char* name);
+ int __cdecl GcEventHook(WPARAM wParam, LPARAM lParam);
+ int __cdecl PrebuildContactMenu(WPARAM wParam, LPARAM lParam);
+ int ChatDeleted(MCONTACT hContact);
+ INT_PTR __cdecl onMenuLeaveChat(WPARAM wParam, LPARAM lParam);
+ INT_PTR __cdecl onMenuCreateChat(WPARAM wParam, LPARAM lParam);
+
+ // sametime_session.cpp
+ void SessionStarted();
+ void SessionStopping();
+ void InitSessionMenu();
+ void DeinitSessionMenu();
+ int LogIn(int status, HANDLE hNetlibUser);
+ int LogOut();
+ void InitCritSection();
+ void DeinitCritSection();
+ int SetSessionStatus(int status);
+ void UpdateSelfStatus();
+ int SetIdle(bool idle);
+ void SetSessionAwayMessage(int status, const PROTOCHAR* msg);
+ WORD GetClientVersion();
+ WORD GetServerVersion();
+ INT_PTR __cdecl SessionAnnounce(WPARAM wParam, LPARAM lParam);
+ void InitGroupChats();
+ void InitAwayMsg();
+ void DeinitAwayMsg();
+ void InitMeanwhileServices();
+ void DeinitMeanwhileServices();
+
+ // options.cpp
+ int __cdecl OptInit(WPARAM wParam, LPARAM lParam);
+ void LoadOptions();
+ void SaveOptions();
+
+ // utils.cpp
+ void showPopup(const TCHAR* msg, SametimePopupEnum flag);
+ void RegisterPopups();
+ void UnregisterPopups();
+ void RegisterGLibLogger();
+ void UnRegisterGLibLogger();
+
+ // places.cpp
+ void InitPlaces(mwSession* session);
+ void DeinitPlaces(mwSession* session);
+
+
+
+
+ /* properties */
+
+ char szProtoGroups[128];
+ HANDLE mainThread;
+ CRITICAL_SECTION session_cs;
+ mwSession* session;
+ int previous_status;
+ bool is_idle;
+
+ // userlist.cpp
+ mwServiceStorage* service_storage;
+ mwServiceAware* service_aware;
+ mwServiceResolve* service_resolve;
+ mwAwareList* aware_list;
+
+ // files.cpp
+ mwServiceFileTransfer* service_files;
+
+ // messaging.cpp
+ CRITICAL_SECTION q_cs;
+ mwServiceIm* service_im;
+ ContactMessageQueue contact_message_queue;
+
+ // sametime_session.cpp
+ bool first_online; // set our status after the first online status comes from the server
+ HANDLE hSessionAnnounceMenuItem;
+ int login_status;
+ bool idle_status;
+ int idle_timerid;
+ HANDLE server_connection;
+
+ // conference.cpp
+ InviteQueue invite_queue;
+ mwServiceConference* service_conference;
+ mwLoginInfo* my_login_info;
+ mwConference* my_conference;
+ HANDLE hLeaveChatMenuItem;
+ HANDLE hCreateChatMenuItem;
+
+ // options.cpp
+ SametimeOptions options;
+
+ // places.cpp
+ mwServicePlace* service_places;
+
+ // utils.cpp
+ HANDLE hPopupError;
+ HANDLE hPopupNotify;
+ guint gLogHandler;
+
+};
+
+
+
+typedef struct tag_TFakeAckParams {
+ CSametimeProto* proto;
+ MCONTACT hContact;
+ LPARAM lParam;
+} TFakeAckParams;
+
+
+struct SendAnnouncementFunc_arg {
+ CSametimeProto* proto;
+ TCHAR msg[MAX_MESSAGE_SIZE];
+ GList* recipients;
+};
+
+typedef void (*SendAnnouncementFunc)(SendAnnouncementFunc_arg* ad);
+
+struct SessionAnnounceDialogProc_arg {
+ CSametimeProto* proto;
+ SendAnnouncementFunc sendAnnouncementFunc;
+};
+
+
+struct PopupData {
+ SametimePopupEnum flag;
+ TCHAR* title;
+ TCHAR* text;
+ CSametimeProto* proto;
+};
+
+
+#endif //#ifndef _SAMETIME_PROTO_H
+
diff --git a/protocols/Sametime/src/sametime_session.cpp b/protocols/Sametime/src/sametime_session.cpp
new file mode 100644
index 0000000000..bc03f86a03
--- /dev/null
+++ b/protocols/Sametime/src/sametime_session.cpp
@@ -0,0 +1,634 @@
+#include "StdAfx.h"
+#include "sametime.h"
+
+/// not in CSametimeProto (used at NETLIBOPENCONNECTION_tag.waitcallback)
+bool continue_connect;
+
+#define MS_SAMETIME_MENUANNOUNCESESSION "/SessionAnnounce"
+
+// utf8 encoded
+struct {
+ char* szOnline;
+ char* szAway;
+ char* szDND;
+} AwayMessages;
+
+
+void __cdecl SessionClear(mwSession* session)
+{
+ CSametimeProto* proto = (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
+ proto->debugLog(_T("SessionClear()"));
+}
+
+int __cdecl SessionWrite(mwSession* session, const unsigned char* buf, gsize len)
+{
+ CSametimeProto* proto = (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
+ proto->debugLog(_T("SessionWrite() server_connection=[%d], len=[%d]"), proto->server_connection, len);
+ if (!proto->server_connection) return 1;
+ if (Netlib_Send(proto->server_connection, (const char*)buf, len, 0) == SOCKET_ERROR)
+ return 1;
+ return 0;
+}
+
+void __cdecl SessionClose(mwSession* session)
+{
+ CSametimeProto* proto = (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
+ proto->debugLog(_T("SessionClose() server_connection=[%d]"), proto->server_connection);
+ Netlib_CloseHandle(proto->server_connection);
+ proto->server_connection = 0;
+}
+
+void CSametimeProto::SessionStarted()
+{
+ UserListCreate();
+ if (options.get_server_contacts) UserListAddStored();
+}
+
+void CSametimeProto::SessionStopping()
+{
+ UserListDestroy();
+}
+
+void CSametimeProto::InitMeanwhileServices()
+{
+ debugLog(_T("InitMeanwhileServices() start"));
+
+ if (options.encrypt_session) {
+ mwSession_addCipher(session, mwCipher_new_RC2_128(session));
+ mwSession_addCipher(session, mwCipher_new_RC2_40(session));
+ }
+
+ InitUserList();
+ InitMessaging();
+ InitFiles();
+ InitConference();
+
+ mwSession_setProperty(session, "PROTO_STRUCT_PTR", this, NULL);
+
+ ///TODO InitMeanwhileServices DeinitMeanwhileServices on LogIn LogOut, do not need restart
+ mwSession_setProperty(session, mwSession_AUTH_USER_ID, options.id, NULL);
+ mwSession_setProperty(session, mwSession_AUTH_PASSWORD, options.pword, NULL);
+ mwSession_setProperty(session, mwSession_CLIENT_TYPE_ID, (void*)options.client_id, NULL);
+
+ if (options.use_old_default_client_ver) {
+ mwSession_setProperty(session, mwSession_CLIENT_VER_MAJOR, GUINT_TO_POINTER(db_get_w(0, m_szModuleName, "ClientVersionMajor", MW_PROTOCOL_VERSION_MAJOR)), 0);
+ mwSession_setProperty(session, mwSession_CLIENT_VER_MINOR, GUINT_TO_POINTER(db_get_w(0, m_szModuleName, "ClientVersionMinor", MW_PROTOCOL_VERSION_MINOR)), 0);
+ } else {
+ mwSession_setProperty(session, mwSession_CLIENT_VER_MAJOR, GUINT_TO_POINTER(db_get_w(0, m_szModuleName, "ClientVersionMajor", 0x001e)), 0);
+ mwSession_setProperty(session, mwSession_CLIENT_VER_MINOR, GUINT_TO_POINTER(db_get_w(0, m_szModuleName, "ClientVersionMinor", 0x196f)), 0);
+ }
+
+}
+
+void CSametimeProto::DeinitMeanwhileServices()
+{
+ debugLog(_T("DeinitMeanwhileServices() start"));
+ DeinitConference();
+ DeinitFiles();
+ DeinitMessaging();
+ DeinitUserList();
+ mwCipher_free(mwSession_getCipher(session, mwCipher_RC2_40));
+ mwCipher_free(mwSession_getCipher(session, mwCipher_RC2_128));
+}
+
+void __cdecl SessionStateChange(mwSession* session, mwSessionState state, gpointer info)
+{
+ CSametimeProto* proto = (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
+ proto->debugLog(_T("SessionStateChange() state=[%d]"), state);
+
+ switch(state) {
+
+ case mwSession_STARTING:
+ break;
+
+ case mwSession_HANDSHAKE:
+ break;
+
+ case mwSession_HANDSHAKE_ACK:
+ break;
+
+ case mwSession_STARTED:
+ proto->SessionStarted();
+ break;
+
+ case mwSession_STOPPING:
+ if ((int)info) {// & ERR_FAILURE) {
+ char *msg = mwError((int)info);
+ TCHAR *msgT = mir_utf8decodeT(msg);
+ proto->showPopup(TranslateTS(msgT), SAMETIME_POPUP_ERROR);
+ mir_free(msgT);
+ g_free(msg);
+ }
+ proto->SessionStopping();
+ break;
+
+ case mwSession_STOPPED:
+ break;
+
+ case mwSession_LOGIN_REDIR:
+ proto->debugLog(_T("SessionStateChange() mwSession_LOGIN_REDIR info=[%s]"), _A2T((char*)info));
+ //options.server_name = str((char*)info);
+ strcpy(proto->options.server_name, (char*)info);
+ proto->LogOut();
+ proto->LogIn(proto->login_status, proto->m_hNetlibUser);
+ break;
+
+ case mwSession_LOGIN_CONT:
+ break;
+
+ case mwSession_LOGIN:
+ break;
+
+ case mwSession_LOGIN_ACK:
+ break;
+
+ case mwSession_UNKNOWN:
+ break;
+
+ }
+}
+
+void __cdecl SessionAdmin(struct mwSession* session, const char* text)
+{
+ CSametimeProto* proto = (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
+ proto->debugLog(_T("SessionAdmin()"));
+ TCHAR* tt = mir_utf8decodeT(text);
+ MessageBox(0, tt, TranslateT("Sametime Administrator Message"), MB_OK);
+ mir_free(tt);
+}
+
+void __cdecl SessionAnnounce(struct mwSession* session, struct mwLoginInfo* from, gboolean may_reply, const char* text)
+{
+ CSametimeProto* proto = (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
+ proto->debugLog(_T("SessionAnnounce()"));
+ TCHAR* stzFrom;
+ TCHAR* stzText;
+ TCHAR stzFromBuff[256];
+ stzFrom = mir_utf8decodeT(from->user_name);
+ stzText = mir_utf8decodeT(text);
+ mir_sntprintf(stzFromBuff, 256, TranslateT("Session Announcement - from '%s'"), stzFrom);
+ MessageBox(0, TranslateTS(stzText), stzFromBuff, MB_OK);
+ mir_free(stzText);
+ mir_free(stzFrom);
+}
+
+void __cdecl SessionSetPrivacyInfo(struct mwSession* session)
+{
+ CSametimeProto* proto = (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
+ proto->debugLog(_T("SessionSetPrivacyInfo()"));
+}
+
+void __cdecl SessionSetUserStatus(struct mwSession* session)
+{
+ CSametimeProto* proto = (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
+
+ int new_status;
+ struct mwUserStatus us;
+ mwUserStatus_clone(&us, mwSession_getUserStatus(session));
+
+ proto->debugLog(_T("SessionSetUserStatus() us.status=[%d]"), us.status);
+
+ switch(us.status) {
+
+ case mwStatus_ACTIVE:
+ new_status = ID_STATUS_ONLINE;
+ break;
+
+ case mwStatus_AWAY:
+ new_status = ID_STATUS_AWAY;
+ if (proto->idle_status) {
+ // ignore setting to away by idle module, after we've set ourselves idle
+ // most standard clients represent idle and away the same way anyway,
+ // but this allows miranda users to make use of the idle timestamp
+ // but show our status in clist as away
+ proto->BroadcastNewStatus(new_status);
+ mwUserStatus_clear(&us);
+ return;
+ }
+ break;
+
+ case mwStatus_BUSY:
+ new_status = ID_STATUS_DND;
+ break;
+
+ case mwStatus_IDLE:
+ new_status = ID_STATUS_AWAY;
+ if (!proto->first_online && !proto->options.idle_as_away) { // show our status in clist as away if idle when going online or treating idle as away
+ mwUserStatus_clear(&us);
+ return;
+ }
+ break;
+
+ case 8: // new 'in a meeting' status, not handled by meanwhile lib
+ new_status = ID_STATUS_OCCUPIED;
+ break;
+
+ default:
+ {
+ TCHAR buff[512];
+ mir_sntprintf(buff, 512, TranslateT("Unknown user status: %d"), us.status);
+ proto->showPopup(buff, SAMETIME_POPUP_ERROR);
+ proto->debugLog(buff);
+ }
+ mwUserStatus_clear(&us);
+ // just go online...to prevent us getting stuck 'connecting'
+ new_status = ID_STATUS_ONLINE;
+ break;
+
+ }
+
+ proto->m_iDesiredStatus = new_status;
+
+ if (proto->first_online) {
+ proto->first_online = false;
+ //proto->showPopup(TranslateT("Setting login status"), SAMETIME_POPUP_INFO);
+ proto->debugLog(_T("Setting login status"));
+ proto->SetSessionStatus(proto->login_status);
+ } else {
+ proto->BroadcastNewStatus(new_status);
+ }
+
+ mwUserStatus_clear(&us);
+}
+
+void CSametimeProto::UpdateSelfStatus()
+{
+ EnterCriticalSection(&session_cs);
+ if (session) SessionSetUserStatus(session);
+ LeaveCriticalSection(&session_cs);
+}
+
+int CSametimeProto::SetSessionStatus(int status)
+{
+ struct mwUserStatus us;
+ debugLog(_T("SetSessionStatus() start status=[%d]"), status);
+
+ if (idle_timerid) KillTimer(0, idle_timerid);
+
+ us.time = (DWORD)time(0);
+ //us.time = 0;
+
+ switch(status) {
+ case ID_STATUS_FREECHAT:
+ case ID_STATUS_ONLINE:
+ us.desc = AwayMessages.szOnline; us.status = mwStatus_ACTIVE;
+ break;
+ case ID_STATUS_NA:
+ case ID_STATUS_INVISIBLE:
+ case ID_STATUS_ONTHEPHONE:
+ case ID_STATUS_OUTTOLUNCH:
+ case ID_STATUS_AWAY:
+ us.desc = AwayMessages.szAway; us.status = mwStatus_AWAY;
+ break;
+ case ID_STATUS_OCCUPIED:
+ case ID_STATUS_DND:
+ us.desc = AwayMessages.szDND; us.status = mwStatus_BUSY;
+ break;
+ default:
+ // act as online for unsupported status
+ us.desc = AwayMessages.szOnline; us.status = mwStatus_ACTIVE; break;
+ }
+
+ debugLog(_T("SetSessionStatus() mwSession_setUserStatus us.status=[%d], us.desc:len=[%d]"), us.status, us.desc == NULL ? -1 : strlen(us.desc));
+ mwSession_setUserStatus(session, &us);
+
+ return 0;
+}
+
+VOID CALLBACK IdleTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
+{
+ CSametimeProto* proto = (CSametimeProto*)idEvent;
+
+ KillTimer(0, proto->idle_timerid);
+ proto->idle_timerid = 0;
+
+ if (proto->idle_status) {
+ struct mwUserStatus us;
+ us.time = (DWORD)time(0);
+ us.status = mwStatus_IDLE;
+ us.desc = 0;
+ mwSession_setUserStatus(proto->session, &us);
+ } else {
+ proto->SetSessionStatus(proto->m_iStatus);
+ }
+}
+
+int CSametimeProto::SetIdle(bool idle)
+{
+ // set a timer, to wait for any autoaway module which might set our status
+ debugLog(_T("CSametimeProto::SetIdle() idle=[%d], idle_status=[%d], idle_timerid=[%d]"), idle, idle_status, idle_timerid);
+ if (idle && !idle_status) {
+ idle_status = true;
+ if (!idle_timerid)
+ idle_timerid = SetTimer(0, (UINT_PTR)this, 200, IdleTimerProc);
+ } else if (idle_status) {
+ idle_status = false;
+ if (!idle_timerid)
+ idle_timerid = SetTimer(0, (UINT_PTR)this, 200, IdleTimerProc);
+ }
+ return 0;
+}
+
+void CSametimeProto::SetSessionAwayMessage(int status, const PROTOCHAR* msgT)
+{
+ debugLog(_T("SetSessionAwayMessage() status=[%d], msgT:len=[%d]"), status, msgT == NULL ? -1 : _tcslen(msgT));
+
+ ptrA msg(mir_utf8encodeT(msgT));
+ if (status == ID_STATUS_ONLINE) {
+ mir_free(AwayMessages.szOnline);
+ if (msg) {
+ AwayMessages.szOnline = mir_strdup(msg);
+ } else AwayMessages.szOnline = 0;
+ } else if (status == ID_STATUS_AWAY) {
+ mir_free(AwayMessages.szAway);
+ if (msg) {
+ AwayMessages.szAway = mir_strdup(msg);
+ } else AwayMessages.szAway = 0;
+ } else if (status == ID_STATUS_DND) {
+ mir_free(AwayMessages.szDND);
+ if (msg) {
+ AwayMessages.szDND = mir_strdup(msg);
+ } else AwayMessages.szDND = 0;
+ } else
+ return; // unsupported status
+
+ if (session){
+ SetSessionStatus(status); // update current away message
+ }
+}
+
+static VOID CALLBACK NullAPC (DWORD_PTR)
+{
+ // This function intentionally left blank
+}
+
+void WakeThread(HANDLE hThread)
+{
+ QueueUserAPC(NullAPC, hThread, 0);
+}
+
+void __cdecl KeepAliveThread(LPVOID param)
+{
+ CSametimeProto* proto = (CSametimeProto*)param;
+ int i = 120;
+ proto->debugLog(_T("KeepAliveThread() start"));
+
+ while(1) {
+
+ if (i <= 0){
+ i = 120;
+ // send keepalive every 120 * 250 = 30000[ms]
+ if (mwSession_isStarted(proto->session) && proto->session){
+ mwSession_sendKeepalive(proto->session);
+ }
+ }
+
+ i--;
+
+ SleepEx(250, TRUE);
+
+ EnterCriticalSection(&(proto->session_cs));
+ if (Miranda_Terminated() || !proto->session) {
+ LeaveCriticalSection(&(proto->session_cs));
+ proto->debugLog(_T("KeepAliveThread() end"));
+ break;
+ }
+ LeaveCriticalSection(&(proto->session_cs));
+ }
+
+ return;
+}
+
+int waitcallback(unsigned int* timeout)
+{
+ return continue_connect ? 1 : 0;
+}
+
+void __cdecl SessionThread(LPVOID param)
+{
+
+ CSametimeProto* proto = (CSametimeProto*)param;
+ HANDLE hNetlibUser = proto->m_hNetlibUser;
+ proto->debugLog(_T("SessionThread() start"));
+
+ continue_connect = true;
+
+ //setup
+ NETLIBOPENCONNECTION conn_data = {0};
+ conn_data.cbSize = sizeof(NETLIBOPENCONNECTION);
+ conn_data.flags = NLOCF_V2;
+ conn_data.szHost = proto->options.server_name;
+ conn_data.wPort = proto->options.port;
+ conn_data.timeout = 20;
+ conn_data.waitcallback = waitcallback;
+
+ proto->BroadcastNewStatus(ID_STATUS_CONNECTING);
+
+ proto->server_connection = (HANDLE)CallService(MS_NETLIB_OPENCONNECTION, (WPARAM)hNetlibUser, (LPARAM)&conn_data);
+
+ if (!proto->server_connection) {
+
+ proto->BroadcastNewStatus(ID_STATUS_OFFLINE);
+
+ if (continue_connect) {
+ // real timeout - not user cancelled
+ proto->showPopup(TranslateT("No server connection!"), SAMETIME_POPUP_ERROR);
+ }
+
+ proto->debugLog(_T("SessionThread() end, no server_connection, continue_connect=[%d]"), continue_connect);
+ return;
+ }
+
+ mwSessionHandler handler = {0};
+ handler.clear = SessionClear;
+ handler.io_write = SessionWrite;
+ handler.io_close = SessionClose;
+ handler.on_stateChange = SessionStateChange;
+ handler.on_admin = SessionAdmin;
+ handler.on_announce = SessionAnnounce;
+ handler.on_setPrivacyInfo = SessionSetPrivacyInfo;
+ handler.on_setUserStatus = SessionSetUserStatus;
+
+ EnterCriticalSection(&proto->session_cs);
+ proto->session = mwSession_new(&handler);
+
+ proto->InitMeanwhileServices();
+
+ mwSession_start(proto->session);
+ LeaveCriticalSection(&proto->session_cs);
+
+ mir_forkthread(KeepAliveThread, (void*)proto);
+
+ unsigned char* recv_buffer = (unsigned char*)mir_alloc(1024 * 32);
+ int bytes;
+ //while(session && server_connection && mwSession_getState(session) != mwSession_STOPPED) {
+ while(proto->server_connection) {// && session) {// && !mwSession_isStopped(session)) { // break on error
+ bytes = Netlib_Recv(proto->server_connection, (char *)recv_buffer, 1024 * 32, 0);
+ proto->debugLog(_T("SessionThread() Netlib_Recv'ed bytes=[%d]"), bytes);
+
+ if (bytes == 0) {
+ break;
+ } else if (bytes == SOCKET_ERROR) {
+ // this is normal - e.g. socket closed due to log off, during blocking read above
+ break;
+ } else {
+ EnterCriticalSection(&proto->session_cs);
+ mwSession_recv(proto->session, recv_buffer, bytes);
+ LeaveCriticalSection(&proto->session_cs);
+ }
+ }
+ mir_free(recv_buffer);
+
+ EnterCriticalSection(&proto->session_cs);
+ proto->DeinitMeanwhileServices();
+ mwSession* old_session = proto->session;
+ proto->session = 0; // kills keepalive thread, if awake
+ mwSession_free(old_session);
+ LeaveCriticalSection(&proto->session_cs);
+
+ proto->BroadcastNewStatus(ID_STATUS_OFFLINE);
+ proto->SetAllOffline();
+ proto->first_online = true;
+
+ proto->debugLog(_T("SessionThread() end"));
+ return;
+}
+
+WORD CSametimeProto::GetClientVersion()
+{
+ if (!session) return 0;
+
+ WORD retval = 0;
+ retval = (int)mwSession_getProperty(session, mwSession_CLIENT_VER_MAJOR) << 8;
+ retval |= (int)mwSession_getProperty(session, mwSession_CLIENT_VER_MINOR);
+ return retval;
+}
+
+WORD CSametimeProto::GetServerVersion()
+{
+ if (!session) return 0;
+
+ WORD retval = 0;
+ retval = (int)mwSession_getProperty(session, mwSession_SERVER_VER_MAJOR) << 8;
+ retval |= (int)mwSession_getProperty(session, mwSession_SERVER_VER_MINOR);
+ return retval;
+}
+
+int CSametimeProto::LogIn(int ls, HANDLE hNetlibUser)
+{
+ debugLog(_T("LogIn() start"));
+
+ EnterCriticalSection(&session_cs);
+ if (session) {
+ LeaveCriticalSection(&session_cs);
+ debugLog(_T("LogIn() end, currently in session"));
+ return 0;
+ }
+ LeaveCriticalSection(&session_cs);
+
+ login_status = ls;
+
+ mir_forkthread(SessionThread, (void*)this);
+
+ return 0;
+}
+
+int CSametimeProto::LogOut()
+{
+ debugLog(_T("LogOut() start"));
+ continue_connect = false;
+
+ EnterCriticalSection(&session_cs);
+ if (session && server_connection && m_iStatus != ID_STATUS_OFFLINE && !mwSession_isStopped(session) && !mwSession_isStopping(session)) {
+ debugLog(_T("LogOut() mwSession_stop"));
+ mwSession_stop(session, 0);
+ }
+ LeaveCriticalSection(&session_cs);
+
+ return 0;
+}
+
+void CSametimeProto::InitAwayMsg()
+{
+ AwayMessages.szOnline = 0;
+ AwayMessages.szAway = 0;
+ AwayMessages.szDND = 0;
+}
+
+void CSametimeProto::DeinitAwayMsg()
+{
+ mir_free(AwayMessages.szOnline);
+ mir_free(AwayMessages.szAway);
+ mir_free(AwayMessages.szDND);
+}
+
+void SendAnnouncement(SendAnnouncementFunc_arg* arg)
+{
+ CSametimeProto* proto = arg->proto;
+ char* utfs = mir_utf8encodeT(arg->msg);
+ if (proto->session && arg->recipients) mwSession_sendAnnounce(proto->session, false , utfs, arg->recipients);
+ mir_free(utfs);
+}
+
+INT_PTR CSametimeProto::SessionAnnounce(WPARAM wParam, LPARAM lParam)
+{
+ debugLog(_T("CSametimeProto::SessionAnnounce() start"));
+ SessionAnnounceDialogProc_arg* sadpArg = (SessionAnnounceDialogProc_arg*)mir_calloc(sizeof(SessionAnnounceDialogProc_arg));
+ sadpArg->proto = this;
+ sadpArg->sendAnnouncementFunc = SendAnnouncement;
+ CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_SESSIONANNOUNCE), GetDesktopWindow(), SessionAnnounceDialogProc, (LPARAM)sadpArg);
+ return 0;
+}
+
+void CSametimeProto::InitSessionMenu()
+{
+ debugLog(_T("CSametimeProto::InitSessionMenu()"));
+
+ CreateProtoService(MS_SAMETIME_MENUANNOUNCESESSION, &CSametimeProto::SessionAnnounce);
+
+ char service[128];
+
+ CLISTMENUITEM mi = { sizeof(mi) };
+ mi.flags = CMIF_TCHAR;
+ mi.popupPosition = 500085001;
+ mi.position = 2000060000;
+ mi.ptszName = LPGENT("Send Announcement...");
+ mir_snprintf(service, sizeof(service), "%s%s", m_szModuleName, MS_SAMETIME_MENUANNOUNCESESSION);
+ mi.pszService = service;
+ mi.icolibItem = GetIconHandle(IDI_ICON_ANNOUNCE);
+ mi.pszContactOwner = m_szModuleName;
+ hSessionAnnounceMenuItem = Menu_AddContactMenuItem(&mi);
+}
+
+void CSametimeProto::DeinitSessionMenu()
+{
+ debugLog(_T("CSametimeProto::DeinitSessionMenu()"));
+ CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hSessionAnnounceMenuItem, (LPARAM)0);
+}
+
+void CSametimeProto::InitCritSection()
+{
+ debugLog(_T("CSametimeProto::InitCritSection()"));
+ InitializeCriticalSection(&session_cs);
+}
+
+void CSametimeProto::DeinitCritSection()
+{
+ debugLog(_T("CSametimeProto::DeinitCritSection()"));
+ DeleteCriticalSection(&session_cs);
+}
+
+void CSametimeProto::InitGroupChats()
+{
+ debugLog(_T("CSametimeProto::InitGroupChats()"));
+
+ // register with chat module
+ GCREGISTER gcr = { sizeof(gcr) };
+ gcr.pszModule = m_szModuleName;
+ gcr.ptszDispName = m_tszUserName;
+ gcr.dwFlags = 0;
+ gcr.iMaxText = MAX_MESSAGE_SIZE;
+ gcr.nColors = 0;
+ gcr.pColors = 0;
+ CallService(MS_GC_REGISTER, 0, (LPARAM)(GCREGISTER*) &gcr);
+}
diff --git a/protocols/Sametime/src/session_announce_win.cpp b/protocols/Sametime/src/session_announce_win.cpp
new file mode 100644
index 0000000000..8cf9cecb8f
--- /dev/null
+++ b/protocols/Sametime/src/session_announce_win.cpp
@@ -0,0 +1,147 @@
+#include "StdAfx.h"
+#include "sametime.h"
+
+INT_PTR CALLBACK SessionAnnounceDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+
+ SessionAnnounceDialogProc_arg* arg = (SessionAnnounceDialogProc_arg*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ CSametimeProto* proto;
+ if (arg != NULL) proto = arg->proto;
+
+ switch(uMsg) {
+ case WM_INITDIALOG: {
+
+ TranslateDialogDefault(hwndDlg);
+
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
+ SessionAnnounceDialogProc_arg* arg = (SessionAnnounceDialogProc_arg*)lParam;
+ proto = arg->proto;
+ proto->debugLog(_T("SessionAnnounceDialogProc WM_INITDIALOG"));
+
+ SendMessage(GetDlgItem(hwndDlg, IDC_LST_ANTO),LVM_SETEXTENDEDLISTVIEWSTYLE, 0,LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES);
+
+ {
+ LVCOLUMN lvc;
+ // Initialize the LVCOLUMN structure.
+ // The mask specifies that the format, width, text, and
+ // subitem members of the structure are valid.
+ lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
+ lvc.fmt = LVCFMT_LEFT;
+
+ lvc.iSubItem = 0;
+ lvc.pszText = TranslateT("Recipients");
+ lvc.cx = 300; // width of column in pixels
+ ListView_InsertColumn(GetDlgItem(hwndDlg, IDC_LST_ANTO), 0, &lvc);
+ }
+
+ //enumerate plugins, fill in list
+ {
+ ListView_DeleteAllItems(GetDlgItem(hwndDlg, IDC_LST_ANTO));
+ LVITEM lvI;
+ // Some code to create the list-view control.
+ // Initialize LVITEM members that are common to all items.
+ lvI.mask = LVIF_TEXT | LVIF_PARAM;// | LVIF_NORECOMPUTE;// | LVIF_IMAGE;
+ lvI.iItem=0;
+ lvI.iSubItem=0;
+
+ for (MCONTACT hContact = db_find_first(proto->m_szModuleName); hContact; hContact = db_find_next(hContact, proto->m_szModuleName)) {
+ if (db_get_b(hContact, proto->m_szModuleName, "ChatRoom", 0) == 0
+ && db_get_w(hContact, proto->m_szModuleName, "Status", ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE)
+ {
+ lvI.lParam = (LPARAM)hContact;
+ lvI.pszText = (TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR);
+ ListView_InsertItem(GetDlgItem(hwndDlg, IDC_LST_ANTO), &lvI);
+ lvI.iItem++;
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ case WM_CLOSE:
+ proto->debugLog(_T("SessionAnnounceDialogProc WM_CLOSE"));
+ mir_free(arg);
+ DestroyWindow(hwndDlg);
+ break;
+
+ case WM_COMMAND:
+ if (HIWORD(wParam) == BN_CLICKED ) {
+ switch(LOWORD(wParam)) {
+
+ case IDC_BUT_SELALL: {
+ int size = ListView_GetItemCount(GetDlgItem(hwndDlg, IDC_LST_ANTO));
+ for (int i = 0; i < size; i++) ListView_SetCheckState(GetDlgItem(hwndDlg, IDC_LST_ANTO), i, true);
+ }
+ return 0;
+
+ case IDC_BUT_SELINV: {
+ int size = ListView_GetItemCount(GetDlgItem(hwndDlg, IDC_LST_ANTO));
+ for (int i = 0; i < size; i++)
+ ListView_SetCheckState(GetDlgItem(hwndDlg, IDC_LST_ANTO), i,
+ !ListView_GetCheckState(GetDlgItem(hwndDlg, IDC_LST_ANTO), i)
+ );
+ }
+ return 0;
+
+ case IDOK: {
+ proto->debugLog(_T("SessionAnnounceDialogProc IDOK BN_CLICKED"));
+ // build SendAnnouncementFunc_arg
+ SendAnnouncementFunc_arg* safArg = (SendAnnouncementFunc_arg*)mir_calloc(sizeof(SendAnnouncementFunc_arg));
+ DBVARIANT dbv;
+ LVITEM lvI = {0};
+
+ char id[1024];
+ strcpy(id, "@U"); // documentation says prepend '@U' to usernames and '@G' to notes group names - but
+ char *p = id + 2; // it's wrong - it works for a list of user id's with no prefix - so we'll do both
+
+ // build recipient list
+ safArg->recipients = 0;
+
+ int size = ListView_GetItemCount(GetDlgItem(hwndDlg, IDC_LST_ANTO));
+ int send_count = 0;
+ for (int i = 0; i < size; i++) {
+ if (ListView_GetCheckState(GetDlgItem(hwndDlg, IDC_LST_ANTO), i)) {
+ lvI.iItem = i;
+ lvI.iSubItem = 0;
+ lvI.mask = LVIF_PARAM;
+ ListView_GetItem(GetDlgItem(hwndDlg, IDC_LST_ANTO), &lvI);
+
+ if (!db_get_utf((MCONTACT)lvI.lParam, proto->m_szModuleName, "stid", &dbv)) {
+ safArg->recipients = g_list_prepend(safArg->recipients, _strdup(dbv.pszVal));
+ strcpy(p, dbv.pszVal);
+ safArg->recipients = g_list_prepend(safArg->recipients, _strdup(id));
+ send_count++;
+ db_free(&dbv);
+ }
+ }
+ }
+
+ if (send_count > 0) {
+ GetWindowText(GetDlgItem(hwndDlg, IDC_ED_ANMSG), safArg->msg, MAX_MESSAGE_SIZE);
+ safArg->proto = proto;
+ SendAnnouncementFunc sendAnnouncementFunc = arg->sendAnnouncementFunc;
+ sendAnnouncementFunc(safArg);
+ }
+
+ // clean up recipient list
+ if (safArg->recipients){
+ for (GList *rit = safArg->recipients; rit; rit = rit->next) {
+ free(rit->data);
+ }
+ g_list_free(safArg->recipients);
+ }
+
+ DestroyWindow(hwndDlg);
+ }
+ return 0;
+
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return 0;
+ }
+ }
+ break;
+ }
+
+ return 0;
+} \ No newline at end of file
diff --git a/protocols/Sametime/src/userlist.cpp b/protocols/Sametime/src/userlist.cpp
new file mode 100644
index 0000000000..89e11a0a81
--- /dev/null
+++ b/protocols/Sametime/src/userlist.cpp
@@ -0,0 +1,836 @@
+#include "StdAfx.h"
+#include "sametime.h"
+
+MCONTACT CSametimeProto::FindContactByUserId(const char* id)
+{
+ DBVARIANT dbv;
+ for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName)) {
+ if (!db_get_utf(hContact, m_szModuleName, "stid", &dbv)) {
+ if (dbv.pszVal && strcmp(id, dbv.pszVal) == 0) {
+ db_free(&dbv);
+ return hContact;
+ }
+ db_free(&dbv);
+ }
+ }
+ return 0;
+}
+
+bool CSametimeProto::GetAwareIdFromContact(MCONTACT hContact, mwAwareIdBlock* id_block)
+{
+ char* proto = (char*)CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact,0 );
+ DBVARIANT dbv;
+ if ( proto && !strcmp(m_szModuleName, proto)) {
+ if (!db_get_utf(hContact, m_szModuleName, "stid", &dbv)) {
+ if (dbv.pszVal) {
+ id_block->type = mwAware_USER;
+ id_block->user = _strdup(dbv.pszVal);
+ id_block->community = 0;
+ db_free(&dbv);
+ return true;
+ }
+ db_free(&dbv);
+ }
+ }
+ return false;
+}
+
+void CSametimeProto::SetContactGroup(MCONTACT hContact, const char* name)
+{
+ db_set_utf(hContact, "CList", "Group", name);
+}
+
+void CSametimeProto::AddGroup(const char* name, bool expanded)
+{
+ if (name && strcmp(name, "MetaContacts Hidden Group") == 0)
+ return;
+
+ if (name && strcmp(name, Translate("None")) == 0)
+ return;
+
+ ptrT ptszGroup(mir_utf8decodeT(name));
+ HANDLE hGroup = Clist_GroupExists(ptszGroup);
+ if (hGroup == NULL) {
+ hGroup = Clist_CreateGroup(NULL, ptszGroup);
+ if (hGroup) {
+ CallService(MS_CLUI_GROUPADDED, (WPARAM)hGroup, 0);
+ CallService(MS_CLIST_GROUPSETEXPANDED, (WPARAM)hGroup, expanded ? 1 : 0);
+ }
+ }
+}
+
+MCONTACT CSametimeProto::AddContact(mwSametimeUser* user, bool temporary)
+{
+
+ debugLog(_T("CSametimeProto::AddContact() start"));
+ const char* id = mwSametimeUser_getUser(user);
+ const char* name = mwSametimeUser_getShortName(user);
+ const char* nick = mwSametimeUser_getAlias(user);
+ //const char* nick = mwSametimeUser_getShortName(user);
+ mwSametimeUserType type = mwSametimeUser_getType(user);
+
+ MCONTACT hContact = FindContactByUserId(id);
+ bool new_contact = false;
+ if (!hContact) {
+ hContact = (MCONTACT)CallService(MS_DB_CONTACT_ADD, 0, 0);
+ if (!hContact) {
+ debugLog(_T("AddContact(): Failed to create Sametime contact"));
+ return NULL; ///TODO error handling
+ }
+ if (CallService(MS_PROTO_ADDTOCONTACT, (WPARAM) hContact, (LPARAM) m_szModuleName) != 0) {
+ CallService(MS_DB_CONTACT_DELETE, (WPARAM) hContact, 0);
+ debugLog(_T("AddContact(): Failed to register Sametime contact"));
+ return NULL; ///TODO error handling
+ }
+ new_contact = true;
+ } else if (!temporary) {
+ db_unset(hContact, "CList", "NotOnList");
+ db_unset(hContact, "CList", "Hidden");
+ }
+
+
+ // add to miranda
+ if (new_contact) db_set_utf(hContact, m_szModuleName, "stid", id);
+
+ if (name && strlen(name))
+ db_set_utf(hContact, m_szModuleName, "Name", name);
+
+ if (nick && strlen(nick)) {
+ db_set_utf(hContact, m_szModuleName, "Nick", nick);
+ } else if (name && strlen(name)) {
+ db_set_utf(hContact, m_szModuleName, "Nick", name);
+ } else {
+ db_set_utf(hContact, m_szModuleName, "Nick", id);
+ }
+
+ db_set_b(hContact, m_szModuleName, "type", (BYTE)type);
+
+ if (new_contact) {
+ //add to our awareness list
+ mwAwareIdBlock id_block;
+ if (GetAwareIdFromContact(hContact, &id_block)) {
+ GList* gl = g_list_prepend(NULL, &id_block);
+ mwAwareList_addAware(aware_list, gl);
+ g_list_free(gl);
+ free(id_block.user);
+ }
+ }
+
+ if (temporary) {
+ db_set_b(hContact, "CList", "NotOnList", 1);
+ db_set_b(hContact, "CList", "Hidden", 1);
+ } else {
+ db_unset(hContact, "CList", "NotOnList");
+ db_unset(hContact, "CList", "Hidden");
+ }
+
+ return hContact;
+}
+
+void CSametimeProto::ImportContactsFromList(mwSametimeList* user_list, bool temporary)
+{
+ debugLog(_T("CSametimeProto::ImportContactsFromList() start"));
+ // add contacts
+ mwSametimeGroup* stgroup;
+ mwSametimeUser* stuser;
+ GList *gl, *gtl, *ul, *utl;
+ const char* group_name;
+ const char* group_alias;
+ mwSametimeGroupType group_type;
+ bool group_open;
+
+ gl = gtl = mwSametimeList_getGroups(user_list);
+ for (; gl; gl = gl->next) {
+ char buff[256];
+ stgroup = (mwSametimeGroup*)gl->data;
+
+ group_name = mwSametimeGroup_getName(stgroup);
+ group_alias = mwSametimeGroup_getAlias(stgroup);
+ if (!group_alias) group_alias = group_name;
+
+ group_type = mwSametimeGroup_getType(stgroup);
+ group_open = (mwSametimeGroup_isOpen(stgroup) != 0);
+
+ mir_snprintf(buff, SIZEOF(buff), "GN_%s", group_alias);
+ db_set_utf(0, szProtoGroups, buff, group_name);
+ mir_snprintf(buff, SIZEOF(buff), "GT_%s", group_alias);
+ db_set_b(0, szProtoGroups, buff, (BYTE)group_type);
+ mir_snprintf(buff, SIZEOF(buff), "GO_%s", group_alias);
+ db_set_b(0, szProtoGroups, buff, (BYTE)(group_open ? 1 : 0));
+
+ // inverse mapping
+ mir_snprintf(buff, SIZEOF(buff), "GA_%s", group_name);
+ db_set_utf(0, szProtoGroups, buff, group_alias);
+
+ AddGroup(group_alias, group_open);
+
+ if (group_type == mwSametimeGroup_DYNAMIC) {
+ mwAwareIdBlock id_block;
+ id_block.type = mwAware_GROUP;
+ id_block.user = (char*)group_name;
+ id_block.community = 0;
+
+ GList* gl = g_list_prepend(NULL, &id_block);
+ mwAwareList_addAware(aware_list, gl);
+ g_list_free(gl);
+ }
+
+ ul = utl = mwSametimeGroup_getUsers(stgroup);
+ for (; ul; ul = ul->next) {
+ stuser = (mwSametimeUser*)ul->data;
+ MCONTACT hContact = AddContact(stuser, temporary);
+ if (hContact && group_alias && strcmp(group_alias, Translate("None")) != 0 && strcmp(group_alias, "MetaContacts Hidden Group") != 0) {
+ SetContactGroup(hContact, group_alias);
+ // mark contact as belonging to dynamic group
+ }
+ }
+ g_list_free(utl);
+ }
+ g_list_free(gtl);
+}
+
+void CSametimeProto::ExportContactsToList(mwSametimeList* user_list)
+{
+ debugLog(_T("CSametimeProto::ExportContactsToList() start"));
+ mwSametimeGroup* stgroup = 0;
+ char* group_name;
+ char* group_alias;
+ mwSametimeGroupType group_type;
+ bool group_open;
+
+ mwSametimeUser* stuser;
+ char* user_alias;
+ char* user_shortName;
+ mwSametimeUserType user_type;
+ DBVARIANT dbv, dbv2;
+ char buff[256];
+ mwAwareIdBlock id_block;
+ mwIdBlock uid;
+
+ GList* gl = 0;
+ for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName)) {
+ if (!db_get_utf(hContact, m_szModuleName, "stid", &dbv)) {
+ if (dbv.pszVal) {
+ if (GetAwareIdFromContact(hContact, &id_block)) {
+ if (!db_get_utf(hContact, "CList", "Group", &dbv2)) {
+ group_alias = _strdup(dbv2.pszVal);
+ db_free(&dbv2);
+ } else
+ group_alias = _strdup(Translate("None"));
+
+ if (group_alias) {
+ mir_snprintf(buff, SIZEOF(buff), "GT_%s", group_alias);
+ group_type = (mwSametimeGroupType)db_get_b(0, szProtoGroups, buff, (BYTE)mwSametimeGroup_NORMAL);
+ // apparently we don't want to upload contacts in dynamic groups - see gaim sametime plugin comments
+ if (group_type == mwSametimeGroup_DYNAMIC) {
+ db_free(&dbv);
+ free(id_block.user);
+ free(group_alias);
+ hContact = db_find_next(hContact, m_szModuleName);
+ continue;
+ }
+
+ mir_snprintf(buff, SIZEOF(buff), "GN_%s", group_alias);
+ if (!db_get_utf(0, szProtoGroups, buff, &dbv2)) {
+ group_name = _strdup(dbv2.pszVal);
+ db_free(&dbv2);
+ } else
+ group_name = _strdup(group_alias);
+
+ //group_open = (db_get_b(0, szProtoGroups, buff, 0) == 1);
+
+ ptrT ptszGroup(mir_utf8decodeT(group_alias));
+ HANDLE hGroup = Clist_GroupExists(ptszGroup);
+ if (hGroup) {
+ int expanded;
+ CallService(MS_CLIST_GROUPGETNAME, (WPARAM)hGroup, (LPARAM)&expanded);
+ group_open = (expanded != 0);
+ } else {
+ mir_snprintf(buff, SIZEOF(buff), "GO_%s", group_alias);
+ group_open = (db_get_b(0, szProtoGroups, buff, 0) == 1);
+ }
+
+ stgroup = 0;
+ stgroup = mwSametimeList_findGroup(user_list, group_name);
+ if (!stgroup) {
+ if (group_name) stgroup = mwSametimeGroup_new(user_list, group_type, group_name);
+ mwSametimeGroup_setAlias(stgroup, group_alias);
+ mwSametimeGroup_setOpen(stgroup, group_open);
+ }
+
+ free(group_name);
+ free(group_alias);
+
+ if (!db_get_utf(hContact, m_szModuleName, "Name", &dbv2)) {
+ user_shortName = _strdup(dbv2.pszVal);
+ db_free(&dbv2);
+ } else
+ user_shortName = 0;
+
+ if (!db_get_utf(hContact, "CList", "MyHandle", &dbv2)) {
+ user_alias = _strdup(dbv2.pszVal);
+ db_free(&dbv2);
+ } else
+ user_alias = 0;
+
+ user_type = (mwSametimeUserType)db_get_b(hContact, m_szModuleName, "type", (BYTE)mwSametimeUser_NORMAL);
+
+ uid.user = id_block.user;
+ uid.community = id_block.community;
+
+ stuser = mwSametimeUser_new(stgroup, user_type, &uid);
+ if (user_shortName) {
+ mwSametimeUser_setShortName(stuser, user_shortName);
+ free(user_shortName);
+ }
+ if (user_alias) {
+ mwSametimeUser_setAlias(stuser, user_alias);
+ free(user_alias);
+ }
+ }
+
+ free(id_block.user);
+ }
+ }
+ db_free(&dbv);
+ }
+ }
+}
+
+void CSametimeProto::ImportContactsFromFile(TCHAR* filename)
+{
+ debugLog(_T("CSametimeProto::ImportContactsFromFile() start"));
+ std::ifstream in(filename);
+ std::string text;
+ std::string line;
+ if (in.is_open()) {
+ while(!in.eof()) {
+ std::getline(in, line);
+ text += line;
+ text += "\r\n";
+ }
+ in.close();
+
+ mwSametimeList* new_list = mwSametimeList_load(text.c_str());
+ ImportContactsFromList(new_list, false);
+ mwSametimeList_free(new_list);
+
+ }
+}
+
+void CSametimeProto::ExportContactsToServer()
+{
+ mwSametimeList* user_list;
+ mwStorageUnit* unit;
+ mwPutBuffer* buff;
+ mwOpaque* op;
+
+ debugLog(_T("CSametimeProto::ExportContactsToServer() start"));
+ if (MW_SERVICE_IS_DEAD(service_storage)) {
+ debugLog(_T("CSametimeProto::ExportContactsToServer() Failed"));
+ showPopup(TranslateT("Failed to upload contacts - Storage service unavailable."), SAMETIME_POPUP_ERROR);
+ return;
+ }
+
+ user_list = mwSametimeList_new();
+ ExportContactsToList(user_list);
+
+ buff = mwPutBuffer_new();
+ mwSametimeList_put(buff, user_list);
+ mwSametimeList_free(user_list);
+
+ /* put the buffer contents into a storage unit */
+ unit = mwStorageUnit_new(mwStore_AWARE_LIST);
+ op = mwStorageUnit_asOpaque(unit);
+ mwPutBuffer_finalize(op, buff);
+
+ /* save the storage unit to the service */
+ mwServiceStorage_save(service_storage, unit, NULL, NULL, NULL);
+}
+
+
+CSametimeProto* getProtoFromMwServiceStorage(mwServiceStorage* srvcStorage)
+{
+ mwService* service = mwServiceStorage_getService(srvcStorage);
+ mwSession* session = mwService_getSession(service);
+ return (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
+}
+
+void load_users_callback(mwServiceStorage* srvc, guint32 result, mwStorageUnit *item, gpointer data)
+{
+ CSametimeProto* proto = getProtoFromMwServiceStorage(srvc);
+
+ if (mwStorageUnit_getKey(item) == mwStore_AWARE_LIST) {
+ mwGetBuffer *buff = mwGetBuffer_wrap(mwStorageUnit_asOpaque(item));
+ if (mwGetBuffer_remaining(buff)) {
+ mwSametimeList* user_list = mwSametimeList_new();
+ mwSametimeList_get(buff, user_list);
+ proto->ImportContactsFromList(user_list, false);
+ mwSametimeList_free(user_list);
+ }
+ }
+}
+
+void CSametimeProto::UserListAddStored()
+{
+ mwStorageUnit* unit;
+ unit = mwStorageUnit_new(mwStore_AWARE_LIST);
+ mwServiceStorage_load(service_storage, unit, &load_users_callback, (gpointer)this, 0);
+}
+
+int CSametimeProto::ContactDeleted(MCONTACT hContact)
+{
+ mwAwareIdBlock id_block;
+
+ if (db_get_b(hContact, m_szModuleName, "ChatRoom", 0))
+ return 0;
+
+ debugLog(_T("CSametimeProto::ContactDeleted()"));
+
+ if (GetAwareIdFromContact(hContact, &id_block)) {
+ GList* gl = g_list_prepend(NULL, &id_block);
+ mwAwareList_removeAware(aware_list, gl);
+ g_list_free(gl);
+ free(id_block.user);
+ }
+
+ return 0;
+}
+
+CSametimeProto* getProtoFromMwServiceResolve(mwServiceResolve* srvcResolve)
+{
+ mwService* service = mwServiceResolve_getService(srvcResolve);
+ mwSession* session = mwService_getSession(service);
+ return (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
+}
+
+
+void mwResolve_handler_dyngroup_callback(mwServiceResolve* srvc, guint32 id, guint32 code, GList *results, gpointer data)
+{
+ CSametimeProto* proto = getProtoFromMwServiceResolve(srvc);
+ mwSametimeGroup* stgroup = (mwSametimeGroup*)data;
+
+ mwResolveResult* result;
+ mwResolveMatch* match;
+ g_return_if_fail(results != NULL);
+
+ if (results) {
+ result = (mwResolveResult*)results->data;
+ if (result && result->matches) {
+
+ match = (mwResolveMatch*)result->matches->data;
+ if (match) {
+ mwIdBlock uid;
+ uid.user = match->id;
+ uid.community = 0;
+ mwSametimeUser *stuser = mwSametimeUser_new(stgroup, mwSametimeUser_NORMAL, &uid);
+ mwSametimeUser_setShortName(stuser, match->name);
+
+ MCONTACT hContact = proto->AddContact(stuser, false);
+
+ const char* group_name = mwSametimeGroup_getName(stgroup);
+ const char* group_alias = mwSametimeGroup_getAlias(stgroup);
+ if (!group_alias) group_alias = group_name;
+ if (hContact && group_alias && strcmp(group_alias, Translate("None")) && strcmp(group_alias, "MetaContacts Hidden Group")) {
+ proto->SetContactGroup(hContact, group_alias);
+ }
+ }
+ }
+ }
+
+ if (stgroup)
+ mwSametimeList_free(mwSametimeGroup_getList(stgroup));
+}
+
+
+CSametimeProto* getProtoFromMwAwareList(mwAwareList* list)
+{
+ mwServiceAware* servAwere = mwAwareList_getServiceAware(list);
+ mwService* service = mwServiceAware_getService(servAwere);
+ mwSession* session = mwService_getSession(service);
+ return (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
+}
+
+void mwAwareList_on_aware(mwAwareList* list, mwAwareSnapshot* aware)
+{
+ CSametimeProto* proto = getProtoFromMwAwareList(list);;
+
+ MCONTACT hContact = proto->FindContactByUserId(aware->id.user);
+ char* group = 0;
+ DBVARIANT dbv;
+
+ // update self - necessary for some servers
+ if (aware->online && !db_get_utf(0, proto->m_szModuleName, "stid", &dbv) && strcmp(aware->id.user, dbv.pszVal) == 0) {
+ int new_status = ID_STATUS_OFFLINE;
+
+ switch(aware->status.status) {
+ case mwStatus_ACTIVE:
+ new_status = ID_STATUS_ONLINE;
+ break;
+ case mwStatus_AWAY:
+ new_status = ID_STATUS_AWAY;
+ break;
+ case mwStatus_IDLE:
+ new_status = ID_STATUS_IDLE;
+ break;
+ case mwStatus_BUSY:
+ new_status = ID_STATUS_DND;
+ break;
+ }
+ if (new_status != ID_STATUS_IDLE) //SetSessionStatus(new_status);
+ proto->UpdateSelfStatus();
+
+ db_free(&dbv);
+ }
+
+ if (hContact && !db_get_utf(hContact, "CList", "Group", &dbv)) {
+ group = _strdup(dbv.pszVal);
+ db_free(&dbv);
+ }
+
+ if (aware->group && (!group || strcmp(aware->group, group) || !hContact)) {
+ // dynamic group member we're not already aware of
+ // resolve server alias to user id via resolver
+ mwSametimeList* user_list = mwSametimeList_new();
+ mwSametimeGroup* stgroup = mwSametimeGroup_new(user_list, mwSametimeGroup_DYNAMIC, aware->group);
+ char buff[256];
+ mir_snprintf(buff, SIZEOF(buff), "GA_%s", aware->group);
+ if (!db_get_utf(0, proto->szProtoGroups, buff, &dbv)) {
+ mwSametimeGroup_setAlias(stgroup, dbv.pszVal);
+ db_free(&dbv);
+ }
+
+ GList* query = g_list_prepend(0, (void*)aware->id.user);
+ mwServiceResolve_resolve(proto->service_resolve, query, mwResolveFlag_USERS, mwResolve_handler_dyngroup_callback, (gpointer)stgroup, 0);
+ g_list_free(query);
+
+ } else if (hContact) {
+
+ if (aware->online) {
+ int new_status = ID_STATUS_OFFLINE;
+
+ switch(aware->status.status) {
+ case mwStatus_ACTIVE:
+ new_status = ID_STATUS_ONLINE;
+ db_set_dw(hContact, proto->m_szModuleName, "IdleTS", 0);
+ db_set_w(hContact, proto->m_szModuleName, "Status", new_status);
+ break;
+ case mwStatus_AWAY:
+ new_status = ID_STATUS_AWAY;
+ db_set_dw(hContact, proto->m_szModuleName, "IdleTS", 0);
+ db_set_w(hContact, proto->m_szModuleName, "Status", new_status);
+ break;
+ case mwStatus_IDLE:
+ if (proto->options.idle_as_away) {
+ new_status = ID_STATUS_AWAY;
+ db_set_w(hContact, proto->m_szModuleName, "Status", new_status);
+ }
+ db_set_dw(hContact, proto->m_szModuleName, "IdleTS", (DWORD)time(0));
+ break;
+ case mwStatus_BUSY:
+ new_status = ID_STATUS_DND;
+ db_set_w(hContact, proto->m_szModuleName, "Status", new_status);
+ db_set_dw(hContact, proto->m_szModuleName, "IdleTS", 0);
+ break;
+ }
+ } else
+ db_set_w(hContact, proto->m_szModuleName, "Status", ID_STATUS_OFFLINE);
+
+ if (proto->service_aware) {
+ const char* desc = mwServiceAware_getText(proto->service_aware, &aware->id);
+ if (desc)
+ //db_set_utf(hContact, m_szModuleName, "StatusMsg", desc);
+ db_set_utf(hContact, "CList", "StatusMsg", desc);
+ else
+ //db_set_utf(hContact, m_szModuleName, "StatusMsg", "");
+ //db_unset(hContact, m_szModuleName, "StatusMsg");
+ db_unset(hContact, "CList", "StatusMsg");
+ }
+ }
+
+ if (group) free(group);
+}
+
+
+void mwAwareList_on_attrib(mwAwareList* list, mwAwareIdBlock* id, mwAwareAttribute* attrib)
+{
+}
+
+
+void mwAwareList_clear(mwAwareList* list)
+{
+}
+
+
+mwAwareListHandler mwAwareList_handler = {
+ &mwAwareList_on_aware,
+ &mwAwareList_on_attrib,
+ &mwAwareList_clear
+};
+
+
+void CSametimeProto::UserListCreate()
+{
+ debugLog(_T("CSametimeProto::UserListCreate() start"));
+ mwServiceAware_unsetAttribute(service_aware, mwAttribute_SPEAKERS);
+ mwServiceAware_unsetAttribute(service_aware, mwAttribute_MICROPHONE);
+ mwServiceAware_unsetAttribute(service_aware, mwAttribute_VIDEO_CAMERA);
+ mwServiceAware_setAttributeBoolean(service_aware, mwAttribute_AV_PREFS_SET, TRUE);
+ mwServiceAware_setAttributeBoolean(service_aware, mwAttribute_FILE_TRANSFER, TRUE);
+
+ aware_list = mwAwareList_new(service_aware, &mwAwareList_handler);
+
+ // add all contacts
+
+ DBVARIANT dbv;
+ mwAwareIdBlock id_block;
+ GList *gl = 0;
+
+ for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName)) {
+ if (db_get_b(hContact, m_szModuleName, "ChatRoom", 0) == 0 /*&& proto && !strcmp( PROTO, proto)*/) {
+ if (!db_get_utf(hContact, m_szModuleName, "stid", &dbv)) {
+ if (dbv.pszVal) {
+ if (GetAwareIdFromContact(hContact, &id_block)) {
+ // add user to aware list
+ gl = g_list_prepend(0, &id_block);
+ mwAwareList_addAware(aware_list, gl);
+ free(id_block.user);
+ g_list_free(gl);
+ }
+ }
+ db_free(&dbv);
+ }
+ }
+ }
+
+ // add self - might be necessary for some servers
+ if (!db_get_utf(0, m_szModuleName, "stid", &dbv)) {
+ id_block.type = mwAware_USER;
+ id_block.user = dbv.pszVal;
+ id_block.community = 0;
+
+ gl = g_list_prepend(0, &id_block);
+ mwAwareList_addAware(aware_list, gl);
+ g_list_free(gl);
+
+ db_free(&dbv);
+ }
+}
+
+void CSametimeProto::UserListDestroy()
+{
+ mwAwareList_free(aware_list);
+ aware_list = 0;
+}
+
+void CSametimeProto::UserRecvAwayMessage(MCONTACT hContact)
+{
+ debugLog(_T("CSametimeProto::UserRecvAwayMessage() start hContact=[%x]"), hContact);
+ DBVARIANT dbv;
+ if (!db_get_s((MCONTACT)hContact, "CList", "StatusMsg", &dbv, DBVT_TCHAR)) {
+ ProtoBroadcastAck((MCONTACT)hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)dbv.ptszVal);
+ db_free(&dbv);
+ } else {
+ ProtoBroadcastAck((MCONTACT)hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)NULL);
+ }
+}
+
+void mwResolve_handler_callback(mwServiceResolve* srvc, guint32 id, guint32 code, GList* results, gpointer data)
+{
+ CSametimeProto* proto = getProtoFromMwServiceResolve(srvc);
+ BOOL advanced = (BOOL)data;
+
+ MYCUSTOMSEARCHRESULTS mcsr = {0};
+ mcsr.nSize = sizeof(MYCUSTOMSEARCHRESULTS);
+ //MYPROTOSEARCHRESULT mpsr = {0};
+ //mpsr.cbSize = sizeof(MYPROTOSEARCHRESULT);
+ mcsr.psr.nick = mcsr.psr.name;
+
+ mcsr.nFieldCount = 4;
+ TCHAR fields[4][512];
+ TCHAR *fields_addr[4];
+ mcsr.pszFields = fields_addr;
+ mcsr.pszFields[0] = fields[0];
+ mcsr.pszFields[1] = fields[1];
+ mcsr.pszFields[2] = fields[2];
+ mcsr.pszFields[3] = fields[3];
+
+ if (advanced == TRUE) {
+ // send column names
+ mcsr.psr.cbSize = 0;
+ _tcsncpy(mcsr.pszFields[0], TranslateT("Id"), 512);
+ _tcsncpy(mcsr.pszFields[1], TranslateT("Name"), 512);
+ _tcsncpy(mcsr.pszFields[2], TranslateT("Description"), 512);
+ _tcsncpy(mcsr.pszFields[3], TranslateT("Group?"), 512);
+ proto->ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SEARCHRESULT, (HANDLE)id, (LPARAM)&mcsr);
+ }
+
+ mcsr.psr.cbSize = sizeof(MYPROTOSEARCHRESULT);
+
+ if (code == mwResolveCode_SUCCESS) {
+ GList *ri = results, *mri;
+ for (;ri;ri = ri->next) {
+ mri = ((mwResolveResult *)ri->data)->matches;
+ for (;mri;mri = mri->next) {
+ strncpy(mcsr.psr.stid, ((mwResolveMatch *)mri->data)->id, 256);
+ mcsr.psr.stid[255] = 0;
+ MultiByteToWideChar(CP_UTF8, 0, mcsr.psr.stid, -1, mcsr.pszFields[0], 512);
+
+ strncpy(mcsr.psr.name, ((mwResolveMatch *)mri->data)->name, 256);
+ mcsr.psr.name[255] = 0;
+ MultiByteToWideChar(CP_UTF8, 0, mcsr.psr.name, -1, mcsr.pszFields[1], 512);
+
+ if (((mwResolveMatch *)mri->data)->desc)
+ MultiByteToWideChar(CP_UTF8, 0, ((mwResolveMatch *)mri->data)->desc, -1, mcsr.pszFields[2], 512);
+ else
+ mcsr.pszFields[2][0] = 0;
+
+ mcsr.psr.group = (((mwResolveMatch *)mri->data)->type == mwResolveMatch_GROUP);
+ //MultiByteToWideChar(CP_UTF8, 0, mcsr.psr.name, -1, mcsr.pszFields[1], 512);
+ _tcsncpy(mcsr.pszFields[3], mcsr.psr.group ? TranslateT("True") : TranslateT("False"), 512);
+
+ if (advanced == TRUE)
+ proto->ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SEARCHRESULT, (HANDLE)id, (LPARAM)&mcsr);
+ else
+ proto->ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)id, (LPARAM)&mcsr.psr);
+ }
+ }
+ proto->ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)id, 0);
+ }
+}
+
+
+void mwResolve_handler_details_callback(mwServiceResolve* srvc, guint32 id, guint32 code, GList* results, gpointer data)
+{
+ CSametimeProto* proto = getProtoFromMwServiceResolve(srvc);
+
+ MYPROTOSEARCHRESULT mpsr = {0};
+ mpsr.cbSize = sizeof(mpsr);
+ mpsr.nick = mpsr.name;
+
+ if (code == mwResolveCode_SUCCESS) {
+ GList *ri = results, *mri;
+ for (;ri;ri = ri->next) {
+ mri = ((mwResolveResult *)ri->data)->matches;
+ for (;mri;mri = mri->next) {
+
+ MCONTACT hContact = proto->FindContactByUserId(((mwResolveMatch*)mri->data)->id);
+ if (hContact) {
+ char* name = ((mwResolveMatch*)mri->data)->name;
+ if (name && strlen(name)) {
+ db_set_utf(hContact, proto->m_szModuleName, "Name", name);
+ db_set_utf(hContact, proto->m_szModuleName, "Nick", name);
+ db_set_utf(hContact, "CList", "MyHandle", name);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+int CSametimeProto::SearchForUser(const char* name, BOOLEAN advanced)
+{
+ if (m_iStatus != ID_STATUS_OFFLINE && service_resolve) {
+ GList *query = g_list_prepend(0, (void*)name);
+ guint32 id = mwServiceResolve_resolve(service_resolve, query, (mwResolveFlag)(mwResolveFlag_USERS | mwResolveFlag_GROUPS), &mwResolve_handler_callback, (gpointer)advanced, 0);
+ g_list_free(query);
+ return id; // search handle
+ }
+ return 0; // fail
+}
+
+
+int CSametimeProto::GetMoreDetails(const char* name)
+{
+ if (m_iStatus != ID_STATUS_OFFLINE && service_resolve) {
+ GList *query = g_list_prepend(0, (void *)name);
+ guint32 id = mwServiceResolve_resolve(service_resolve, query, (mwResolveFlag)(mwResolveFlag_USERS | mwResolveFlag_UNIQUE), &mwResolve_handler_details_callback, NULL, 0);
+ g_list_free(query);
+ return id; // search handle
+ }
+ return 0; // fail
+}
+
+
+INT_PTR CALLBACK CALLBACK SearchDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault(hwndDlg);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+MCONTACT CSametimeProto::AddSearchedUser(MYPROTOSEARCHRESULT* mpsr, bool temporary)
+{
+ MCONTACT hContact = 0;
+ debugLog(_T("CSametimeProto::AddSearchedUser() start"));
+ mwSametimeList* user_list = mwSametimeList_new();
+ mwSametimeGroup* stgroup = 0;
+ if (mpsr->group) {
+ stgroup = mwSametimeGroup_new(user_list, mwSametimeGroup_DYNAMIC, mpsr->stid);
+ mwSametimeGroup_setAlias(stgroup, mpsr->name);
+ ImportContactsFromList(user_list, temporary);
+ } else {
+ stgroup = mwSametimeGroup_new(user_list, mwSametimeGroup_NORMAL, Translate("None"));
+
+ mwIdBlock uid;
+ uid.user = mpsr->stid;
+ uid.community = 0;
+ mwSametimeUser *stuser = mwSametimeUser_new(stgroup, mwSametimeUser_NORMAL, &uid);
+ mwSametimeUser_setShortName(stuser, mpsr->name);
+
+ hContact = AddContact(stuser, temporary);
+ mwSametimeList_free(mwSametimeGroup_getList(stgroup));
+ }
+
+ return hContact;
+}
+
+
+void mwServiceAware_on_attrib_callback(mwServiceAware* srvc, mwAwareAttribute* attrib)
+{
+}
+
+void mwServiceAware_clear_callback(mwServiceAware* srvc)
+{
+}
+
+
+void CSametimeProto::InitUserList()
+{
+ debugLog(_T("CSametimeProto::InitUserList()"));
+
+ mwSession_addService(session, (mwService*)(service_storage = mwServiceStorage_new(session)));
+ mwSession_addService(session, (mwService*)(service_resolve = mwServiceResolve_new(session)));
+
+ mwAwareHandler mwAware_handler = {
+ &mwServiceAware_on_attrib_callback,
+ &mwServiceAware_clear_callback
+ };
+ mwSession_addService(session, (mwService*)(service_aware = mwServiceAware_new(session, &mwAware_handler)));
+
+}
+
+void CSametimeProto::DeinitUserList()
+{
+ debugLog(_T("CSametimeProto::DeinitUserList()"));
+
+ mwSession_removeService(session, mwService_AWARE);
+ mwService_free((mwService*)service_aware);
+ service_aware = 0;
+
+ mwSession_removeService(session, mwService_RESOLVE);
+ mwService_free((mwService*)service_resolve);
+ service_resolve = 0;
+
+ mwSession_removeService(session, mwService_STORAGE);
+ mwService_free((mwService*)service_storage);
+ service_storage = 0;
+}
+
diff --git a/protocols/Sametime/src/utils.cpp b/protocols/Sametime/src/utils.cpp
new file mode 100644
index 0000000000..40e23fbe4a
--- /dev/null
+++ b/protocols/Sametime/src/utils.cpp
@@ -0,0 +1,170 @@
+#include "StdAfx.h"
+#include "sametime.h"
+
+
+LRESULT CALLBACK PopupWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_COMMAND:
+ {
+ PUDeletePopup(hWnd);
+ break;
+ }
+
+ case WM_CONTEXTMENU:
+ PUDeletePopup(hWnd);
+ break;
+
+ case UM_FREEPLUGINDATA:
+ {
+ PopupData* puData = (PopupData*)PUGetPluginData(hWnd);
+ if (puData != NULL && puData != (PopupData*)CALLSERVICE_NOTFOUND)
+ {
+ mir_free(puData->title);
+ mir_free(puData->text);
+ mir_free(puData);
+ }
+ break;
+ }
+ }
+
+ return DefWindowProc(hWnd, msg, wParam, lParam);
+}
+
+
+void CSametimeProto::RegisterPopups()
+{
+ TCHAR szDescr[256];
+ char szName[256];
+
+ debugLog(_T("CSametimeProto::RegisterPopups()"));
+
+ POPUPCLASS puc = { sizeof(puc) };
+ puc.PluginWindowProc = PopupWindowProc;
+ puc.flags = PCF_TCHAR;
+ puc.ptszDescription = szDescr;
+ puc.pszName = szName;
+
+ mir_snprintf(szName, SIZEOF(szName), "%s_%s", m_szModuleName, "Notify");
+ mir_sntprintf(szDescr, SIZEOF(szDescr), _T("%s/%s"), m_tszUserName, TranslateT("Notification"));
+ puc.hIcon = CopyIcon(LoadIconEx("notify", FALSE));
+ ReleaseIconEx("notify", FALSE);
+ puc.iSeconds = 8;
+ puc.colorBack = GetSysColor(COLOR_BTNFACE);
+ puc.colorText = GetSysColor(COLOR_WINDOWTEXT);
+ hPopupNotify = Popup_RegisterClass(&puc);
+
+ mir_snprintf(szName, SIZEOF(szName), "%s_%s", m_szModuleName, "Error");
+ mir_sntprintf(szDescr, SIZEOF(szDescr), _T("%s/%s"), m_tszUserName, TranslateT("Error"));
+ puc.hIcon = CopyIcon(LoadIconEx("error", FALSE));
+ ReleaseIconEx("error", FALSE);
+ puc.iSeconds = 10;
+ puc.colorBack = GetSysColor(COLOR_BTNFACE);
+ puc.colorText = GetSysColor(COLOR_WINDOWTEXT);
+ hPopupError = Popup_RegisterClass(&puc);
+
+}
+
+
+void CSametimeProto::UnregisterPopups()
+{
+ debugLog(_T("CSametimeProto::RegisterPopups()"));
+ Popup_UnregisterClass(hPopupError);
+ Popup_UnregisterClass(hPopupNotify);
+}
+
+
+void CALLBACK sttMainThreadCallback(PVOID dwParam)
+{
+
+ PopupData* puData = (PopupData*)dwParam;
+ CSametimeProto* proto = puData->proto;
+
+ ErrorDisplay disp = proto->options.err_method;
+ // funny logic :) ... try to avoid message boxes
+ // if want baloons but no balloons, try popups
+ // if want popups but no popups, try baloons
+ // if, after that, you want balloons but no balloons, revert to message boxes
+ if (disp == ED_BAL && !ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) disp = ED_POP;
+ if (disp == ED_POP && !ServiceExists(MS_POPUP_ADDPOPUPCLASS)) disp = ED_BAL;
+ if (disp == ED_BAL && !ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) disp = ED_MB;
+
+ if (disp == ED_POP){
+
+ POPUPDATACLASS ppd = {sizeof(ppd)};
+ char szName[256];
+ ppd.ptszTitle = puData->title;
+ ppd.ptszText = puData->text;
+ if (puData->flag == SAMETIME_POPUP_ERROR){
+ mir_snprintf(szName, SIZEOF(szName), "%s_%s", proto->m_szModuleName, "Error");
+ } else {
+ mir_snprintf(szName, SIZEOF(szName), "%s_%s", proto->m_szModuleName, "Notify");
+ }
+ CallService(MS_POPUP_ADDPOPUPCLASS, 0, (LPARAM)&ppd);
+
+ } else if (disp == ED_BAL) {
+
+ MIRANDASYSTRAYNOTIFY sn = { sizeof(sn) };
+ sn.szProto = proto->m_szModuleName;
+ sn.tszInfoTitle = puData->title;
+ sn.tszInfo = puData->text;
+ sn.dwInfoFlags = NIIF_INTERN_UNICODE;
+ if (puData->flag == SAMETIME_POPUP_ERROR){
+ sn.dwInfoFlags = sn.dwInfoFlags | NIIF_WARNING;
+ sn.uTimeout = 1000 * 10;
+ } else {
+ sn.dwInfoFlags = sn.dwInfoFlags | NIIF_INFO;
+ sn.uTimeout = 1000 * 8;
+ }
+ CallService(MS_CLIST_SYSTRAY_NOTIFY, 0, (LPARAM)&sn);
+
+ } else { //disp == ED_MB
+
+ if (puData->flag == SAMETIME_POPUP_ERROR){
+ MessageBox(NULL, puData->text, puData->title, MB_OK | MB_ICONWARNING);
+ } else {
+ MessageBox(NULL, puData->text, puData->title, MB_OK | MB_ICONINFORMATION);
+ }
+
+ }
+
+ if (disp != ED_POP){
+ mir_free(puData->title);
+ mir_free(puData->text);
+ mir_free(puData);
+ }
+
+}
+
+void CSametimeProto::showPopup(const TCHAR* msg, SametimePopupEnum flag)
+{
+ if (Miranda_Terminated()) return;
+
+ PopupData *puData = (PopupData*)mir_calloc(sizeof(PopupData));
+ puData->flag = flag;
+ puData->title = mir_tstrdup(m_tszUserName);
+ puData->text = mir_tstrdup(msg);
+ puData->proto = this;
+
+ CallFunctionAsync(sttMainThreadCallback, puData);
+}
+
+
+void LogFromGLib(const gchar* log_domain, GLogLevelFlags log_level, const gchar* message, gpointer user_data)
+{
+ CSametimeProto* proto = (CSametimeProto*)user_data;
+ proto->debugLog(_A2T(message));
+}
+
+void CSametimeProto::RegisterGLibLogger()
+{
+ debugLog(_T("CSametimeProto::RegisterGLibLogger"));
+ gLogHandler = g_log_set_handler(G_LOG_DOMAIN, G_LOG_LEVEL_MASK, LogFromGLib, this);
+}
+
+void CSametimeProto::UnRegisterGLibLogger()
+{
+ debugLog(_T("CSametimeProto::UnRegisterGLibLogger"));
+ if (gLogHandler) g_log_remove_handler(G_LOG_DOMAIN, gLogHandler);
+}
diff --git a/protocols/Sametime/src/version.h b/protocols/Sametime/src/version.h
new file mode 100644
index 0000000000..c66789c5b1
--- /dev/null
+++ b/protocols/Sametime/src/version.h
@@ -0,0 +1,13 @@
+#define __MAJOR_VERSION 0
+#define __MINOR_VERSION 7
+#define __RELEASE_NUM 0
+#define __BUILD_NUM 0
+
+#include <stdver.h>
+
+#define __PLUGIN_NAME "Sametime Protocol"
+#define __DESCRIPTION "Implementation of Instant Messaging for the Lotus Sametime protocol."
+#define __AUTHOR "Scott Ellis, Szymon Tokarz"
+#define __AUTHOREMAIL "mail"/*antispam*/"@"/*antispam*/"scottellis.com.au, wsx22"/*antispam*/"@"/*antispam*/"o2.pl"
+#define __COPYRIGHT "© 2005 Scott Ellis, 2014 wsx22"
+#define __AUTHORWEB "http://miranda-ng.org/p/Sametime/" \ No newline at end of file