minor update for options api
[squirrelmail.git] / doc / plugin.txt
CommitLineData
99098885 1$Id$
2
9cd2ae7d 3In addition to this document, please check out the SquirrelMail
4development FAQ for more information. Also, help writing plugins
5is easily obtained by posting to the squirrelmail-plugins mailing
b2978b37 6list. (See details about mailing lists on the website)
99098885 7
8FAQ -> http://www.squirrelmail.org/wiki/wiki.php?DeveloperFAQ
9cd2ae7d 9Plugin Development ->
10 http://www.squirrelmail.org/wiki/wiki.php?DevelopingPlugins
99098885 11
12
1aaef171 13A FEW NOTES ON THE PLUGIN ARCHITECTURE
14======================================
15
9cd2ae7d 16The plugin architecture of SquirrelMail is designed to make it possible
17to add new features without having to patch SquirrelMail itself.
18Functionality like password changing, displaying ads and calendars should
19be possible to add as plugins.
1aaef171 20
21
9cd2ae7d 22The Idea
1aaef171 23--------
24
25The idea is to be able to run random code at given places in the
26SquirrelMail code. This random code should then be able to do whatever
27needed to enhance the functionality of SquirrelMail. The places where
28code can be executed are called "hooks".
29
30There are some limitations in what these hooks can do. It is difficult
31to use them to change the layout and to change functionality that
32already is in SquirrelMail.
33
34Some way for the plugins to interact with the help subsystem and
35translations will be provided.
36
37
9cd2ae7d 38The Implementation
1aaef171 39------------------
40
9cd2ae7d 41The plugin jumping off point in the main SquirrelMail code is in the
42file functions/plugin.php. In places where hooks are made available,
43they are executed by calling the function do_hook('hookname'). The
44do_hook function then traverses the array
45$squirrelmail_plugin_hooks['hookname'] and executes all the functions
46that are named in that array. Those functions are placed there when
47plugins register themselves with SquirrelMail as discussed below. A
48plugin may add its own internal functions to this array under any
49hook name provided by the SquirrelMail developers.
1aaef171 50
51A plugin must reside in a subdirectory in the plugins/ directory. The
9cd2ae7d 52name of the subdirectory is considered to be the name of the plugin.
53(The plugin will not function correctly if this is not the case.)
1aaef171 54
55To start using a plugin, its name must be added to the $plugins array
56in config.php like this:
57
9cd2ae7d 58 $plugins[0] = 'plugin_name';
1aaef171 59
9cd2ae7d 60When a plugin is registered, the file plugins/plugin_name/setup.php is
61included and the function squirrelmail_plugin_init_plugin_name() is
62called with no parameters. That function is where the plugin may
63register itself against any hooks it wishes to take advantage of.
1aaef171 64
65
9cd2ae7d 66WRITING PLUGINS
67===============
68
69All plugins must contain a file called setup.php and must include a
70function called squirrelmail_plugin_init_plugin_name() therein. Since
71including numerous plugins can slow SquirrelMail performance
72considerably, the setup.php file should contain little else. Any
73functions that are registered against plugin hooks should do little
74more than call another function in a different file.
75
76Any other files used by the plugin should also be placed in the
77plugin directory (or subdirectory thereof) and should contain the
78bulk of the plugin logic.
1aaef171 79
9cd2ae7d 80The function squirrelmail_plugin_init_plugin_name() is called to
81initalize a plugin. This function could look something like this (if
82the plugin was named "demo" and resided in the directory plugins/demo/):
1aaef171 83
9cd2ae7d 84function squirrelmail_plugin_init_demo ()
85{
86 global $squirrelmail_plugin_hooks;
1aaef171 87
9cd2ae7d 88 $squirrelmail_plugin_hooks['generic_header']['demo'] = 'plugin_demo_header';
89 $squirrelmail_plugin_hooks['menuline']['demo'] = 'plugin_demo_menuline';
90}
91
92Please note that as of SquirrelMail 1.5.0, this function will no longer
93be called at run time and will instead be called only once at configure-
94time. Thus, the inclusion of any dynamic code (anything except hook
95registration) here is strongly discouraged.
1aaef171 96
9cd2ae7d 97In this example, the "demo" plugin should also have two other functions
98in its setup.php file called plugin_demo_header() and plugin_demo_menuline().
99The first of these might look something like this:
100
101function plugin_demo_header()
102{
103 include_once(SM_PATH . 'plugins/demo/functions.php');
104 plugin_demo_header_do();
1aaef171 105}
106
9cd2ae7d 107The function called plugin_demo_header_do() would be in the file called
108functions.php in the demo plugin directory and would contain the plugin's
109core logic for the "generic_header" hook.
110
111
112Including Other Files
113---------------------
114
115A plugin may need to reference functionality provided in other
116files, and therefore need to include those files. Most of the
117core SquirrelMail functions are already available to your plugin
118unless it has any files that are requested directly by the client
119browser (custom options page, etc.). In this case, you'll need
120to make sure you include the files you need (see below).
121
122Note that as of SquirrelMail 1.4.0, all files are accessed using a
123constant called SM_PATH that always contains the relative path to
124the main SquirrelMail directory. This constant is always available
125for you to use when including other files from the SquirrelMail core,
126your own plugin, or other plugins, should the need arise. If any of
127your plugin files are requested directly from the client browser,
128you will need to define this constant before you do anything else:
129
130 define('SM_PATH', '../../');
131
132Files are included like this:
133
134 include_once(SM_PATH . 'include/validate.php');
135
136When including files, please make sure to use the include_once() function
137and NOT include(), require(), or require_once(), since these all are much
138less efficient than include_once() and can have a cumulative effect on
139SquirrelMail performance.
140
141The files that you may need to include in a plugin will vary greatly
142depending upon what the plugin is designed to do. For files that are
143requested directly by the client browser, we strongly recommend that
144you include the file include/validate.php, since it will set up the
145SquirrelMail environment automatically. It will ensure the the user
146has been authenticated and is currently logged in, load all user
147preferences, include internationalization support, call stripslashes()
148on all incoming data (if magic_quotes_gpc is on), and initialize and
149include all other basic SquirrelMail resources and functions. You may
150see other plugins that directly include other SquirrelMail files, but
151that is no longer necessary and is a hold-over from older SquirrelMail
152versions.
6b638171 153
154
9cd2ae7d 155Hook Types: Parameters and Return Values
156-----------------------------------------
157
a3a95e4a 158Hooks, when executed, are called with one parameter, an array of data
159that is passed to the hook. The first element in the array is the name
160of the hook that is being called. Any other elements in the array are
9cd2ae7d 161dependant on the type of hook that is being called. Most hooks do not
162pass any other data, but be sure to check the hook you are using for
163any useful information it may provide. Generally speaking, in the case
164that any extra data is available here, your plugin should NOT change
165it unless you know what you are doing or it is documented otherwise.
166See below for further discussion of special hook types and the values
a3a95e4a 167
9cd2ae7d 168Most hooks, when executed, are called using the do_hook() function,
169where no return value is used. There are a limited number of hooks,
170however, that are called using the do_hook_function() and
171concat_hook_function() function calls. Both of these hook types may
172use the value returned by your plugin for its own purposes or to
173display in the resultant HTML output (you need to research the specific
174hook to determine its use). The do_hook_function() type hook will
175only use the return value it retrieves from the LAST plugin in the
176list of plugins registered against such a hook, whereas the
177concat_hook_function() type hook will concatenate the return values
178from all plugins that are registered against the hook and use that
179value (usually as a string of HTML code to output to the client).
a3a95e4a 180
181
9cd2ae7d 182List of Hooks
6b638171 183-------------
ef3c69f0 184
9cd2ae7d 185This is a list of all hooks currently available in SquirrelMail, ordered
186by file. Note that this list is accurate as of June 17, 2003 (should be
187close to what is contained in release 1.4.1, plus or minus a hook or two),
188but may be out of date soon thereafter. You never know. ;-)
6b638171 189
9cd2ae7d 190 Hook Name Found In Called With(#)
191 --------- -------- --------------
192 loading_constants functions/constants.php do_hook
193 get_pref_override functions/file_prefs.php hook_func
194 get_pref functions/file_prefs.php hook_func
195 special_mailbox functions/imap_mailbox.php hook_func
196 % rename_or_delete_folder functions/imap_mailbox.php hook_func
197 msg_envelope functions/mailbox_display.php do_hook
198 mailbox_index_before functions/mailbox_display.php do_hook
199 mailbox_form_before functions/mailbox_display.php do_hook
200 mailbox_index_after functions/mailbox_display.php do_hook
201 check_handleAsSent_result functions/mailbox_display.php do_hook
202 subject_link functions/mailbox_display.php concat_hook
203 message_body functions/mime.php do_hook
204 ^ attachment $type0/$type1 functions/mime.php do_hook
205 generic_header functions/page_header.php do_hook
206 menuline functions/page_header.php do_hook
207 loading_prefs include/load_prefs.php do_hook
208 addrbook_html_search_below src/addrbook_search_html.php do_hook
209 addressbook_bottom src/addressbook.php do_hook
210 compose_form src/compose.php do_hook
211 compose_bottom src/compose.php do_hook
212 compose_button_row src/compose.php do_hook
213 compose_send src/compose.php do_hook
214 folders_bottom src/folders.php do_hook
215 help_top src/help.php do_hook
216 help_chapter src/help.php do_hook
217 help_bottom src/help.php do_hook
7022cc97 218 left_main_after_each_folder src/left_main.php concat_hook
9cd2ae7d 219 left_main_before src/left_main.php do_hook
220 left_main_after src/left_main.php do_hook
221 login_cookie src/login.php do_hook
222 login_top src/login.php do_hook
223 login_form src/login.php do_hook
224 login_bottom src/login.php do_hook
225 move_before_move src/move_messages.php do_hook
226 * optpage_set_loadinfo src/options.php do_hook
227 * optpage_loadhook_personal src/options.php do_hook
228 * optpage_loadhook_display src/options.php do_hook
229 * optpage_loadhook_highlight src/options.php do_hook
230 * optpage_loadhook_folder src/options.php do_hook
231 * optpage_loadhook_order src/options.php do_hook
232 * options_personal_save src/options.php do_hook
233 * options_display_save src/options.php do_hook
234 * options_folder_save src/options.php do_hook
235 * options_save src/options.php do_hook
236 * optpage_register_block src/options.php do_hook
237 * options_link_and_description src/options.php do_hook
238 * options_personal_inside src/options.php do_hook
239 * options_display_inside src/options.php do_hook
240 * options_highlight_inside src/options.php do_hook
241 * options_folder_inside src/options.php do_hook
242 * options_order_inside src/options.php do_hook
243 * options_personal_bottom src/options.php do_hook
244 * options_display_bottom src/options.php do_hook
245 * options_highlight_bottom src/options.php do_hook
246 * options_folder_bottom src/options.php do_hook
247 * options_order_bottom src/options.php do_hook
248 * options_highlight_bottom src/options_highlight.php do_hook
249 & options_identities_process src/options_identities.php do_hook
250 & options_identities_top src/options_identities.php do_hook
251 &% options_identities_renumber src/options_identities.php do_hook
252 & options_identities_table src/options_identities.php concat_hook
253 & options_identities_buttons src/options_identities.php concat_hook
254 message_body src/printer_friendly_bottom.php do_hook
255 read_body_header src/read_body.php do_hook
256 read_body_menu_top src/read_body.php do_hook
257 read_body_menu_bottom src/read_body.php do_hook
258 read_body_header_right src/read_body.php do_hook
259 html_top src/read_body.php do_hook
260 read_body_top src/read_body.php do_hook
261 read_body_bottom src/read_body.php do_hook
262 html_bottom src/read_body.php do_hook
263 login_before src/redirect.php do_hook
264 login_verified src/redirect.php do_hook
265 generic_header src/right_main.php do_hook
266 right_main_after_header src/right_main.php do_hook
267 right_main_bottom src/right_main.php do_hook
268 search_before_form src/search.php do_hook
269 search_after_form src/search.php do_hook
270 search_bottom src/search.php do_hook
271 logout src/signout.php do_hook
272 webmail_top src/webmail.php do_hook
273 webmail_bottom src/webmail.php do_hook
274 logout_above_text src/signout.php concat_hook
275
276% = This hook is used in multiple places in the given file
277# = Called with hook type (see below)
278& = Special identity hooks (see below)
279^ = Special attachments hook (see below)
280* = Special options hooks (see below)
6b638171 281
6b638171 282
9cd2ae7d 283(#) Called With
284---------------
285Each hook is called using the hook type specified in the list above:
286 do_hook do_hook()
287 hook_func do_hook_function()
288 concat_hook concat_hook_function()
a3a95e4a 289
290
0f101579 291(&) Identity Hooks
292------------------
9cd2ae7d 293This set of hooks is passed special information in the array of arguments:
0f101579 294
295options_identities_process
9cd2ae7d 296
297 This hook is called at the top of the Identities page, which is
298 most useful when the user has changed any identity settings - this
299 is where you'll want to save any custom information you are keeping
300 for each identity or catch any custom submit buttons that you may
301 have added to the identities page. The arguments to this hook are:
302
303 [0] = hook name (always "options_identities_process")
304 [1] = should I run the SaveUpdateFunction() (alterable)
305
306 Obviously, set the second array element to 1/true if you want to
307 trigger SaveUpdateFunction() after the hook is finished - by default,
308 it will not be called.
0f101579 309
310options_identities_renumber
9cd2ae7d 311
312 This hook is called when one of the identities is being renumbered,
313 such as if the user had three identities and deletes the second -
314 this hook would be called with an array that looks like this:
315 ('options_identities_renumber', 2, 1). The arguments to this hook
316 are:
317
318 [0] = hook name (always "options_identities_renumber")
319 [1] = being renumbered from ('default' or 1 through (# idents) - 1)
320 [2] = being renumbered to ('default' or 1 through (# idents) - 1)
0f101579 321
322options_identities_table
9cd2ae7d 323
324 This hook allows you to insert additional rows into the table that
325 holds each identity. The arguments to this hook are:
326
327 [0] = color of table (use it like this in your plugin:
328 <tr bgcolor="<?PHP echo $info[1]?>">
329 [1] = is this an empty section (the one at the end of the list)?
330 [2] = what is the 'post' value? (ident # or empty string if default)
331
332 You need to return any HTML you would like to add to the table.
333 You could add a table row with code similar to this:
334
335 function demo_identities_table(&$args)
336 {
337 return '<tr bgcolor="' . $args[0] . '"><td>&nbsp;</td><td>'
338 . 'YOUR CODE HERE' . '</td></tr>' . "\n";
339 }
0f101579 340
341options_identities_buttons
9cd2ae7d 342
343 This hook allows you to add a button (or other HTML) to the row of
344 buttons under each identity. The arguments to this hook are:
345
346 [0] = is this an empty section (the one at the end of the list)?
347 [1] = what is the 'post' value? (ident # or empty string if default)
348
349 You need to return any HTML you would like to add here. You could add
350 a button with code similar to this:
351
352 function demo_identities_button(&$args)
353 {
354 return '<input type="submit" name="demo_button_' . $args[1]
355 . '" value="Press Me">';
356 }
0f101579 357
358
a3a95e4a 359(^) Attachment Hooks
360--------------------
361When a message has attachments, this hook is called with the MIME types. For
362instance, a .zip file hook is "attachment application/x-zip". The hook should
363probably show a link to do a specific action, such as "Verify" or "View" for a
9cd2ae7d 364.zip file. Thus, to register your plugin for .zip attachments, you'd do this
365in setup.php (assuming your plugin is called "demo"):
366
367 $squirrelmail_plugin_hooks['attachment application/x-zip']['demo']
368 = 'demo_handle_zip_attachment';
a3a95e4a 369
370This is a breakdown of the data passed in the array to the hook that is called:
371
372 [0] = Hook's name ('attachment text/plain')
9cd2ae7d 373 [1] = Array of links of actions (see below) (alterable)
a3a95e4a 374 [2] = Used for returning to mail message (startMessage)
375 [3] = Used for finding message to display (id)
376 [4] = Mailbox name, urlencode()'d (urlMailbox)
377 [5] = Entity ID inside mail message (ent)
9cd2ae7d 378 [6] = Default URL to go to when filename is clicked on (alterable)
ef30bf50 379 [7] = Filename that is displayed for the attachment
380 [8] = Sent if message was found from a search (where)
381 [9] = Sent if message was found from a search (what)
a3a95e4a 382
383To set up links for actions, you assign them like this:
384
9cd2ae7d 385 $Args[1]['<plugin_name>']['href'] = 'URL to link to';
386 $Args[1]['<plugin_name>']['text'] = 'What to display';
441f2d33 387
ae2f65a9 388It's also possible to specify a hook as "attachment type0/*",
389for example "attachment text/*". This hook will be executed whenever there's
390no more specific rule available for that type.
391
9cd2ae7d 392Putting all this together, the demo_handle_zip_attachment() function should
393look like this (note the argument being passed):
57945c53 394
9cd2ae7d 395 function demo_handle_zip_attachment(&$Args)
396 {
397 include_once(SM_PATH . 'plugins/demo/functions.php');
398 demo_handle_zip_attachment_do($Args);
399 }
57945c53 400
9cd2ae7d 401And the demo_handle_zip_attachment_do() function in the
402plugins/demo/functions.php file would typically (but not necessarily)
403display a custom link:
404
405 function demo_handle_zip_attachment_do(&$Args)
406 {
407 $Args[1]['demo']['href'] = SM_PATH . 'plugins/demo/zip_handler.php?'
408 . 'passed_id=' . $Args[3] . '&mailbox=' . $Args[4]
409 . '&passed_ent_id=' . $Args[5];
410 $Args[1]['demo']['text'] = 'show zip contents';
411 }
412
413The file plugins/demo/zip_handler.php can now do whatever it needs with the
414attachment (note that this will hand information about how to retrieve the
415source message from the IMAP server as GET varibles).
416
417
418(*) Options
419-----------
420Before you start adding user preferences to your plugin, please take a moment
421to think about it: in some cases, more options may not be a good thing.
422Having too many options can be confusing. Thinking from the user's
423perspective, will the proposed options actually be used? Will users
424understand what these options are for?
425
426There are two ways to add options for your plugin. When you only have a few
427options that don't merit an entirely new preferences page, you can incorporate
428them into an existing section of SquirrelMail preferences (Personal
429Information, Display Preferences, Message Highlighting, Folder Preferences or
430Index Order). Or, if you have an extensive number of settings or for some
431reason need a separate page for the user to interact with, you can create your
432own preferences page.
433
434
435Integrating Your Options Into Existing SquirrelMail Preferences Pages
436---------------------------------------------------------------------
437
438There are two ways to accomplish the integration of your plugin's settings
439into another preferences page. The first method is to add the HTML code
440for your options directly to the preferences page of your choice. Although
441currently very popular, this method will soon be deprecated, so avoid it
442if you can. That said, here is how it works. :) Look for any of the hooks
443named as "options_<pref page>_inside", where <pref page> is "display",
444"personal", etc. For this example, we'll use "options_display_inside" and,
445as above, "demo" as our plugin name:
446
447 1. In setup.php in the squirrelmail_plugin_init_demo() function:
448
449 $squirrelmail_plugin_hooks['options_display_inside']['demo']
450 = 'demo_show_options';
451
452 Note that there are also hooks such as "options_display_bottom",
453 however, they place your options at the bottom of the preferences
454 page, which is usually not desirable (mostly because they also
455 come AFTER the HTML FORM tag is already closed). It is possible
456 to use these hooks if you want to create your own FORM with custom
457 submission logic.
458
459 2. Assuming the function demo_show_options() calls another function
460 elsewhere called demo_show_options_do(), that function should have
461 output similar to this (note that you will be inserting code into
462 a table that is already defined with two columns, so please be sure
463 to keep this framework in your plugin):
464
465 ------cut here-------
466 <tr>
467 <td>
468 OPTION_NAME
469 </td>
470 <td>
471 OPTION_INPUT
472 </td>
473 </tr>
474 ------cut here-------
475
476 Of course, you can place any text where OPTION_NAME is and any input
477 tags where OPTION_INPUT is.
478
479 3. You will want to use the "options_<pref page>_save" hook (in this case,
480 "options_display_save") to save the user's settings after they have
481 pressed the "Submit" button. Again, back in setup.php in the
482 squirrelmail_plugin_init_demo() function:
57945c53 483
9cd2ae7d 484 $squirrelmail_plugin_hooks['options_display_save']['demo']
485 = 'demo_save_options';
57945c53 486
9cd2ae7d 487 4. Assuming the function demo_save_options() calls another function
488 elsewhere called demo_save_options_do(), that function should put
489 the user's settings into permanent storage (see the preferences
490 section below for more information). This example assumes that
491 in the preferences page, the INPUT tag's NAME attribute was set
492 to "demo_option":
493
494 global $data_dir, $username;
495 sqgetGlobalVar('demo_option', $demo_option);
496 setPref($data_dir, $username, 'demo_option', $demo_option);
497
498
499The second way to add options to one of the SquirrelMail preferences page is
500to use one of the "optpage_loadhook_<pref page>" hooks. The sent_subfolders
501plugin is an excellent example of this method. Briefly, this way of adding
502options consists of adding some plugin-specific information to a predefined
503data structure which SquirrelMail then uses to build the HTML input forms
504for you. This is the preferred method of building options lists going forward.
505
506 1. We'll use the "optpage_loadhook_display" hook to add a new group of
507 options to the display preferences page. In setup.php in the
508 squirrelmail_plugin_init_demo() function:
509
510 $squirrelmail_plugin_hooks['optpage_loadhook_display']['demo']
511 = 'demo_options';
512
513 2. Assuming the function demo_options() calls another function elsewhere
514 called demo_options_do(), that function needs to add a new key to two
515 arrays, $optpage_data['grps'] and $optpage_data['vals']. The value
516 associated with that key should simply be a section heading for your
517 plugin on the preferences page for the $optpage_data['grps'] array,
518 and yet another array with all of your plugin's options for the
519 $optpage_data['vals'] array. The options are built as arrays (yes,
520 that's four levels of nested arrays) that specify attributes that are
521 used by SquirrelMail to build your HTML input tags automatically.
522 This example includes just one input element, a SELECT (drop-down)
523 list:
524
525 global $optpage_data;
526 $optpage_data['grps']['DEMO_PLUGIN'] = 'Demo Options';
527 $optionValues = array();
528 $optionValues[] = array(
529 'name' => 'plugin_demo_favorite_color',
530 'caption' => 'Please Choose Your Favorite Color',
531 'type' => SMOPT_TYPE_STRLIST,
532 'refresh' => SMOPT_REFRESH_ALL,
533 'posvals' => array(0 => 'red',
534 1 => 'blue',
535 2 => 'green',
536 3 => 'orange'),
537 'save' => 'save_plugin_demo_favorite_color'
538 );
539 $optpage_data['vals']['DEMO_PLUGIN'] = $optionValues;
540
541 The array that you use to specify each plugin option has the following
542 possible attributes:
543
544 name The name of this setting, which is used not only for
545 the INPUT tag name, but also for the name of this
546 setting in the user's preferences
547 caption The text that prefaces this setting on the preferences page
548 type The type of INPUT element, which should be one of:
549 SMOPT_TYPE_STRING String/text input
550 SMOPT_TYPE_STRLIST Select list input
551 SMOPT_TYPE_TEXTAREA Text area input
552 SMOPT_TYPE_INTEGER Integer input
553 SMOPT_TYPE_FLOAT Floating point number input
554 SMOPT_TYPE_BOOLEAN Boolean (yes/no radio buttons)
555 input
556 SMOPT_TYPE_HIDDEN Hidden input (not actually shown
557 on preferences page)
558 SMOPT_TYPE_COMMENT Text is shown (specified by the
559 'comment' attribute), but no user
560 input is needed
561 SMOPT_TYPE_FLDRLIST Select list of IMAP folders
562 refresh Indicates if a link should be shown to refresh part or all
563 of the window (optional). Possible values are:
564 SMOPT_REFRESH_NONE No refresh link is shown
565 SMOPT_REFRESH_FOLDERLIST Link is shown to refresh
566 only the folder list
567 SMOPT_REFRESH_ALL Link is shown to refresh
568 the entire window
569 posvals For select lists, this should be an associative array,
570 where each key is an actual input value and the
571 corresponding value is what is displayed to the user
572 for that list item in the drop-down list
573 value Specify the default/preselected value for this option input
574 save You may indicate that special functionality needs to be
575 used instead of just saving this setting by giving the
576 name of a function to call when this value would otherwise
577 just be saved in the user's preferences
578 size Specifies the size of certain input items (typically
579 textual inputs). Possible values are:
580 SMOPT_SIZE_TINY
581 SMOPT_SIZE_SMALL
582 SMOPT_SIZE_MEDIUM
583 SMOPT_SIZE_LARGE
584 SMOPT_SIZE_HUGE
585 SMOPT_SIZE_NORMAL
586 comment For SMOPT_TYPE_COMMENT type options, this is the text
587 displayed to the user
588 script This is where you may add any additional javascript
589 or other code to the user input
590
591 3. If you indicated a 'save' attribute for any of your options, you must
592 create that function (you'll only need to do this if you need to do
593 some special processing for one of your settings). The function gets
594 one parameter, which is an object with mostly the same attributes you
595 defined when you made the option above... the 'new_value' (and possibly
596 'value', which is the current value for this setting) is the most useful
597 attribute in this context:
598
599 function save_plugin_demo_favorite_color($option)
600 {
601 // if user chose orange, make note that they are really dumb
602 if ($option->new_value == 3)
603 {
604 // more code here as needed
605 }
606
607 // don't even save this setting if user chose green (old
608 // setting will remain)
609 if ($option->new_value == 2)
610 return;
611
612 // for all other colors, save as normal
613 save_option($option);
614 }
615
616
617Creating Your Own Preferences Page
618----------------------------------
619
620It is also possible to create your own preferences page for a plugin. This
621is particularly useful when your plugin has numerous options or needs to
622offer special interaction with the user (for things such as changing password,
623etc.). Here is an outline of how to do so (again, using the "demo" plugin
624name):
625
626 1. Add a new listing to the main Options page. Older versions of
627 SquirrelMail offered a hook called "options_link_and_description"
628 although its use is deprecated (and it is harder to use in that
629 it requires you to write your own HTML to add the option). Instead,
630 you should always use the "optpage_register_block" hook where you
631 create a simple array that lets SquirrelMail build the HTML
632 to add the plugin options entry automatically. In setup.php in the
633 squirrelmail_plugin_init_demo() function:
634
635 $squirrelmail_plugin_hooks['optpage_register_block']['demo']
636 = 'demo_options_block';
637
638 2. Assuming the function demo_options_block() calls another function
639 elsewhere called demo_options_block_do(), that function only needs
640 to create a simple array and add it to the $optpage_blocks array:
641
642 global $optpage_blocks;
643 $optpage_blocks[] = array(
644 'name' => 'Favorite Color Settings',
645 'url' => SM_PATH . 'plugins/demo/options.php',
646 'desc' => 'Change your favorite color & find new exciting colors',
647 'js' => FALSE
648 );
649
650 The array should have four elements:
651 name The title of the plugin's options as it will be displayed on
652 the Options page
653 url The URI that points to your plugin's custom preferences page
654 desc A description of what the preferences page offers the user,
655 displayed on the Options page below the title
656 js Indicates if this option page requires the client browser
657 to be Javascript-capable. Should be TRUE or FALSE.
658
659 3. There are two different ways to create the actual preferences page
660 itself. One is to simply write all of your own HTML and other
661 interactive functionality, while the other is to define some data
662 structures that allow SquirrelMail to build your user inputs and save
663 your data automatically.
664
665 Building your own page is wide open, and for ideas, you should look at
666 any of the plugins that currently have their own preferences pages. If
667 you do this, make sure to read step number 4 below for information on
668 saving settings. In order to maintain security, consistant look and
669 feel, internationalization support and overall integrity, there are just
670 a few things you should always do in this case: define the SM_PATH
671 constant, include the file include/validate.php (see the section about
672 including other files above) and make a call to place the standard page
673 heading at the top of your preferences page. The top of your PHP file
674 might look something like this:
675
676 define('SM_PATH', '../../');
677 include_once(SM_PATH . 'include/validate.php');
678 global $color;
679 displayPageHeader($color, 'None');
680
681 From here you are on your own, although you are encouraged to do things
682 such as use the $color array to keep your HTML correctly themed, etc.
683
684 If you want SquirrelMail to build your preferences page for you,
685 creating input forms and automatically saving users' settings, then
686 you should change the 'url' attribute in the options block you created
687 in step number 2 above to read as follows:
688
689 'url' => SM_PATH . 'src/options.php?optpage=plugin_demo',
690
691 Now, you will need to use the "optpage_set_loadinfo" hook to tell
692 SquirrelMail about your new preferences page. In setup.php in the
693 squirrelmail_plugin_init_demo() function:
57945c53 694
9cd2ae7d 695 $squirrelmail_plugin_hooks['optpage_set_loadinfo']['demo']
696 = 'demo_optpage_loadinfo';
697
698 Assuming the function demo_optpage_loadinfo() calls another function
699 elsewhere called demo_optpage_loadinfo_do(), that function needs to
700 define values for four variables (make sure you test to see that it
701 is your plugin that is being called by checking the GET variable you
702 added to the url just above):
703
704 global $optpage, $optpage_name, $optpage_file,
705 $optpage_loader, $optpage_loadhook;
706 if ($optpage == 'plugin_demo')
707 {
708 $optpage_name = "Favorite Color Preferences";
709 $optpage_file = SM_PATH . 'plugins/demo/options.php';
710 $optpage_loader = 'load_optpage_data_demo';
711 $optpage_loadhook = 'optpage_loadhook_demo';
712 }
713
714 Now you are ready to build all of your options. In the file you
715 indicated for the variable $optpage_file above, you'll need to create
716 a function named the same as the value you used for $optpage_loader
717 above. In this example, the file plugins/demo/options.php should
718 have at least this function in it:
719
720 function load_optpage_data_demo()
721 {
722 $optpage_data = array();
723 $optpage_data['grps']['DEMO_PLUGIN'] = 'Demo Options';
724 $optionValues = array();
725 $optionValues[] = array(
726 'name' => 'plugin_demo_favorite_color',
727 'caption' => 'Please Choose Your Favorite Color',
728 'type' => SMOPT_TYPE_STRLIST,
729 'refresh' => SMOPT_REFRESH_ALL,
730 'posvals' => array(0 => 'red',
731 1 => 'blue',
732 2 => 'green',
733 3 => 'orange'),
734 'save' => 'save_plugin_demo_favorite_color'
735 );
736 $optpage_data['vals']['DEMO_PLUGIN'] = $optionValues;
737 return $optpage_data;
738 }
739
740 For a detailed description of how you build these options, please read
741 step number 2 for the second method of adding options to an existing
742 preferences page above. Notice that the only difference here is in the
743 very first and last lines of this function where you are actually
744 creating and returning the options array instead of just adding onto it.
745
746 That's all there is to it - SquirrelMail will create a preferences page
747 titled as you indicated for $optpage_name above, and other plugins
748 can even add extra options to this new preferences page. To do so,
749 they should use the hook name you specified for $optpage_loadhook above
750 and use the second method for adding option settings to existing
751 preferences pages described above.
752
753 4. Saving your options settings: if you used the second method in step
754 number 3 above, your settings will be saved automatically (or you can
755 define special functions to save special settings such as the
756 save_plugin_demo_favorite_color() function in the example described
757 above) and there is probably no need to follow this step. If you
758 created your own preferences page from scratch, you'll need to follow
759 this step. First, you need to register your plugin against the
760 "options_save" hook. In setup.php in the squirrelmail_plugin_init_demo()
761 function:
762
763 $squirrelmail_plugin_hooks['options_save']['demo']
764 = 'demo_save_options';
765
766 Assuming the function demo_save_options() calls another function
767 elsewhere called demo_save_options_do(), that function needs to grab
768 all of your POST and/or GET settings values and save them in the user's
769 preferences (for more about preferences, see that section below). Since
770 this is a generic hook called for all custom preferences pages, you
771 should always set "optpage" as a POST or GET variable with a string that
772 uniquely identifies your plugin:
773
774 <input type="hidden" name="optpage" value="plugin_demo">
775
776 Now in your demo_save_options_do() function, do something like this:
777
778 global $username, $data_dir, $optpage, $favorite_color;
779 if ($optpage == 'plugin_demo')
780 {
781 sqgetGlobalVar('favorite_color', $favorite_color, SQ_FORM);
782 setPref($data_dir, $username, 'favorite_color', $favorite_color);
783 }
784
785 Note that $favorite_color may not need to be globalized, although
786 experience has shown that some versions of PHP don't behave as expected
787 unless you do so. Even when you use SquirrelMail's built-in preferences
788 page generation functionality, you may still use this hook, although
789 there should be no need to do so. If you need to do some complex
790 validation routines, note that it might be better to do so in the file
791 you specified as the "$optpage_file" (in our example, that was the
792 plugins/demo/options.php file), since at this point, you can still
793 redisplay your preferences page. You could put code similar to this
794 in the plugins/demp/options.php file (note that there is no function;
795 this code needs to be executed at include time):
796
797 global $optmode;
798 if ($optmode == 'submit')
799 {
800 // do something here such as validation, etc
801 if (you want to redisplay your preferences page)
802 $optmode = '';
803 }
804
805
806Preferences
807-----------
808
809Saving and retrieving user preferences is very easy in SquirrelMail.
810SquirrelMail supports preference storage in files or in a database
811backend, however, the code you need to write to manipulate preferences
812is the same in both cases.
813
814Setting preferences:
815
816 Setting preferences is done for you if you use the built-in facilities
817 for automatic options construction and presentation (see above). If
818 you need to manually set preferences, however, all you need to do is:
819
820 global $data_dir, $username;
821 setPref($data_dir, $username, 'pref_name', $pref_value);
822
823 Where "pref_name" is the key under which the value will be stored
824 and "pref_value" is a variable that should contain the actual
825 preference value to be stored.
826
827Loading preferences:
828
829 There are two approaches to retrieving plugin (or any other) preferences.
830 You can grab individual preferences one at a time or you can add your
831 plugin's preferences to the routine that loads up user preferences at
832 the beginning of each page request. If you do the latter, making sure
833 to place your preference variables into the global scope, they will be
834 immediately available in all other plugin code. To retrieve a single
835 preference value at any time, do this:
836
837 global $data_dir, $username;
838 $pref_value = getPref($data_dir, $username, 'pref_name', 'default value');
839
840 Where "pref_name" is the preference you are retrieving, "default_value"
841 is what will be returned if the preference is not found for this user,
842 and, of course, "pref_value" is the variable that will get the actual
843 preference value.
844
845 To have all your preferences loaded at once when each page request is
846 made, you'll need to register a function against the "loading_prefs" hook.
847 For our "demo" plugin, in setup.php in the squirrelmail_plugin_init_demo()
848 function:
849
850 $squirrelmail_plugin_hooks['loading_prefs']['demo']
851 = 'demo_load_prefs';
852
853 Assuming the function demo_load_prefs() calls another function
854 elsewhere called demo_load_prefs_do(), that function just needs to
855 pull out any all all preferences you'll be needing elsewhere:
856
857 global $data_dir, $username, $pref_value;
858 $pref_value = getPref($data_dir, $username, 'pref_name', 'default value');
859
860 Remember to globalize each preference, or this code is useless.
861
862
863Internationalization
864--------------------
865
866Although this document may only be available in English, we sure hope that you
867are thinking about making your plugin useful to the thousands of non-English
868speaking SquirrelMail users out there! It is almost rude not to do so, and
869it isn't much trouble, either. This document will only describe how you can
870accomplish the internationalization of a plugin. For more general information
871about PHP and SquirrelMail translation facilities, see:
872
873http://www.squirrelmail.org/wiki/wiki.php?LanguageTranslation
874
875The unofficial way to internationalize a plugin is to put all plugin output
876into the proper format but to rely on the SquirrelMail translation facilities
877for all the rest. If the plugin were really to get translated, you'd need
878to make sure that all output strings for your plugin are either added to or
879already exist in the main SquirrelMail locale files.
880
881The better way to make sure your plugin is translated is to create your own
882locale files and what is called a "gettext domain" (see the link above for
883more information).
884
885There are three basic steps to getting your plugins internationalized: put
886all output into the proper format, switch gettext domains and create locale
887files.
888
889 1. Putting plugin output into the correct format is quite easy. The hard
890 part is making sure you catch every last echo statement. You need to
891 echo text like this:
892
893 echo _("Hello");
894
895 So, even in the HTML segments of your plugin files, you need to do this:
896
897 <input type="submit" value="<?php echo _("Submit") ?>">
898
899 You can put any text you want inside of the quotes (you MUST use double
900 quotes!), including HTML tags, etc. What you should think carefully
901 about is that some languages may use different word ordering, so this
902 might be problematic:
903
904 echo _("I want to eat a ") . $fruitName . _(" before noon");
905
906 Because some languages (Japanese, for instance) would need to translate
907 such a sentence to "Before noon " . $fruitName . " I want to eat", but
908 with the format above, they are stuck having to translate each piece
909 separately. You might want to reword your original sentence:
910
911 echo _("This is what I want to eat before noon: ") . $fruitName;
912
913 2. By default, the SquirrelMail gettext domain is always in use. That
914 means that any text in the format described above will be translated
915 using the locale files found in the main SquirrelMail locale directory.
916 Unless your plugin produces no output or only output that is in fact
917 translated under the default SquirrelMail domain, you need to create
918 your own gettext domain. The PHP for doing so is very simple. At
919 the top of any file that produces any output, place the following code
920 (again, using "demo" as the plugin name):
921
922 bindtextdomain('demo', SM_PATH . 'plugins/demo/locale');
923 textdomain('demo');
924
925 Now all output will be translated using your own custom locale files.
926 Please be sure to switch back to the SquirrelMail domain at the end
927 of the file, or many of the other SquirrelMail files may misbehave:
928
929 bindtextdomain('squirrelmail', SM_PATH . 'locale');
930 textdomain('squirrelmail');
931
932 Note that if, in the middle of your plugin file, you use any
933 SquirrelMail functions that send output to the browser, you'll need
934 to temporarily switch back to the SquirrelMail domain:
935
936 bindtextdomain('squirrelmail', SM_PATH . 'locale');
937 textdomain('squirrelmail');
938 displayPageHeader($color, 'None');
939 bindtextdomain('demo', SM_PATH . 'plugins/demo/locale');
940 textdomain('demo');
941
942 Note that technically speaking, you only need to have one bindtextdomain
943 call per file, you should always use it before every textdomain call,
944 since PHP installations without gettext compiled into them will not
945 function properly if you do not.
946
947 3. Finally, you just need to create your own locale. You should create
948 a directory structure like this in the plugin directory:
949
950 demo
951 |
952 ------locale
953 |
954 ------de_DE
955 | |
956 | ------LC_MESSAGES
957 |
958 ------ja_JP
959 |
960 ------LC_MESSAGES
961
962 Create a directories such as de_DE for each language (de_DE is German,
963 ja_JP is Japanese, etc. - check the SquirrelMail locale directory for
964 a fairly comprehensive listing). Inside of each LC_MESSAGES directory
965 you should place two files, one with your translations in it, called
966 <plugin name>.po (in this case, "demo.po"), and one that is a compiled
967 version of the ".po" file, called <plugin name>.mo (in this case,
968 "demo.mo"). On most linux systems, there is a tool you can use to pull
969 out most of the strings that you need to have translated from your PHP
970 files into a sample .po file:
971
972 xgettext --keyword=_ -d <plugin name> -s -C *.php
973
974 --keyword option tells xgettext what your strings are enclosed in
975 -d is the domain of your plugin which should be the plugin's name
976 -s tells xgettext to sort the results and remove duplicate strings
977 -C means you are translating a file with C/C++ type syntax (ie. PHP)
978 *.php is all the files you want translations for
979
980 Note, however, that this will not always pick up all strings, so you
981 should double-check manually. Of course, it's easiest if you just keep
982 track of all your strings as you are coding your plugin. Your .po file
983 will now look something like:
984
985 # SOME DESCRIPTIVE TITLE.
986 # Copyright (C) YEAR Free Software Foundation, Inc.
987 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
988 #
989 #, fuzzy
990 msgid ""
991 msgstr ""
992 "Project-Id-Version: PACKAGE VERSION\n"
993 "POT-Creation-Date: 2003-06-18 11:22-0600\n"
994 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
995 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
996 "Language-Team: LANGUAGE <LL@li.org>\n"
997 "MIME-Version: 1.0\n"
998 "Content-Type: text/plain; charset=CHARSET\n"
999 "Content-Transfer-Encoding: ENCODING\n"
1000
1001 #: functions.php:45
1002 msgid "Hello"
1003 msgstr ""
1004
1005 #: functions.php:87
1006 msgid "Favorite Color"
1007 msgstr ""
1008
1009 You should change the header to look something more like:
1010
1011 # Copyright (c) 1999-2003 The Squirrelmail Development Team
1012 # Roland Bauerschmidt <rb@debian.org>, 1999.
1013 msgid ""
1014 msgstr ""
1015 "Project-Id-Version: $Id: squirrelmail.po,v 1.10 2003/06/04 15:01:59
1016 philippe_mingo Exp $\n"
1017 "POT-Creation-Date: 2003-01-21 19:21+0100\n"
1018 "PO-Revision-Date: 2003-01-21 21:01+0100\n"
1019 "Last-Translator: Juergen Edner <juergen.edner@epost.de>\n"
1020 "Language-Team: German <squirrelmail-i18n@lists.squirrelmail.net>\n"
1021 "MIME-Version: 1.0\n"
1022 "Content-Type: text/plain; charset=ISO-8859-1\n"
1023 "Content-Transfer-Encoding: 8bit\n"
1024
1025 The most important thing to change here is the charset on the next to
1026 last line. You'll want to keep a master copy of the .po file and make
1027 a copy for each language you have a translation for. You'll need to
1028 translate each string in the .po file:
1029
1030 msgid "Hello"
1031 msgstr "Guten Tag"
1032
1033 After you're done translating, you can create the .mo file very simply
1034 by running the following command (available on most linux systems):
1035
1036 msgfmt -0 <plugin name>.mo <plugin name>.po
1037
1038 In the case of the "demo" plugin:
1039
1040 msgfmt -0 demo.mo demo.po
1041
1042 Please be sure that the .po and .mo files both are named exactly the
1043 same as the domain you bound in step 2 above and everything else works
1044 automatically. In SquirrelMail, go to Options -> Display Preferences
1045 and change your Language setting to see the translations in action!
1046
1047
1048PLUGIN STANDARDS AND REQUIREMENTS
1049=================================
1050
1051The SquirrelMail project has some important goals, such as avoiding the
1052use of JavaScript, avoiding non-standard HTML tags, keeping file sizes
1053small and providing the fastest webmail client on the Internet. As such,
1054we'd like it if plugin authors coded with the same goals in mind that the
1055core developers do. Common sense is always a good tool to have in your
1056programming repertoire, but below is an outline of some standards that we
1057ask you as a plugin developer to meet. Depending upon how far you bend
1058these rules, we may not want to post your plugin on the SquirrelMail
1059website... and of course, no one really wants your efforts to go to waste
1060and for the SquirrelMail community to miss out on a potentially useful
1061plugin, so please try to follow these guidelines as closely as possible.
1062
1063
1064Small setup.php
1065---------------
1066
1067In order for SquirrelMail to remain fast and lean, we are now asking
1068that all plugin authors remove all unnecessary functionality from setup.php
1069and refactoring it into another file. There are a few ways to accomplish
1070this, none of which are difficult. At a minimum, you'll want to have the
1071squirrelmail_plugin_init_<plugin name>() function in setup.php, and naturally,
1072you'll need functions that are merely stubs for each hook that you are using.
1073One (but not the only) way to do it is:
1074
1075 function squirrelmail_plugin_init_demo()
1076 {
1077 global $squirrelmail_plugin_hooks;
1078 $squirrelmail_plugin_hooks['generic_header']['demo'] = 'plugin_demo_header';
1079 }
1080 function plugin_demo_header()
1081 {
1082 include_once(SM_PATH . 'plugins/demo/functions.php');
1083 plugin_demo_header_do();
1084 }
1085
1086
1087Internationalization
1088--------------------
1089
1090Q: What is more disappointing to users in France who would make good
1091 use of your plugin than learning that it is written entirely in English?
1092A: Learning that they cannot send you a French translation file for your
1093 plugin.
1094
1095There are thousands of users out there whose native tongue is not English,
1096and when you develop your plugin without going through the three simple steps
1097needed to internationalize it, you are effectively writing them all off.
1098PLEASE consider internationalizing your plugin!
1099
1100
1101Developing with E_ALL
1102---------------------
1103
1104When you are developing your plugin, you should always have error reporting
1105turned all the way up. You can do this by changing two settings in your
1106php.ini and restarting your web server:
1107
1108 display_errors = Off
1109 error_reporting = E_ALL
1110
1111This way, you'll be sure to see all Notices, Warnings and Errors that your
1112code generates (it's OK, really, it happens to the best of us... except me!).
1113Please make sure to fix them all before you release the plugin.
1114
1115
1b6b1526 1116Compatibility with register_globals=Off
1117---------------------------------------
1118
1119Most sensible systems administrators now run their PHP systems with the
1120setting "register_globals" as OFF. This is a prudent security setting,
1121and as the SquirrelMail core code has long since been upgraded to work
1122in such an environment, we are now requiring that all plugins do the same.
1123Compatibility with this setting amounts to little more than explicitly
1124gathering any and all variables you sent from a <form> tag as GET or POST
1125values instead of just assuming that they will be placed in the global
1126scope automatically. There is nothing more to do than this:
1127
1128 global $favorite_color;
1129 sqgetGlobalVar('favorite_color', $favorite_color, SQ_FORM);
1130
1131
9cd2ae7d 1132Extra Blank Lines
1133-----------------
1134
1135It may seem innocuous, but if you have any blank lines either before the
1136first <?php tag or after the last ?> tag in any of your plugin files, you
1137you will break SquirrelMail in ways that may seem entirely unrelated. For
1138instance, this will often cause a line feed character to be included with
1139email attachments when they are viewed or downloaded, rendering them useless!
1140
1141
1142include_once
1143------------
1144
1145When including files, please make sure to use the include_once() function
1146and NOT include(), require(), or require_once(), since these all are much
1147less efficient than include_once() and can have a cumulative effect on
1148SquirrelMail performance.
1149
1150
1151Version Reporting
1152-----------------
1153
1154In order for systems administrators to keep better track of your plugin and
1155get upgrades more efficiently, you are requested to make version information
1156available to SquirrelMail in a format that it understands. There are two
1157ways to do this. Presently, we are asking that you do both, since we are
1158still in a transition period between the two. This is painless, so please
1159be sure to include it:
1160
1161 1. Create a file called "version" in the plugin directory. That file
1162 should have only two lines: the first line should have the name of
1163 the plugin as named on the SquirrelMail web site (this is often a
1164 prettified version of the plugin directory name), the second line
1165 must have the version and nothing more. So for our "demo" plugin,
1166 whose name on the web site might be something like "Demo Favorite
1167 Colors", the file plugins/demo/version should have these two lines:
1168
1169 Demo Favorite Colors
1170 1.0
1171
1172 2. In setup.php, you should have a function called <plugin name>_version().
1173 That function should return the version of your plugin. For the "demo"
1174 plugin, that should look like this:
1175
1176 function demo_version()
1177 {
1178 return '1.0';
1179 }
1180
1181
1182Configuration Files
1183-------------------
1184
1185It is common to need a configuration file that holds some variables that
1186are set up at install time. For ease of installation and maintenance, you
1187should place all behavioral settings in a config file, isolated from the
1188rest of your plugin code. A typical file name to use is "config.php". If
1189you are using such a file, you should NOT include a file called "config.php"
1190in your plugin distribution, but instead a copy of that file called
1191"config.php.sample". This helps systems administrators avoid overwriting
1192the "config.php" files and losing all of their setup information when they
1193upgrade your plugin.
1194
1195
1196Session Variables
1197-----------------
1198
1199In the past, there have been some rather serious issues with PHP sessions
1200and SquirrelMail, and certain people have worked long and hard to ensure
1201that these problems no longer occur in an extremely wide variety of OS/PHP/
1202web server environments. Thus, if you need to place any values into the
1203user's session, there are some built-in SquirrelMail functions that you are
1204strongly encouraged to make use of. Using them also makes your job easier.
1205
1206 1. To place a variable into the session:
1207
1208 global $favorite_color;
1209 $favoriteColor = 'green';
1210 sqsession_register($favorite_color, 'favorite_color');
1211
1212 Strictly speaking, globalizing the variable shouldn't be necessary,
1213 but certain versions of PHP seem to behave more predictably if you do.
1214
1215 2. To retrieve a variable from the session:
1216
1217 global $favorite_color;
1218 sqgetGlobalVar('favorite_color', $favorite_color, SQ_SESSION);
1219
1220 3. You can also check for the presence of a variable in the session:
1221
1222 if (sqsession_is_registered('favorite_color'))
1223 // do something important
1224
1225 4. To remove a variable from the session:
1226
ea26c996 1227 global $favorite_color;
9cd2ae7d 1228 sqsession_unregister('favorite_color');
1229
ea26c996 1230 Strictly speaking, globalizing the variable shouldn't be necessary,
1231 but certain versions of PHP seem to behave more predictably if you do.
1232
9cd2ae7d 1233
1234Form Variables
1235--------------
1236
1237You are also encouraged to use SquirrelMail's built-in facilities to
1238retrieve variables from POST and GET submissions. This is also much
1239easier on you and makes sure that all PHP installations are accounted
1240for (such as those that don't make the $_POST array automatically
1241global, etc.):
1242
1243 global $favorite_color;
1244 sqgetGlobalVar('favorite_color', $favorite_color, SQ_FORM);
1245
1246
1247Files In Plugin Directory
1248-------------------------
1249
1250There are a few files that you should make sure to include when you build
1251your final plugin distribution:
1252
1253 1. A copy of the file index.php from the main plugins directory. When
1254 working in your plugin directory, just copy it in like this:
1255
1256 $ cp ../index.php .
1257
1258 This will redirect anyone who tries to browse to your plugin directory
1259 to somewhere more appropriate. If you create other directories under
1260 your plugin directory, you may copy the file there as well to be extra
1261 safe. If you are storing sensitive configuration files or other data
1262 in such a directory, you could even include a .htaccess file with the
1263 contents "Deny From All" that will disallow access to that directory
1264 entirely (when the target system is running the Apache web server).
1265 Keep in mind that not all web servers will honor an .htaccess file, so
1266 don't depend on it for security. Make sure not to put such a file in
1267 your main plugin directory!
1268
1269 2. A file that describes your plugin and offers detailed instructions for
1270 configuration or help with troubleshooting, etc. This file is usually
1271 entitled "README". Some useful sections to include might be:
1272
1273 Plugin Name and Author
1274 Current Version
1275 Plugin Features
1276 Detailed Plugin Description
1277 How-to for Plugin Configuration
1278 Change Log
1279 Future Ideas/Enhancements/To Do List
1280
1281 3. A file that explains how to install your plugin. This file is typically
1282 called "INSTALL". If you do not require any special installation
1283 actions, you can probably copy one from another plugin or use this as
1284 a template:
1285
1286 Installing the Demo Plugin
1287 ==========================
1288
1289 1) Start with untaring the file into the plugins directory.
1290 Here is a example for the 1.0 version of the Demo plugin.
1291
1292 $ cd plugins
1293 $ tar -zxvf demo-1.0-1.4.0.tar.gz
1294
1295 2) Change into the demo directory, copy config.php.sample
1296 to config.php and edit config.php, making adjustments as
1297 you deem necessary. For more detailed explanations about
1298 each of these parameters, consult the README file.
1299
1300 $ cd demo
1301 $ cp config.php.sample config.php
1302 $ vi config.php
1303
1304
1305 3) Then go to your config directory and run conf.pl. Choose
1306 option 8 and move the plugin from the "Available Plugins"
1307 category to the "Installed Plugins" category. Save and exit.
1308
1309 $ cd ../../config/
1310 $ ./conf.pl
1311
1312
1313 Upgrading the Demo Plugin
1314 =========================
1315
1316 1) Start with untaring the file into the plugins directory.
1317 Here is a example for the 3.1 version of the demo plugin.
1318
1319 $ cd plugins
1320 $ tar -zxvf demo-3.1-1.4.0.tar.gz
1321
1322
1323 2) Change into the demo directory, check your config.php
1324 file against the new version, to see if there are any new
1325 settings that you must add to your config.php file.
1326
1327 $ diff -Nau config.php config.php.sample
1328
1329 Or simply replace your config.php file with the provided sample
1330 and reconfigure the plugin from scratch (see step 2 under the
1331 installation procedure above).
1332
1333
1334COMPATIBILITY WITH OLDER VERSIONS OF SQUIRRELMAIL
1335=================================================
1336
1337Whenever new versions of SquirrelMail are released, there is always a
1338considerable lag time before it is widely adopted. During that transitional
1339time, especially when the new SquirrelMail version contains any architectural
1340and/or functional changes, plugin developers are put in a unique and very
1341difficult position. That is, there will be people running both the old and
1342new versions of SquirrelMail who want to use your plugin, and you will
1343probably want to accomodate them both.
1344
1345The easiest way to keep both sides happy is to keep two different versions
1346of your pluign up to date, one that runs under the older SquirrelMail, and
1347one that requires the newest SquirrelMail. This is inconvenient, however,
1348especially if you are continuing to develop the plugin. Depending on the
1349changes the SquirrelMail has implemented in the new version, you may be able
1350to include code that can auto-sense SquirrelMail version and make adjustments
1351on the fly. There is a function available to you for determining the
1352SquirrelMail version called check_sm_version() and it can be used as such:
1353
1354 check_sm_version(1, 4, 0)
1355
1356This will return TRUE if the SquirrelMail being used is at least 1.4.0, and
1357FALSE otherwise.
1358
1359As this document is written, we are in a transition period between versions
13601.2.11 and 1.4.0. There is a plugin called "Compatibilty" that is intended
1361for use by plugin authors so they can develop one version of their plugin
1362and seamlessly support both 1.2.x and 1.4.x SquirrelMail installations. For
1363more information about how to use the "Compatibility" plugin, download it and
1364read its README file or see:
1365
1366 http://www.squirrelmail.org/wiki/wiki.php?PluginUpgrading
1367
1368
1369REQUESTING NEW HOOKS
1370====================
1371
1372It's impossible to foresee all of the places where hooks might be useful
1373(it's also impossible to put in hooks everywhere!), so you might need to
1374negotiate the insertion of a new hook to make your plugin work. In order
1375to do so, you should post such a request to the squirrelmail-devel mailing
1376list.
1377
1378
1379HOW TO RELEASE YOUR PLUGIN
1380==========================
1381
1382As long as you've consulted the list of plugin standards and done your
1383best to follow them, there's little standing in the way of great fame as an
1384official SquirrelMail plugin developer.
1385
1386 1. Make a distribution file. There is a convenient Perl script in
1387 the plugins directory that will help you do this:
1388
1389 make_archive.pl -v demo 1.0 1.4.0
1390
1391 -v is optional and indicates that the script should run in verbose mode
1392 demo is the name of your plugin
1393 1.0 is the version of your plugin
1394 1.4.0 is the version of SquirrelMail that is required to run your plugin
1395
1396 You can also create the distribution file manually in most *nix
1397 environments by running this command from the plugins directory (NOT
1398 your plugin directory):
1399
1400 $ tar czvf demo-1.0-1.4.0.tar.gz demo
1401
1402 Where "demo" is the name of your plugin, "1.0" is the version of
1403 your plugin, and "1.4.0" is the version of SquirrelMail required
1404 to use your plugin.
1405
1406 2. Consult the SquirrelMail web site for contact information for the
1407 Plugins Team Leaders, to whom you should make your request. If they
1408 do not respond, you should feel free to ask for help contacting them
1409 on the squirrelmail-plugins mailing list.
1410
1411 http://www.squirrelmail.org/wiki/wiki.php?SquirrelMailLeadership
1412