📄 sametime.c
字号:
}static void mw_conf_text(struct mwConference *conf, struct mwLoginInfo *who, const char *text) { struct mwServiceConference *srvc; struct mwSession *session; struct mwPurplePluginData *pd; PurpleConnection *gc; char *esc; if(! text) return; srvc = mwConference_getService(conf); session = mwService_getSession(MW_SERVICE(srvc)); pd = mwSession_getClientData(session); gc = pd->gc; esc = g_markup_escape_text(text, -1); serv_got_chat_in(gc, CONF_TO_ID(conf), who->user_id, 0, esc, time(NULL)); g_free(esc);}static void mw_conf_typing(struct mwConference *conf, struct mwLoginInfo *who, gboolean typing) { /* purple really has no good way to expose this to the user. */ const char *n = mwConference_getName(conf); const char *w = who->user_id; if(typing) { DEBUG_INFO("%s in conf %s: <typing>\n", NSTR(w), NSTR(n)); } else { DEBUG_INFO("%s in conf %s: <stopped typing>\n", NSTR(w), NSTR(n)); }}static void mw_conf_clear(struct mwServiceConference *srvc) { ;}static struct mwConferenceHandler mw_conference_handler = { mw_conf_invited, mw_conf_opened, mw_conf_closed, mw_conf_peer_joined, mw_conf_peer_parted, mw_conf_text, mw_conf_typing, mw_conf_clear,};static struct mwServiceConference *mw_srvc_conf_new(struct mwSession *s) { struct mwServiceConference *srvc; srvc = mwServiceConference_new(s, &mw_conference_handler); return srvc;}/** size of an outgoing file transfer chunk */#define MW_FT_LEN (BUF_LONG * 2)static void ft_incoming_cancel(PurpleXfer *xfer) { /* incoming transfer rejected or canceled in-progress */ struct mwFileTransfer *ft = xfer->data; if(ft) mwFileTransfer_reject(ft);}static void ft_incoming_init(PurpleXfer *xfer) { /* incoming transfer accepted */ /* - accept the mwFileTransfer - open/create the local FILE "wb" - stick the FILE's fp in xfer->dest_fp */ struct mwFileTransfer *ft; FILE *fp; ft = xfer->data; fp = g_fopen(xfer->local_filename, "wb"); if(! fp) { mwFileTransfer_cancel(ft); return; } xfer->dest_fp = fp; mwFileTransfer_accept(ft);}static void mw_ft_offered(struct mwFileTransfer *ft) { /* - create a purple ft object - offer it */ struct mwServiceFileTransfer *srvc; struct mwSession *session; struct mwPurplePluginData *pd; PurpleConnection *gc; PurpleAccount *acct; const char *who; PurpleXfer *xfer; /* @todo add some safety checks */ srvc = mwFileTransfer_getService(ft); session = mwService_getSession(MW_SERVICE(srvc)); pd = mwSession_getClientData(session); gc = pd->gc; acct = purple_connection_get_account(gc); who = mwFileTransfer_getUser(ft)->user; DEBUG_INFO("file transfer %p offered\n", ft); DEBUG_INFO(" from: %s\n", NSTR(who)); DEBUG_INFO(" file: %s\n", NSTR(mwFileTransfer_getFileName(ft))); DEBUG_INFO(" size: %u\n", mwFileTransfer_getFileSize(ft)); DEBUG_INFO(" text: %s\n", NSTR(mwFileTransfer_getMessage(ft))); xfer = purple_xfer_new(acct, PURPLE_XFER_RECEIVE, who); if (xfer) { purple_xfer_ref(xfer); mwFileTransfer_setClientData(ft, xfer, (GDestroyNotify) purple_xfer_unref); xfer->data = ft; purple_xfer_set_init_fnc(xfer, ft_incoming_init); purple_xfer_set_cancel_recv_fnc(xfer, ft_incoming_cancel); purple_xfer_set_request_denied_fnc(xfer, ft_incoming_cancel); purple_xfer_set_filename(xfer, mwFileTransfer_getFileName(ft)); purple_xfer_set_size(xfer, mwFileTransfer_getFileSize(ft)); purple_xfer_set_message(xfer, mwFileTransfer_getMessage(ft)); purple_xfer_request(xfer); }}static void ft_send(struct mwFileTransfer *ft, FILE *fp) { guchar buf[MW_FT_LEN]; struct mwOpaque o = { .data = buf, .len = MW_FT_LEN }; guint32 rem; PurpleXfer *xfer; xfer = mwFileTransfer_getClientData(ft); rem = mwFileTransfer_getRemaining(ft); if(rem < MW_FT_LEN) o.len = rem; if(fread(buf, (size_t) o.len, 1, fp)) { /* calculate progress and display it */ xfer->bytes_sent += o.len; xfer->bytes_remaining -= o.len; purple_xfer_update_progress(xfer); mwFileTransfer_send(ft, &o); } else { int err = errno; DEBUG_WARN("problem reading from file %s: %s\n", NSTR(mwFileTransfer_getFileName(ft)), strerror(err)); mwFileTransfer_cancel(ft); }}static void mw_ft_opened(struct mwFileTransfer *ft) { /* - get purple ft from client data in ft - set the state to active */ PurpleXfer *xfer; xfer = mwFileTransfer_getClientData(ft); if(! xfer) { mwFileTransfer_cancel(ft); mwFileTransfer_free(ft); g_return_if_reached(); } if(purple_xfer_get_type(xfer) == PURPLE_XFER_SEND) { xfer->dest_fp = g_fopen(xfer->local_filename, "rb"); ft_send(ft, xfer->dest_fp); } }static void mw_ft_closed(struct mwFileTransfer *ft, guint32 code) { /* - get purple ft from client data in ft - indicate rejection/cancelation/completion - free the file transfer itself */ PurpleXfer *xfer; xfer = mwFileTransfer_getClientData(ft); if(xfer) { xfer->data = NULL; if(! mwFileTransfer_getRemaining(ft)) { purple_xfer_set_completed(xfer, TRUE); purple_xfer_end(xfer); } else if(mwFileTransfer_isCancelLocal(ft)) { /* calling purple_xfer_cancel_local is redundant, since that's probably what triggered this function to be called */ ; } else if(mwFileTransfer_isCancelRemote(ft)) { /* steal the reference for the xfer */ mwFileTransfer_setClientData(ft, NULL, NULL); purple_xfer_cancel_remote(xfer); /* drop the stolen reference */ purple_xfer_unref(xfer); return; } } mwFileTransfer_free(ft);}static void mw_ft_recv(struct mwFileTransfer *ft, struct mwOpaque *data) { /* - get purple ft from client data in ft - update transfered percentage - if done, destroy the ft, disassociate from purple ft */ PurpleXfer *xfer; FILE *fp; xfer = mwFileTransfer_getClientData(ft); g_return_if_fail(xfer != NULL); fp = xfer->dest_fp; g_return_if_fail(fp != NULL); /* we must collect and save our precious data */ fwrite(data->data, 1, data->len, fp); /* update the progress */ xfer->bytes_sent += data->len; xfer->bytes_remaining -= data->len; purple_xfer_update_progress(xfer); /* let the other side know we got it, and to send some more */ mwFileTransfer_ack(ft);}static void mw_ft_ack(struct mwFileTransfer *ft) { PurpleXfer *xfer; xfer = mwFileTransfer_getClientData(ft); g_return_if_fail(xfer != NULL); g_return_if_fail(xfer->watcher == 0); if(! mwFileTransfer_getRemaining(ft)) { purple_xfer_set_completed(xfer, TRUE); purple_xfer_end(xfer); } else if(mwFileTransfer_isOpen(ft)) { ft_send(ft, xfer->dest_fp); }}static void mw_ft_clear(struct mwServiceFileTransfer *srvc) { ;}static struct mwFileTransferHandler mw_ft_handler = { mw_ft_offered, mw_ft_opened, mw_ft_closed, mw_ft_recv, mw_ft_ack, mw_ft_clear,};static struct mwServiceFileTransfer *mw_srvc_ft_new(struct mwSession *s) { struct mwServiceFileTransfer *srvc; GHashTable *ft_map; ft_map = g_hash_table_new(g_direct_hash, g_direct_equal); srvc = mwServiceFileTransfer_new(s, &mw_ft_handler); mwService_setClientData(MW_SERVICE(srvc), ft_map, (GDestroyNotify) g_hash_table_destroy); return srvc;}static void convo_data_free(struct convo_data *cd) { GList *l; /* clean the queue */ for(l = cd->queue; l; l = g_list_delete_link(l, l)) { struct convo_msg *m = l->data; if(m->clear) m->clear(m->data); g_free(m); } g_free(cd);}/** allocates a convo_data structure and associates it with the conversation in the client data slot */static void convo_data_new(struct mwConversation *conv) { struct convo_data *cd; g_return_if_fail(conv != NULL); if(mwConversation_getClientData(conv)) return; cd = g_new0(struct convo_data, 1); cd->conv = conv; mwConversation_setClientData(conv, cd, (GDestroyNotify) convo_data_free);}static PurpleConversation *convo_get_gconv(struct mwConversation *conv) { struct mwServiceIm *srvc; struct mwSession *session; struct mwPurplePluginData *pd; PurpleConnection *gc; PurpleAccount *acct; struct mwIdBlock *idb; srvc = mwConversation_getService(conv); session = mwService_getSession(MW_SERVICE(srvc)); pd = mwSession_getClientData(session); gc = pd->gc; acct = purple_connection_get_account(gc); idb = mwConversation_getTarget(conv); return purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, idb->user, acct);}static void convo_queue(struct mwConversation *conv, enum mwImSendType type, gconstpointer data) { struct convo_data *cd; struct convo_msg *m; convo_data_new(conv); cd = mwConversation_getClientData(conv); m = g_new0(struct convo_msg, 1); m->type = type; switch(type) { case mwImSend_PLAIN: m->data = g_strdup(data); m->clear = g_free; break; case mwImSend_TYPING: default: m->data = (gpointer) data; m->clear = NULL; } cd->queue = g_list_append(cd->queue, m);}/* Does what it takes to get an error displayed for a conversation */static void convo_error(struct mwConversation *conv, guint32 err) { PurpleConversation *gconv; char *tmp, *text; struct mwIdBlock *idb; idb = mwConversation_getTarget(conv); tmp = mwError(err); text = g_strconcat(_("Unable to send message: "), tmp, NULL); gconv = convo_get_gconv(conv); if(gconv && !purple_conv_present_error(idb->user, gconv->account, text)) { g_free(text); text = g_strdup_printf(_("Unable to send message to %s:"), (idb->user)? idb->user: "(unknown)"); purple_notify_error(purple_account_get_connection(gconv->account), NULL, text, tmp); } g_free(tmp); g_free(text);}static void convo_queue_send(struct mwConversation *conv) { struct convo_data *cd; GList *l; cd = mwConversation_getClientData(conv); for(l = cd->queue; l; l = g_list_delete_link(l, l)) { struct convo_msg *m = l->data; mwConversation_send(conv, m->type, m->data); if(m->clear) m->clear(m->data); g_free(m); } cd->queue = NULL;}/** called when a mw conversation leaves a purple conversation to inform the purple conversation that it's unsafe to offer any *cool* features. */static void convo_nofeatures(struct mwConversation *conv) { PurpleConversation *gconv; PurpleConnection *gc; gconv = convo_get_gconv(conv); if(! gconv) return; gc = purple_conversation_get_gc(gconv); if(! gc) return; purple_conversation_set_features(gconv, gc->flags);}/** called when a mw conversation and purple conversation come together, to inform the purple conversation of what features to offer the user */static void convo_features(struct mwConversation *conv) { PurpleConversation *gconv; PurpleConnectionFlags feat; gconv = convo_get_gconv(conv); if(! gconv) return; feat = purple_conversation_get_features(gconv); if(mwConversation_isOpen(conv)) { if(mwConversation_supports(conv, mwImSend_HTML)) { feat |= PURPLE_CONNECTION_HTML; } else { feat &= ~PURPLE_CONNECTION_HTML; } if(mwConversation_supports(conv, mwImSend_MIME)) { feat &= ~PURPLE_CONNECTION_NO_IMAGES; } else { feat |= PURPLE_CONNECTION_NO_IMAGES; } DEBUG_INFO("conversation features set to 0x%04x\n", feat); purple_conversation_set_features(gconv, feat); } else { convo_nofeatures(conv); }}static void mw_conversation_opened(struct mwConversation *conv) { struct mwServiceIm *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -