comparison src/protocols/novell/novell.c @ 8675:9ee2542d1104

[gaim-migrate @ 9428] A GroupWise plugin from Novell. committer: Tailor Script <tailor@pidgin.im>
author Sean Egan <seanegan@gmail.com>
date Sat, 17 Apr 2004 13:55:28 +0000
parents
children e096d797d958
comparison
equal deleted inserted replaced
8674:8c7da2e36136 8675:9ee2542d1104
1 /*
2 * novell.c
3 *
4 * Copyright © 2004 Unpublished Work of Novell, Inc. All Rights Reserved.
5 *
6 * THIS WORK IS AN UNPUBLISHED WORK OF NOVELL, INC. NO PART OF THIS WORK MAY BE
7 * USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED,
8 * TRANSLATED, ABRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED,
9 * RECAST, TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL,
10 * INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT
11 * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
12 *
13 * AS BETWEEN [GAIM] AND NOVELL, NOVELL GRANTS [GAIM] THE RIGHT TO REPUBLISH
14 * THIS WORK UNDER THE GPL (GNU GENERAL PUBLIC LICENSE) WITH ALL RIGHTS AND
15 * LICENSES THEREUNDER. IF YOU HAVE RECEIVED THIS WORK DIRECTLY OR INDIRECTLY
16 * FROM [GAIM] AS PART OF SUCH A REPUBLICATION, YOU HAVE ALL RIGHTS AND LICENSES
17 * GRANTED BY [GAIM] UNDER THE GPL. IN CONNECTION WITH SUCH A REPUBLICATION, IF
18 * ANYTHING IN THIS NOTICE CONFLICTS WITH THE TERMS OF THE GPL, SUCH TERMS
19 * PREVAIL.
20 *
21 */
22
23 #include "internal.h"
24 #include "accountopt.h"
25 #include "debug.h"
26 #include "prpl.h"
27 #include "server.h"
28 #include "nmuser.h"
29 #include "notify.h"
30 #include "util.h"
31 #include "sslconn.h"
32 #include "request.h"
33 #include "network.h"
34
35 #define DEFAULT_PORT 8300
36 #define NOVELL_CONNECT_STEPS 4
37
38 static GaimPlugin *my_protocol = NULL;
39
40 static gboolean
41 _is_disconnect_error(NMERR_T err);
42
43 static gboolean
44 _check_for_disconnect(NMUser * user, NMERR_T err);
45
46 static void
47 _send_message(NMUser * user, NMMessage * message);
48
49 static void
50 _update_buddy_status(GaimBuddy * buddy, int status, int gmt);
51
52 static void
53 _remove_gaim_buddies(NMUser * user);
54
55 static void
56 _add_contacts_to_gaim_blist(NMUser * user, NMFolder * folder);
57
58 static void
59 _add_gaim_buddies(NMUser * user);
60
61 static void
62 _show_info(GaimConnection * gc, NMUserRecord * user_record);
63
64 /*******************************************************************************
65 * Response callbacks
66 *******************************************************************************/
67
68 /* Handle login response */
69 static void
70 _login_resp_cb(NMUser * user, NMERR_T ret_code,
71 gpointer resp_data, gpointer user_data)
72 {
73 GaimConnection *gc;
74 const char *alias;
75 NMERR_T rc;
76
77 if (user == NULL)
78 return;
79
80 gc = gaim_account_get_connection(user->client_data);
81 if (gc == NULL)
82 return;
83
84 if (ret_code == NM_OK) {
85
86 /* Set alias for user if not set (use Full Name) */
87 alias = gaim_account_get_alias(user->client_data);
88 if (alias == NULL || *alias == '\0') {
89 alias = nm_user_record_get_full_name(user->user_record);
90
91 if (alias)
92 gaim_account_set_alias(user->client_data, alias);
93 }
94
95 /* Tell Gaim that we are connected */
96 gaim_connection_set_state(gc, GAIM_CONNECTED);
97 serv_finish_login(gc);
98
99 /* Sync the contact list. This is pretty simplistic right now,
100 * we just remove all of the GaimBuddy from the client side list
101 * for this account and then add in all of the contacts from the
102 * server side list.
103 */
104 _remove_gaim_buddies(user);
105 _add_gaim_buddies(user);
106
107 rc = nm_send_set_status(user, NM_STATUS_AVAILABLE, NULL, NULL, NULL,
108 NULL);
109 _check_for_disconnect(user, rc);
110
111 } else {
112
113 char *err = g_strdup_printf(_("Login failed (0x%X)."), ret_code);
114
115 gaim_connection_error(gc, err);
116 g_free(err);
117
118 }
119 }
120
121 /* Handle getstatus response*/
122 static void
123 _get_status_resp_cb(NMUser * user, NMERR_T ret_code,
124 gpointer resp_data, gpointer user_data)
125 {
126 GaimBuddy *buddy;
127 GSList *buddies;
128 GSList *bnode;
129 NMUserRecord *user_record = (NMUserRecord *) resp_data;
130 int status;
131
132 if (user == NULL || user_record == NULL)
133 return;
134
135 if (ret_code == NM_OK) {
136
137 /* Find all Gaim buddies and update their statuses */
138 const char *name = nm_user_record_get_display_id(user_record);
139
140 if (name) {
141 buddies = gaim_find_buddies((GaimAccount *) user->client_data, name);
142 for (bnode = buddies; bnode; bnode = bnode->next) {
143 buddy = (GaimBuddy *) bnode->data;
144 if (buddy) {
145 status = nm_user_record_get_status(user_record);
146 _update_buddy_status(buddy, status, time(0));
147 }
148 }
149 }
150
151 } else {
152
153 gaim_debug(GAIM_DEBUG_INFO, "novell",
154 "_get_status_resp_cb(): rc = 0x%X\n", ret_code);
155
156 }
157 }
158
159 /* Show an error if the rename failed */
160 static void
161 _rename_contact_resp_cb(NMUser * user, NMERR_T ret_code,
162 gpointer resp_data, gpointer user_data)
163 {
164 if (ret_code != NM_OK) {
165 gaim_debug(GAIM_DEBUG_INFO, "novell",
166 "_rename_contact_resp_cb(): rc = 0x%X\n", ret_code);
167 }
168 }
169
170 /* Handle the getdetails response and send the message */
171 static void
172 _get_details_resp_send_msg(NMUser * user, NMERR_T ret_code,
173 gpointer resp_data, gpointer user_data)
174 {
175 GaimConversation *gconv;
176 GaimConnection *gc;
177 NMUserRecord *user_record = NULL;
178 NMContact *cntct = NULL;
179 NMConference *conf;
180 NMMessage *msg = user_data;
181 const char *dn = NULL;
182 const char *name;
183
184 if (user == NULL || msg == NULL)
185 return;
186
187 if (ret_code == NM_OK) {
188 user_record = (NMUserRecord *) resp_data;
189 if (user_record) {
190
191 /* Set the title for the conversation */
192 gconv = gaim_find_conversation_with_account(nm_user_record_get_display_id(user_record),
193 (GaimAccount *) user->client_data);
194 if (gconv) {
195
196 dn = nm_user_record_get_dn(user_record);
197 if (dn) {
198 cntct = nm_find_contact(user, dn);
199 }
200
201 if (cntct) {
202 gaim_conversation_set_title(gconv,
203 nm_contact_get_display_name(cntct));
204 } else {
205
206 /* Not in the contact list, try to user full name */
207 name = (char *) nm_user_record_get_full_name(user_record);
208 if (name)
209 gaim_conversation_set_title(gconv, name);
210 }
211 }
212
213 /* Add the user record to particpant list */
214 conf = nm_message_get_conference(msg);
215 if (conf) {
216 nm_conference_add_participant(conf, user_record);
217 _send_message(user, msg);
218 }
219 }
220
221 } else {
222
223 gc = gaim_account_get_connection(user->client_data);
224 if (gc != NULL) {
225 char *err = g_strdup_printf(_("Unable to send message."
226 " Could not get details for user (0x%X)."),
227 ret_code);
228
229 gaim_notify_error(gc, NULL, err, NULL);
230 g_free(err);
231 }
232
233 if (msg)
234 nm_release_message(msg);
235 }
236 }
237
238 /* Set up the new GaimBuddy based on the response from getdetails */
239 static void
240 _get_details_resp_setup_buddy(NMUser * user, NMERR_T ret_code,
241 gpointer resp_data, gpointer user_data)
242 {
243 NMUserRecord *user_record;
244 NMContact *contact;
245 GaimBuddy *buddy;
246 const char *alias;
247 NMERR_T rc = NM_OK;
248
249 if (user == NULL || resp_data == NULL || user_data == NULL)
250 return;
251
252 contact = user_data;
253
254 if (ret_code == NM_OK) {
255 user_record = resp_data;
256
257 buddy = nm_contact_get_data(contact);
258
259 nm_contact_set_user_record(contact, user_record);
260
261 /* Set the display id */
262 gaim_blist_rename_buddy(buddy,
263 nm_user_record_get_display_id(user_record));
264
265 alias = gaim_get_buddy_alias(buddy);
266 if (alias == NULL || (strcmp(alias, buddy->name) == 0)) {
267 gaim_blist_alias_buddy(buddy,
268 nm_user_record_get_full_name(user_record));
269
270 /* Tell the server about the new display name */
271 rc = nm_send_rename_contact(user, contact,
272 nm_user_record_get_full_name(user_record),
273 NULL, NULL);
274 _check_for_disconnect(user, rc);
275
276 }
277
278
279 /* Get initial status for the buddy */
280 rc = nm_send_get_status(user, resp_data, _get_status_resp_cb, NULL);
281 _check_for_disconnect(user, rc);
282
283 /* nm_release_contact(contact);*/
284
285 }
286
287 if (contact)
288 nm_release_contact(contact);
289 }
290
291 /* Add the new contact into the GaimBuddy list */
292 static void
293 _create_contact_resp_cb(NMUser * user, NMERR_T ret_code,
294 gpointer resp_data, gpointer user_data)
295 {
296 NMContact *tmp_contact = (NMContact *) user_data;
297 NMContact *new_contact = NULL;
298 NMFolder *folder = NULL;
299 GaimGroup *group;
300 GaimBuddy *buddy;
301 const char *folder_name = NULL;
302 NMERR_T rc = NM_OK;
303
304 if (user == NULL)
305 return;
306
307 if (ret_code == NM_OK) {
308
309 new_contact = (NMContact *) resp_data;
310 if (new_contact == NULL || tmp_contact == NULL)
311 return;
312
313 /* Get the userid and folder name for the new contact */
314 folder = nm_find_folder_by_id(user,
315 nm_contact_get_parent_id(new_contact));
316 if (folder) {
317 folder_name = nm_folder_get_name(folder);
318 }
319
320 /* Re-add the buddy now that we got the okay from the server */
321 if (folder_name && (group = gaim_find_group(folder_name))) {
322
323 const char *alias = nm_contact_get_display_name(tmp_contact);
324 const char *display_id = nm_contact_get_display_id(new_contact);
325
326 if (display_id == NULL)
327 display_id = nm_contact_get_dn(new_contact);
328
329 if (alias && strcmp(alias, display_id)) {
330
331 /* The user requested an alias, tell the server about it. */
332 rc = nm_send_rename_contact(user, new_contact, alias,
333 _rename_contact_resp_cb, NULL);
334 _check_for_disconnect(user, rc);
335
336 } else {
337
338 alias = "";
339
340 }
341
342 /* Add it to the gaim buddy list if it is not there */
343 buddy = gaim_find_buddy_in_group(user->client_data, display_id, group);
344 if (buddy == NULL) {
345 buddy = gaim_buddy_new(user->client_data, display_id, alias);
346 gaim_blist_add_buddy(buddy, NULL, group, NULL);
347 }
348
349 /* Save the new buddy as part of the contact object */
350 nm_contact_set_data(new_contact, (gpointer) buddy);
351
352 /* We need details for the user before we can setup the
353 * new Gaim buddy. We always call this because the
354 * 'createcontact' response fields do not always contain
355 * everything that we need.
356 */
357 nm_contact_add_ref(new_contact);
358
359 rc = nm_send_get_details(user, nm_contact_get_dn(new_contact),
360 _get_details_resp_setup_buddy, new_contact);
361 _check_for_disconnect(user, rc);
362
363 }
364
365 } else {
366 GaimConnection *gc = gaim_account_get_connection(user->client_data);
367 const char *name = nm_contact_get_dn(tmp_contact);
368 char *err;
369
370 err =
371 g_strdup_printf(_("Unable to add %s to your buddy list (0x%X)."),
372 name, ret_code);
373 gaim_notify_error(gc, NULL, err, NULL);
374 g_free(err);
375
376 }
377
378 if (tmp_contact)
379 nm_release_contact(tmp_contact);
380 }
381
382 /* Show an error if we failed to send the message */
383 static void
384 _send_message_resp_cb(NMUser * user, NMERR_T ret_code,
385 gpointer resp_data, gpointer user_data)
386 {
387 GaimConnection *gc;
388 char *err = NULL;
389
390 if (user == NULL)
391 return;
392
393 if (ret_code != NM_OK) {
394 gc = gaim_account_get_connection(user->client_data);
395
396 /* TODO: Improve this! message to who or for what conference? */
397 err = g_strdup_printf(_("Unable to send message (0x%X)."),
398 ret_code);
399 gaim_notify_error(gc, NULL, err, NULL);
400 g_free(err);
401 }
402 }
403
404 /* Show an error if the remove failed */
405 static void
406 _remove_contact_resp_cb(NMUser * user, NMERR_T ret_code,
407 gpointer resp_data, gpointer user_data)
408 {
409 if (ret_code != NM_OK) {
410 /* TODO: Display an error? */
411
412 gaim_debug(GAIM_DEBUG_INFO, "novell",
413 "_remove_contact_resp_cb(): rc = 0x%x\n", ret_code);
414 }
415 }
416
417 /* Show an error if the remove failed */
418 static void
419 _remove_folder_resp_cb(NMUser * user, NMERR_T ret_code,
420 gpointer resp_data, gpointer user_data)
421 {
422 if (ret_code != NM_OK) {
423 /* TODO: Display an error? */
424
425 gaim_debug(GAIM_DEBUG_INFO, "novell",
426 "_remove_folder_resp_cb(): rc = 0x%x\n", ret_code);
427 }
428 }
429
430 /* Show an error if the move failed */
431 static void
432 _move_contact_resp_cb(NMUser * user, NMERR_T ret_code,
433 gpointer resp_data, gpointer user_data)
434 {
435 if (ret_code != NM_OK) {
436 /* TODO: Display an error? */
437
438 gaim_debug(GAIM_DEBUG_INFO, "novell",
439 "_move_contact_resp_cb(): rc = 0x%x\n", ret_code);
440 }
441 }
442
443 /* Show an error if the rename failed */
444 static void
445 _rename_folder_resp_cb(NMUser * user, NMERR_T ret_code,
446 gpointer resp_data, gpointer user_data)
447 {
448 if (ret_code != NM_OK) {
449 /* TODO: Display an error? */
450
451 gaim_debug(GAIM_DEBUG_INFO, "novell",
452 "_rename_folder_resp_cb(): rc = 0x%x\n", ret_code);
453 }
454 }
455
456 /* If the createconf was successful attempt to send the message,
457 * otherwise display an error message to the user.
458 */
459 static void
460 _createconf_resp_send_msg(NMUser * user, NMERR_T ret_code,
461 gpointer resp_data, gpointer user_data)
462 {
463 NMConference *conf;
464 NMMessage *msg = user_data;
465
466 if (user == NULL || msg == NULL)
467 return;
468
469 if (ret_code == NM_OK) {
470 _send_message(user, msg);
471 } else {
472
473 if ((conf = nm_message_get_conference(msg))) {
474
475 GaimConnection *gc = gaim_account_get_connection(user->client_data);
476 const char *name = NULL;
477 char *err;
478 NMUserRecord *ur;
479
480 ur = nm_conference_get_participant(conf, 0);
481 if (ur)
482 name = nm_user_record_get_userid(ur);
483
484 if (name)
485 err = g_strdup_printf(_("Unable to send message to %s."
486 " Could not create the conference (0x%X)."),
487 name, ret_code);
488 else
489 err = g_strdup_printf(_("Unable to send message."
490 " Could not create the conference (0x%X)."),
491 ret_code);
492
493 gaim_notify_error(gc, NULL, err, NULL);
494 g_free(err);
495 }
496
497 if (msg)
498 nm_release_message(msg);
499 }
500 }
501
502 /* Move contact to newly created folder */
503 static void
504 _create_folder_resp_move_contact(NMUser * user, NMERR_T ret_code,
505 gpointer resp_data, gpointer user_data)
506 {
507 NMContact *contact = user_data;
508 NMFolder *new_folder;
509 char *folder_name = resp_data;
510 NMERR_T rc = NM_OK;
511
512 if (user == NULL || folder_name == NULL || contact == NULL) {
513
514 if (folder_name)
515 g_free(folder_name);
516
517 return;
518 }
519
520 if (ret_code == NM_OK || ret_code == 0xD126) {
521 new_folder = nm_find_folder(user, folder_name);
522 if (new_folder) {
523
524 /* Tell the server to move the contact to the new folder */
525 /* rc = nm_send_move_contact(user, contact, new_folder,
526 _move_contact_resp_cb, NULL); */
527
528 rc = nm_send_create_contact(user, new_folder, contact,
529 NULL, NULL);
530
531 _check_for_disconnect(user, rc);
532
533 }
534 } else {
535 GaimConnection *gc = gaim_account_get_connection(user->client_data);
536 char *err = g_strdup_printf(_("Unable to move user %s"
537 " to folder %s in the server side list."
538 " Error while creating folder (0x%X)."),
539 nm_contact_get_dn(contact),
540 folder_name,
541 ret_code);
542
543 gaim_notify_error(gc, NULL, err, NULL);
544 g_free(err);
545 }
546
547 if (folder_name)
548 g_free(folder_name);
549 }
550
551 /* Add contact to newly create folder */
552 static void
553 _create_folder_resp_add_contact(NMUser * user, NMERR_T ret_code,
554 gpointer resp_data, gpointer user_data)
555 {
556 NMContact *contact = (NMContact *) user_data;
557 NMFolder *folder;
558 char *folder_name = (char *) resp_data;
559 NMERR_T rc = NM_OK;
560
561 if (user == NULL || folder_name == NULL || contact == NULL) {
562
563 if (contact)
564 nm_release_contact(contact);
565
566 if (folder_name)
567 g_free(folder_name);
568
569 return;
570 }
571
572 if (ret_code == NM_OK || ret_code == 0xD126) {
573 folder = nm_find_folder(user, folder_name);
574 if (folder) {
575
576 rc = nm_send_create_contact(user, folder, contact,
577 _create_contact_resp_cb, contact);
578 _check_for_disconnect(user, rc);
579 }
580 } else {
581 GaimConnection *gc = gaim_account_get_connection(user->client_data);
582 const char *name = nm_contact_get_dn(contact);
583 char *err =
584 g_strdup_printf(_("Unable to add %s to your buddy list."
585 " Error creating folder in server side list (0x%X)."),
586 name, ret_code);
587
588 gaim_notify_error(gc, NULL, err, NULL);
589
590 nm_release_contact(contact);
591 g_free(err);
592 }
593
594 g_free(folder_name);
595 }
596
597 static void
598 _join_conf_resp_cb(NMUser * user, NMERR_T ret_code,
599 gpointer resp_data, gpointer user_data)
600 {
601 GaimConversation *chat;
602 GaimConnection *gc;
603 NMUserRecord *ur;
604 NMConference *conference = user_data;
605 const char *name;
606 char *conf_name;
607 int i, count;
608
609 if (user == NULL || conference == NULL)
610 return;
611
612 gc = gaim_account_get_connection(user->client_data);
613
614 if (ret_code == NM_OK) {
615 conf_name = g_strdup_printf(_("GroupWise Conference %d"),
616 ++user->conference_count);
617 chat = serv_got_joined_chat(gc, user->conference_count, conf_name);
618 if (chat) {
619
620 nm_conference_set_data(conference, (gpointer) chat);
621
622 count = nm_conference_get_participant_count(conference);
623 for (i = 0; i < count; i++) {
624 ur = nm_conference_get_participant(conference, i);
625 if (ur) {
626 name = nm_user_record_get_display_id(ur);
627 gaim_conv_chat_add_user(GAIM_CONV_CHAT(chat), name, NULL);
628 }
629 }
630 }
631 g_free(conf_name);
632 }
633 }
634
635 /* Show info returned by getdetails */
636 static void
637 _get_details_resp_show_info(NMUser * user, NMERR_T ret_code,
638 gpointer resp_data, gpointer user_data)
639 {
640 GaimConnection *gc;
641 NMUserRecord *user_record;
642 char *name;
643 char *err;
644
645 if (user == NULL)
646 return;
647
648 name = user_data;
649
650 if (ret_code == NM_OK) {
651 user_record = (NMUserRecord *) resp_data;
652 if (user_record) {
653 _show_info(gaim_account_get_connection(user->client_data),
654 user_record);
655 }
656 } else {
657 gc = gaim_account_get_connection(user->client_data);
658 err =
659 g_strdup_printf(_("Could not get details for user %s (0x%X)."), name,
660 ret_code);
661 gaim_notify_error(gc, NULL, err, NULL);
662 g_free(err);
663 }
664
665 if (name)
666 g_free(name);
667 }
668
669 /*******************************************************************************
670 * Helper functions
671 ******************************************************************************/
672
673 static char *
674 _user_agent_string()
675 {
676
677 #if !defined(_WIN32)
678
679 const char *sysname = "";
680 const char *release = "";
681 const char *template = "Gaim/%s (%s; %s)";
682 struct utsname u;
683
684 if (uname(&u) == 0) {
685 sysname = u.sysname;
686 release = u.release;
687 } else {
688 sysname = "Linux";
689 release = "Unknown";
690 }
691
692 return g_strdup_printf(template, VERSION, sysname, release);
693
694 #else
695
696 const char *sysname = "";
697 const char *template = "Gaim/%s (%s; %d.%d)";
698 OSVERSIONINFO os_info;
699 SYSTEM_INFO sys_info;
700
701 os_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
702 GetVersionEx(&os_info);
703 GetSystemInfo(&sys_info);
704
705 if (os_info.dwPlatformId == VER_PLATFORM_WIN32_NT) {
706 switch (os_info.dwMajorVersion) {
707 case 3:
708 case 4:
709 sysname = "Windows NT";
710 break;
711 case 5:
712 switch (os_info.dwMinorVersion) {
713 case 0:
714 sysname = "Windows 2000";
715 break;
716 case 1:
717 sysname = "Windows XP";
718 break;
719 case 2:
720 sysname = "Windows Server 2003";
721 break;
722 default:
723 sysname = "Windows";
724 break;
725 }
726 break;
727 default:
728 sysname = "Windows";
729 break;
730 }
731
732 } else if (os_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
733 switch (os_info.dwMinorVersion) {
734 case 0:
735 sysname = "Windows 95";
736 break;
737 case 10:
738 sysname = "Windows 98";
739 break;
740 case 90:
741 sysname = "Windows ME";
742 break;
743 default:
744 sysname = "Windows";
745 break;
746 }
747 } else {
748 sysname = "Windows";
749 }
750
751 return g_strdup_printf(template, VERSION, sysname,
752 os_info.dwMajorVersion, os_info.dwMinorVersion);
753
754 #endif
755
756
757 }
758
759 static gboolean
760 _is_disconnect_error(NMERR_T err)
761 {
762 return (err == NMERR_TCP_WRITE ||
763 err == NMERR_TCP_READ || err == NMERR_PROTOCOL);
764 }
765
766 static gboolean
767 _check_for_disconnect(NMUser * user, NMERR_T err)
768 {
769 GaimConnection *gc = gaim_account_get_connection(user->client_data);
770
771 if (_is_disconnect_error(err)) {
772
773 gaim_connection_error(gc, _("Error communicating with server."
774 " Closing connection."));
775 return TRUE;
776
777 }
778
779 return FALSE;
780 }
781
782 /* Check to see if the conference is instantiated, if so send the message.
783 * If not send the create conference -- the response handler for the createconf
784 * will call this function again.
785 */
786 static void
787 _send_message(NMUser * user, NMMessage * message)
788 {
789 NMConference *conf;
790 NMERR_T rc = NM_OK;
791
792 conf = nm_message_get_conference(message);
793 if (conf) {
794 /* We have a conference make sure that the
795 server knows about it already. */
796 if (nm_conference_is_instantiated(conf)) {
797
798 /* We have everything that we need...finally! */
799 rc = nm_send_message(user, message, _send_message_resp_cb);
800 _check_for_disconnect(user, rc);
801
802 nm_release_message(message);
803
804 } else {
805 rc = nm_send_create_conference(user, conf,
806 _createconf_resp_send_msg, message);
807 _check_for_disconnect(user, rc);
808 }
809 }
810 }
811
812 /* Update the status of the given buddy in the Gaim buddy list */
813 static void
814 _update_buddy_status(GaimBuddy * buddy, int status, int gmt)
815 {
816 GaimConnection *gc = gaim_account_get_connection(buddy->account);
817 int gstatus = status << 1;
818 int idle = 0;
819 int loggedin = 1;
820
821 switch (status) {
822 case NM_STATUS_AVAILABLE:
823 /*nothing to do */
824 break;
825 case NM_STATUS_AWAY:
826 case NM_STATUS_BUSY:
827 gstatus |= UC_UNAVAILABLE;
828 break;
829 case NM_STATUS_OFFLINE:
830 loggedin = 0;
831 gstatus |= UC_UNAVAILABLE;
832 break;
833 case NM_STATUS_AWAY_IDLE:
834 idle = gmt;
835 gstatus |= UC_UNAVAILABLE;
836 break;
837 default:
838 gstatus |= UC_UNAVAILABLE;
839 loggedin = 0;
840 break;
841 }
842
843 serv_got_update(gc, buddy->name, loggedin, 0, 0, idle, gstatus);
844 }
845
846 /* Iterate through the cached Gaim buddy list and remove all buddies
847 * for this account.
848 */
849 static void
850 _remove_gaim_buddies(NMUser * user)
851 {
852 GaimBlistNode *gnode;
853 GaimBlistNode *cnode;
854 GaimBlistNode *bnode;
855 GaimGroup *group;
856 GaimBuddy *buddy;
857 GaimBuddyList *blist;
858 GSList *rem_list = NULL;
859 GSList *l;
860
861 if ((blist = gaim_get_blist())) {
862 for (gnode = blist->root; gnode; gnode = gnode->next) {
863 if (!GAIM_BLIST_NODE_IS_GROUP(gnode))
864 continue;
865 group = (GaimGroup *) gnode;
866 for (cnode = gnode->child; cnode; cnode = cnode->next) {
867 if (!GAIM_BLIST_NODE_IS_CONTACT(cnode))
868 continue;
869 for (bnode = cnode->child; bnode; bnode = bnode->next) {
870 if (!GAIM_BLIST_NODE_IS_BUDDY(bnode))
871 continue;
872 buddy = (GaimBuddy *) bnode;
873 if (buddy->account == user->client_data) {
874 rem_list = g_slist_append(rem_list, buddy);
875 }
876 }
877 }
878 }
879
880 if (rem_list) {
881 for (l = rem_list; l; l = l->next) {
882 gaim_blist_remove_buddy(l->data);
883 }
884 g_slist_free(rem_list);
885 }
886 }
887 }
888
889 /* Add all of the contacts in the given folder to the Gaim buddy list */
890 static void
891 _add_contacts_to_gaim_blist(NMUser * user, NMFolder * folder)
892 {
893 NMUserRecord *user_record = NULL;
894 NMContact *contact = NULL;
895 GaimBuddy *buddy = NULL;
896 NMERR_T cnt = 0, i;
897 const char *text = NULL;
898 const char *name = NULL;
899 int status = 0;
900
901 /* Get each contact for this folder */
902 cnt = nm_folder_get_contact_count(folder);
903 for (i = 0; i < cnt; i++) {
904 contact = nm_folder_get_contact(folder, i);
905 if (contact) {
906
907 name = nm_contact_get_display_id(contact);
908 if (name) {
909 /* Add it to the gaim buddy list */
910 buddy = gaim_buddy_new(user->client_data,
911 name,
912 nm_contact_get_display_name(contact));
913
914 /* Does the Gaim group exist already? */
915 GaimGroup *group = gaim_find_group(nm_folder_get_name(folder));
916
917 if (group == NULL) {
918 group = gaim_group_new(nm_folder_get_name(folder));
919 gaim_blist_add_group(group, NULL);
920 }
921
922 /* Set the initial status for the buddy */
923 user_record = nm_contact_get_user_record(contact);
924 if (user_record) {
925 status = nm_user_record_get_status(user_record);
926 text = nm_user_record_get_status_text(user_record);
927 }
928
929 gaim_blist_add_buddy(buddy, NULL, group, NULL);
930 _update_buddy_status(buddy, status, time(0));
931
932 /* Save the new buddy as part of the contact object */
933 nm_contact_set_data(contact, (gpointer) buddy);
934 }
935
936 } else {
937 /* NULL contact. This should not happen, but
938 * let's break out of the loop.
939 */
940 break;
941 }
942 }
943
944 }
945
946 /* Add all of the server side contacts to the Gaim buddy list. */
947 static void
948 _add_gaim_buddies(NMUser * user)
949 {
950 NMERR_T cnt = 0, i;
951 NMFolder *root_folder = NULL;
952 NMFolder *folder = NULL;
953
954 root_folder = nm_get_root_folder(user);
955 if (root_folder) {
956
957 /* Add contacts for the sub folders */
958 cnt = nm_folder_get_subfolder_count(root_folder);
959 for (i = 0; i < cnt; i++) {
960 folder = nm_folder_get_subfolder(root_folder, i);
961 if (folder) {
962 _add_contacts_to_gaim_blist(user, folder);
963 }
964 }
965
966 /* Add contacts for the root folder */
967 _add_contacts_to_gaim_blist(user, root_folder);
968 }
969 }
970
971 /* Display a dialog box showing the properties for the given user record */
972 static void
973 _show_info(GaimConnection * gc, NMUserRecord * user_record)
974 {
975 GString *info_text;
976 int count, i;
977 NMProperty *property;
978 const char *tag, *value;
979
980 info_text = g_string_new("");
981
982 tag = _("Userid");
983 value = nm_user_record_get_userid(user_record);
984 if (value) {
985 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>\n", tag, value);
986 }
987
988 /* tag = _("DN");
989 value = nm_user_record_get_dn(user_record);
990 if (value) {
991 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>\n",
992 tag, value);
993 }
994 */
995
996 tag = _("Full name");
997 value = nm_user_record_get_full_name(user_record);
998 if (value) {
999 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>\n", tag, value);
1000 }
1001
1002 count = nm_user_record_get_property_count(user_record);
1003 for (i = 0; i < count; i++) {
1004 property = nm_user_record_get_property(user_record, i);
1005 if (property) {
1006 tag = nm_property_get_tag(property);
1007 value = nm_property_get_value(property);
1008 if (tag && value) {
1009 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>\n",
1010 tag, value);
1011 }
1012 nm_release_property(property);
1013 }
1014 }
1015
1016 gaim_notify_formatted(NULL, "Title", _("User Properties"),
1017 NULL, info_text->str, NULL, NULL);
1018
1019 g_string_free(info_text, TRUE);
1020 }
1021
1022 /* Send a join conference, the first item in the parms list is the
1023 * NMUser object and the second item is the conference to join.
1024 * This callback is passed to gaim_request_action when we ask the
1025 * user if they want to join the conference.
1026 */
1027 static void
1028 _join_conference_cb(GSList * parms)
1029 {
1030 NMUser *user;
1031 NMConference *conference;
1032 NMERR_T rc = NM_OK;
1033
1034 if (parms == NULL || g_slist_length(parms) != 2)
1035 return;
1036
1037 user = g_slist_nth_data(parms, 0);
1038 conference = g_slist_nth_data(parms, 1);
1039
1040 if (user && conference) {
1041 rc = nm_send_join_conference(user, conference,
1042 _join_conf_resp_cb, conference);
1043 _check_for_disconnect(user, rc);
1044 }
1045
1046 g_slist_free(parms);
1047 }
1048
1049 /* Send a reject conference, the first item in the parms list is the
1050 * NMUser object and the second item is the conference to reject.
1051 * This callback is passed to gaim_request_action when we ask the
1052 * user if they want to joing the conference.
1053 */
1054 static void
1055 _reject_conference_cb(GSList * parms)
1056 {
1057 NMUser *user;
1058 NMConference *conference;
1059 NMERR_T rc = NM_OK;
1060
1061 if (parms == NULL || g_slist_length(parms) != 2)
1062 return;
1063
1064 user = g_slist_nth_data(parms, 0);
1065 conference = g_slist_nth_data(parms, 1);
1066
1067 if (user && conference) {
1068 rc = nm_send_reject_conference(user, conference, NULL, NULL);
1069 _check_for_disconnect(user, rc);
1070 }
1071
1072 g_slist_free(parms);
1073 }
1074
1075 /*******************************************************************************
1076 * Connect and recv callbacks
1077 ******************************************************************************/
1078
1079 static void
1080 novell_ssl_connect_error(GaimSslConnection * gsc,
1081 GaimSslErrorType error, gpointer data)
1082 {
1083 gaim_connection_error((GaimConnection *)data,
1084 _("Unable to make SSL connection to server."));
1085 }
1086
1087 static void
1088 novell_ssl_recv_cb(gpointer data, GaimSslConnection * gsc,
1089 GaimInputCondition condition)
1090 {
1091 GaimConnection *gc = data;
1092 NMUser *user;
1093 NMERR_T rc;
1094
1095 if (gc == NULL)
1096 return;
1097
1098 user = gc->proto_data;
1099 if (user == NULL)
1100 return;
1101
1102 rc = nm_process_new_data(user);
1103 if (rc != NM_OK) {
1104
1105 if (_is_disconnect_error(rc)) {
1106 gaim_connection_error(gc,
1107 _("Error communicating with server."
1108 " Closing connection."));
1109 } else {
1110
1111 char *error;
1112
1113 error = g_strdup_printf(_("Error processing event or response."
1114 " (0x%X)"), rc);
1115 gaim_notify_error(gc, NULL, error, NULL);
1116 g_free(error);
1117
1118 }
1119
1120 }
1121 }
1122
1123 static void
1124 novell_ssl_connected_cb(gpointer data, GaimSslConnection * gsc,
1125 GaimInputCondition cond)
1126 {
1127 GaimConnection *gc = data;
1128 NMUser *user;
1129 NMConn *conn;
1130 NMERR_T rc = 0;
1131 const char *pwd = NULL;
1132 const char *my_addr = NULL;
1133 char *ua = NULL;
1134
1135 if (gc == NULL || gsc == NULL)
1136 return;
1137
1138 user = gc->proto_data;
1139 if ((user == NULL) || (conn = user->conn) == NULL)
1140 return;
1141
1142 conn->ssl_conn = g_new0(NMSSLConn, 1);
1143 conn->ssl_conn->data = gsc;
1144 conn->ssl_conn->read = (nm_ssl_read_cb) gaim_ssl_read;
1145 conn->ssl_conn->write = (nm_ssl_write_cb) gaim_ssl_write;
1146
1147 gaim_connection_update_progress(gc, _("Authenticating..."),
1148 2, NOVELL_CONNECT_STEPS);
1149
1150 my_addr = gaim_network_get_ip_for_account(user->client_data, gsc->fd);
1151 pwd = gaim_account_get_password(user->client_data);
1152 ua = _user_agent_string();
1153
1154 rc = nm_send_login(user, pwd, my_addr, ua, _login_resp_cb, NULL);
1155 if (rc == NM_OK) {
1156 conn->connected = TRUE;
1157 gaim_ssl_input_add(gsc, novell_ssl_recv_cb, gc);
1158 } else {
1159 gaim_connection_error(gc, _("Unable to connect to server."));
1160 }
1161
1162 gaim_connection_update_progress(gc, _("Waiting for response..."),
1163 3, NOVELL_CONNECT_STEPS);
1164
1165 g_free(ua);
1166 }
1167
1168 /*******************************************************************************
1169 * Event callback and event handlers
1170 ******************************************************************************/
1171
1172 static void
1173 _evt_receive_message(NMUser * user, NMEvent * event)
1174 {
1175 NMUserRecord *user_record = NULL;
1176 NMContact *contact = NULL;
1177 GaimConversation *gconv;
1178 NMConference *conference;
1179 GaimConvImFlags imflags;
1180
1181 conference = nm_event_get_conference(event);
1182 if (conference) {
1183
1184 GaimConversation *chat = nm_conference_get_data(conference);
1185
1186 /* Is this a single person 'conversation' or a conference? */
1187 if (chat == NULL && nm_conference_get_participant_count(conference) == 1) {
1188
1189 user_record = nm_find_user_record(user, nm_event_get_source(event));
1190 if (user_record) {
1191
1192 imflags = 0;
1193 if (nm_event_get_type(event) == NMEVT_RECEIVE_AUTOREPLY)
1194 imflags |= GAIM_CONV_IM_AUTO_RESP;
1195
1196 serv_got_im(gaim_account_get_connection(user->client_data),
1197 nm_user_record_get_display_id(user_record),
1198 nm_event_get_text(event), imflags,
1199 nm_event_get_gmt(event));
1200
1201 gconv = gaim_find_conversation_with_account(
1202 nm_user_record_get_display_id(user_record),
1203 (GaimAccount *) user->client_data);
1204 if (gconv) {
1205
1206 contact = nm_find_contact(user, nm_event_get_source(event));
1207 if (contact) {
1208
1209 gaim_conversation_set_title(
1210 gconv,
1211 nm_contact_get_display_name(contact));
1212
1213
1214 } else {
1215
1216 const char *name =
1217 nm_user_record_get_full_name(user_record);
1218
1219 if (name == NULL)
1220 name = nm_user_record_get_userid(user_record);
1221
1222 gaim_conversation_set_title(gconv, name);
1223 }
1224
1225 }
1226
1227 } else {
1228 /* this should not happen, see the event code.
1229 * the event code will get the contact details from
1230 * the server if it does not have them before calling
1231 * the event callback.
1232 */
1233 }
1234
1235 } else if (chat) {
1236
1237 /* get the contact for send if we have one */
1238 NMContact *contact = nm_find_contact(user,
1239 nm_event_get_source(event));
1240
1241 /* get the user record for the sender */
1242 user_record = nm_find_user_record(user, nm_event_get_source(event));
1243 if (user_record) {
1244 const char *name = nm_contact_get_display_name(contact);
1245
1246 if (name == NULL) {
1247 name = nm_user_record_get_full_name(user_record);
1248 if (name == NULL)
1249 name = nm_user_record_get_display_id(user_record);
1250 }
1251
1252 serv_got_chat_in(gaim_account_get_connection(user->client_data),
1253 gaim_conv_chat_get_id(GAIM_CONV_CHAT(chat)),
1254 name,
1255 0, nm_event_get_text(event),
1256 nm_event_get_gmt(event));
1257 }
1258 }
1259 }
1260 }
1261
1262 static void
1263 _evt_conference_left(NMUser * user, NMEvent * event)
1264 {
1265 GaimConversation *chat;
1266 NMConference *conference;
1267
1268 conference = nm_event_get_conference(event);
1269 if (conference) {
1270 chat = nm_conference_get_data(conference);
1271 if (chat) {
1272 NMUserRecord *ur = nm_find_user_record(user,
1273 nm_event_get_source(event));
1274
1275 if (ur)
1276 gaim_conv_chat_remove_user(GAIM_CONV_CHAT(chat),
1277 nm_user_record_get_display_id(ur),
1278 NULL);
1279 }
1280 }
1281 }
1282
1283 static void
1284 _evt_conference_invite(NMUser * user, NMEvent * event)
1285 {
1286 NMUserRecord *ur;
1287 GSList *parms = NULL;
1288 const char *title = NULL;
1289 const char *secondary = NULL;
1290 const char *name = NULL;
1291 char *primary = NULL;
1292 time_t gmt;
1293
1294 ur = nm_find_user_record(user, nm_event_get_source(event));
1295 if (ur)
1296 name = nm_user_record_get_full_name(ur);
1297
1298 if (name == NULL)
1299 name = nm_event_get_source(event);
1300
1301 gmt = nm_event_get_gmt(event);
1302 title = _("Invitation to Conversation");
1303 primary = g_strdup_printf(_("Invitation from: %s\n\nSent: %s"),
1304 name, asctime(localtime(&gmt)));
1305 secondary = _("Would you like to join the conversation?");
1306
1307 /* Set up parms list for the callbacks
1308 * We need to send the NMUser object and
1309 * the NMConference object to the callbacks
1310 */
1311 parms = NULL;
1312 parms = g_slist_append(parms, user);
1313 parms = g_slist_append(parms, nm_event_get_conference(event));
1314
1315 /* Prompt the user */
1316 gaim_request_action(NULL, title, primary, secondary, -1, parms, 2,
1317 _("Yes"), G_CALLBACK(_join_conference_cb),
1318 _("No"), G_CALLBACK(_reject_conference_cb));
1319
1320 g_free(primary);
1321 }
1322
1323
1324 static void
1325 _evt_conference_joined(NMUser * user, NMEvent * event)
1326 {
1327 GaimConversation *chat = NULL;
1328 GaimConnection *gc;
1329 NMConference *conference = NULL;
1330 NMUserRecord *ur = NULL;
1331 const char *name;
1332 char *conf_name;
1333
1334 gc = gaim_account_get_connection(user->client_data);
1335 if (gc == NULL)
1336 return;
1337
1338 conference = nm_event_get_conference(event);
1339 if (conference) {
1340 chat = nm_conference_get_data(conference);
1341 if (nm_conference_get_participant_count(conference) == 2 && chat == NULL) {
1342 ur = nm_conference_get_participant(conference, 0);
1343 if (ur) {
1344 conf_name = g_strdup_printf(_("GroupWise Conference %d"),
1345 ++user->conference_count);
1346 chat =
1347 serv_got_joined_chat(gc, user->conference_count, conf_name);
1348 g_free(conf_name);
1349 if (chat) {
1350
1351 nm_conference_set_data(conference, (gpointer) chat);
1352
1353 name = nm_user_record_get_display_id(ur);
1354 gaim_conv_chat_add_user(GAIM_CONV_CHAT(chat), name, NULL);
1355
1356 }
1357 }
1358 }
1359
1360 if (chat != NULL) {
1361 ur = nm_find_user_record(user, nm_event_get_source(event));
1362 if (ur) {
1363 name = nm_user_record_get_display_id(ur);
1364 gaim_conv_chat_add_user(GAIM_CONV_CHAT(chat), name, NULL);
1365 }
1366 }
1367 }
1368 }
1369
1370 static void
1371 _evt_status_change(NMUser * user, NMEvent * event)
1372 {
1373 GaimBuddy *buddy = NULL;
1374 GSList *buddies;
1375 GSList *bnode;
1376 NMUserRecord *user_record;
1377 const char *display_id;
1378 int status;
1379
1380 user_record = nm_event_get_user_record(event);
1381 if (user_record) {
1382
1383 /* Retrieve new status */
1384 status = nm_user_record_get_status(user_record);
1385
1386 /* Update status for buddy in all folders */
1387 display_id = nm_user_record_get_display_id(user_record);
1388 buddies = gaim_find_buddies(user->client_data, display_id);
1389 for (bnode = buddies; bnode; bnode = bnode->next) {
1390 buddy = (GaimBuddy *) bnode->data;
1391 if (buddy) {
1392 _update_buddy_status(buddy, status, nm_event_get_gmt(event));
1393 }
1394 }
1395
1396 g_slist_free(buddies);
1397
1398 }
1399 }
1400
1401 static void
1402 _evt_user_disconnect(NMUser * user, NMEvent * event)
1403 {
1404 GaimConnection *gc;
1405
1406 gc = gaim_account_get_connection((GaimAccount *) user->client_data);
1407 if (gc)
1408 gaim_connection_error(gc, _("You have been logged out because you"
1409 " logged in at another workstation."));
1410 }
1411
1412 static void
1413 _evt_user_typing(NMUser * user, NMEvent * event)
1414 {
1415 GaimConnection *gc;
1416 NMUserRecord *user_record = NULL;
1417
1418 gc = gaim_account_get_connection((GaimAccount *) user->client_data);
1419 if (gc) {
1420 user_record = nm_find_user_record(user, nm_event_get_source(event));
1421 if (user_record) {
1422 serv_got_typing(gc, nm_user_record_get_display_id(user_record),
1423 30, GAIM_TYPING);
1424 }
1425 }
1426 }
1427
1428 static void
1429 _evt_user_not_typing(NMUser * user, NMEvent * event)
1430 {
1431 GaimConnection *gc;
1432 NMUserRecord *user_record;
1433
1434 gc = gaim_account_get_connection((GaimAccount *) user->client_data);
1435 if (gc) {
1436 user_record = nm_find_user_record(user, nm_event_get_source(event));
1437 if (user_record) {
1438 serv_got_typing_stopped(gc,
1439 nm_user_record_get_display_id(user_record));
1440 }
1441 }
1442 }
1443
1444 static void
1445 _evt_undeliverable_status(NMUser * user, NMEvent * event)
1446 {
1447 NMUserRecord *ur;
1448 GaimConversation *gconv;
1449 char *str;
1450
1451 ur = nm_find_user_record(user, nm_event_get_source(event));
1452 if (ur) {
1453 gconv =
1454 gaim_find_conversation_with_account(nm_user_record_get_display_id(ur),
1455 user->client_data);
1456 if (gconv) {
1457 const char *name = nm_user_record_get_full_name(ur);
1458
1459 if (name == NULL) {
1460 name = nm_user_record_get_display_id(ur);
1461 }
1462 str = g_strdup_printf(_("%s appears to be offline and did not receive"
1463 " the message that you just sent."), name);
1464 gaim_conversation_write(gconv, NULL, str,
1465 GAIM_MESSAGE_SYSTEM, time(NULL));
1466 g_free(str);
1467 }
1468 }
1469 }
1470
1471 static void
1472 _event_callback(NMUser * user, NMEvent * event)
1473 {
1474 if (user == NULL || event == NULL)
1475 return;
1476
1477 switch (nm_event_get_type(event)) {
1478 case NMEVT_STATUS_CHANGE:
1479 _evt_status_change(user, event);
1480 break;
1481 case NMEVT_RECEIVE_AUTOREPLY:
1482 case NMEVT_RECEIVE_MESSAGE:
1483 _evt_receive_message(user, event);
1484 break;
1485 case NMEVT_USER_DISCONNECT:
1486 _evt_user_disconnect(user, event);
1487 break;
1488 case NMEVT_USER_TYPING:
1489 _evt_user_typing(user, event);
1490 break;
1491 case NMEVT_USER_NOT_TYPING:
1492 _evt_user_not_typing(user, event);
1493 break;
1494 case NMEVT_SERVER_DISCONNECT:
1495 /* Nothing to do? */
1496 break;
1497 case NMEVT_INVALID_RECIPIENT:
1498 break;
1499 case NMEVT_UNDELIVERABLE_STATUS:
1500 _evt_undeliverable_status(user, event);
1501 break;
1502 case NMEVT_CONFERENCE_INVITE_NOTIFY:
1503 /* Someone else has been invited to join a
1504 * conference that we are currently a part of
1505 */
1506 /* TODO: show the invite notify in chat window */
1507 break;
1508 case NMEVT_CONFERENCE_INVITE:
1509 /* We have been invited to join a conference */
1510 _evt_conference_invite(user, event);
1511 break;
1512 case NMEVT_CONFERENCE_JOINED:
1513 /* Some one has joined a conference that we
1514 * are a part of
1515 */
1516 _evt_conference_joined(user, event);
1517 break;
1518 case NMEVT_CONFERENCE_LEFT:
1519 /* Someone else has left a conference that we
1520 * are currently a part of
1521 */
1522 _evt_conference_left(user, event);
1523 break;
1524 default:
1525 gaim_debug(GAIM_DEBUG_INFO, "novell",
1526 "_event_callback(): unhandled event, %d\n",
1527 nm_event_get_type(event));
1528 break;
1529 }
1530 }
1531
1532 /*******************************************************************************
1533 * Prpl Ops
1534 ******************************************************************************/
1535
1536 static void
1537 novell_login(GaimAccount * account)
1538 {
1539 GaimConnection *gc;
1540 NMUser *user = NULL;
1541 const char *server;
1542 const char *name;
1543 int port;
1544
1545 if (account == NULL)
1546 return;
1547
1548 gc = gaim_account_get_connection(account);
1549 if (gc == NULL)
1550 return;
1551
1552 server = gaim_account_get_string(account, "server", NULL);
1553 if (server == NULL || *server == '\0') {
1554
1555 /* TODO: Would be nice to prompt if not set!
1556 * gaim_request_fields(gc, _("Server Address"),...);
1557 */
1558
1559 /* ...but for now just error out with a nice message. */
1560 gaim_connection_error(gc, _("Unable to connect to server."
1561 " Please enter the address of the server"
1562 " you wish to connect to."));
1563 return;
1564 }
1565
1566 port = gaim_account_get_int(account, "port", DEFAULT_PORT);
1567 name = gaim_account_get_username(account);
1568
1569 user = nm_initialize_user(name, server, port, account, _event_callback);
1570 if (user) {
1571 /* save user */
1572 gc->proto_data = user;
1573
1574 /* connect to the server */
1575 gaim_connection_update_progress(gc, _("Connecting"),
1576 1, NOVELL_CONNECT_STEPS);
1577
1578 user->conn->use_ssl = TRUE;
1579 if (gaim_ssl_connect(user->client_data, user->conn->addr,
1580 user->conn->port, novell_ssl_connected_cb,
1581 novell_ssl_connect_error, gc) == NULL) {
1582 gaim_connection_error(gc, _("Error."
1583 " SSL support is not installed."));
1584 }
1585 }
1586 }
1587
1588 static void
1589 novell_close(GaimConnection * gc)
1590 {
1591 NMUser *user;
1592 NMConn *conn;
1593
1594 if (gc == NULL)
1595 return;
1596
1597 user = gc->proto_data;
1598 if (user) {
1599 conn = user->conn;
1600 if (conn) {
1601 if (conn->use_ssl && user->conn->ssl_conn) {
1602 gaim_ssl_close(user->conn->ssl_conn->data);
1603 } else {
1604 gaim_input_remove(gc->inpa);
1605 close(conn->fd);
1606 }
1607 }
1608 nm_deinitialize_user(user);
1609 }
1610 gc->proto_data = NULL;
1611 }
1612
1613 static int
1614 novell_send_im(GaimConnection * gc, const char *name,
1615 const char *message_body, GaimConvImFlags flags)
1616 {
1617 NMUserRecord *user_record = NULL;
1618 NMConference *conf = NULL;
1619 NMMessage *message;
1620 NMUser *user;
1621 const char *dn = NULL;
1622 gboolean done = TRUE, created_conf = FALSE;
1623 NMERR_T rc = NM_OK;
1624
1625 if (gc == NULL || name == NULL ||
1626 message_body == NULL || *message_body == '\0')
1627 return 0;
1628
1629 user = gc->proto_data;
1630 if (user == NULL)
1631 return 0;
1632
1633 /* Create a new message */
1634 message = nm_create_message(gaim_markup_strip_html(message_body));
1635
1636 /* Need to get the DN for the buddy so we can look up the convo */
1637 dn = nm_lookup_dn(user, name);
1638
1639 /* Do we already know about the sender? */
1640 user_record = nm_find_user_record(user, dn);
1641 if (user_record) {
1642
1643 /* Do we already have an instantiated conference? */
1644 conf = nm_find_conversation(user, dn);
1645 if (conf == NULL) {
1646
1647 /* If not, create a blank conference */
1648 conf = nm_create_conference(NULL);
1649 created_conf = TRUE;
1650
1651 nm_conference_add_participant(conf, user_record);
1652 }
1653
1654 nm_message_set_conference(message, conf);
1655
1656 /* Make sure conference is instatiated */
1657 if (!nm_conference_is_instantiated(conf)) {
1658
1659 /* It is not, so send the createconf. We will
1660 * have to finish sending the message when we
1661 * get the response with the new conference guid.
1662 */
1663 rc = nm_send_create_conference(user, conf,
1664 _createconf_resp_send_msg, message);
1665 _check_for_disconnect(user, rc);
1666
1667 done = FALSE;
1668 }
1669
1670 } else {
1671
1672 /* If we don't have details for the user, then we don't have
1673 * a conference yet. So create one and send the getdetails
1674 * to the server. We will have to finish sending the message
1675 * when we get the response from the server.
1676 */
1677 conf = nm_create_conference(NULL);
1678 created_conf = TRUE;
1679
1680 nm_message_set_conference(message, conf);
1681
1682 rc = nm_send_get_details(user, name, _get_details_resp_send_msg, message);
1683 _check_for_disconnect(user, rc);
1684
1685 done = FALSE;
1686 }
1687
1688 if (done) {
1689
1690 /* Did we find everything we needed? */
1691 rc = nm_send_message(user, message, _send_message_resp_cb);
1692 _check_for_disconnect(user, rc);
1693
1694 nm_release_message(message);
1695 }
1696
1697 if (created_conf && conf)
1698 nm_release_conference(conf);
1699
1700 return 1;
1701 }
1702
1703 static int
1704 novell_send_typing(GaimConnection * gc, const char *name, int typing)
1705 {
1706 NMConference *conf = NULL;
1707 NMUser *user;
1708 const char *dn = NULL;
1709 NMERR_T rc = NM_OK;
1710
1711 if (gc == NULL || name == NULL)
1712 return -1;
1713
1714 user = gc->proto_data;
1715 if (user == NULL)
1716 return -1;
1717
1718 /* Need to get the DN for the buddy so we can look up the convo */
1719 dn = nm_lookup_dn(user, name);
1720 if (dn) {
1721
1722 /* Now find the conference in our list */
1723 conf = nm_find_conversation(user, dn);
1724 if (conf) {
1725
1726 rc = nm_send_typing(user, conf,
1727 ((typing == GAIM_TYPING) ? TRUE : FALSE), NULL);
1728 _check_for_disconnect(user, rc);
1729
1730 }
1731
1732 }
1733
1734 return 0;
1735 }
1736
1737 static void
1738 novell_convo_closed(GaimConnection * gc, const char *who)
1739 {
1740 NMUser *user;
1741 NMConference *conf;
1742 const char *dn;
1743 NMERR_T rc = NM_OK;
1744
1745 if (gc == NULL || who == NULL)
1746 return;
1747
1748 user = gc->proto_data;
1749 if (user && (dn = nm_lookup_dn(user, who))) {
1750 conf = nm_find_conversation(user, dn);
1751 if (conf) {
1752 rc = nm_send_leave_conference(user, conf, NULL, NULL);
1753 _check_for_disconnect(user, rc);
1754 }
1755 }
1756 }
1757
1758 static void
1759 novell_chat_leave(GaimConnection * gc, int id)
1760 {
1761 NMConference *conference;
1762 NMUser *user;
1763 GaimConversation *chat;
1764 GSList *cnode;
1765 NMERR_T rc = NM_OK;
1766
1767 if (gc == NULL)
1768 return;
1769
1770 user = gc->proto_data;
1771 if (user == NULL)
1772 return;
1773
1774 for (cnode = user->conferences; cnode != NULL; cnode = cnode->next) {
1775 conference = cnode->data;
1776 if (conference && (chat = nm_conference_get_data(conference))) {
1777 if (gaim_conv_chat_get_id(GAIM_CONV_CHAT(chat)) == id) {
1778 rc = nm_send_leave_conference(user, conference, NULL, NULL);
1779 _check_for_disconnect(user, rc);
1780 break;
1781 }
1782 }
1783 }
1784
1785 serv_got_chat_left(gc, id);
1786 }
1787
1788 static int
1789 novell_chat_send(GaimConnection * gc, int id, const char *text)
1790 {
1791 NMConference *conference;
1792 GaimConversation *chat;
1793 GSList *cnode;
1794 NMMessage *message;
1795 NMUser *user;
1796 NMERR_T rc = NM_OK;
1797 const char *name;
1798 char *str;
1799
1800 if (gc == NULL || text == NULL)
1801 return -1;
1802
1803 user = gc->proto_data;
1804 if (user == NULL)
1805 return -1;
1806
1807 message = nm_create_message(gaim_markup_strip_html(text));
1808
1809 for (cnode = user->conferences; cnode != NULL; cnode = cnode->next) {
1810 conference = cnode->data;
1811 if (conference && (chat = nm_conference_get_data(conference))) {
1812 if (gaim_conv_chat_get_id(GAIM_CONV_CHAT(chat)) == id) {
1813
1814 nm_message_set_conference(message, conference);
1815
1816 rc = nm_send_message(user, message, _send_message_resp_cb);
1817 nm_release_message(message);
1818
1819 if (!_check_for_disconnect(user, rc)) {
1820
1821 /* Use the account alias if it is set */
1822 name = gaim_account_get_alias(user->client_data);
1823 if (name == NULL || *name == '\0') {
1824
1825 /* If there is no account alias, try full name */
1826 name = nm_user_record_get_full_name(user->user_record);
1827 if (name == NULL || *name == '\0') {
1828
1829 /* Fall back to the username that we are signed in with */
1830 name = gaim_account_get_username(user->client_data);
1831 }
1832 }
1833
1834 serv_got_chat_in(gc, id, name, 0, text, time(NULL));
1835 return 0;
1836 } else
1837 return -1;
1838
1839 }
1840 }
1841 }
1842
1843 /* The conference was not found, must be closed */
1844 chat = gaim_find_chat(gc, id);
1845 if (chat) {
1846 str = g_strdup_printf(_("This conference has been closed."
1847 " No more messages can be sent."));
1848 gaim_conversation_write(chat, NULL, str, GAIM_MESSAGE_SYSTEM, time(NULL));
1849 g_free(str);
1850 }
1851
1852 return -1;
1853 }
1854
1855 static void
1856 novell_add_buddy(GaimConnection * gc, const char *name, GaimGroup * group)
1857 {
1858 GaimBuddy *buddy;
1859 NMFolder *folder = NULL;
1860 NMContact *contact;
1861 NMUser *user;
1862 NMERR_T rc = NM_OK;
1863
1864 if (gc == NULL || name == NULL || group == NULL)
1865 return;
1866
1867 user = (NMUser *) gc->proto_data;
1868 if (user == NULL)
1869 return;
1870
1871 contact = nm_create_contact();
1872 nm_contact_set_dn(contact, name);
1873
1874 /* Remove the GaimBuddy (we will add it back after adding it
1875 * to the server side list). Save the alias if there is one.
1876 */
1877 buddy = gaim_find_buddy_in_group(user->client_data, name, group);
1878 if (buddy) {
1879 const char *alias = gaim_get_buddy_alias(buddy);
1880
1881 if (alias && strcmp(alias, name))
1882 nm_contact_set_display_name(contact, gaim_get_buddy_alias(buddy));
1883 gaim_blist_remove_buddy(buddy);
1884 buddy = NULL;
1885 }
1886
1887
1888 folder = nm_find_folder(user, group->name);
1889 if (folder) {
1890
1891 /* We have everything that we need, so send the createcontact */
1892 rc = nm_send_create_contact(user, folder, contact,
1893 _create_contact_resp_cb, contact);
1894
1895 } else {
1896
1897 /* Need to create the folder before we can add the contact */
1898 rc = nm_send_create_folder(user, group->name,
1899 _create_folder_resp_add_contact, contact);
1900 }
1901
1902 _check_for_disconnect(user, rc);
1903
1904 }
1905
1906 static void
1907 novell_remove_buddy(GaimConnection * gc, const char *name, const char *group_name)
1908 {
1909 NMContact *contact;
1910 NMFolder *folder;
1911 NMUser *user;
1912 const char *dn;
1913 NMERR_T rc = NM_OK;
1914
1915 if (gc == NULL || name == NULL || group_name == NULL)
1916 return;
1917
1918 user = (NMUser *) gc->proto_data;
1919 if (user && (dn = nm_lookup_dn(user, name))) {
1920
1921 folder = nm_find_folder(user, group_name);
1922 if (folder) {
1923 contact = nm_folder_find_contact(folder, dn);
1924 if (contact) {
1925
1926 /* Remove the buddy from the contact */
1927 nm_contact_set_data(contact, NULL);
1928
1929 /* Tell the server to remove the contact */
1930 rc = nm_send_remove_contact(user, folder, contact,
1931 _remove_contact_resp_cb, NULL);
1932 _check_for_disconnect(user, rc);
1933 }
1934 }
1935 }
1936 }
1937
1938 static void
1939 novell_remove_group(GaimConnection * gc, const char *name)
1940 {
1941 NMUser *user;
1942 NMERR_T rc = NM_OK;
1943
1944 if (gc == NULL || name == NULL)
1945 return;
1946
1947 user = (NMUser *) gc->proto_data;
1948 if (user) {
1949 NMFolder *folder = nm_find_folder(user, name);
1950
1951 if (folder) {
1952 rc = nm_send_remove_folder(user, folder,
1953 _remove_folder_resp_cb, NULL);
1954 _check_for_disconnect(user, rc);
1955 }
1956 }
1957 }
1958
1959 static void
1960 novell_alias_buddy(GaimConnection * gc, const char *name, const char *alias)
1961 {
1962 NMContact *contact;
1963 NMUser *user;
1964 GList *contacts = NULL;
1965 GList *cnode = NULL;
1966 const char *dn = NULL;
1967 NMERR_T rc = NM_OK;
1968
1969 if (gc == NULL || name == NULL || alias == NULL)
1970 return;
1971
1972 user = (NMUser *) gc->proto_data;
1973 if (user && (dn = nm_lookup_dn(user, name))) {
1974
1975 /* Alias all of instances of the contact */
1976 contacts = nm_find_contacts(user, dn);
1977 for (cnode = contacts; cnode != NULL; cnode = cnode->next) {
1978 contact = (NMContact *) cnode->data;
1979 if (contact) {
1980 GaimGroup *group;
1981 GaimBuddy *buddy;
1982 NMFolder *folder;
1983
1984 /* Alias the Gaim buddy? */
1985 folder = nm_find_folder_by_id(user,
1986 nm_contact_get_parent_id(contact));
1987 if (folder &&
1988 (group = gaim_find_group(nm_folder_get_name(folder)))) {
1989 buddy = gaim_find_buddy_in_group(user->client_data,
1990 name, group);
1991 if (buddy && strcmp(buddy->alias, alias))
1992 gaim_blist_alias_buddy(buddy, alias);
1993
1994 }
1995 /* Tell the server to alias the contact */
1996 rc = nm_send_rename_contact(user, contact, alias,
1997 _rename_contact_resp_cb, NULL);
1998 _check_for_disconnect(user, rc);
1999 }
2000 }
2001 if (contacts)
2002 g_list_free(contacts);
2003 }
2004 }
2005
2006 static void
2007 novell_group_buddy(GaimConnection * gc,
2008 const char *name, const char *old_group_name,
2009 const char *new_group_name)
2010 {
2011 NMFolder *old_folder;
2012 NMFolder *new_folder;
2013 NMContact *contact;
2014 NMUser *user;
2015 const char *dn;
2016 NMERR_T rc = NM_OK;
2017
2018 if (gc == NULL || name == NULL ||
2019 old_group_name == NULL || new_group_name == NULL)
2020 return;
2021
2022 user = (NMUser *) gc->proto_data;
2023 if (user && (dn = nm_lookup_dn(user, name))) {
2024
2025 /* Find the old folder */
2026 old_folder = nm_find_folder(user, old_group_name);
2027 if (old_folder && (contact = nm_folder_find_contact(old_folder, dn))) {
2028
2029 /* Find the new folder */
2030 new_folder = nm_find_folder(user, new_group_name);
2031 if (new_folder) {
2032
2033 /* Tell the server to move the contact to the new folder */
2034 rc = nm_send_move_contact(user, contact, new_folder,
2035 _move_contact_resp_cb, NULL);
2036
2037 } else {
2038
2039 nm_contact_add_ref(contact);
2040
2041 /* Remove the old contact first */
2042 nm_send_remove_contact(user, old_folder, contact,
2043 _remove_contact_resp_cb, NULL);
2044
2045 /* New folder does not exist yet, so create it */
2046 rc = nm_send_create_folder(user, new_group_name,
2047 _create_folder_resp_move_contact,
2048 contact);
2049 }
2050
2051 _check_for_disconnect(user, rc);
2052 }
2053 }
2054 }
2055
2056 static void
2057 novell_rename_group(GaimConnection * gc, const char *old_name,
2058 const char *new_name, GList * tobemoved)
2059 {
2060 NMERR_T rc = NM_OK;
2061 NMUser *user;
2062
2063 if (gc == NULL || old_name == NULL || new_name == NULL || tobemoved == NULL) {
2064 return;
2065 }
2066
2067 user = gc->proto_data;
2068 if (user) {
2069 /* Does new folder exist already? */
2070 if (nm_find_folder(user, new_name)) {
2071 /* Gaim currently calls novell_group_buddy() for
2072 * for all buddies in the group, so we don't
2073 * need to worry about this situation.
2074 */
2075 return;
2076 }
2077
2078 NMFolder *folder = nm_find_folder(user, old_name);
2079
2080 if (folder) {
2081 rc = nm_send_rename_folder(user, folder, new_name,
2082 _rename_folder_resp_cb, NULL);
2083 _check_for_disconnect(user, rc);
2084 }
2085 }
2086 }
2087
2088 static void
2089 novell_list_emblems(GaimBuddy * buddy, char **se, char **sw, char **nw, char **ne)
2090 {
2091 int status = buddy->uc >> 1;
2092
2093 switch (status) {
2094 case NM_STATUS_AVAILABLE:
2095 *se = "";
2096 break;
2097 case NM_STATUS_AWAY:
2098 *se = "away";
2099 break;
2100 case NM_STATUS_BUSY:
2101 *se = "occupied";
2102 break;
2103 case NM_STATUS_UNKNOWN:
2104 *se = "error";
2105 break;
2106 }
2107 }
2108
2109 static const char *
2110 novell_list_icon(GaimAccount * account, GaimBuddy * buddy)
2111 {
2112 return "novell";
2113 }
2114
2115 static char *
2116 novell_tooltip_text(GaimBuddy * buddy)
2117 {
2118 NMUserRecord *user_record = NULL;
2119 GaimConnection *gc;
2120 NMUser *user;
2121 int status = 0;
2122 char *ret_text = NULL;
2123 const char *status_str = NULL;
2124 const char *text = NULL;
2125
2126 if (buddy == NULL)
2127 return "";
2128
2129 gc = gaim_account_get_connection(buddy->account);
2130 if (gc == NULL || (user = gc->proto_data) == NULL)
2131 return "";
2132
2133 if (GAIM_BUDDY_IS_ONLINE(buddy)) {
2134 user_record = nm_find_user_record(user, buddy->name);
2135 if (user_record) {
2136 status = nm_user_record_get_status(user_record);
2137 text = nm_user_record_get_status_text(user_record);
2138 /* No custom text, so default it ... */
2139 switch (status) {
2140 case NM_STATUS_AVAILABLE:
2141 status_str = _("Available");
2142 break;
2143 case NM_STATUS_AWAY:
2144 status_str = _("Away");
2145 break;
2146 case NM_STATUS_BUSY:
2147 status_str = _("Busy");
2148 break;
2149 case NM_STATUS_AWAY_IDLE:
2150 status_str = _("Idle");
2151 break;
2152 case NM_STATUS_OFFLINE:
2153 status_str = _("Offline");
2154 break;
2155 default:
2156 status_str = _("Unknown");
2157 break;
2158 }
2159
2160 if (text)
2161 ret_text = g_strdup_printf(_("<b>Status:</b> %s\n"
2162 "<b>Message:</b> %s"),
2163 status_str, text);
2164 else
2165 ret_text = g_strdup_printf(_("<b>Status:</b> %s"), status_str);
2166 }
2167 }
2168
2169 return ret_text;
2170 }
2171
2172 static void
2173 novell_set_idle(GaimConnection * gc, int time)
2174 {
2175 NMUser *user;
2176 NMERR_T rc = NM_OK;
2177
2178 if (gc == NULL)
2179 return;
2180
2181 user = gc->proto_data;
2182 if (user == NULL)
2183 return;
2184
2185 if (time > 0)
2186 rc = nm_send_set_status(user, NM_STATUS_AWAY_IDLE, NULL, NULL, NULL,
2187 NULL);
2188 else
2189 rc = nm_send_set_status(user, NM_STATUS_AVAILABLE, NULL, NULL, NULL,
2190 NULL);
2191
2192 _check_for_disconnect(user, rc);
2193 }
2194
2195 static void
2196 novell_get_info(GaimConnection * gc, const char *name)
2197 {
2198 NMUserRecord *user_record;
2199 NMUser *user;
2200 NMERR_T rc;
2201
2202 if (gc == NULL || name == NULL)
2203 return;
2204
2205 user = (NMUser *) gc->proto_data;
2206 if (user) {
2207
2208 user_record = nm_find_user_record(user, name);
2209 if (user_record) {
2210
2211 _show_info(gc, user_record);
2212
2213 } else {
2214
2215 rc = nm_send_get_details(user, name,
2216 _get_details_resp_show_info, g_strdup(name));
2217
2218 _check_for_disconnect(user, rc);
2219
2220 }
2221
2222 }
2223 }
2224
2225 static char *
2226 novell_status_text(GaimBuddy * buddy)
2227 {
2228 const char *text = NULL;
2229 const char *dn = NULL;
2230
2231 if (buddy && buddy->account) {
2232 GaimConnection *gc = gaim_account_get_connection(buddy->account);
2233
2234 if (gc && gc->proto_data) {
2235 NMUser *user = gc->proto_data;
2236
2237 dn = nm_lookup_dn(user, buddy->name);
2238 if (dn) {
2239 NMUserRecord *user_record = nm_find_user_record(user, dn);
2240
2241 if (user_record) {
2242 text = nm_user_record_get_status_text(user_record);
2243 if (text)
2244 return g_strdup(text);
2245 }
2246 }
2247 }
2248 }
2249
2250 return NULL;
2251 }
2252
2253 static GList *
2254 novell_away_states(GaimConnection * gc)
2255 {
2256 GList *m = NULL;
2257
2258 m = g_list_append(m, _("Available"));
2259 m = g_list_append(m, _("Away"));
2260 m = g_list_append(m, _("Busy"));
2261 m = g_list_append(m, _("Appear Offline"));
2262 m = g_list_append(m, GAIM_AWAY_CUSTOM);
2263
2264 return m;
2265 }
2266
2267 static void
2268 novell_set_away(GaimConnection * gc, const char *state, const char *msg)
2269 {
2270 NMUser *user;
2271 NMSTATUS_T status = NM_STATUS_AVAILABLE;
2272 NMERR_T rc = NM_OK;
2273 char *text = NULL;
2274 char *tmp = NULL;
2275 char *p = NULL;
2276
2277 if (gc == NULL)
2278 return;
2279
2280 user = gc->proto_data;
2281 if (user == NULL)
2282 return;
2283
2284 if (gc->away) {
2285 g_free(gc->away);
2286 gc->away = NULL;
2287 }
2288
2289 if (msg != NULL) {
2290 status = NM_STATUS_AWAY;
2291 gc->away = g_strdup("");
2292
2293 /* Don't want newlines in status text */
2294 tmp = g_strdup(msg);
2295 if ((p = strchr(tmp, '\n'))) {
2296 *p = '\0';
2297 }
2298
2299 /* Truncate the status text if necessary */
2300 text = g_strdup(tmp);
2301 if (g_utf8_strlen(tmp, -1) > 60) {
2302 g_utf8_strncpy(text, tmp, 60);
2303 strcat(text, "...");
2304 }
2305
2306 g_free(tmp);
2307
2308 } else if (state) {
2309 if (!strcmp(state, _("Available"))) {
2310 status = NM_STATUS_AVAILABLE;
2311 } else if (!strcmp(state, _("Away"))) {
2312 status = NM_STATUS_AWAY;
2313 gc->away = g_strdup("");
2314 } else if (!strcmp(state, _("Busy"))) {
2315 status = NM_STATUS_BUSY;
2316 gc->away = g_strdup("");
2317 } else if (!strcmp(state, _("Appear Offline"))) {
2318 status = NM_STATUS_OFFLINE;
2319 gc->away = g_strdup("");
2320 } else {
2321 status = NM_STATUS_AVAILABLE;
2322 g_free(gc->away);
2323 gc->away = NULL;
2324 }
2325 } else if (gc->is_idle) {
2326 status = NM_STATUS_AWAY_IDLE;
2327 } else {
2328 status = NM_STATUS_AVAILABLE;
2329 }
2330
2331 rc = nm_send_set_status(user, status, text, msg, NULL, NULL);
2332 _check_for_disconnect(user, rc);
2333
2334 if (text)
2335 g_free(text);
2336 }
2337
2338 static GaimPluginProtocolInfo prpl_info = {
2339 0,
2340 NULL,
2341 NULL,
2342 NULL,
2343 novell_list_icon,
2344 novell_list_emblems,
2345 novell_status_text,
2346 novell_tooltip_text,
2347 novell_away_states,
2348 NULL, /* prpl_actions */
2349 NULL, /* buddy_menu */
2350 NULL, /* chat_info */
2351 novell_login,
2352 novell_close,
2353 novell_send_im,
2354 NULL, /* set_info */
2355 novell_send_typing,
2356 novell_get_info,
2357 novell_set_away,
2358 NULL, /* set_dir */
2359 NULL, /* get_dir */
2360 NULL, /* dir_search */
2361 novell_set_idle,
2362 NULL, /* change pwd */
2363 novell_add_buddy,
2364 NULL, /* add_buddies */
2365 novell_remove_buddy,
2366 NULL, /* remove_buddies */
2367 NULL, /* add_permit */
2368 NULL, /* add_deny */
2369 NULL, /* rem_permit */
2370 NULL, /* rem_deny */
2371 NULL, /* set_permit_deny */
2372 NULL, /* warn */
2373 NULL, /* join_chat */
2374 NULL, /* reject_chat ?? */
2375 NULL, /* chat_invite */
2376 novell_chat_leave,
2377 NULL, /* chat_whisper */
2378 novell_chat_send,
2379 NULL, /* keepalive */
2380 NULL, /* register_user */
2381 NULL, /* get_cb_info */
2382 NULL, /* get_cb_away_msg */
2383 novell_alias_buddy,
2384 novell_group_buddy,
2385 novell_rename_group,
2386 NULL, /* buddy_free */
2387 novell_convo_closed,
2388 NULL, /* normalize */
2389 NULL, /* set_buddy_icon */
2390 novell_remove_group,
2391 NULL
2392 };
2393
2394 static GaimPluginInfo info = {
2395 2, /**< api_version */
2396 GAIM_PLUGIN_PROTOCOL, /**< type */
2397 NULL, /**< ui_requirement */
2398 0, /**< flags */
2399 NULL, /**< dependencies */
2400 GAIM_PRIORITY_DEFAULT, /**< priority */
2401
2402 "prpl-novell", /**< id */
2403 "GroupWise Messenger", /**< name */
2404 VERSION, /**< version */
2405 /** summary */
2406 N_("Novell GroupWise Messenger Protocol Plugin"),
2407 /** description */
2408 N_("Novell GroupWise Messenger Protocol Plugin"),
2409 NULL, /**< author */
2410 GAIM_WEBSITE, /**< homepage */
2411
2412 NULL, /**< load */
2413 NULL, /**< unload */
2414 NULL, /**< destroy */
2415
2416 NULL, /**< ui_info */
2417 &prpl_info /**< extra_info */
2418 };
2419
2420 static void
2421 init_plugin(GaimPlugin * plugin)
2422 {
2423 GaimAccountOption *option;
2424
2425 option = gaim_account_option_string_new(_("Server address"), "server", NULL);
2426 prpl_info.protocol_options =
2427 g_list_append(prpl_info.protocol_options, option);
2428
2429 option = gaim_account_option_int_new(_("Server port"), "port", DEFAULT_PORT);
2430 prpl_info.protocol_options =
2431 g_list_append(prpl_info.protocol_options, option);
2432
2433 my_protocol = plugin;
2434 }
2435
2436 GAIM_INIT_PLUGIN(novell, init_plugin, info);