2 * nullclient-ecore.c - an ecore libpurple client test.
3 * Copyright (C) 2009, Marco Trevisan (TreviƱo) <mail@3v1n0.net>
6 * Pidgin is the legal property of its developers, whose names are too numerous
7 * to list here. Please refer to the COPYRIGHT file distributed with this
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
29 #include <eina_list.h>
35 // Client related settings
36 #define CUSTOM_USER_DIRECTORY "/dev/null"
37 #define CUSTOM_PLUGIN_PATH ""
38 #define PLUGIN_SAVE_PREF "/purple/nullclient-ecore/plugins/saved"
39 #define UI_ID "nullclient-ecore"
43 static guint loopID = 0;
44 Eina_List *timerList = NULL;
45 Eina_List *inputList = NULL;
47 typedef struct _timerRef {
52 typedef struct _fdRef {
53 PurpleInputFunction function;
54 Ecore_Fd_Handler_Flags condition;
55 Ecore_Fd_Handler *fdh;
60 static guint ecore_purple_timeout_add(guint interval, GSourceFunc function, gpointer data) {
61 timerRef *ref = calloc(1, sizeof(timerRef));
62 double timer_interval = ((double) interval)/1000;
64 ref->timer = ecore_timer_add(timer_interval, function, data);
66 timerList = eina_list_append(timerList, ref);
71 static gboolean ecore_purple_timeout_remove(guint handle) {
75 EINA_LIST_FOREACH(timerList, tlist, ref) {
76 if (ref->id == handle) {
78 ecore_timer_del(ref->timer);
79 timerList = eina_list_remove(timerList, ref);
88 static int ecore_purple_input_cb(void *data, Ecore_Fd_Handler *fd_handler) {
90 PurpleInputCondition purple_cond = 0;
92 if (ref->condition & ECORE_FD_READ)
93 purple_cond |= PURPLE_INPUT_READ;
95 if (ref->condition & ECORE_FD_WRITE)
96 purple_cond |= PURPLE_INPUT_WRITE;
98 if (ref->function && fd_handler) {
99 ref->function(ref->data, ecore_main_fd_handler_fd_get(fd_handler), purple_cond);
105 static guint ecore_purple_input_add(int fd, PurpleInputCondition condition,
106 PurpleInputFunction func, gpointer user_data) {
107 Ecore_Fd_Handler_Flags fdflags = 0;
113 if (condition & PURPLE_INPUT_READ)
114 fdflags |= ECORE_FD_READ;
116 if (condition & PURPLE_INPUT_WRITE)
117 fdflags |= ECORE_FD_WRITE;
119 ref = calloc(1, sizeof(fdRef));
120 ref->fdh = ecore_main_fd_handler_add(fd, fdflags, ecore_purple_input_cb, ref, NULL, NULL);
122 ref->data = user_data;
123 ref->function = func;
124 inputList = eina_list_append(inputList, ref);
129 static gboolean ecore_purple_input_remove(guint handle) {
133 EINA_LIST_FOREACH(inputList, tlist, ref) {
134 if (ref && ref->id == handle) {
136 ecore_main_fd_handler_del(ref->fdh);
137 inputList = eina_list_remove(inputList, ref);
146 static PurpleEventLoopUiOps ecore_eventloops =
148 ecore_purple_timeout_add,
149 ecore_purple_timeout_remove,
150 ecore_purple_input_add,
151 ecore_purple_input_remove,
158 /*** End of the eventloop functions. ***/
160 /*** Conversation uiops ***/
162 null_write_conv(PurpleConversation *conv, const char *who, const char *alias,
163 const char *message, PurpleMessageFlags flags, time_t mtime)
168 else if (who && *who)
173 printf("(%s) %s %s: %s\n", purple_conversation_get_name(conv),
174 purple_utf8_strftime("(%H:%M:%S)", localtime(&mtime)),
178 static PurpleConversationUiOps null_conv_uiops =
180 NULL, /* create_conversation */
181 NULL, /* destroy_conversation */
182 NULL, /* write_chat */
184 null_write_conv, /* write_conv */
185 NULL, /* chat_add_users */
186 NULL, /* chat_rename_user */
187 NULL, /* chat_remove_users */
188 NULL, /* chat_update_user */
190 NULL, /* has_focus */
191 NULL, /* custom_smiley_add */
192 NULL, /* custom_smiley_write */
193 NULL, /* custom_smiley_close */
194 NULL, /* send_confirm */
205 * This should initialize the UI components for all the modules. Here we
206 * just initialize the UI for conversations.
208 purple_conversations_set_ui_ops(&null_conv_uiops);
212 static PurpleCoreUiOps null_core_uiops =
227 /* Set a custom user directory (optional) */
228 purple_util_set_user_dir(CUSTOM_USER_DIRECTORY);
230 /* We do not want any debugging for now to keep the noise to a minimum. */
231 purple_debug_set_enabled(TRUE);
233 /* Set the core-uiops, which is used to
234 * - initialize the ui specific preferences.
235 * - initialize the debug ui.
236 * - initialize the ui components for all the modules.
237 * - uninitialize the ui components for all the modules when the core terminates.
239 purple_core_set_ui_ops(&null_core_uiops);
241 /* Set the uiops for the eventloop. */
242 purple_eventloop_set_ui_ops(&ecore_eventloops);
244 /* Set path to search for plugins. The core (libpurple) takes care of loading the
245 * core-plugins, which includes the protocol-plugins. So it is not essential to add
246 * any path here, but it might be desired, especially for ui-specific plugins. */
247 purple_plugins_add_search_path(CUSTOM_PLUGIN_PATH);
249 /* Now that all the essential stuff has been set, let's try to init the core. It's
250 * necessary to provide a non-NULL name for the current ui to the core. This name
251 * is used by stuff that depends on this ui, for example the ui-specific plugins. */
252 if (!purple_core_init(UI_ID)) {
253 /* Initializing the core failed. Terminate. */
255 "libpurple initialization failed. Dumping core.\n"
256 "Please report this!\n");
260 /* Create and load the buddylist. */
261 purple_set_blist(purple_blist_new());
264 /* Load the preferences. */
267 /* Load the desired plugins. The client should save the list of loaded plugins in
268 * the preferences using purple_plugins_save_loaded(PLUGIN_SAVE_PREF) */
269 purple_plugins_load_saved(PLUGIN_SAVE_PREF);
271 /* Load the pounces. */
272 purple_pounces_load();
276 signed_on(PurpleConnection *gc, gpointer null)
278 PurpleBlistNode *node;
280 PurpleAccount *account = purple_connection_get_account(gc);
281 printf("Account connected: %s %s\n", account->username, account->protocol_id);
284 static void loopListsfree(void) {
289 EINA_LIST_FOREACH(timerList, tlist, fref) {
290 if (fref && fref->fdh)
291 ecore_main_fd_handler_del(fref->fdh);
292 timerList = eina_list_remove(timerList, fref);
296 EINA_LIST_FOREACH(inputList, tlist, tref) {
297 if (tref && tref->timer)
298 ecore_timer_del(tref->timer);
299 inputList = eina_list_remove(inputList, tref);
303 eina_list_free(timerList);
304 eina_list_free(inputList);
307 static void signed_off(PurpleConnection *gc, gpointer null)
309 printf("Connection is gone :(...\n ");
310 ecore_main_loop_quit();
314 connect_to_signals_for_demonstration_purposes_only(void)
317 purple_signal_connect(purple_connections_get_handle(), "signed-on", &handle,
318 PURPLE_CALLBACK(signed_on), NULL);
321 purple_signal_connect(purple_connections_get_handle(), "signed-off", &handle2,
322 PURPLE_CALLBACK(signed_off), NULL);
325 int main(int argc, char *argv[])
330 PurpleAccount *account;
331 PurpleSavedStatus *status;
334 /* libpurple's built-in DNS resolution forks processes to perform
335 * blocking lookups without blocking the main process. It does not
336 * handle SIGCHLD itself, so if the UI does not you quickly get an army
337 * of zombie subprocesses marching around.
339 signal(SIGCHLD, SIG_IGN);
346 printf("libpurple initialized.\n");
350 Eina_List *names = NULL;
351 iter = purple_plugins_get_protocols();
352 for (i = 0; iter; iter = iter->next) {
353 PurplePlugin *plugin = iter->data;
354 PurplePluginInfo *info = plugin->info;
355 if (info && info->name) {
356 printf("\t%d: %s\n", i++, info->name);
357 names = eina_list_append(names, info->id);
361 printf("Select the protocol [0-%d]: ", i-1);
362 res = fgets(name, sizeof(name), stdin);
364 fprintf(stderr, "Failed to gets protocol selection.");
367 sscanf(name, "%d", &num);
368 prpl = eina_list_nth(names, num);
370 printf("Username: ");
371 res = fgets(name, sizeof(name), stdin);
373 fprintf(stderr, "Failed to read user name.");
376 name[strlen(name) - 1] = 0; /* strip the \n at the end */
378 /* Create the account */
379 account = purple_account_new(name, prpl);
381 /* Get the password for the account */
382 password = getpass("Password: ");
383 purple_account_set_password(account, password);
385 /* It's necessary to enable the account first. */
386 purple_account_set_enabled(account, UI_ID, TRUE);
388 /* Now, to connect the account(s), create a status and activate it. */
389 status = purple_savedstatus_new(NULL, PURPLE_STATUS_INVISIBLE);
390 purple_savedstatus_activate(status);
392 connect_to_signals_for_demonstration_purposes_only();
394 ecore_main_loop_begin();
396 ecore_main_loop_quit();
398 eina_list_shutdown();