📄 nullprpl.c
字号:
/** * purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * Nullprpl is a mock protocol plugin for Pidgin and libpurple. You can create * accounts with it, sign on and off, add buddies, and send and receive IMs, * all without connecting to a server! * * Beyond that basic functionality, nullprpl supports presence and * away/available messages, offline messages, user info, typing notification, * privacy allow/block lists, chat rooms, whispering, room lists, and protocol * icons and emblems. Notable missing features are file transfer and account * registration and authentication. * * Nullprpl is intended as an example of how to write a libpurple protocol * plugin. It doesn't contain networking code or an event loop, but it does * demonstrate how to use the libpurple API to do pretty much everything a prpl * might need to do. * * Nullprpl is also a useful tool for hacking on Pidgin, Finch, and other * libpurple clients. It's a full-featured protocol plugin, but doesn't depend * on an external server, so it's a quick and easy way to exercise test new * code. It also allows you to work while you're disconnected. * * 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 */#include <stdarg.h>#include <string.h>#include <time.h>#include <glib.h>#include "internal.h"#include "config.h"#include "account.h"#include "accountopt.h"#include "blist.h"#include "cmds.h"#include "conversation.h"#include "connection.h"#include "debug.h"#include "notify.h"#include "privacy.h"#include "prpl.h"#include "roomlist.h"#include "status.h"#include "util.h"#include "version.h"#define NULLPRPL_ID "prpl-null"static PurplePlugin *_null_protocol = NULL;#define NULL_STATUS_ONLINE "online"#define NULL_STATUS_AWAY "away"#define NULL_STATUS_OFFLINE "offline"typedef void (*GcFunc)(PurpleConnection *from, PurpleConnection *to, gpointer userdata);typedef struct { GcFunc fn; PurpleConnection *from; gpointer userdata;} GcFuncData;/* * stores offline messages that haven't been delivered yet. maps username * (char *) to GList * of GOfflineMessages. initialized in nullprpl_init. */GHashTable* goffline_messages = NULL;typedef struct { char *from; char *message; time_t mtime; PurpleMessageFlags flags;} GOfflineMessage;/* * helpers */static PurpleConnection *get_nullprpl_gc(const char *username) { PurpleAccount *acct = purple_accounts_find(username, NULLPRPL_ID); if (acct && purple_account_is_connected(acct)) return acct->gc; else return NULL;}static void call_if_nullprpl(gpointer data, gpointer userdata) { PurpleConnection *gc = (PurpleConnection *)(data); GcFuncData *gcfdata = (GcFuncData *)userdata; if (!strcmp(gc->account->protocol_id, NULLPRPL_ID)) gcfdata->fn(gcfdata->from, gc, gcfdata->userdata);}static void foreach_nullprpl_gc(GcFunc fn, PurpleConnection *from, gpointer userdata) { GcFuncData gcfdata = { fn, from, userdata }; g_list_foreach(purple_connections_get_all(), call_if_nullprpl, &gcfdata);}typedef void(*ChatFunc)(PurpleConvChat *from, PurpleConvChat *to, int id, const char *room, gpointer userdata);typedef struct { ChatFunc fn; PurpleConvChat *from_chat; gpointer userdata;} ChatFuncData;static void call_chat_func(gpointer data, gpointer userdata) { PurpleConnection *to = (PurpleConnection *)data; ChatFuncData *cfdata = (ChatFuncData *)userdata; int id = cfdata->from_chat->id; PurpleConversation *conv = purple_find_chat(to, id); if (conv) { PurpleConvChat *chat = purple_conversation_get_chat_data(conv); cfdata->fn(cfdata->from_chat, chat, id, conv->name, cfdata->userdata); }}static void foreach_gc_in_chat(ChatFunc fn, PurpleConnection *from, int id, gpointer userdata) { PurpleConversation *conv = purple_find_chat(from, id); ChatFuncData cfdata = { fn, purple_conversation_get_chat_data(conv), userdata }; g_list_foreach(purple_connections_get_all(), call_chat_func, &cfdata);}static void discover_status(PurpleConnection *from, PurpleConnection *to, gpointer userdata) { char *from_username = from->account->username; char *to_username = to->account->username; if (purple_find_buddy(from->account, to_username)) { PurpleStatus *status = purple_account_get_active_status(to->account); const char *status_id = purple_status_get_id(status); const char *message = purple_status_get_attr_string(status, "message"); if (!strcmp(status_id, NULL_STATUS_ONLINE) || !strcmp(status_id, NULL_STATUS_AWAY) || !strcmp(status_id, NULL_STATUS_OFFLINE)) { purple_debug_info("nullprpl", "%s sees that %s is %s: %s\n", from_username, to_username, status_id, message); purple_prpl_got_user_status(from->account, to_username, status_id, (message) ? "message" : NULL, message, NULL); } else { purple_debug_error("nullprpl", "%s's buddy %s has an unknown status: %s, %s", from_username, to_username, status_id, message); } }}static void report_status_change(PurpleConnection *from, PurpleConnection *to, gpointer userdata) { purple_debug_info("nullprpl", "notifying %s that %s changed status\n", to->account->username, from->account->username); discover_status(to, from, NULL);}/* * UI callbacks */static void nullprpl_input_user_info(PurplePluginAction *action){ PurpleConnection *gc = (PurpleConnection *)action->context; PurpleAccount *acct = purple_connection_get_account(gc); purple_debug_info("nullprpl", "showing 'Set User Info' dialog for %s\n", acct->username); purple_account_request_change_user_info(acct);}/* this is set to the actions member of the PurplePluginInfo struct at the * bottom. */static GList *nullprpl_actions(PurplePlugin *plugin, gpointer context){ PurplePluginAction *action = purple_plugin_action_new( _("Set User Info..."), nullprpl_input_user_info); return g_list_append(NULL, action);}/* * prpl functions */static const char *nullprpl_list_icon(PurpleAccount *acct, PurpleBuddy *buddy){ /* shamelessly steal (er, borrow) the meanwhile protocol icon. it's cute! */ return "meanwhile";}static const char *nullprpl_list_emblem(PurpleBuddy *buddy){ const char* emblem; if (get_nullprpl_gc(buddy->name)) { PurplePresence *presence = purple_buddy_get_presence(buddy); PurpleStatus *status = purple_presence_get_active_status(presence); emblem = purple_status_get_name(status); } else { emblem = "offline"; } purple_debug_info("nullprpl", "using emblem %s for %s's buddy %s\n", emblem, buddy->account->username, buddy->name); return emblem;}static char *nullprpl_status_text(PurpleBuddy *buddy) { purple_debug_info("nullprpl", "getting %s's status text for %s\n", buddy->name, buddy->account->username); if (purple_find_buddy(buddy->account, buddy->name)) { PurplePresence *presence = purple_buddy_get_presence(buddy); PurpleStatus *status = purple_presence_get_active_status(presence); const char *name = purple_status_get_name(status); const char *message = purple_status_get_attr_string(status, "message"); char *text; if (message && strlen(message) > 0) text = g_strdup_printf("%s: %s", name, message); else text = g_strdup(name); purple_debug_info("nullprpl", "%s's status text is %s\n", buddy->name, text); return text; } else { purple_debug_info("nullprpl", "...but %s is not logged in\n", buddy->name); return "Not logged in"; }}static void nullprpl_tooltip_text(PurpleBuddy *buddy, PurpleNotifyUserInfo *info, gboolean full) { PurpleConnection *gc = get_nullprpl_gc(buddy->name); if (gc) { /* they're logged in */ PurplePresence *presence = purple_buddy_get_presence(buddy); PurpleStatus *status = purple_presence_get_active_status(presence); const char *msg = nullprpl_status_text(buddy); purple_notify_user_info_add_pair(info, purple_status_get_name(status), msg); if (full) { const char *user_info = purple_account_get_user_info(gc->account); if (user_info) purple_notify_user_info_add_pair(info, _("User info"), user_info); } } else { /* they're not logged in */ purple_notify_user_info_add_pair(info, _("User info"), _("not logged in")); } purple_debug_info("nullprpl", "showing %s tooltip for %s\n", (full) ? "full" : "short", buddy->name);}static GList *nullprpl_status_types(PurpleAccount *acct){ GList *types = NULL; PurpleStatusType *type; purple_debug_info("nullprpl", "returning status types for %s: %s, %s, %s\n", acct->username, NULL_STATUS_ONLINE, NULL_STATUS_AWAY, NULL_STATUS_OFFLINE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -