2 my $message = shift @_;
3 my ($package) = caller;
5 # redirect Gtk/Glib errors and warnings back to STDERR
6 my $message_levels = qr/ERROR|CRITICAL|WARNING|MESSAGE|INFO|DEBUG/i;
7 if( $message =~ /^(?:Gtk|GLib|Gdk)(?:-\w+)?-$message_levels/i ) {
11 if( defined &Xchat
::Internal
::print ) {
12 Xchat
::print( $message );
20 use File
::Basename
();
28 use base
qw(Exporter);
51 sub Xchat
::Internal
::context_info
;
52 sub Xchat
::Internal
::print;
56 qw(PRI_HIGHEST PRI_HIGH PRI_NORM PRI_LOW PRI_LOWEST), # priorities
57 qw(EAT_NONE EAT_XCHAT EAT_PLUGIN EAT_ALL), # callback return values
58 qw(FD_READ FD_WRITE FD_EXCEPTION FD_NOTSOCKET), # fd flags
59 qw(KEEP REMOVE), # timers
62 qw(hook_server hook_command hook_print hook_timer hook_fd unhook),
65 qw(register nickcmp strip_code send_modes), # misc
66 qw(print prnt printf prntf command commandf emit_print), # output
67 qw(find_context get_context set_context), # context
68 qw(get_info get_prefs get_list context_info user_info), # input
72 $EXPORT_TAGS{all
} = [ map { @
{$_} } @EXPORT_TAGS{qw(constants hooks util)}];
73 our @EXPORT = @
{$EXPORT_TAGS{constants
}};
74 our @EXPORT_OK = @
{$EXPORT_TAGS{all
}};
77 my ($package, $calling_package) = Xchat
::Embed
::find_pkg
();
78 my $pkg_info = Xchat
::Embed
::pkg_info
( $package );
79 my $filename = $pkg_info->{filename
};
80 my ($name, $version, $description, $callback) = @_;
82 if( defined $pkg_info->{gui_entry
} ) {
83 Xchat
::print( "Xchat::register called more than once in "
84 . $pkg_info->{filename
} );
88 $description = "" unless defined $description;
90 $callback = Xchat
::Embed
::fix_callback
(
91 $package, $calling_package, $callback
94 $pkg_info->{shutdown} = $callback;
95 unless( $name && $name =~ /[[:print:]\w]/ ) {
96 $name = "Not supplied";
98 unless( $version && $version =~ /\d+(?:\.\d+)?/ ) {
101 $pkg_info->{gui_entry
} =
102 Xchat
::Internal
::register
( $name, $version, $description, $filename );
103 # keep with old behavior
107 sub _process_hook_options
{
108 my ($options, $keys, $store) = @_;
110 unless( @
$keys == @
$store ) {
111 die 'Number of keys must match the size of the store';
116 if( ref( $options ) eq 'HASH' ) {
117 for my $index ( 0 .. @
$keys - 1 ) {
118 my $key = $keys->[$index];
119 if( exists( $options->{ $key } ) && defined( $options->{ $key } ) ) {
120 ${$store->[$index]} = $options->{ $key };
128 return undef unless @_ >= 2;
130 my $callback = shift;
132 my ($package, $calling_package) = Xchat
::Embed
::find_pkg
();
134 $callback = Xchat
::Embed
::fix_callback
(
135 $package, $calling_package, $callback
138 my ($priority, $data) = ( Xchat
::PRI_NORM
, undef );
139 _process_hook_options
(
142 [\
($priority, $data)],
145 my $pkg_info = Xchat
::Embed
::pkg_info
( $package );
146 my $hook = Xchat
::Internal
::hook_server
(
147 $message, $priority, $callback, $data, $package
149 push @
{$pkg_info->{hooks
}}, $hook if defined $hook;
154 return undef unless @_ >= 2;
156 my $callback = shift;
158 my ($package, $calling_package) = Xchat
::Embed
::find_pkg
();
160 $callback = Xchat
::Embed
::fix_callback
(
161 $package, $calling_package, $callback
164 my ($priority, $help_text, $data) = ( Xchat
::PRI_NORM
, undef, undef );
165 _process_hook_options
(
167 [qw(priority help_text data)],
168 [\
($priority, $help_text, $data)],
171 my $pkg_info = Xchat
::Embed
::pkg_info
( $package );
172 my $hook = Xchat
::Internal
::hook_command
(
173 $command, $priority, $callback, $help_text, $data, $package
175 push @
{$pkg_info->{hooks
}}, $hook if defined $hook;
180 return undef unless @_ >= 2;
182 my $callback = shift;
184 my ($package, $calling_package) = Xchat
::Embed
::find_pkg
();
186 $callback = Xchat
::Embed
::fix_callback
(
187 $package, $calling_package, $callback
190 my ($priority, $run_after, $filter, $data) = ( Xchat
::PRI_NORM
, 0, 0, undef );
191 _process_hook_options
(
193 [qw(priority run_after_event filter data)],
194 [\
($priority, $run_after, $filter, $data)],
197 if( $run_after and $filter ) {
198 Carp
::carp
( "Xchat::hook_print's run_after_event and filter options are mutually exclusive, you can only use of them at a time per hook" );
209 if( ref $run_after eq 'CODE' ) {
210 $run_after->( @args );
222 my $event_data = $_[1];
223 my $event_name = $event;
224 my $last_arg = @args - 1;
226 my @new = $cb->( \
@args, $event_data, $event_name );
228 # allow changing event by returning the new value
230 $event_name = pop @new;
233 # a filter can either return the new results or it can modify
235 if( @new == @args ) {
236 emit_print
( $event_name, @new[ 0 .. $last_arg ] );
239 join( "\0", @
{$_[0]} ) ne join( "\0", @args[ 0 .. $last_arg ] )
241 emit_print
( $event_name, @args[ 0 .. $last_arg ] );
250 my $pkg_info = Xchat
::Embed
::pkg_info
( $package );
251 my $hook = Xchat
::Internal
::hook_print
(
252 $event, $priority, $callback, $data, $package
254 push @
{$pkg_info->{hooks
}}, $hook if defined $hook;
259 return undef unless @_ >= 2;
260 my ($timeout, $callback, $data) = @_;
261 my ($package, $calling_package) = Xchat
::Embed
::find_pkg
();
263 $callback = Xchat
::Embed
::fix_callback
(
264 $package, $calling_package, $callback
268 ref( $data ) eq 'HASH' && exists( $data->{data
} )
269 && defined( $data->{data
} )
271 $data = $data->{data
};
274 my $pkg_info = Xchat
::Embed
::pkg_info
( $package );
275 my $hook = Xchat
::Internal
::hook_timer
( $timeout, $callback, $data, $package );
276 push @
{$pkg_info->{hooks
}}, $hook if defined $hook;
281 return undef unless @_ >= 2;
282 my ($fd, $callback, $options) = @_;
283 return undef unless defined $fd && defined $callback;
285 my $fileno = fileno $fd;
286 return undef unless defined $fileno; # no underlying fd for this handle
288 my ($package, $calling_package) = Xchat
::Embed
::find_pkg
();
289 $callback = Xchat
::Embed
::fix_callback
(
290 $package, $calling_package, $callback
293 my ($flags, $data) = (Xchat
::FD_READ
, undef);
294 _process_hook_options
(
301 my $userdata = shift;
302 return $userdata->{CB
}->(
303 $userdata->{FD
}, $userdata->{FLAGS
}, $userdata->{DATA
},
307 my $pkg_info = Xchat
::Embed
::pkg_info
( $package );
308 my $hook = Xchat
::Internal
::hook_fd
(
309 $fileno, $cb, $flags, {
310 DATA
=> $data, FD
=> $fd, CB
=> $callback, FLAGS
=> $flags,
314 push @
{$pkg_info->{hooks
}}, $hook if defined $hook;
320 my $package = shift @_;
321 ($package) = caller unless $package;
322 my $pkg_info = Xchat
::Embed
::pkg_info
( $package );
326 && grep { $_ == $hook } @
{$pkg_info->{hooks
}} ) {
327 $pkg_info->{hooks
} = [grep { $_ != $hook } @
{$pkg_info->{hooks
}}];
328 return Xchat
::Internal
::unhook
( $hook );
334 my ($cb, $channels, $servers) = @_;
336 # not specifying any channels or servers is not the same as specifying
338 # - not specifying either results in calling the callback inthe current ctx
339 # - specifying undef for for both results in calling the callback in the
340 # front/currently selected tab
341 if( @_ == 3 && !($channels || $servers) ) {
342 $channels = [ undef ];
343 $servers = [ undef ];
344 } elsif( !($channels || $servers) ) {
349 $channels = [ $channels ] unless ref( $channels ) eq 'ARRAY';
352 $servers = [ $servers ] unless ref( $servers ) eq 'ARRAY';
354 $servers = [ undef ];
358 my $old_ctx = Xchat
::get_context
();
359 for my $server ( @
$servers ) {
360 for my $channel ( @
$channels ) {
361 if( Xchat
::set_context
( $channel, $server ) ) {
367 Xchat
::set_context
( $old_ctx );
373 return "" unless defined $text;
374 if( ref( $text ) eq 'ARRAY' ) {
376 $text = join $, , @
$text;
378 $text = join "", @
$text;
383 sub { Xchat
::Internal
::print( $text ); },
390 Xchat
::print( sprintf( $format, @_ ) );
393 # make Xchat::prnt() and Xchat::prntf() as aliases for Xchat::print() and
394 # Xchat::printf(), mainly useful when these functions are exported
405 return "" unless defined $command;
408 if( ref( $command ) eq 'ARRAY' ) {
409 @commands = @
$command;
411 @commands = ($command);
415 sub { Xchat
::Internal
::command
( $_ ) foreach @commands },
422 Xchat
::command
( sprintf( $format, @_ ) );
428 my ($channel, $server) = @_;
429 $context = Xchat
::find_context
( $channel, $server );
431 if( defined $_[0] && $_[0] =~ /^\d+$/ ) {
434 $context = Xchat
::find_context
( $_[0] );
437 $context = Xchat
::find_context
();
439 return $context ? Xchat
::Internal
::set_context
( $context ) : 0;
446 if( defined( $id ) ) {
447 if( grep { $id eq $_ } qw(state_cursor id) ) {
448 $info = Xchat
::get_prefs
( $id );
450 $info = Xchat
::Internal
::get_info
( $id );
457 my $nick = Xchat
::strip_code
(shift @_ || Xchat
::get_info
( "nick" ));
459 for (Xchat
::get_list
( "users" ) ) {
460 if ( Xchat
::nickcmp
( $_->{nick
}, $nick ) == 0 ) {
469 my $ctx = shift @_ || Xchat
::get_context
;
470 my $old_ctx = Xchat
::get_context
;
472 qw(away channel charset host id inputbox libdirfs modes network),
473 qw(nick nickserv server topic version win_ptr win_status),
474 qw(xchatdir xchatdirfs state_cursor),
477 if( Xchat
::set_context
( $ctx ) ) {
479 for my $field ( @fields ) {
480 $info{$field} = Xchat
::get_info
( $field );
483 my $ctx_info = Xchat
::Internal
::context_info
;
484 @info{keys %$ctx_info} = values %$ctx_info;
486 Xchat
::set_context
( $old_ctx );
487 return %info if wantarray;
495 unless( grep { $_[0] eq $_ } qw(channels dcc ignore notify users networks) ) {
496 Carp
::carp
( "'$_[0]' does not appear to be a valid list name" );
498 if( $_[0] eq 'networks' ) {
499 return Xchat
::List
::Network
->get();
501 return Xchat
::Internal
::get_list
( $_[0] );
508 \cC\d
{0,2}(?
:,\d
{1,2})?
| #Color
509 \e\
[(?
:\d
{1,2}(?
:;\d
{1,2})*)?m
| # ANSI color code
516 if( defined wantarray ) {
518 $msg =~ s/$pattern//g;
521 $_[0] =~ s/$pattern//g if defined $_[0];