]> git.zarvox.org Git - imoo.git/blob - ribbon/ribbonmanager.cpp
373d3e74e9f49f601e1be483186d263c22b7a451
[imoo.git] / ribbon / ribbonmanager.cpp
1 #include "ribbonmanager.h"
2
3 #include <QDebug>
4 #include <QFile>
5 #include <QDateTime>
6 #include <libpurple/purple.h>
7 #include <cstdio>
8
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)
12
13 typedef struct _PurpleGLibIOClosure {
14     PurpleInputFunction function;
15     guint result;
16     gpointer data;
17 } PurpleGLibIOClosure;
18
19 static void purple_glib_io_destroy(gpointer data)
20 {
21     g_free(data);
22 }
23
24 static gboolean purple_glib_io_invoke(GIOChannel *source, GIOCondition condition, gpointer data)
25 {
26     PurpleGLibIOClosure *closure = (PurpleGLibIOClosure*)data;
27     PurpleInputCondition purple_cond = (PurpleInputCondition)0;
28
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);
33
34     closure->function(closure->data, g_io_channel_unix_get_fd(source),
35         purple_cond);
36
37     return TRUE;
38 }
39
40 static guint glib_input_add(gint fd, PurpleInputCondition condition,
41     PurpleInputFunction function, gpointer data)
42 {
43     PurpleGLibIOClosure *closure = g_new0(PurpleGLibIOClosure, 1);
44     GIOChannel *channel;
45     GIOCondition cond = (GIOCondition)0;
46
47     closure->function = function;
48     closure->data = data;
49
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);
54
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);
58
59     g_io_channel_unref(channel);
60     return closure->result;
61 }
62
63 static PurpleEventLoopUiOps glib_eventloops =
64 {
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) */
71
72     /* padding */
73     //NULL,
74     NULL,
75     NULL,
76     NULL
77 };
78 /* End verbatim copied code */
79
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         */
97 //      NULL,
98 //      NULL,
99 //      NULL,
100 //      NULL
101 //};
102
103 static QVariantMap ctx_from_account(PurpleAccount* account)
104 {
105         QVariantMap ctx;
106         ctx["protocol"] = QVariant(purple_account_get_protocol_id(account));
107         ctx["username"] = QVariant(purple_account_get_username(account));
108         return ctx;
109 }
110
111 static void connect_progress(PurpleConnection *gc, const char* text, size_t step, size_t step_count)
112 {
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);
122 }
123
124 static void connection_notice(PurpleConnection *gc, const char* text)
125 {
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);
132 }
133
134 static void connection_disconnected(PurpleConnection *gc, const char* text)
135 {
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);
142 }
143
144 static void network_connected(void)
145 {
146         qWarning() << "Network connection established";
147 }
148
149 static void network_disconnected(void)
150 {
151         qWarning() << "This machine has been disconnected from the internet";
152 }
153
154 static void report_disconnect_reason(PurpleConnection *gc, PurpleConnectionError reason, const char *text)
155 {
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);
163 }
164
165 static PurpleConnectionUiOps connection_uiops =
166 {
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 */
175         NULL,
176         NULL,
177         NULL
178 };
179
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);
184 }
185
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 */
194         /* padding */
195         //NULL,
196         NULL,
197         NULL,
198         NULL
199 };
200
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)
205 {
206         Q_UNUSED(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));
209 }
210
211 static void received_im_msg(PurpleAccount *account, char *sender, char *message,
212                             PurpleConversation *conv, PurpleMessageFlags flags, void* data)
213 {
214         Q_UNUSED(data);
215         RibbonManager* r = static_cast<RibbonManager*>(account->ui_data);
216         r->received_im_msg(account, sender, message, conv, flags);
217 }
218
219 static void buddy_signed_on(PurpleBuddy* buddy, void* data)
220 {
221         Q_UNUSED(data);
222         qDebug() << purple_buddy_get_contact_alias(buddy) << "signed on";
223 }
224
225 static void connect_to_signals(void)
226 {
227         static int handle;
228         void *blist_handle = purple_blist_get_handle();
229         void *connections_handle = purple_connections_get_handle();
230         void *conversations_handle = purple_conversations_get_handle();
231
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(
239 }
240
241 RibbonManager::RibbonManager(QObject* parent) : QObject(parent)
242 {
243 }
244
245 RibbonManager::~RibbonManager()
246 {
247 }
248
249 void RibbonManager::init(void)
250 {
251         /* optional:
252         purple_util_set_user_dir(CUSTOM_USER_DIRECTORY);
253         */
254
255         /* Enable debugging messages */
256         purple_debug_set_enabled(FALSE);
257
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. */
265                 fprintf(stderr,
266                                 "libpurple initialization failed. Dumping core.\n"
267                                 "Please report this!\n");
268                 abort();
269         }
270
271         /* Create and load the buddylist */
272         purple_set_blist(purple_blist_new());
273         purple_blist_load();
274
275         /* Hopefully this is an okay time for this? */
276         connect_to_signals();
277 }
278
279 const char* RibbonManager::get_version(void)
280 {
281         return purple_core_get_version();
282 }
283
284 void RibbonManager::received_im_msg(PurpleAccount *account, char *sender, char *message,
285                             PurpleConversation *conv, PurpleMessageFlags flags) {
286         Q_UNUSED(flags);
287         if (conv==NULL) {
288                 conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sender);
289         }
290         qDebug() << QDateTime::currentDateTime().toString("hh:mm:ss") << sender << purple_conversation_get_name(conv) << message;
291 }
292
293 void RibbonManager::handleExternalEvent(QString destination, QString method, QVariantMap context)
294 {
295         // TODO: handle external event
296         qDebug() << "TODO: do something with" << destination << "." << method << "(" << context << ")";
297 }
298
299 void RibbonManager::sign_in_user(void)
300 {
301         QFile file("account.txt");
302         if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
303                 qDebug() << "Couldn't load account information from account.txt!";
304                 return;
305         }
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;
313
314         purple_account_set_password(account, password.data());
315         purple_accounts_add(account);
316         purple_account_set_enabled(account, UI_ID, TRUE);
317 }