/[drupal]/contributions/modules/subscriptions/subscriptions_mail.cron.inc
ViewVC logotype

Contents of /contributions/modules/subscriptions/subscriptions_mail.cron.inc

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.3 - (show annotations) (download) (as text)
Tue Nov 3 22:35:11 2009 UTC (3 weeks, 2 days ago) by salvis
Branch: MAIN
Changes since 1.2: +5 -5 lines
File MIME type: text/x-php
Fix some strings.
1 <?php
2 // $Id: subscriptions_mail.cron.inc,v 1.2 2009/10/04 15:51:07 salvis Exp $
3
4 /**
5 * @file
6 * Subscriptions module mail gateway (cron functions).
7 */
8
9 /**
10 * Implementation of hook_cron().
11 *
12 * Takes items from {subscriptions_queue} and generates notification emails.
13 */
14 function _subscriptions_mail_cron() {
15
16 // set_time_limit(3600); drupal_set_message('DON\'T FORGET TO REMOVE THE TIME LIMIT EXTENSION!!!');
17
18 global $user, $language;
19 drupal_init_language();
20 include_once drupal_get_path('module', 'subscriptions_mail') .'/subscriptions_mail.templates.inc';
21
22 $mails_allowed = variable_get('subscriptions_number_of_mails', 0);
23 $from = _subscriptions_mail_site_mail();
24 $old_uid = 0;
25 $single_count = 0;
26 $digest_count = 0;
27 $loaded_objects = array();
28 $users = array();
29 $fields = array();
30
31 // Strategy for cron:
32 // Use a defined percentage of the total cron time (default: 50%), but leave at least 5s.
33 $total_seconds = ini_get('max_execution_time');
34 if (empty($total_seconds)) {
35 // Work-around for D6.14, which broke this in #193383-106 with http://cvs.drupal.org/viewvc.py/drupal/drupal/includes/common.inc?r1=1.756.2.65&r2=1.756.2.66&pathrev=DRUPAL-6
36 // D6.15 will revert this to a hard-coded 240 in http://cvs.drupal.org/viewvc.py/drupal/drupal/includes/common.inc?r1=1.756.2.70&r2=1.756.2.71&pathrev=DRUPAL-6
37 $total_seconds = 240;
38 }
39 $lost_seconds = timer_read('page')/1000;
40 $available_seconds = $total_seconds - $lost_seconds;
41 $usable_seconds = min(array($available_seconds - 5, $total_seconds*subscriptions_mail_get_cron_percentage()/100));
42 //TEST: watchdog('cron', "Subscriptions has $available_seconds of $total_seconds seconds available.");
43 if ($usable_seconds <= 0) {
44 $variables = array(
45 '!Module' => 'Subscriptions',
46 '@link' => url('admin/settings/subscriptions', array('fragment' => 'edit-subscriptions-cron-percent')),
47 );
48 $watchdog = 'watchdog'; // keep potx from translating 'cron'
49 if ($usable_seconds == 0) {
50 $watchdog('cron', t('!Module cannot send any notifications because its <a href="@link">cron job time</a> is 0!', $variables), NULL, WATCHDOG_WARNING);
51 }
52 else {
53 $watchdog('cron', t('!Module cannot send any notifications because the cron run has less than 5 available seconds left!', $variables), NULL, WATCHDOG_WARNING);
54 }
55 }
56
57 while ((empty($mails_allowed) || $single_count + $digest_count < $mails_allowed)
58 && timer_read('page')/1000 < $lost_seconds + $usable_seconds) {
59 $result = db_query_range('SELECT * FROM {subscriptions_queue} WHERE last_sent + send_interval < %d ORDER BY sqid', time(), 0, 1);
60 if (!($s = db_fetch_array($result))) {
61 break; // No more ready queue items, terminate loop.
62 }
63
64 if (!isset($users[$s['uid']])) {
65 $users[$s['uid']] = user_load(array('uid' => $s['uid']));
66 }
67 $saved_user = $user;
68 $saved_language = $language;
69 session_save_session(FALSE);
70 $user = $users[$s['uid']];
71 drupal_init_language();
72 $langcode = $language->language;
73 $user_mails = array();
74
75 do { // once and repeat while adding to a digest
76 if ($user->status && $user->access) {
77 $cids = array();
78 $load_function = $s['load_function'];
79 $index = $load_args = $s['load_args'];
80 if (!isset($loaded_objects[$user->uid][$load_function][$load_args])) {
81 if (is_numeric($load_args)) {
82 $object = $load_function($load_args, $s['sqid'], $s['is_new']);
83 }
84 else {
85 $load_args = unserialize($load_args);
86 $load_args[] = $s['is_new'];
87 $object = call_user_func_array($load_function, $load_args);
88 }
89 if (!empty($object)) {
90 $access = module_invoke_all('subscriptions', 'access', $load_function, $load_args, $object);
91 // One FALSE vote is enough to deny. Also, we need a non-empty array.
92 $allow = !empty($access) && array_search(FALSE, $access) === FALSE;
93 $loaded_objects[$user->uid][$load_function][$index] = $allow ? $object : FALSE;
94 }
95 }
96 if ($object = $loaded_objects[$user->uid][$load_function][$index]) {
97 if (!isset($users[$object->uid])) {
98 $users[$object->uid] = user_load(array('uid' => $object->uid));
99 }
100 $sender = $users[$object->uid];
101 $module = $s['module'];
102 $ori_field = $field = $s['field'];
103 $ori_value = $value = $s['value'];
104 if (!isset($fields[$langcode][$module])) {
105 $fields[$langcode][$module] = module_invoke_all('subscriptions', 'fields', $module);
106 }
107 if ($module == 'node' && $field == 'nid' && (!empty($object->_subscriptions_is_updated) || !empty($object->_subscriptions_is_new)) && user_access('subscribe to content types', $user)) {
108 $unlisteds = variable_get('subscriptions_unlisted_content_types', array());
109 if (isset($object->type) && !in_array($object->type, $unlisteds)) {
110 // Convert node-nid to node-type because that can give more specific information.
111 $field = 'type';
112 $value = $object->type;
113 }
114 }
115 $mailvars_function = $fields[$langcode][$module][$field]['mailvars_function'];
116 $mailkey = $fields[$langcode][$module][$field]['mailkey'];
117 if (!is_numeric($value)) {
118 $mailkey .= '-'. $value;
119 }
120 $digest = $s['digest'] > 0 || $s['digest'] == -1 && _subscriptions_get_setting('digest', 0) > 0;
121 if ($digest) {
122 $body_template = subscriptions_mail_template_load(SUBSCRIPTIONS_DIGEST_MAILKEY .'+item', $langcode, 'body', 'DITEM');
123 }
124 else {
125 $body_template = subscriptions_mail_template_load($mailkey, $langcode, 'body', 'BODY');
126 $subject_template = subscriptions_mail_template_load($mailkey, $langcode, 'subject', 'SUBJ');
127 }
128 init_theme();
129 $show_node_info = (isset($object->type) ? theme_get_setting('toggle_node_info_'. $object->type) : TRUE);
130 $base = 'user/'. $s['uid'];
131 $mailvars = array(
132 '!site' => variable_get('site_name', 'drupal'),
133 '!recipient_name' => $s['name'],
134 '!recipient_page' => url($base, array('absolute' => TRUE)),
135 '!sender_name' => ($show_node_info ? ($sender->uid ? $sender->name : variable_get('anonymous', '!sender_name')) : '!sender_name'),
136 '!sender_page' => ($show_node_info && $sender->uid ? url("user/$sender->uid", array('absolute' => TRUE)) : '!sender_page'),
137 '!sender_contact_page' => ($show_node_info ? (empty($sender->contact) ? t('(disabled)') : url("user/$sender->uid/contact", array('absolute' => TRUE))) : '!sender_contact_page'),
138 '!sender_has_contact_page' => ($show_node_info ? (empty($sender->contact) ? 0 : 1) : 0),
139 '!manage_url' => url($base .'/subscriptions', array('absolute' => TRUE)),
140 '!name' => $s['name'],
141 '!subs_type' => $fields[$langcode][$module][$field]['!subs_type'],
142 '!unsubscribe_url' => url("s/del/$module/$ori_field/$ori_value/". $s['author_uid'] .'/'. $s['uid'] .'/'. md5(drupal_get_private_key() . $module . $ori_field . $ori_value . $s['author_uid'] . $s['uid']), array('absolute' => TRUE)),
143 );
144 $mailvars_function($mailvars, $object, $field, $s);
145 $mailvars += module_invoke_all('subscriptions_get_mailvars', $object);
146 if ($digest && !empty($object->_subscriptions_comments) && module_exists('subscriptions_content')) {
147 $digest_comment_template = subscriptions_mail_template_load(SUBSCRIPTIONS_DIGEST_MAILKEY .'+comment', $langcode, 'body', 'DITEMCMT');
148 $mailvars['!comments'] = _subscriptions_content_format_comments($object, $digest_comment_template, '');
149 }
150 $body = strtr(subscriptions_mail_template_preprocess($body_template, $mailvars), $mailvars);
151 if (variable_get('subscriptions_showmailkeys', 0)) {
152 $body .= t('| Mailkey: @mailkey/@langcode', array('@mailkey' => $mailkey, '@langcode' => $langcode)) ."\n";
153 }
154 if ($digest) {
155 $user_mails['bodies'][] = $body;
156 $user_mails['send'] = array(
157 'name' => $s['name'],
158 'mail' => $s['mail'],
159 'from' => $from,
160 '!name' => $mailvars['!name'],
161 '!manage_url' => $mailvars['!manage_url'],
162 );
163 $user_mails['send_intervals'][$s['send_interval']] = $s['send_interval'];
164 }
165 else {
166 $subject = strtr(subscriptions_mail_template_preprocess($subject_template, $mailvars), $mailvars);
167 _subscriptions_mail_send('passthru', $s['name'], $s['mail'], $subject, $body, $from, $s['uid'], array($s['send_interval']));
168 ++$single_count;
169 }
170 }
171 }
172 db_query("DELETE FROM {subscriptions_queue} WHERE load_function = '%s' AND load_args = '%s' AND uid = %d", $s['load_function'], $s['load_args'], $s['uid']);
173
174 if ($digest) {
175 // Get next ready queue item for this user.
176 $result = db_query_range('SELECT * FROM {subscriptions_queue} WHERE uid = %d AND last_sent + send_interval < %d ORDER BY sqid', $user->uid, time(), 0, 1);
177 if (!($s = db_fetch_array($result))) {
178 // No more ready queue items for this user, finish off this digest.
179 $s = $user_mails['send'];
180 $subject_template = subscriptions_mail_template_load(SUBSCRIPTIONS_DIGEST_MAILKEY, $langcode, 'subject', 'DSUBJ');
181 $body_template = subscriptions_mail_template_load(SUBSCRIPTIONS_DIGEST_MAILKEY, $langcode, 'body', 'DBODY');
182 $separator = subscriptions_mail_template_load(SUBSCRIPTIONS_DIGEST_MAILKEY .'+item', $langcode, 'subject', 'SEP');
183 $mailvars['!bodies'] = implode($separator, $user_mails['bodies']);
184 $mailvars['!name'] = $s['!name'];
185 $mailvars['!manage_url'] = $s['!manage_url'];
186 $subject = strtr(subscriptions_mail_template_preprocess($subject_template, $mailvars), $mailvars);
187 $body = strtr(subscriptions_mail_template_preprocess($body_template, $mailvars), $mailvars);
188 _subscriptions_mail_send(SUBSCRIPTIONS_DIGEST_MAILKEY, $s['name'], $s['mail'], $subject, $body, $s['from'], $user->uid, $user_mails['send_intervals']);
189 ++$digest_count;
190 $digest = false;
191 }
192 }
193 } while ( $digest );
194
195 $user = $saved_user;
196 $language = $saved_language;
197 session_save_session(TRUE);
198 }
199
200 if ($single_count + $digest_count > 0) {
201 $current_seconds = timer_read('page')/1000;
202 $watchdog = 'watchdog'; // keep potx from translating 'cron'
203 $watchdog('cron', '!Module sent !single_count single and !digest_count digest notifications in !used_seconds of !total_seconds seconds; !remaining_items queue items remaining, !remaining_seconds seconds left for other cron client modules.', array(
204 '!Module' => 'Subscriptions',
205 '!single_count' => $single_count,
206 '!digest_count' => $digest_count,
207 '!used_seconds' => round($current_seconds - $lost_seconds),
208 '!total_seconds' => $total_seconds,
209 '!remaining_items' => db_result(db_query("SELECT COUNT(*) FROM {subscriptions_queue} WHERE last_sent + send_interval < %d", time())),
210 '!remaining_seconds' => round($total_seconds - $current_seconds),
211 ));
212 }
213 }
214
215 /**
216 * Implementation of hook_mail().
217 */
218 function subscriptions_mail_mail($key, &$message, $params) {
219 global $base_url;
220
221 $url = parse_url($base_url);
222 $list_id = variable_get('site_name', '') .' '. t('Subscriptions') .' <subscriptions.'. $url['host'] .'>';
223
224 $message['subject'] = $params['context']['subject'];
225 $message['body'] = $params['context']['message'];
226 $message['headers']['List-Id'] = $list_id;
227 }
228
229
230 /**
231 * Send the notification by mail.
232 */
233 function _subscriptions_mail_send($mailkey, $name, $to, $subject, $body, $from, $uid, $send_intervals) {
234 global $user;
235
236 $mail_success = drupal_mail('subscriptions_mail', $mailkey, $to, user_preferred_language($user), array(
237 'account' => $user,
238 'object' => NULL,
239 'context' => array(
240 'recipient' => $to,
241 'subject' => $subject,
242 'message' => $body,
243 ),
244 ), $from, TRUE);
245
246 $watchdog_params = array('@name' => $name, '@to' => "<$to>");
247 if (!empty($mail_success['result'])) {
248 if (variable_get('subscriptions_watchgood', 1)) {
249 watchdog('subscriptions', 'notification for @name at @to', $watchdog_params);
250 }
251 foreach ($send_intervals as $send_interval) {
252 db_query("UPDATE {subscriptions_last_sent} SET last_sent = %d WHERE uid = %d AND send_interval = %d", time(), $uid, $send_interval);
253 if (!db_affected_rows()) {
254 @db_query("INSERT INTO {subscriptions_last_sent} (uid, send_interval, last_sent) VALUES(%d, %d, %d)", $uid, $send_interval, time());
255 }
256 }
257 }
258 else {
259 watchdog('subscriptions', 'error mailing notification for @name at @to', $watchdog_params, WATCHDOG_ERROR);
260 }
261 }
262
263 /**
264 * Preprocess a mail template (subject or body), detecting conditional clauses
265 * that conform to a prescribed syntax
266 *
267 * @param string $template
268 * the template for preprocessing
269 * @param array $mailvars
270 * an associatvie array of currently existing variables that are to be
271 * interpolated into the template later , and which can be used by this
272 * function for preprocessing
273 *
274 * This function allows the administrator to specify ternary-type conditions
275 * to determine what text is used in a mail in a particular situation, using
276 * the variables that are currently available for that mail for reference.
277 * The syntax is standard PHP/C-style ternary syntax, but only allows the
278 * "==" and "!=":
279 * {{!variable_name==sometext?text for true condition:text for false condition}}
280 *
281 * sometext must not contain a question mark, and the true text no colon.
282 */
283 function subscriptions_mail_template_preprocess($template, $mailvars) {
284 preg_match_all('/{{(?P<condition>[^?]+?)\?(?P<true>[^:]*?):(?P<false>[^\]]*?)}}/', $template, $conditions);
285
286 // locate the actual operators/operand for each
287 $replacement = '';
288 foreach ($conditions[0] as $k => $v) {
289 preg_match('/(?P<operand_1>!.+)\s*(?P<operator>==|!=)\s*(?P<operand_2>.+)/', $conditions['condition'][$k], $matches);
290 $operand1 = (isset($mailvars[$matches['operand_1']]) ? $mailvars[$matches['operand_1']] : $matches['operand_1']);
291 if ($matches['operator'] == '==') {
292 $replacement = ($operand1 == $matches['operand_2']) ? $conditions['true'][$k] : $conditions['false'][$k];
293 }
294 elseif ($matches['operator'] == '!=') {
295 $replacement = ($operand1 != $matches['operand_2']) ? $conditions['true'][$k] : $conditions['false'][$k];
296 }
297 else {
298 continue;
299 }
300 // replace the condition with the result of its evalutation
301 $template = str_replace($v, $replacement, $template);
302 }
303 return $template;
304 }
305
306 /**
307 * Implementation of hook_mail_alter().
308 *
309 * Remove any trailing spaces (must run after mail_edit_mail_alter()!).
310 */
311 function subscriptions_mail_mail_alter(&$message) {
312 $message['body'] = preg_replace('/ +(\r?\n)/', '\\1', $message['body']);
313 }
314

  ViewVC Help
Powered by ViewVC 1.1.2