mark PurpleImageClass as private
[pidgin-git.git] / libpurple / protocols / novell / nmevent.c
blobf709e66bc2645110ba2538c58d582055f39564f4
1 /*
2 * nmevent.c
4 * Copyright (c) 2004 Novell, Inc. All Rights Reserved.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
21 #include <glib.h>
22 #include <string.h>
23 #include <time.h>
24 #include "nmevent.h"
25 #include "nmfield.h"
26 #include "nmconn.h"
27 #include "nmuserrecord.h"
28 #include "nmrtf.h"
30 #define MAX_UINT32 0xFFFFFFFF
32 struct _NMEvent
35 /* Event type */
36 int type;
38 /* The DN of the event source */
39 char *source;
41 /* Timestamp of the event */
42 guint32 gmt;
44 /* Conference to associate with the event */
45 NMConference *conference;
47 /* User record to associate with the event */
48 NMUserRecord *user_record;
50 /* Text associated with the event */
51 char *text;
53 /* Reference count for event structure */
54 int ref_count;
58 /* Handle getdetails response and set the new user record into the event */
59 static void
60 _got_user_for_event(NMUser * user, NMERR_T ret_val,
61 gpointer resp_data, gpointer user_data)
63 NMUserRecord *user_record;
64 NMEvent *event;
65 nm_event_cb cb;
67 if (user == NULL)
68 return;
70 user_record = resp_data;
71 event = user_data;
73 if (ret_val == NM_OK) {
74 if (event && user_record) {
76 /* Add the user record to the event structure
77 * and make the callback.
79 nm_event_set_user_record(event, user_record);
80 if ((cb = nm_user_get_event_callback(user))) {
81 cb(user, event);
85 } else {
86 /* Cleanup resp_data */
90 /* Clean up */
91 if (event)
92 nm_release_event(event);
96 /* Handle getdetails response, set the new user record into the event
97 * and add the user record as a participant in the conference
99 static void
100 _got_user_for_conference(NMUser * user, NMERR_T ret_val,
101 gpointer resp_data, gpointer user_data)
103 NMUserRecord *user_record = resp_data;
104 NMEvent *event = user_data;
105 NMConference *conference;
106 nm_event_cb cb;
108 if (user == NULL)
109 return;
111 if (event && user_record) {
113 conference = nm_event_get_conference(event);
114 if (conference) {
116 /* Add source of event as recip of the conference */
117 nm_conference_add_participant(conference, user_record);
119 /* Add the user record to the event structure
120 * and make the callback.
122 nm_event_set_user_record(event, user_record);
123 if ((cb = nm_user_get_event_callback(user))) {
124 cb(user, event);
129 if (event)
130 nm_release_event(event);
133 /* Read the receive message event, set up the event object, and
134 * get details for the event source if we don't have them yet.
136 static NMERR_T
137 handle_receive_message(NMUser * user, NMEvent * event, gboolean autoreply)
139 NMConference *conference;
140 NMUserRecord *user_record;
141 NMConn *conn;
142 NMERR_T rc = NM_OK;
143 guint32 size = 0, flags = 0;
144 char *msg = NULL;
145 char *nortf = NULL;
146 char *guid = NULL;
148 conn = nm_user_get_conn(user);
150 /* Read the conference guid */
151 rc = nm_read_uint32(conn, &size);
152 if (size > 1000) return NMERR_PROTOCOL;
154 if (rc == NM_OK) {
155 guid = g_new0(char, size + 1);
156 rc = nm_read_all(conn, guid, size);
159 /* Read the conference flags */
160 if (rc == NM_OK) {
161 rc = nm_read_uint32(conn, &flags);
164 /* Read the message text */
165 if (rc == NM_OK) {
166 rc = nm_read_uint32(conn, &size);
167 if (size > 100000) return NMERR_PROTOCOL;
169 if (rc == NM_OK) {
170 msg = g_new0(char, size + 1);
171 rc = nm_read_all(conn, msg, size);
173 purple_debug(PURPLE_DEBUG_INFO, "novell", "Message is %s\n", msg);
175 /* Auto replies are not in RTF format! */
176 if (!autoreply) {
177 NMRtfContext *ctx;
179 ctx = nm_rtf_init();
180 nortf = nm_rtf_strip_formatting(ctx, msg);
181 nm_rtf_deinit(ctx);
183 purple_debug(PURPLE_DEBUG_INFO, "novell",
184 "Message without RTF is %s\n", nortf);
186 /* Store the event data */
187 nm_event_set_text(event, nortf);
189 } else {
191 /* Store the event data */
192 nm_event_set_text(event, msg);
197 /* Check to see if we already know about the conference */
198 conference = nm_conference_list_find(user, guid);
199 if (conference) {
201 nm_conference_set_flags(conference, flags);
202 nm_event_set_conference(event, conference);
204 /* Add a reference to the user record in our event object */
205 user_record = nm_find_user_record(user, nm_event_get_source(event));
206 if (user_record) {
207 nm_event_set_user_record(event, user_record);
210 } else {
212 /* This is a new conference, so create one and add it to our list */
213 conference = nm_create_conference(guid);
214 nm_conference_set_flags(conference, flags);
216 /* Add a reference to the conference in the event */
217 nm_event_set_conference(event, conference);
219 /* Add new conference to the conference list */
220 nm_conference_list_add(user, conference);
222 /* Check to see if we have details for the event source yet */
223 user_record = nm_find_user_record(user, nm_event_get_source(event));
224 if (user_record) {
226 /* We do so add the user record as a recipient of the conference */
227 nm_conference_add_participant(conference, user_record);
229 /* Add a reference to the user record in our event object */
230 nm_event_set_user_record(event, user_record);
232 } else {
234 /* Need to go to the server to get details for the user */
235 rc = nm_send_get_details(user, nm_event_get_source(event),
236 _got_user_for_conference, event);
237 if (rc == NM_OK)
238 rc = -1; /* Not done processing the event yet! */
241 nm_release_conference(conference);
244 g_free(msg);
245 g_free(nortf);
246 g_free(guid);
248 return rc;
251 /* Read the invite event, set up the event object, and
252 * get details for the event source if we don't have them yet.
254 static NMERR_T
255 handle_conference_invite(NMUser * user, NMEvent * event)
257 NMERR_T rc = NM_OK;
258 guint32 size = 0;
259 char *guid = NULL;
260 char *msg = NULL;
261 NMConn *conn;
262 NMUserRecord *user_record;
264 conn = nm_user_get_conn(user);
266 /* Read the conference guid */
267 rc = nm_read_uint32(conn, &size);
268 if (size > 1000) return NMERR_PROTOCOL;
270 if (rc == NM_OK) {
271 guid = g_new0(char, size + 1);
272 rc = nm_read_all(conn, guid, size);
275 /* Read the the message */
276 if (rc == NM_OK) {
277 rc = nm_read_uint32(conn, &size);
278 if (size > 100000) return NMERR_PROTOCOL;
280 if (rc == NM_OK) {
281 msg = g_new0(char, size + 1);
282 rc = nm_read_all(conn, msg, size);
286 /* Store the event data */
287 if (rc == NM_OK) {
288 NMConference *conference;
290 nm_event_set_text(event, msg);
292 conference = nm_conference_list_find(user, guid);
293 if (conference == NULL) {
294 conference = nm_create_conference(guid);
296 /* Add new conference to the list and the event */
297 nm_conference_list_add(user, conference);
298 nm_event_set_conference(event, conference);
300 /* Check to see if we have details for the event source yet */
301 user_record = nm_find_user_record(user, nm_event_get_source(event));
302 if (user_record) {
304 /* Add a reference to the user record in our event object */
305 nm_event_set_user_record(event, user_record);
307 } else {
309 /* Need to go to the server to get details for the user */
310 rc = nm_send_get_details(user, nm_event_get_source(event),
311 _got_user_for_event, event);
312 if (rc == NM_OK)
313 rc = -1; /* Not done processing the event yet! */
316 nm_release_conference(conference);
321 g_free(msg);
322 g_free(guid);
324 return rc;
327 /* Read the invite notify event, set up the event object, and
328 * get details for the event source if we don't have them yet.
330 static NMERR_T
331 handle_conference_invite_notify(NMUser * user, NMEvent * event)
333 NMERR_T rc = NM_OK;
334 guint32 size = 0;
335 char *guid = NULL;
336 NMConn *conn;
337 NMConference *conference;
338 NMUserRecord *user_record;
340 conn = nm_user_get_conn(user);
342 /* Read the conference guid */
343 rc = nm_read_uint32(conn, &size);
344 if (size > 1000) return NMERR_PROTOCOL;
346 if (rc == NM_OK) {
347 guid = g_new0(char, size + 1);
348 rc = nm_read_all(conn, guid, size);
351 conference = nm_conference_list_find(user, guid);
352 if (conference) {
353 nm_event_set_conference(event, conference);
355 /* Check to see if we have details for the event source yet */
356 user_record = nm_find_user_record(user, nm_event_get_source(event));
357 if (user_record) {
359 /* Add a reference to the user record in our event object */
360 nm_event_set_user_record(event, user_record);
362 } else {
364 /* Need to go to the server to get details for the user */
365 rc = nm_send_get_details(user, nm_event_get_source(event),
366 _got_user_for_event, event);
367 if (rc == NM_OK)
368 rc = -1; /* Not done processing the event yet! */
371 } else {
372 rc = NMERR_CONFERENCE_NOT_FOUND;
376 g_free(guid);
378 return rc;
381 /* Read the conference reject event and set up the event object */
382 static NMERR_T
383 handle_conference_reject(NMUser * user, NMEvent * event)
385 NMERR_T rc = NM_OK;
386 guint32 size = 0;
387 char *guid = NULL;
388 NMConn *conn;
389 NMConference *conference;
391 conn = nm_user_get_conn(user);
393 /* Read the conference guid */
394 rc = nm_read_uint32(conn, &size);
395 if (size > 1000) return NMERR_PROTOCOL;
397 if (rc == NM_OK) {
398 guid = g_new0(char, size + 1);
399 rc = nm_read_all(conn, guid, size);
402 if (rc == NM_OK) {
403 conference = nm_conference_list_find(user, guid);
404 if (conference) {
405 nm_event_set_conference(event, conference);
406 } else {
407 rc = NMERR_CONFERENCE_NOT_FOUND;
411 g_free(guid);
413 return rc;
416 /* Read the conference left event, set up the event object, and
417 * remove the conference from the list if there are no more
418 * participants
420 static NMERR_T
421 handle_conference_left(NMUser * user, NMEvent * event)
423 NMERR_T rc = NM_OK;
424 guint32 size = 0, flags = 0;
425 char *guid = NULL;
426 NMConference *conference;
427 NMConn *conn;
429 conn = nm_user_get_conn(user);
431 /* Read the conference guid */
432 rc = nm_read_uint32(conn, &size);
433 if (size > 1000) return NMERR_PROTOCOL;
435 if (rc == NM_OK) {
436 guid = g_new0(char, size + 1);
437 rc = nm_read_all(conn, guid, size);
440 /* Read the conference flags */
441 if (rc == NM_OK) {
442 rc = nm_read_uint32(conn, &flags);
445 if (rc == NM_OK) {
446 conference = nm_conference_list_find(user, guid);
447 if (conference) {
448 nm_event_set_conference(event, conference);
449 nm_conference_set_flags(conference, flags);
451 nm_conference_remove_participant(conference, nm_event_get_source(event));
452 if (nm_conference_get_participant_count(conference) == 0) {
453 nm_conference_list_remove(user, conference);
456 } else {
457 rc = NMERR_CONFERENCE_NOT_FOUND;
461 g_free(guid);
463 return rc;
466 /* Read the conference closed, set up the event object, and
467 * remove the conference from the list
469 static NMERR_T
470 handle_conference_closed(NMUser * user, NMEvent * event)
472 NMERR_T rc = NM_OK;
473 guint32 size = 0;
474 char *guid = NULL;
475 NMConference *conference;
476 NMConn *conn;
478 conn = nm_user_get_conn(user);
480 /* Read the conference guid */
481 rc = nm_read_uint32(conn, &size);
482 if (size > 1000) return NMERR_PROTOCOL;
484 if (rc == NM_OK) {
485 guid = g_new0(char, size + 1);
486 rc = nm_read_all(conn, guid, size);
489 if (rc == NM_OK) {
490 conference = nm_conference_list_find(user, guid);
491 if (conference) {
492 nm_event_set_conference(event, conference);
493 nm_conference_list_remove(user, conference);
494 } else {
495 rc = NMERR_CONFERENCE_NOT_FOUND;
499 g_free(guid);
501 return rc;
504 /* Read the conference joined event, set up the event object, and
505 * get details for the event source if we don't have them yet.
507 static NMERR_T
508 handle_conference_joined(NMUser * user, NMEvent * event)
510 NMERR_T rc = NM_OK;
511 guint32 size = 0, flags = 0;
512 char *guid = NULL;
513 NMConn *conn;
514 NMConference *conference;
515 NMUserRecord *user_record;
517 conn = nm_user_get_conn(user);
519 /* Read the conference guid */
520 rc = nm_read_uint32(conn, &size);
521 if (size > 1000) return NMERR_PROTOCOL;
523 if (rc == NM_OK) {
524 guid = g_new0(char, size + 1);
525 rc = nm_read_all(conn, guid, size);
528 /* Read the conference flags */
529 if (rc == NM_OK) {
530 rc = nm_read_uint32(conn, &flags);
533 if (rc == NM_OK) {
534 conference = nm_conference_list_find(user, guid);
535 if (conference) {
536 nm_conference_set_flags(conference, flags);
538 nm_event_set_conference(event, conference);
540 /* Add the new user to the participants list */
541 user_record = nm_find_user_record(user, nm_event_get_source(event));
542 if (user_record) {
543 nm_conference_remove_participant(conference,
544 nm_user_record_get_dn(user_record));
545 nm_conference_add_participant(conference, user_record);
546 } else {
548 /* Need to go to the server to get details for the user */
549 rc = nm_send_get_details(user, nm_event_get_source(event),
550 _got_user_for_conference, event);
551 if (rc == NM_OK)
552 rc = -1; /* Not done processing the event yet! */
555 } else {
556 rc = NMERR_CONFERENCE_NOT_FOUND;
560 g_free(guid);
562 return rc;
565 /* Read the typing event and set up the event object */
566 static NMERR_T
567 handle_typing(NMUser * user, NMEvent * event)
569 NMERR_T rc = NM_OK;
570 guint32 size = 0;
571 char *guid = NULL;
572 NMConference *conference;
573 NMConn *conn;
575 conn = nm_user_get_conn(user);
577 /* Read the conference guid */
578 rc = nm_read_uint32(conn, &size);
579 if (size > 1000) return NMERR_PROTOCOL;
581 if (rc == NM_OK) {
582 guid = g_new0(char, size + 1);
583 rc = nm_read_all(conn, guid, size);
586 if (rc == NM_OK) {
587 conference = nm_conference_list_find(user, guid);
588 if (conference) {
589 nm_event_set_conference(event, conference);
590 } else {
591 rc = NMERR_CONFERENCE_NOT_FOUND;
595 g_free(guid);
597 return rc;
600 /* Read the event, set up the event object, and update
601 * the status in the user record (for the event source)
603 static NMERR_T
604 handle_status_change(NMUser * user, NMEvent * event)
606 NMERR_T rc = NM_OK;
607 guint16 status;
608 guint32 size;
609 char *text = NULL;
610 NMUserRecord *user_record;
611 NMConn *conn;
613 conn = nm_user_get_conn(user);
615 /* Read new status */
616 rc = nm_read_uint16(conn, &status);
617 if (rc == NM_OK) {
619 /* Read the status text */
620 rc = nm_read_uint32(conn, &size);
621 if (size > 10000) return NMERR_PROTOCOL;
623 if (rc == NM_OK) {
624 text = g_new0(char, size + 1);
625 rc = nm_read_all(conn, text, size);
629 if (rc == NM_OK) {
630 nm_event_set_text(event, text);
632 /* Get a reference to the user record and store the new status */
633 user_record = nm_find_user_record(user, nm_event_get_source(event));
634 if (user_record) {
635 nm_event_set_user_record(event, user_record);
636 nm_user_record_set_status(user_record, status, text);
640 g_free(text);
642 return rc;
645 /* Read the undeliverable event */
646 static NMERR_T
647 handle_undeliverable_status(NMUser * user, NMEvent * event)
649 NMERR_T rc = NM_OK;
650 guint32 size = 0;
651 char *guid = NULL;
652 NMConn *conn;
654 conn = nm_user_get_conn(user);
656 /* Read the conference guid */
657 rc = nm_read_uint32(conn, &size);
658 if (size > 1000) return NMERR_PROTOCOL;
660 if (rc == NM_OK) {
661 guid = g_new0(char, size + 1);
662 rc = nm_read_all(conn, guid, size);
665 g_free(guid);
667 return rc;
670 /*******************************************************************************
671 * Event API -- see header file for comments
672 ******************************************************************************/
674 NMEvent *
675 nm_create_event(int type, const char *source, guint32 gmt)
677 NMEvent *event = g_new0(NMEvent, 1);
679 event->type = type;
680 event->gmt = gmt;
682 if (source)
683 event->source = g_strdup(source);
685 event->ref_count = 1;
687 return event;
690 void
691 nm_release_event(NMEvent * event)
693 if (event == NULL) {
694 return;
697 if (--(event->ref_count) == 0) {
699 g_free(event->source);
701 if (event->conference)
702 nm_release_conference(event->conference);
704 if (event->user_record)
705 nm_release_user_record(event->user_record);
707 g_free(event->text);
709 g_free(event);
714 NMConference *
715 nm_event_get_conference(NMEvent * event)
717 if (event)
718 return event->conference;
719 else
720 return NULL;
723 void
724 nm_event_set_conference(NMEvent * event, NMConference * conference)
726 if (event && conference) {
727 nm_conference_add_ref(conference);
728 event->conference = conference;
732 NMUserRecord *
733 nm_event_get_user_record(NMEvent * event)
735 if (event)
736 return event->user_record;
737 else
738 return NULL;
741 void
742 nm_event_set_user_record(NMEvent * event, NMUserRecord * user_record)
744 if (event && user_record) {
745 nm_user_record_add_ref(user_record);
746 event->user_record = user_record;
750 const char *
751 nm_event_get_text(NMEvent * event)
753 if (event)
754 return event->text;
755 else
756 return NULL;
759 void
760 nm_event_set_text(NMEvent * event, const char *text)
762 if (event) {
763 if (text)
764 event->text = g_strdup(text);
765 else
766 event->text = NULL;
770 const char *
771 nm_event_get_source(NMEvent * event)
773 if (event)
774 return event->source;
775 else
776 return NULL;
780 nm_event_get_type(NMEvent * event)
782 if (event)
783 return event->type;
784 else
785 return -1;
788 time_t
789 nm_event_get_gmt(NMEvent * event)
791 if (event)
792 return event->gmt;
793 else
794 return (time_t)-1;
797 NMERR_T
798 nm_process_event(NMUser * user, int type)
800 NMERR_T rc = NM_OK;
801 guint32 size = 0;
802 NMEvent *event = NULL;
803 char *source = NULL;
804 nm_event_cb cb;
805 NMConn *conn;
807 if (user == NULL)
808 return NMERR_BAD_PARM;
810 if (type < NMEVT_START || type > NMEVT_STOP)
811 return NMERR_PROTOCOL;
813 conn = nm_user_get_conn(user);
815 /* Read the event source */
816 rc = nm_read_uint32(conn, &size);
817 if (rc == NM_OK) {
818 if (size > 1000000) {
819 /* Size is larger than our 1MB sanity check. Ignore it. */
820 rc = NMERR_PROTOCOL;
821 } else {
822 source = g_new0(char, size);
824 rc = nm_read_all(conn, source, size);
828 /* Read the event data */
829 if (rc == NM_OK) {
830 event = nm_create_event(type, source, time(0));
832 if (event) {
834 switch (type) {
835 case NMEVT_STATUS_CHANGE:
836 rc = handle_status_change(user, event);
837 break;
839 case NMEVT_RECEIVE_MESSAGE:
840 rc = handle_receive_message(user, event, FALSE);
841 break;
843 case NMEVT_RECEIVE_AUTOREPLY:
844 rc = handle_receive_message(user, event, TRUE);
845 break;
847 case NMEVT_USER_TYPING:
848 case NMEVT_USER_NOT_TYPING:
849 rc = handle_typing(user, event);
850 break;
852 case NMEVT_CONFERENCE_LEFT:
853 rc = handle_conference_left(user, event);
854 break;
856 case NMEVT_CONFERENCE_CLOSED:
857 rc = handle_conference_closed(user, event);
858 break;
860 case NMEVT_CONFERENCE_JOINED:
861 rc = handle_conference_joined(user, event);
862 break;
864 case NMEVT_CONFERENCE_INVITE:
865 rc = handle_conference_invite(user, event);
866 break;
868 case NMEVT_CONFERENCE_REJECT:
869 rc = handle_conference_reject(user, event);
870 break;
872 case NMEVT_CONFERENCE_INVITE_NOTIFY:
873 rc = handle_conference_invite_notify(user, event);
874 break;
876 case NMEVT_UNDELIVERABLE_STATUS:
877 rc = handle_undeliverable_status(user, event);
878 break;
880 case NMEVT_INVALID_RECIPIENT:
881 /* Nothing else to read, just callback */
882 break;
884 case NMEVT_USER_DISCONNECT:
885 /* Nothing else to read, just callback */
886 break;
888 case NMEVT_SERVER_DISCONNECT:
889 /* Nothing else to read, just callback */
890 break;
892 case NMEVT_RECEIVE_FILE:
893 case NMEVT_CONTACT_ADD:
894 /* Safely ignored for now */
895 break;
897 default:
898 purple_debug(PURPLE_DEBUG_INFO, "novell",
899 "Unknown event %d received.\n", type);
900 rc = NMERR_PROTOCOL;
901 break;
906 if (rc == (NMERR_T)-1) {
907 /* -1 means that we are not ready to callback yet. */
908 rc = NM_OK;
909 } else if (rc == NM_OK && (cb = nm_user_get_event_callback(user))) {
911 cb(user, event);
913 if (event)
914 nm_release_event(event);
915 } else {
916 if (event)
917 nm_release_event(event);
920 /* Cleanup */
921 g_free(source);
923 return rc;