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

📄 sametime.c

📁 Linux下的多协议即时通讯程序源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/*  Meanwhile Protocol Plugin for Purple  Adds Lotus Sametime support to Purple using the Meanwhile library  Copyright (C) 2004 Christopher (siege) O'Brien <siege@preoccupied.net>  This program is free software; you can redistribute it and/or modify  it under the terms of the GNU General Public License as published by  the Free Software Foundation; either version 2 of the License, or (at  your option) any later version.  This program is distributed in the hope that it will be useful, but  WITHOUT ANY WARRANTY; without even the implied warranty of  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU  General Public License for more details.  You should have received a copy of the GNU General Public License  along with this program; if not, write to the Free Software  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,  USA.*//* system includes */#include <stdlib.h>#include <time.h>/* glib includes */#include <glib.h>#include <glib/ghash.h>#include <glib/glist.h>/* purple includes */#include "internal.h"#include "config.h"#include "account.h"#include "accountopt.h"#include "circbuffer.h"#include "conversation.h"#include "debug.h"#include "ft.h"#include "imgstore.h"#include "mime.h"#include "notify.h"#include "plugin.h"#include "privacy.h"#include "prpl.h"#include "request.h"#include "util.h"#include "version.h"/* meanwhile includes */#include <mw_cipher.h>#include <mw_common.h>#include <mw_error.h>#include <mw_service.h>#include <mw_session.h>#include <mw_srvc_aware.h>#include <mw_srvc_conf.h>#include <mw_srvc_ft.h>#include <mw_srvc_im.h>#include <mw_srvc_place.h>#include <mw_srvc_resolve.h>#include <mw_srvc_store.h>#include <mw_st_list.h>/* plugin includes */#include "sametime.h"/* considering that there's no display of this information for prpls,   I don't know why I even bother providing these. Oh valiant reader,   I do it all for you. *//* scratch that, I just added it to the prpl options panel */#define PLUGIN_ID        "prpl-meanwhile"#define PLUGIN_NAME      "Sametime"#define PLUGIN_SUMMARY   "Sametime Protocol Plugin"#define PLUGIN_DESC      "Open implementation of a Lotus Sametime client"#define PLUGIN_AUTHOR    "Christopher (siege) O'Brien <siege@preoccupied.net>"#define PLUGIN_HOMEPAGE  "http://meanwhile.sourceforge.net/"/* plugin preference names */#define MW_PRPL_OPT_BASE          "/plugins/prpl/meanwhile"#define MW_PRPL_OPT_BLIST_ACTION  MW_PRPL_OPT_BASE "/blist_action"#define MW_PRPL_OPT_PSYCHIC       MW_PRPL_OPT_BASE "/psychic"#define MW_PRPL_OPT_FORCE_LOGIN   MW_PRPL_OPT_BASE "/force_login"#define MW_PRPL_OPT_SAVE_DYNAMIC  MW_PRPL_OPT_BASE "/save_dynamic"/* stages of connecting-ness */#define MW_CONNECT_STEPS  11/* stages of conciousness */#define MW_STATE_OFFLINE      "offline"#define MW_STATE_ACTIVE       "active"#define MW_STATE_AWAY         "away"#define MW_STATE_BUSY         "dnd"#define MW_STATE_MESSAGE      "message"#define MW_STATE_ENLIGHTENED  "buddha"/* keys to get/set chat information */#define CHAT_KEY_CREATOR   "chat.creator"#define CHAT_KEY_NAME      "chat.name"#define CHAT_KEY_TOPIC     "chat.topic"#define CHAT_KEY_INVITE    "chat.invite"#define CHAT_KEY_IS_PLACE  "chat.is_place"/* key for associating a mwLoginType with a buddy */#define BUDDY_KEY_CLIENT  "meanwhile.client"/* store the remote alias so that we can re-create it easily */#define BUDDY_KEY_NAME    "meanwhile.shortname"/* enum mwSametimeUserType */#define BUDDY_KEY_TYPE    "meanwhile.type"/* key for the real group name for a meanwhile group */#define GROUP_KEY_NAME    "meanwhile.group"/* enum mwSametimeGroupType */#define GROUP_KEY_TYPE    "meanwhile.type"/* NAB group owning account */#define GROUP_KEY_OWNER   "meanwhile.account"/* key gtk blist uses to indicate a collapsed group */#define GROUP_KEY_COLLAPSED  "collapsed"/* verification replacement */#define mwSession_NO_SECRET  "meanwhile.no_secret"/* keys to get/set purple plugin information */#define MW_KEY_HOST        "server"#define MW_KEY_PORT        "port"#define MW_KEY_FORCE       "force_login"#define MW_KEY_FAKE_IT     "fake_client_id"#define MW_KEY_CLIENT      "client_id_val"#define MW_KEY_MAJOR       "client_major"#define MW_KEY_MINOR       "client_minor"/** number of seconds from the first blist change before a save to the    storage service occurs. */#define BLIST_SAVE_SECONDS  15/** the possible buddy list storage settings */enum blist_choice {  blist_choice_LOCAL = 1, /**< local only */  blist_choice_MERGE = 2, /**< merge from server */  blist_choice_STORE = 3, /**< merge from and save to server */  blist_choice_SYNCH = 4, /**< sync with server */};/** the default blist storage option */#define BLIST_CHOICE_DEFAULT  blist_choice_SYNCH/* testing for the above */#define BLIST_PREF_IS(n) (purple_prefs_get_int(MW_PRPL_OPT_BLIST_ACTION)==(n))#define BLIST_PREF_IS_LOCAL()  BLIST_PREF_IS(blist_choice_LOCAL)#define BLIST_PREF_IS_MERGE()  BLIST_PREF_IS(blist_choice_MERGE)#define BLIST_PREF_IS_STORE()  BLIST_PREF_IS(blist_choice_STORE)#define BLIST_PREF_IS_SYNCH()  BLIST_PREF_IS(blist_choice_SYNCH)/* debugging output */#define DEBUG_ERROR(a...)  purple_debug_error(G_LOG_DOMAIN, a)#define DEBUG_INFO(a...)   purple_debug_info(G_LOG_DOMAIN, a)#define DEBUG_MISC(a...)   purple_debug_misc(G_LOG_DOMAIN, a)#define DEBUG_WARN(a...)   purple_debug_warning(G_LOG_DOMAIN, a)/** ensure non-null strings */#ifndef NSTR# define NSTR(str) ((str)? (str): "(null)")#endif/** calibrates distinct secure channel nomenclature */static const unsigned char no_secret[] = {  0x2d, 0x2d, 0x20, 0x73, 0x69, 0x65, 0x67, 0x65,  0x20, 0x6c, 0x6f, 0x76, 0x65, 0x73, 0x20, 0x6a,  0x65, 0x6e, 0x6e, 0x69, 0x20, 0x61, 0x6e, 0x64,  0x20, 0x7a, 0x6f, 0x65, 0x20, 0x2d, 0x2d, 0x00,};/** handler IDs from g_log_set_handler in mw_plugin_init */static guint log_handler[2] = { 0, 0 };/** the purple plugin data.    available as gc->proto_data and mwSession_getClientData */struct mwPurplePluginData {  struct mwSession *session;  struct mwServiceAware *srvc_aware;  struct mwServiceConference *srvc_conf;  struct mwServiceFileTransfer *srvc_ft;  struct mwServiceIm *srvc_im;  struct mwServicePlace *srvc_place;  struct mwServiceResolve *srvc_resolve;  struct mwServiceStorage *srvc_store;  /** map of PurpleGroup:mwAwareList and mwAwareList:PurpleGroup */  GHashTable *group_list_map;  /** event id for the buddy list save callback */  guint save_event;  /** socket fd */  int socket;  gint outpa;  /* like inpa, but the other way */  /** circular buffer for outgoing data */  PurpleCircBuffer *sock_buf;  PurpleConnection *gc;};typedef struct {  PurpleBuddy *buddy;  PurpleGroup *group;} BuddyAddData;/* blist and aware functions */static void blist_export(PurpleConnection *gc, struct mwSametimeList *stlist);static void blist_store(struct mwPurplePluginData *pd);static void blist_schedule(struct mwPurplePluginData *pd);static void blist_merge(PurpleConnection *gc, struct mwSametimeList *stlist);static void blist_sync(PurpleConnection *gc, struct mwSametimeList *stlist);static gboolean buddy_is_external(PurpleBuddy *b);static void buddy_add(struct mwPurplePluginData *pd, PurpleBuddy *buddy);static PurpleBuddy *buddy_ensure(PurpleConnection *gc, PurpleGroup *group,	     struct mwSametimeUser *stuser);static void group_add(struct mwPurplePluginData *pd, PurpleGroup *group);static PurpleGroup *group_ensure(PurpleConnection *gc, struct mwSametimeGroup *stgroup);static struct mwAwareList *list_ensure(struct mwPurplePluginData *pd, PurpleGroup *group);/* session functions */static struct mwSession *gc_to_session(PurpleConnection *gc);static PurpleConnection *session_to_gc(struct mwSession *session);/* conference functions */static struct mwConference *conf_find_by_id(struct mwPurplePluginData *pd, int id);/* conversation functions */struct convo_msg {  enum mwImSendType type;  gpointer data;  GDestroyNotify clear;};struct convo_data {  struct mwConversation *conv;  GList *queue;   /**< outgoing message queue, list of convo_msg */};static void convo_data_new(struct mwConversation *conv);static void convo_data_free(struct convo_data *conv);static void convo_features(struct mwConversation *conv);static PurpleConversation *convo_get_gconv(struct mwConversation *conv);/* name and id */struct named_id {  char *id;  char *name;};/* connection functions */static void connect_cb(gpointer data, gint source, const gchar *error_message);/* ----- session ------ *//** resolves a mwSession from a PurpleConnection */static struct mwSession *gc_to_session(PurpleConnection *gc) {  struct mwPurplePluginData *pd;    g_return_val_if_fail(gc != NULL, NULL);    pd = gc->proto_data;  g_return_val_if_fail(pd != NULL, NULL);    return pd->session;}/** resolves a PurpleConnection from a mwSession */static PurpleConnection *session_to_gc(struct mwSession *session) {  struct mwPurplePluginData *pd;  g_return_val_if_fail(session != NULL, NULL);  pd = mwSession_getClientData(session);  g_return_val_if_fail(pd != NULL, NULL);  return pd->gc;}static void write_cb(gpointer data, gint source, PurpleInputCondition cond) {  struct mwPurplePluginData *pd = data;  PurpleCircBuffer *circ = pd->sock_buf;  gsize avail;  int ret;  DEBUG_INFO("write_cb\n");  g_return_if_fail(circ != NULL);  avail = purple_circ_buffer_get_max_read(circ);  if(BUF_LONG < avail) avail = BUF_LONG;  while(avail) {    ret = write(pd->socket, circ->outptr, avail);        if(ret <= 0)      break;    purple_circ_buffer_mark_read(circ, ret);    avail = purple_circ_buffer_get_max_read(circ);    if(BUF_LONG < avail) avail = BUF_LONG;  }  if(! avail) {    purple_input_remove(pd->outpa);    pd->outpa = 0;  }}static int mw_session_io_write(struct mwSession *session,			       const guchar *buf, gsize len) {  struct mwPurplePluginData *pd;  int ret = 0;  int err = 0;  pd = mwSession_getClientData(session);  /* socket was already closed. */  if(pd->socket == 0)    return 1;  if(pd->outpa) {    DEBUG_INFO("already pending INPUT_WRITE, buffering\n");    purple_circ_buffer_append(pd->sock_buf, buf, len);    return 0;  }  while(len) {    ret = write(pd->socket, buf, (len > BUF_LEN)? BUF_LEN: len);    if(ret <= 0)      break;    len -= ret;    buf += ret;  }  if(ret <= 0)    err = errno;  if(err == EAGAIN) {    /* append remainder to circular buffer */    DEBUG_INFO("EAGAIN\n");    purple_circ_buffer_append(pd->sock_buf, buf, len);    pd->outpa = purple_input_add(pd->socket, PURPLE_INPUT_WRITE, write_cb, pd);  } else if(len > 0) {    DEBUG_ERROR("write returned %i, %i bytes left unwritten\n", ret, len);    purple_connection_error(pd->gc, _("Connection closed (writing)"));#if 0    close(pd->socket);    pd->socket = 0;#endif    return -1;  }  return 0;}static void mw_session_io_close(struct mwSession *session) {  struct mwPurplePluginData *pd;  PurpleConnection *gc;  pd = mwSession_getClientData(session);  g_return_if_fail(pd != NULL);  gc = pd->gc;    if(pd->outpa) {    purple_input_remove(pd->outpa);    pd->outpa = 0;  }  if(pd->socket) {    close(pd->socket);    pd->socket = 0;  }    if(gc->inpa) {    purple_input_remove(gc->inpa);    gc->inpa = 0;  }}static void mw_session_clear(struct mwSession *session) {  ; /* nothing for now */}/* ----- aware list ----- */static void blist_resolve_alias_cb(struct mwServiceResolve *srvc,				   guint32 id, guint32 code, GList *results,				   gpointer data) {  struct mwResolveResult *result;  struct mwResolveMatch *match;  g_return_if_fail(results != NULL);  result = results->data;  g_return_if_fail(result != NULL);  g_return_if_fail(result->matches != NULL);  match = result->matches->data;  g_return_if_fail(match != NULL);  purple_blist_server_alias_buddy(data, match->name);  purple_blist_node_set_string(data, BUDDY_KEY_NAME, match->name);}static void mw_aware_list_on_aware(struct mwAwareList *list,				   struct mwAwareSnapshot *aware) {  PurpleConnection *gc;  PurpleAccount *acct;      struct mwPurplePluginData *pd;  guint32 idle;  guint stat;  const char *id;  const char *status = MW_STATE_ACTIVE;  gc = mwAwareList_getClientData(list);  acct = purple_connection_get_account(gc);

⌨️ 快捷键说明

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