1 /*
2 * plugins.c
3 * vim: expandtab:ts=4:sts=4:sw=4
4 *
5 * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
6 *
7 * This file is part of Profanity.
8 *
9 * Profanity is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * Profanity is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with Profanity. If not, see <https://www.gnu.org/licenses/>.
21 *
22 * In addition, as a special exception, the copyright holders give permission to
23 * link the code of portions of this program with the OpenSSL library under
24 * certain conditions as described in each individual source file, and
25 * distribute linked combinations including the two.
26 *
27 * You must obey the GNU General Public License in all respects for all of the
28 * code used other than OpenSSL. If you modify file(s) with this exception, you
29 * may extend this exception to your version of the file(s), but you are not
30 * obligated to do so. If you do not wish to do so, delete this exception
31 * statement from your version. If you delete this exception statement from all
32 * source files in the program, then also delete it here.
33 *
34 */
35
36 #include <string.h>
37 #include <stdlib.h>
38 #include <gio/gio.h>
39
40 #include "log.h"
41 #include "config.h"
42 #include "common.h"
43 #include "config/files.h"
44 #include "config/preferences.h"
45 #include "event/client_events.h"
46 #include "plugins/callbacks.h"
47 #include "plugins/autocompleters.h"
48 #include "plugins/api.h"
49 #include "plugins/plugins.h"
50 #include "plugins/themes.h"
51 #include "plugins/settings.h"
52 #include "plugins/disco.h"
53 #include "ui/ui.h"
54 #include "xmpp/xmpp.h"
55
56 #ifdef HAVE_PYTHON
57 #include "plugins/python_plugins.h"
58 #include "plugins/python_api.h"
59 #endif
60
61 #ifdef HAVE_C
62 #include "plugins/c_plugins.h"
63 #include "plugins/c_api.h"
64 #endif
65
66 static GHashTable* plugins;
67
68 void
plugins_init(void)69 plugins_init(void)
70 {
71 plugins = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL);
72 callbacks_init();
73 autocompleters_init();
74 plugin_themes_init();
75 plugin_settings_init();
76
77 #ifdef HAVE_PYTHON
78 python_env_init();
79 #endif
80 #ifdef HAVE_C
81 c_env_init();
82 #endif
83
84 // load plugins
85 gchar** plugins_pref = prefs_get_plugins();
86 if (plugins_pref) {
87 for (int i = 0; i < g_strv_length(plugins_pref); i++) {
88 gboolean loaded = FALSE;
89 gchar* filename = plugins_pref[i];
90 #ifdef HAVE_PYTHON
91 if (g_str_has_suffix(filename, ".py")) {
92 ProfPlugin* plugin = python_plugin_create(filename);
93 if (plugin) {
94 g_hash_table_insert(plugins, strdup(filename), plugin);
95 loaded = TRUE;
96 }
97 }
98 #endif
99 #ifdef HAVE_C
100 if (g_str_has_suffix(filename, ".so")) {
101 ProfPlugin* plugin = c_plugin_create(filename);
102 if (plugin) {
103 g_hash_table_insert(plugins, strdup(filename), plugin);
104 loaded = TRUE;
105 }
106 }
107 #endif
108 if (loaded) {
109 log_info("Loaded plugin: %s", filename);
110 } else {
111 log_info("Failed to load plugin: %s", filename);
112 }
113 }
114
115 // initialise plugins
116 GList* values = g_hash_table_get_values(plugins);
117 GList* curr = values;
118 while (curr) {
119 ProfPlugin* plugin = curr->data;
120 plugin->init_func(plugin, PACKAGE_VERSION, PACKAGE_STATUS, NULL, NULL);
121 curr = g_list_next(curr);
122 }
123 g_list_free(values);
124 }
125
126 prefs_free_plugins(plugins_pref);
127
128 return;
129 }
130
131 void
plugins_free_install_result(PluginsInstallResult * result)132 plugins_free_install_result(PluginsInstallResult* result)
133 {
134 if (!result) {
135 return;
136 }
137 g_slist_free_full(result->installed, free);
138 g_slist_free_full(result->failed, free);
139 }
140
141 PluginsInstallResult*
plugins_install_all(const char * const path)142 plugins_install_all(const char* const path)
143 {
144 PluginsInstallResult* result = malloc(sizeof(PluginsInstallResult));
145 result->installed = NULL;
146 result->failed = NULL;
147 GSList* contents = NULL;
148 get_file_paths_recursive(path, &contents);
149
150 GSList* curr = contents;
151 GString* error_message = NULL;
152 while (curr) {
153 error_message = g_string_new(NULL);
154 if (g_str_has_suffix(curr->data, ".py") || g_str_has_suffix(curr->data, ".so")) {
155 gchar* plugin_name = g_path_get_basename(curr->data);
156 if (plugins_install(plugin_name, curr->data, error_message)) {
157 result->installed = g_slist_append(result->installed, strdup(curr->data));
158 } else {
159 result->failed = g_slist_append(result->failed, strdup(curr->data));
160 }
161 }
162 curr = g_slist_next(curr);
163 g_string_free(error_message, TRUE);
164 }
165
166 g_slist_free_full(contents, g_free);
167
168 return result;
169 }
170
171 gboolean
plugins_uninstall(const char * const plugin_name)172 plugins_uninstall(const char* const plugin_name)
173 {
174 plugins_unload(plugin_name);
175 char* plugins_dir = files_get_data_path(DIR_PLUGINS);
176 GString* target_path = g_string_new(plugins_dir);
177 free(plugins_dir);
178 g_string_append(target_path, "/");
179 g_string_append(target_path, plugin_name);
180 GFile* file = g_file_new_for_path(target_path->str);
181 GError* error = NULL;
182 gboolean result = g_file_delete(file, NULL, &error);
183 g_object_unref(file);
184 g_error_free(error);
185 g_string_free(target_path, TRUE);
186 return result;
187 }
188
189 gboolean
plugins_install(const char * const plugin_name,const char * const filename,GString * error_message)190 plugins_install(const char* const plugin_name, const char* const filename, GString* error_message)
191 {
192 char* plugins_dir = files_get_data_path(DIR_PLUGINS);
193 GString* target_path = g_string_new(plugins_dir);
194 free(plugins_dir);
195 g_string_append(target_path, "/");
196 g_string_append(target_path, plugin_name);
197
198 if (g_file_test(target_path->str, G_FILE_TEST_EXISTS)) {
199 log_info("Failed to install plugin: %s, file exists", plugin_name);
200 g_string_assign(error_message, "File exists");
201 return FALSE;
202 }
203
204 gboolean result = copy_file(filename, target_path->str, false);
205 g_string_free(target_path, TRUE);
206
207 if (result) {
208 result = plugins_load(plugin_name, error_message);
209 }
210 return result;
211 }
212
213 GSList*
plugins_load_all(void)214 plugins_load_all(void)
215 {
216 GSList* plugins = plugins_unloaded_list();
217 GSList* loaded = NULL;
218 GSList* curr = plugins;
219 GString* error_message = NULL;
220 while (curr) {
221 error_message = g_string_new(NULL);
222 if (plugins_load(curr->data, error_message)) {
223 loaded = g_slist_append(loaded, strdup(curr->data));
224 }
225 curr = g_slist_next(curr);
226 g_string_free(error_message, TRUE);
227 }
228 g_slist_free_full(plugins, g_free);
229
230 return loaded;
231 }
232
233 gboolean
plugins_load(const char * const name,GString * error_message)234 plugins_load(const char* const name, GString* error_message)
235 {
236 ProfPlugin* plugin = g_hash_table_lookup(plugins, name);
237 if (plugin) {
238 log_info("Failed to load plugin: %s, plugin already loaded", name);
239 return FALSE;
240 }
241
242 if (g_str_has_suffix(name, ".py")) {
243 #ifdef HAVE_PYTHON
244 plugin = python_plugin_create(name);
245 #else
246 g_string_assign(error_message, "Python plugins support is disabled.");
247 #endif
248 }
249
250 if (g_str_has_suffix(name, ".so")) {
251 #ifdef HAVE_C
252 plugin = c_plugin_create(name);
253 #else
254 g_string_assign(error_message, "C plugins support is disabled.");
255 #endif
256 }
257 if (plugin) {
258 g_hash_table_insert(plugins, strdup(name), plugin);
259 if (connection_get_status() == JABBER_CONNECTED) {
260 const char* account_name = session_get_account_name();
261 const char* fulljid = connection_get_fulljid();
262 plugin->init_func(plugin, PACKAGE_VERSION, PACKAGE_STATUS, account_name, fulljid);
263 } else {
264 plugin->init_func(plugin, PACKAGE_VERSION, PACKAGE_STATUS, NULL, NULL);
265 }
266 log_info("Loaded plugin: %s", name);
267 prefs_add_plugin(name);
268 return TRUE;
269 } else {
270 log_info("Failed to load plugin: %s", name);
271 return FALSE;
272 }
273 }
274
275 gboolean
plugins_unload_all(void)276 plugins_unload_all(void)
277 {
278 gboolean result = TRUE;
279 GList* plugin_names = g_hash_table_get_keys(plugins);
280 GList* plugin_names_dup = NULL;
281 GList* curr = plugin_names;
282 while (curr) {
283 plugin_names_dup = g_list_append(plugin_names_dup, strdup(curr->data));
284 curr = g_list_next(curr);
285 }
286 g_list_free(plugin_names);
287
288 curr = plugin_names_dup;
289 while (curr) {
290 if (!plugins_unload(curr->data)) {
291 result = FALSE;
292 }
293 curr = g_list_next(curr);
294 }
295
296 g_list_free_full(plugin_names_dup, free);
297
298 return result;
299 }
300
301 gboolean
plugins_unload(const char * const name)302 plugins_unload(const char* const name)
303 {
304 ProfPlugin* plugin = g_hash_table_lookup(plugins, name);
305 if (plugin) {
306 plugin->on_unload_func(plugin);
307 #ifdef HAVE_PYTHON
308 if (plugin->lang == LANG_PYTHON) {
309 python_plugin_destroy(plugin);
310 }
311 #endif
312 #ifdef HAVE_C
313 if (plugin->lang == LANG_C) {
314 c_plugin_destroy(plugin);
315 }
316 #endif
317 prefs_remove_plugin(name);
318 g_hash_table_remove(plugins, name);
319
320 caps_reset_ver();
321 // resend presence to update server's disco info data for this client
322 if (connection_get_status() == JABBER_CONNECTED) {
323 char* account_name = session_get_account_name();
324 resource_presence_t last_presence = accounts_get_last_presence(account_name);
325 cl_ev_presence_send(last_presence, 0);
326 }
327 return TRUE;
328 }
329 return FALSE;
330 }
331
332 void
plugins_reload_all(void)333 plugins_reload_all(void)
334 {
335 GList* plugin_names = g_hash_table_get_keys(plugins);
336 GList* plugin_names_dup = NULL;
337 GList* curr = plugin_names;
338 while (curr) {
339 plugin_names_dup = g_list_append(plugin_names_dup, strdup(curr->data));
340 curr = g_list_next(curr);
341 }
342 g_list_free(plugin_names);
343
344 GString* error_message = NULL;
345 curr = plugin_names_dup;
346 while (curr) {
347 error_message = g_string_new(NULL);
348 plugins_reload(curr->data, error_message);
349 g_string_free(error_message, TRUE);
350 curr = g_list_next(curr);
351 }
352
353 g_list_free_full(plugin_names_dup, free);
354 }
355
356 gboolean
plugins_reload(const char * const name,GString * error_message)357 plugins_reload(const char* const name, GString* error_message)
358 {
359 gboolean res = plugins_unload(name);
360 if (res) {
361 res = plugins_load(name, error_message);
362 }
363
364 return res;
365 }
366
367 void
_plugins_unloaded_list_dir(const gchar * const dir,GSList ** result)368 _plugins_unloaded_list_dir(const gchar* const dir, GSList** result)
369 {
370 GDir* plugins_dir = g_dir_open(dir, 0, NULL);
371 if (plugins_dir == NULL) {
372 return;
373 }
374
375 const gchar* plugin = g_dir_read_name(plugins_dir);
376 while (plugin) {
377 ProfPlugin* found = g_hash_table_lookup(plugins, plugin);
378 if ((g_str_has_suffix(plugin, ".so") || g_str_has_suffix(plugin, ".py")) && !found) {
379 *result = g_slist_append(*result, strdup(plugin));
380 }
381 plugin = g_dir_read_name(plugins_dir);
382 }
383 g_dir_close(plugins_dir);
384 }
385
386 GSList*
plugins_unloaded_list(void)387 plugins_unloaded_list(void)
388 {
389 GSList* result = NULL;
390 char* plugins_dir = files_get_data_path(DIR_PLUGINS);
391 _plugins_unloaded_list_dir(plugins_dir, &result);
392 free(plugins_dir);
393
394 return result;
395 }
396
397 GList*
plugins_loaded_list(void)398 plugins_loaded_list(void)
399 {
400 return g_hash_table_get_keys(plugins);
401 }
402
403 char*
plugins_autocomplete(const char * const input,gboolean previous)404 plugins_autocomplete(const char* const input, gboolean previous)
405 {
406 return autocompleters_complete(input, previous);
407 }
408
409 void
plugins_reset_autocomplete(void)410 plugins_reset_autocomplete(void)
411 {
412 autocompleters_reset();
413 }
414
415 void
plugins_win_process_line(char * win,const char * const line)416 plugins_win_process_line(char* win, const char* const line)
417 {
418 PluginWindowCallback* window = callbacks_get_window_handler(win);
419 if (window) {
420 window->callback_exec(window, win, line);
421 }
422 }
423
424 void
plugins_close_win(const char * const plugin_name,const char * const tag)425 plugins_close_win(const char* const plugin_name, const char* const tag)
426 {
427 callbacks_remove_win(plugin_name, tag);
428 }
429
430 void
plugins_on_start(void)431 plugins_on_start(void)
432 {
433 GList* values = g_hash_table_get_values(plugins);
434 GList* curr = values;
435 while (curr) {
436 ProfPlugin* plugin = curr->data;
437 plugin->on_start_func(plugin);
438 curr = g_list_next(curr);
439 }
440 g_list_free(values);
441 }
442
443 void
plugins_on_shutdown(void)444 plugins_on_shutdown(void)
445 {
446 GList* values = g_hash_table_get_values(plugins);
447 GList* curr = values;
448 while (curr) {
449 ProfPlugin* plugin = curr->data;
450 plugin->on_shutdown_func(plugin);
451 curr = g_list_next(curr);
452 }
453 g_list_free(values);
454 }
455
456 void
plugins_on_connect(const char * const account_name,const char * const fulljid)457 plugins_on_connect(const char* const account_name, const char* const fulljid)
458 {
459 GList* values = g_hash_table_get_values(plugins);
460 GList* curr = values;
461 while (curr) {
462 ProfPlugin* plugin = curr->data;
463 plugin->on_connect_func(plugin, account_name, fulljid);
464 curr = g_list_next(curr);
465 }
466 g_list_free(values);
467 }
468
469 void
plugins_on_disconnect(const char * const account_name,const char * const fulljid)470 plugins_on_disconnect(const char* const account_name, const char* const fulljid)
471 {
472 GList* values = g_hash_table_get_values(plugins);
473 GList* curr = values;
474 while (curr) {
475 ProfPlugin* plugin = curr->data;
476 plugin->on_disconnect_func(plugin, account_name, fulljid);
477 curr = g_list_next(curr);
478 }
479 g_list_free(values);
480 }
481
482 char*
plugins_pre_chat_message_display(const char * const barejid,const char * const resource,const char * message)483 plugins_pre_chat_message_display(const char* const barejid, const char* const resource, const char* message)
484 {
485 char* new_message = NULL;
486 char* curr_message = strdup(message);
487
488 GList* values = g_hash_table_get_values(plugins);
489 GList* curr = values;
490 while (curr) {
491 ProfPlugin* plugin = curr->data;
492 new_message = plugin->pre_chat_message_display(plugin, barejid, resource, curr_message);
493 if (new_message) {
494 free(curr_message);
495 curr_message = strdup(new_message);
496 free(new_message);
497 }
498 curr = g_list_next(curr);
499 }
500 g_list_free(values);
501
502 return curr_message;
503 }
504
505 void
plugins_post_chat_message_display(const char * const barejid,const char * const resource,const char * message)506 plugins_post_chat_message_display(const char* const barejid, const char* const resource, const char* message)
507 {
508 GList* values = g_hash_table_get_values(plugins);
509 GList* curr = values;
510 while (curr) {
511 ProfPlugin* plugin = curr->data;
512 plugin->post_chat_message_display(plugin, barejid, resource, message);
513 curr = g_list_next(curr);
514 }
515 g_list_free(values);
516 }
517
518 char*
plugins_pre_chat_message_send(const char * const barejid,const char * message)519 plugins_pre_chat_message_send(const char* const barejid, const char* message)
520 {
521 char* new_message = NULL;
522 char* curr_message = strdup(message);
523
524 GList* values = g_hash_table_get_values(plugins);
525 GList* curr = values;
526 while (curr) {
527 ProfPlugin* plugin = curr->data;
528 if (plugin->contains_hook(plugin, "prof_pre_chat_message_send")) {
529 new_message = plugin->pre_chat_message_send(plugin, barejid, curr_message);
530 if (new_message) {
531 free(curr_message);
532 curr_message = strdup(new_message);
533 free(new_message);
534 } else {
535 free(curr_message);
536 g_list_free(values);
537
538 return NULL;
539 }
540 }
541 curr = g_list_next(curr);
542 }
543 g_list_free(values);
544
545 return curr_message;
546 }
547
548 void
plugins_post_chat_message_send(const char * const barejid,const char * message)549 plugins_post_chat_message_send(const char* const barejid, const char* message)
550 {
551 GList* values = g_hash_table_get_values(plugins);
552 GList* curr = values;
553 while (curr) {
554 ProfPlugin* plugin = curr->data;
555 plugin->post_chat_message_send(plugin, barejid, message);
556 curr = g_list_next(curr);
557 }
558 g_list_free(values);
559 }
560
561 char*
plugins_pre_room_message_display(const char * const barejid,const char * const nick,const char * message)562 plugins_pre_room_message_display(const char* const barejid, const char* const nick, const char* message)
563 {
564 char* new_message = NULL;
565 char* curr_message = strdup(message);
566
567 GList* values = g_hash_table_get_values(plugins);
568 GList* curr = values;
569 while (curr) {
570 ProfPlugin* plugin = curr->data;
571 new_message = plugin->pre_room_message_display(plugin, barejid, nick, curr_message);
572 if (new_message) {
573 free(curr_message);
574 curr_message = strdup(new_message);
575 free(new_message);
576 }
577 curr = g_list_next(curr);
578 }
579 g_list_free(values);
580
581 return curr_message;
582 }
583
584 void
plugins_post_room_message_display(const char * const barejid,const char * const nick,const char * message)585 plugins_post_room_message_display(const char* const barejid, const char* const nick, const char* message)
586 {
587 GList* values = g_hash_table_get_values(plugins);
588 GList* curr = values;
589 while (curr) {
590 ProfPlugin* plugin = curr->data;
591 plugin->post_room_message_display(plugin, barejid, nick, message);
592 curr = g_list_next(curr);
593 }
594 g_list_free(values);
595 }
596
597 char*
plugins_pre_room_message_send(const char * const barejid,const char * message)598 plugins_pre_room_message_send(const char* const barejid, const char* message)
599 {
600 char* new_message = NULL;
601 char* curr_message = strdup(message);
602
603 GList* values = g_hash_table_get_values(plugins);
604 GList* curr = values;
605 while (curr) {
606 ProfPlugin* plugin = curr->data;
607 if (plugin->contains_hook(plugin, "prof_pre_room_message_send")) {
608 new_message = plugin->pre_room_message_send(plugin, barejid, curr_message);
609 if (new_message) {
610 free(curr_message);
611 curr_message = strdup(new_message);
612 free(new_message);
613 } else {
614 free(curr_message);
615 g_list_free(values);
616
617 return NULL;
618 }
619 }
620 curr = g_list_next(curr);
621 }
622 g_list_free(values);
623
624 return curr_message;
625 }
626
627 void
plugins_post_room_message_send(const char * const barejid,const char * message)628 plugins_post_room_message_send(const char* const barejid, const char* message)
629 {
630 GList* values = g_hash_table_get_values(plugins);
631 GList* curr = values;
632 while (curr) {
633 ProfPlugin* plugin = curr->data;
634 plugin->post_room_message_send(plugin, barejid, message);
635 curr = g_list_next(curr);
636 }
637 g_list_free(values);
638 }
639
640 void
plugins_on_room_history_message(const char * const barejid,const char * const nick,const char * const message,GDateTime * timestamp)641 plugins_on_room_history_message(const char* const barejid, const char* const nick, const char* const message,
642 GDateTime* timestamp)
643 {
644 char* timestamp_str = NULL;
645 GTimeVal timestamp_tv;
646 gboolean res = g_date_time_to_timeval(timestamp, ×tamp_tv);
647 if (res) {
648 timestamp_str = g_time_val_to_iso8601(×tamp_tv);
649 }
650
651 GList* values = g_hash_table_get_values(plugins);
652 GList* curr = values;
653 while (curr) {
654 ProfPlugin* plugin = curr->data;
655 plugin->on_room_history_message(plugin, barejid, nick, message, timestamp_str);
656 curr = g_list_next(curr);
657 }
658 g_list_free(values);
659
660 free(timestamp_str);
661 }
662
663 char*
plugins_pre_priv_message_display(const char * const fulljid,const char * message)664 plugins_pre_priv_message_display(const char* const fulljid, const char* message)
665 {
666 Jid* jidp = jid_create(fulljid);
667 char* new_message = NULL;
668 char* curr_message = strdup(message);
669
670 GList* values = g_hash_table_get_values(plugins);
671 GList* curr = values;
672 while (curr) {
673 ProfPlugin* plugin = curr->data;
674 new_message = plugin->pre_priv_message_display(plugin, jidp->barejid, jidp->resourcepart, curr_message);
675 if (new_message) {
676 free(curr_message);
677 curr_message = strdup(new_message);
678 free(new_message);
679 }
680 curr = g_list_next(curr);
681 }
682 g_list_free(values);
683
684 jid_destroy(jidp);
685 return curr_message;
686 }
687
688 void
plugins_post_priv_message_display(const char * const fulljid,const char * message)689 plugins_post_priv_message_display(const char* const fulljid, const char* message)
690 {
691 Jid* jidp = jid_create(fulljid);
692
693 GList* values = g_hash_table_get_values(plugins);
694 GList* curr = values;
695 while (curr) {
696 ProfPlugin* plugin = curr->data;
697 plugin->post_priv_message_display(plugin, jidp->barejid, jidp->resourcepart, message);
698 curr = g_list_next(curr);
699 }
700 g_list_free(values);
701
702 jid_destroy(jidp);
703 }
704
705 char*
plugins_pre_priv_message_send(const char * const fulljid,const char * const message)706 plugins_pre_priv_message_send(const char* const fulljid, const char* const message)
707 {
708 Jid* jidp = jid_create(fulljid);
709 char* new_message = NULL;
710 char* curr_message = strdup(message);
711
712 GList* values = g_hash_table_get_values(plugins);
713 GList* curr = values;
714 while (curr) {
715 ProfPlugin* plugin = curr->data;
716 if (plugin->contains_hook(plugin, "prof_pre_priv_message_send")) {
717 new_message = plugin->pre_priv_message_send(plugin, jidp->barejid, jidp->resourcepart, curr_message);
718 if (new_message) {
719 free(curr_message);
720 curr_message = strdup(new_message);
721 free(new_message);
722 } else {
723 free(curr_message);
724 g_list_free(values);
725 jid_destroy(jidp);
726
727 return NULL;
728 }
729 }
730 curr = g_list_next(curr);
731 }
732 g_list_free(values);
733
734 jid_destroy(jidp);
735 return curr_message;
736 }
737
738 void
plugins_post_priv_message_send(const char * const fulljid,const char * const message)739 plugins_post_priv_message_send(const char* const fulljid, const char* const message)
740 {
741 Jid* jidp = jid_create(fulljid);
742
743 GList* values = g_hash_table_get_values(plugins);
744 GList* curr = values;
745 while (curr) {
746 ProfPlugin* plugin = curr->data;
747 plugin->post_priv_message_send(plugin, jidp->barejid, jidp->resourcepart, message);
748 curr = g_list_next(curr);
749 }
750 g_list_free(values);
751
752 jid_destroy(jidp);
753 }
754
755 char*
plugins_on_message_stanza_send(const char * const text)756 plugins_on_message_stanza_send(const char* const text)
757 {
758 char* new_stanza = NULL;
759 char* curr_stanza = strdup(text);
760
761 GList* values = g_hash_table_get_values(plugins);
762 GList* curr = values;
763 while (curr) {
764 ProfPlugin* plugin = curr->data;
765 new_stanza = plugin->on_message_stanza_send(plugin, curr_stanza);
766 if (new_stanza) {
767 free(curr_stanza);
768 curr_stanza = strdup(new_stanza);
769 free(new_stanza);
770 }
771 curr = g_list_next(curr);
772 }
773 g_list_free(values);
774
775 return curr_stanza;
776 }
777
778 gboolean
plugins_on_message_stanza_receive(const char * const text)779 plugins_on_message_stanza_receive(const char* const text)
780 {
781 gboolean cont = TRUE;
782
783 GList* values = g_hash_table_get_values(plugins);
784 GList* curr = values;
785 while (curr) {
786 ProfPlugin* plugin = curr->data;
787 gboolean res = plugin->on_message_stanza_receive(plugin, text);
788 if (res == FALSE) {
789 cont = FALSE;
790 }
791 curr = g_list_next(curr);
792 }
793 g_list_free(values);
794
795 return cont;
796 }
797
798 char*
plugins_on_presence_stanza_send(const char * const text)799 plugins_on_presence_stanza_send(const char* const text)
800 {
801 char* new_stanza = NULL;
802 char* curr_stanza = strdup(text);
803
804 GList* values = g_hash_table_get_values(plugins);
805 GList* curr = values;
806 while (curr) {
807 ProfPlugin* plugin = curr->data;
808 new_stanza = plugin->on_presence_stanza_send(plugin, curr_stanza);
809 if (new_stanza) {
810 free(curr_stanza);
811 curr_stanza = strdup(new_stanza);
812 free(new_stanza);
813 }
814 curr = g_list_next(curr);
815 }
816 g_list_free(values);
817
818 return curr_stanza;
819 }
820
821 gboolean
plugins_on_presence_stanza_receive(const char * const text)822 plugins_on_presence_stanza_receive(const char* const text)
823 {
824 gboolean cont = TRUE;
825
826 GList* values = g_hash_table_get_values(plugins);
827 GList* curr = values;
828 while (curr) {
829 ProfPlugin* plugin = curr->data;
830 gboolean res = plugin->on_presence_stanza_receive(plugin, text);
831 if (res == FALSE) {
832 cont = FALSE;
833 }
834 curr = g_list_next(curr);
835 }
836 g_list_free(values);
837
838 return cont;
839 }
840
841 char*
plugins_on_iq_stanza_send(const char * const text)842 plugins_on_iq_stanza_send(const char* const text)
843 {
844 char* new_stanza = NULL;
845 char* curr_stanza = strdup(text);
846
847 GList* values = g_hash_table_get_values(plugins);
848 GList* curr = values;
849 while (curr) {
850 ProfPlugin* plugin = curr->data;
851 new_stanza = plugin->on_iq_stanza_send(plugin, curr_stanza);
852 if (new_stanza) {
853 free(curr_stanza);
854 curr_stanza = strdup(new_stanza);
855 free(new_stanza);
856 }
857 curr = g_list_next(curr);
858 }
859 g_list_free(values);
860
861 return curr_stanza;
862 }
863
864 gboolean
plugins_on_iq_stanza_receive(const char * const text)865 plugins_on_iq_stanza_receive(const char* const text)
866 {
867 gboolean cont = TRUE;
868
869 GList* values = g_hash_table_get_values(plugins);
870 GList* curr = values;
871 while (curr) {
872 ProfPlugin* plugin = curr->data;
873 gboolean res = plugin->on_iq_stanza_receive(plugin, text);
874 if (res == FALSE) {
875 cont = FALSE;
876 }
877 curr = g_list_next(curr);
878 }
879 g_list_free(values);
880
881 return cont;
882 }
883
884 void
plugins_on_contact_offline(const char * const barejid,const char * const resource,const char * const status)885 plugins_on_contact_offline(const char* const barejid, const char* const resource, const char* const status)
886 {
887 GList* values = g_hash_table_get_values(plugins);
888 GList* curr = values;
889 while (curr) {
890 ProfPlugin* plugin = curr->data;
891 plugin->on_contact_offline(plugin, barejid, resource, status);
892 curr = g_list_next(curr);
893 }
894 g_list_free(values);
895 }
896
897 void
plugins_on_contact_presence(const char * const barejid,const char * const resource,const char * const presence,const char * const status,const int priority)898 plugins_on_contact_presence(const char* const barejid, const char* const resource, const char* const presence, const char* const status, const int priority)
899 {
900 GList* values = g_hash_table_get_values(plugins);
901 GList* curr = values;
902 while (curr) {
903 ProfPlugin* plugin = curr->data;
904 plugin->on_contact_presence(plugin, barejid, resource, presence, status, priority);
905 curr = g_list_next(curr);
906 }
907 g_list_free(values);
908 }
909
910 void
plugins_on_chat_win_focus(const char * const barejid)911 plugins_on_chat_win_focus(const char* const barejid)
912 {
913 GList* values = g_hash_table_get_values(plugins);
914 GList* curr = values;
915 while (curr) {
916 ProfPlugin* plugin = curr->data;
917 plugin->on_chat_win_focus(plugin, barejid);
918 curr = g_list_next(curr);
919 }
920 g_list_free(values);
921 }
922
923 void
plugins_on_room_win_focus(const char * const barejid)924 plugins_on_room_win_focus(const char* const barejid)
925 {
926 GList* values = g_hash_table_get_values(plugins);
927 GList* curr = values;
928 while (curr) {
929 ProfPlugin* plugin = curr->data;
930 plugin->on_room_win_focus(plugin, barejid);
931 curr = g_list_next(curr);
932 }
933 g_list_free(values);
934 }
935
936 GList*
plugins_get_disco_features(void)937 plugins_get_disco_features(void)
938 {
939 return disco_get_features();
940 }
941
942 void
plugins_shutdown(void)943 plugins_shutdown(void)
944 {
945 GList* values = g_hash_table_get_values(plugins);
946 GList* curr = values;
947
948 while (curr) {
949 #ifdef HAVE_PYTHON
950 if (((ProfPlugin*)curr->data)->lang == LANG_PYTHON) {
951 python_plugin_destroy(curr->data);
952 }
953 #endif
954 #ifdef HAVE_C
955 if (((ProfPlugin*)curr->data)->lang == LANG_C) {
956 c_plugin_destroy(curr->data);
957 }
958 #endif
959
960 curr = g_list_next(curr);
961 }
962 g_list_free(values);
963 #ifdef HAVE_PYTHON
964 python_shutdown();
965 #endif
966 #ifdef HAVE_C
967 c_shutdown();
968 #endif
969
970 autocompleters_destroy();
971 plugin_themes_close();
972 plugin_settings_close();
973 callbacks_close();
974 disco_close();
975 g_hash_table_destroy(plugins);
976 plugins = NULL;
977 }
978