3 // This file is part of Moodle - http://moodle.org/
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
19 * messagelib.php - Contains generic messaging functions for the message system
23 * @copyright Luis Rodrigues and Martin Dougiamas
24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27 defined('MOODLE_INTERNAL') || die();
30 * Called when a message provider wants to send a message.
31 * This functions checks the user's processor configuration to send the given type of message,
32 * then tries to send it.
34 * Required parameter $eventdata structure:
39 * fullmessage - the full message in a given format
40 * fullmessageformat - the format if the full message (FORMAT_MOODLE, FORMAT_HTML, ..)
41 * fullmessagehtml - the full version (the message processor will choose with one to use)
42 * smallmessage - the small version of the message
44 * @param object $eventdata information about the message (modulename, userfrom, userto, ...)
45 * @return boolean success
47 function message_send($eventdata) {
50 //TODO: this function is very slow and inefficient, it would be a major bottleneck in cron processing, this has to be improved in 2.0
51 // probably we could add two parameters with user messaging preferences and we could somehow preload/cache them in cron
53 //TODO: we need to solve problems with database transactions here somehow, for now we just prevent transactions - sorry
54 $DB->transactions_forbidden();
56 //after how long inactive should the user be considered logged off?
57 if (isset($CFG->block_online_users_timetosee)) {
58 $timetoshowusers = $CFG->block_online_users_timetosee * 60;
60 $timetoshowusers = 300;//5 minutes
63 // Work out if the user is logged in or not
64 if ((time() - $timetoshowusers) < $eventdata->userto->lastaccess) {
65 $userstate = 'loggedin';
67 $userstate = 'loggedoff';
70 // Create the message object
71 $savemessage = new stdClass();
72 $savemessage->useridfrom = $eventdata->userfrom->id;
73 $savemessage->useridto = $eventdata->userto->id;
74 $savemessage->subject = $eventdata->subject;
75 $savemessage->fullmessage = $eventdata->fullmessage;
76 $savemessage->fullmessageformat = $eventdata->fullmessageformat;
77 $savemessage->fullmessagehtml = $eventdata->fullmessagehtml;
78 $savemessage->smallmessage = $eventdata->smallmessage;
79 $savemessage->timecreated = time();
81 // Find out what processors are defined currently
82 // When a user doesn't have settings none gets return, if he doesn't want contact "" gets returned
83 $preferencename = 'message_provider_'.$eventdata->component.'_'.$eventdata->name.'_'.$userstate;
84 $processor = get_user_preferences($preferencename, NULL, $eventdata->userto->id);
86 if ($processor == NULL) { //this user never had a preference, save default
87 if (!message_set_default_message_preferences($eventdata->userto)) {
88 print_error('cannotsavemessageprefs', 'message');
90 if ($userstate == 'loggedin') {
93 if ($userstate == 'loggedoff') {
98 // if we are supposed to do something with this message
99 // No processor for this message, mark it as read
100 if ($processor == "") { //this user cleared all the preferences
101 $savemessage->timeread = time();
102 $DB->insert_record('message_read', $savemessage);
104 } else { // Process the message
105 /// Store unread message just in case we can not send it
106 $savemessage->id = $DB->insert_record('message', $savemessage);
108 /// Try to deliver the message to each processor
109 $processorlist = explode(',', $processor);
110 foreach ($processorlist as $procname) {
111 $processorfile = $CFG->dirroot. '/message/output/'.$procname.'/message_output_'.$procname.'.php';
113 if (is_readable($processorfile)) {
114 include_once($processorfile); // defines $module with version etc
115 $processclass = 'message_output_' . $procname;
117 if (class_exists($processclass)) {
118 $pclass = new $processclass();
120 if (!$pclass->send_message($savemessage)) {
121 debugging('Error calling message processor '.$procname);
126 debugging('Error calling message processor '.$procname);
131 $savemessage->timeread = time();
132 $messageid = $savemessage->id;
133 unset($savemessage->id);
135 //MDLSITE-1042 only the popup processor adds rows to message_working
136 //if the popup processor isnt selected messages will be marked read now and may not be seen
137 //For example, if the receiver has an incorrect email address configured or all processors deselected
139 //if there is no more processors that want to process this we can move message to message_read
140 //if ( $DB->count_records('message_working', array('unreadmessageid' => $messageid)) == 0){
141 //$DB->insert_record('message_read', $savemessage);
142 //$DB->delete_records('message', array('id' => $messageid));
151 * This code updates the message_providers table with the current set of providers
152 * @param $component - examples: 'moodle', 'mod_forum', 'block_quiz_results'
155 function message_update_providers($component='moodle') {
158 // load message providers from files
159 $fileproviders = message_get_providers_from_file($component);
161 // load message providers from the database
162 $dbproviders = message_get_providers_from_db($component);
164 foreach ($fileproviders as $messagename => $fileprovider) {
166 if (!empty($dbproviders[$messagename])) { // Already exists in the database
168 if ($dbproviders[$messagename]->capability == $fileprovider['capability']) { // Same, so ignore
169 // exact same message provider already present in db, ignore this entry
170 unset($dbproviders[$messagename]);
173 } else { // Update existing one
174 $provider = new stdClass();
175 $provider->id = $dbproviders[$messagename]->id;
176 $provider->capability = $fileprovider['capability'];
177 $DB->update_record('message_providers', $provider);
178 unset($dbproviders[$messagename]);
182 } else { // New message provider, add it
184 $provider = new stdClass();
185 $provider->name = $messagename;
186 $provider->component = $component;
187 $provider->capability = $fileprovider['capability'];
189 $DB->insert_record('message_providers', $provider);
193 foreach ($dbproviders as $dbprovider) { // Delete old ones
194 $DB->delete_records('message_providers', array('id' => $dbprovider->id));
201 * Returns the active providers for the current user, based on capability
202 * @return array of message providers
204 function message_get_my_providers() {
207 $systemcontext = get_context_instance(CONTEXT_SYSTEM);
209 $providers = $DB->get_records('message_providers');
211 // Remove all the providers we aren't allowed to see now
212 foreach ($providers as $providerid => $provider) {
213 if (!empty($provider->capability)) {
214 if (!has_capability($provider->capability, $systemcontext)) {
215 unset($providers[$providerid]); // Not allowed to see this
224 * Gets the message providers that are in the database for this component.
225 * @param $component - examples: 'moodle', 'mod/forum', 'block/quiz_results'
226 * @return array of message providers
228 * INTERNAL - to be used from messagelib only
230 function message_get_providers_from_db($component) {
233 return $DB->get_records('message_providers', array('component'=>$component), '', 'name, id, component, capability'); // Name is unique per component
237 * Loads the messages definitions for the component (from file). If no
238 * messages are defined for the component, we simply return an empty array.
239 * @param $component - examples: 'moodle', 'mod_forum', 'block_quiz_results'
240 * @return array of message providerss or empty array if not exists
242 * INTERNAL - to be used from messagelib only
244 function message_get_providers_from_file($component) {
245 $defpath = get_component_directory($component).'/db/messages.php';
247 $messageproviders = array();
249 if (file_exists($defpath)) {
253 foreach ($messageproviders as $name => $messageprovider) { // Fix up missing values if required
254 if (empty($messageprovider['capability'])) {
255 $messageproviders[$name]['capability'] = NULL;
259 return $messageproviders;
263 * Remove all message providers
264 * @param $component - examples: 'moodle', 'mod/forum', 'block/quiz_results'
266 function message_uninstall($component) {
268 return $DB->delete_records('message_providers', array('component' => $component));
272 * Set default message preferences.
273 * @param $user - User to set message preferences
275 function message_set_default_message_preferences($user) {
278 $providers = $DB->get_records('message_providers');
279 $preferences = array();
280 foreach ($providers as $providerid => $provider) {
281 $preferences['message_provider_'.$provider->component.'_'.$provider->name.'_loggedin'] = 'popup';
282 $preferences['message_provider_'.$provider->component.'_'.$provider->name.'_loggedoff'] = 'email';
284 return set_user_preferences($preferences, $user->id);