2 * Copyright (C) 2002 Peter Zelezny.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
36 typedef struct session xchat_context
;
37 #include "xchat-plugin.h"
43 /* the USE_PLUGIN define only removes libdl stuff */
55 /* crafted to be an even 32 bytes */
58 xchat_plugin
*pl
; /* the plugin to which it belongs */
59 char *name
; /* "xdcc" */
60 void *callback
; /* pointer to xdcc_callback */
61 char *help_text
; /* help_text for commands only */
62 void *userdata
; /* passed to the callback */
63 int tag
; /* for timers & FDs only */
64 int type
; /* HOOK_* */
65 int pri
; /* fd */ /* priority / fd for HOOK_FD only */
70 int type
; /* LIST_* */
71 GSList
*pos
; /* current pos */
72 GSList
*next
; /* next pos */
73 GSList
*head
; /* for LIST_USERS only */
74 struct notify_per_server
*notifyps
; /* notify_per_server * */
77 typedef int (xchat_cmd_cb
) (char *word
[], char *word_eol
[], void *user_data
);
78 typedef int (xchat_serv_cb
) (char *word
[], char *word_eol
[], void *user_data
);
79 typedef int (xchat_print_cb
) (char *word
[], void *user_data
);
80 typedef int (xchat_fd_cb
) (int fd
, int flags
, void *user_data
);
81 typedef int (xchat_timer_cb
) (void *user_data
);
82 typedef int (xchat_init_func
) (xchat_plugin
*, char **, char **, char **, char *);
83 typedef int (xchat_deinit_func
) (xchat_plugin
*);
96 HOOK_COMMAND
, /* /command */
97 HOOK_SERVER
, /* PRIVMSG, NOTICE, numerics */
98 HOOK_PRINT
, /* All print events */
99 HOOK_TIMER
, /* timeouts */
100 HOOK_FD
, /* sockets & fds */
101 HOOK_DELETED
/* marked for deletion */
104 GSList
*plugin_list
= NULL
; /* export for plugingui.c */
105 static GSList
*hook_list
= NULL
;
107 extern const struct prefs vars
[]; /* cfgfiles.c */
110 /* unload a plugin and remove it from our linked list */
113 plugin_free (xchat_plugin
*pl
, int do_deinit
, int allow_refuse
)
117 xchat_deinit_func
*deinit_func
;
119 /* fake plugin added by xchat_plugingui_add() */
123 /* run the plugin's deinit routine, if any */
124 if (do_deinit
&& pl
->deinit_callback
!= NULL
)
126 deinit_func
= pl
->deinit_callback
;
127 if (!deinit_func (pl
) && allow_refuse
)
131 /* remove all of this plugin's hooks */
138 xchat_unhook (NULL
, hook
);
145 g_module_close (pl
->handle
);
147 dlclose (pl
->handle
);
152 if (pl
->free_strings
)
162 free ((char *)pl
->filename
);
165 plugin_list
= g_slist_remove (plugin_list
, pl
);
168 fe_pluginlist_update ();
174 static xchat_plugin
*
175 plugin_list_add (xchat_context
*ctx
, char *filename
, const char *name
,
176 const char *desc
, const char *version
, void *handle
,
177 void *deinit_func
, int fake
, int free_strings
)
181 pl
= malloc (sizeof (xchat_plugin
));
183 pl
->filename
= filename
;
185 pl
->name
= (char *)name
;
186 pl
->desc
= (char *)desc
;
187 pl
->version
= (char *)version
;
188 pl
->deinit_callback
= deinit_func
;
190 pl
->free_strings
= free_strings
; /* free() name,desc,version? */
192 plugin_list
= g_slist_prepend (plugin_list
, pl
);
198 xchat_dummy (xchat_plugin
*ph
)
203 /* Load a static plugin */
206 plugin_add (session
*sess
, char *filename
, void *handle
, void *init_func
,
207 void *deinit_func
, char *arg
, int fake
)
214 file
= strdup (filename
);
216 pl
= plugin_list_add (sess
, file
, file
, NULL
, NULL
, handle
, deinit_func
,
221 /* win32 uses these because it doesn't have --export-dynamic! */
222 pl
->xchat_hook_command
= xchat_hook_command
;
223 pl
->xchat_hook_server
= xchat_hook_server
;
224 pl
->xchat_hook_print
= xchat_hook_print
;
225 pl
->xchat_hook_timer
= xchat_hook_timer
;
226 pl
->xchat_hook_fd
= xchat_hook_fd
;
227 pl
->xchat_unhook
= xchat_unhook
;
228 pl
->xchat_print
= xchat_print
;
229 pl
->xchat_printf
= xchat_printf
;
230 pl
->xchat_command
= xchat_command
;
231 pl
->xchat_commandf
= xchat_commandf
;
232 pl
->xchat_nickcmp
= xchat_nickcmp
;
233 pl
->xchat_set_context
= xchat_set_context
;
234 pl
->xchat_find_context
= xchat_find_context
;
235 pl
->xchat_get_context
= xchat_get_context
;
236 pl
->xchat_get_info
= xchat_get_info
;
237 pl
->xchat_get_prefs
= xchat_get_prefs
;
238 pl
->xchat_list_get
= xchat_list_get
;
239 pl
->xchat_list_free
= xchat_list_free
;
240 pl
->xchat_list_fields
= xchat_list_fields
;
241 pl
->xchat_list_str
= xchat_list_str
;
242 pl
->xchat_list_next
= xchat_list_next
;
243 pl
->xchat_list_int
= xchat_list_int
;
244 pl
->xchat_plugingui_add
= xchat_plugingui_add
;
245 pl
->xchat_plugingui_remove
= xchat_plugingui_remove
;
246 pl
->xchat_emit_print
= xchat_emit_print
;
247 pl
->xchat_read_fd
= xchat_dummy
;
248 pl
->xchat_list_time
= xchat_list_time
;
249 pl
->xchat_gettext
= xchat_gettext
;
250 pl
->xchat_send_modes
= xchat_send_modes
;
251 pl
->xchat_strip
= xchat_strip
;
252 pl
->xchat_free
= xchat_free
;
254 /* incase new plugins are loaded on older xchat */
255 pl
->xchat_dummy4
= xchat_dummy
;
256 pl
->xchat_dummy3
= xchat_dummy
;
257 pl
->xchat_dummy2
= xchat_dummy
;
258 pl
->xchat_dummy1
= xchat_dummy
;
260 /* run xchat_plugin_init, if it returns 0, close the plugin */
261 if (((xchat_init_func
*)init_func
) (pl
, &pl
->name
, &pl
->desc
, &pl
->version
, arg
) == 0)
263 plugin_free (pl
, FALSE
, FALSE
);
269 fe_pluginlist_update ();
273 /* kill any plugin by the given (file) name (used by /unload) */
276 plugin_kill (char *name
, int by_filename
)
285 /* static-plugins (plugin-timer.c) have a NULL filename */
286 if ((by_filename
&& pl
->filename
&& strcasecmp (name
, pl
->filename
) == 0) ||
287 (by_filename
&& pl
->filename
&& strcasecmp (name
, file_part (pl
->filename
)) == 0) ||
288 (!by_filename
&& strcasecmp (name
, pl
->name
) == 0))
290 /* statically linked plugins have a NULL filename */
291 if (pl
->filename
!= NULL
&& !pl
->fake
)
293 if (plugin_free (pl
, TRUE
, TRUE
))
304 /* kill all running plugins (at shutdown) */
307 plugin_kill_all (void)
318 plugin_free (list
->data
, TRUE
, FALSE
);
325 /* load a plugin from a filename. Returns: NULL-success or an error string */
328 plugin_load (session
*sess
, char *filename
, char *arg
)
331 xchat_init_func
*init_func
;
332 xchat_deinit_func
*deinit_func
;
335 /* load the plugin */
336 handle
= g_module_open (filename
, 0);
338 return (char *)g_module_error ();
340 /* find the init routine xchat_plugin_init */
341 if (!g_module_symbol (handle
, "xchat_plugin_init", (gpointer
*)&init_func
))
343 g_module_close (handle
);
344 return _("No xchat_plugin_init symbol; is this really an xchat plugin?");
347 /* find the plugin's deinit routine, if any */
348 if (!g_module_symbol (handle
, "xchat_plugin_deinit", (gpointer
*)&deinit_func
))
355 /* OpenBSD lacks this! */
357 #define RTLD_GLOBAL 0
364 /* get the filename without path */
365 filepart
= file_part (filename
);
367 /* load the plugin */
369 /* xsys draws in libgtk-1.2, causing crashes, so force RTLD_LOCAL */
370 (strstr (filepart
, "local") || strncmp (filepart
, "libxsys-1", 9) == 0)
372 handle
= dlopen (filename
, RTLD_NOW
);
374 handle
= dlopen (filename
, RTLD_GLOBAL
| RTLD_NOW
);
376 return (char *)dlerror ();
377 dlerror (); /* Clear any existing error */
379 /* find the init routine xchat_plugin_init */
380 init_func
= dlsym (handle
, "xchat_plugin_init");
381 error
= (char *)dlerror ();
385 return _("No xchat_plugin_init symbol; is this really an xchat plugin?");
388 /* find the plugin's deinit routine, if any */
389 deinit_func
= dlsym (handle
, "xchat_plugin_deinit");
390 error
= (char *)dlerror ();
393 /* add it to our linked list */
394 plugin_add (sess
, filename
, handle
, init_func
, deinit_func
, arg
, FALSE
);
402 plugin_auto_load_cb (char *filename
)
406 if (!strcmp (file_part (filename
), "dbus.so"))
409 pMsg
= plugin_load (ps
, filename
, NULL
);
412 PrintTextf (ps
, "AutoLoad failed for: %s\n", filename
);
413 PrintText (ps
, pMsg
);
418 plugin_auto_load (session
*sess
)
421 for_files (XCHATLIBDIR
"/plugins", "*.so", plugin_auto_load_cb
);
422 for_files (get_xdir_fs (), "*.so", plugin_auto_load_cb
);
428 plugin_hook_find (GSList
*list
, int type
, char *name
)
435 if (hook
->type
== type
)
437 if (strcasecmp (hook
->name
, name
) == 0)
440 if (type
== HOOK_SERVER
)
442 if (strcasecmp (hook
->name
, "RAW LINE") == 0)
452 /* check for plugin hooks and run them */
455 plugin_hook_run (session
*sess
, char *name
, char *word
[], char *word_eol
[], int type
)
464 list
= plugin_hook_find (list
, type
, name
);
470 hook
->pl
->context
= sess
;
472 /* run the plugin's callback function */
476 ret
= ((xchat_cmd_cb
*)hook
->callback
) (word
, word_eol
, hook
->userdata
);
479 ret
= ((xchat_serv_cb
*)hook
->callback
) (word
, word_eol
, hook
->userdata
);
481 default: /*case HOOK_PRINT:*/
482 ret
= ((xchat_print_cb
*)hook
->callback
) (word
, hook
->userdata
);
486 if ((ret
& XCHAT_EAT_XCHAT
) && (ret
& XCHAT_EAT_PLUGIN
))
491 if (ret
& XCHAT_EAT_PLUGIN
)
492 goto xit
; /* stop running plugins */
493 if (ret
& XCHAT_EAT_XCHAT
)
494 eat
= 1; /* eventually we'll return 1, but continue running plugins */
500 /* really remove deleted hooks now */
506 if (hook
->type
== HOOK_DELETED
)
508 hook_list
= g_slist_remove (hook_list
, hook
);
517 /* execute a plugged in command. Called from outbound.c */
520 plugin_emit_command (session
*sess
, char *name
, char *word
[], char *word_eol
[])
522 return plugin_hook_run (sess
, name
, word
, word_eol
, HOOK_COMMAND
);
525 /* got a server PRIVMSG, NOTICE, numeric etc... */
528 plugin_emit_server (session
*sess
, char *name
, char *word
[], char *word_eol
[])
530 return plugin_hook_run (sess
, name
, word
, word_eol
, HOOK_SERVER
);
533 /* see if any plugins are interested in this print event */
536 plugin_emit_print (session
*sess
, char *word
[])
538 return plugin_hook_run (sess
, word
[0], word
, NULL
, HOOK_PRINT
);
542 plugin_emit_dummy_print (session
*sess
, char *name
)
548 for (i
= 1; i
< 32; i
++)
551 return plugin_hook_run (sess
, name
, word
, NULL
, HOOK_PRINT
);
555 plugin_emit_keypress (session
*sess
, unsigned int state
, unsigned int keyval
,
556 int len
, char *string
)
558 char *word
[PDIWORDS
];
567 sprintf (keyval_str
, "%u", keyval
);
568 sprintf (state_str
, "%u", state
);
569 sprintf (len_str
, "%d", len
);
571 word
[0] = "Key Press";
572 word
[1] = keyval_str
;
576 for (i
= 5; i
< PDIWORDS
; i
++)
579 return plugin_hook_run (sess
, word
[0], word
, NULL
, HOOK_PRINT
);
583 plugin_timeout_cb (xchat_hook
*hook
)
587 /* timer_cb's context starts as front-most-tab */
588 hook
->pl
->context
= current_sess
;
590 /* call the plugin's timeout function */
591 ret
= ((xchat_timer_cb
*)hook
->callback
) (hook
->userdata
);
593 /* the callback might have already unhooked it! */
594 if (!g_slist_find (hook_list
, hook
) || hook
->type
== HOOK_DELETED
)
599 hook
->tag
= 0; /* avoid fe_timeout_remove, returning 0 is enough! */
600 xchat_unhook (hook
->pl
, hook
);
606 /* insert a hook into hook_list according to its priority */
609 plugin_insert_hook (xchat_hook
*new_hook
)
618 if (hook
->type
== new_hook
->type
&& hook
->pri
<= new_hook
->pri
)
620 hook_list
= g_slist_insert_before (hook_list
, list
, new_hook
);
626 hook_list
= g_slist_append (hook_list
, new_hook
);
630 plugin_fd_cb (GIOChannel
*source
, GIOCondition condition
, xchat_hook
*hook
)
633 typedef int (xchat_fd_cb2
) (int fd
, int flags
, void *user_data
, GIOChannel
*);
635 if (condition
& G_IO_IN
)
636 flags
|= XCHAT_FD_READ
;
637 if (condition
& G_IO_OUT
)
638 flags
|= XCHAT_FD_WRITE
;
639 if (condition
& G_IO_PRI
)
640 flags
|= XCHAT_FD_EXCEPTION
;
642 ret
= ((xchat_fd_cb2
*)hook
->callback
) (hook
->pri
, flags
, hook
->userdata
, source
);
644 /* the callback might have already unhooked it! */
645 if (!g_slist_find (hook_list
, hook
) || hook
->type
== HOOK_DELETED
)
650 hook
->tag
= 0; /* avoid fe_input_remove, returning 0 is enough! */
651 xchat_unhook (hook
->pl
, hook
);
657 /* allocate and add a hook to our list. Used for all 4 types */
660 plugin_add_hook (xchat_plugin
*pl
, int type
, int pri
, const char *name
,
661 const char *help_text
, void *callb
, int timeout
, void *userdata
)
665 hook
= malloc (sizeof (xchat_hook
));
666 memset (hook
, 0, sizeof (xchat_hook
));
671 hook
->name
= strdup (name
);
673 hook
->help_text
= strdup (help_text
);
674 hook
->callback
= callb
;
676 hook
->userdata
= userdata
;
678 /* insert it into the linked list */
679 plugin_insert_hook (hook
);
681 if (type
== HOOK_TIMER
)
682 hook
->tag
= fe_timeout_add (timeout
, plugin_timeout_cb
, hook
);
688 plugin_command_list(GList
*tmp_list
)
691 GSList
*list
= hook_list
;
696 if (hook
->type
== HOOK_COMMAND
)
697 tmp_list
= g_list_prepend(tmp_list
, hook
->name
);
704 plugin_command_foreach (session
*sess
, void *userdata
,
705 void (*cb
) (session
*sess
, void *userdata
, char *name
, char *help
))
714 if (hook
->type
== HOOK_COMMAND
&& hook
->name
[0])
716 cb (sess
, userdata
, hook
->name
, hook
->help_text
);
723 plugin_show_help (session
*sess
, char *cmd
)
728 list
= plugin_hook_find (hook_list
, HOOK_COMMAND
, cmd
);
734 PrintText (sess
, hook
->help_text
);
742 /* ========================================================= */
743 /* ===== these are the functions plugins actually call ===== */
744 /* ========================================================= */
747 xchat_unhook (xchat_plugin
*ph
, xchat_hook
*hook
)
749 /* perl.c trips this */
750 if (!g_slist_find (hook_list
, hook
) || hook
->type
== HOOK_DELETED
)
753 if (hook
->type
== HOOK_TIMER
&& hook
->tag
!= 0)
754 fe_timeout_remove (hook
->tag
);
756 if (hook
->type
== HOOK_FD
&& hook
->tag
!= 0)
757 fe_input_remove (hook
->tag
);
759 hook
->type
= HOOK_DELETED
; /* expunge later */
762 free (hook
->name
); /* NULL for timers & fds */
764 free (hook
->help_text
); /* NULL for non-commands */
766 return hook
->userdata
;
770 xchat_hook_command (xchat_plugin
*ph
, const char *name
, int pri
,
771 xchat_cmd_cb
*callb
, const char *help_text
, void *userdata
)
773 return plugin_add_hook (ph
, HOOK_COMMAND
, pri
, name
, help_text
, callb
, 0,
778 xchat_hook_server (xchat_plugin
*ph
, const char *name
, int pri
,
779 xchat_serv_cb
*callb
, void *userdata
)
781 return plugin_add_hook (ph
, HOOK_SERVER
, pri
, name
, 0, callb
, 0, userdata
);
785 xchat_hook_print (xchat_plugin
*ph
, const char *name
, int pri
,
786 xchat_print_cb
*callb
, void *userdata
)
788 return plugin_add_hook (ph
, HOOK_PRINT
, pri
, name
, 0, callb
, 0, userdata
);
792 xchat_hook_timer (xchat_plugin
*ph
, int timeout
, xchat_timer_cb
*callb
,
795 return plugin_add_hook (ph
, HOOK_TIMER
, 0, 0, 0, callb
, timeout
, userdata
);
799 xchat_hook_fd (xchat_plugin
*ph
, int fd
, int flags
,
800 xchat_fd_cb
*callb
, void *userdata
)
804 hook
= plugin_add_hook (ph
, HOOK_FD
, 0, 0, 0, callb
, 0, userdata
);
806 /* plugin hook_fd flags correspond exactly to FIA_* flags (fe.h) */
807 hook
->tag
= fe_input_add (fd
, flags
, plugin_fd_cb
, hook
);
813 xchat_print (xchat_plugin
*ph
, const char *text
)
815 if (!is_session (ph
->context
))
817 DEBUG(PrintTextf(0, "%s\txchat_print called without a valid context.\n", ph
->name
));
821 PrintText (ph
->context
, (char *)text
);
825 xchat_printf (xchat_plugin
*ph
, const char *format
, ...)
830 va_start (args
, format
);
831 buf
= g_strdup_vprintf (format
, args
);
834 xchat_print (ph
, buf
);
839 xchat_command (xchat_plugin
*ph
, const char *command
)
844 if (!is_session (ph
->context
))
846 DEBUG(PrintTextf(0, "%s\txchat_command called without a valid context.\n", ph
->name
));
850 /* scripts/plugins continue to send non-UTF8... *sigh* */
851 conv
= text_validate ((char **)&command
, &len
);
852 handle_command (ph
->context
, (char *)command
, FALSE
);
857 xchat_commandf (xchat_plugin
*ph
, const char *format
, ...)
862 va_start (args
, format
);
863 buf
= g_strdup_vprintf (format
, args
);
866 xchat_command (ph
, buf
);
871 xchat_nickcmp (xchat_plugin
*ph
, const char *s1
, const char *s2
)
873 return ((session
*)ph
->context
)->server
->p_cmp (s1
, s2
);
877 xchat_get_context (xchat_plugin
*ph
)
883 xchat_set_context (xchat_plugin
*ph
, xchat_context
*context
)
885 if (is_session (context
))
887 ph
->context
= context
;
894 xchat_find_context (xchat_plugin
*ph
, const char *servname
, const char *channel
)
896 GSList
*slist
, *clist
, *sessions
= NULL
;
901 if (servname
== NULL
&& channel
== NULL
)
908 netname
= server_get_network (serv
, TRUE
);
910 if (servname
== NULL
||
911 rfc_casecmp (servname
, serv
->servername
) == 0 ||
912 strcasecmp (servname
, serv
->hostname
) == 0 ||
913 strcasecmp (servname
, netname
) == 0)
916 return serv
->front_session
;
922 if (sess
->server
== serv
)
924 if (rfc_casecmp (channel
, sess
->channel
) == 0)
926 if (sess
->server
== ph
->context
->server
)
928 g_slist_free (sessions
);
932 sessions
= g_slist_prepend (sessions
, sess
);
944 sessions
= g_slist_reverse (sessions
);
945 sess
= sessions
->data
;
946 g_slist_free (sessions
);
954 xchat_get_info (xchat_plugin
*ph
, const char *id
)
960 if (!strncmp (id
, "event_text", 10))
962 char *e
= (char *)id
+ 10;
963 if (*e
== ' ') e
++; /* 2.8.0 only worked without a space */
964 return text_find_format_string (e
);
967 hash
= str_hash (id
);
968 /* do the session independant ones first */
971 case 0x325acab5: /* libdirfs */
974 case 0x14f51cd8: /* version */
975 return PACKAGE_VERSION
;
977 case 0xdd9b1abd: /* xchatdir */
978 return get_xdir_utf8 ();
980 case 0xe33f6c4a: /* xchatdirfs */
981 return get_xdir_fs ();
985 if (!is_session (sess
))
987 DEBUG(PrintTextf(0, "%s\txchat_get_info called without a valid context.\n", ph
->name
));
993 case 0x2de2ee: /* away */
994 if (sess
->server
->is_away
)
995 return sess
->server
->last_away_reason
;
998 case 0x2c0b7d03: /* channel */
999 return sess
->channel
;
1001 case 0x2c0d614c: /* charset */
1005 if (sess
->server
->encoding
)
1006 return sess
->server
->encoding
;
1009 g_get_charset (&locale
);
1013 case 0x30f5a8: /* host */
1014 return sess
->server
->hostname
;
1016 case 0x1c0e99c1: /* inputbox */
1017 return fe_get_inputbox_contents (sess
);
1019 case 0x633fb30: /* modes */
1020 return sess
->current_modes
;
1022 case 0x6de15a2e: /* network */
1023 return server_get_network (sess
->server
, FALSE
);
1025 case 0x339763: /* nick */
1026 return sess
->server
->nick
;
1028 case 0xca022f43: /* server */
1029 if (!sess
->server
->connected
)
1031 return sess
->server
->servername
;
1033 case 0x696cd2f: /* topic */
1036 case 0x3419f12d: /* gtkwin_ptr */
1037 return fe_gui_info_ptr (sess
, 1);
1039 case 0x506d600b: /* native win_ptr */
1040 return fe_gui_info_ptr (sess
, 0);
1042 case 0x6d3431b5: /* win_status */
1043 switch (fe_gui_info (sess
, 0)) /* check window status */
1045 case 0: return "normal";
1046 case 1: return "active";
1047 case 2: return "hidden";
1056 xchat_get_prefs (xchat_plugin
*ph
, const char *name
, const char **string
, int *integer
)
1060 /* some special run-time info (not really prefs, but may aswell throw it in here) */
1061 switch (str_hash (name
))
1063 case 0xf82136c4: /* state_cursor */
1064 *integer
= fe_get_inputbox_cursor (ph
->context
);
1067 case 0xd1b: /* id */
1068 *integer
= ph
->context
->server
->id
;
1074 if (!strcasecmp (name
, vars
[i
].name
))
1076 switch (vars
[i
].type
)
1079 *string
= ((char *) &prefs
+ vars
[i
].offset
);
1083 *integer
= *((int *) &prefs
+ vars
[i
].offset
);
1088 if (*((int *) &prefs
+ vars
[i
].offset
))
1097 while (vars
[i
].name
);
1103 xchat_list_get (xchat_plugin
*ph
, const char *name
)
1107 list
= malloc (sizeof (xchat_list
));
1110 switch (str_hash (name
))
1112 case 0x556423d0: /* channels */
1113 list
->type
= LIST_CHANNELS
;
1114 list
->next
= sess_list
;
1117 case 0x183c4: /* dcc */
1118 list
->type
= LIST_DCC
;
1119 list
->next
= dcc_list
;
1122 case 0xb90bfdd2: /* ignore */
1123 list
->type
= LIST_IGNORE
;
1124 list
->next
= ignore_list
;
1127 case 0xc2079749: /* notify */
1128 list
->type
= LIST_NOTIFY
;
1129 list
->next
= notify_list
;
1130 list
->head
= (void *)ph
->context
; /* reuse this pointer */
1133 case 0x6a68e08: /* users */
1134 if (is_session (ph
->context
))
1136 list
->type
= LIST_USERS
;
1137 list
->head
= list
->next
= userlist_flat_list (ph
->context
);
1138 fe_userlist_set_selected (ph
->context
);
1140 } /* fall through */
1151 xchat_list_free (xchat_plugin
*ph
, xchat_list
*xlist
)
1153 if (xlist
->type
== LIST_USERS
)
1154 g_slist_free (xlist
->head
);
1159 xchat_list_next (xchat_plugin
*ph
, xchat_list
*xlist
)
1161 if (xlist
->next
== NULL
)
1164 xlist
->pos
= xlist
->next
;
1165 xlist
->next
= xlist
->pos
->next
;
1167 /* NOTIFY LIST: Find the entry which matches the context
1168 of the plugin when list_get was originally called. */
1169 if (xlist
->type
== LIST_NOTIFY
)
1171 xlist
->notifyps
= notify_find_server_entry (xlist
->pos
->data
,
1172 ((session
*)xlist
->head
)->server
);
1173 if (!xlist
->notifyps
)
1180 const char * const *
1181 xchat_list_fields (xchat_plugin
*ph
, const char *name
)
1183 static const char * const dcc_fields
[] =
1185 "iaddress32","icps", "sdestfile","sfile", "snick", "iport",
1186 "ipos", "iposhigh", "iresume", "iresumehigh", "isize", "isizehigh", "istatus", "itype", NULL
1188 static const char * const channels_fields
[] =
1190 "schannel", "schantypes", "pcontext", "iflags", "iid", "ilag", "imaxmodes",
1191 "snetwork", "snickmodes", "snickprefixes", "iqueue", "sserver", "itype", "iusers",
1194 static const char * const ignore_fields
[] =
1196 "iflags", "smask", NULL
1198 static const char * const notify_fields
[] =
1200 "iflags", "snetworks", "snick", "toff", "ton", "tseen", NULL
1202 static const char * const users_fields
[] =
1204 "iaway", "shost", "tlasttalk", "snick", "sprefix", "srealname", "iselected", NULL
1206 static const char * const list_of_lists
[] =
1208 "channels", "dcc", "ignore", "notify", "users", NULL
1211 switch (str_hash (name
))
1213 case 0x556423d0: /* channels */
1214 return channels_fields
;
1215 case 0x183c4: /* dcc */
1217 case 0xb90bfdd2: /* ignore */
1218 return ignore_fields
;
1219 case 0xc2079749: /* notify */
1220 return notify_fields
;
1221 case 0x6a68e08: /* users */
1222 return users_fields
;
1223 case 0x6236395: /* lists */
1224 return list_of_lists
;
1231 xchat_list_time (xchat_plugin
*ph
, xchat_list
*xlist
, const char *name
)
1233 guint32 hash
= str_hash (name
);
1236 switch (xlist
->type
)
1239 if (!xlist
->notifyps
)
1243 case 0x1ad6f: /* off */
1244 return xlist
->notifyps
->lastoff
;
1245 case 0xddf: /* on */
1246 return xlist
->notifyps
->laston
;
1247 case 0x35ce7b: /* seen */
1248 return xlist
->notifyps
->lastseen
;
1253 data
= xlist
->pos
->data
;
1256 case 0xa9118c42: /* lasttalk */
1257 return ((struct User
*)data
)->lasttalk
;
1265 xchat_list_str (xchat_plugin
*ph
, xchat_list
*xlist
, const char *name
)
1267 guint32 hash
= str_hash (name
);
1268 gpointer data
= ph
->context
;
1269 int type
= LIST_CHANNELS
;
1271 /* a NULL xlist is a shortcut to current "channels" context */
1274 data
= xlist
->pos
->data
;
1283 case 0x2c0b7d03: /* channel */
1284 return ((session
*)data
)->channel
;
1285 case 0x577e0867: /* chantypes */
1286 return ((session
*)data
)->server
->chantypes
;
1287 case 0x38b735af: /* context */
1288 return data
; /* this is a session * */
1289 case 0x6de15a2e: /* network */
1290 return server_get_network (((session
*)data
)->server
, FALSE
);
1291 case 0x8455e723: /* nickprefixes */
1292 return ((session
*)data
)->server
->nick_prefixes
;
1293 case 0x829689ad: /* nickmodes */
1294 return ((session
*)data
)->server
->nick_modes
;
1295 case 0xca022f43: /* server */
1296 return ((session
*)data
)->server
->servername
;
1303 case 0x3d9ad31e: /* destfile */
1304 return ((struct DCC
*)data
)->destfile
;
1305 case 0x2ff57c: /* file */
1306 return ((struct DCC
*)data
)->file
;
1307 case 0x339763: /* nick */
1308 return ((struct DCC
*)data
)->nick
;
1315 case 0x3306ec: /* mask */
1316 return ((struct ignore
*)data
)->mask
;
1323 case 0x4e49ec05: /* networks */
1324 return ((struct notify
*)data
)->networks
;
1325 case 0x339763: /* nick */
1326 return ((struct notify
*)data
)->name
;
1333 case 0x339763: /* nick */
1334 return ((struct User
*)data
)->nick
;
1335 case 0x30f5a8: /* host */
1336 return ((struct User
*)data
)->hostname
;
1337 case 0xc594b292: /* prefix */
1338 return ((struct User
*)data
)->prefix
;
1339 case 0xccc6d529: /* realname */
1340 return ((struct User
*)data
)->realname
;
1349 xchat_list_int (xchat_plugin
*ph
, xchat_list
*xlist
, const char *name
)
1351 guint32 hash
= str_hash (name
);
1352 gpointer data
= ph
->context
;
1353 int tmp
, type
= LIST_CHANNELS
;
1355 /* a NULL xlist is a shortcut to current "channels" context */
1358 data
= xlist
->pos
->data
;
1367 case 0x34207553: /* address32 */
1368 return ((struct DCC
*)data
)->addr
;
1369 case 0x181a6: /* cps */
1370 return ((struct DCC
*)data
)->cps
;
1371 case 0x349881: /* port */
1372 return ((struct DCC
*)data
)->port
;
1373 case 0x1b254: /* pos */
1374 return ((struct DCC
*)data
)->pos
& 0xffffffff;
1375 case 0xe8a945f6: /* poshigh */
1377 return (((struct DCC
*)data
)->pos
>> 32) & 0xffffffff;
1379 return (((struct DCC
*)data
)->pos
);
1381 case 0xc84dc82d: /* resume */
1382 return ((struct DCC
*)data
)->resumable
& 0xffffffff;
1383 case 0xded4c74f: /* resumehigh */
1385 return (((struct DCC
*)data
)->resumable
>> 32) & 0xffffffff;
1387 return (((struct DCC
*)data
)->resumable
);
1389 case 0x35e001: /* size */
1390 return ((struct DCC
*)data
)->size
& 0xffffffff;
1391 case 0x3284d523: /* sizehigh */
1393 return (((struct DCC
*)data
)->size
>> 32) & 0xffffffff;
1395 return (((struct DCC
*)data
)->size
);
1397 case 0xcacdcff2: /* status */
1398 return ((struct DCC
*)data
)->dccstat
;
1399 case 0x368f3a: /* type */
1400 return ((struct DCC
*)data
)->type
;
1407 case 0x5cfee87: /* flags */
1408 return ((struct ignore
*)data
)->type
;
1415 case 0xd1b: /* id */
1416 return ((struct session
*)data
)->server
->id
;
1417 case 0x5cfee87: /* flags */
1418 tmp
= ((struct session
*)data
)->alert_taskbar
; /* bit 10 */
1420 tmp
|= ((struct session
*)data
)->alert_tray
; /* 9 */
1422 tmp
|= ((struct session
*)data
)->alert_beep
; /* 8 */
1424 /*tmp |= ((struct session *)data)->color_paste;*/ /* 7 */
1426 tmp
|= ((struct session
*)data
)->text_hidejoinpart
; /* 6 */
1428 tmp
|= ((struct session
*)data
)->server
->have_idmsg
; /* 5 */
1430 tmp
|= ((struct session
*)data
)->server
->have_whox
; /* 4 */
1432 tmp
|= ((struct session
*)data
)->server
->end_of_motd
;/* 3 */
1434 tmp
|= ((struct session
*)data
)->server
->is_away
; /* 2 */
1436 tmp
|= ((struct session
*)data
)->server
->connecting
; /* 1 */
1438 tmp
|= ((struct session
*)data
)->server
->connected
; /* 0 */
1440 case 0x1a192: /* lag */
1441 return ((struct session
*)data
)->server
->lag
;
1442 case 0x1916144c: /* maxmodes */
1443 return ((struct session
*)data
)->server
->modes_per_line
;
1444 case 0x66f1911: /* queue */
1445 return ((struct session
*)data
)->server
->sendq_len
;
1446 case 0x368f3a: /* type */
1447 return ((struct session
*)data
)->type
;
1448 case 0x6a68e08: /* users */
1449 return ((struct session
*)data
)->total
;
1454 if (!xlist
->notifyps
)
1458 case 0x5cfee87: /* flags */
1459 return xlist
->notifyps
->ison
;
1465 case 0x2de2ee: /* away */
1466 return ((struct User
*)data
)->away
;
1467 case 0x4705f29b: /* selected */
1468 return ((struct User
*)data
)->selected
;
1478 xchat_plugingui_add (xchat_plugin
*ph
, const char *filename
,
1479 const char *name
, const char *desc
,
1480 const char *version
, char *reserved
)
1483 ph
= plugin_list_add (NULL
, strdup (filename
), strdup (name
), strdup (desc
),
1484 strdup (version
), NULL
, NULL
, TRUE
, TRUE
);
1485 fe_pluginlist_update ();
1492 xchat_plugingui_remove (xchat_plugin
*ph
, void *handle
)
1495 plugin_free (handle
, FALSE
, FALSE
);
1500 xchat_emit_print (xchat_plugin
*ph
, const char *event_name
, ...)
1503 /* currently only 4 because no events use more than 4.
1504 This can be easily expanded without breaking the API. */
1505 char *argv
[4] = {NULL
, NULL
, NULL
, NULL
};
1508 va_start (args
, event_name
);
1511 argv
[i
] = va_arg (args
, char *);
1519 i
= text_emit_by_name ((char *)event_name
, ph
->context
, argv
[0], argv
[1],
1527 xchat_gettext (xchat_plugin
*ph
, const char *msgid
)
1529 /* so that plugins can use xchat's internal gettext strings. */
1530 /* e.g. The EXEC plugin uses this on Windows. */
1535 xchat_send_modes (xchat_plugin
*ph
, const char **targets
, int ntargets
, int modes_per_line
, char sign
, char mode
)
1537 char tbuf
[514]; /* modes.c needs 512 + null */
1539 send_channel_modes (ph
->context
, tbuf
, (char **)targets
, 0, ntargets
, sign
, mode
, modes_per_line
);
1543 xchat_strip (xchat_plugin
*ph
, const char *str
, int len
, int flags
)
1545 return strip_color ((char *)str
, len
, flags
);
1549 xchat_free (xchat_plugin
*ph
, void *ptr
)