comparison src/protocols/sametime/sametime.c @ 11943:0110fc7c6a8a

[gaim-migrate @ 14234] Bringing things up to date with the last Meanwhile release, 0.5.0 and the last gaim-meanwhile plugin release, 1.2.5 (which should be the last plugin release against oldstatus, if all goes well with HEAD and no major bugs crop up) It builds, so that's a start. The status bits that have been empty since the first import of the sametime stuff are still empty, but I'm going to try and fill those in tomorrow. I've decided to try and start using HEAD actively, to encourage me to get this freaking prpl fully functional. committer: Tailor Script <tailor@pidgin.im>
author Christopher O'Brien <siege@pidgin.im>
date Wed, 02 Nov 2005 03:39:03 +0000
parents fa742ad8068c
children 47e1723a89d7
comparison
equal deleted inserted replaced
11942:a24cfe32961a 11943:0110fc7c6a8a
19 along with this program; if not, write to the Free Software 19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
21 USA. 21 USA.
22 */ 22 */
23 23
24
25 /* system includes */
24 #include <stdlib.h> 26 #include <stdlib.h>
25 27 #include <time.h>
28
29 /* glib includes */
30 #include <glib.h>
31 #include <glib/ghash.h>
32 #include <glib/glist.h>
33
34 /* gaim includes */
26 #include <internal.h> 35 #include <internal.h>
27 #include <gaim.h> 36 #include <gaim.h>
28 #include <config.h> 37 #include <config.h>
29 38
30 #include <account.h> 39 #include <account.h>
40 #include <prpl.h> 49 #include <prpl.h>
41 #include <request.h> 50 #include <request.h>
42 #include <util.h> 51 #include <util.h>
43 #include <version.h> 52 #include <version.h>
44 53
45 #include <glib.h> 54 /* meanwhile includes */
46 #include <glib/ghash.h>
47 #include <glib/glist.h>
48
49 #include <mw_cipher.h> 55 #include <mw_cipher.h>
50 #include <mw_common.h> 56 #include <mw_common.h>
51 #include <mw_error.h> 57 #include <mw_error.h>
52 #include <mw_service.h> 58 #include <mw_service.h>
53 #include <mw_session.h> 59 #include <mw_session.h>
54 #include <mw_srvc_aware.h> 60 #include <mw_srvc_aware.h>
55 #include <mw_srvc_conf.h> 61 #include <mw_srvc_conf.h>
56 #include <mw_srvc_ft.h> 62 #include <mw_srvc_ft.h>
57 #include <mw_srvc_im.h> 63 #include <mw_srvc_im.h>
64 #include <mw_srvc_place.h>
58 #include <mw_srvc_resolve.h> 65 #include <mw_srvc_resolve.h>
59 #include <mw_srvc_store.h> 66 #include <mw_srvc_store.h>
60 #include <mw_st_list.h> 67 #include <mw_st_list.h>
61 68
69 /* project includes */
62 #include "sametime.h" 70 #include "sametime.h"
63 71
64 72
65 /* considering that there's no display of this information for prpls, 73 /* considering that there's no display of this information for prpls,
66 I don't know why I even bother providing these. Oh valiant reader, 74 I don't know why I even bother providing these. Oh valiant reader,
81 #define MW_PRPL_OPT_FORCE_LOGIN MW_PRPL_OPT_BASE "/force_login" 89 #define MW_PRPL_OPT_FORCE_LOGIN MW_PRPL_OPT_BASE "/force_login"
82 #define MW_PRPL_OPT_SAVE_DYNAMIC MW_PRPL_OPT_BASE "/save_dynamic" 90 #define MW_PRPL_OPT_SAVE_DYNAMIC MW_PRPL_OPT_BASE "/save_dynamic"
83 91
84 92
85 /* stages of connecting-ness */ 93 /* stages of connecting-ness */
86 #define MW_CONNECT_STEPS 10 94 #define MW_CONNECT_STEPS 9
87 95
88 96
89 /* stages of conciousness */ 97 /* stages of conciousness */
90 #define MW_STATE_OFFLINE "offline" 98 #define MW_STATE_OFFLINE "offline"
91 #define MW_STATE_ACTIVE "available" 99 #define MW_STATE_ACTIVE "active"
92 #define MW_STATE_AWAY "away" 100 #define MW_STATE_AWAY "away"
93 #define MW_STATE_BUSY "busy" 101 #define MW_STATE_BUSY "dnd"
94 #define MW_STATE_IDLE "idle" 102 #define MW_STATE_MESSAGE "message"
95 #define MW_STATE_UNKNOWN "unknown" 103 #define MW_STATE_ENLIGHTENED "buddha"
96 #define MW_STATE_BUDHA "enlightened"
97
98 #define MW_STATE_MESSAGE "message"
99 104
100 105
101 /* keys to get/set chat information */ 106 /* keys to get/set chat information */
102 #define CHAT_KEY_CREATOR "chat.creator" 107 #define CHAT_KEY_CREATOR "chat.creator"
103 #define CHAT_KEY_NAME "chat.name" 108 #define CHAT_KEY_NAME "chat.name"
104 #define CHAT_KEY_TOPIC "chat.topic" 109 #define CHAT_KEY_TOPIC "chat.topic"
105 #define CHAT_KEY_INVITE "chat.invite" 110 #define CHAT_KEY_INVITE "chat.invite"
111 #define CHAT_KEY_IS_PLACE "chat.is_place"
106 112
107 113
108 /* key for associating a mwLoginType with a buddy */ 114 /* key for associating a mwLoginType with a buddy */
109 #define BUDDY_KEY_CLIENT "meanwhile.client" 115 #define BUDDY_KEY_CLIENT "meanwhile.client"
110 116
138 #define MW_KEY_ACTIVE_MSG "active_msg" 144 #define MW_KEY_ACTIVE_MSG "active_msg"
139 #define MW_KEY_AWAY_MSG "away_msg" 145 #define MW_KEY_AWAY_MSG "away_msg"
140 #define MW_KEY_BUSY_MSG "busy_msg" 146 #define MW_KEY_BUSY_MSG "busy_msg"
141 #define MW_KEY_MSG_PROMPT "msg_prompt" 147 #define MW_KEY_MSG_PROMPT "msg_prompt"
142 #define MW_KEY_INVITE "conf_invite" 148 #define MW_KEY_INVITE "conf_invite"
149 #define MW_KEY_ENCODING "encoding"
150 #define MW_KEY_FORCE "force_login"
143 151
144 152
145 /** number of seconds from the first blist change before a save to the 153 /** number of seconds from the first blist change before a save to the
146 storage service occurs. */ 154 storage service occurs. */
147 #define BLIST_SAVE_SECONDS 15 155 #define BLIST_SAVE_SECONDS 15
148 156
149 157
150 /** blist storage option, local only */ 158 /** the possible buddy list storage settings */
151 #define BLIST_CHOICE_NONE 1 159 enum blist_choice {
152 160 blist_choice_LOCAL = 1, /**< local only */
153 /** blist storage option, load from server */ 161 blist_choice_MERGE = 2, /**< merge from server */
154 #define BLIST_CHOICE_LOAD 2 162 blist_choice_STORE = 3, /**< merge from and save to server */
155 163 blist_choice_SYNCH = 4, /**< sync with server */
156 /** blist storage option, load and save to server */ 164 };
157 #define BLIST_CHOICE_SAVE 3
158
159 /** blist storage option, server only */
160 #define BLIST_CHOICE_SERVER 4
161 165
162 166
163 /** the default blist storage option */ 167 /** the default blist storage option */
164 #define BLIST_CHOICE_DEFAULT BLIST_CHOICE_SAVE 168 #define BLIST_CHOICE_DEFAULT blist_choice_SYNCH
165 169
166 170
167 /* testing for the above */ 171 /* testing for the above */
168 #define BLIST_CHOICE_IS(n) (gaim_prefs_get_int(MW_PRPL_OPT_BLIST_ACTION)==(n)) 172 #define BLIST_PREF_IS(n) (gaim_prefs_get_int(MW_PRPL_OPT_BLIST_ACTION)==(n))
169 #define BLIST_CHOICE_IS_NONE() BLIST_CHOICE_IS(BLIST_CHOICE_NONE) 173 #define BLIST_PREF_IS_LOCAL() BLIST_PREF_IS(blist_choice_LOCAL)
170 #define BLIST_CHOICE_IS_LOAD() BLIST_CHOICE_IS(BLIST_CHOICE_LOAD) 174 #define BLIST_PREF_IS_MERGE() BLIST_PREF_IS(blist_choice_MERGE)
171 #define BLIST_CHOICE_IS_SAVE() BLIST_CHOICE_IS(BLIST_CHOICE_SAVE) 175 #define BLIST_PREF_IS_STORE() BLIST_PREF_IS(blist_choice_STORE)
176 #define BLIST_PREF_IS_SYNCH() BLIST_PREF_IS(blist_choice_SYNCH)
172 177
173 178
174 /* debugging output */ 179 /* debugging output */
175 #define DEBUG_ERROR(a...) gaim_debug_error(G_LOG_DOMAIN, a) 180 #define DEBUG_ERROR(a...) gaim_debug_error(G_LOG_DOMAIN, a)
176 #define DEBUG_INFO(a...) gaim_debug_info(G_LOG_DOMAIN, a) 181 #define DEBUG_INFO(a...) gaim_debug_info(G_LOG_DOMAIN, a)
204 209
205 struct mwServiceAware *srvc_aware; 210 struct mwServiceAware *srvc_aware;
206 struct mwServiceConference *srvc_conf; 211 struct mwServiceConference *srvc_conf;
207 struct mwServiceFileTransfer *srvc_ft; 212 struct mwServiceFileTransfer *srvc_ft;
208 struct mwServiceIm *srvc_im; 213 struct mwServiceIm *srvc_im;
214 struct mwServicePlace *srvc_place;
209 struct mwServiceResolve *srvc_resolve; 215 struct mwServiceResolve *srvc_resolve;
210 struct mwServiceStorage *srvc_store; 216 struct mwServiceStorage *srvc_store;
211 217
212 /** map of GaimGroup:mwAwareList and mwAwareList:GaimGroup */ 218 /** map of GaimGroup:mwAwareList and mwAwareList:GaimGroup */
213 GHashTable *group_list_map; 219 GHashTable *group_list_map;
228 234
229 static void blist_store(struct mwGaimPluginData *pd); 235 static void blist_store(struct mwGaimPluginData *pd);
230 236
231 static void blist_schedule(struct mwGaimPluginData *pd); 237 static void blist_schedule(struct mwGaimPluginData *pd);
232 238
233 static void blist_import(GaimConnection *gc, struct mwSametimeList *stlist); 239 static void blist_merge(GaimConnection *gc, struct mwSametimeList *stlist);
240
241 static void blist_sync(GaimConnection *gc, struct mwSametimeList *stlist);
242
243 static gboolean buddy_is_external(GaimBuddy *b);
234 244
235 static void buddy_add(struct mwGaimPluginData *pd, GaimBuddy *buddy); 245 static void buddy_add(struct mwGaimPluginData *pd, GaimBuddy *buddy);
236 246
237 static GaimBuddy * 247 static GaimBuddy *
238 buddy_ensure(GaimConnection *gc, GaimGroup *group, 248 buddy_ensure(GaimConnection *gc, GaimGroup *group,
289 struct resolved_id { 299 struct resolved_id {
290 char *id; 300 char *id;
291 char *name; 301 char *name;
292 }; 302 };
293 303
304 static struct resolved_id *resolved_id_new(const char *id, const char *name);
305
306 static void resolved_id_free(struct resolved_id *rid);
307
308
309 /* connection functions */
310
311 static void connect_cb(gpointer data, gint source, GaimInputCondition cond);
312
294 313
295 /* ----- session ------ */ 314 /* ----- session ------ */
296 315
297 316
298 /** resolves a mwSession from a GaimConnection */ 317 /** resolves a mwSession from a GaimConnection */
338 len -= ret; 357 len -= ret;
339 } 358 }
340 359
341 if(len > 0) { 360 if(len > 0) {
342 DEBUG_ERROR("write returned %i, %i bytes left unwritten\n", ret, len); 361 DEBUG_ERROR("write returned %i, %i bytes left unwritten\n", ret, len);
343 gaim_connection_error(pd->gc, "Connection closed (writing)"); 362 gaim_connection_error(pd->gc, _("Connection closed (writing)"));
344 363
345 #if 0 364 #if 0
346 close(pd->socket); 365 close(pd->socket);
347 pd->socket = 0; 366 pd->socket = 0;
348 #endif 367 #endif
406 static void mw_aware_list_on_aware(struct mwAwareList *list, 425 static void mw_aware_list_on_aware(struct mwAwareList *list,
407 struct mwAwareSnapshot *aware) { 426 struct mwAwareSnapshot *aware) {
408 427
409 GaimConnection *gc; 428 GaimConnection *gc;
410 GaimAccount *acct; 429 GaimAccount *acct;
430
411 struct mwGaimPluginData *pd; 431 struct mwGaimPluginData *pd;
412 const char *status_id = MW_STATE_ACTIVE; 432 time_t idle;
413 gboolean idle = FALSE; 433 guint stat;
414 434 const char *id;
415 guint stat = aware->status.status; 435 const char *status = MW_STATE_ACTIVE;
416
417 const char *id = aware->id.user;
418 436
419 gc = mwAwareList_getClientData(list); 437 gc = mwAwareList_getClientData(list);
438 acct = gaim_connection_get_account(gc);
439
420 pd = gc->proto_data; 440 pd = gc->proto_data;
421 acct = gaim_connection_get_account(gc); 441 idle = aware->status.time;
422 442 stat = aware->status.status;
443 id = aware->id.user;
444
445 /* not sure which client sends this yet */
446 if(idle == 0xdeadbeef) {
447 /* knock knock!
448 who's there?
449 rude interrupting cow.
450 rude interr...
451 MOO! */
452 idle = -1;
453 }
454
423 switch(stat) { 455 switch(stat) {
456 case mwStatus_ACTIVE:
457 status = MW_STATE_ACTIVE;
458 idle = 0;
459 break;
460
424 case mwStatus_IDLE: 461 case mwStatus_IDLE:
425 idle = TRUE; 462 if(! idle) idle = -1;
426 break; 463 break;
427 464
428 case mwStatus_AWAY: 465 case mwStatus_AWAY:
429 status_id = MW_STATE_AWAY; 466 status = MW_STATE_AWAY;
430 break; 467 break;
468
431 case mwStatus_BUSY: 469 case mwStatus_BUSY:
432 status_id = MW_STATE_BUSY; 470 status = MW_STATE_BUSY;
433 break; 471 break;
434 } 472 }
435 473
474 /* NAB group members */
436 if(aware->group) { 475 if(aware->group) {
437 GaimGroup *group; 476 GaimGroup *group;
438 GaimBuddy *buddy; 477 GaimBuddy *buddy;
439 GaimBlistNode *bnode; 478 GaimBlistNode *bnode;
440 479
449 buddy = gaim_buddy_new(acct, id, NULL); 488 buddy = gaim_buddy_new(acct, id, NULL);
450 gaim_blist_add_buddy(buddy, NULL, group, NULL); 489 gaim_blist_add_buddy(buddy, NULL, group, NULL);
451 490
452 bnode = (GaimBlistNode *) buddy; 491 bnode = (GaimBlistNode *) buddy;
453 492
454 /* mark buddy as transient if preferences do not indicate that
455 we should save the buddy between gaim sessions */
456 if(! gaim_prefs_get_bool(MW_PRPL_OPT_SAVE_DYNAMIC))
457 bnode->flags |= GAIM_BLIST_NODE_FLAG_NO_SAVE;
458
459 srvc = pd->srvc_resolve; 493 srvc = pd->srvc_resolve;
460 query = g_list_append(NULL, (char *) id); 494 query = g_list_append(NULL, (char *) id);
461 495
462 mwServiceResolve_resolve(srvc, query, mwResolveFlag_USERS, 496 mwServiceResolve_resolve(srvc, query, mwResolveFlag_USERS,
463 blist_resolve_alias_cb, buddy, NULL); 497 blist_resolve_alias_cb, buddy, NULL);
498 g_list_free(query);
464 } 499 }
465 500
466 gaim_blist_node_set_int(bnode, BUDDY_KEY_TYPE, mwSametimeUser_NORMAL); 501 gaim_blist_node_set_int(bnode, BUDDY_KEY_TYPE, mwSametimeUser_NORMAL);
467 } 502 }
468 503
469 gaim_prpl_got_user_status(acct, id, status_id, NULL); 504 gaim_prpl_got_user_status(acct, id, status, NULL);
470 gaim_prpl_got_user_login_time(acct, id, aware->online - time(NULL)); 505 gaim_prpl_got_user_idle(acct, id, !!idle, idle);
471
472 if (idle)
473 gaim_prpl_got_user_idle(acct, id, TRUE, -1);
474 else
475 gaim_prpl_got_user_idle(acct, id, FALSE, 0);
476 } 506 }
477 507
478 508
479 static void mw_aware_list_on_attrib(struct mwAwareList *list, 509 static void mw_aware_list_on_attrib(struct mwAwareList *list,
480 struct mwAwareIdBlock *id, 510 struct mwAwareIdBlock *id,
631 srvc = pd->srvc_store; 661 srvc = pd->srvc_store;
632 g_return_if_fail(srvc != NULL); 662 g_return_if_fail(srvc != NULL);
633 663
634 gc = pd->gc; 664 gc = pd->gc;
635 665
636 /* check if we should do this, according to user prefs */ 666 if(BLIST_PREF_IS_LOCAL() || BLIST_PREF_IS_MERGE()) {
637 if(! BLIST_CHOICE_IS_SAVE()) {
638 DEBUG_INFO("preferences indicate not to save remote blist\n"); 667 DEBUG_INFO("preferences indicate not to save remote blist\n");
639 return; 668 return;
640 669
641 } else if(MW_SERVICE_IS_DEAD(srvc)) { 670 } else if(MW_SERVICE_IS_DEAD(srvc)) {
642 DEBUG_INFO("aborting save of blist: storage service is not alive\n"); 671 DEBUG_INFO("aborting save of blist: storage service is not alive\n");
643 return; 672 return;
644 673
674 } else if(BLIST_PREF_IS_STORE() || BLIST_PREF_IS_SYNCH()) {
675 DEBUG_INFO("saving remote blist\n");
676
645 } else { 677 } else {
646 DEBUG_INFO("saving remote blist\n"); 678 g_return_if_reached();
647 } 679 }
648 680
649 /* create and export to a list object */ 681 /* create and export to a list object */
650 stlist = mwSametimeList_new(); 682 stlist = mwSametimeList_new();
651 blist_export(gc, stlist); 683 blist_export(gc, stlist);
678 static void blist_schedule(struct mwGaimPluginData *pd) { 710 static void blist_schedule(struct mwGaimPluginData *pd) {
679 if(pd->save_event) return; 711 if(pd->save_event) return;
680 712
681 pd->save_event = gaim_timeout_add(BLIST_SAVE_SECONDS * 1000, 713 pd->save_event = gaim_timeout_add(BLIST_SAVE_SECONDS * 1000,
682 blist_save_cb, pd); 714 blist_save_cb, pd);
715 }
716
717
718 static gboolean buddy_is_external(GaimBuddy *b) {
719 g_return_val_if_fail(b != NULL, FALSE);
720 return g_str_has_prefix(b->name, "@E ");
683 } 721 }
684 722
685 723
686 /** Actually add a buddy to the aware service, and schedule the buddy 724 /** Actually add a buddy to the aware service, and schedule the buddy
687 list to be saved to the server */ 725 list to be saved to the server */
800 return group; 838 return group;
801 } 839 }
802 840
803 841
804 /** merge the entries from a st list into the gaim blist */ 842 /** merge the entries from a st list into the gaim blist */
805 static void blist_import(GaimConnection *gc, struct mwSametimeList *stlist) { 843 static void blist_merge(GaimConnection *gc, struct mwSametimeList *stlist) {
806 struct mwSametimeGroup *stgroup; 844 struct mwSametimeGroup *stgroup;
807 struct mwSametimeUser *stuser; 845 struct mwSametimeUser *stuser;
808 846
809 GaimGroup *group; 847 GaimGroup *group;
810 GaimBuddy *buddy; 848 GaimBuddy *buddy;
824 buddy = buddy_ensure(gc, group, stuser); 862 buddy = buddy_ensure(gc, group, stuser);
825 } 863 }
826 g_list_free(utl); 864 g_list_free(utl);
827 } 865 }
828 g_list_free(gtl); 866 g_list_free(gtl);
867 }
868
869
870 /** remove all buddies on account from group. If del is TRUE and group
871 is left empty, remove group as well */
872 static void group_clear(GaimGroup *group, GaimAccount *acct, gboolean del) {
873 GaimConnection *gc;
874 GList *prune = NULL;
875 GaimBlistNode *gn, *cn, *bn;
876
877 g_return_if_fail(group != NULL);
878
879 DEBUG_INFO("clearing members from pruned group %s\n", NSTR(group->name));
880
881 gc = gaim_account_get_connection(acct);
882 g_return_if_fail(gc != NULL);
883
884 gn = (GaimBlistNode *) group;
885
886 for(cn = gn->child; cn; cn = cn->next) {
887 if(! GAIM_BLIST_NODE_IS_CONTACT(cn)) continue;
888
889 for(bn = cn->child; bn; bn = bn->next) {
890 GaimBuddy *gb = (GaimBuddy *) bn;
891
892 if(! GAIM_BLIST_NODE_IS_BUDDY(bn)) continue;
893
894 if(gb->account == acct) {
895 DEBUG_INFO("clearing %s from group\n", NSTR(gb->name));
896 prune = g_list_prepend(prune, gb);
897 }
898 }
899 }
900
901 /* quickly unsubscribe from presence for the entire group */
902 gaim_account_remove_group(acct, group);
903
904 /* remove blist entries that need to go */
905 while(prune) {
906 gaim_blist_remove_buddy(prune->data);
907 prune = g_list_delete_link(prune, prune);
908 }
909 DEBUG_INFO("cleared buddies\n");
910
911 /* optionally remove group from blist */
912 if(del && !gaim_blist_get_group_size(group, TRUE)) {
913 DEBUG_INFO("removing empty group\n");
914 gaim_blist_remove_group(group);
915 }
916 }
917
918
919 /** prune out group members that shouldn't be there */
920 static void group_prune(GaimConnection *gc, GaimGroup *group,
921 struct mwSametimeGroup *stgroup) {
922
923 GaimAccount *acct;
924 GaimBlistNode *gn, *cn, *bn;
925
926 GHashTable *stusers;
927 GList *prune = NULL;
928 GList *ul, *utl;
929
930 g_return_if_fail(group != NULL);
931
932 DEBUG_INFO("pruning membership of group %s\n", NSTR(group->name));
933
934 acct = gaim_connection_get_account(gc);
935 g_return_if_fail(acct != NULL);
936
937 stusers = g_hash_table_new(g_str_hash, g_str_equal);
938
939 /* build a hash table for quick lookup while pruning the group
940 contents */
941 utl = mwSametimeGroup_getUsers(stgroup);
942 for(ul = utl; ul; ul = ul->next) {
943 const char *id = mwSametimeUser_getUser(ul->data);
944 g_hash_table_insert(stusers, (char *) id, ul->data);
945 DEBUG_INFO("server copy has %s\n", NSTR(id));
946 }
947 g_list_free(utl);
948
949 gn = (GaimBlistNode *) group;
950
951 for(cn = gn->child; cn; cn = cn->next) {
952 if(! GAIM_BLIST_NODE_IS_CONTACT(cn)) continue;
953
954 for(bn = cn->child; bn; bn = bn->next) {
955 GaimBuddy *gb = (GaimBuddy *) bn;
956
957 if(! GAIM_BLIST_NODE_IS_BUDDY(bn)) continue;
958
959 /* if the account is correct and they're not in our table, mark
960 them for pruning */
961 if(gb->account == acct && !g_hash_table_lookup(stusers, gb->name)) {
962 DEBUG_INFO("marking %s for pruning\n", NSTR(gb->name));
963 prune = g_list_prepend(prune, gb);
964 }
965 }
966 }
967 DEBUG_INFO("done marking\n");
968
969 g_hash_table_destroy(stusers);
970
971 if(prune) {
972 gaim_account_remove_buddies(acct, prune, NULL);
973 while(prune) {
974 gaim_blist_remove_buddy(prune->data);
975 prune = g_list_delete_link(prune, prune);
976 }
977 }
978 }
979
980
981 /** synch the entries from a st list into the gaim blist, removing any
982 existing buddies that aren't in the st list */
983 static void blist_sync(GaimConnection *gc, struct mwSametimeList *stlist) {
984
985 GaimAccount *acct;
986 GaimBuddyList *blist;
987 GaimBlistNode *gn;
988
989 GHashTable *stgroups;
990 GList *g_prune = NULL;
991
992 GList *gl, *gtl;
993
994 const char *acct_n;
995
996 DEBUG_INFO("synchronizing local buddy list from server list\n");
997
998 acct = gaim_connection_get_account(gc);
999 g_return_if_fail(acct != NULL);
1000
1001 acct_n = gaim_account_get_username(acct);
1002
1003 blist = gaim_get_blist();
1004 g_return_if_fail(blist != NULL);
1005
1006 /* build a hash table for quick lookup while pruning the local
1007 list, mapping group name to group structure */
1008 stgroups = g_hash_table_new(g_str_hash, g_str_equal);
1009
1010 gtl = mwSametimeList_getGroups(stlist);
1011 for(gl = gtl; gl; gl = gl->next) {
1012 const char *name = mwSametimeGroup_getName(gl->data);
1013 g_hash_table_insert(stgroups, (char *) name, gl->data);
1014 }
1015 g_list_free(gtl);
1016
1017 /* find all groups which should be pruned from the local list */
1018 for(gn = blist->root; gn; gn = gn->next) {
1019 GaimGroup *grp = (GaimGroup *) gn;
1020 const char *gname, *owner;
1021 struct mwSametimeGroup *stgrp;
1022
1023 if(! GAIM_BLIST_NODE_IS_GROUP(gn)) continue;
1024
1025 /* group not belonging to this account */
1026 if(! gaim_group_on_account(grp, acct))
1027 continue;
1028
1029 /* dynamic group belonging to this account. don't prune contents */
1030 owner = gaim_blist_node_get_string(gn, GROUP_KEY_OWNER);
1031 if(owner && !strcmp(owner, acct_n))
1032 continue;
1033
1034 /* we actually are synching by this key as opposed to the group
1035 title, which can be different things in the st list */
1036 gname = gaim_blist_node_get_string(gn, GROUP_KEY_NAME);
1037 if(! gname) gname = grp->name;
1038
1039 stgrp = g_hash_table_lookup(stgroups, gname);
1040 if(! stgrp) {
1041 /* remove the whole group */
1042 DEBUG_INFO("marking group %s for pruning\n", grp->name);
1043 g_prune = g_list_prepend(g_prune, grp);
1044
1045 } else {
1046 /* synch the group contents */
1047 group_prune(gc, grp, stgrp);
1048 }
1049 }
1050 DEBUG_INFO("done marking groups\n");
1051
1052 /* don't need this anymore */
1053 g_hash_table_destroy(stgroups);
1054
1055 /* prune all marked groups */
1056 while(g_prune) {
1057 GaimGroup *grp = g_prune->data;
1058 GaimBlistNode *gn = (GaimBlistNode *) grp;
1059 const char *owner;
1060 gboolean del = TRUE;
1061
1062 owner = gaim_blist_node_get_string(gn, GROUP_KEY_OWNER);
1063 if(owner && strcmp(owner, acct_n)) {
1064 /* it's a specialty group belonging to another account with some
1065 of our members in it, so don't fully delete it */
1066 del = FALSE;
1067 }
1068
1069 group_clear(g_prune->data, acct, del);
1070 g_prune = g_list_delete_link(g_prune, g_prune);
1071 }
1072
1073 /* done with the pruning, let's merge in the additions */
1074 blist_merge(gc, stlist);
829 } 1075 }
830 1076
831 1077
832 /** callback passed to the storage service when it's told to load the 1078 /** callback passed to the storage service when it's told to load the
833 st list */ 1079 st list */
842 struct mwGetBuffer *b; 1088 struct mwGetBuffer *b;
843 1089
844 g_return_if_fail(result == ERR_SUCCESS); 1090 g_return_if_fail(result == ERR_SUCCESS);
845 1091
846 /* check our preferences for loading */ 1092 /* check our preferences for loading */
847 if(BLIST_CHOICE_IS_NONE()) { 1093 if(BLIST_PREF_IS_LOCAL()) {
848 DEBUG_INFO("preferences indicate not to load remote buddy list\n"); 1094 DEBUG_INFO("preferences indicate not to load remote buddy list\n");
849 return; 1095 return;
850 } 1096 }
851 1097
852 b = mwGetBuffer_wrap(mwStorageUnit_asOpaque(item)); 1098 b = mwGetBuffer_wrap(mwStorageUnit_asOpaque(item));
853 1099
854 stlist = mwSametimeList_new(); 1100 stlist = mwSametimeList_new();
855 mwSametimeList_get(b, stlist); 1101 mwSametimeList_get(b, stlist);
856 1102
857 s = mwService_getSession(MW_SERVICE(srvc)); 1103 s = mwService_getSession(MW_SERVICE(srvc));
858 blist_import(pd->gc, stlist); 1104
1105 /* merge or synch depending on preferences */
1106 if(BLIST_PREF_IS_MERGE() || BLIST_PREF_IS_STORE()) {
1107 blist_merge(pd->gc, stlist);
1108
1109 } else if(BLIST_PREF_IS_SYNCH()) {
1110 blist_sync(pd->gc, stlist);
1111 }
859 1112
860 mwSametimeList_free(stlist); 1113 mwSametimeList_free(stlist);
861 } 1114 }
862 1115
863 1116
926 1179
927 g_free(msg); 1180 g_free(msg);
928 msg = NULL; 1181 msg = NULL;
929 1182
930 #if 0 1183 #if 0
931 /* XXX */ 1184 /* XXX resets the status, thus updating the message */
932 if(!gc->away_state || !strcmp(gc->away_state, MW_STATE_ACTIVE)) { 1185 if(!gc->away_state || !strcmp(gc->away_state, MW_STATE_ACTIVE)) {
933 msg = MW_STATE_ACTIVE; 1186 msg = MW_STATE_ACTIVE;
934 } else if(gc->away_state && !strcmp(gc->away_state, MW_STATE_AWAY)) { 1187 } else if(gc->away_state && !strcmp(gc->away_state, MW_STATE_AWAY)) {
935 msg = MW_STATE_AWAY; 1188 msg = MW_STATE_AWAY;
936 } else if(gc->away_state && !strcmp(gc->away_state, MW_STATE_BUSY)) { 1189 } else if(gc->away_state && !strcmp(gc->away_state, MW_STATE_BUSY)) {
937 msg = MW_STATE_BUSY; 1190 msg = MW_STATE_BUSY;
938 } 1191 }
939 1192
940 if(msg) 1193 if(msg) serv_set_away(gc, msg, NULL);
941 serv_set_away(gc, msg, NULL);
942 #endif 1194 #endif
943 } 1195 }
944 1196
945 1197
946 /** signal triggered when a conversation is opened in Gaim */ 1198 /** signal triggered when a conversation is opened in Gaim */
952 message is sent before offering NotesBuddy features. Therefore 1204 message is sent before offering NotesBuddy features. Therefore
953 whenever Gaim creates a conversation, we'll immediately open the 1205 whenever Gaim creates a conversation, we'll immediately open the
954 channel to the other side and figure out what the target can 1206 channel to the other side and figure out what the target can
955 handle. Unfortunately, this makes us vulnerable to Psychic Mode, 1207 handle. Unfortunately, this makes us vulnerable to Psychic Mode,
956 whereas a more lazy negotiation based on the first message 1208 whereas a more lazy negotiation based on the first message
957 isn't */ 1209 would not */
958 1210
959 GaimConnection *gc; 1211 GaimConnection *gc;
960 struct mwIdBlock who = { 0, 0 }; 1212 struct mwIdBlock who = { 0, 0 };
961 struct mwConversation *conv; 1213 struct mwConversation *conv;
962 1214
995 1247
996 str = g_string_new(NULL); 1248 str = g_string_new(NULL);
997 1249
998 tmp = (char *) gaim_blist_node_get_string(node, GROUP_KEY_NAME); 1250 tmp = (char *) gaim_blist_node_get_string(node, GROUP_KEY_NAME);
999 1251
1000 g_string_append_printf(str, "<b>Group Title:</b> %s<br>", group->name); 1252 g_string_append_printf(str, _("<b>Group Title:</b> %s<br>"), group->name);
1001 g_string_append_printf(str, "<b>Notes Group ID:</b> %s<br>", tmp); 1253 g_string_append_printf(str, _("<b>Notes Group ID:</b> %s<br>"), tmp);
1002 1254
1003 tmp = g_strdup_printf("Info for Group %s", group->name); 1255 tmp = g_strdup_printf(_("Info for Group %s"), group->name);
1004 1256
1005 gaim_notify_formatted(gc, tmp, "Notes Address Book Information", 1257 gaim_notify_formatted(gc, tmp, _("Notes Address Book Information"),
1006 NULL, str->str, NULL, NULL); 1258 NULL, str->str, NULL, NULL);
1007 1259
1008 g_free(tmp); 1260 g_free(tmp);
1009 g_string_free(str, TRUE); 1261 g_string_free(str, TRUE);
1010 } 1262 }
1027 acct = gaim_accounts_find(owner, PLUGIN_ID); 1279 acct = gaim_accounts_find(owner, PLUGIN_ID);
1028 if(! acct) return; 1280 if(! acct) return;
1029 if(! gaim_account_is_connected(acct)) return; 1281 if(! gaim_account_is_connected(acct)) return;
1030 if(acct != gaim_connection_get_account(pd->gc)) return; 1282 if(acct != gaim_connection_get_account(pd->gc)) return;
1031 1283
1032 act = gaim_blist_node_action_new("Get Notes Address Book Info", 1284 act = gaim_blist_node_action_new(_("Get Notes Address Book Info"),
1033 blist_menu_nab, pd, NULL); 1285 blist_menu_nab, pd, NULL);
1034 1286
1035 *menu = g_list_append(*menu, NULL); 1287 *menu = g_list_append(*menu, NULL);
1036 *menu = g_list_append(*menu, act); 1288 *menu = g_list_append(*menu, act);
1037 } 1289 }
1106 mwServiceAware_setAttributeBoolean(pd->srvc_aware, 1358 mwServiceAware_setAttributeBoolean(pd->srvc_aware,
1107 mwAttribute_FILE_TRANSFER, TRUE); 1359 mwAttribute_FILE_TRANSFER, TRUE);
1108 } 1360 }
1109 1361
1110 1362
1363 static void session_loginRedirect(struct mwSession *session,
1364 const char *host) {
1365 struct mwGaimPluginData *pd;
1366 GaimConnection *gc;
1367 GaimAccount *account;
1368 guint port;
1369
1370 pd = mwSession_getClientData(session);
1371 gc = pd->gc;
1372 account = gaim_connection_get_account(gc);
1373 port = gaim_account_get_int(account, MW_KEY_PORT, MW_PLUGIN_DEFAULT_PORT);
1374
1375 if(gaim_account_get_bool(account, MW_KEY_FORCE, FALSE) ||
1376 gaim_proxy_connect(account, host, port, connect_cb, pd)) {
1377
1378 mwSession_forceLogin(session);
1379 }
1380 }
1381
1382
1111 /** called from mw_session_stateChange when the session's state is 1383 /** called from mw_session_stateChange when the session's state is
1112 mwSession_STARTED. Any finalizing of start-up stuff should go 1384 mwSession_STARTED. Any finalizing of start-up stuff should go
1113 here */ 1385 here */
1114 static void session_started(struct mwGaimPluginData *pd) { 1386 static void session_started(struct mwGaimPluginData *pd) {
1115 1387
1119 services_starting(pd); 1391 services_starting(pd);
1120 } 1392 }
1121 1393
1122 1394
1123 static void mw_session_stateChange(struct mwSession *session, 1395 static void mw_session_stateChange(struct mwSession *session,
1124 enum mwSessionState state, guint32 info) { 1396 enum mwSessionState state,
1397 gpointer info) {
1125 struct mwGaimPluginData *pd; 1398 struct mwGaimPluginData *pd;
1126 GaimConnection *gc; 1399 GaimConnection *gc;
1127 char *msg = NULL; 1400 char *msg = NULL;
1128 1401
1129 pd = mwSession_getClientData(session); 1402 pd = mwSession_getClientData(session);
1151 break; 1424 break;
1152 1425
1153 case mwSession_LOGIN_REDIR: 1426 case mwSession_LOGIN_REDIR:
1154 msg = _("Login Redirected"); 1427 msg = _("Login Redirected");
1155 gaim_connection_update_progress(gc, msg, 6, MW_CONNECT_STEPS); 1428 gaim_connection_update_progress(gc, msg, 6, MW_CONNECT_STEPS);
1429 session_loginRedirect(session, info);
1156 break; 1430 break;
1157 1431
1158 case mwSession_LOGIN_CONT: 1432 case mwSession_LOGIN_CONT:
1159 msg = _("Forcing Login"); 1433 msg = _("Forcing Login");
1160 gaim_connection_update_progress(gc, msg, 7, MW_CONNECT_STEPS); 1434 gaim_connection_update_progress(gc, msg, 7, MW_CONNECT_STEPS);
1166 1440
1167 case mwSession_STARTED: 1441 case mwSession_STARTED:
1168 msg = _("Connected to Sametime Community Server"); 1442 msg = _("Connected to Sametime Community Server");
1169 gaim_connection_update_progress(gc, msg, 9, MW_CONNECT_STEPS); 1443 gaim_connection_update_progress(gc, msg, 9, MW_CONNECT_STEPS);
1170 gaim_connection_set_state(gc, GAIM_CONNECTED); 1444 gaim_connection_set_state(gc, GAIM_CONNECTED);
1171 /* XXX serv_finish_login(gc); */
1172 1445
1173 session_started(pd); 1446 session_started(pd);
1174 break; 1447 break;
1175 1448
1176 case mwSession_STOPPING: 1449 case mwSession_STOPPING:
1177 if(info & ERR_FAILURE) { 1450 if(GPOINTER_TO_UINT(info) & ERR_FAILURE) {
1178 msg = mwError(info); 1451 msg = mwError(GPOINTER_TO_UINT(info));
1179 gaim_connection_error(gc, msg); 1452 gaim_connection_error(gc, msg);
1180 g_free(msg); 1453 g_free(msg);
1181 } 1454 }
1182 break; 1455 break;
1183 1456
1285 GaimInputCondition cond) { 1558 GaimInputCondition cond) {
1286 1559
1287 struct mwGaimPluginData *pd = data; 1560 struct mwGaimPluginData *pd = data;
1288 int ret = 0, err = 0; 1561 int ret = 0, err = 0;
1289 1562
1563 /* How the heck can this happen? Fix submitted to Gaim so that it
1564 won't happen anymore. */
1290 if(! cond) return; 1565 if(! cond) return;
1291 1566
1292 g_return_if_fail(pd != NULL); 1567 g_return_if_fail(pd != NULL);
1293 g_return_if_fail(cond & GAIM_INPUT_READ); 1568 g_return_if_fail(cond & GAIM_INPUT_READ);
1294 1569
1313 pd->gc->inpa = 0; 1588 pd->gc->inpa = 0;
1314 } 1589 }
1315 1590
1316 if(! ret) { 1591 if(! ret) {
1317 DEBUG_INFO("connection reset\n"); 1592 DEBUG_INFO("connection reset\n");
1318 gaim_connection_error(pd->gc, "Connection reset"); 1593 gaim_connection_error(pd->gc, _("Connection reset"));
1319 1594
1320 } else if(ret < 0) { 1595 } else if(ret < 0) {
1321 char *msg = strerror(err); 1596 char *msg = strerror(err);
1322 1597
1323 DEBUG_INFO("error in read callback: %s\n", msg); 1598 DEBUG_INFO("error in read callback: %s\n", msg);
1324 1599
1325 msg = g_strdup_printf("Error reading from socket: %s", msg); 1600 msg = g_strdup_printf(_("Error reading from socket: %s"), msg);
1326 gaim_connection_error(pd->gc, msg); 1601 gaim_connection_error(pd->gc, msg);
1327 g_free(msg); 1602 g_free(msg);
1328 } 1603 }
1329 } 1604 }
1330 1605
1349 /* this is a redirect connect, force login on existing socket */ 1624 /* this is a redirect connect, force login on existing socket */
1350 mwSession_forceLogin(pd->session); 1625 mwSession_forceLogin(pd->session);
1351 1626
1352 } else { 1627 } else {
1353 /* this is a regular connect, error out */ 1628 /* this is a regular connect, error out */
1354 gaim_connection_error(pd->gc, "Unable to connect to host"); 1629 gaim_connection_error(pd->gc, _("Unable to connect to host"));
1355 } 1630 }
1356 1631
1357 return; 1632 return;
1358 } 1633 }
1359 1634
1367 1642
1368 mwSession_start(pd->session); 1643 mwSession_start(pd->session);
1369 } 1644 }
1370 1645
1371 1646
1372 static void mw_session_loginRedirect(struct mwSession *session, 1647 static void mw_session_announce(struct mwSession *s,
1373 const char *host) { 1648 struct mwLoginInfo *from,
1374 1649 gboolean may_reply,
1650 const char *text) {
1375 struct mwGaimPluginData *pd; 1651 struct mwGaimPluginData *pd;
1376 GaimConnection *gc; 1652 GaimAccount *acct;
1377 GaimAccount *account; 1653 GaimConversation *conv;
1378 guint port; 1654 GSList *buddies;
1379 1655 char *who = from->user_id;
1380 pd = mwSession_getClientData(session); 1656 char *msg;
1381 gc = pd->gc; 1657
1382 account = gaim_connection_get_account(gc); 1658 pd = mwSession_getClientData(s);
1383 port = gaim_account_get_int(account, "port", MW_PLUGIN_DEFAULT_PORT); 1659 acct = gaim_connection_get_account(pd->gc);
1384 1660 conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, who, acct);
1385 if(gaim_prefs_get_bool(MW_PRPL_OPT_FORCE_LOGIN) || 1661 if(! conv) conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, acct, who);
1386 gaim_proxy_connect(account, host, port, connect_cb, pd)) { 1662
1387 1663 buddies = gaim_find_buddies(acct, who);
1388 mwSession_forceLogin(session); 1664 if(buddies) {
1389 } 1665 who = (char *) gaim_buddy_get_contact_alias(buddies->data);
1666 g_slist_free(buddies);
1667 }
1668
1669 who = g_strdup_printf(_("Announcement from %s"), who);
1670 msg = gaim_markup_linkify(text);
1671
1672 gaim_conversation_write(conv, who, msg, GAIM_MESSAGE_RECV, time(NULL));
1673 g_free(who);
1674 g_free(msg);
1390 } 1675 }
1391 1676
1392 1677
1393 static struct mwSessionHandler mw_session_handler = { 1678 static struct mwSessionHandler mw_session_handler = {
1394 .io_write = mw_session_io_write, 1679 .io_write = mw_session_io_write,
1396 .clear = mw_session_clear, 1681 .clear = mw_session_clear,
1397 .on_stateChange = mw_session_stateChange, 1682 .on_stateChange = mw_session_stateChange,
1398 .on_setPrivacyInfo = mw_session_setPrivacyInfo, 1683 .on_setPrivacyInfo = mw_session_setPrivacyInfo,
1399 .on_setUserStatus = mw_session_setUserStatus, 1684 .on_setUserStatus = mw_session_setUserStatus,
1400 .on_admin = mw_session_admin, 1685 .on_admin = mw_session_admin,
1401 .on_loginRedirect = mw_session_loginRedirect, 1686 .on_announce = mw_session_announce,
1402 }; 1687 };
1403 1688
1404 1689
1405 static void mw_aware_on_attrib(struct mwServiceAware *srvc, 1690 static void mw_aware_on_attrib(struct mwServiceAware *srvc,
1406 struct mwAwareAttribute *attrib) { 1691 struct mwAwareAttribute *attrib) {
1550 pd = mwSession_getClientData(session); 1835 pd = mwSession_getClientData(session);
1551 gc = pd->gc; 1836 gc = pd->gc;
1552 1837
1553 serv_got_chat_left(gc, CONF_TO_ID(conf)); 1838 serv_got_chat_left(gc, CONF_TO_ID(conf));
1554 1839
1555 gaim_notify_error(gc, "Conference Closed", NULL, msg); 1840 gaim_notify_error(gc, _("Conference Closed"), NULL, msg);
1556 g_free(msg); 1841 g_free(msg);
1557 } 1842 }
1558 1843
1559 1844
1560 static void mw_conf_peer_joined(struct mwConference *conf, 1845 static void mw_conf_peer_joined(struct mwConference *conf,
1969 gc = pd->gc; 2254 gc = pd->gc;
1970 acct = gaim_connection_get_account(gc); 2255 acct = gaim_connection_get_account(gc);
1971 2256
1972 idb = mwConversation_getTarget(conv); 2257 idb = mwConversation_getTarget(conv);
1973 2258
1974 return gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM,idb->user, acct); 2259 return gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM,
2260 idb->user, acct);
1975 } 2261 }
1976 2262
1977 2263
1978 static void convo_queue(struct mwConversation *conv, 2264 static void convo_queue(struct mwConversation *conv,
1979 enum mwImSendType type, gconstpointer data) { 2265 enum mwImSendType type, gconstpointer data) {
2010 struct mwIdBlock *idb; 2296 struct mwIdBlock *idb;
2011 2297
2012 idb = mwConversation_getTarget(conv); 2298 idb = mwConversation_getTarget(conv);
2013 2299
2014 tmp = mwError(err); 2300 tmp = mwError(err);
2015 text = g_strconcat("Unable to send message: ", tmp, NULL); 2301 text = g_strconcat(_("Unable to send message: "), tmp, NULL);
2016 2302
2017 gconv = convo_get_gconv(conv); 2303 gconv = convo_get_gconv(conv);
2018 if(gconv && !gaim_conv_present_error(idb->user, gconv->account, text)) { 2304 if(gconv && !gaim_conv_present_error(idb->user, gconv->account, text)) {
2019 2305
2020 g_free(text); 2306 g_free(text);
2021 text = g_strdup_printf("Unable to send message to %s:", 2307 text = g_strdup_printf(_("Unable to send message to %s:"),
2022 (idb->user)? idb->user: "(unknown)"); 2308 (idb->user)? idb->user: "(unknown)");
2023 gaim_notify_error(gaim_account_get_connection(gconv->account), 2309 gaim_notify_error(gaim_account_get_connection(gconv->account),
2024 NULL, text, tmp); 2310 NULL, text, tmp);
2025 } 2311 }
2026 2312
2097 convo_nofeatures(conv); 2383 convo_nofeatures(conv);
2098 } 2384 }
2099 } 2385 }
2100 2386
2101 2387
2388 #if 0
2102 /** triggered from mw_conversation_opened if the appropriate plugin 2389 /** triggered from mw_conversation_opened if the appropriate plugin
2103 preference is set. This will open a window for the conversation 2390 preference is set. This will open a window for the conversation
2104 before the first message is sent. */ 2391 before the first message is sent. */
2105 static void convo_do_psychic(struct mwConversation *conv) { 2392 static void convo_do_psychic(struct mwConversation *conv) {
2106 struct mwServiceIm *srvc; 2393 struct mwServiceIm *srvc;
2110 GaimAccount *acct; 2397 GaimAccount *acct;
2111 2398
2112 struct mwIdBlock *idb; 2399 struct mwIdBlock *idb;
2113 2400
2114 GaimConversation *gconv; 2401 GaimConversation *gconv;
2402 GaimConvWindow *win;
2115 2403
2116 srvc = mwConversation_getService(conv); 2404 srvc = mwConversation_getService(conv);
2117 session = mwService_getSession(MW_SERVICE(srvc)); 2405 session = mwService_getSession(MW_SERVICE(srvc));
2118 pd = mwSession_getClientData(session); 2406 pd = mwSession_getClientData(session);
2119 gc = pd->gc; 2407 gc = pd->gc;
2120 acct = gaim_connection_get_account(gc); 2408 acct = gaim_connection_get_account(gc);
2121 2409
2122 idb = mwConversation_getTarget(conv); 2410 idb = mwConversation_getTarget(conv);
2123 2411
2124 gconv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, idb->user, acct); 2412 gconv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM,
2413 idb->user, acct);
2125 if(! gconv) { 2414 if(! gconv) {
2126 gconv = gaim_conversation_new(GAIM_CONV_TYPE_IM, acct, idb->user); 2415 gconv = gaim_conversation_new(GAIM_CONV_TYPE_IM, acct, idb->user);
2127 } 2416 }
2128 2417
2129 g_return_if_fail(gconv != NULL); 2418 g_return_if_fail(gconv != NULL);
2130 2419
2131
2132 #if 0
2133 GaimConvWindow *win;
2134 win = gaim_conversation_get_window(gconv); 2420 win = gaim_conversation_get_window(gconv);
2135 g_return_if_fail(win != NULL); 2421 g_return_if_fail(win != NULL);
2136 2422
2137 gaim_conv_window_show(win); 2423 gaim_conv_window_show(win);
2424 }
2138 #endif 2425 #endif
2139 }
2140 2426
2141 2427
2142 static void mw_conversation_opened(struct mwConversation *conv) { 2428 static void mw_conversation_opened(struct mwConversation *conv) {
2143 struct mwServiceIm *srvc; 2429 struct mwServiceIm *srvc;
2144 struct mwSession *session; 2430 struct mwSession *session;
2165 } 2451 }
2166 2452
2167 } else { 2453 } else {
2168 convo_data_new(conv); 2454 convo_data_new(conv);
2169 2455
2456 #if 0
2170 if(gaim_prefs_get_bool(MW_PRPL_OPT_PSYCHIC)) { 2457 if(gaim_prefs_get_bool(MW_PRPL_OPT_PSYCHIC)) {
2171 convo_do_psychic(conv); 2458 convo_do_psychic(conv);
2172 } 2459 }
2460 #endif
2173 } 2461 }
2174 2462
2175 { /* record the client key for the buddy */ 2463 { /* record the client key for the buddy */
2176 GaimBuddy *buddy; 2464 GaimBuddy *buddy;
2177 struct mwLoginInfo *info; 2465 struct mwLoginInfo *info;
2193 2481
2194 struct convo_data *cd; 2482 struct convo_data *cd;
2195 2483
2196 g_return_if_fail(conv != NULL); 2484 g_return_if_fail(conv != NULL);
2197 2485
2198 /* if there's a error code and a non-typing message in the queue, 2486 /* if there's an error code and a non-typing message in the queue,
2199 print an error message to the conversation */ 2487 print an error message to the conversation */
2200 cd = mwConversation_getClientData(conv); 2488 cd = mwConversation_getClientData(conv);
2201 if(reason && cd && cd->queue) { 2489 if(reason && cd && cd->queue) {
2202 GList *l; 2490 GList *l;
2203 for(l = cd->queue; l; l = l->next) { 2491 for(l = cd->queue; l; l = l->next) {
2218 2506
2219 mwConversation_removeClientData(conv); 2507 mwConversation_removeClientData(conv);
2220 } 2508 }
2221 2509
2222 2510
2511
2512 static char *im_decode(GaimConnection *gc, const char *msg) {
2513 return gaim_utf8_try_convert(msg);
2514 }
2515
2516
2223 static void im_recv_text(struct mwConversation *conv, 2517 static void im_recv_text(struct mwConversation *conv,
2224 struct mwGaimPluginData *pd, 2518 struct mwGaimPluginData *pd,
2225 const char *msg) { 2519 const char *msg) {
2226 2520
2227 struct mwIdBlock *idb; 2521 struct mwIdBlock *idb;
2228 char *txt, *esc; 2522 char *txt, *esc, *t;
2229 2523
2230 idb = mwConversation_getTarget(conv); 2524 idb = mwConversation_getTarget(conv);
2231 txt = gaim_utf8_try_convert(msg); 2525 txt = im_decode(pd->gc, msg);
2232 esc = g_markup_escape_text(txt, -1); 2526
2233 2527 t = txt? txt: (char *) msg;
2528
2529 esc = g_markup_escape_text(t, -1);
2234 serv_got_im(pd->gc, idb->user, esc, 0, time(NULL)); 2530 serv_got_im(pd->gc, idb->user, esc, 0, time(NULL));
2531 g_free(esc);
2235 2532
2236 g_free(txt); 2533 g_free(txt);
2237 g_free(esc);
2238 } 2534 }
2239 2535
2240 2536
2241 static void im_recv_typing(struct mwConversation *conv, 2537 static void im_recv_typing(struct mwConversation *conv,
2242 struct mwGaimPluginData *pd, 2538 struct mwGaimPluginData *pd,
2253 static void im_recv_html(struct mwConversation *conv, 2549 static void im_recv_html(struct mwConversation *conv,
2254 struct mwGaimPluginData *pd, 2550 struct mwGaimPluginData *pd,
2255 const char *msg) { 2551 const char *msg) {
2256 2552
2257 struct mwIdBlock *idb; 2553 struct mwIdBlock *idb;
2258 char *txt; 2554 char *txt, *t;
2259 2555
2260 idb = mwConversation_getTarget(conv); 2556 idb = mwConversation_getTarget(conv);
2261 txt = gaim_utf8_try_convert(msg); 2557 txt = im_decode(pd->gc, msg);
2262 2558
2263 serv_got_im(pd->gc, idb->user, txt, 0, time(NULL)); 2559 t = txt? txt: (char *) msg;
2560
2561 serv_got_im(pd->gc, idb->user, t, 0, time(NULL));
2264 2562
2265 g_free(txt); 2563 g_free(txt);
2266 } 2564 }
2267 2565
2268 2566
2363 char *txt; 2661 char *txt;
2364 gsize len; 2662 gsize len;
2365 2663
2366 gaim_mime_part_get_data_decoded(part, &data, &len); 2664 gaim_mime_part_get_data_decoded(part, &data, &len);
2367 2665
2368 txt = gaim_utf8_try_convert((const char *)data); 2666 txt = im_decode(pd->gc, data);
2667 g_string_append(str, txt?txt:(char *)data);
2668
2369 g_free(data); 2669 g_free(data);
2370
2371 g_string_append(str, txt);
2372 g_free(txt); 2670 g_free(txt);
2373 } 2671 }
2374 } 2672 }
2375 2673
2376 gaim_mime_document_free(doc); 2674 gaim_mime_document_free(doc);
2377 2675
2676 /* @todo should put this in its own function */
2378 { /* replace each IMG tag's SRC attribute with an ID attribute. This 2677 { /* replace each IMG tag's SRC attribute with an ID attribute. This
2379 actually modifies the contents of str */ 2678 actually modifies the contents of str */
2380 GData *attribs; 2679 GData *attribs;
2381 char *start, *end; 2680 char *start, *end;
2382 char *tmp = str->str; 2681 char *tmp = str->str;
2467 ; /* erm... */ 2766 ; /* erm... */
2468 } 2767 }
2469 } 2768 }
2470 2769
2471 2770
2472 #if 0
2473 /* this will be appropriate when meanwhile supports the Place service */
2474 static void mw_place_invite(struct mwConversation *conv, 2771 static void mw_place_invite(struct mwConversation *conv,
2475 const char *message, 2772 const char *message,
2476 const char *title, const char *name) { 2773 const char *title, const char *name) {
2477 struct mwServiceIm *srvc; 2774 struct mwServiceIm *srvc;
2478 struct mwSession *session; 2775 struct mwSession *session;
2490 ht = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free); 2787 ht = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
2491 g_hash_table_insert(ht, CHAT_KEY_CREATOR, g_strdup(idb->user)); 2788 g_hash_table_insert(ht, CHAT_KEY_CREATOR, g_strdup(idb->user));
2492 g_hash_table_insert(ht, CHAT_KEY_NAME, g_strdup(name)); 2789 g_hash_table_insert(ht, CHAT_KEY_NAME, g_strdup(name));
2493 g_hash_table_insert(ht, CHAT_KEY_TOPIC, g_strdup(title)); 2790 g_hash_table_insert(ht, CHAT_KEY_TOPIC, g_strdup(title));
2494 g_hash_table_insert(ht, CHAT_KEY_INVITE, g_strdup(message)); 2791 g_hash_table_insert(ht, CHAT_KEY_INVITE, g_strdup(message));
2792 g_hash_table_insert(ht, CHAT_KEY_IS_PLACE, g_strdup("")); /* ugh */
2495 2793
2496 serv_got_chat_invite(pd->gc, title, idb->user, message, ht); 2794 serv_got_chat_invite(pd->gc, title, idb->user, message, ht);
2497 } 2795
2498 #endif 2796 mwConversation_close(conv, ERR_SUCCESS);
2797 mwConversation_free(conv);
2798 }
2499 2799
2500 2800
2501 static void mw_im_clear(struct mwServiceIm *srvc) { 2801 static void mw_im_clear(struct mwServiceIm *srvc) {
2502 ; 2802 ;
2503 } 2803 }
2505 2805
2506 static struct mwImHandler mw_im_handler = { 2806 static struct mwImHandler mw_im_handler = {
2507 .conversation_opened = mw_conversation_opened, 2807 .conversation_opened = mw_conversation_opened,
2508 .conversation_closed = mw_conversation_closed, 2808 .conversation_closed = mw_conversation_closed,
2509 .conversation_recv = mw_conversation_recv, 2809 .conversation_recv = mw_conversation_recv,
2510 .place_invite = NULL, /* = mw_place_invite, */ 2810 .place_invite = mw_place_invite,
2511 .clear = mw_im_clear, 2811 .clear = mw_im_clear,
2512 }; 2812 };
2513 2813
2514 2814
2515 static struct mwServiceIm *mw_srvc_im_new(struct mwSession *s) { 2815 static struct mwServiceIm *mw_srvc_im_new(struct mwSession *s) {
2516 struct mwServiceIm *srvc; 2816 struct mwServiceIm *srvc;
2517 srvc = mwServiceIm_new(s, &mw_im_handler); 2817 srvc = mwServiceIm_new(s, &mw_im_handler);
2518 mwServiceIm_setClientType(srvc, mwImClient_NOTESBUDDY); 2818 mwServiceIm_setClientType(srvc, mwImClient_NOTESBUDDY);
2819 return srvc;
2820 }
2821
2822
2823 /* The following helps us relate a mwPlace to a GaimConvChat in the
2824 various forms by which either may be indicated. Uses some of
2825 the similar macros from the conference service above */
2826
2827 #define PLACE_TO_ID(place) (GPOINTER_TO_INT(place))
2828 #define ID_TO_PLACE(pd, id) (place_find_by_id((pd), (id)))
2829
2830 #define CHAT_TO_PLACE(pd, chat) (ID_TO_PLACE((pd), CHAT_TO_ID(chat)))
2831 #define PLACE_TO_CHAT(place) (ID_TO_CHAT(PLACE_TO_ID(place)))
2832
2833
2834 static struct mwPlace *
2835 place_find_by_id(struct mwGaimPluginData *pd, int id) {
2836 struct mwServicePlace *srvc = pd->srvc_place;
2837 struct mwPlace *place = NULL;
2838 GList *l;
2839
2840 l = (GList *) mwServicePlace_getPlaces(srvc);
2841 for(; l; l = l->next) {
2842 struct mwPlace *p = l->data;
2843 GaimConvChat *h = GAIM_CONV_CHAT(mwPlace_getClientData(p));
2844
2845 if(CHAT_TO_ID(h) == id) {
2846 place = p;
2847 break;
2848 }
2849 }
2850
2851 return place;
2852 }
2853
2854
2855 static void mw_place_opened(struct mwPlace *place) {
2856 struct mwServicePlace *srvc;
2857 struct mwSession *session;
2858 struct mwGaimPluginData *pd;
2859 GaimConnection *gc;
2860 GaimConversation *gconf;
2861
2862 GList *members, *l;
2863
2864 const char *n = mwPlace_getName(place);
2865
2866 srvc = mwPlace_getService(place);
2867 session = mwService_getSession(MW_SERVICE(srvc));
2868 pd = mwSession_getClientData(session);
2869 gc = pd->gc;
2870
2871 members = mwPlace_getMembers(place);
2872
2873 DEBUG_INFO("place %s opened, %u initial members\n",
2874 NSTR(n), g_list_length(members));
2875
2876 gconf = serv_got_joined_chat(gc, PLACE_TO_ID(place),
2877 mwPlace_getTitle(place));
2878
2879 mwPlace_setClientData(place, gconf, NULL);
2880
2881 for(l = members; l; l = l->next) {
2882 struct mwIdBlock *idb = l->data;
2883 gaim_conv_chat_add_user(GAIM_CONV_CHAT(gconf), idb->user,
2884 NULL, GAIM_CBFLAGS_NONE, FALSE);
2885 }
2886 g_list_free(members);
2887 }
2888
2889
2890 static void mw_place_closed(struct mwPlace *place, guint32 code) {
2891 struct mwServicePlace *srvc;
2892 struct mwSession *session;
2893 struct mwGaimPluginData *pd;
2894 GaimConnection *gc;
2895
2896 const char *n = mwPlace_getName(place);
2897 char *msg = mwError(code);
2898
2899 DEBUG_INFO("place %s closed, 0x%08x\n", NSTR(n), code);
2900
2901 srvc = mwPlace_getService(place);
2902 session = mwService_getSession(MW_SERVICE(srvc));
2903 pd = mwSession_getClientData(session);
2904 gc = pd->gc;
2905
2906 serv_got_chat_left(gc, PLACE_TO_ID(place));
2907
2908 gaim_notify_error(gc, _("Place Closed"), NULL, msg);
2909 g_free(msg);
2910 }
2911
2912
2913 static void mw_place_peerJoined(struct mwPlace *place,
2914 const struct mwIdBlock *peer) {
2915 struct mwServicePlace *srvc;
2916 struct mwSession *session;
2917 struct mwGaimPluginData *pd;
2918 GaimConnection *gc;
2919 GaimConversation *gconf;
2920
2921 const char *n = mwPlace_getName(place);
2922
2923 DEBUG_INFO("%s joined place %s\n", NSTR(peer->user), NSTR(n));
2924
2925 srvc = mwPlace_getService(place);
2926 session = mwService_getSession(MW_SERVICE(srvc));
2927 pd = mwSession_getClientData(session);
2928 gc = pd->gc;
2929
2930 gconf = mwPlace_getClientData(place);
2931 g_return_if_fail(gconf != NULL);
2932
2933 gaim_conv_chat_add_user(GAIM_CONV_CHAT(gconf), peer->user,
2934 NULL, GAIM_CBFLAGS_NONE, TRUE);
2935 }
2936
2937
2938 static void mw_place_peerParted(struct mwPlace *place,
2939 const struct mwIdBlock *peer) {
2940 struct mwServicePlace *srvc;
2941 struct mwSession *session;
2942 struct mwGaimPluginData *pd;
2943 GaimConnection *gc;
2944 GaimConversation *gconf;
2945
2946 const char *n = mwPlace_getName(place);
2947
2948 DEBUG_INFO("%s left place %s\n", NSTR(peer->user), NSTR(n));
2949
2950 srvc = mwPlace_getService(place);
2951 session = mwService_getSession(MW_SERVICE(srvc));
2952 pd = mwSession_getClientData(session);
2953 gc = pd->gc;
2954
2955 gconf = mwPlace_getClientData(place);
2956 g_return_if_fail(gconf != NULL);
2957
2958 gaim_conv_chat_remove_user(GAIM_CONV_CHAT(gconf), peer->user, NULL);
2959 }
2960
2961
2962 static void mw_place_peerSetAttribute(struct mwPlace *place,
2963 const struct mwIdBlock *peer,
2964 guint32 attr, struct mwOpaque *o) {
2965 ;
2966 }
2967
2968
2969 static void mw_place_peerUnsetAttribute(struct mwPlace *place,
2970 const struct mwIdBlock *peer,
2971 guint32 attr) {
2972 ;
2973 }
2974
2975
2976 static void mw_place_message(struct mwPlace *place,
2977 const struct mwIdBlock *who,
2978 const char *msg) {
2979 struct mwServicePlace *srvc;
2980 struct mwSession *session;
2981 struct mwGaimPluginData *pd;
2982 GaimConnection *gc;
2983 char *esc;
2984
2985 srvc = mwPlace_getService(place);
2986 session = mwService_getSession(MW_SERVICE(srvc));
2987 pd = mwSession_getClientData(session);
2988 gc = pd->gc;
2989
2990 esc = g_markup_escape_text(msg, -1);
2991 serv_got_chat_in(gc, PLACE_TO_ID(place), who->user, 0, esc, time(NULL));
2992 g_free(esc);
2993 }
2994
2995
2996 static void mw_place_clear(struct mwServicePlace *srvc) {
2997 ;
2998 }
2999
3000
3001 static struct mwPlaceHandler mw_place_handler = {
3002 .opened = mw_place_opened,
3003 .closed = mw_place_closed,
3004 .peerJoined = mw_place_peerJoined,
3005 .peerParted = mw_place_peerParted,
3006 .peerSetAttribute = mw_place_peerSetAttribute,
3007 .peerUnsetAttribute = mw_place_peerUnsetAttribute,
3008 .message = mw_place_message,
3009 .clear = mw_place_clear,
3010 };
3011
3012
3013 static struct mwServicePlace *mw_srvc_place_new(struct mwSession *s) {
3014 struct mwServicePlace *srvc;
3015 srvc = mwServicePlace_new(s, &mw_place_handler);
2519 return srvc; 3016 return srvc;
2520 } 3017 }
2521 3018
2522 3019
2523 static struct mwServiceResolve *mw_srvc_resolve_new(struct mwSession *s) { 3020 static struct mwServiceResolve *mw_srvc_resolve_new(struct mwSession *s) {
2545 pd->session = mwSession_new(&mw_session_handler); 3042 pd->session = mwSession_new(&mw_session_handler);
2546 pd->srvc_aware = mw_srvc_aware_new(pd->session); 3043 pd->srvc_aware = mw_srvc_aware_new(pd->session);
2547 pd->srvc_conf = mw_srvc_conf_new(pd->session); 3044 pd->srvc_conf = mw_srvc_conf_new(pd->session);
2548 pd->srvc_ft = mw_srvc_ft_new(pd->session); 3045 pd->srvc_ft = mw_srvc_ft_new(pd->session);
2549 pd->srvc_im = mw_srvc_im_new(pd->session); 3046 pd->srvc_im = mw_srvc_im_new(pd->session);
3047 pd->srvc_place = mw_srvc_place_new(pd->session);
2550 pd->srvc_resolve = mw_srvc_resolve_new(pd->session); 3048 pd->srvc_resolve = mw_srvc_resolve_new(pd->session);
2551 pd->srvc_store = mw_srvc_store_new(pd->session); 3049 pd->srvc_store = mw_srvc_store_new(pd->session);
2552 pd->group_list_map = g_hash_table_new(g_direct_hash, g_direct_equal); 3050 pd->group_list_map = g_hash_table_new(g_direct_hash, g_direct_equal);
2553 3051
2554 mwSession_addService(pd->session, MW_SERVICE(pd->srvc_aware)); 3052 mwSession_addService(pd->session, MW_SERVICE(pd->srvc_aware));
2555 mwSession_addService(pd->session, MW_SERVICE(pd->srvc_conf)); 3053 mwSession_addService(pd->session, MW_SERVICE(pd->srvc_conf));
2556 mwSession_addService(pd->session, MW_SERVICE(pd->srvc_ft)); 3054 mwSession_addService(pd->session, MW_SERVICE(pd->srvc_ft));
2557 mwSession_addService(pd->session, MW_SERVICE(pd->srvc_im)); 3055 mwSession_addService(pd->session, MW_SERVICE(pd->srvc_im));
3056 mwSession_addService(pd->session, MW_SERVICE(pd->srvc_place));
2558 mwSession_addService(pd->session, MW_SERVICE(pd->srvc_resolve)); 3057 mwSession_addService(pd->session, MW_SERVICE(pd->srvc_resolve));
2559 mwSession_addService(pd->session, MW_SERVICE(pd->srvc_store)); 3058 mwSession_addService(pd->session, MW_SERVICE(pd->srvc_store));
2560 3059
2561 mwSession_addCipher(pd->session, mwCipher_new_RC2_40(pd->session)); 3060 mwSession_addCipher(pd->session, mwCipher_new_RC2_40(pd->session));
3061 mwSession_addCipher(pd->session, mwCipher_new_RC2_128(pd->session));
2562 3062
2563 mwSession_setClientData(pd->session, pd, NULL); 3063 mwSession_setClientData(pd->session, pd, NULL);
2564 gc->proto_data = pd; 3064 gc->proto_data = pd;
2565 3065
2566 return pd; 3066 return pd;
2570 static void mwGaimPluginData_free(struct mwGaimPluginData *pd) { 3070 static void mwGaimPluginData_free(struct mwGaimPluginData *pd) {
2571 g_return_if_fail(pd != NULL); 3071 g_return_if_fail(pd != NULL);
2572 3072
2573 pd->gc->proto_data = NULL; 3073 pd->gc->proto_data = NULL;
2574 3074
2575 mwSession_removeService(pd->session, SERVICE_AWARE); 3075 mwSession_removeService(pd->session, mwService_AWARE);
2576 mwSession_removeService(pd->session, SERVICE_CONFERENCE); 3076 mwSession_removeService(pd->session, mwService_CONFERENCE);
2577 mwSession_removeService(pd->session, SERVICE_IM); 3077 mwSession_removeService(pd->session, mwService_FILE_TRANSFER);
2578 mwSession_removeService(pd->session, SERVICE_RESOLVE); 3078 mwSession_removeService(pd->session, mwService_IM);
2579 mwSession_removeService(pd->session, SERVICE_STORAGE); 3079 mwSession_removeService(pd->session, mwService_PLACE);
3080 mwSession_removeService(pd->session, mwService_RESOLVE);
3081 mwSession_removeService(pd->session, mwService_STORAGE);
2580 3082
2581 mwService_free(MW_SERVICE(pd->srvc_aware)); 3083 mwService_free(MW_SERVICE(pd->srvc_aware));
2582 mwService_free(MW_SERVICE(pd->srvc_conf)); 3084 mwService_free(MW_SERVICE(pd->srvc_conf));
3085 mwService_free(MW_SERVICE(pd->srvc_ft));
2583 mwService_free(MW_SERVICE(pd->srvc_im)); 3086 mwService_free(MW_SERVICE(pd->srvc_im));
3087 mwService_free(MW_SERVICE(pd->srvc_place));
2584 mwService_free(MW_SERVICE(pd->srvc_resolve)); 3088 mwService_free(MW_SERVICE(pd->srvc_resolve));
2585 mwService_free(MW_SERVICE(pd->srvc_store)); 3089 mwService_free(MW_SERVICE(pd->srvc_store));
2586 3090
2587 mwCipher_free(mwSession_getCipher(pd->session, mwCipher_RC2_40)); 3091 mwCipher_free(mwSession_getCipher(pd->session, mwCipher_RC2_40));
3092 mwCipher_free(mwSession_getCipher(pd->session, mwCipher_RC2_128));
2588 3093
2589 mwSession_free(pd->session); 3094 mwSession_free(pd->session);
2590 3095
2591 g_hash_table_destroy(pd->group_list_map); 3096 g_hash_table_destroy(pd->group_list_map);
2592 3097
2611 3116
2612 3117
2613 static void mw_prpl_list_emblems(GaimBuddy *b, 3118 static void mw_prpl_list_emblems(GaimBuddy *b,
2614 const char **se, const char **sw, 3119 const char **se, const char **sw,
2615 const char **nw, const char **ne) { 3120 const char **nw, const char **ne) {
2616 GaimPresence *presence = gaim_buddy_get_presence(b); 3121
2617 GaimStatus *status = gaim_presence_get_active_status(presence); 3122 /* speaking of custom icons, the external icon here is an ugly
3123 little example of what happens when I use Gimp */
3124
3125 GaimPresence *presence;
3126 GaimStatus *status;
3127 const char *status_id;
3128
3129 presence = gaim_buddy_get_presence(b);
3130 status = gaim_presence_get_active_status(presence);
3131 status_id = gaim_status_get_id(status);
2618 3132
2619 if(! GAIM_BUDDY_IS_ONLINE(b)) { 3133 if(! GAIM_BUDDY_IS_ONLINE(b)) {
2620 *se = "offline"; 3134 *se = "offline";
2621 } else if(!gaim_presence_is_available(presence) && 3135 } else if(!strcmp(status_id, MW_STATE_AWAY)) {
2622 !strcmp(gaim_status_get_id(status), MW_STATE_AWAY)) {
2623 *se = "away"; 3136 *se = "away";
2624 } else if(!gaim_presence_is_available(presence) && 3137 } else if(!strcmp(status_id, MW_STATE_BUSY)) {
2625 !strcmp(gaim_status_get_id(status), MW_STATE_BUSY)) {
2626 *se = "dnd"; 3138 *se = "dnd";
3139 }
3140
3141 if(buddy_is_external(b)) {
3142 /* best assignment ever */
3143 *(*se?sw:se) = "external";
2627 } 3144 }
2628 } 3145 }
2629 3146
2630 3147
2631 static char *mw_prpl_status_text(GaimBuddy *b) { 3148 static char *mw_prpl_status_text(GaimBuddy *b) {
2636 3153
2637 gc = b->account->gc; 3154 gc = b->account->gc;
2638 pd = gc->proto_data; 3155 pd = gc->proto_data;
2639 3156
2640 ret = mwServiceAware_getText(pd->srvc_aware, &t); 3157 ret = mwServiceAware_getText(pd->srvc_aware, &t);
2641 return (ret)? g_strdup(ret): NULL; 3158 return g_strdup(ret);
2642 } 3159 }
2643 3160
2644 3161
2645 static const char *status_text(GaimBuddy *b) { 3162 static const char *status_text(GaimBuddy *b) {
2646 GaimPresence *presence = gaim_buddy_get_presence(b); 3163 GaimPresence *presence;
2647 GaimStatus *status = gaim_presence_get_active_status(presence); 3164 GaimStatus *status;
3165
3166 presence = gaim_buddy_get_presence(b);
3167 status = gaim_presence_get_active_status(presence);
2648 3168
2649 return gaim_status_get_name(status); 3169 return gaim_status_get_name(status);
2650
2651 /* I left this here in case it's more accurate than the status name.
2652 * Stu. */
2653 #if 0
2654
2655 guint status = b->uc;
2656
2657 if(! GAIM_BUDDY_IS_ONLINE(b) ) {
2658 return MW_STATE_OFFLINE;
2659
2660 } else if(status == (mwStatus_AWAY /* XXX | UC_UNAVAILABLE */)) {
2661 return MW_STATE_AWAY;
2662
2663 } else if(status == (mwStatus_BUSY /* XXX | UC_UNAVAILABLE */)) {
2664 return MW_STATE_BUSY;
2665
2666 } else if(status == mwStatus_IDLE) {
2667 return MW_STATE_IDLE;
2668
2669 } else if(status == mwStatus_ACTIVE) {
2670 return MW_STATE_ACTIVE;
2671
2672 } else {
2673 return MW_STATE_UNKNOWN;
2674 }
2675 #endif
2676 } 3170 }
2677 3171
2678 3172
2679 static gboolean user_supports(struct mwServiceAware *srvc, 3173 static gboolean user_supports(struct mwServiceAware *srvc,
2680 const char *who, guint32 feature) { 3174 const char *who, guint32 feature) {
2696 3190
2697 mic = user_supports(srvc, who, mwAttribute_MICROPHONE); 3191 mic = user_supports(srvc, who, mwAttribute_MICROPHONE);
2698 speak = user_supports(srvc, who, mwAttribute_SPEAKERS); 3192 speak = user_supports(srvc, who, mwAttribute_SPEAKERS);
2699 video = user_supports(srvc, who, mwAttribute_VIDEO_CAMERA); 3193 video = user_supports(srvc, who, mwAttribute_VIDEO_CAMERA);
2700 3194
2701 if(mic) *f++ = "Microphone"; 3195 if(mic) *f++ = _("Microphone");
2702 if(speak) *f++ = "Speakers"; 3196 if(speak) *f++ = _("Speakers");
2703 if(video) *f++ = "Video Camera"; 3197 if(video) *f++ = _("Video Camera");
2704 } 3198 }
2705 3199
2706 if(user_supports(srvc, who, mwAttribute_FILE_TRANSFER)) 3200 if(user_supports(srvc, who, mwAttribute_FILE_TRANSFER))
2707 *f++ = "File Transfer"; 3201 *f++ = _("File Transfer");
2708 3202
2709 return (*feat)? g_strjoinv(", ", feat): NULL; 3203 return (*feat)? g_strjoinv(", ", feat): NULL;
2710 /* jenni loves siege */ 3204 /* jenni loves siege */
2711 } 3205 }
2712 3206
2723 pd = gc->proto_data; 3217 pd = gc->proto_data;
2724 3218
2725 str = g_string_new(NULL); 3219 str = g_string_new(NULL);
2726 3220
2727 tmp = status_text(b); 3221 tmp = status_text(b);
2728 g_string_append_printf(str, "\n<b>Status</b>: %s", tmp); 3222 g_string_append_printf(str, _("\n<b>Status</b>: %s"), tmp);
2729 3223
2730 tmp = mwServiceAware_getText(pd->srvc_aware, &idb); 3224 tmp = mwServiceAware_getText(pd->srvc_aware, &idb);
2731 if(tmp) { 3225 if(tmp) {
2732 tmp = g_markup_escape_text(tmp, -1); 3226 tmp = g_markup_escape_text(tmp, -1);
2733 g_string_append_printf(str, "\n<b>Message</b>: %s", tmp); 3227 g_string_append_printf(str, _("\n<b>Message</b>: %s"), tmp);
2734 g_free((char *) tmp); 3228 g_free((char *) tmp);
2735 } 3229 }
2736 3230
2737 tmp = user_supports_text(pd->srvc_aware, b->name); 3231 tmp = user_supports_text(pd->srvc_aware, b->name);
2738 if(tmp) { 3232 if(tmp) {
2739 g_string_append_printf(str, "\n<b>Supports</b>: %s", tmp); 3233 g_string_append_printf(str, _("\n<b>Supports</b>: %s"), tmp);
2740 g_free((char *) tmp); 3234 g_free((char *) tmp);
3235 }
3236
3237 if(buddy_is_external(b)) {
3238 g_string_append(str, _("\n<b>External User</b>"));
2741 } 3239 }
2742 3240
2743 tmp = str->str; 3241 tmp = str->str;
2744 g_string_free(str, FALSE); 3242 g_string_free(str, FALSE);
2745 return (char *) tmp; 3243 return (char *) tmp;
2763 type = gaim_status_type_new(GAIM_STATUS_AWAY, MW_STATE_AWAY, 3261 type = gaim_status_type_new(GAIM_STATUS_AWAY, MW_STATE_AWAY,
2764 _("Away"), TRUE); 3262 _("Away"), TRUE);
2765 gaim_status_type_add_attr(type, MW_STATE_MESSAGE, _("Message"), 3263 gaim_status_type_add_attr(type, MW_STATE_MESSAGE, _("Message"),
2766 gaim_value_new(GAIM_TYPE_STRING)); 3264 gaim_value_new(GAIM_TYPE_STRING));
2767 types = g_list_append(types, type); 3265 types = g_list_append(types, type);
2768 3266
2769 type = gaim_status_type_new(GAIM_STATUS_UNAVAILABLE, MW_STATE_BUSY, 3267 type = gaim_status_type_new(GAIM_STATUS_UNAVAILABLE, MW_STATE_BUSY,
2770 _("Do Not Disturb"), TRUE); 3268 _("Do Not Disturb"), TRUE);
2771 gaim_status_type_add_attr(type, MW_STATE_MESSAGE, _("Message"), 3269 gaim_status_type_add_attr(type, MW_STATE_MESSAGE, _("Message"),
2772 gaim_value_new(GAIM_TYPE_STRING)); 3270 gaim_value_new(GAIM_TYPE_STRING));
2773 types = g_list_append(types, type); 3271 types = g_list_append(types, type);
2774 3272
2775 return types; 3273 return types;
2776 } 3274 }
2777 3275
2778 3276
2779 static void conf_create_prompt_cancel(GaimBuddy *buddy, 3277 static void conf_create_prompt_cancel(GaimBuddy *buddy,
2780 GaimRequestFields *fields) { 3278 GaimRequestFields *fields) {
2781 ; 3279 ; /* nothing to do */
2782 } 3280 }
2783 3281
2784 3282
2785 static void conf_create_prompt_join(GaimBuddy *buddy, 3283 static void conf_create_prompt_join(GaimBuddy *buddy,
2786 GaimRequestFields *fields) { 3284 GaimRequestFields *fields) {
2836 fields = gaim_request_fields_new(); 3334 fields = gaim_request_fields_new();
2837 3335
2838 g = gaim_request_field_group_new(NULL); 3336 g = gaim_request_field_group_new(NULL);
2839 gaim_request_fields_add_group(fields, g); 3337 gaim_request_fields_add_group(fields, g);
2840 3338
2841 f = gaim_request_field_string_new(CHAT_KEY_TOPIC, "Topic", NULL, FALSE); 3339 f = gaim_request_field_string_new(CHAT_KEY_TOPIC, _("Topic"), NULL, FALSE);
2842 gaim_request_field_group_add_field(g, f); 3340 gaim_request_field_group_add_field(g, f);
2843 3341
2844 f = gaim_request_field_string_new(CHAT_KEY_INVITE, "Message", msg, FALSE); 3342 f = gaim_request_field_string_new(CHAT_KEY_INVITE, _("Message"), msg, FALSE);
2845 gaim_request_field_group_add_field(g, f); 3343 gaim_request_field_group_add_field(g, f);
2846 3344
2847 msgA = ("Create conference with user"); 3345 msgA = _("Create conference with user");
2848 msgB = ("Please enter a topic for the new conference, and an invitation" 3346 msgB = _("Please enter a topic for the new conference, and an invitation"
2849 " message to be sent to %s"); 3347 " message to be sent to %s");
2850 msgB = g_strdup_printf(msgB, buddy->name); 3348 msgB = g_strdup_printf(msgB, buddy->name);
2851 3349
2852 gaim_request_fields(gc, "New Conference", 3350 gaim_request_fields(gc, _("New Conference"),
2853 msgA, msgB, fields, 3351 msgA, msgB, fields,
2854 "Create", G_CALLBACK(conf_create_prompt_join), 3352 _("Create"), G_CALLBACK(conf_create_prompt_join),
2855 "Cancel", G_CALLBACK(conf_create_prompt_cancel), 3353 _("Cancel"), G_CALLBACK(conf_create_prompt_cancel),
2856 buddy); 3354 buddy);
2857 g_free(msgB); 3355 g_free(msgB);
2858 } 3356 }
2859 3357
2860 3358
2911 fields = gaim_request_fields_new(); 3409 fields = gaim_request_fields_new();
2912 3410
2913 g = gaim_request_field_group_new(NULL); 3411 g = gaim_request_field_group_new(NULL);
2914 gaim_request_fields_add_group(fields, g); 3412 gaim_request_fields_add_group(fields, g);
2915 3413
2916 f = gaim_request_field_list_new("conf", "Available Conferences"); 3414 f = gaim_request_field_list_new("conf", _("Available Conferences"));
2917 gaim_request_field_list_set_multi_select(f, FALSE); 3415 gaim_request_field_list_set_multi_select(f, FALSE);
2918 for(; confs; confs = confs->next) { 3416 for(; confs; confs = confs->next) {
2919 struct mwConference *c = confs->data; 3417 struct mwConference *c = confs->data;
2920 gaim_request_field_list_add(f, mwConference_getTitle(c), c); 3418 gaim_request_field_list_add(f, mwConference_getTitle(c), c);
2921 } 3419 }
2922 gaim_request_field_list_add(f, "Create New Conference...", 3420 gaim_request_field_list_add(f, _("Create New Conference..."),
2923 GINT_TO_POINTER(0x01)); 3421 GINT_TO_POINTER(0x01));
2924 gaim_request_field_group_add_field(g, f); 3422 gaim_request_field_group_add_field(g, f);
2925 3423
2926 f = gaim_request_field_string_new(CHAT_KEY_INVITE, "Message", NULL, FALSE); 3424 f = gaim_request_field_string_new(CHAT_KEY_INVITE, "Message", NULL, FALSE);
2927 gaim_request_field_group_add_field(g, f); 3425 gaim_request_field_group_add_field(g, f);
2928 3426
2929 msgA = "Invite user to a conference"; 3427 msgA = _("Invite user to a conference");
2930 msgB = ("Select a conference from the list below to send an invite to" 3428 msgB = _("Select a conference from the list below to send an invite to"
2931 " user %s. Select \"Create New Conference\" if you'd like to" 3429 " user %s. Select \"Create New Conference\" if you'd like to"
2932 " create a new conference to invite this user to."); 3430 " create a new conference to invite this user to.");
2933 msgB = g_strdup_printf(msgB, buddy->name); 3431 msgB = g_strdup_printf(msgB, buddy->name);
2934 3432
2935 gaim_request_fields(gc, "Invite to Conference", 3433 gaim_request_fields(gc, _("Invite to Conference"),
2936 msgA, msgB, fields, 3434 msgA, msgB, fields,
2937 "Invite", G_CALLBACK(conf_select_prompt_invite), 3435 _("Invite"), G_CALLBACK(conf_select_prompt_invite),
2938 "Cancel", G_CALLBACK(conf_select_prompt_cancel), 3436 _("Cancel"), G_CALLBACK(conf_select_prompt_cancel),
2939 buddy); 3437 buddy);
2940 g_free(msgB); 3438 g_free(msgB);
2941 } 3439 }
2942 3440
2943 3441
2984 if(! GAIM_BLIST_NODE_IS_BUDDY(node)) 3482 if(! GAIM_BLIST_NODE_IS_BUDDY(node))
2985 return l; 3483 return l;
2986 3484
2987 l = g_list_append(l, NULL); 3485 l = g_list_append(l, NULL);
2988 3486
2989 act = gaim_blist_node_action_new("Invite to Conference...", 3487 act = gaim_blist_node_action_new(_("Invite to Conference..."),
2990 blist_menu_conf, NULL, NULL); 3488 blist_menu_conf, NULL, NULL);
2991 l = g_list_append(l, act); 3489 l = g_list_append(l, act);
2992 3490
2993 /** note: this never gets called for a GaimGroup, have to use the 3491 /** note: this never gets called for a GaimGroup, have to use the
2994 blist-node-extended-menu signal for that. The function 3492 blist-node-extended-menu signal for that. The function
3002 static GList *mw_prpl_chat_info(GaimConnection *gc) { 3500 static GList *mw_prpl_chat_info(GaimConnection *gc) {
3003 GList *l = NULL; 3501 GList *l = NULL;
3004 struct proto_chat_entry *pce; 3502 struct proto_chat_entry *pce;
3005 3503
3006 pce = g_new0(struct proto_chat_entry, 1); 3504 pce = g_new0(struct proto_chat_entry, 1);
3007 pce->label = "Topic:"; 3505 pce->label = _("Topic:");
3008 pce->identifier = CHAT_KEY_TOPIC; 3506 pce->identifier = CHAT_KEY_TOPIC;
3009 l = g_list_append(l, pce); 3507 l = g_list_append(l, pce);
3010 3508
3011 return l; 3509 return l;
3012 } 3510 }
3030 3528
3031 static void mw_prpl_login(GaimAccount *acct); 3529 static void mw_prpl_login(GaimAccount *acct);
3032 3530
3033 3531
3034 static void prompt_host_cancel_cb(GaimConnection *gc) { 3532 static void prompt_host_cancel_cb(GaimConnection *gc) {
3035 gaim_connection_error(gc, "No Sametime Community Server specified"); 3533 gaim_connection_error(gc, _("No Sametime Community Server specified"));
3036 } 3534 }
3037 3535
3038 3536
3039 static void prompt_host_ok_cb(GaimConnection *gc, const char *host) { 3537 static void prompt_host_ok_cb(GaimConnection *gc, const char *host) {
3040 if(host && *host) { 3538 if(host && *host) {
3041 GaimAccount *acct; 3539 GaimAccount *acct = gaim_connection_get_account(gc);
3042
3043 acct = gaim_connection_get_account(gc);
3044 gaim_account_set_string(acct, MW_KEY_HOST, host); 3540 gaim_account_set_string(acct, MW_KEY_HOST, host);
3045
3046 mw_prpl_login(acct); 3541 mw_prpl_login(acct);
3047 3542
3048 } else { 3543 } else {
3049 prompt_host_cancel_cb(gc); 3544 prompt_host_cancel_cb(gc);
3050 } 3545 }
3054 static void prompt_host(GaimConnection *gc) { 3549 static void prompt_host(GaimConnection *gc) {
3055 GaimAccount *acct; 3550 GaimAccount *acct;
3056 char *msg; 3551 char *msg;
3057 3552
3058 acct = gaim_connection_get_account(gc); 3553 acct = gaim_connection_get_account(gc);
3059 msg = ("No host or IP address has been configured for the" 3554 msg = _("No host or IP address has been configured for the"
3060 " Meanwhile account %s. Please enter one below to" 3555 " Meanwhile account %s. Please enter one below to"
3061 " continue logging in."); 3556 " continue logging in.");
3062 msg = g_strdup_printf(msg, NSTR(gaim_account_get_username(acct))); 3557 msg = g_strdup_printf(msg, NSTR(gaim_account_get_username(acct)));
3063 3558
3064 gaim_request_input(gc, "Meanwhile Connection Setup", 3559 gaim_request_input(gc, _("Meanwhile Connection Setup"),
3065 "No Sametime Community Server Specified", msg, 3560 _("No Sametime Community Server Specified"), msg,
3066 MW_PLUGIN_DEFAULT_HOST, FALSE, FALSE, NULL, 3561 MW_PLUGIN_DEFAULT_HOST, FALSE, FALSE, NULL,
3067 "Connect", G_CALLBACK(prompt_host_ok_cb), 3562 _("Connect"), G_CALLBACK(prompt_host_ok_cb),
3068 "Cancel", G_CALLBACK(prompt_host_cancel_cb), 3563 _("Cancel"), G_CALLBACK(prompt_host_cancel_cb),
3069 gc); 3564 gc);
3070 3565
3071 g_free(msg); 3566 g_free(msg);
3072 } 3567 }
3073 3568
3118 mwSession_setProperty(pd->session, mwSession_AUTH_USER_ID, user, g_free); 3613 mwSession_setProperty(pd->session, mwSession_AUTH_USER_ID, user, g_free);
3119 mwSession_setProperty(pd->session, mwSession_AUTH_PASSWORD, pass, NULL); 3614 mwSession_setProperty(pd->session, mwSession_AUTH_PASSWORD, pass, NULL);
3120 mwSession_setProperty(pd->session, mwSession_CLIENT_TYPE_ID, 3615 mwSession_setProperty(pd->session, mwSession_CLIENT_TYPE_ID,
3121 GUINT_TO_POINTER(MW_CLIENT_TYPE_ID), NULL); 3616 GUINT_TO_POINTER(MW_CLIENT_TYPE_ID), NULL);
3122 3617
3123 gaim_connection_update_progress(gc, "Connecting", 1, MW_CONNECT_STEPS); 3618 gaim_connection_update_progress(gc, _("Connecting"), 1, MW_CONNECT_STEPS);
3124 3619
3125 if(gaim_proxy_connect(account, host, port, connect_cb, pd)) { 3620 if(gaim_proxy_connect(account, host, port, connect_cb, pd)) {
3126 gaim_connection_error(gc, "Unable to connect to host"); 3621 gaim_connection_error(gc, _("Unable to connect to host"));
3127 } 3622 }
3128 } 3623 }
3129 3624
3130 3625
3131 static void mw_prpl_close(GaimConnection *gc) { 3626 static void mw_prpl_close(GaimConnection *gc) {
3175 srand(time(0) ^ rand()); 3670 srand(time(0) ^ rand());
3176 return g_strdup_printf(c, rand() & 0xfff, rand() & 0xffff); 3671 return g_strdup_printf(c, rand() & 0xfff, rand() & 0xffff);
3177 } 3672 }
3178 3673
3179 3674
3675 /** determine content type from extension. Not so happy about this,
3676 but I don't want to actually write image type detection */
3180 static const char *im_mime_img_content_type(GaimStoredImage *img) { 3677 static const char *im_mime_img_content_type(GaimStoredImage *img) {
3181 const char *fn = gaim_imgstore_get_filename(img); 3678 const char *fn = gaim_imgstore_get_filename(img);
3182 3679
3183 fn = strrchr(fn, '.'); 3680 fn = strrchr(fn, '.');
3184 if(! fn) { 3681 if(! fn) {
3206 const char *fn = gaim_imgstore_get_filename(img); 3703 const char *fn = gaim_imgstore_get_filename(img);
3207 return g_strdup_printf("attachment; filename=\"%s\"", fn); 3704 return g_strdup_printf("attachment; filename=\"%s\"", fn);
3208 } 3705 }
3209 3706
3210 3707
3708 /** turn an IM with embedded images into a multi-part mime document */
3211 static char *im_mime_convert(const char *message) { 3709 static char *im_mime_convert(const char *message) {
3212 GString *str; 3710 GString *str;
3213 GaimMimeDocument *doc; 3711 GaimMimeDocument *doc;
3214 GaimMimePart *part; 3712 GaimMimePart *part;
3215 3713
3305 3803
3306 return tmp; 3804 return tmp;
3307 } 3805 }
3308 3806
3309 3807
3808 static char *im_try_convert(const char *msg,
3809 const char *enc_to,
3810 const char *enc_from) {
3811 char *ret;
3812 GError *error = NULL;
3813
3814 ret = g_convert(msg, -1, enc_to, enc_from, NULL, NULL, &error);
3815 if(error) {
3816 /* if there's something that just won't convert, leave it as UTF-8 */
3817 DEBUG_INFO("problem converting to %s, preserving %s: %s\n",
3818 NSTR(enc_to), NSTR(enc_from), NSTR(error->message));
3819 g_error_free(error);
3820 }
3821
3822 return ret;
3823 }
3824
3825
3826 static char *im_encode(GaimConnection *gc, const char *msg) {
3827 GaimAccount *acct;
3828 const char *enc;
3829
3830 acct = gaim_connection_get_account(gc);
3831 g_return_val_if_fail(acct != NULL, NULL);
3832
3833 enc = gaim_account_get_string(acct, MW_KEY_ENCODING,
3834 MW_PLUGIN_DEFAULT_ENCODING);
3835
3836 return im_try_convert(msg, enc, "UTF-8");
3837 }
3838
3839
3310 static int mw_prpl_send_im(GaimConnection *gc, 3840 static int mw_prpl_send_im(GaimConnection *gc,
3311 const char *name, 3841 const char *name,
3312 const char *message, 3842 const char *message,
3313 GaimConvImFlags flags) { 3843 GaimConvImFlags flags) {
3314 3844
3315 struct mwGaimPluginData *pd; 3845 struct mwGaimPluginData *pd;
3316 struct mwIdBlock who = { (char *) name, NULL }; 3846 struct mwIdBlock who = { (char *) name, NULL };
3317 struct mwConversation *conv; 3847 struct mwConversation *conv;
3848 char *msg = NULL;
3318 3849
3319 g_return_val_if_fail(gc != NULL, 0); 3850 g_return_val_if_fail(gc != NULL, 0);
3320 pd = gc->proto_data; 3851 pd = gc->proto_data;
3321 3852
3322 g_return_val_if_fail(pd != NULL, 0); 3853 g_return_val_if_fail(pd != NULL, 0);
3854
3855 msg = im_encode(gc, message);
3856 if(!msg) msg = g_strdup(message);
3323 3857
3324 conv = mwServiceIm_getConversation(pd->srvc_im, &who); 3858 conv = mwServiceIm_getConversation(pd->srvc_im, &who);
3325 3859
3326 /* this detection of features to determine how to send the message 3860 /* this detection of features to determine how to send the message
3327 (plain, html, or mime) is flawed because the other end of the 3861 (plain, html, or mime) is flawed because the other end of the
3329 existing formatting in an outgoing message innapropriate. The end 3863 existing formatting in an outgoing message innapropriate. The end
3330 result is that it may be possible that the other side of the 3864 result is that it may be possible that the other side of the
3331 conversation will receive a plaintext message with html contents, 3865 conversation will receive a plaintext message with html contents,
3332 which is bad. I'm not sure how to fix this correctly. */ 3866 which is bad. I'm not sure how to fix this correctly. */
3333 3867
3334 if(strstr(message, "<img ") || strstr(message, "<IMG ")) 3868 if(strstr(msg, "<img ") || strstr(msg, "<IMG "))
3335 flags |= GAIM_CONV_IM_IMAGES; 3869 flags |= GAIM_CONV_IM_IMAGES;
3336 3870
3337 if(mwConversation_isOpen(conv)) { 3871 if(mwConversation_isOpen(conv)) {
3338 char *msg = NULL; 3872 char *tmp;
3339 int ret; 3873 int ret;
3340 3874
3341 if((flags & GAIM_CONV_IM_IMAGES) && 3875 if((flags & GAIM_CONV_IM_IMAGES) &&
3342 mwConversation_supports(conv, mwImSend_MIME)) { 3876 mwConversation_supports(conv, mwImSend_MIME)) {
3343 3877 /* send a MIME message */
3344 msg = im_mime_convert(message); 3878
3345 ret = mwConversation_send(conv, mwImSend_MIME, msg); 3879 tmp = im_mime_convert(msg);
3880 g_free(msg);
3881
3882 ret = mwConversation_send(conv, mwImSend_MIME, tmp);
3883 g_free(tmp);
3346 3884
3347 } else if(mwConversation_supports(conv, mwImSend_HTML)) { 3885 } else if(mwConversation_supports(conv, mwImSend_HTML)) {
3886 /* send an HTML message */
3348 3887
3349 /* need to do this to get the \n to <br> conversion */ 3888 /* need to do this to get the \n to <br> conversion */
3350 msg = gaim_strdup_withhtml(message); 3889 tmp = gaim_strdup_withhtml(msg);
3351 ret = mwConversation_send(conv, mwImSend_HTML, msg); 3890 g_free(msg);
3891
3892 ret = mwConversation_send(conv, mwImSend_HTML, tmp);
3893 g_free(tmp);
3352 3894
3353 } else { 3895 } else {
3354 ret = mwConversation_send(conv, mwImSend_PLAIN, message); 3896 /* default to text */
3897 ret = mwConversation_send(conv, mwImSend_PLAIN, msg);
3898 g_free(msg);
3355 } 3899 }
3356 3900
3901 return !ret;
3902
3903 } else {
3904
3905 /* queue up the message safely as plain text */
3906 char *tmp = gaim_markup_strip_html(msg);
3357 g_free(msg); 3907 g_free(msg);
3358 return !ret; 3908
3359 3909 convo_queue(conv, mwImSend_PLAIN, tmp);
3360 } else { 3910 g_free(tmp);
3361 char *msg;
3362
3363 /* queue up the message safely as plain text */
3364 msg = gaim_markup_strip_html(message);
3365 convo_queue(conv, mwImSend_PLAIN, msg);
3366 g_free(msg);
3367 3911
3368 if(! mwConversation_isPending(conv)) 3912 if(! mwConversation_isPending(conv))
3369 mwConversation_open(conv); 3913 mwConversation_open(conv);
3370 3914
3371 return 1; 3915 return 1;
3408 } 3952 }
3409 3953
3410 3954
3411 static void mw_prpl_get_info(GaimConnection *gc, const char *who) { 3955 static void mw_prpl_get_info(GaimConnection *gc, const char *who) {
3412 3956
3957 struct mwAwareIdBlock idb = { mwAware_USER, (char *) who, NULL };
3958
3413 struct mwGaimPluginData *pd; 3959 struct mwGaimPluginData *pd;
3414 struct mwAwareIdBlock idb = { mwAware_USER, (char *) who, NULL };
3415
3416 GaimAccount *acct; 3960 GaimAccount *acct;
3417 GaimBuddy *b; 3961 GaimBuddy *b;
3418 3962
3419 GString *str; 3963 GString *str;
3420 const char *tmp; 3964 const char *tmp;
3421 guint32 type; 3965
3966 g_return_if_fail(who != NULL);
3967 g_return_if_fail(*who != '\0');
3422 3968
3423 pd = gc->proto_data; 3969 pd = gc->proto_data;
3424 3970
3425 acct = gaim_connection_get_account(gc); 3971 acct = gaim_connection_get_account(gc);
3426 b = gaim_find_buddy(acct, who); 3972 b = gaim_find_buddy(acct, who);
3427 3973
3428 g_return_if_fail(b != NULL);
3429
3430 str = g_string_new(NULL); 3974 str = g_string_new(NULL);
3431 3975
3432 g_string_append_printf(str, "<b>User ID:</b> %s<br>", b->name); 3976 if(g_str_has_prefix(who, "@E ")) {
3433 3977 g_string_append(str, _("<b>External User</b><br>"));
3434 if(b->server_alias) { 3978 }
3435 g_string_append_printf(str, "<b>Full Name:</b> %s<br>", 3979
3436 b->server_alias); 3980 g_string_append_printf(str, _("<b>User ID:</b> %s<br>"), who);
3437 } 3981
3438 3982 if(b) {
3439 type = gaim_blist_node_get_int((GaimBlistNode *) b, BUDDY_KEY_CLIENT); 3983 guint32 type;
3440 if(type) { 3984
3441 g_string_append(str, "<b>Last Known Client:</b> "); 3985 if(b->server_alias) {
3442 3986 g_string_append_printf(str, _("<b>Full Name:</b> %s<br>"),
3443 tmp = mwLoginType_getName(type); 3987 b->server_alias);
3444 if(tmp) { 3988 }
3445 g_string_append(str, tmp); 3989
3446 g_string_append(str, "<br>"); 3990 type = gaim_blist_node_get_int((GaimBlistNode *) b, BUDDY_KEY_CLIENT);
3447 3991 if(type) {
3448 } else { 3992 g_string_append(str, _("<b>Last Known Client:</b> "));
3449 g_string_append_printf(str, "Unknown (0x%04x)<br>", type); 3993
3994 tmp = mwLoginType_getName(type);
3995 if(tmp) {
3996 g_string_append(str, tmp);
3997 g_string_append(str, "<br>");
3998
3999 } else {
4000 g_string_append_printf(str, _("Unknown (0x%04x)<br>"), type);
4001 }
3450 } 4002 }
3451 } 4003 }
3452 4004
3453 tmp = user_supports_text(pd->srvc_aware, who); 4005 tmp = user_supports_text(pd->srvc_aware, who);
3454 if(tmp) { 4006 if(tmp) {
3455 g_string_append_printf(str, "<b>Supports:</b> %s<br>", tmp); 4007 g_string_append_printf(str, _("<b>Supports:</b> %s<br>"), tmp);
3456 g_free((char *) tmp); 4008 g_free((char *) tmp);
3457 } 4009 }
3458 4010
3459 tmp = status_text(b); 4011 if(b) {
3460 g_string_append_printf(str, "<b>Status:</b> %s", tmp); 4012 tmp = status_text(b);
3461 4013 g_string_append_printf(str, _("<b>Status:</b> %s"), tmp);
3462 g_string_append(str, "<hr>"); 4014
3463 4015 g_string_append(str, "<hr>");
3464 tmp = mwServiceAware_getText(pd->srvc_aware, &idb); 4016
3465 g_string_append(str, tmp); 4017 tmp = mwServiceAware_getText(pd->srvc_aware, &idb);
4018 if(tmp) g_string_append(str, tmp);
4019 }
3466 4020
3467 /* @todo emit a signal to allow a plugin to override the display of 4021 /* @todo emit a signal to allow a plugin to override the display of
3468 this notification, so that it can create its own */ 4022 this notification, so that it can create its own */
3469 4023
3470 gaim_notify_userinfo(gc, who, str->str, NULL, NULL); 4024 gaim_notify_userinfo(gc, who, str->str, NULL, NULL);
3471 4025
3472 g_string_free(str, TRUE); 4026 g_string_free(str, TRUE);
3473 } 4027 }
3474 4028
3475 4029
3476 static void mw_prpl_set_status(GaimAccount *acct, GaimStatus *status) { 4030 static void mw_prpl_set_status(GaimAccount *acct, GaimStatus *status) {
3477 GaimConnection *gc; 4031 GaimConnection *gc;
3478 const char *state; 4032 const char *state;
3479 char *message = NULL; 4033 char *message = NULL;
3480 struct mwSession *session; 4034 struct mwSession *session;
3481 struct mwUserStatus stat; 4035 struct mwUserStatus stat;
3482 4036
3483 g_return_if_fail(acct != NULL); 4037 g_return_if_fail(acct != NULL);
3484 gc = gaim_account_get_connection(acct); 4038 gc = gaim_account_get_connection(acct);
3485 4039
3486 state = gaim_status_get_id(status); 4040 state = gaim_status_get_id(status);
3487 4041
3488 gaim_debug_info("meanwhile", "Set status to %s\n", gaim_status_get_name(status)); 4042 gaim_debug_info("meanwhile", "Set status to %s\n",
3489 4043 gaim_status_get_name(status));
4044
3490 g_return_if_fail(gc != NULL); 4045 g_return_if_fail(gc != NULL);
3491 4046
3492 session = gc_to_session(gc); 4047 session = gc_to_session(gc);
3493 g_return_if_fail(session != NULL); 4048 g_return_if_fail(session != NULL);
3494 4049
3495 /* get a working copy of the current status */ 4050 /* get a working copy of the current status */
3496 mwUserStatus_clone(&stat, mwSession_getUserStatus(session)); 4051 mwUserStatus_clone(&stat, mwSession_getUserStatus(session));
3497 4052
3498 /* determine the state */ 4053 /* determine the state */
3499 if(! strcmp(state, MW_STATE_ACTIVE)) { 4054 if(! strcmp(state, MW_STATE_ACTIVE)) {
3500 stat.status = mwStatus_ACTIVE; 4055 stat.status = mwStatus_ACTIVE;
3501 4056
3502 } else if(! strcmp(state, MW_STATE_AWAY)) { 4057 } else if(! strcmp(state, MW_STATE_AWAY)) {
3503 stat.status = mwStatus_AWAY; 4058 stat.status = mwStatus_AWAY;
3504 4059
3505 } else if(! strcmp(state, MW_STATE_BUSY)) { 4060 } else if(! strcmp(state, MW_STATE_BUSY)) {
3506 stat.status = mwStatus_BUSY; 4061 stat.status = mwStatus_BUSY;
3507 } 4062 }
3508 4063
3509 /* determine the message */ 4064 /* determine the message */
3510 switch(stat.status) { 4065 switch(stat.status) {
3511 case mwStatus_ACTIVE: 4066 case mwStatus_ACTIVE:
3512 stat.time = 0; 4067 stat.time = 0;
3513 case mwStatus_AWAY: 4068 case mwStatus_AWAY:
3514 case mwStatus_BUSY: 4069 case mwStatus_BUSY:
3515 message = (char *)gaim_status_get_attr_string(status, MW_STATE_MESSAGE); 4070 message = (char *)gaim_status_get_attr_string(status, MW_STATE_MESSAGE);
3516 break; 4071 break;
3517 } 4072 }
3518 4073
3519 if(message) { 4074 if(message) {
3520 /* all the possible non-NULL values of message up to this point 4075 /* all the possible non-NULL values of message up to this point
3521 are const, so we don't need to free them */ 4076 are const, so we don't need to free them */
3522 message = gaim_markup_strip_html(message); 4077 message = gaim_markup_strip_html(message);
3523 } 4078 }
3524 4079
3525 /* out with the old */ 4080 /* out with the old */
3526 g_free(stat.desc); 4081 g_free(stat.desc);
3527 4082
3528 /* in with the new */ 4083 /* in with the new */
3529 stat.desc = (char *) message; 4084 stat.desc = (char *) message;
3530 4085
3531 mwSession_setUserStatus(session, &stat); 4086 mwSession_setUserStatus(session, &stat);
3532 mwUserStatus_clear(&stat); 4087 mwUserStatus_clear(&stat);
3533 } 4088 }
3534 4089
3535 4090
3536 static void mw_prpl_set_idle(GaimConnection *gc, int time) { 4091 static void mw_prpl_set_idle(GaimConnection *gc, int t) {
3537 struct mwSession *session; 4092 struct mwSession *session;
3538 struct mwUserStatus stat; 4093 struct mwUserStatus stat;
3539 4094
3540 session = gc_to_session(gc); 4095 session = gc_to_session(gc);
3541 g_return_if_fail(session != NULL); 4096 g_return_if_fail(session != NULL);
3542 4097
3543 mwUserStatus_clone(&stat, mwSession_getUserStatus(session)); 4098 mwUserStatus_clone(&stat, mwSession_getUserStatus(session));
3544 4099
3545 if(time > 0 && stat.status == mwStatus_ACTIVE) { 4100 if(t > 0 && stat.status == mwStatus_ACTIVE) {
4101 time_t now = time(NULL);
4102 stat.time = now - t;
3546 stat.status = mwStatus_IDLE; 4103 stat.status = mwStatus_IDLE;
3547 4104
3548 } else if(time == 0 && stat.status == mwStatus_IDLE) { 4105 } else if(t == 0 && stat.status == mwStatus_IDLE) {
4106 stat.time = 0;
3549 stat.status = mwStatus_ACTIVE; 4107 stat.status = mwStatus_ACTIVE;
3550 } 4108 }
3551 4109
3552 /** @todo actually put the idle time in the user status */
3553
3554 mwSession_setUserStatus(session, &stat); 4110 mwSession_setUserStatus(session, &stat);
3555 mwUserStatus_clear(&stat); 4111 mwUserStatus_clear(&stat);
4112 }
4113
4114
4115 static struct resolved_id *resolved_id_new(const char *id,
4116 const char *name) {
4117
4118 struct resolved_id *rid = g_new0(struct resolved_id, 1);
4119 rid->id = g_strdup(id);
4120 rid->name = g_strdup(name);
4121 return rid;
4122 }
4123
4124
4125 static void resolved_id_free(struct resolved_id *rid) {
4126 if(rid) {
4127 g_free(rid->id);
4128 g_free(rid->name);
4129 g_free(rid);
4130 }
3556 } 4131 }
3557 4132
3558 4133
3559 static void add_resolved_done(const char *id, const char *name, 4134 static void add_resolved_done(const char *id, const char *name,
3560 GaimBuddy *buddy) { 4135 GaimBuddy *buddy) {
3581 buddy_add(pd, buddy); 4156 buddy_add(pd, buddy);
3582 } 4157 }
3583 4158
3584 4159
3585 static void multi_resolved_cleanup(GaimRequestFields *fields) { 4160 static void multi_resolved_cleanup(GaimRequestFields *fields) {
3586
3587 GaimRequestField *f; 4161 GaimRequestField *f;
3588 const GList *l; 4162 const GList *l;
3589 4163
3590 f = gaim_request_fields_get_field(fields, "user"); 4164 f = gaim_request_fields_get_field(fields, "user");
3591 l = gaim_request_field_list_get_items(f); 4165 l = gaim_request_field_list_get_items(f);
3593 for(; l; l = l->next) { 4167 for(; l; l = l->next) {
3594 const char *i = l->data; 4168 const char *i = l->data;
3595 struct resolved_id *res; 4169 struct resolved_id *res;
3596 4170
3597 res = gaim_request_field_list_get_data(f, i); 4171 res = gaim_request_field_list_get_data(f, i);
3598 4172 resolved_id_free(res);
3599 g_free(res->id);
3600 g_free(res->name);
3601 g_free(res);
3602 } 4173 }
3603 } 4174 }
3604 4175
3605 4176
3606 static void multi_resolved_cancel(GaimBuddy *buddy, 4177 static void multi_resolved_cancel(GaimBuddy *buddy,
3636 multi_resolved_cleanup(fields); 4207 multi_resolved_cleanup(fields);
3637 4208
3638 } else { 4209 } else {
3639 multi_resolved_cancel(buddy, fields); 4210 multi_resolved_cancel(buddy, fields);
3640 } 4211 }
4212 }
4213
4214
4215 static void foreach_resolved_id(char *key, char *val, GList **l) {
4216 struct resolved_id *res = resolved_id_new(key, val);
4217 *l = g_list_prepend(*l, res);
4218 }
4219
4220
4221 static gint resolved_id_comp(struct resolved_id *a, struct resolved_id *b) {
4222 return g_ascii_strcasecmp(a->name, b->name);
3641 } 4223 }
3642 4224
3643 4225
3644 static void multi_resolved_query(struct mwResolveResult *result, 4226 static void multi_resolved_query(struct mwResolveResult *result,
3645 GaimBuddy *buddy) { 4227 GaimBuddy *buddy) {
3646 GaimRequestFields *fields; 4228 GaimRequestFields *fields;
3647 GaimRequestFieldGroup *g; 4229 GaimRequestFieldGroup *g;
3648 GaimRequestField *f; 4230 GaimRequestField *f;
4231 GHashTable *hash;
3649 GList *l; 4232 GList *l;
3650 char *msgA, *msgB; 4233 char *msgA, *msgB;
3651 4234
3652 GaimAccount *acct; 4235 GaimAccount *acct;
3653 GaimConnection *gc; 4236 GaimConnection *gc;
3666 4249
3667 /* note that Gaim segfaults if you don't add the group to the fields 4250 /* note that Gaim segfaults if you don't add the group to the fields
3668 before you add a required field to the group. Feh. */ 4251 before you add a required field to the group. Feh. */
3669 gaim_request_fields_add_group(fields, g); 4252 gaim_request_fields_add_group(fields, g);
3670 4253
3671 f = gaim_request_field_list_new("user", "Possible Matches"); 4254 f = gaim_request_field_list_new("user", _("Possible Matches"));
3672 gaim_request_field_list_set_multi_select(f, FALSE); 4255 gaim_request_field_list_set_multi_select(f, FALSE);
3673 gaim_request_field_set_required(f, TRUE); 4256 gaim_request_field_set_required(f, TRUE);
3674 4257
4258 /* collect results into a set of identities */
4259 hash = g_hash_table_new(g_str_hash, g_str_equal);
3675 for(l = result->matches; l; l = l->next) { 4260 for(l = result->matches; l; l = l->next) {
3676 struct mwResolveMatch *match = l->data; 4261 struct mwResolveMatch *match = l->data;
3677 struct resolved_id *res = g_new0(struct resolved_id, 1); 4262
4263 if(!match->id || !match->name)
4264 continue;
4265
4266 g_hash_table_insert(hash, match->id, match->name);
4267 }
4268
4269 /* collect set into a list of structures */
4270 l = NULL;
4271 g_hash_table_foreach(hash, (GHFunc) foreach_resolved_id, &l);
4272 g_list_sort(l, (GCompareFunc) resolved_id_comp);
4273
4274 /* populate choices in request field */
4275 for(; l; l = l->next) {
4276 struct resolved_id *res = l->data;
3678 char *label; 4277 char *label;
3679 4278
3680 res->id = g_strdup(match->id);
3681 res->name = g_strdup(match->name);
3682
3683 /* fixes bug 1178603 by making the selection label a combination 4279 /* fixes bug 1178603 by making the selection label a combination
3684 of the full name and the user id. Problems arrise when multiple 4280 of the full name and the user id. Problems arrise when multiple
3685 entries have identical labels */ 4281 entries have identical labels */
3686 label = g_strdup_printf("%s (%s)", NSTR(res->name), NSTR(res->id)); 4282 label = g_strdup_printf("%s (%s)", NSTR(res->name), NSTR(res->id));
3687 gaim_request_field_list_add(f, label, res); 4283 gaim_request_field_list_add(f, label, res);
3688 g_free(label); 4284 g_free(label);
3689 } 4285 }
3690 4286
4287 g_list_free(l);
4288
3691 gaim_request_field_group_add_field(g, f); 4289 gaim_request_field_group_add_field(g, f);
3692 4290
3693 msgA = ("An ambiguous user ID was entered"); 4291 msgA = _("An ambiguous user ID was entered");
3694 msgB = ("The identifier '%s' may possibly refer to any of the following" 4292 msgB = _("The identifier '%s' may possibly refer to any of the following"
3695 " users. Please select the correct user from the list below to" 4293 " users. Please select the correct user from the list below to"
3696 " add them to your buddy list."); 4294 " add them to your buddy list.");
3697 msgB = g_strdup_printf(msgB, result->name); 4295 msgB = g_strdup_printf(msgB, result->name);
3698 4296
3699 gaim_request_fields(gc, "Select User to Add", 4297 gaim_request_fields(gc, _("Select User to Add"),
3700 msgA, msgB, fields, 4298 msgA, msgB, fields,
3701 "Add User", G_CALLBACK(multi_resolved_cb), 4299 _("Add User"), G_CALLBACK(multi_resolved_cb),
3702 "Cancel", G_CALLBACK(multi_resolved_cancel), 4300 _("Cancel"), G_CALLBACK(multi_resolved_cancel),
3703 buddy); 4301 buddy);
3704 g_free(msgB); 4302 g_free(msgB);
3705 } 4303 }
3706 4304
3707 4305
3757 4355
3758 if(res && res->name) { 4356 if(res && res->name) {
3759 /* compose and display an error message */ 4357 /* compose and display an error message */
3760 char *msgA, *msgB; 4358 char *msgA, *msgB;
3761 4359
3762 msgA = "Unable to add user: user not found"; 4360 msgA = _("Unable to add user: user not found");
3763 4361
3764 msgB = ("The identifier '%s' did not match any users in your" 4362 msgB = _("The identifier '%s' did not match any users in your"
3765 " Sametime community. This entry has been removed from" 4363 " Sametime community. This entry has been removed from"
3766 " your buddy list."); 4364 " your buddy list.");
3767 msgB = g_strdup_printf(msgB, NSTR(res->name)); 4365 msgB = g_strdup_printf(msgB, NSTR(res->name));
3768 4366
3769 gaim_notify_error(gc, "Unable to add user", msgA, msgB); 4367 gaim_notify_error(gc, _("Unable to add user"), msgA, msgB);
3770 4368
3771 g_free(msgB); 4369 g_free(msgB);
3772 } 4370 }
3773 } 4371 }
3774 4372
3784 guint32 req; 4382 guint32 req;
3785 4383
3786 pd = gc->proto_data; 4384 pd = gc->proto_data;
3787 srvc = pd->srvc_resolve; 4385 srvc = pd->srvc_resolve;
3788 4386
4387 /* catch external buddies. They won't be in the resolve service */
4388 if(g_str_has_prefix(buddy->name, "@E ")) {
4389 buddy_add(pd, buddy);
4390 return;
4391 }
4392
3789 query = g_list_prepend(NULL, buddy->name); 4393 query = g_list_prepend(NULL, buddy->name);
3790 flags = mwResolveFlag_FIRST | mwResolveFlag_USERS; 4394 flags = mwResolveFlag_FIRST | mwResolveFlag_USERS;
3791 4395
3792 req = mwServiceResolve_resolve(srvc, query, flags, add_buddy_resolved, 4396 req = mwServiceResolve_resolve(srvc, query, flags, add_buddy_resolved,
3793 buddy, NULL); 4397 buddy, NULL);
3800 } 4404 }
3801 4405
3802 4406
3803 static void foreach_add_buddies(GaimGroup *group, GList *buddies, 4407 static void foreach_add_buddies(GaimGroup *group, GList *buddies,
3804 struct mwGaimPluginData *pd) { 4408 struct mwGaimPluginData *pd) {
3805
3806 struct mwAwareList *list; 4409 struct mwAwareList *list;
3807 4410
3808 list = list_ensure(pd, group); 4411 list = list_ensure(pd, group);
3809 mwAwareList_addAware(list, buddies); 4412 mwAwareList_addAware(list, buddies);
3810 g_list_free(buddies); 4413 g_list_free(buddies);
3997 4600
3998 static void mw_prpl_join_chat(GaimConnection *gc, 4601 static void mw_prpl_join_chat(GaimConnection *gc,
3999 GHashTable *components) { 4602 GHashTable *components) {
4000 4603
4001 struct mwGaimPluginData *pd; 4604 struct mwGaimPluginData *pd;
4002 struct mwServiceConference *srvc;
4003 struct mwConference *conf = NULL;
4004 char *c, *t; 4605 char *c, *t;
4005 4606
4006 pd = gc->proto_data; 4607 pd = gc->proto_data;
4007 srvc = pd->srvc_conf;
4008 4608
4009 c = g_hash_table_lookup(components, CHAT_KEY_NAME); 4609 c = g_hash_table_lookup(components, CHAT_KEY_NAME);
4010 t = g_hash_table_lookup(components, CHAT_KEY_TOPIC); 4610 t = g_hash_table_lookup(components, CHAT_KEY_TOPIC);
4011 4611
4012 if(c) conf = conf_find(srvc, c); 4612 if(g_hash_table_lookup(components, CHAT_KEY_IS_PLACE)) {
4013 4613 /* use place service */
4014 if(conf) { 4614 struct mwServicePlace *srvc;
4015 DEBUG_INFO("accepting conference invitation\n"); 4615 struct mwPlace *place = NULL;
4016 mwConference_accept(conf); 4616
4017 4617 srvc = pd->srvc_place;
4618 place = mwPlace_new(srvc, c, t);
4619 mwPlace_open(place);
4620
4018 } else { 4621 } else {
4019 DEBUG_INFO("creating new conference\n"); 4622 /* use conference service */
4020 conf = mwConference_new(srvc, t); 4623 struct mwServiceConference *srvc;
4021 mwConference_open(conf); 4624 struct mwConference *conf = NULL;
4625
4626 srvc = pd->srvc_conf;
4627 if(c) conf = conf_find(srvc, c);
4628
4629 if(conf) {
4630 DEBUG_INFO("accepting conference invitation\n");
4631 mwConference_accept(conf);
4632
4633 } else {
4634 DEBUG_INFO("creating new conference\n");
4635 conf = mwConference_new(srvc, t);
4636 mwConference_open(conf);
4637 }
4022 } 4638 }
4023 } 4639 }
4024 4640
4025 4641
4026 static void mw_prpl_reject_chat(GaimConnection *gc, 4642 static void mw_prpl_reject_chat(GaimConnection *gc,
4031 char *c; 4647 char *c;
4032 4648
4033 pd = gc->proto_data; 4649 pd = gc->proto_data;
4034 srvc = pd->srvc_conf; 4650 srvc = pd->srvc_conf;
4035 4651
4036 c = g_hash_table_lookup(components, CHAT_KEY_NAME); 4652 if(g_hash_table_lookup(components, CHAT_KEY_IS_PLACE)) {
4037 if(c) { 4653 ; /* nothing needs doing */
4038 struct mwConference *conf = conf_find(srvc, c); 4654
4039 if(conf) mwConference_reject(conf, ERR_SUCCESS, "Declined"); 4655 } else {
4656 /* reject conference */
4657 c = g_hash_table_lookup(components, CHAT_KEY_NAME);
4658 if(c) {
4659 struct mwConference *conf = conf_find(srvc, c);
4660 if(conf) mwConference_reject(conf, ERR_SUCCESS, "Declined");
4661 }
4040 } 4662 }
4041 } 4663 }
4042 4664
4043 4665
4044 static char *mw_prpl_get_chat_name(GHashTable *components) { 4666 static char *mw_prpl_get_chat_name(GHashTable *components) {
4061 conf = ID_TO_CONF(pd, id); 4683 conf = ID_TO_CONF(pd, id);
4062 4684
4063 g_return_if_fail(conf != NULL); 4685 g_return_if_fail(conf != NULL);
4064 4686
4065 mwConference_invite(conf, &idb, invitation); 4687 mwConference_invite(conf, &idb, invitation);
4688
4689 /* @todo: use Place by default instead */
4066 } 4690 }
4067 4691
4068 4692
4069 static void mw_prpl_chat_leave(GaimConnection *gc, 4693 static void mw_prpl_chat_leave(GaimConnection *gc,
4070 int id) { 4694 int id) {
4075 pd = gc->proto_data; 4699 pd = gc->proto_data;
4076 4700
4077 g_return_if_fail(pd != NULL); 4701 g_return_if_fail(pd != NULL);
4078 conf = ID_TO_CONF(pd, id); 4702 conf = ID_TO_CONF(pd, id);
4079 4703
4080 g_return_if_fail(conf != NULL); 4704 if(conf) {
4081 4705 mwConference_destroy(conf, ERR_SUCCESS, "Leaving");
4082 mwConference_destroy(conf, ERR_SUCCESS, "Leaving"); 4706
4707 } else {
4708 struct mwPlace *place = ID_TO_PLACE(pd, id);
4709 g_return_if_fail(place != NULL);
4710
4711 mwPlace_destroy(place, ERR_SUCCESS);
4712 }
4083 } 4713 }
4084 4714
4085 4715
4086 static void mw_prpl_chat_whisper(GaimConnection *gc, 4716 static void mw_prpl_chat_whisper(GaimConnection *gc,
4087 int id, 4717 int id,
4102 pd = gc->proto_data; 4732 pd = gc->proto_data;
4103 4733
4104 g_return_val_if_fail(pd != NULL, 0); 4734 g_return_val_if_fail(pd != NULL, 0);
4105 conf = ID_TO_CONF(pd, id); 4735 conf = ID_TO_CONF(pd, id);
4106 4736
4107 g_return_val_if_fail(conf != NULL, 0); 4737 if(conf) {
4108 4738 return ! mwConference_sendText(conf, message);
4109 return ! mwConference_sendText(conf, message); 4739
4740 } else {
4741 struct mwPlace *place = ID_TO_PLACE(pd, id);
4742 g_return_val_if_fail(place != NULL, 0);
4743
4744 return ! mwPlace_sendText(place, message);
4745 }
4110 } 4746 }
4111 4747
4112 4748
4113 static void mw_prpl_keepalive(GaimConnection *gc) { 4749 static void mw_prpl_keepalive(GaimConnection *gc) {
4114 struct mwSession *session; 4750 struct mwSession *session;
4289 idb.user = xfer->who; 4925 idb.user = xfer->who;
4290 4926
4291 /* test that we can actually send the file */ 4927 /* test that we can actually send the file */
4292 fp = g_fopen(filename, "rb"); 4928 fp = g_fopen(filename, "rb");
4293 if(! fp) { 4929 if(! fp) {
4294 char *msg = g_strdup_printf("Error reading %s: \n%s\n", 4930 char *msg = g_strdup_printf(_("Error reading file %s: \n%s\n"),
4295 filename, strerror(errno)); 4931 filename, strerror(errno));
4296 gaim_xfer_error(gaim_xfer_get_type(xfer), acct, xfer->who, msg); 4932 gaim_xfer_error(gaim_xfer_get_type(xfer), acct, xfer->who, msg);
4297 g_free(msg); 4933 g_free(msg);
4298 return; 4934 return;
4299 } 4935 }
4323 static void mw_prpl_send_file(GaimConnection *gc, 4959 static void mw_prpl_send_file(GaimConnection *gc,
4324 const char *who, const char *file) { 4960 const char *who, const char *file) {
4325 4961
4326 GaimAccount *acct; 4962 GaimAccount *acct;
4327 GaimXfer *xfer; 4963 GaimXfer *xfer;
4328
4329 DEBUG_INFO("mw_prpl_send_file\n");
4330 4964
4331 acct = gaim_connection_get_account(gc); 4965 acct = gaim_connection_get_account(gc);
4332 4966
4333 xfer = gaim_xfer_new(acct, GAIM_XFER_SEND, who); 4967 xfer = gaim_xfer_new(acct, GAIM_XFER_SEND, who);
4334 gaim_xfer_set_init_fnc(xfer, ft_outgoing_init); 4968 gaim_xfer_set_init_fnc(xfer, ft_outgoing_init);
4407 5041
4408 static GaimPluginPrefFrame * 5042 static GaimPluginPrefFrame *
4409 mw_plugin_get_plugin_pref_frame(GaimPlugin *plugin) { 5043 mw_plugin_get_plugin_pref_frame(GaimPlugin *plugin) {
4410 GaimPluginPrefFrame *frame; 5044 GaimPluginPrefFrame *frame;
4411 GaimPluginPref *pref; 5045 GaimPluginPref *pref;
4412 5046
4413 frame = gaim_plugin_pref_frame_new(); 5047 frame = gaim_plugin_pref_frame_new();
4414 5048
4415 pref = gaim_plugin_pref_new_with_label("Remotely Stored Buddy List"); 5049 pref = gaim_plugin_pref_new_with_label(_("Remotely Stored Buddy List"));
4416 gaim_plugin_pref_frame_add(frame, pref); 5050 gaim_plugin_pref_frame_add(frame, pref);
4417 5051
4418 5052
4419 pref = gaim_plugin_pref_new_with_name(MW_PRPL_OPT_BLIST_ACTION); 5053 pref = gaim_plugin_pref_new_with_name(MW_PRPL_OPT_BLIST_ACTION);
4420 gaim_plugin_pref_set_label(pref, "Buddy List Storage Mode"); 5054 gaim_plugin_pref_set_label(pref, _("Buddy List Storage Mode"));
4421 5055
4422 gaim_plugin_pref_set_type(pref, GAIM_PLUGIN_PREF_CHOICE); 5056 gaim_plugin_pref_set_type(pref, GAIM_PLUGIN_PREF_CHOICE);
4423 gaim_plugin_pref_add_choice(pref, "Local Buddy List Only", 5057 gaim_plugin_pref_add_choice(pref, _("Local Buddy List Only"),
4424 GINT_TO_POINTER(BLIST_CHOICE_NONE)); 5058 GINT_TO_POINTER(blist_choice_LOCAL));
4425 gaim_plugin_pref_add_choice(pref, "Merge List from Server", 5059 gaim_plugin_pref_add_choice(pref, _("Merge List from Server"),
4426 GINT_TO_POINTER(BLIST_CHOICE_LOAD)); 5060 GINT_TO_POINTER(blist_choice_MERGE));
4427 gaim_plugin_pref_add_choice(pref, "Merge and Save List to Server", 5061 gaim_plugin_pref_add_choice(pref, _("Merge and Save List to Server"),
4428 GINT_TO_POINTER(BLIST_CHOICE_SAVE)); 5062 GINT_TO_POINTER(blist_choice_STORE));
4429 5063 gaim_plugin_pref_add_choice(pref, _("Synchronize List with Server"),
4430 #if 0 5064 GINT_TO_POINTER(blist_choice_SYNCH));
4431 /* possible ways to handle: 5065
4432 - mark all buddies as NO_SAVE
4433 - load server list, delete all local buddies not in server list
4434 */
4435 gaim_plugin_pref_add_choice(pref, "Server Buddy List Only",
4436 GINT_TO_POINTER(BLIST_CHOISE_SERVER));
4437 #endif
4438
4439 gaim_plugin_pref_frame_add(frame, pref);
4440
4441 pref = gaim_plugin_pref_new_with_label("General Options");
4442 gaim_plugin_pref_frame_add(frame, pref);
4443
4444 pref = gaim_plugin_pref_new_with_name(MW_PRPL_OPT_FORCE_LOGIN);
4445 gaim_plugin_pref_set_type(pref, GAIM_PLUGIN_PREF_NONE);
4446 gaim_plugin_pref_set_label(pref, "Force Login (Ignore Login Redirects)");
4447 gaim_plugin_pref_frame_add(frame, pref);
4448
4449 pref = gaim_plugin_pref_new_with_name(MW_PRPL_OPT_PSYCHIC);
4450 gaim_plugin_pref_set_type(pref, GAIM_PLUGIN_PREF_NONE);
4451 gaim_plugin_pref_set_label(pref, "Enable Psychic Mode");
4452 gaim_plugin_pref_frame_add(frame, pref);
4453
4454 pref = gaim_plugin_pref_new_with_name(MW_PRPL_OPT_SAVE_DYNAMIC);
4455 gaim_plugin_pref_set_type(pref, GAIM_PLUGIN_PREF_NONE);
4456 gaim_plugin_pref_set_label(pref, "Save NAB group members locally");
4457 gaim_plugin_pref_frame_add(frame, pref); 5066 gaim_plugin_pref_frame_add(frame, pref);
4458 5067
4459 return frame; 5068 return frame;
4460 } 5069 }
4461 5070
4468 static void status_msg_action_cb(GaimConnection *gc, 5077 static void status_msg_action_cb(GaimConnection *gc,
4469 GaimRequestFields *fields) { 5078 GaimRequestFields *fields) {
4470 GaimAccount *acct; 5079 GaimAccount *acct;
4471 GaimRequestField *f; 5080 GaimRequestField *f;
4472 const char *msg; 5081 const char *msg;
4473 /* gboolean prompt; */
4474 5082
4475 struct mwGaimPluginData *pd; 5083 struct mwGaimPluginData *pd;
4476 struct mwServiceStorage *srvc; 5084 struct mwServiceStorage *srvc;
4477 struct mwStorageUnit *unit; 5085 struct mwStorageUnit *unit;
4478 5086
4496 f = gaim_request_fields_get_field(fields, "busy"); 5104 f = gaim_request_fields_get_field(fields, "busy");
4497 msg = gaim_request_field_string_get_value(f); 5105 msg = gaim_request_field_string_get_value(f);
4498 gaim_account_set_string(acct, MW_KEY_BUSY_MSG, msg); 5106 gaim_account_set_string(acct, MW_KEY_BUSY_MSG, msg);
4499 unit = mwStorageUnit_newString(mwStore_BUSY_MESSAGES, msg); 5107 unit = mwStorageUnit_newString(mwStore_BUSY_MESSAGES, msg);
4500 mwServiceStorage_save(srvc, unit, NULL, NULL, NULL); 5108 mwServiceStorage_save(srvc, unit, NULL, NULL, NULL);
4501
4502 #if 0
4503 /** @todo not yet used. It should be possible to prompt the user for
4504 a message (ala the Sametime Connect client) when changing to one
4505 of the default states, and that preference is here */
4506 f = gaim_request_fields_get_field(fields, "prompt");
4507 prompt = gaim_request_field_bool_get_value(f);
4508 gaim_account_set_bool(acct, MW_KEY_MSG_PROMPT, prompt);
4509 #endif
4510 5109
4511 #if 0 5110 #if 0
4512 /* XXX */ 5111 /* XXX */
4513 /* need to propagate the message change if we're in any of those 5112 /* need to propagate the message change if we're in any of those
4514 default states */ 5113 default states */
4536 GaimRequestFieldGroup *g; 5135 GaimRequestFieldGroup *g;
4537 GaimRequestField *f; 5136 GaimRequestField *f;
4538 5137
4539 char *msgA, *msgB; 5138 char *msgA, *msgB;
4540 const char *val; 5139 const char *val;
4541 /* gboolean prompt; */
4542 5140
4543 gc = act->context; 5141 gc = act->context;
4544 acct = gaim_connection_get_account(gc); 5142 acct = gaim_connection_get_account(gc);
4545 5143
4546 fields = gaim_request_fields_new(); 5144 fields = gaim_request_fields_new();
4548 g = gaim_request_field_group_new(NULL); 5146 g = gaim_request_field_group_new(NULL);
4549 gaim_request_fields_add_group(fields, g); 5147 gaim_request_fields_add_group(fields, g);
4550 5148
4551 val = gaim_account_get_string(acct, MW_KEY_ACTIVE_MSG, 5149 val = gaim_account_get_string(acct, MW_KEY_ACTIVE_MSG,
4552 MW_PLUGIN_DEFAULT_ACTIVE_MSG); 5150 MW_PLUGIN_DEFAULT_ACTIVE_MSG);
4553 f = gaim_request_field_string_new("active", "Active Message", val, FALSE); 5151 f = gaim_request_field_string_new("active", _("Active Message"), val, FALSE);
4554 gaim_request_field_set_required(f, FALSE); 5152 gaim_request_field_set_required(f, FALSE);
4555 gaim_request_field_group_add_field(g, f); 5153 gaim_request_field_group_add_field(g, f);
4556 5154
4557 val = gaim_account_get_string(acct, MW_KEY_AWAY_MSG, 5155 val = gaim_account_get_string(acct, MW_KEY_AWAY_MSG,
4558 MW_PLUGIN_DEFAULT_AWAY_MSG); 5156 MW_PLUGIN_DEFAULT_AWAY_MSG);
4559 f = gaim_request_field_string_new("away", "Away Message", val, FALSE); 5157 f = gaim_request_field_string_new("away", _("Away Message"), val, FALSE);
4560 gaim_request_field_set_required(f, FALSE); 5158 gaim_request_field_set_required(f, FALSE);
4561 gaim_request_field_group_add_field(g, f); 5159 gaim_request_field_group_add_field(g, f);
4562 5160
4563 val = gaim_account_get_string(acct, MW_KEY_BUSY_MSG, 5161 val = gaim_account_get_string(acct, MW_KEY_BUSY_MSG,
4564 MW_PLUGIN_DEFAULT_BUSY_MSG); 5162 MW_PLUGIN_DEFAULT_BUSY_MSG);
4565 f = gaim_request_field_string_new("busy", "Busy Message", val, FALSE); 5163 f = gaim_request_field_string_new("busy", _("Busy Message"), val, FALSE);
4566 gaim_request_field_set_required(f, FALSE); 5164 gaim_request_field_set_required(f, FALSE);
4567 gaim_request_field_group_add_field(g, f); 5165 gaim_request_field_group_add_field(g, f);
4568 5166
4569 #if 0 5167 msgA = _("Default status messages");
4570 /** @todo not yet used. It should be possible to prompt the user for
4571 a message (ala the Sametime Connect client) when changing to one
4572 of the default states, and that preference is here */
4573 prompt = gaim_account_get_bool(acct, MW_KEY_MSG_PROMPT, FALSE);
4574 f = gaim_request_field_bool_new("prompt",
4575 ("Prompt for message when changing"
4576 " to one of these states?"), FALSE);
4577 gaim_request_field_group_add_field(g, f);
4578 #endif
4579
4580 msgA = ("Default status messages");
4581 msgB = (""); 5168 msgB = ("");
4582 5169
4583 gaim_request_fields(gc, "Edit Status Messages", 5170 gaim_request_fields(gc, _("Edit Status Messages"),
4584 msgA, msgB, fields, 5171 msgA, msgB, fields,
4585 _("OK"), G_CALLBACK(status_msg_action_cb), 5172 _("OK"), G_CALLBACK(status_msg_action_cb),
4586 _("Cancel"), NULL, 5173 _("Cancel"), NULL,
4587 gc); 5174 gc);
4588 } 5175 }
4608 fclose(file); 5195 fclose(file);
4609 5196
4610 l = mwSametimeList_load(str->str); 5197 l = mwSametimeList_load(str->str);
4611 g_string_free(str, TRUE); 5198 g_string_free(str, TRUE);
4612 5199
4613 blist_import(gc, l); 5200 blist_merge(gc, l);
4614 mwSametimeList_free(l); 5201 mwSametimeList_free(l);
4615 } 5202 }
4616 5203
4617 5204
4618 /** prompts for a file to import blist from */ 5205 /** prompts for a file to import blist from */
4621 GaimAccount *account; 5208 GaimAccount *account;
4622 char *title; 5209 char *title;
4623 5210
4624 gc = act->context; 5211 gc = act->context;
4625 account = gaim_connection_get_account(gc); 5212 account = gaim_connection_get_account(gc);
4626 title = g_strdup_printf("Import Sametime List for Account %s", 5213 title = g_strdup_printf(_("Import Sametime List for Account %s"),
4627 gaim_account_get_username(account)); 5214 gaim_account_get_username(account));
4628 5215
4629 gaim_request_file(gc, title, NULL, FALSE, 5216 gaim_request_file(gc, title, NULL, FALSE,
4630 G_CALLBACK(st_import_action_cb), NULL, 5217 G_CALLBACK(st_import_action_cb), NULL,
4631 gc); 5218 gc);
4660 GaimAccount *account; 5247 GaimAccount *account;
4661 char *title; 5248 char *title;
4662 5249
4663 gc = act->context; 5250 gc = act->context;
4664 account = gaim_connection_get_account(gc); 5251 account = gaim_connection_get_account(gc);
4665 title = g_strdup_printf("Export Sametime List for Account %s", 5252 title = g_strdup_printf(_("Export Sametime List for Account %s"),
4666 gaim_account_get_username(account)); 5253 gaim_account_get_username(account));
4667 5254
4668 gaim_request_file(gc, title, NULL, TRUE, 5255 gaim_request_file(gc, title, NULL, TRUE,
4669 G_CALLBACK(st_export_action_cb), NULL, 5256 G_CALLBACK(st_export_action_cb), NULL,
4670 gc); 5257 gc);
4711 /* collision checking */ 5298 /* collision checking */
4712 group = gaim_find_group(name); 5299 group = gaim_find_group(name);
4713 if(group) { 5300 if(group) {
4714 char *msgA, *msgB; 5301 char *msgA, *msgB;
4715 5302
4716 msgA = "Unable to add group: group exists"; 5303 msgA = _("Unable to add group: group exists");
4717 msgB = "A group named '%s' already exists in your buddy list."; 5304 msgB = _("A group named '%s' already exists in your buddy list.");
4718 msgB = g_strdup_printf(msgB, name); 5305 msgB = g_strdup_printf(msgB, name);
4719 5306
4720 gaim_notify_error(gc, "Unable to add group", msgA, msgB); 5307 gaim_notify_error(gc, _("Unable to add group"), msgA, msgB);
4721 5308
4722 g_free(msgB); 5309 g_free(msgB);
4723 return; 5310 return;
4724 } 5311 }
4725 5312
4772 fields = gaim_request_fields_new(); 5359 fields = gaim_request_fields_new();
4773 5360
4774 g = gaim_request_field_group_new(NULL); 5361 g = gaim_request_field_group_new(NULL);
4775 gaim_request_fields_add_group(fields, g); 5362 gaim_request_fields_add_group(fields, g);
4776 5363
4777 f = gaim_request_field_list_new("group", "Possible Matches"); 5364 f = gaim_request_field_list_new("group", _("Possible Matches"));
4778 gaim_request_field_list_set_multi_select(f, FALSE); 5365 gaim_request_field_list_set_multi_select(f, FALSE);
4779 gaim_request_field_set_required(f, TRUE); 5366 gaim_request_field_set_required(f, TRUE);
4780 5367
4781 for(l = result->matches; l; l = l->next) { 5368 for(l = result->matches; l; l = l->next) {
4782 struct mwResolveMatch *match = l->data; 5369 struct mwResolveMatch *match = l->data;
4788 gaim_request_field_list_add(f, res->name, res); 5375 gaim_request_field_list_add(f, res->name, res);
4789 } 5376 }
4790 5377
4791 gaim_request_field_group_add_field(g, f); 5378 gaim_request_field_group_add_field(g, f);
4792 5379
4793 msgA = ("Notes Address Book group results"); 5380 msgA = _("Notes Address Book group results");
4794 msgB = ("The identifier '%s' may possibly refer to any of the following" 5381 msgB = _("The identifier '%s' may possibly refer to any of the following"
4795 " Notes Address Book groups. Please select the correct group from" 5382 " Notes Address Book groups. Please select the correct group from"
4796 " the list below to add it to your buddy list."); 5383 " the list below to add it to your buddy list.");
4797 msgB = g_strdup_printf(msgB, result->name); 5384 msgB = g_strdup_printf(msgB, result->name);
4798 5385
4799 gaim_request_fields(gc, "Select Notes Address Book", 5386 gaim_request_fields(gc, _("Select Notes Address Book"),
4800 msgA, msgB, fields, 5387 msgA, msgB, fields,
4801 "Add Group", G_CALLBACK(remote_group_multi_cb), 5388 _("Add Group"), G_CALLBACK(remote_group_multi_cb),
4802 "Cancel", G_CALLBACK(remote_group_multi_cleanup), 5389 _("Cancel"), G_CALLBACK(remote_group_multi_cleanup),
4803 pd); 5390 pd);
4804 5391
4805 g_free(msgB); 5392 g_free(msgB);
4806 } 5393 }
4807 5394
4834 } 5421 }
4835 5422
4836 if(res && res->name) { 5423 if(res && res->name) {
4837 char *msgA, *msgB; 5424 char *msgA, *msgB;
4838 5425
4839 msgA = "Unable to add group: group not found"; 5426 msgA = _("Unable to add group: group not found");
4840 5427
4841 msgB = ("The identifier '%s' did not match any Notes Address Book" 5428 msgB = _("The identifier '%s' did not match any Notes Address Book"
4842 " groups in your Sametime community."); 5429 " groups in your Sametime community.");
4843 msgB = g_strdup_printf(msgB, res->name); 5430 msgB = g_strdup_printf(msgB, res->name);
4844 5431
4845 gaim_notify_error(gc, "Unable to add group", msgA, msgB); 5432 gaim_notify_error(gc, _("Unable to add group"), msgA, msgB);
4846 5433
4847 g_free(msgB); 5434 g_free(msgB);
4848 } 5435 }
4849 } 5436 }
4850 5437
4876 GaimConnection *gc; 5463 GaimConnection *gc;
4877 const char *msgA, *msgB; 5464 const char *msgA, *msgB;
4878 5465
4879 gc = act->context; 5466 gc = act->context;
4880 5467
4881 msgA = "Notes Address Book Group"; 5468 msgA = _("Notes Address Book Group");
4882 msgB = ("Enter the name of a Notes Address Book group in the field below" 5469 msgB = _("Enter the name of a Notes Address Book group in the field below"
4883 " to add the group and its members to your buddy list."); 5470 " to add the group and its members to your buddy list.");
4884 5471
4885 gaim_request_input(gc, "Add Group", msgA, msgB, NULL, 5472 gaim_request_input(gc, _("Add Group"), msgA, msgB, NULL,
4886 FALSE, FALSE, NULL, 5473 FALSE, FALSE, NULL,
4887 "Add", G_CALLBACK(remote_group_action_cb), 5474 _("Add"), G_CALLBACK(remote_group_action_cb),
4888 "Cancel", NULL, 5475 _("Cancel"), NULL,
4889 gc); 5476 gc);
4890 } 5477 }
4891 5478
4892 5479
4893 static GList *mw_plugin_actions(GaimPlugin *plugin, gpointer context) { 5480 static GList *mw_plugin_actions(GaimPlugin *plugin, gpointer context) {
4894 GaimPluginAction *act; 5481 GaimPluginAction *act;
4895 GList *l = NULL; 5482 GList *l = NULL;
4896 5483
4897 act = gaim_plugin_action_new("Set Status Messages...", status_msg_action); 5484 act = gaim_plugin_action_new(_("Set Status Messages..."),
5485 status_msg_action);
4898 l = g_list_append(l, act); 5486 l = g_list_append(l, act);
4899 5487
4900 act = gaim_plugin_action_new("Import Sametime List...", st_import_action); 5488 act = gaim_plugin_action_new(_("Import Sametime List..."),
5489 st_import_action);
4901 l = g_list_append(l, act); 5490 l = g_list_append(l, act);
4902 5491
4903 act = gaim_plugin_action_new("Export Sametime List...", st_export_action); 5492 act = gaim_plugin_action_new(_("Export Sametime List..."),
5493 st_export_action);
4904 l = g_list_append(l, act); 5494 l = g_list_append(l, act);
4905 5495
4906 act = gaim_plugin_action_new("Add Notes Address Book Group...", 5496 act = gaim_plugin_action_new(_("Add Notes Address Book Group..."),
4907 remote_group_action); 5497 remote_group_action);
4908 l = g_list_append(l, act); 5498 l = g_list_append(l, act);
4909 5499
4910 return l; 5500 return l;
4911 } 5501 }
4982 GList *l = NULL; 5572 GList *l = NULL;
4983 5573
4984 GLogLevelFlags logflags = 5574 GLogLevelFlags logflags =
4985 G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION; 5575 G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION;
4986 5576
5577 /* set up the preferences */
5578 gaim_prefs_add_none(MW_PRPL_OPT_BASE);
5579 gaim_prefs_add_int(MW_PRPL_OPT_BLIST_ACTION, BLIST_CHOICE_DEFAULT);
5580
5581 /* remove dead preferences */
5582 gaim_prefs_remove(MW_PRPL_OPT_PSYCHIC);
5583 gaim_prefs_remove(MW_PRPL_OPT_SAVE_DYNAMIC);
5584
4987 /* host to connect to */ 5585 /* host to connect to */
4988 opt = gaim_account_option_string_new("Server", MW_KEY_HOST, 5586 opt = gaim_account_option_string_new(_("Server"), MW_KEY_HOST,
4989 MW_PLUGIN_DEFAULT_HOST); 5587 MW_PLUGIN_DEFAULT_HOST);
4990 l = g_list_append(l, opt); 5588 l = g_list_append(l, opt);
4991 5589
4992 /* port to connect to */ 5590 /* port to connect to */
4993 opt = gaim_account_option_int_new("Port", MW_KEY_PORT, 5591 opt = gaim_account_option_int_new(_("Port"), MW_KEY_PORT,
4994 MW_PLUGIN_DEFAULT_PORT); 5592 MW_PLUGIN_DEFAULT_PORT);
4995 l = g_list_append(l, opt); 5593 l = g_list_append(l, opt);
4996 5594
5595 /* default attempted encoding */
5596 opt = gaim_account_option_string_new(_("Encoding"), MW_KEY_ENCODING,
5597 MW_PLUGIN_DEFAULT_ENCODING);
5598 l = g_list_append(l, opt);
5599
5600 { /* copy the old force login setting from prefs if it's
5601 there. Don't delete the preference, since there may be more
5602 than one account that wants to check for it. */
5603 gboolean b = FALSE;
5604 const char *label = _("Force Login (Ignore Server Redirects)");
5605
5606 if(gaim_prefs_exists(MW_PRPL_OPT_FORCE_LOGIN))
5607 b = gaim_prefs_get_bool(MW_PRPL_OPT_FORCE_LOGIN);
5608
5609 opt = gaim_account_option_bool_new(label, MW_KEY_FORCE, b);
5610 l = g_list_append(l, opt);
5611 }
5612
4997 mw_prpl_info.protocol_options = l; 5613 mw_prpl_info.protocol_options = l;
4998 l = NULL; 5614 l = NULL;
4999
5000 /* set up the prefs for blist options */
5001 gaim_prefs_add_none(MW_PRPL_OPT_BASE);
5002 gaim_prefs_add_int(MW_PRPL_OPT_BLIST_ACTION, BLIST_CHOICE_DEFAULT);
5003 gaim_prefs_add_bool(MW_PRPL_OPT_PSYCHIC, FALSE);
5004 gaim_prefs_add_bool(MW_PRPL_OPT_FORCE_LOGIN, FALSE);
5005 gaim_prefs_add_bool(MW_PRPL_OPT_SAVE_DYNAMIC, TRUE);
5006 5615
5007 /* forward all our g_log messages to gaim. Generally all the logging 5616 /* forward all our g_log messages to gaim. Generally all the logging
5008 calls are using gaim_log directly, but the g_return macros will 5617 calls are using gaim_log directly, but the g_return macros will
5009 get caught here */ 5618 get caught here */
5010 log_handler[0] = g_log_set_handler(G_LOG_DOMAIN, logflags, 5619 log_handler[0] = g_log_set_handler(G_LOG_DOMAIN, logflags,