I neglected to remove this letter l because
[pidgin-git.git] / doc / PERL-HOWTO.dox
blob6b6eb9ecf413eedf56823e43483f4d9c5de43333
1 /** @page perl-howto Perl Scripting HOWTO
3 @section Introduction
4 libpurple Perl Plugins are set up very similarly to their C counterparts.  Most of the API calls are implemented and are divided into packages.  There are some significant differences between the Perl and C API.  Much like the C API, the best place to seek guidance is the source, which is located in the *.xs files in the [libpurple|pidgin]/plugins/perl/common directories.  The tutorial that follows will be example based and attempt to touch on some of the notable features of the embedded perl interpreter.  It is also important to note that some of the C API is missing in libpurple's perl API.
6 It is possible to get Gtk2-Perl to work with libpurple's Perl API, however you must not load the module with @c use, but rather with @c require.  Keep this in mind if you would like to use other perl modules that are dynamically loaded.  You can avoid the problem by always using @c require instead of @c use.
8 @section first-script Writing your first script
10 Let us start with a simple example of a perl plugin.  The following code sample is a complete plugin that can be copied and used as-is.
12 @code
13 use Purple;
15 %PLUGIN_INFO = (
16         perl_api_version => 2,
17         name => "Perl Test Plugin",
18         version => "0.1",
19         summary => "Test plugin for the Perl interpreter.",
20         description => "Your description here",
21         author => "John H. Kelm <johnhkelm\@gmail.com",
22         url => "http://pidgin.im",
24         load => "plugin_load",
25         unload => "plugin_unload"
28 sub plugin_init {
29         return %PLUGIN_INFO;
32 sub plugin_load {
33         my $plugin = shift;
34         Purple::Debug::info("testplugin", "plugin_load() - Test Plugin Loaded.\n");
37 sub plugin_unload {
38         my $plugin = shift;
39         Purple::Debug::info("testplugin", "plugin_unload() - Test Plugin Unloaded.\n");
41 @endcode
43 It is necessary to load the libpurple perl package with the @code use Purple; @endcode line; this makes all the libpurple perl API available to the script.  The @c \%PLUGIN_INFO hash contains all the information that will be displayed in the Plugin frame of the Preferences dialog, it also contains information about how the plugin is to be handled.  The @c load and @c unload keys specify subroutines to be called when the plugin is loaded and unloaded.  There are other key values that may be present in the @c \%PLUGIN_INFO hash; some of those will be covered in the following sections.
45 The Perl subroutine @c plugin_init is executed when the plugin is probed by the plugin subsystem.  What this means is that as soon as Pidgin or Finch is started, this subroutine is run once, regardless of whether or not the plugin is actually loaded. The other two subroutines present are the @c load and @c unload routines specified in the @c \%PLUGIN_INFO hash and will receive the plugin handle as an argument.  When the plugin is loaded and subsequently unloaded, it will print a message to the debug window using the @c Purple::Debug::info() API call.
47 In order to use this simple plugin, save the script text in a file with a @c .pl extension in your ~/.purple/plugins directory.  After restarting Pidgin, you should see the plugin  ("Perl Test Plugin") listed in the plugin list under "Tools -> Plugins".  To view the debug output, make sure you run Pidgin from the console with the '-d' flag or open the Debug Window which is available in the "Help" menu.  When you check the checkbox next the plugin, you should see a message appear in the Debug Window (or console); similarly, when you uncheck the checkbox you should see another message appear.  You have now created a framework that will allow you to create almost any kind of libpurple plugin you can imagine.
49 @section account-api Account and Account Option Functions
51 The Account API is in the @c Purple::Account:: and @c Purple::Accounts:: packages;
52 both are nearly identical to their C counterparts, @c purple_account_ and @c
53 purple_accounts_.  The Account Option API is in the @c Purple::Account::Option
54 package and is identical to the C implementation, @c purple_account_option.
56 The Account* APIs allow scripts to create, remove, and edit accounts.  An
57 account will have the Perl type of "PurpleAccount". (Note: Purple types have no real
58 meaning in perl scripts, other than that the types passed to perl subroutines
59 need to be correct.)  This section will not go into detail about the @c
60 Purple::Account::Option package since its use is mainly in building protocol
61 plugins, which are outside the scope of this document.  However, the API for the
62 @c Purple::Account::Option package should function as expected, should you need to
63 use it.
65 To reduce redundant code, the following code examples will use the simple plugin
66 from the previous section as a template.  To highlight some of the more useful
67 features of the Account API, we will be replacing the @c plugin_load perl
68 subroutine.  For testing purposes, we will display output on the command line by
69 using perl @c print commands.
71 @code
72 sub plugin_load {
73         $plugin = shift;
75         # Testing was done using Oscar, but this should work regardless of the protocol chosen
76         my $protocol = "prpl-oscar";
77         my $account_name = "test";
79         # Create a new Account
80         print "Testing: Purple::Account::new()... ";
81         $account = Purple::Account->new($account_name, $protocol);
82         if ($account) { print "ok.\n"; } else { print "fail.\n"; }
84         # Add a new Account
85         print "Testing: Purple::Account::add()...";
86         Purple::Accounts::add($account);
87         print "pending find...\n";
89         # Find the account we just added to verify its existence
90         print "Testing: Purple::Accounts::find()...";
91         $account = Purple::Accounts::find($account_name, $protocol);
92         if ($account) { print "ok.\n"; } else { print "fail.\n"; }
94         # Return the username
95         print "Testing: Purple::Account::get_username()... ";
96         $user_name = $account->get_username();
97         if ($user_name) {
98                 print "Success: $user_name.\n";
99         } else {
100                 print "Failed!\n";
101         }
102         # Verify if the user is connected
103         print "Testing: Purple::Account::is_connected()";
104         if ($account->is_connected()) {
105                 print " Connected.\n";
106         } else {
107                 print " Disconnected.\n";
108         }
110         # The status mechanism is how users are Connected, set Away,
111         # Disconnected (status set to Offline), etc
112         #  $status is now a Purple::Status perl type.
113         print "Testing: Purple::Accounts::get_active_status()... ";
114         if ($account->get_active_status()) {
115                 print "Okay.\n";
116         } else {
117                 print "Failed!\n";
118         }
120         # It follows that to connect a user you must set the account status to
121         # "available" similarly we can disconnect a user by setting the account
122         # status to "offline"
124         print "Testing: Purple::Accounts::connect()...pending...\n";
126         $account->set_status("available", TRUE);
127         $account->set_enabled(Purple::Core::get_ui(), TRUE);
128         $account->connect();
131 @endcode
133 The above code is mostly explained in the comments, however there are a few
134 notable points to make.  The variables above are all specialized Perl types that
135 contain pointers to the actual Purple types.  They can be reassigned at will, just
136 like any other variable in Perl.  The only way to edit the internal values of a
137 Purple type from within perl is to use the accessor methods, e.g.
138 @c Purple::Account::get_username().  If you would like to assign a C @c NULL value,
139 simply use @c undef.
141 @section buddylist-api Buddylist, Group and Chat API
143 The BuddyList, Group and Chat APIs are very similar and whatever is shown for
144 the @c Purple::BuddyList API should carry over to @c Purple::BuddyList::Chat and
145 @c Purple::BuddyList::Group.  Note that a @c Purple::Find package was created to
146 keep the naming consistent with the C API.
148 @code
149 sub plugin_load {
150         my $plugin = shift;
152         my $protocol = "prpl-oscar";
153         my $account_name = "test";
155         # This is how we get an account to use in the following tests.  You should replace the username
156         #  with an existing user
157         $account = Purple::Accounts::find($account_name, $protocol);
159         # Testing a find function: Note Purple::Find not Purple::Buddy:find!
160         #  Furthermore, this should work the same for chats and groups
161         Purple::Debug::info("testplugin", "Testing: Purple::Find::buddy()...");
162         $buddy = Purple::Find::buddy($account, "BUDDYNAME");
163         Purple::Debug::info("", ($buddy ? "ok." : "fail.") . "\n");
165         # If you should need the handle for some reason, here is how you do it
166         Purple::Debug::info("testplugin", "Testing: Purple::BuddyList::get_handle()...");
167         $handle = Purple::BuddyList::get_handle();
168         Purple::Debug::info("", ($handle ? "ok." : "fail.") . "\n");
170         # This gets the Purple::BuddyList and references it by $blist
171         Purple::Debug::info("testplugin", "Testing: Purple::get_blist()...");
172         $blist = Purple::get_blist();
173         Purple::Debug::info("", ($blist ? "ok." : "fail.") . "\n");
175         # This is how you would add a buddy named "NEWNAME" with the alias "ALIAS"
176         Purple::Debug::info("testplugin", "Testing: Purple::BuddyList::Buddy::new...");
177         $buddy = Purple::BuddyList::Buddy::new($account, "NEWNAME", "ALIAS");
178         Purple::Debug::info("", ($buddy ? "ok." : "fail.") . "\n");
180         # Here we add the new buddy '$buddy' to the group "GROUP"
181         #  so first we must find the group
182         Purple::Debug::info("testplugin", "Testing: Purple::Find::group...");
183         $group = Purple::Find::group("GROUP");
184         Purple::Debug::info("", ($group ? "ok." : "fail.") . "\n");
186         # To add the buddy we need to have the buddy, contact, group and node for insertion.
187         #  For this example we can let contact be undef and set the insertion node as the group
188         Purple::Debug::info("testplugin", "Testing: Purple::BuddyList::add_buddy...\n");
189         Purple::BuddyList::add_buddy($buddy, undef, $group, $group);
191         # The example that follows gives an indication of how an API call that returns a list is handled.
192         #  In this case the buddies of the account found earlier are retrieved and put in an array '@buddy_array'
193         #  Further down an accessor method is used, 'get_name()' -- see source for details on the full set of methods
194         Purple::Debug::info("testplugin",  "Testing: Purple::Find::buddies...\n");
195         @buddy_array = Purple::Find::buddies($account, undef);
196         if (@buddy_array) {
197                 Purple::Debug::info("testplugin", "Buddies in list (" . @buddy_array . "): \n");
198                 foreach $bud (@buddy_array) {
199                         Purple::Debug::info("testplugin", Purple::BuddyList::Buddy::get_name($bud) . "\n");
200                 }
201         }
203 @endcode
205 The BuddyList API allows plugins to edit buddies in the list, find the buddies
206 for a given account, assign aliases, and further manipulate the structure
207 as needed.  It is also contains methods for accessing @c Purple::BuddyList::Group
208 and @c Purple::BuddyList::Chat types.
210 @section conn-api Connection API
212 The @c Purple::Connection API is one of the many packages that will not be covered
213 in-depth in this tutorial.  It is most useful to protocol plugin developers.
214 However, the entire @c purple_connection_ API has corresponding, functioning perl subroutines.
216 @section conv-api Conversation API
218 The libpurple perl APIs for @c purple_conversation_ and @c pidgin_conv_window_ allow
219 plugins to interact with existing conversations, create new conversations, and
220 modify conversations at will.  In the example script, a new window is created,
221 displayed and a new conversation instant message is created.  The following
222 example again replaces the @c plugin_load subroutine in the simple plugin
223 template.  The @c Purple::Conversation::Chat package handles the
224 @c purple_conv_chat_ portion of the API very similarly to how the
225 Purple::Conversation::IM package is used in the examples that follow.
227 Notice that the interaction with the conversation window is in the @c Pidgin package as it
228 is UI-specific code interacting with Pidgin and not libpurple.
229 To use any of the Pidgin:: functionality, you will need to add the following to the top of your script: @code use Pidgin; @endcode
232 @code
233 sub plugin_load {
234         my $plugin = shift;
235         my $protocol = "prpl-oscar";
236         my $account_name = "test";
238         $account = Purple::Accounts::find($account_name, $protocol);
240         # First we create two new conversations.
241         print "Testing Purple::Conversation->new()...";
242         $conv1 = Purple::Conversation->new(1, $account, "Test Conversation 1");
243         if ($conv1) { print "ok.\n"; } else { print "fail.\n"; }
245         print "Testing Purple::Conversation->new()...";
246         $conv2 = Purple::Conversation->new(1, $account, "Test Conversation 2");
247         if ($conv2) { print "ok.\n"; } else { print "fail.\n"; }
248         
249         # Second we create a window to display the conversations in.
250         #  Note that the package here is Pidgin::Conversation::Window
251         print "Testing Pidgin::Conversation::Window->new()...\n";
252         $win = Pidgin::Conversation::Window->new();
254         # The third thing to do is to move second the conversation to a new window.
255         # The subroutine add_gtkconv() returns the number of conversations
256         # present in the window.
257         print "Testing Pidgin::Conversation::Window::add_conversation()...";
258         $gtkconv2 = Pidgin::Conversation::get_gtkconv($conv2);
259         $gtkconv2->get_window()->remove_gtkconv($gtkconv2);
260         $conv_count = $win->add_gtkconv($gtkconv2);
261         if ($conv_count) {
262                 print "ok..." . $conv_count . " conversations...\n";
263         } else {
264                 print "fail.\n";
265         }
267         # Now the window is displayed to the user.
268         print "Testing Pidgin::Conversation::Window::show()...\n";
269         $win->show();
271         # Use get_im_data() to get a handle for the conversation
272         print "Testing Purple::Conversation::get_im_data()...\n";
273         $im = $conv1->get_im_data();
274         if ($im) { print "ok.\n"; } else { print "fail.\n"; }
276         # Here we send messages to the conversation
277         print "Testing Purple::Conversation::IM::send()...\n";
278         $im->send("Message Test.");
280         print "Testing Purple::Conversation::IM::write()...\n";
281         $conv2->get_im_data()->write("SENDER", "<b>Message</b> Test.", 0, 0);
283 @endcode
285 The next block of code shows how a script can close a known conversation window
286 @c $win.
288 @code
289         print "Testing Pidgin::Conversation::Window::get_gtkconv_count()...\n";
290         $conv_count = $win->get_gtkconv_count();
291         print "...and it returned $conv_count.\n";
292         if ($conv_count > 0) {
293                 print "Testing Pidgin::Conversation::Window::destroy()...\n";
294                 $win->destroy();
295         }
296 @endcode
298 @section plugin-pref-api Plugin Preference and Gtk Preference API
300 The plugin preference API allows plugins to display options for manipulating the
301 plugin's behavior in a popup window.  The method used for creating the pane in
302 native C plugins does not allow a direct mapping into perl. Therefore, perl
303 plugin writers must be aware that there will be significant differences in how
304 they create plugin preference panes.
306 To first create a standard plugin preference tab, we need specify the
307 @c prefs_info key/value pair in the @c \%PLUGIN_INFO hash.  This specifies the
308 name of the perl subroutine that will build and return a @c Purple::Pref::Frame.
310 @code
311 %PLUGIN_INFO = {
312         ...,
313         prefs_info => "prefs_info_cb"
315 @endcode
317 The perl subroutine @c prefs_info_cb will be called to create the preferences
318 popup for the perl plugin.  The following example will demonstrate creating a
319 preference frame. It is necessary to first initialize the preferences to be used
320 in the @c plugin_load subroutine, as follows.
322 @code
323 sub plugin_load {
324         my $plugin = shift;
326         # This is necessary to create each level in the preferences tree.
327         Purple::Prefs::add_none("/plugins/core/perl_test");
328         # Here we are adding a set of preferences
329         #  The second argument is the default value for the preference.
330         Purple::Prefs::add_bool("/plugins/core/perl_test/bool", 1);
331         Purple::Prefs::add_string("/plugins/core/perl_test/choice_str", "ch1");
332         Purple::Prefs::add_int("/plugins/core/perl_test/choice_int", 1);
333         Purple::Prefs::add_string("/plugins/core/perl_test/text", "Foobar");
335 @endcode
337 Now we can provide an UI for manipulating these preferences in our @c prefs_info
338 function.
340 @code
341 sub prefs_info_cb {
342         # The first step is to initialize the Purple::Pref::Frame that will be returned
343         $frame = Purple::PluginPref::Frame->new();
345         # Create a new boolean option with a label "Boolean Label" and then add
346         # it to the frame
347         $ppref = Purple::PluginPref->new_with_label("Boolean Label");
348         $frame->add($ppref);
350         $ppref = Purple::PluginPref->new_with_name_and_label(
351                 "/plugins/core/perl_test/bool", "Boolean Preference");
352         $frame->add($ppref);
354         # Create a set of choices.  To do so, we must set the type to 1 which is
355         # the numerical equivalent of the PurplePrefType for choice.
356         $ppref = Purple::PluginPref->new_with_name_and_label(
357                 "/plugins/core/perl_test/choice_str", "Choice Preference");
358         $ppref->set_type(1);
359         $ppref->add_choice("ch0", "ch0");
360         # The following will be the default value as set from plugin_load
361         $ppref->add_choice("ch1", "ch1");
362         $frame->add($ppref);
364         # Create a set of choices.  To do so we must set the type to 1 which is
365         # the numerical equivalent of the PurplePrefType for choice.
366         $ppref = Purple::PluginPref->new_with_name_and_label(
367                 "/plugins/core/perl_test/choice_int", "Choice Preference 2");
368         $ppref->set_type(1);
369         $ppref->add_choice("zero", 0);
370         # The following will be the default value as set from plugin_load
371         $ppref->add_choice("one", 1);
372         $frame->add($ppref);
375         # Create a text box.  The default value will be "Foobar" as set by
376         # plugin_load
377         $ppref = Purple::PluginPref->new_with_name_and_label(
378                 "/plugins/core/perl_test/text", "Text Box Preference");
379         $ppref->set_type(2);
380         $ppref->set_max_length(16);
381         $frame->add($ppref);
383         return $frame;
385 @endcode
387 <!--
388 Using the Gtk2-Perl module for Perl it is possible to create tailored @c GtkFrame elements and display them in a preference window.  Note that Gtk2-Perl must be loaded with @c require and not @c use .  The first step is to create the proper key/value pairs in the @c \%PLUGIN_INFO hash noting that the @c prefs_info key is no longer valid. Instead the keys @c GTK_UI and @c gtk_prefs_info must be set as follows.
390 @code
391 %PLUGIN_INFO = {
392         ...,
393         # Used to differentiate between a regular and a Gtk preference frame
394         GTK_UI => TRUE,
395         gtk_prefs_info => "gtk_prefs_info_cb",
397 @endcode
399 To finish this example @c gtk_prefs_info_cb needs to be defined.  To introduce some of the flexibility of using Gtk2-Perl the example also includes a button and a callback for the button.  Explaining Gtk2-Perl is beyond the scope of this tutorial and more info can be found at the project's website <a href="http://gtk2-perl.sourceforge.net/">http://gtk2-perl.sourceforge.net/</a>.
401 @code
402 # A simple call back that prints out whatever value it is given as an argument.
403 sub button_cb {
404         my $widget = shift;
405         my $data = shift;
406         print "Clicked button with message: " . $data . "\n";
409 sub gtk_prefs_info_cb {
410         #  Create a button that prints a message to the console and places it in the frame.
411         use Glib;
412         require Gtk2;
414         $frame = Gtk2::Frame->new(\'Gtk Test Frame\');
415         $button = Gtk2::Button->new(\'Print Message\');
417         $frame->set_border_width(10);
418         $button->set_border_width(150);
419         $button->signal_connect("clicked" => \&button_cb, "Message Text");
420         $frame->add($button);
422         $button->show();
423         $frame->show();
425         return $frame;
427 @endcode
430 @section request-api Request Dialog Box API
432 The @c Purple::Request package allows plugins to have interactive dialog boxes
433 without the need to directly interact with the UI (e.g. GTK+).  This allows core
434 (libpurple) plugins to create a UI that can be displayed on whichever UI frontend
435 is being used.  The portion of the Request API available to perl scripts is
436 listed below, followed by an example illustrating its use.
438 These arguments are the same for each of the three request types:
439         @arg @em handle         - The plugin handle.
440         @arg @em title          - String title for the dialog.
441         @arg @em primary        - The first sub-heading.
442         @arg @em secondary      - The second sub-heading.
443         @arg @em ok_text        - The Text for the OK button.
444         @arg @em ok_cb          - The string name of the perl subroutine to call when the OK button is clicked.
445         @arg @em cancel_text    - The text for the Cancel button.
446         @arg @em cancel_cb      - The string name of the perl subroutine to call when the Cancel button is clicked.
447         @arg @em default_value  - Default text string to display in the input box.
448         @arg @em multiline      - Boolean where true indicates multiple line input boxes are allowed.
449         @arg @em masked         - Boolean indicating if the user can edit the text.
450         @arg @em hint   - See source for more information - can be left blank.
451         @arg @em filename       - String default file name value.
452         @arg @em savedialog     - Boolean where true indicates use as a save file dialog and false indicates an open file dialog.
454 @code
455 # Create a simple text input box
456 Purple::Request::input(handle, title, primary, secondary, default_value, multiline, masked, hint, ok_text, ok_cb, cancel_text, cancel_cb);
458 # Prompt user to select a file
459 Purple::Request::file(handle, title, filename, savedialog, ok_cb, cancel_cb);
461 # Create a unique input dialog as shown in the following example
462 Purple::Request::fields(handle, title, primary, secondary, fields, ok_text, ok_cb, cancel_text, cancel_cb);
463 @endcode
465 The following is an example of a @c Purple::Request::fields() dialog box with a
466 callback for the OK button and another for the Cancel Button.
468 @code
469 sub ok_cb_test{
470         # The $fields is passed to the callback function when the button is clicked.
471         # To access a specific field, it must be extracted from $fields by name.
472         $fields = shift;
473         $account = Purple::Request::Fields::get_account($fields, "acct_test");
474         $int = Purple::Request::Fields::get_integer($fields, "int_test");
475         $choice = Purple::Request::Fields::get_choice($fields, "ch_test");
478 sub cancel_cb_test{
479         # Cancel does nothing but is equivalent to the ok_cb_test
482 sub plugin_load {
483         my $plugin = shift;
485         # Create a group to pool together multiple fields.
486         $group = Purple::Request::Field::Group::new("Group Name");
488         # Each field is created with Purple::Request::*_new(), is made viewable with Purple::Request::field_*_set_show_all()
489         #  and is then added to the group with Purple::Request::field_group_add_field()
491         # Add an account combobox containing all active accounts
492         $field = Purple::Request::Field::account_new("acct_test", "Account Text", undef);
493         Purple::Request::Field::account_set_show_all($field, 0);
494         Purple::Request::Field::Group::add_field($group, $field);
496         # Add an integer input box
497         $field = Purple::Request::Field::int_new("int_test", "Integer Text", 33);
498         Purple::Request::Field::Group::add_field($group, $field);
500         # Add a list of choices
501         $field = Purple::Request::Field::choice_new("ch_test", "Choice Text", 1);
502         Purple::Request::Field::choice_add($field, "Choice 0");
503         Purple::Request::Field::choice_add($field, "Choice 1");
504         Purple::Request::Field::choice_add($field, "Choice 2");
506         Purple::Request::Field::Group::add_field($group, $field);
508         # Create a Purple::Request and add the group that was just created.
509         $request = Purple::Request::Fields::new();
510         Purple::Request::Fields::add_group($request, $group);
512         #  Display the dialog box with the input fields added earlier with the appropriate titles.
513         Purple::Request::fields(
514                 $plugin,
515                 "Request Title!",
516                 "Primary Title",
517                 "Secondary Title",
518                 $request,
519                 "Ok Text", "ok_cb_test",
520                 "Cancel Text", "cancel_cb_test");
522 @endcode
524 @section timeout-cb Misc: Plugin Actions, Timeouts and Callbacks
526 This section of the manual covers some of the important features that can be
527 added to libpurple perl Plugins.  Plugin actions are callback functions that are
528 accessible to the user from the Buddy List window under "Tools -> [Plugin Name]".
529 Timeouts allow a plugin to execute a perl subroutine after a given period of time.
530 Note that timeouts only occur once, so if the timeout must occur periodically,
531 the timeout needs to be re-added at the end of the timeout callback function.
532 Callbacks are functions that are called when an event occurs (such as a buddy
533 signing-on, or a message being received).  The following three examples will
534 demonstrate the usage of these features.
536 Plugin actions require the @c \%PLUGIN_INFO hash to have a key/value pair added,
537 specifying a perl subroutine which will list the available actions; each action
538 listed must have a definition, including a reference to a callback subroutine,
539 added to the @c \%plugin_actions hash.
541 @code
542 %PLUGIN_INFO = {
543         ...,
544         plugin_action_sub => "plugin_actions_cb",
547 sub plugin_actions_cb {
548         my @actions = ("Action 1", "Action 2");
551 %plugin_actions = (
552         # The callback subroutine that is called when "Tools -> Plugin -> Action 1" is selected
553         "Action 1" => \&action1_cb,
554         # The callback subroutine that is called when "Tools -> Plugin -> Action 2" is selected
555         "Action 2" => \&action2_cb
558 sub action1_cb {
559         Purple::Debug::info("Test Plugin", "Action 1 activated\n");
562 sub action2_cb {
563         Purple::Debug::info("Test Plugin", "Action 2 activated\n");
565 @endcode
567 Timeouts allow a perl subroutine to be executed after a specified time.  They only occur once, so, as stated earlier, the timeout must be re-registered after every time it is called.
569 @code
570 sub timeout_cb {
571         my $plugin = shift;
572         Purple::Debug::info("testplugin", "Timeout occurred.\n");
574         # Reschedule timeout
575         Purple::timeout_add($plugin, 10, \&timeout_cb, $plugin);
578 sub plugin_load {
579         $plugin = shift;
581         # Schedule a timeout for ten seconds from now
582         Purple::timeout_add($plugin, 10, \&timeout_cb, $plugin);
584 @endcode
586 Callbacks are handled by creating a perl subroutine to serve as the callback and
587 then attaching the callback to a signal.
589 @code
590 sub signal_cb {
591         # The signal data and the user data come in as arguments
592         my ($account, $data) = @_;
593         Purple::Debug::info("testplugin", "Account \"" . $account->get_username() . "\" just connected.\n");
596 sub plugin_load {
597         $plugin = shift;
599         # User data to be given as an argument to the callback perl subroutine.
600         $data = "";
602         # A pointer to the handle to which the signal belongs needed by the callback function
603         $accounts_handle = Purple::Accounts::get_handle();
605         # Connect the perl subroutine 'signal_cb' to the event 'account-connecting'
606         Purple::Signal::connect($accounts_handle, "account-connecting", $plugin, \&signal_cb, $data);
608 @endcode
610 @section Resources
611         @see API Documentation