Mercurial > pidgin
annotate src/protocols/sametime/meanwhile/srvc_im.c @ 12264:2be62353f708
[gaim-migrate @ 14566]
this was TRUE in oldstatus
committer: Tailor Script <tailor@pidgin.im>
| author | Nathan Walp <nwalp@pidgin.im> |
|---|---|
| date | Tue, 29 Nov 2005 23:50:39 +0000 |
| parents | d6417efb990c |
| children | a2ebf585d8c6 |
| rev | line source |
|---|---|
| 10969 | 1 |
| 2 /* | |
| 3 Meanwhile - Unofficial Lotus Sametime Community Client Library | |
| 4 Copyright (C) 2004 Christopher (siege) O'Brien | |
| 5 | |
| 6 This library is free software; you can redistribute it and/or | |
| 7 modify it under the terms of the GNU Library General Public | |
| 8 License as published by the Free Software Foundation; either | |
| 9 version 2 of the License, or (at your option) any later version. | |
| 10 | |
| 11 This library is distributed in the hope that it will be useful, | |
| 12 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 14 Library General Public License for more details. | |
| 15 | |
| 16 You should have received a copy of the GNU Library General Public | |
| 17 License along with this library; if not, write to the Free | |
| 18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 19 */ | |
| 20 | |
| 21 #include <glib.h> | |
| 22 #include <glib/glist.h> | |
| 23 #include <string.h> | |
| 24 | |
| 25 #include "mw_channel.h" | |
| 26 #include "mw_debug.h" | |
| 27 #include "mw_error.h" | |
| 28 #include "mw_message.h" | |
| 29 #include "mw_service.h" | |
| 30 #include "mw_session.h" | |
| 31 #include "mw_srvc_im.h" | |
| 32 #include "mw_util.h" | |
| 33 | |
| 34 | |
| 35 #define PROTOCOL_TYPE 0x00001000 | |
| 36 #define PROTOCOL_VER 0x00000003 | |
| 37 | |
| 38 | |
| 39 /* data for the addtl blocks of channel creation */ | |
| 40 #define mwImAddtlA_NORMAL 0x00000001 | |
| 41 | |
| 42 #define mwImAddtlB_NORMAL 0x00000001 /**< standard */ | |
| 43 #define mwImAddtlB_PRECONF 0x00000019 /**< pre-conference chat */ | |
| 44 #define mwImAddtlB_NOTESBUDDY 0x00033453 /**< notesbuddy */ | |
| 45 | |
| 46 #define mwImAddtlC_NORMAL 0x00000002 | |
| 47 | |
| 48 | |
| 49 /* send-on-channel message type */ | |
| 50 #define msg_MESSAGE 0x0064 /**< IM message */ | |
| 51 | |
| 52 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
53 #define BREAKUP 2048 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
54 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
55 |
| 10969 | 56 /* which type of im? */ |
| 57 enum mwImType { | |
| 58 mwIm_TEXT = 0x00000001, /**< text message */ | |
| 59 mwIm_DATA = 0x00000002, /**< status message (usually) */ | |
| 60 }; | |
| 61 | |
| 62 | |
| 63 /* which type of data im? */ | |
| 64 enum mwImDataType { | |
| 65 mwImData_TYPING = 0x00000001, /**< common use typing indicator */ | |
| 66 mwImData_SUBJECT = 0x00000003, /**< notesbuddy IM topic */ | |
| 67 mwImData_HTML = 0x00000004, /**< notesbuddy HTML message */ | |
| 68 mwImData_MIME = 0x00000005, /**< notesbuddy MIME message, w/image */ | |
| 69 | |
| 70 mwImData_INVITE = 0x0000000a, /**< Places invitation */ | |
| 71 | |
| 72 mwImData_MULTI_START = 0x00001388, | |
| 73 mwImData_MULTI_STOP = 0x00001389, | |
| 74 }; | |
| 75 | |
| 76 | |
| 77 /** @todo might be appropriate to make a couple of hashtables to | |
| 78 reference conversations by channel and target */ | |
| 79 struct mwServiceIm { | |
| 80 struct mwService service; | |
| 81 | |
| 82 enum mwImClientType features; | |
| 83 | |
| 84 struct mwImHandler *handler; | |
| 85 GList *convs; /**< list of struct im_convo */ | |
| 86 }; | |
| 87 | |
| 88 | |
| 89 struct mwConversation { | |
| 90 struct mwServiceIm *service; /**< owning service */ | |
| 91 struct mwChannel *channel; /**< channel */ | |
| 92 struct mwIdBlock target; /**< conversation target */ | |
| 93 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
94 gboolean ext_id; /**< special treatment, external ID */ |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
95 |
| 10969 | 96 /** state of the conversation, based loosely on the state of its |
| 97 underlying channel */ | |
| 98 enum mwConversationState state; | |
| 99 | |
| 100 enum mwImClientType features; | |
| 101 | |
| 102 GString *multi; /**< buffer for multi-chunk message */ | |
| 103 enum mwImSendType multi_type; /**< type of incoming multi-chunk message */ | |
| 104 | |
| 105 struct mw_datum client_data; | |
| 106 }; | |
| 107 | |
| 108 | |
| 109 /** momentarily places a mwLoginInfo into a mwIdBlock */ | |
| 110 static void login_into_id(struct mwIdBlock *to, struct mwLoginInfo *from) { | |
| 111 to->user = from->user_id; | |
| 112 to->community = from->community; | |
| 113 } | |
| 114 | |
| 115 | |
| 116 static struct mwConversation *convo_find_by_user(struct mwServiceIm *srvc, | |
| 117 struct mwIdBlock *to) { | |
| 118 GList *l; | |
| 119 | |
| 120 for(l = srvc->convs; l; l = l->next) { | |
| 121 struct mwConversation *c = l->data; | |
| 122 if(mwIdBlock_equal(&c->target, to)) | |
| 123 return c; | |
| 124 } | |
| 125 | |
| 126 return NULL; | |
| 127 } | |
| 128 | |
| 129 | |
| 130 static const char *conv_state_str(enum mwConversationState state) { | |
| 131 switch(state) { | |
| 132 case mwConversation_CLOSED: | |
| 133 return "closed"; | |
| 134 | |
| 135 case mwConversation_OPEN: | |
| 136 return "open"; | |
| 137 | |
| 138 case mwConversation_PENDING: | |
| 139 return "pending"; | |
| 140 | |
| 141 case mwConversation_UNKNOWN: | |
| 142 default: | |
| 143 return "UNKNOWN"; | |
| 144 } | |
| 145 } | |
| 146 | |
| 147 | |
| 148 static void convo_set_state(struct mwConversation *conv, | |
| 149 enum mwConversationState state) { | |
| 150 | |
| 151 g_return_if_fail(conv != NULL); | |
| 152 | |
| 153 if(conv->state != state) { | |
| 154 g_info("setting conversation (%s, %s) state: %s", | |
| 155 NSTR(conv->target.user), NSTR(conv->target.community), | |
| 156 conv_state_str(state)); | |
| 157 conv->state = state; | |
| 158 } | |
| 159 } | |
| 160 | |
| 161 | |
| 162 struct mwConversation *mwServiceIm_findConversation(struct mwServiceIm *srvc, | |
| 163 struct mwIdBlock *to) { | |
| 164 g_return_val_if_fail(srvc != NULL, NULL); | |
| 165 g_return_val_if_fail(to != NULL, NULL); | |
| 166 | |
| 167 return convo_find_by_user(srvc, to); | |
| 168 } | |
| 169 | |
| 170 | |
| 171 struct mwConversation *mwServiceIm_getConversation(struct mwServiceIm *srvc, | |
| 172 struct mwIdBlock *to) { | |
| 173 struct mwConversation *c; | |
| 174 | |
| 175 g_return_val_if_fail(srvc != NULL, NULL); | |
| 176 g_return_val_if_fail(to != NULL, NULL); | |
| 177 | |
| 178 c = convo_find_by_user(srvc, to); | |
| 179 if(! c) { | |
| 180 c = g_new0(struct mwConversation, 1); | |
| 181 c->service = srvc; | |
| 182 mwIdBlock_clone(&c->target, to); | |
| 183 c->state = mwConversation_CLOSED; | |
| 184 c->features = srvc->features; | |
| 185 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
186 /* mark external users */ |
| 12166 | 187 c->ext_id = mw_str_has_prefix(to->user, "@E "); |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
188 |
| 10969 | 189 srvc->convs = g_list_prepend(srvc->convs, c); |
| 190 } | |
| 191 | |
| 192 return c; | |
| 193 } | |
| 194 | |
| 195 | |
| 196 static void convo_create_chan(struct mwConversation *c) { | |
| 197 struct mwSession *s; | |
| 198 struct mwChannelSet *cs; | |
| 199 struct mwChannel *chan; | |
| 200 struct mwLoginInfo *login; | |
| 201 struct mwPutBuffer *b; | |
| 202 | |
| 203 /* we only should be calling this if there isn't a channel already | |
| 204 associated with the conversation */ | |
| 205 g_return_if_fail(c != NULL); | |
| 206 g_return_if_fail(mwConversation_isPending(c)); | |
| 207 g_return_if_fail(c->channel == NULL); | |
| 208 | |
| 209 s = mwService_getSession(MW_SERVICE(c->service)); | |
| 210 cs = mwSession_getChannels(s); | |
| 211 | |
| 212 chan = mwChannel_newOutgoing(cs); | |
| 213 mwChannel_setService(chan, MW_SERVICE(c->service)); | |
| 214 mwChannel_setProtoType(chan, PROTOCOL_TYPE); | |
| 215 mwChannel_setProtoVer(chan, PROTOCOL_VER); | |
| 216 | |
| 217 /* offer all known ciphers */ | |
| 218 mwChannel_populateSupportedCipherInstances(chan); | |
| 219 | |
| 220 /* set the target */ | |
| 221 login = mwChannel_getUser(chan); | |
| 222 login->user_id = g_strdup(c->target.user); | |
| 223 login->community = g_strdup(c->target.community); | |
| 224 | |
| 225 /* compose the addtl create, with optional FANCY HTML! */ | |
| 226 b = mwPutBuffer_new(); | |
| 227 guint32_put(b, mwImAddtlA_NORMAL); | |
| 228 guint32_put(b, c->features); | |
| 229 mwPutBuffer_finalize(mwChannel_getAddtlCreate(chan), b); | |
| 230 | |
| 231 c->channel = mwChannel_create(chan)? NULL: chan; | |
| 232 if(c->channel) { | |
| 233 mwChannel_setServiceData(c->channel, c, NULL); | |
| 234 } | |
| 235 } | |
| 236 | |
| 237 | |
| 238 void mwConversation_open(struct mwConversation *conv) { | |
| 239 g_return_if_fail(conv != NULL); | |
| 240 g_return_if_fail(mwConversation_isClosed(conv)); | |
| 241 | |
| 242 convo_set_state(conv, mwConversation_PENDING); | |
| 243 convo_create_chan(conv); | |
| 244 } | |
| 245 | |
| 246 | |
| 247 static void convo_opened(struct mwConversation *conv) { | |
| 248 struct mwImHandler *h = NULL; | |
| 249 | |
| 250 g_return_if_fail(conv != NULL); | |
| 251 g_return_if_fail(conv->service != NULL); | |
| 252 | |
| 253 convo_set_state(conv, mwConversation_OPEN); | |
| 254 h = conv->service->handler; | |
| 255 | |
| 256 g_return_if_fail(h != NULL); | |
| 257 | |
| 258 if(h->conversation_opened) | |
| 259 h->conversation_opened(conv); | |
| 260 } | |
| 261 | |
| 262 | |
| 263 static void convo_free(struct mwConversation *conv) { | |
| 264 struct mwServiceIm *srvc; | |
| 265 | |
| 266 mwConversation_removeClientData(conv); | |
| 267 | |
| 268 srvc = conv->service; | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
269 srvc->convs = g_list_remove_all(srvc->convs, conv); |
| 10969 | 270 |
| 271 mwIdBlock_clear(&conv->target); | |
| 272 g_free(conv); | |
| 273 } | |
| 274 | |
| 275 | |
| 276 static int send_accept(struct mwConversation *c) { | |
| 277 | |
| 278 struct mwChannel *chan = c->channel; | |
| 279 struct mwSession *s = mwChannel_getSession(chan); | |
| 280 struct mwUserStatus *stat = mwSession_getUserStatus(s); | |
| 281 | |
| 282 struct mwPutBuffer *b; | |
| 283 struct mwOpaque *o; | |
| 284 | |
| 285 b = mwPutBuffer_new(); | |
| 286 guint32_put(b, mwImAddtlA_NORMAL); | |
| 287 guint32_put(b, c->features); | |
| 288 guint32_put(b, mwImAddtlC_NORMAL); | |
| 289 mwUserStatus_put(b, stat); | |
| 290 | |
| 291 o = mwChannel_getAddtlAccept(chan); | |
| 292 mwOpaque_clear(o); | |
| 293 mwPutBuffer_finalize(o, b); | |
| 294 | |
| 295 return mwChannel_accept(chan); | |
| 296 } | |
| 297 | |
| 298 | |
| 299 static void recv_channelCreate(struct mwService *srvc, | |
| 300 struct mwChannel *chan, | |
| 301 struct mwMsgChannelCreate *msg) { | |
| 302 | |
| 303 /* - ensure it's the right service,proto,and proto ver | |
| 304 - check the opaque for the right opaque junk | |
| 305 - if not, close channel | |
| 306 - compose & send a channel accept | |
| 307 */ | |
| 308 | |
| 309 struct mwServiceIm *srvc_im = (struct mwServiceIm *) srvc; | |
| 310 struct mwImHandler *handler; | |
| 311 struct mwSession *s; | |
| 312 struct mwUserStatus *stat; | |
| 313 guint32 x, y, z; | |
| 314 struct mwGetBuffer *b; | |
| 315 struct mwConversation *c = NULL; | |
| 316 struct mwIdBlock idb; | |
| 317 | |
| 318 handler = srvc_im->handler; | |
| 319 s = mwChannel_getSession(chan); | |
| 320 stat = mwSession_getUserStatus(s); | |
| 321 | |
| 322 /* ensure the appropriate service/proto/ver */ | |
| 323 x = mwChannel_getServiceId(chan); | |
| 324 y = mwChannel_getProtoType(chan); | |
| 325 z = mwChannel_getProtoVer(chan); | |
| 326 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
327 if( (x != mwService_IM) || (y != PROTOCOL_TYPE) || (z != PROTOCOL_VER) ) { |
| 10969 | 328 g_warning("unacceptable service, proto, ver:" |
| 329 " 0x%08x, 0x%08x, 0x%08x", x, y, z); | |
| 330 mwChannel_destroy(chan, ERR_SERVICE_NO_SUPPORT, NULL); | |
| 331 return; | |
| 332 } | |
| 333 | |
| 334 /* act upon the values in the addtl block */ | |
| 335 b = mwGetBuffer_wrap(&msg->addtl); | |
| 336 guint32_get(b, &x); | |
| 337 guint32_get(b, &y); | |
| 338 z = (guint) mwGetBuffer_error(b); | |
| 339 mwGetBuffer_free(b); | |
| 340 | |
| 341 if(z /* buffer error, BOOM! */ ) { | |
| 342 g_warning("bad/malformed addtl in IM service"); | |
| 343 mwChannel_destroy(chan, ERR_FAILURE, NULL); | |
| 344 return; | |
| 345 | |
| 346 } else if(x != mwImAddtlA_NORMAL) { | |
| 347 g_message("unknown params: 0x%08x, 0x%08x", x, y); | |
| 348 mwChannel_destroy(chan, ERR_IM_NOT_REGISTERED, NULL); | |
| 349 return; | |
| 350 | |
| 351 } else if(y == mwImAddtlB_PRECONF) { | |
| 352 if(! handler->place_invite) { | |
| 353 g_info("rejecting place-invite channel"); | |
| 354 mwChannel_destroy(chan, ERR_IM_NOT_REGISTERED, NULL); | |
| 355 return; | |
| 356 | |
| 357 } else { | |
| 358 g_info("accepting place-invite channel"); | |
| 359 } | |
| 360 | |
| 361 } else if(y != mwImClient_PLAIN && y != srvc_im->features) { | |
| 362 /** reject what we do not understand */ | |
| 363 mwChannel_destroy(chan, ERR_IM_NOT_REGISTERED, NULL); | |
| 364 return; | |
| 365 | |
| 366 } else if(stat->status == mwStatus_BUSY) { | |
| 367 g_info("rejecting IM channel due to DND status"); | |
| 368 mwChannel_destroy(chan, ERR_CLIENT_USER_DND, NULL); | |
| 369 return; | |
| 370 } | |
| 371 | |
| 372 login_into_id(&idb, mwChannel_getUser(chan)); | |
| 373 | |
| 374 #if 0 | |
| 375 c = convo_find_by_user(srvc_im, &idb); | |
| 376 #endif | |
| 377 | |
| 378 if(! c) { | |
| 379 c = g_new0(struct mwConversation, 1); | |
| 380 c->service = srvc_im; | |
| 381 srvc_im->convs = g_list_prepend(srvc_im->convs, c); | |
| 382 } | |
| 383 | |
| 384 #if 0 | |
| 385 /* we're going to re-associate any existing conversations with this | |
| 386 new channel. That means closing any existing ones */ | |
| 387 if(c->channel) { | |
| 388 g_info("closing existing IM channel 0x%08x", mwChannel_getId(c->channel)); | |
| 389 mwConversation_close(c, ERR_SUCCESS); | |
| 390 } | |
| 391 #endif | |
| 392 | |
| 393 /* set up the conversation with this channel, target, and be fancy | |
| 394 if the other side requested it */ | |
| 395 c->channel = chan; | |
| 396 mwIdBlock_clone(&c->target, &idb); | |
| 397 c->features = y; | |
| 398 convo_set_state(c, mwConversation_PENDING); | |
| 399 mwChannel_setServiceData(c->channel, c, NULL); | |
| 400 | |
| 401 if(send_accept(c)) { | |
| 402 g_warning("sending IM channel accept failed"); | |
| 403 mwConversation_free(c); | |
| 404 | |
| 405 } else { | |
| 406 convo_opened(c); | |
| 407 } | |
| 408 } | |
| 409 | |
| 410 | |
| 411 static void recv_channelAccept(struct mwService *srvc, struct mwChannel *chan, | |
| 412 struct mwMsgChannelAccept *msg) { | |
| 413 | |
| 414 struct mwConversation *conv; | |
| 415 | |
| 416 conv = mwChannel_getServiceData(chan); | |
| 417 if(! conv) { | |
| 418 g_warning("received channel accept for non-existant conversation"); | |
| 419 mwChannel_destroy(chan, ERR_FAILURE, NULL); | |
| 420 return; | |
| 421 } | |
| 422 | |
| 423 convo_opened(conv); | |
| 424 } | |
| 425 | |
| 426 | |
| 427 static void recv_channelDestroy(struct mwService *srvc, struct mwChannel *chan, | |
| 428 struct mwMsgChannelDestroy *msg) { | |
| 429 | |
| 430 struct mwConversation *c; | |
| 431 | |
| 432 c = mwChannel_getServiceData(chan); | |
| 433 g_return_if_fail(c != NULL); | |
| 434 | |
| 435 c->channel = NULL; | |
| 436 | |
| 437 if(mwChannel_isState(chan, mwChannel_ERROR)) { | |
| 438 | |
| 439 /* checking for failure on the receiving end to accept html | |
| 440 messages. Fail-over to a non-html format on a new channel for | |
| 441 the convo */ | |
| 442 if(c->features != mwImClient_PLAIN | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
443 && (msg->reason == ERR_IM_NOT_REGISTERED || |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
444 msg->reason == ERR_SERVICE_NO_SUPPORT)) { |
| 10969 | 445 |
| 446 g_debug("falling back on a plaintext conversation"); | |
| 447 c->features = mwImClient_PLAIN; | |
| 448 convo_create_chan(c); | |
| 449 return; | |
| 450 } | |
| 451 } | |
| 452 | |
| 453 mwConversation_close(c, msg->reason); | |
| 454 } | |
| 455 | |
| 456 | |
| 457 static void convo_recv(struct mwConversation *conv, enum mwImSendType type, | |
| 458 gconstpointer msg) { | |
| 459 | |
| 460 struct mwServiceIm *srvc; | |
| 461 struct mwImHandler *handler; | |
| 462 | |
| 463 g_return_if_fail(conv != NULL); | |
| 464 | |
| 465 srvc = conv->service; | |
| 466 g_return_if_fail(srvc != NULL); | |
| 467 | |
| 468 handler = srvc->handler; | |
| 469 if(handler && handler->conversation_recv) | |
| 470 handler->conversation_recv(conv, type, msg); | |
| 471 } | |
| 472 | |
| 473 | |
| 474 static void convo_multi_start(struct mwConversation *conv) { | |
| 475 g_return_if_fail(conv->multi == NULL); | |
| 476 conv->multi = g_string_new(NULL); | |
| 477 } | |
| 478 | |
| 479 | |
| 480 static void convo_multi_stop(struct mwConversation *conv) { | |
| 481 | |
| 482 g_return_if_fail(conv->multi != NULL); | |
| 483 | |
| 484 /* actually send it */ | |
| 485 convo_recv(conv, conv->multi_type, conv->multi->str); | |
| 486 | |
| 487 /* clear up the multi buffer */ | |
| 488 g_string_free(conv->multi, TRUE); | |
| 489 conv->multi = NULL; | |
| 490 } | |
| 491 | |
| 492 | |
| 493 static void recv_text(struct mwServiceIm *srvc, struct mwChannel *chan, | |
| 494 struct mwGetBuffer *b) { | |
| 495 | |
| 496 struct mwConversation *c; | |
| 497 char *text = NULL; | |
| 498 | |
| 499 mwString_get(b, &text); | |
| 500 | |
| 501 if(! text) return; | |
| 502 | |
| 503 c = mwChannel_getServiceData(chan); | |
| 504 if(c) { | |
| 505 if(c->multi) { | |
| 506 g_string_append(c->multi, text); | |
| 507 | |
| 508 } else { | |
| 509 convo_recv(c, mwImSend_PLAIN, text); | |
| 510 } | |
| 511 } | |
| 512 | |
| 513 g_free(text); | |
| 514 } | |
| 515 | |
| 516 | |
| 517 static void convo_invite(struct mwConversation *conv, | |
| 518 struct mwOpaque *o) { | |
| 519 | |
| 520 struct mwServiceIm *srvc; | |
| 521 struct mwImHandler *handler; | |
| 522 | |
| 523 struct mwGetBuffer *b; | |
| 524 char *title, *name, *msg; | |
| 525 | |
| 526 g_info("convo_invite"); | |
| 527 | |
| 528 srvc = conv->service; | |
| 529 handler = srvc->handler; | |
| 530 | |
| 531 g_return_if_fail(handler != NULL); | |
| 532 g_return_if_fail(handler->place_invite != NULL); | |
| 533 | |
| 534 b = mwGetBuffer_wrap(o); | |
| 535 mwGetBuffer_advance(b, 4); | |
| 536 mwString_get(b, &title); | |
| 537 mwString_get(b, &msg); | |
| 538 mwGetBuffer_advance(b, 19); | |
| 539 mwString_get(b, &name); | |
| 540 | |
| 541 if(! mwGetBuffer_error(b)) { | |
| 542 handler->place_invite(conv, msg, title, name); | |
| 543 } | |
| 544 | |
| 545 mwGetBuffer_free(b); | |
| 546 g_free(msg); | |
| 547 g_free(title); | |
| 548 g_free(name); | |
| 549 } | |
| 550 | |
| 551 | |
| 552 static void recv_data(struct mwServiceIm *srvc, struct mwChannel *chan, | |
| 553 struct mwGetBuffer *b) { | |
| 554 | |
| 555 struct mwConversation *conv; | |
| 556 guint32 type, subtype; | |
| 557 struct mwOpaque o = { 0, 0 }; | |
| 558 char *x; | |
| 559 | |
| 560 guint32_get(b, &type); | |
| 561 guint32_get(b, &subtype); | |
| 562 mwOpaque_get(b, &o); | |
| 563 | |
| 564 if(mwGetBuffer_error(b)) { | |
| 565 mwOpaque_clear(&o); | |
| 566 return; | |
| 567 } | |
| 568 | |
| 569 conv = mwChannel_getServiceData(chan); | |
| 570 if(! conv) return; | |
| 571 | |
| 572 switch(type) { | |
| 573 case mwImData_TYPING: | |
| 574 convo_recv(conv, mwImSend_TYPING, GINT_TO_POINTER(! subtype)); | |
| 575 break; | |
| 576 | |
| 577 case mwImData_HTML: | |
| 578 if(o.len) { | |
| 579 if(conv->multi) { | |
| 580 g_string_append_len(conv->multi, o.data, o.len); | |
| 581 conv->multi_type = mwImSend_HTML; | |
| 582 | |
| 583 } else { | |
| 584 x = g_strndup(o.data, o.len); | |
| 585 convo_recv(conv, mwImSend_HTML, x); | |
| 586 g_free(x); | |
| 587 } | |
| 588 } | |
| 589 break; | |
| 590 | |
| 591 case mwImData_SUBJECT: | |
| 592 x = g_strndup(o.data, o.len); | |
| 593 convo_recv(conv, mwImSend_SUBJECT, x); | |
| 594 g_free(x); | |
| 595 break; | |
| 596 | |
| 597 case mwImData_MIME: | |
| 598 if(conv->multi) { | |
| 599 g_string_append_len(conv->multi, o.data, o.len); | |
| 600 conv->multi_type = mwImSend_MIME; | |
| 601 | |
| 602 } else { | |
| 603 x = g_strndup(o.data, o.len); | |
| 604 convo_recv(conv, mwImSend_MIME, x); | |
| 605 g_free(x); | |
| 606 } | |
| 607 break; | |
| 608 | |
| 609 case mwImData_INVITE: | |
| 610 convo_invite(conv, &o); | |
| 611 break; | |
| 612 | |
| 613 case mwImData_MULTI_START: | |
| 614 convo_multi_start(conv); | |
| 615 break; | |
| 616 | |
| 617 case mwImData_MULTI_STOP: | |
| 618 convo_multi_stop(conv); | |
| 619 break; | |
| 620 | |
| 621 default: | |
| 622 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
623 mw_mailme_opaque(&o, "unknown data message type in IM service:" |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
624 " (0x%08x, 0x%08x)", type, subtype); |
| 10969 | 625 } |
| 626 | |
| 627 mwOpaque_clear(&o); | |
| 628 } | |
| 629 | |
| 630 | |
| 631 static void recv(struct mwService *srvc, struct mwChannel *chan, | |
| 632 guint16 type, struct mwOpaque *data) { | |
| 633 | |
| 634 /* - ensure message type is something we want | |
| 635 - parse message type into either mwIMText or mwIMData | |
| 636 - handle | |
| 637 */ | |
| 638 | |
| 639 struct mwGetBuffer *b; | |
| 640 guint32 mt; | |
| 641 | |
| 642 g_return_if_fail(type == msg_MESSAGE); | |
| 643 | |
| 644 b = mwGetBuffer_wrap(data); | |
| 645 guint32_get(b, &mt); | |
| 646 | |
| 647 if(mwGetBuffer_error(b)) { | |
| 648 g_warning("failed to parse message for IM service"); | |
| 649 mwGetBuffer_free(b); | |
| 650 return; | |
| 651 } | |
| 652 | |
| 653 switch(mt) { | |
| 654 case mwIm_TEXT: | |
| 655 recv_text((struct mwServiceIm *) srvc, chan, b); | |
| 656 break; | |
| 657 | |
| 658 case mwIm_DATA: | |
| 659 recv_data((struct mwServiceIm *) srvc, chan, b); | |
| 660 break; | |
| 661 | |
| 662 default: | |
| 663 g_warning("unknown message type 0x%08x for IM service", mt); | |
| 664 } | |
| 665 | |
| 666 if(mwGetBuffer_error(b)) | |
| 667 g_warning("failed to parse message type 0x%08x for IM service", mt); | |
| 668 | |
| 669 mwGetBuffer_free(b); | |
| 670 } | |
| 671 | |
| 672 | |
| 673 static void clear(struct mwServiceIm *srvc) { | |
| 674 struct mwImHandler *h; | |
| 675 | |
| 676 while(srvc->convs) | |
| 677 convo_free(srvc->convs->data); | |
| 678 | |
| 679 h = srvc->handler; | |
| 680 if(h && h->clear) | |
| 681 h->clear(srvc); | |
| 682 srvc->handler = NULL; | |
| 683 } | |
| 684 | |
| 685 | |
| 686 static const char *name(struct mwService *srvc) { | |
| 687 return "Instant Messaging"; | |
| 688 } | |
| 689 | |
| 690 | |
| 691 static const char *desc(struct mwService *srvc) { | |
| 692 return "IM service with Standard and NotesBuddy features"; | |
| 693 } | |
| 694 | |
| 695 | |
| 696 static void start(struct mwService *srvc) { | |
| 697 mwService_started(srvc); | |
| 698 } | |
| 699 | |
| 700 | |
| 701 static void stop(struct mwServiceIm *srvc) { | |
| 702 | |
| 703 while(srvc->convs) | |
| 704 mwConversation_free(srvc->convs->data); | |
| 705 | |
| 706 mwService_stopped(MW_SERVICE(srvc)); | |
| 707 } | |
| 708 | |
| 709 | |
| 710 struct mwServiceIm *mwServiceIm_new(struct mwSession *session, | |
| 711 struct mwImHandler *hndl) { | |
| 712 | |
| 713 struct mwServiceIm *srvc_im; | |
| 714 struct mwService *srvc; | |
| 715 | |
| 716 g_return_val_if_fail(session != NULL, NULL); | |
| 717 g_return_val_if_fail(hndl != NULL, NULL); | |
| 718 | |
| 719 srvc_im = g_new0(struct mwServiceIm, 1); | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
720 srvc = MW_SERVICE(srvc_im); |
| 10969 | 721 |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
722 mwService_init(srvc, session, mwService_IM); |
| 10969 | 723 srvc->recv_create = recv_channelCreate; |
| 724 srvc->recv_accept = recv_channelAccept; | |
| 725 srvc->recv_destroy = recv_channelDestroy; | |
| 726 srvc->recv = recv; | |
| 727 srvc->clear = (mwService_funcClear) clear; | |
| 728 srvc->get_name = name; | |
| 729 srvc->get_desc = desc; | |
| 730 srvc->start = start; | |
| 731 srvc->stop = (mwService_funcStop) stop; | |
| 732 | |
| 733 srvc_im->features = mwImClient_PLAIN; | |
| 734 srvc_im->handler = hndl; | |
| 735 | |
| 736 return srvc_im; | |
| 737 } | |
| 738 | |
| 739 | |
| 740 struct mwImHandler *mwServiceIm_getHandler(struct mwServiceIm *srvc) { | |
| 741 g_return_val_if_fail(srvc != NULL, NULL); | |
| 742 return srvc->handler; | |
| 743 } | |
| 744 | |
| 745 | |
| 746 gboolean mwServiceIm_supports(struct mwServiceIm *srvc, | |
| 747 enum mwImSendType type) { | |
| 748 | |
| 749 g_return_val_if_fail(srvc != NULL, FALSE); | |
| 750 | |
| 751 switch(type) { | |
| 752 case mwImSend_PLAIN: | |
| 753 case mwImSend_TYPING: | |
| 754 return TRUE; | |
| 755 | |
| 756 case mwImSend_SUBJECT: | |
| 757 case mwImSend_HTML: | |
| 758 case mwImSend_MIME: | |
| 759 return srvc->features == mwImClient_NOTESBUDDY; | |
| 760 | |
| 761 default: | |
| 762 return FALSE; | |
| 763 } | |
| 764 } | |
| 765 | |
| 766 | |
| 767 void mwServiceIm_setClientType(struct mwServiceIm *srvc, | |
| 768 enum mwImClientType type) { | |
| 769 | |
| 770 g_return_if_fail(srvc != NULL); | |
| 771 srvc->features = type; | |
| 772 } | |
| 773 | |
| 774 | |
| 775 enum mwImClientType mwServiceIm_getClientType(struct mwServiceIm *srvc) { | |
| 776 g_return_val_if_fail(srvc != NULL, mwImClient_UNKNOWN); | |
| 777 return srvc->features; | |
| 778 } | |
| 779 | |
| 780 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
781 static int convo_send_data(struct mwConversation *conv, |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
782 guint32 type, guint32 subtype, |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
783 struct mwOpaque *data) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
784 struct mwPutBuffer *b; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
785 struct mwOpaque o; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
786 struct mwChannel *chan; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
787 int ret; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
788 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
789 chan = conv->channel; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
790 g_return_val_if_fail(chan != NULL, -1); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
791 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
792 b = mwPutBuffer_new(); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
793 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
794 guint32_put(b, mwIm_DATA); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
795 guint32_put(b, type); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
796 guint32_put(b, subtype); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
797 mwOpaque_put(b, data); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
798 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
799 mwPutBuffer_finalize(&o, b); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
800 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
801 ret = mwChannel_sendEncrypted(chan, msg_MESSAGE, &o, !conv->ext_id); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
802 mwOpaque_clear(&o); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
803 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
804 return ret; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
805 } |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
806 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
807 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
808 static int convo_send_multi_start(struct mwConversation *conv) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
809 return convo_send_data(conv, mwImData_MULTI_START, 0x00, NULL); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
810 } |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
811 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
812 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
813 static int convo_send_multi_stop(struct mwConversation *conv) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
814 return convo_send_data(conv, mwImData_MULTI_STOP, 0x00, NULL); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
815 } |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
816 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
817 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
818 /* breaks up a large message into segments, sends a start_segment |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
819 message, then sends each segment in turn, then sends a stop_segment |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
820 message */ |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
821 static int |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
822 convo_sendSegmented(struct mwConversation *conv, const char *message, |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
823 int (*send)(struct mwConversation *conv, |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
824 const char *msg)) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
825 char *buf = (char *) message; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
826 gsize len; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
827 int ret = 0; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
828 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
829 len = strlen(buf); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
830 ret = convo_send_multi_start(conv); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
831 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
832 while(len && !ret) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
833 char tail; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
834 gsize seg; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
835 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
836 seg = BREAKUP; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
837 if(len < BREAKUP) |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
838 seg = len; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
839 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
840 /* temporarily NUL-terminate this segment */ |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
841 tail = buf[seg]; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
842 buf[seg] = 0x00; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
843 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
844 ret = send(conv, buf); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
845 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
846 /* restore this segment */ |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
847 buf[seg] = tail; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
848 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
849 buf += seg; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
850 len -= seg; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
851 } |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
852 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
853 if(! ret) |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
854 ret = convo_send_multi_stop(conv); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
855 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
856 return ret; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
857 } |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
858 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
859 |
| 10969 | 860 static int convo_sendText(struct mwConversation *conv, const char *text) { |
| 861 struct mwPutBuffer *b; | |
| 862 struct mwOpaque o; | |
| 863 int ret; | |
| 864 | |
| 865 b = mwPutBuffer_new(); | |
| 866 | |
| 867 guint32_put(b, mwIm_TEXT); | |
| 868 mwString_put(b, text); | |
| 869 | |
| 870 mwPutBuffer_finalize(&o, b); | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
871 ret = mwChannel_sendEncrypted(conv->channel, msg_MESSAGE, &o, !conv->ext_id); |
| 10969 | 872 mwOpaque_clear(&o); |
| 873 | |
| 874 return ret; | |
| 875 } | |
| 876 | |
| 877 | |
| 878 static int convo_sendTyping(struct mwConversation *conv, gboolean typing) { | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
879 return convo_send_data(conv, mwImData_TYPING, !typing, NULL); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
880 } |
| 10969 | 881 |
| 882 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
883 static int convo_sendSubject(struct mwConversation *conv, |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
884 const char *subject) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
885 struct mwOpaque o; |
| 10969 | 886 |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
887 o.len = strlen(subject); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
888 o.data = (char *) subject; |
| 10969 | 889 |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
890 return convo_send_data(conv, mwImData_SUBJECT, 0x00, &o); |
| 10969 | 891 } |
| 892 | |
| 893 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
894 static int convo_sendHtml(struct mwConversation *conv, const char *html) { |
| 10969 | 895 struct mwOpaque o; |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
896 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
897 o.len = strlen(html); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
898 o.data = (char *) html; |
| 10969 | 899 |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
900 if(o.len > BREAKUP) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
901 return convo_sendSegmented(conv, html, convo_sendHtml); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
902 } else { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
903 return convo_send_data(conv, mwImData_HTML, 0x00, &o); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
904 } |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
905 } |
| 10969 | 906 |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
907 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
908 static int convo_sendMime(struct mwConversation *conv, const char *mime) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
909 struct mwOpaque o; |
| 10969 | 910 |
| 911 o.len = strlen(mime); | |
| 912 o.data = (char *) mime; | |
| 913 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
914 if(o.len > BREAKUP) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
915 return convo_sendSegmented(conv, mime, convo_sendMime); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
916 } else { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
917 return convo_send_data(conv, mwImData_MIME, 0x00, &o); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
918 } |
| 10969 | 919 } |
| 920 | |
| 921 | |
| 922 int mwConversation_send(struct mwConversation *conv, enum mwImSendType type, | |
| 923 gconstpointer msg) { | |
| 924 | |
| 925 g_return_val_if_fail(conv != NULL, -1); | |
| 926 g_return_val_if_fail(mwConversation_isOpen(conv), -1); | |
| 927 g_return_val_if_fail(conv->channel != NULL, -1); | |
| 928 | |
| 929 switch(type) { | |
| 930 case mwImSend_PLAIN: | |
| 931 return convo_sendText(conv, msg); | |
| 932 case mwImSend_TYPING: | |
| 933 return convo_sendTyping(conv, GPOINTER_TO_INT(msg)); | |
| 934 case mwImSend_SUBJECT: | |
| 935 return convo_sendSubject(conv, msg); | |
| 936 case mwImSend_HTML: | |
| 937 return convo_sendHtml(conv, msg); | |
| 938 case mwImSend_MIME: | |
| 939 return convo_sendMime(conv, msg); | |
| 940 | |
| 941 default: | |
| 942 g_warning("unsupported IM Send Type, 0x%x", type); | |
| 943 return -1; | |
| 944 } | |
| 945 } | |
| 946 | |
| 947 | |
| 948 enum mwConversationState mwConversation_getState(struct mwConversation *conv) { | |
| 949 g_return_val_if_fail(conv != NULL, mwConversation_UNKNOWN); | |
| 950 return conv->state; | |
| 951 } | |
| 952 | |
| 953 | |
| 954 struct mwServiceIm *mwConversation_getService(struct mwConversation *conv) { | |
| 955 g_return_val_if_fail(conv != NULL, NULL); | |
| 956 return conv->service; | |
| 957 } | |
| 958 | |
| 959 | |
| 960 gboolean mwConversation_supports(struct mwConversation *conv, | |
| 961 enum mwImSendType type) { | |
| 962 g_return_val_if_fail(conv != NULL, FALSE); | |
| 963 | |
| 964 switch(type) { | |
| 965 case mwImSend_PLAIN: | |
| 966 case mwImSend_TYPING: | |
| 967 return TRUE; | |
| 968 | |
| 969 case mwImSend_SUBJECT: | |
| 970 case mwImSend_HTML: | |
| 971 case mwImSend_MIME: | |
| 972 return conv->features == mwImClient_NOTESBUDDY; | |
| 973 | |
| 974 default: | |
| 975 return FALSE; | |
| 976 } | |
| 977 } | |
| 978 | |
| 979 | |
| 980 enum mwImClientType | |
| 981 mwConversation_getClientType(struct mwConversation *conv) { | |
| 982 g_return_val_if_fail(conv != NULL, mwImClient_UNKNOWN); | |
| 983 return conv->features; | |
| 984 } | |
| 985 | |
| 986 | |
| 987 struct mwIdBlock *mwConversation_getTarget(struct mwConversation *conv) { | |
| 988 g_return_val_if_fail(conv != NULL, NULL); | |
| 989 return &conv->target; | |
| 990 } | |
| 991 | |
| 992 | |
| 993 struct mwLoginInfo *mwConversation_getTargetInfo(struct mwConversation *conv) { | |
| 994 g_return_val_if_fail(conv != NULL, NULL); | |
| 995 g_return_val_if_fail(conv->channel != NULL, NULL); | |
| 996 return mwChannel_getUser(conv->channel); | |
| 997 } | |
| 998 | |
| 999 | |
| 1000 void mwConversation_setClientData(struct mwConversation *conv, | |
| 1001 gpointer data, GDestroyNotify clean) { | |
| 1002 g_return_if_fail(conv != NULL); | |
| 1003 mw_datum_set(&conv->client_data, data, clean); | |
| 1004 } | |
| 1005 | |
| 1006 | |
| 1007 gpointer mwConversation_getClientData(struct mwConversation *conv) { | |
| 1008 g_return_val_if_fail(conv != NULL, NULL); | |
| 1009 return mw_datum_get(&conv->client_data); | |
| 1010 } | |
| 1011 | |
| 1012 | |
| 1013 void mwConversation_removeClientData(struct mwConversation *conv) { | |
| 1014 g_return_if_fail(conv != NULL); | |
| 1015 mw_datum_clear(&conv->client_data); | |
| 1016 } | |
| 1017 | |
| 1018 | |
| 1019 void mwConversation_close(struct mwConversation *conv, guint32 reason) { | |
| 1020 struct mwServiceIm *srvc; | |
| 1021 struct mwImHandler *h; | |
| 1022 | |
| 1023 g_return_if_fail(conv != NULL); | |
| 1024 | |
| 1025 convo_set_state(conv, mwConversation_CLOSED); | |
| 1026 | |
| 1027 srvc = conv->service; | |
| 1028 g_return_if_fail(srvc != NULL); | |
| 1029 | |
| 1030 h = srvc->handler; | |
| 1031 if(h && h->conversation_closed) | |
| 1032 h->conversation_closed(conv, reason); | |
| 1033 | |
| 1034 if(conv->channel) { | |
| 1035 mwChannel_destroy(conv->channel, reason, NULL); | |
| 1036 conv->channel = NULL; | |
| 1037 } | |
| 1038 } | |
| 1039 | |
| 1040 | |
| 1041 void mwConversation_free(struct mwConversation *conv) { | |
| 1042 g_return_if_fail(conv != NULL); | |
| 1043 | |
| 1044 if(! mwConversation_isClosed(conv)) | |
| 1045 mwConversation_close(conv, ERR_SUCCESS); | |
| 1046 | |
| 1047 convo_free(conv); | |
| 1048 } | |
| 1049 |
