1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
|
{
Miranda IM: the free IM client for Microsoft* Windows*
Copyright 2000-2006 Miranda ICQ/IM project,
all portions of this codebase are copyrighted to the people
listed in contributors.txt.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
}
{$IFNDEF M_SESSION}
{$DEFINE M_SESSION}
// Pipe Messages
{
szEntity=szUI, szProto (always != NULL)
hSession=yes
A new entity handle is about to be created to bind .szUI for usage by .szProto,
note that this handle is not yet in the handle list and the .szProto will
get the message first, then the .szUI will.
.szUI must set up any instance data within the given hSession,
this is done with Sion_EntityCookieSet(hSession,SDR_UI,data).
.szProto may also set up data to associate with the given hSession,
this is done with Sion_EntityCookieSet(hSession,SDR_PROTO,data);
This message is always sent from the main thread (a thread context switch
occurs if needed).
}
const
ENTITY_CREATE = 1;
ENTITY_DESTROY = 2;
// Services/Hooks
{ either .dwTo, dwFrom may have an SDR_* type, and SDR_* flag }
SDR_ALL = 1;
SDR_SION = 2;
SDR_PROTO = 3;
SDR_UI = 4;
{ you may extend this structure but .cbSize must stay and the reserved data
at the end of the structure must not be rewritten into }
type
PIPE_DATA = record
cbSize :int;
szEntity:PAnsiChar; // can be NULL
hSession:THANDLE; // ""
dwMsg :DWORD;
dwTo :DWORD
dwFrom :DWORD; // SDR_*, SDR_ALL is not a good thing
wParam :WPARAM;
lParam :LPARAM;
reserved[0..1] of DWORD; // is actually apart of the structure and is used internally
end;
{
wParam=0
lParam=(LPARAM)&PIPE_DATA
Issue a call to an entity by name, type or to everyone, if you send
a message to an entity by name, e.g. "ICQ" it will only goto "ICQ" and not
to anyone else.
}
const
MS_SION_PIPE = 'Sion/PipeCall';
{
wParam=0
lParam=(LPARAM)&PIPE_DATA
Begin your lovely relationship with everyone else who began a relationship
before you, uh.. fill a pipe data structure and call this service :
struct PIPE_DATA pd;
pd.cbSize=sizeof(pd);
pd.dwTo=SDR_PROTO;
pd.szEntity="ICQ";
pd.lParam=(MIRANDASERVICE)MyCallback;
CallService(MS_SION_PIPEHOOK,0,(LPARAM)&pd);
The service returns 0 on success and non zero on failure, once you have registered either as a UI or a protocol
your MIRANDASERVICE will be called on the event on a pipe message that is
either directed to your entity name (.szEntity!=NULL) or by SDR_* type.
Note that the entity name may not be yours, but the pipe system may of been
instructed to issue the call with the caller's entity name given to you, because
you know what your entity name is already, you should not rely on .szEntity
being anything, but if it is there, the message is for you only and no one else
will get it and the value of .szEntity is dependant on the message.
}
MS_SION_PIPEHOOK = 'Sion/PipeHook';
{
wParam=0
lParam=(LPARAM)&SION_ENTITY_DESCRIPTOR
Create an entity handle binded to .szUI and for .szProto, this service will
switch threads if it needs to to send ENTITY_CREATE to both .szUI and .szProto
}
type
SION_ENTITY_DESCRIPTOR = record
cbSize:int;
szUI:PAnsiChar;
szProto:PAnsiChar;
hSession:THANDLE; // returned if successful
end;
const
MS_SION_ENTITY_CREATE = 'Sion/EntityCreate';
{
wParam=0
lParam=(LPARAM)HANDLE
Decrement the given handle reference count by one, this will cause the
handle to be freed if the reference count reaches zero, if this is the case
there will be a thread switch to the main thread (if not called from the main thread)
During handle shutdown, ENTITY_DESTROY will be sent to the protocol and then the UI,
note that you do not need to give .szUI or .szProto because the handle knows
who it is binded to.
}
MS_SION_ENTITY_RELEASE = 'Sion/EntityRelease';
{
wParam=0
lParam=HANDLE
Add one to the reference count of HANDLE.
}
MS_SION_ENTITY_CLONE = 'Sion/EntityClone';
{
wParam=0
lParam=&SION_ENTITY_COOKIE
Given a .hSession and a .dwSdr (SDR_*) code get/set a cookie pointer,
if you pass data=NULL, then the current data stored for (SDR_*) will be
returned, if you want to wipe that data, set persist=0
Note that this function is now thread safe for SDR_UI, SDR_PROTO, SDR_SION,
also note that UI's must store their instance data using this method.
}
type
SION_ENTITY_COOKIE = record
cbSize :int;
hSession:THANDLE;
dwSdr :dword; // SDR_* type to store data against, this can be SDR_UI or SDR_PROTO
data :pointer; // can be NULL
persist :int; // if TRUE and data is NULL then data will not be wiped
end;
const
MS_SION_ENTITY_SETCOOKIE = 'Sion/EntitySetCookie';
{
wParam=0
lParam=&SION_ENTITY_COOKIE
Given .data and SDR_code, finds the associated .hSession and returns
a reference to it, note that .data can not be NULL, .dwSdr is used
to match the type of cookie.
}
MS_SION_ENTITY_FINDCOOKIE = 'Sion/EntityFindCookie';
(*
// -- Helper functions --
__inline int Sion_PipeRegister(DWORD dwSdr,AnsiChar *szEntity,MIRANDASERVICE pfnService)
{
struct PIPE_DATA pd;
pd.cbSize=sizeof(struct PIPE_DATA);
pd.dwTo=dwSdr;
pd.szEntity=szEntity;
pd.lParam=(LPARAM)pfnService;
return CallService(MS_SION_PIPEHOOK,0,(LPARAM)&pd);
}
__inline HANDLE Sion_EntityCreate(AnsiChar *szProto, AnsiChar *szUI)
{
struct SION_ENTITY_DESCRIPTOR sed;
sed.cbSize=sizeof(sed);
sed.szProto=szProto;
sed.szUI=szUI;
sed.hSession=NULL;
if (!CallService(MS_SION_ENTITY_CREATE,0,(LPARAM)&sed) && sed.hSession) {
return sed.hSession;
}
return NULL;
}
__inline int Sion_EntityRelease(HANDLE seh)
{
return CallService(MS_SION_ENTITY_RELEASE,0,(LPARAM)seh);
}
__inline int Sion_EntityClone(HANDLE seh)
{
return CallService(MS_SION_ENTITY_CLONE,0,(LPARAM)seh);
}
__inline void* Sion_EntityCookieGet(HANDLE seh, DWORD dwSdr)
{
struct SION_ENTITY_COOKIE sec;
sec.cbSize=sizeof(sec);
sec.hSession=seh;
sec.dwSdr=dwSdr;
sec.data=NULL;
sec.persist=1;
CallService(MS_SION_ENTITY_SETCOOKIE,0,(LPARAM)&sec);
return sec.data;
}
__inline int Sion_EntityCookieSet(HANDLE seh, DWORD dwSdr, void* cookie)
{
struct SION_ENTITY_COOKIE sec;
sec.cbSize=sizeof(sec);
sec.hSession=seh;
sec.dwSdr=dwSdr;
sec.data=cookie;
sec.persist=0;
return CallService(MS_SION_ENTITY_SETCOOKIE,0,(LPARAM)&sec);
}
__inline HANDLE Sion_EntityCookieFind(DWORD dwSdr, void* cookie)
{
struct SION_ENTITY_COOKIE sec;
sec.cbSize=sizeof(sec);
sec.hSession=NULL;
sec.dwSdr=dwSdr;
sec.data=cookie;
CallService(MS_SION_ENTITY_FINDCOOKIE,0,(LPARAM)&sec);
return sec.hSession;
}
__inline int Sion_PipeBroadcast(AnsiChar* szEntity, HANDLE hSession, DWORD dwMsg,
WPARAM wParam, LPARAM lParam, DWORD dwFrom, DWORD dwTo) {
struct PIPE_DATA pd;
pd.cbSize=sizeof(struct PIPE_DATA);
pd.szEntity=szEntity;
pd.hSession=hSession;
pd.dwMsg=dwMsg;
pd.dwTo=dwTo;
pd.dwFrom=dwFrom;
pd.wParam=wParam;
pd.lParam=lParam;
return CallService(MS_SION_PIPE,0,(LPARAM)&pd);
}
*)
{
--Pipe Convos--
The following is the planned pathway message, not all may make
it to the final draft.
Because of the nature of some protocols, there are some
messages that some protocols can ignore since they have no meaning.
SION : sends ENTITY_CREATE after creating a temporary entity handle
PROTO,
UI : both UI and protocol store structures as cookies within the handle
which it can later fetch. At this point the UI is assumed single
contact.
SION : sends a message to the protocol to let it know it should allocate transport
PROTO: the proto can assume this from ENTITY_CREATE, but I'm not sure this a good idea.
PROTO: Protocol needs to send a message to tell the UI about basic channel stuff
like if it is multiple contact from the start (IRC style) or open to change
(MSN style) or if it is private and restricted in all forms of JOIN, INVITE, etc.
UI : Can use this message to present information in a 2 person format even if
the protocol level is widly different.
SION : ATTACH_CHANNEL or ATTACH_CONTACT
PROTO: will send "JOIN" or "INVITE" to request a join/a contact
this maybe on the transport just created above.
These two messages will be have a HPROCESS code
that must be acknowledged later.
Note that if the protocol does not require contacts
to be attached in this way (invited) then just fake the
ATTACHED_* messages.
The contacts(s) will be shown in the channel at the UI level
even if they are not yet within the channel at the protocol
level.
PROTO: sends ATTACHED_CHANNEL or ATTACHED_CONTACT with the HPROCESS
code given by the ATTACH_* messages, this is to signal
that the JOIN was successful or that the invited contact
has joined.
Note that there maybe more than one ATTACHED_* message.
PROTO: sends a CHANNEL_WHOLIST
UI : is supposed to listen out for this WHOLIST and present
a list of people already inside the channel.
if for a single user, the channel list maybe hidden.
PROTO: sends a CHANNEL_TOPIC
UI : displays the topic inside the channel, this message is optional and may not be sent
PROTO: sends a CHANNEL_MODE
UI : displays the modes that the channel is in, the modes still have to be abstracted
to Miranda, e.g. IRC mode +M have another Miranda spec flag.
PROTO: sends a CHANNEL_DONE
UI : the UI is now sure that no more messages are expected.
UI : sends a UI_TEXT message, with optional source MCONTACT and of course the message.
PROTO: picks up on this message and transmits it, it must return
a HPROCESS code that is later acknowledged.
It is upto the protocol if it processes this message with the protocol
send chain.
PROTO: sends a UI_TEXTED with HPROCESS code given above
UI : the UI may show the message as 'sent' or show nothing to the user.
UI : sends UI_IAMTYPING
PROTO: the protocol may or may not send this message to the other parties
but it must process it, this message is also optional.
PROTO: sends UI_CONTACT_ISTYPING (source MCONTACT)
UI : an MCONTACT within the session is typing, the UI may elect to show this
message in a status bar, or with a visual effect.
}
{$ENDIF}
|