1 #include "ribbonmanager.h"
6 #include <libpurple/purple.h>
9 /* Eventloop and glib IO stuff copied verbatim from nullclient.c */
10 #define PURPLE_GLIB_READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR)
11 #define PURPLE_GLIB_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL)
13 typedef struct _PurpleGLibIOClosure {
14 PurpleInputFunction function;
17 } PurpleGLibIOClosure;
19 static void purple_glib_io_destroy(gpointer data)
24 static gboolean purple_glib_io_invoke(GIOChannel *source, GIOCondition condition, gpointer data)
26 PurpleGLibIOClosure *closure = (PurpleGLibIOClosure*)data;
27 PurpleInputCondition purple_cond = (PurpleInputCondition)0;
29 if (condition & PURPLE_GLIB_READ_COND)
30 purple_cond = (PurpleInputCondition)(purple_cond | PURPLE_INPUT_READ);
31 if (condition & PURPLE_GLIB_WRITE_COND)
32 purple_cond = (PurpleInputCondition)(purple_cond | PURPLE_INPUT_WRITE);
34 closure->function(closure->data, g_io_channel_unix_get_fd(source),
40 static guint glib_input_add(gint fd, PurpleInputCondition condition,
41 PurpleInputFunction function, gpointer data)
43 PurpleGLibIOClosure *closure = g_new0(PurpleGLibIOClosure, 1);
45 GIOCondition cond = (GIOCondition)0;
47 closure->function = function;
50 if (condition & PURPLE_INPUT_READ)
51 cond = (GIOCondition)(cond | PURPLE_GLIB_READ_COND);
52 if (condition & PURPLE_INPUT_WRITE)
53 cond = (GIOCondition)(cond | PURPLE_GLIB_WRITE_COND);
55 channel = g_io_channel_unix_new(fd);
56 closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT,
57 cond, purple_glib_io_invoke, closure, purple_glib_io_destroy);
59 g_io_channel_unref(channel);
60 return closure->result;
63 static PurpleEventLoopUiOps glib_eventloops =
65 g_timeout_add, /* guint timeout_add(guint interval, GSourceFunc function, gpointer data) */
66 g_source_remove, /* gboolean timeout_remove(guint handle); */
67 glib_input_add, /* guint input_add(int fd, PurpleInputCondition cond, PurpleInputFunction func, gpointer user_data) */
68 g_source_remove, /* gboolean input_remove(guint handle) */
69 NULL, /* int input_get_error(int fd, int* error) */
70 g_timeout_add_seconds, /* guint timeout_add_seconds(guint interval, GSourceFunc function, gpointer data) */
78 /* End verbatim copied code */
80 /* noops for now, add features later */
81 //static PurpleConversationUiOps ribbon_conversation_callbacks = {
82 // NULL, /* create_conversation */
83 // NULL, /* destroy_conversation */
84 // NULL, /* write_chat */
85 // NULL, /* write_im */
86 // NULL, /* write_conv */
87 // NULL, /* chat_add_users */
88 // NULL, /* chat_rename_user */
89 // NULL, /* chat_remove_users */
90 // NULL, /* chat_update_user */
91 // NULL, /* present */
92 // NULL, /* has_focus */
93 // NULL, /* custom_smiley_add */
94 // NULL, /* custom_smiley_write */
95 // NULL, /* custom_smiley_close */
96 // NULL, /* send_confirm */
103 static QVariantMap ctx_from_account(PurpleAccount* account)
106 ctx["protocol"] = QVariant(purple_account_get_protocol_id(account));
107 ctx["username"] = QVariant(purple_account_get_username(account));
111 static void connect_progress(PurpleConnection *gc, const char* text, size_t step, size_t step_count)
113 PurpleAccount* account = purple_connection_get_account(gc);
114 RibbonManager* r = static_cast<RibbonManager*>(account->ui_data);
115 qDebug() << QString("Connection progress (%1:%2):").arg(account->protocol_id, account->username).toUtf8().constData() << text << step << "of" << step_count;
116 // TODO: add enough unique information from account to ctx to handle the message
117 QVariantMap ctx = ctx_from_account(account);
118 ctx["step"] = QVariant((qulonglong)step);
119 ctx["step_count"] = QVariant((qulonglong)step_count);
120 ctx["text"] = QVariant(QString::fromUtf8(text));
121 r->event(QString("connection"), QString("connect_progress"), ctx);
124 static void connection_notice(PurpleConnection *gc, const char* text)
126 qDebug() << "Connection notice:" << text;
127 PurpleAccount* account = purple_connection_get_account(gc);
128 RibbonManager* r = static_cast<RibbonManager*>(account->ui_data);
129 QVariantMap ctx = ctx_from_account(account);
130 ctx["message"] = QVariant(QString::fromUtf8(text));
131 r->event(QString("connection"), QString("connect_notice"), ctx);
134 static void connection_disconnected(PurpleConnection *gc, const char* text)
136 qDebug() << "Connection disconnected:" << text;
137 PurpleAccount* account = purple_connection_get_account(gc);
138 RibbonManager* r = static_cast<RibbonManager*>(account->ui_data);
139 QVariantMap ctx = ctx_from_account(account);
140 ctx["message"] = QVariant(QString::fromUtf8(text));
141 r->event(QString("connection"), QString("connection_disconnected"), ctx);
144 static void network_connected(void)
146 qWarning() << "Network connection established";
149 static void network_disconnected(void)
151 qWarning() << "This machine has been disconnected from the internet";
154 static void report_disconnect_reason(PurpleConnection *gc, PurpleConnectionError reason, const char *text)
156 PurpleAccount *account = purple_connection_get_account(gc);
157 //qDebug() << QString("Connection disconnected: \'%1\' (%2)\n >Error: %3\n >Reason: %4\n").arg(purple_account_get_username(account), purple_account_get_protocol_id(account), qint32(reason), text);
158 RibbonManager* r = static_cast<RibbonManager*>(account->ui_data);
159 QVariantMap ctx = ctx_from_account(account);
160 ctx["reason_code"] = QVariant(qint32(reason));
161 ctx["reason_text"] = QVariant(QString::fromUtf8(text));
162 r->event(QString("connection"), QString("disconnect_reason"), ctx);
165 static PurpleConnectionUiOps connection_uiops =
167 connect_progress, /* connect_progress */
168 NULL, /* connected */
169 NULL, /* disconnected */
170 connection_notice, /* notice */
171 connection_disconnected, /* report_disconnect */
172 network_connected, /* network_connected */
173 network_disconnected, /* network_disconnected */
174 report_disconnect_reason, /* report_disconnect_reason */
180 static void ribbon_core_init(void) {
181 printf("core_init called\n");
182 printf("setting connection callbacks\n");
183 purple_connections_set_ui_ops(&connection_uiops);
186 static PurpleCoreUiOps ribbon_core_callbacks = {
187 NULL, /* ui_prefs_init - called just after preferences subsystem is initialized */
188 NULL, /* debug_ui_init - called just after the debug system is inited, but before other components init */
189 ribbon_core_init, /* ui_init - called after all of libpurple has been initialized */
190 NULL, /* quit - called after most of libpurple has been uninitialized */
191 NULL, /* get_ui_info - called by purple_core_get_ui_info, should return a
192 GHashTable* with string key/value pairs containing info about the UI, like:
193 name, version, website, dev_website */
201 // TODO: note that the void* data can be set at purple_signal_connect time, and
202 // set it to the class instance to allow for convenient upcalls
203 // Then, actually do upcalls and emit the appropriate signals.
204 static void signed_on(PurpleConnection *gc, void* data)
207 PurpleAccount *account = purple_connection_get_account(gc);
208 printf("Account connected: \"%s\" (%s)\n", purple_account_get_username(account), purple_account_get_protocol_id(account));
211 static void received_im_msg(PurpleAccount *account, char *sender, char *message,
212 PurpleConversation *conv, PurpleMessageFlags flags, void* data)
215 RibbonManager* r = static_cast<RibbonManager*>(account->ui_data);
216 r->received_im_msg(account, sender, message, conv, flags);
219 static void buddy_signed_on(PurpleBuddy* buddy, void* data)
222 qDebug() << purple_buddy_get_contact_alias(buddy) << "signed on";
225 static void connect_to_signals(void)
228 void *blist_handle = purple_blist_get_handle();
229 void *connections_handle = purple_connections_get_handle();
230 void *conversations_handle = purple_conversations_get_handle();
232 purple_signal_connect(connections_handle, "signed-on", &handle,
233 PURPLE_CALLBACK(signed_on), NULL);
234 purple_signal_connect(conversations_handle, "received-im-msg", &handle,
235 PURPLE_CALLBACK(received_im_msg), NULL);
236 purple_signal_connect(blist_handle, "buddy-signed-on", &handle,
237 PURPLE_CALLBACK(buddy_signed_on), NULL);
238 //purple_signal_connect(
241 RibbonManager::RibbonManager(QObject* parent) : QObject(parent)
245 RibbonManager::~RibbonManager()
249 void RibbonManager::init(void)
252 purple_util_set_user_dir(CUSTOM_USER_DIRECTORY);
255 /* Enable debugging messages */
256 purple_debug_set_enabled(FALSE);
258 /* configure purple core callbacks */
259 purple_core_set_ui_ops(&ribbon_core_callbacks);
260 /* configure purple eventloop */
261 purple_eventloop_set_ui_ops(&glib_eventloops);
262 /* Init purple core */
263 if (!purple_core_init(UI_ID)) {
264 /* Initializing the core failed. Terminate. */
266 "libpurple initialization failed. Dumping core.\n"
267 "Please report this!\n");
271 /* Create and load the buddylist */
272 purple_set_blist(purple_blist_new());
275 /* Hopefully this is an okay time for this? */
276 connect_to_signals();
279 const char* RibbonManager::get_version(void)
281 return purple_core_get_version();
284 void RibbonManager::received_im_msg(PurpleAccount *account, char *sender, char *message,
285 PurpleConversation *conv, PurpleMessageFlags flags) {
288 conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sender);
290 qDebug() << QDateTime::currentDateTime().toString("hh:mm:ss") << sender << purple_conversation_get_name(conv) << message;
293 void RibbonManager::handleExternalEvent(QString destination, QString method, QVariantMap context)
295 // TODO: handle external event
296 qDebug() << "TODO: do something with" << destination << "." << method << "(" << context << ")";
299 void RibbonManager::sign_in_user(void)
301 QFile file("account.txt");
302 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
303 qDebug() << "Couldn't load account information from account.txt!";
306 QByteArray protocol = file.readLine().trimmed();//this could be prpl-aim, prpl-yahoo, prpl-msn, prpl-icq, etc.
307 QByteArray username = file.readLine().trimmed();
308 QByteArray password = file.readLine().trimmed();
309 // Allocate and enable an account.
310 PurpleAccount *account = purple_account_new(username.data(), protocol.data());
311 // ui_data needed for upcalls
312 account->ui_data = this;
314 purple_account_set_password(account, password.data());
315 purple_accounts_add(account);
316 purple_account_set_enabled(account, UI_ID, TRUE);