1<?php
2
3/**
4 * phplistPlugin main class to extend for plugins.
5 */
6
7/**
8 * a plugin for phpList should extend this class to work. Once you have extended
9 * you can implement all the hooks provided to manipulate the functionality of phpList
10 * in many places.
11 */
12require_once dirname(__FILE__).'/accesscheck.php';
13
14class phplistPlugin
15{
16    public $name = 'Default Plugin';
17    public $version = 'unknown';
18    public $authors = '';
19    public $description = 'No description';
20    public $documentationUrl = ''; //# link to documentation for this plugin (eg https://resources.phplist.com/plugin/pluginname
21    public $enabled = 1; // use directly, can be privitsed later and calculated with __get and __set
22    public $system_root = ''; //# root dir of the phpList admin directory
23
24    //@@Some ideas to implement this:
25    // * Start each method with if (!$this->enabled) return parent :: parentMethod($args);
26    // * Don't add to manage Global plugins if disabled
27    public $coderoot = './PLUGIN_ROOTDIR/defaultplugin/'; // coderoot relative to the phplist admin directory
28    // optional configuration variables
29    public $configvars = array();
30    // config var    array( type, name [array values]));
31    public $DBstruct = array();
32
33    // These files can be called from the commandline
34    // The variable holds an array of page names, (the file name without .php) and the files must be in the $coderoot directory.
35    public $commandlinePluginPages = array();
36
37    // An array of page names that can be called as public pages, e.g. www.mysite.com/lists/?pi=myplugin&p=mypage
38    // The page name is the file name without .php. The files must be in the $coderoot directory
39    public $publicPages = array();
40
41    // Pages that can be called using the remote processing secret parameter,
42    // e.g. www.mysite.com/lists/admin/?pi=myplugin&page=mypage&secret=1234567890
43    public $remotePages = array();
44
45    public $configArray = array();
46
47    public $importTabTitle = ''; //# title of the tab for the import page
48
49    public $needI18N = 0;
50
51    /**
52     * set to true, if this plugin provides the WYSIWYG editor for the send page
53     * the plugin will then need to implement:.
54     *
55     * function editor($fieldname,$fieldvalue)
56     *
57     * which returns the HTML for the editor.
58     */
59    public $editorProvider = false;
60
61    /** set to true, if this plugin provides verification of the administrator login
62     * the plugin will then need to implement a variety of methods, check the docs.
63     */
64    public $authProvider = false;
65
66    /**
67     * The priority of this plugin.
68     * phplist will activate() plugins in descending priority order
69     */
70    public $priority = 10;
71
72    /**
73     * Holds tablename -> real table mapping
74     */
75    public $tables = array();
76
77    /**
78     * array of pages in this plugin to add to the main menu
79     *
80     * example format:
81     *      array(
82     *          'page' => array('category' => 'subscribers'),
83     *      )
84     *
85     * valid categories are:
86     *
87     * subscribers
88     * campaigns
89     * statistics
90     * system
91     * config
92     * develop (will only show up in "dev" mode)
93     * info
94     *
95     */
96    public $topMenuLinks = array();
97
98    /**
99     * titles of pages in the plugin, this is used in the listing of the pages in the menu
100     *
101     * example:
102     *    array(
103     *      'page' => 'Title of page'
104     *    )
105     */
106    public $pageTitles = array();
107
108    /**
109     * dependency check
110     *
111     * provides tests to determine whether this plugin can be used
112     * example:
113     *    array(
114     *        'description of dependency' => condition for plugin to be enabled
115     *    )
116     */
117    public function dependencyCheck()
118    {
119        return array(
120            'phpList version' => version_compare(VERSION, '3.0.12') >= 0,
121        );
122    }
123
124    /**
125     * name of this plugin.
126     */
127    public function name()
128    {
129        return $this->name;
130    }
131
132    /**
133     * constructor
134     * plugins should not run SQL queries as construction time
135     * use the "activate" function instead
136     * that way you can use processDBerror to handle DB errors
137     */
138    public function __construct()
139    {
140        $this->phplistplugin();
141    }
142
143    public function phplistplugin()
144    {
145        // constructor
146        // Startup code, other objects might not be constructed yet
147        //print ("<BR>Construct " . $this->name);
148        //# try to prepend PLUGIN ROOTDIR, if necessary
149        if (!is_dir($this->coderoot)) {
150            $this->coderoot = PLUGIN_ROOTDIR.'/'.$this->coderoot;
151        }
152        //# always enable in dev mode
153        if (!empty($GLOBALS['developer_email'])) {
154            $this->enabled = 1;
155        }
156        $this->importTabTitle = $this->name;
157        $this->system_root = dirname(__FILE__);
158        $this->version = $this->getVersion();
159        //# map table names
160        $me = new ReflectionObject($this);
161        foreach ($this->DBstruct as $table => $structure) {
162            $this->tables[$table] = $GLOBALS['table_prefix'].$me->getName().'_'.$table;
163        }
164    }
165
166    public function getVersion()
167    {
168        $version = array();
169        $me = new ReflectionObject($this);
170
171        //# interesting trick from Dokuwiki inc/infoutils.php
172        if (is_dir(dirname($me->getFileName()).'/../.git')) {
173            $version['type'] = 'Git';
174            $version['date'] = 'unknown';
175
176            $inventory = dirname($me->getFileName()).'/../.git/logs/HEAD';
177            if (is_file($inventory)) {
178                $sz = filesize($inventory);
179                $seek = max(0, $sz - 2000); // read from back of the file
180                $fh = fopen($inventory, 'rb');
181                fseek($fh, $seek);
182                $chunk = fread($fh, 2000);
183                fclose($fh);
184                $chunk = trim($chunk);
185                $chunk = @array_pop(explode("\n", $chunk));   //last log line
186                $chunk = @array_shift(explode("\t", $chunk)); //strip commit msg
187                $chunk = explode(' ', $chunk);
188                array_pop($chunk); //strip timezone
189                $date = date('Y-m-d', array_pop($chunk));
190                if ($date) {
191                    $version['date'] = $date;
192                }
193            }
194
195            return $version['type'].' - '.$version['date'];
196        }
197
198        return $this->version;
199    }
200
201    public function initialise()
202    {
203        global $table_prefix;
204        $me = new ReflectionObject($this);
205        $plugin_initialised = getConfig(md5('plugin-'.$me->getName().'-initialised'));
206        if (empty($plugin_initialised)) {
207            foreach ($this->DBstruct as $table => $structure) {
208                if (!Sql_Table_exists($table_prefix.$me->getName().'_'.$table)) {
209                    //  print s('Creating table').' '.$table . '<br/>';
210                    Sql_Create_Table($table_prefix.$me->getName().'_'.$table, $structure);
211                }
212            }
213            saveConfig(md5('plugin-'.$me->getName().'-initialised'), time(), 0);
214        }
215    }
216
217    public function upgrade($previous)
218    {
219        return true;
220    }
221
222    /**
223     * Allows a plugin to override the default check for a new version.
224     *
225     * @param array $pluginDetails
226     *
227     * @returns string|false|null new version, or false if update not available, or null to use the default update check
228     *
229     */
230    public function checkForUpdate(array $pluginDetails)
231    {
232    }
233
234    /**
235     * Startup code, all other objects are constructed
236     * returns success or failure, false means we cannot start
237     */
238    public function activate()
239    {
240        if (isset($this->settings)) {
241            foreach ($this->settings as $item => $itemDetails) {
242                $GLOBALS['default_config'][$item] = $itemDetails;
243                $GLOBALS['default_config'][$item]['hidden'] = false;
244            }
245        }
246    }
247
248    /**
249     * Return html snippet to tell about copyrights of used third party code.
250     * @note Plugin author is already displayed elsewhere
251     */
252    public function displayAbout()
253    {
254        return;
255    }
256
257    /**
258     * Return i18n Language Dir so that main page content can be extended
259     */
260    public function i18nLanguageDir()
261    {
262        return;
263    }
264
265    public function pageTitle($page)
266    {
267        if (isset($this->pageTitles[$page])) {
268            return s($this->pageTitles[$page]);
269        }
270
271        return $this->name.' : '.$page;
272    }
273
274    public function pageTitleHover($page)
275    {
276        if (isset($this->pageTitleHover[$page])) {
277            return s($this->pageTitleHover[$page]);
278        }
279
280        return $this->name.' : '.$page;
281    }
282
283    /**
284     * deleteSent - wipe DB entries marking a campaign sent for subscribers
285     * this is used in DEV mode only.
286     */
287    public function deleteSent()
288    {
289    }
290
291    /**
292     * write a value to the general config to be retrieved at a later stage
293     * parameters: name -> name of the variable
294     * value -> value of the variablesiable, can be a scalar, array or object
295     * returns success or failure    $store = '';
296     */
297    public function writeConfig($name, $value)
298    {
299        if (is_object($value) || is_array($value)) {
300            $store = 'SER:'.serialize($value);
301        } else {
302            $store = $value;
303        }
304        Sql_Query(sprintf('replace into %s set item = "%s-%s",value="%s",editable=0', $GLOBALS['tables']['config'],
305            $this->name, addslashes($name), addslashes($store)));
306        //# force refresh of config in session
307        unset($_SESSION['config']);
308
309        return 1;
310    }
311
312    /**
313     * read a value from the general config to be retrieved at a later stage
314     * parameters: name -> name of the variable
315     * returns value
316     */
317    public function getConfig($name)
318    {
319        if (isset($_SESSION['config'][$this->name.'-'.addslashes($name)])) {
320            return $_SESSION['config'][$this->name.'-'.addslashes($name)];
321        }
322
323        $req = Sql_Fetch_Array_Query(sprintf('select value from  %s where item = "%s-%s"', $GLOBALS['tables']['config'],
324            $this->name, addslashes($name)));
325        $result = stripslashes($req[0]);
326        if (!empty($result) && strpos('SER:', $result) == 1) {
327            $result = substr($result, 4);
328            $value = unserialize($result);
329        } else {
330            $value = $result;
331        }
332        $_SESSION['config'][$this->name.'-'.addslashes($name)] = $value;
333
334        return $result;
335    }
336
337    /**
338     * displayConfig
339     * purpose: display input for a config variable in the backend
340     * parameters:
341     * name -> name of the config variable, as found in $this->configvars
342     * return, HTML snippet of input to slot into a form
343     */
344    public function displayConfig($name)
345    {
346        $name = trim(strtolower($name));
347        $name = preg_replace('/\W/', '', $name);
348        $type = $this->configvars[$name][0];
349        $label = $this->configvars[$name][1];
350        $currentvalue = $this->getConfig($name);
351        $html = '';
352        switch ($type) {
353            case 'attributeselect':
354                $html = sprintf('<select name="%s"><option value=""> --%s</option>', $name,
355                    $GLOBALS['I18N']->get('choose'));
356                $req = Sql_Query(sprintf('select * from %s', $GLOBALS['tables']['attribute']));
357                while ($row = Sql_Fetch_Array($req)) {
358                    $html .= sprintf('<option value="%d" %s>%s</option>', $row['id'],
359                        $row['id'] == $currentvalue ? 'selected="selected"' : '',
360                        substr(htmlspecialchars($row['name']), 0, 25));
361                }
362                $html .= '</select>';
363
364                return $html;
365            case 'radio':
366                $values = $this->configvars[$name][2];
367                foreach ($values as $key => $label) {
368                    $html .= sprintf('<input type="radio" name="%s" value="%s" %s> %s', $name, $key,
369                        $currentvalue == $key ? 'checked="checked"' : '', $label);
370                }
371
372                return $html;
373            case 'textarea':
374                $html = sprintf('<textarea name="%s" rows="10" cols="40" wrap="virtual">%s </textarea>', $name,
375                    htmlspecialchars($currentvalue));
376
377                return $html;
378            case 'text':
379            default:
380                $html = sprintf('<input type="text" name="%s" value="%s" size="45">', $name,
381                    htmlspecialchars($currentvalue));
382
383                return $html;
384        }
385    }
386
387    //###########################################################
388    // Main interface hooks
389
390    public function adminmenu()
391    {
392        return array(
393            // page, description
394            'main'       => 'Main Page',
395            'helloworld' => 'Hello World page',
396        );
397    }
398
399    //###########################################################
400    // Frontend
401
402    /**
403     * return snippet for the Subscribe page
404     */
405    public function displaySubscriptionChoice($pageData, $userID = 0)
406    {
407        return '';
408    }
409
410    public function validateSubscriptionPage($pageData)
411    {
412        return;
413    }
414
415    /**
416     * parse the text of the thankyou page
417     * parameters:
418     * pageid -> id of the subscribe page
419     * userid -> id of the user
420     * text -> current text of the page
421     * returns parsed text
422     */
423    public function parseThankyou($pageid = 0, $userid = 0, $text = '')
424    {
425        return $text;
426    }
427
428    public function subscriberConfirmation($subscribepageID, $userdata = array())
429    {
430    }
431
432    //###########################################################
433    // Messages
434
435    /**
436     * displayMessages
437     *  obsolete
438     * @return string
439     */
440    public function displayMessages($msg, &$status)
441    {
442        return '';
443    }
444
445    //###########################################################
446    // Message
447
448    /**
449     * add a tab to the "Send a Message page" for options to be set in the plugin
450     * @param messageid ID of the message being displayed (should always be > 0)
451     * @param messagedata associative array of all data from the db for this message
452     * @return HTML code to slot into the form to submit to the database
453     */
454    public function sendMessageTab($messageid = 0, $messagedata = array())
455    {
456        return '';
457    }
458
459    /**
460     * If adding a TAB to the Send a Message page, what is the TAB's name
461     * parameters: none
462     * @return short title (less than about 10 characters)
463     */
464    public function sendMessageTabTitle($messageid = 0)
465    {
466
467        return '';
468    }
469
470    /**
471     * If adding a TAB to the Send a Message page, try to insert the tab before the one returned here by title
472     * parameters: none
473     * returns: tab title to insert before
474     */
475    public function sendMessageTabInsertBefore()
476    {
477        return false;
478    }
479
480    /** sendMessageTabSave
481     * called before a campaign is being saved. All data will be saved by phpList,
482     * but you can capture it here and save it elsewhere if you need to.
483     *
484     * @param messageid integer: id of the campaign
485     * @param messagedata array: associative array with all data
486     */
487    public function sendMessageTabSave($messageid = 0, $data = array())
488    {
489        return '';
490    }
491
492    public function sendFormats()
493    {
494        //# sendFormats();
495        // parameters: none
496        // returns array of "shorttag" => "description" of possible formats this plugin can provide
497        // this will be listed in the "Send As" list of radio buttons, so that an editor can choose the format
498        // prefix the shorttag with _ to suppress it from the send page (for internal use)
499        return array();
500    }
501
502    /**
503     * Called when viewing a message
504     * The plugin can return a caption and a value that will be displayed as an additional row.
505     * Each can include HTML and should be html encoded.
506     *
507     * @param messageid integer: id of the campaign
508     * @param messagedata array: associative array of message data
509     *
510     * @return array 2-element array, [0] caption, [1] value.
511     *               or false if the plugin does not want to display a row
512     */
513    public function viewMessage($messageid, array $messagedata)
514    {
515        return false;
516    }
517
518    /**
519     * HelloWorld
520     * just a simple check
521     */
522    public function HelloWorld($params)
523    {
524        echo 'Hello to you from '.$this->name;
525    }
526
527    //###########################################################
528    // Processqueue
529
530    /**
531     * canSend
532     *
533     * can this message be sent to this subscriber
534     * if false is returned, the message will be identified as sent to the subscriber
535     * and never tried again
536     *
537     * @param $messagedata array of all message data
538     * @param $userdata array of all user data
539     * returns bool: true, send it, false don't send it
540     */
541    public function canSend($messagedata, $subscriberdata)
542    {
543        return true; //@@@
544    }
545
546    /**
547     * throttleSend
548     *
549     * can this message be sent to this subscriber
550     * if false is returned, the message will be identified as failed
551     * and re-tried in the next queue run
552     *
553     * @param $messagedata array of all message data
554     * @param $userdata array of all user data
555     * returns bool: true, do not send it, false send it
556     */
557    public function throttleSend($messagedata, $subscriberdata)
558    {
559        return false;
560    }
561
562    /**
563     * throttleDomainMap
564     *
565     * Return the mapping of the domain for throttling
566     * Only the first plugin that returns a non-false value will be used
567     *
568     * @param string $domain domain to map
569     * @return string mapping or false if not mapped
570     */
571    public function throttleDomainMap($domain)
572    {
573        return false;
574    }
575
576    /**
577     * messageStatusLimitReached.
578     *
579     * @param $recentlySent integer
580     *
581     * @return text to display in the status panel of the active message
582     */
583    public function messageStatusLimitReached($recentlySent)
584    {
585        return '';
586    }
587
588    /**
589     * messageStatus
590     * @param int    $id     messageid
591     * @param string $status message status
592     *
593     * @return possible additional text to display
594     */
595    public function messageStatus($id, $status)
596    {
597        return '';
598    }
599
600    /**
601     * Allows plugins to modify the fields of the loaded campaign.
602     * Those fields will then be customised for each subscriber
603     *
604     * @param integer $messageid: ID of the message
605     * @param array   &$message: associative array of message data
606     * @return void
607     */
608    public function processPrecachedCampaign($messageid, array &$message)
609    {
610    }
611
612    /**
613     * handle the moment that sending a campaign has finished.
614     * this is after the campaign has been potentially duplicated for repetition.
615     *
616     * @param int $messageid ID of the campaign
617     * @param array messagedata associative array with the current message data
618     */
619    public function processSendingCampaignFinished($messageid, array $messagedata)
620    {
621    }
622
623    /**
624     * parseOutgoingTextMessage
625     * @param integer messageid: ID of the message
626     * @param string  content: entire text content of a message going out
627     * @param string  destination: destination email
628     * @param array   userdata: associative array with data about user
629     * @return string parsed content
630     */
631    public function parseOutgoingTextMessage($messageid, $content, $destination, $userdata = null)
632    {
633        return $content;
634    }
635
636    /**
637     * parseOutgoingHTMLMessage
638     * @param integer messageid: ID of the message
639     * @param string  content: entire text content of a message going out
640     * @param string  destination: destination email
641     * @param array   userdata: associative array with data about user
642     * @return string parsed content
643     */
644    public function parseOutgoingHTMLMessage($messageid, $content, $destination, $userdata = null)
645    {
646        return $content;
647    }
648
649    /**
650      * getMessageAttachment($messageid,$mail->Body);
651      * parameters: $messageid,$messagecontent
652      * @return array (
653      *  'content' => Content of the attachment
654      *  'filename' => name of the attached file
655      *  'mimetype' => mimetype of the attachment
656      *  );
657      */
658    public function getMessageAttachment($messageid, $content)
659    {
660        return array();
661    }
662
663    /**
664     * mimeWrap
665     * purpose: wrap the actual contents of the message in another MIME layer
666     * Designed to ENCRYPT the fully expanded message just before sending
667     * Designed to be called by phplistmailer
668     * parameters:
669     *   messageid: message being sent
670     *   body: current body of message
671     *   header: current header of message, except for the Content-Type
672     *   contenttype: Content-Type of message
673     *   destination: email that this message is going out to
674     * returns array(newheader,newbody,newcontenttype)
675     */
676    public function mimeWrap($messageid, $body, $header, $contenttype, $destination)
677    {
678        return array(
679            $header,
680            $body,
681            $contenttype,
682        );
683    }
684
685    /**
686     * setFinalDestinationEmail
687     * purpose: change the actual recipient based on user Attribute values:
688     * parameters:
689     *   messageid: message being sent
690     *   uservalues: array of "attributename" => "attributevalue" of all user attributes
691     *   email: email that this message is current set to go out to
692     * @returN email that it should go out to
693     */
694    public function setFinalDestinationEmail($messageid, $uservalues, $email)
695    {
696        return $email;
697    }
698
699    /**
700     * messageHeaders.
701     *
702     * return headers for the message to be added, as "key => val"
703     *
704     * @param object $mail
705     *
706     * @return array (headeritem => headervalue)
707     */
708    public function messageHeaders($mail)
709    {
710        return array();
711    }
712
713    /**
714     * parseFinalMessage
715     * purpose: create the actual message, based on the text and html content as prepared by phplist
716     * parameters:
717     * sendformat: the send format chosen by the admin
718     *    if this is not one of the sendFormats() set up for this plugin, return 0
719     * htmlmessage: contents of HTML version of message
720     * textmessage: contents of Text version of message
721     * mail:  mail object that is going to be send.
722     *
723     * ### you can alter the outgoing mail by calling the required methods of the mail object
724     * returns 1 if the message has been dealt with successfully and 0 if not
725     */
726    public function parseFinalMessage($sendformat, $htmlmessage, $textmessage, &$mail, $messageid)
727    {
728        return 0;
729    }
730
731    /**
732     * process the success or failure of sending an email in $sendformat.
733     *
734     * @deprecated, no longer used since 3.2.4
735     */
736    public function processSuccesFailure($messageid, $sendformat, $userdata, $success = true)
737    {
738    }
739
740    /**
741     * processSendSuccess.
742     *
743     * called when sending of this messageid to this subscriber was successful
744     *
745     * @param messageid integer
746     * @param userdata array
747     * @param isTest boolean, true when testmessage
748     */
749    public function processSendSuccess($messageid, $userdata, $isTest = false)
750    {
751    }
752
753    /**
754     * processSendFailed.
755     *
756     * called when sending of this messageid to this subscriber failed
757     *
758     * @param messageid integer
759     * @param userdata array
760     * @param isTest boolean, true when testmessage
761     */
762    public function processSendFailed($messageid, $userdata, $isTest = false)
763    {
764    }
765
766    /*
767     * processSendStats
768     * called when sending a campaign has finished
769     * @param integer $sent - amount sent
770     * @param integer $invalid - amount invalid
771     * @param integer $failed_sent - amount failed
772     * @param integer $unconfirmed - amount unconfirmed
773     *
774     * receive stats from phpList for further handling
775     * @return null
776     */
777    public function processSendStats($sent = 0, $invalid = 0, $failed_sent = 0, $unconfirmed = 0, $counters = array())
778    {
779        return;
780    }
781
782    /**
783     * sendReport
784     * @param string $subject
785     * @param string $message
786     * @return bool -> true if report has been processed and dealt with
787     */
788    public function sendReport($subject, $message)
789    {
790        return false;
791    }
792
793    /**
794     * sendError
795     * @param string $subject
796     * @param string $to
797     * @param string $message
798     * @return null
799     */
800    public function sendError($subject, $to = '', $message = '')
801    {
802    }
803
804    /**
805     * processDBerror
806     * @param integer $error number
807     * @return null
808     */
809    public function processDBerror($errorid)
810    {
811    }
812
813    /**
814     * importReport
815     * called when a subscriber import has finished
816     * @param string $report
817     * @return null
818     */
819    public function importReport($report)
820    {
821    }
822
823    /**
824     * processError
825     * @param string msg
826     */
827    public function processError($msg)
828    {
829    }
830
831    /**
832     * processQueueStart
833     * called at the beginning of processQueue, after the process was locked
834     * @param none
835     * @return null
836     */
837    public function processQueueStart()
838    {
839    }
840
841    /**
842     * allowProcessQueue
843     * called at the beginning of processQueue
844     * if this returns anything but "true" processing will be cancelled
845     * @param none
846     * @return bool
847     */
848    public function allowProcessQueue()
849    {
850        return true;
851    }
852
853    /**
854     * sendtestAllowed
855     * called when trying to send a test email
856     * return false is sending a test email is not allowed
857     * @param array messagedata
858     * @return bool;
859     */
860    public function sendTestAllowed($messagedata)
861    {
862        return true;
863    }
864
865    /**
866     * campaignStarted
867     * called when sending of a campaign starts
868     * @param array messagedata - associative array with all data for campaign
869     * @return null
870     */
871    public function campaignStarted($messagedata = array())
872    {
873    }
874
875    /**
876     * allowMessageToBeQueued
877     * called to verify that the message can be added to the queue
878     * @param array messagedata - associative array with all data for campaign
879     * @return empty string if allowed, or error string containing reason for not allowing
880     */
881    public function allowMessageToBeQueued($messagedata = array())
882    {
883        return '';
884    }
885
886    /**
887     * messageQueued
888     * called when a message is placed in the queue
889     * @param integer id message id
890     * @return null
891     */
892    public function messageQueued($id)
893    {
894    }
895
896    /**
897     * messageReQueued
898     * called when a message is placed back in the queue
899     * @param integer id message id
900     * @return null
901     */
902    public function messageReQueued($id)
903    {
904    }
905
906    /**
907     * messageQueueFinished
908     * called when a sending of the queue has finished
909     * @return null
910     */
911    public function messageQueueFinished()
912    {
913    }
914
915    /**
916     * logEvent
917     * @param string msg message to log
918     * @return true when dealt with or false to pass on
919     */
920    public function logEvent($msg = '')
921    {
922        return false;
923    }
924
925    /**
926     * login
927     * called on login
928     * @param none
929     * @return true when user is successfully logged by plugin, false instead
930     */
931    public function login()
932    {
933        return false;
934    }
935
936    /**
937     * logout
938     * called on logout
939     * @param none
940     * @return null
941     */
942    public function logout()
943    {
944        return '';
945    }
946
947    /**
948     * cronJobs.
949     *
950     * @param null
951     *
952     * @return array of cronjobs to call for this plugin
953     *
954     * eg
955     * array(
956     *    array( // cronJob1
957     *     'page' => 'pagetocall',
958     *     'frequency' => (int) minutes, // how often to call
959     *    ),
960     *    ...
961     *    ...
962     *    array( // cronJobN
963     *     'page' => 'anotherpagetocall',
964     *     'frequency' => (int) minutes, // how often to call
965     *    ),
966     * );
967     */
968    public function cronJobs()
969    {
970        return array();
971    }
972
973    /**
974     * displayUsers.
975     *
976     * add columns for this plugin to WebblerListing
977     * Currently used in users.php and members.php
978     *
979     * @param (array) user - associative array of user data
980     * @param string         $rowid - $element of the WebblerListing
981     * @param WebblerListing $list  - listing object to add to
982     *
983     * @note, unclear if this actually works. Better not to use it.
984     */
985    public function displayUsers($user, $rowid, $list)
986    {
987    }
988
989    /**
990     * deleteUser.
991     *
992     * allow plugins to delete their data when deleting a user
993     *
994     * @param int $id the ID of the subscriber
995     */
996    public function deleteUser($id)
997    {
998    }
999
1000    //###########################################################
1001    // List
1002
1003    /**
1004     * purpose: return html snippet with plugin info for this list
1005     * Currently used in lists.php
1006     * 200711 Bas
1007     */
1008    public function displayLists($list)
1009    {
1010        return;
1011    }
1012
1013    /**
1014     * purpose: return tablerows with list attributes for this list
1015     * Currently used in list.php
1016     * 200710 Bas
1017     */
1018    public function displayEditList($list)
1019    {
1020        return;
1021    }
1022
1023    /**
1024     * purpose: process edit list page (usually save fields)
1025     * return false if failed
1026     * 200710 Bas
1027     */
1028    public function processEditList($id)
1029    {
1030        return true;
1031    }
1032
1033    public function processSpamComplaint($email, $date)
1034    {
1035    }
1036
1037    //###########################################################
1038    // Subscribe page
1039
1040    /**
1041     * purpose: return tablerows with subscribepage options for this list
1042     * Currently used in spageedit.php
1043     * 200710 Bas
1044     */
1045    public function displaySubscribePageEdit($subscribePageData)
1046    {
1047        return;
1048    }
1049
1050    /**
1051     * unsubscribePage
1052     * @param email string - email to unsubscribe
1053     * @return true when processed, which will then override the standard subscribe page
1054     */
1055    public function unsubscribePage($email)
1056    {
1057        return false;
1058    }
1059
1060    /**
1061     * purpose: process selected subscribepage options for this list
1062     * return false if failed
1063     * Currently used in spageedit.php
1064     * 200710 Bas
1065     */
1066    public function processSubscribePageEdit($subscribePageID)
1067    {
1068        return true;
1069    }
1070
1071    /**
1072     * purpose: show content for this plugin on the import page
1073     */
1074    public function importContent()
1075    {
1076        return '';
1077    }
1078
1079    /**
1080     * validateEmailAddress
1081     * @param string $emailaddress
1082     * @return bool true if email address is correct
1083     */
1084    public function validateEmailAddress($emailAddress)
1085    {
1086        return true;
1087    }
1088
1089    /**
1090      * isBlacklistedEmail
1091      * @param string $emailaddress
1092      * @return bool true if email address should is considered blacklisted
1093     */
1094    public function isBlackListedEmail($email = '')
1095    {
1096        return false;
1097    }
1098
1099    /**
1100     * Allow additional processing of a link click.
1101     *
1102     * @param string $msgtype   H or T
1103     * @param int    $fwdid     id of row in linktrack_forward table
1104     * @param int    $messageid id of row in message table
1105     * @param int    $userid    id of row in user table
1106     * @param string $url       url of row in linktrack_forward table
1107     */
1108    public function linkClick($msgtype, $fwdid, $messageid, $userid, $url)
1109    {
1110    }
1111
1112    //#####################################
1113    // Static functions to manage the collection of plugins
1114
1115    /**
1116     * see if a plugin is enabled, static method so it can be called even if existance of plugin is unknown.
1117     */
1118    public static function isEnabled($pluginName)
1119    {
1120        return array_key_exists($pluginName, $GLOBALS['plugins']) && $GLOBALS['plugins'][$pluginName]->enabled;
1121    }
1122}
1123