⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sametime.c

📁 Linux下的多协议即时通讯程序源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
  g_return_if_fail(group != NULL);  DEBUG_INFO("clearing members from pruned group %s\n", NSTR(group->name));  gc = purple_account_get_connection(acct);  g_return_if_fail(gc != NULL);  gn = (PurpleBlistNode *) group;  for(cn = gn->child; cn; cn = cn->next) {    if(! PURPLE_BLIST_NODE_IS_CONTACT(cn)) continue;    for(bn = cn->child; bn; bn = bn->next) {      PurpleBuddy *gb = (PurpleBuddy *) bn;      if(! PURPLE_BLIST_NODE_IS_BUDDY(bn)) continue;            if(gb->account == acct) {	DEBUG_INFO("clearing %s from group\n", NSTR(gb->name));	prune = g_list_prepend(prune, gb);      }    }  }  /* quickly unsubscribe from presence for the entire group */  purple_account_remove_group(acct, group);  /* remove blist entries that need to go */  while(prune) {    purple_blist_remove_buddy(prune->data);    prune = g_list_delete_link(prune, prune);  }  DEBUG_INFO("cleared buddies\n");  /* optionally remove group from blist */  if(del && !purple_blist_get_group_size(group, TRUE)) {    DEBUG_INFO("removing empty group\n");    purple_blist_remove_group(group);  }}/** prune out group members that shouldn't be there */static void group_prune(PurpleConnection *gc, PurpleGroup *group,			struct mwSametimeGroup *stgroup) {  PurpleAccount *acct;  PurpleBlistNode *gn, *cn, *bn;    GHashTable *stusers;  GList *prune = NULL;  GList *ul, *utl;  g_return_if_fail(group != NULL);  DEBUG_INFO("pruning membership of group %s\n", NSTR(group->name));  acct = purple_connection_get_account(gc);  g_return_if_fail(acct != NULL);  stusers = g_hash_table_new(g_str_hash, g_str_equal);    /* build a hash table for quick lookup while pruning the group     contents */  utl = mwSametimeGroup_getUsers(stgroup);  for(ul = utl; ul; ul = ul->next) {    const char *id = mwSametimeUser_getUser(ul->data);    g_hash_table_insert(stusers, (char *) id, ul->data);    DEBUG_INFO("server copy has %s\n", NSTR(id));  }  g_list_free(utl);  gn = (PurpleBlistNode *) group;  for(cn = gn->child; cn; cn = cn->next) {    if(! PURPLE_BLIST_NODE_IS_CONTACT(cn)) continue;    for(bn = cn->child; bn; bn = bn->next) {      PurpleBuddy *gb = (PurpleBuddy *) bn;      if(! PURPLE_BLIST_NODE_IS_BUDDY(bn)) continue;      /* if the account is correct and they're not in our table, mark	 them for pruning */      if(gb->account == acct && !g_hash_table_lookup(stusers, gb->name)) {	DEBUG_INFO("marking %s for pruning\n", NSTR(gb->name));	prune = g_list_prepend(prune, gb);      }    }  }  DEBUG_INFO("done marking\n");  g_hash_table_destroy(stusers);  if(prune) {    purple_account_remove_buddies(acct, prune, NULL);    while(prune) {      purple_blist_remove_buddy(prune->data);      prune = g_list_delete_link(prune, prune);    }  }}/** synch the entries from a st list into the purple blist, removing any    existing buddies that aren't in the st list */static void blist_sync(PurpleConnection *gc, struct mwSametimeList *stlist) {  PurpleAccount *acct;  PurpleBuddyList *blist;  PurpleBlistNode *gn;  GHashTable *stgroups;  GList *g_prune = NULL;  GList *gl, *gtl;  const char *acct_n;  DEBUG_INFO("synchronizing local buddy list from server list\n");  acct = purple_connection_get_account(gc);  g_return_if_fail(acct != NULL);  acct_n = purple_account_get_username(acct);  blist = purple_get_blist();  g_return_if_fail(blist != NULL);  /* build a hash table for quick lookup while pruning the local     list, mapping group name to group structure */  stgroups = g_hash_table_new(g_str_hash, g_str_equal);  gtl = mwSametimeList_getGroups(stlist);  for(gl = gtl; gl; gl = gl->next) {    const char *name = mwSametimeGroup_getName(gl->data);    g_hash_table_insert(stgroups, (char *) name, gl->data);  }  g_list_free(gtl);  /* find all groups which should be pruned from the local list */  for(gn = blist->root; gn; gn = gn->next) {    PurpleGroup *grp = (PurpleGroup *) gn;    const char *gname, *owner;    struct mwSametimeGroup *stgrp;    if(! PURPLE_BLIST_NODE_IS_GROUP(gn)) continue;    /* group not belonging to this account */    if(! purple_group_on_account(grp, acct))      continue;    /* dynamic group belonging to this account. don't prune contents */    owner = purple_blist_node_get_string(gn, GROUP_KEY_OWNER);    if(owner && !strcmp(owner, acct_n))       continue;    /* we actually are synching by this key as opposed to the group       title, which can be different things in the st list */    gname = purple_blist_node_get_string(gn, GROUP_KEY_NAME);    if(! gname) gname = grp->name;    stgrp = g_hash_table_lookup(stgroups, gname);    if(! stgrp) {      /* remove the whole group */      DEBUG_INFO("marking group %s for pruning\n", grp->name);      g_prune = g_list_prepend(g_prune, grp);    } else {      /* synch the group contents */      group_prune(gc, grp, stgrp);    }  }  DEBUG_INFO("done marking groups\n");  /* don't need this anymore */  g_hash_table_destroy(stgroups);  /* prune all marked groups */  while(g_prune) {    PurpleGroup *grp = g_prune->data;    PurpleBlistNode *gn = (PurpleBlistNode *) grp;    const char *owner;    gboolean del = TRUE;    owner = purple_blist_node_get_string(gn, GROUP_KEY_OWNER);    if(owner && strcmp(owner, acct_n)) {      /* it's a specialty group belonging to another account with some	 of our members in it, so don't fully delete it */      del = FALSE;    }        group_clear(g_prune->data, acct, del);    g_prune = g_list_delete_link(g_prune, g_prune);  }  /* done with the pruning, let's merge in the additions */  blist_merge(gc, stlist);}/** callback passed to the storage service when it's told to load the    st list */static void fetch_blist_cb(struct mwServiceStorage *srvc,			   guint32 result, struct mwStorageUnit *item,			   gpointer data) {  struct mwPurplePluginData *pd = data;  struct mwSametimeList *stlist;  struct mwGetBuffer *b;  g_return_if_fail(result == ERR_SUCCESS);  /* check our preferences for loading */  if(BLIST_PREF_IS_LOCAL()) {    DEBUG_INFO("preferences indicate not to load remote buddy list\n");    return;  }  b = mwGetBuffer_wrap(mwStorageUnit_asOpaque(item));  stlist = mwSametimeList_new();  mwSametimeList_get(b, stlist);  /* merge or synch depending on preferences */  if(BLIST_PREF_IS_MERGE() || BLIST_PREF_IS_STORE()) {    blist_merge(pd->gc, stlist);  } else if(BLIST_PREF_IS_SYNCH()) {    blist_sync(pd->gc, stlist);  }  mwSametimeList_free(stlist);}/** signal triggered when a conversation is opened in Purple */static void conversation_created_cb(PurpleConversation *g_conv,				    struct mwPurplePluginData *pd) {  /* we need to tell the IM service to negotiate features for the     conversation right away, otherwise it'll wait until the first     message is sent before offering NotesBuddy features. Therefore     whenever Purple creates a conversation, we'll immediately open the     channel to the other side and figure out what the target can     handle. Unfortunately, this makes us vulnerable to Psychic Mode,     whereas a more lazy negotiation based on the first message     would not */  PurpleConnection *gc;  struct mwIdBlock who = { 0, 0 };  struct mwConversation *conv;  gc = purple_conversation_get_gc(g_conv);  if(pd->gc != gc)    return; /* not ours */  if(purple_conversation_get_type(g_conv) != PURPLE_CONV_TYPE_IM)    return; /* wrong type */  who.user = (char *) purple_conversation_get_name(g_conv);  conv = mwServiceIm_getConversation(pd->srvc_im, &who);  convo_features(conv);      if(mwConversation_isClosed(conv))    mwConversation_open(conv);}static void blist_menu_nab(PurpleBlistNode *node, gpointer data) {  struct mwPurplePluginData *pd = data;  PurpleConnection *gc;  PurpleGroup *group = (PurpleGroup *) node;  GString *str;  char *tmp;  g_return_if_fail(pd != NULL);  gc = pd->gc;  g_return_if_fail(gc != NULL);  g_return_if_fail(PURPLE_BLIST_NODE_IS_GROUP(node));  str = g_string_new(NULL);  tmp = (char *) purple_blist_node_get_string(node, GROUP_KEY_NAME);  g_string_append_printf(str, _("<b>Group Title:</b> %s<br>"), group->name);  g_string_append_printf(str, _("<b>Notes Group ID:</b> %s<br>"), tmp);  tmp = g_strdup_printf(_("Info for Group %s"), group->name);  purple_notify_formatted(gc, tmp, _("Notes Address Book Information"),			NULL, str->str, NULL, NULL);  g_free(tmp);  g_string_free(str, TRUE);}/** The normal blist menu prpl function doesn't get called for groups,    so we use the blist-node-extended-menu signal to trigger this    handler */static void blist_node_menu_cb(PurpleBlistNode *node,                               GList **menu, struct mwPurplePluginData *pd) {  const char *owner;  PurpleGroup *group;  PurpleAccount *acct;  PurpleMenuAction *act;  /* we only want groups */  if(! PURPLE_BLIST_NODE_IS_GROUP(node)) return;  group = (PurpleGroup *) node;  acct = purple_connection_get_account(pd->gc);  g_return_if_fail(acct != NULL);  /* better make sure we're connected */  if(! purple_account_is_connected(acct)) return;#if 0  /* if there's anyone in the group for this acct, offer to invite     them all to a conference */  if(purple_group_on_account(group, acct)) {    act = purple_menu_action_new(_("Invite Group to Conference..."),                               PURPLE_CALLBACK(blist_menu_group_invite),                               pd, NULL);    *menu = g_list_append(*menu, NULL);  }#endif  /* check if it's a NAB group for this account */  owner = purple_blist_node_get_string(node, GROUP_KEY_OWNER);  if(owner && !strcmp(owner, purple_account_get_username(acct))) {    act = purple_menu_action_new(_("Get Notes Address Book Info"),                               PURPLE_CALLBACK(blist_menu_nab), pd, NULL);    *menu = g_list_append(*menu, act);  }}/* lifted this from oldstatus, since HEAD doesn't do this at login   anymore. */static void blist_init(PurpleAccount *acct) {  PurpleBlistNode *gnode, *cnode, *bnode;  GList *add_buds = NULL;  for(gnode = purple_get_blist()->root; gnode; gnode = gnode->next) {    if(! PURPLE_BLIST_NODE_IS_GROUP(gnode)) continue;    for(cnode = gnode->child; cnode; cnode = cnode->next) {      if(! PURPLE_BLIST_NODE_IS_CONTACT(cnode))	continue;      for(bnode = cnode->child; bnode; bnode = bnode->next) {	PurpleBuddy *b;	if(!PURPLE_BLIST_NODE_IS_BUDDY(bnode))	  continue;		b = (PurpleBuddy *)bnode;	if(b->account == acct) {	  add_buds = g_list_append(add_buds, b);	}      }    }  }    if(add_buds) {    purple_account_add_buddies(acct, add_buds);    g_list_free(add_buds);  }}/** Last thing to happen from a started session */static void services_starting(struct mwPurplePluginData *pd) {  PurpleConnection *gc;  PurpleAccount *acct;  struct mwStorageUnit *unit;  PurpleBuddyList *blist;  PurpleBlistNode *l;  gc = pd->gc;  acct = purple_connection_get_account(gc);  /* grab the buddy list from the server */  unit = mwStorageUnit_new(mwStore_AWARE_LIST);  mwServiceStorage_load(pd->srvc_store, unit, fetch_blist_cb, pd, NULL);   /* find all the NAB groups and subscribe to them */  blist = purple_get_blist();  for(l = blist->root; l; l = l->next) {    PurpleGroup *group = (PurpleGroup *) l;    enum mwSametimeGroupType gt;    const char *owner;    if(! PURPLE_BLIST_NODE_IS_GROUP(l)) continue;    /* if the group is ownerless, or has an owner and we're not it,       skip it */    owner = purple_blist_node_get_string(l, GROUP_KEY_OWNER);    if(!owner || strcmp(owner, purple_account_get_username(acct)))      continue;    gt = purple_blist_node_get_int(l, GROUP_KEY_TYPE);    if(gt == mwSametimeGroup_DYNAMIC)      group_add(pd, group);  }  /* set the aware attributes */  /* indicate we understand what AV prefs are, but don't support any */  mwServiceAware_setAttributeBoolean(pd->srvc_aware,				     mwAttribute_AV_PREFS_SET, TRUE);  mwServiceAware_unsetAttribute(pd->srvc_aware, mwAttribute_MICROPHONE);  mwServiceAware_unsetAttribute(pd->srvc_aware, mwAttribute_SPEAKERS);  mwServiceAware_unsetAttribute(pd->srvc_aware, mwAttribute_VIDEO_CAMERA);  /* ... but we can do file transfers! */  mwServiceAware_setAttributeBoolean(pd->srvc_aware,				     mwAttribute_FILE_TRANSFER, TRUE);  blist_init(acct);}static void session_loginRedirect(struct mwSession *session,				  const char *host) {  struct mwPurplePluginData *pd;  PurpleConnection *gc;  PurpleAccount *account;  guint port;  const char *current_host;  pd = mwSession_getClientData(session);  gc = pd->gc;  account = purple_connection_get_account(gc);  port = purple_account_get_int(account, MW_KEY_PORT, MW_PLUGIN_DEFAULT_PORT);  current_host = purple_account_get_string(account, MW_KEY_HOST,					 MW_PLUGIN_DEFAULT_HOST);  if(purple_account_get_bool(account, MW_KEY_FORCE, FALSE) ||     (! strcmp(current_host, host)) ||     (purple_proxy_connect(NULL, account, host, port, connect_cb, pd) == NULL)) {    /* if we're configured to force logins, or if we're being       redirected to the already configured host, or if we couldn't       connect to the new host, we'll force the login instead */    mwSession_forceLogin(session);  }}static void mw_prpl_set_status(PurpleAccount *acct, PurpleStatus *status);/** called from mw_session_stateChange when the session's state is    mwSession_STARTED. Any finalizing of start-up stuff should go    here */static void session_started(struct mwPurplePluginData *pd) {  PurpleStatus *status;  PurpleAccount *acct;  /* set out initial status */  acct = purple_connection_get_account(pd->gc);  status = purple_account_get_active_status(acct);  mw_prpl_set_status(acct, status);    /* start watching for new conversations */  purple_signal_connect(purple_conversations_get_handle(),		      "conversation-created", pd,		      PURPLE_CALLBACK(conversation_created_cb), pd);  /* watch for group extended menu items */  purple_signal_connect(purple_blist_get_handle(),		      "blist-node-extended-menu", pd,		      PURPLE_CALLBACK(blist_node_menu_cb), pd);    /* use our services to do neat things */  services_starting(pd);}static void session_stopping(struct mwPurplePluginData *pd) {  /* stop watching the signals from session_started */  purple_signals_disconnect_by_handle(pd);}static void mw_session_stateChange(struct mwSession *session,				   enum mwSessionState state,				   gpointer info) {  struct mwPurplePluginData *pd;  PurpleConnection *gc;  const char *msg = NULL;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -