This commit was manufactured by cvs2svn to create tag
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_dmailer.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2004 Kasper Skaarhoj (kasper@typo3.com)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Class, doing the sending of Direct-mails, eg. through a cron-job
29 * Belongs to/See "direct_mail" extension.
30 *
31 * $Id$
32 *
33 * @author Kasper Skaarhoj <kasper@typo3.com>
34 */
35 /**
36 * [CLASS/FUNCTION INDEX of SCRIPT]
37 *
38 *
39 *
40 * 86: class t3lib_dmailer extends t3lib_htmlmail
41 * 97: function dmailer_prepare($row)
42 * 145: function dmailer_sendAdvanced($recipRow,$tableNameChar)
43 * 216: function dmailer_sendSimple($addressList)
44 * 238: function dmailer_getBoundaryParts($cArray,$userCategories)
45 * 260: function dmailer_masssend($query_info,$table,$mid)
46 * 296: function dmailer_masssend_list($query_info,$mid)
47 * 357: function shipOfMail($mid,$recipRow,$tKey)
48 * 375: function convertFields($recipRow)
49 * 390: function dmailer_setBeginEnd($mid,$key)
50 * 414: function dmailer_howManySendMails($mid,$rtbl='')
51 * 428: function dmailer_isSend($mid,$rid,$rtbl)
52 * 440: function dmailer_getSentMails($mid,$rtbl)
53 * 459: function dmailer_addToMailLog($mid,$rid,$size,$parsetime,$html)
54 * 481: function runcron()
55 *
56 * TOTAL FUNCTIONS: 14
57 * (This index is automatically created/updated by the extension "extdeveval")
58 *
59 */
60
61
62
63 /**
64 *
65 * SETTING UP a cron job on a UNIX box for distribution:
66 *
67 * Write at the shell:
68 *
69 * crontab -e
70 *
71 *
72 * Then enter this line follow by a line-break:
73 *
74 * * * * * /www/[path-to-your-typo3-site]/typo3/mod/web/dmail/dmailerd.phpcron
75 *
76 * Every minute the cronjob checks if there are mails in the queue.
77 * If there are mails, 100 is sent at a time per job.
78 */
79 /**
80 * Class, doing the sending of Direct-mails, eg. through a cron-job
81 *
82 * @author Kasper Skaarhoj <kasper@typo3.com>
83 * @package TYPO3
84 * @subpackage t3lib
85 */
86 class t3lib_dmailer extends t3lib_htmlmail {
87 var $sendPerCycle =50;
88 var $logArray =array();
89 var $massend_id_lists = array();
90 var $flag_html = 0;
91 var $flag_plain = 0;
92
93 /**
94 * @param [type] $row: ...
95 * @return [type] ...
96 */
97 function dmailer_prepare($row) {
98 $sys_dmail_uid = $row['uid'];
99 $this->useBase64();
100 $this->theParts = unserialize($row['mailContent']);
101 $this->messageid = $this->theParts['messageid'];
102 $this->subject = $row['subject'];
103 $this->from_email = $row['from_email'];
104 $this->from_name = ($row['from_name']) ? $row['from_name'] : '';
105 $this->replyto_email = ($row['replyto_email']) ? $row['replyto_email'] : '';
106 $this->replyto_name = ($row['replyto_name']) ? $row['replyto_name'] : '';
107 $this->organisation = ($row['organisation']) ? $row['organisation'] : '';
108 $this->priority = t3lib_div::intInRange($row['priority'],1,5);
109 $this->mailer = 'TYPO3 Direct Mail module';
110
111 $this->dmailer['sectionBoundary'] = '<!--DMAILER_SECTION_BOUNDARY';
112 $this->dmailer['html_content'] = base64_decode($this->theParts['html']['content']);
113 $this->dmailer['plain_content'] = base64_decode($this->theParts['plain']['content']);
114 $this->dmailer['messageID'] = $this->messageid;
115 $this->dmailer['sys_dmail_uid'] = $sys_dmail_uid;
116 $this->dmailer['sys_dmail_rec'] = $row;
117
118 $this->dmailer['boundaryParts_html'] = explode($this->dmailer['sectionBoundary'], '_END-->'.$this->dmailer['html_content']);
119 while(list($bKey,$bContent)=each($this->dmailer['boundaryParts_html'])) {
120 $this->dmailer['boundaryParts_html'][$bKey] = explode('-->',$bContent,2);
121 // Now, analyzing which media files are used in this part of the mail:
122 $mediaParts = explode('cid:part',$this->dmailer['boundaryParts_html'][$bKey][1]);
123 reset($mediaParts);
124 next($mediaParts);
125 while(list(,$part)=each($mediaParts)) {
126 $this->dmailer['boundaryParts_html'][$bKey]['mediaList'].=','.strtok($part,'.');
127 }
128 }
129 $this->dmailer['boundaryParts_plain'] = explode($this->dmailer['sectionBoundary'], '_END-->'.$this->dmailer['plain_content']);
130 while(list($bKey,$bContent)=each($this->dmailer['boundaryParts_plain'])) {
131 $this->dmailer['boundaryParts_plain'][$bKey] = explode('-->',$bContent,2);
132 }
133
134 $this->flag_html = $this->theParts['html']['content'] ? 1 : 0;
135 $this->flag_plain = $this->theParts['plain']['content'] ? 1 : 0;
136 }
137
138 /**
139 * [Describe function...]
140 *
141 * @param [type] $recipRow: ...
142 * @param [type] $tableNameChar: ...
143 * @return [type] ...
144 */
145 function dmailer_sendAdvanced($recipRow,$tableNameChar) {
146 $returnCode=0;
147 if ($recipRow['email']) {
148 $midRidId = 'MID'.$this->dmailer['sys_dmail_uid'].'_'.$tableNameChar.$recipRow['uid'];
149 $uniqMsgId = md5(microtime()).'_'.$midRidId;
150 $rowFieldsArray = explode(',', 'uid,name,title,email,phone,www,address,company,city,zip,country,fax,firstname');
151 $uppercaseFieldsArray = explode(',', 'name,firstname');
152 $authCode = t3lib_div::stdAuthCode($recipRow['uid']);
153 $this->mediaList='';
154 if ($this->flag_html && $recipRow['module_sys_dmail_html']) {
155 $tempContent_HTML = $this->dmailer_getBoundaryParts($this->dmailer['boundaryParts_html'],$recipRow['module_sys_dmail_category']);
156 reset($rowFieldsArray);
157 while(list(,$substField)=each($rowFieldsArray)) {
158 $tempContent_HTML = str_replace('###USER_'.$substField.'###', $recipRow[$substField], $tempContent_HTML);
159 }
160 reset($uppercaseFieldsArray);
161 while(list(,$substField)=each($uppercaseFieldsArray)) {
162 $tempContent_HTML = str_replace('###USER_'.strtoupper($substField).'###', strtoupper($recipRow[$substField]), $tempContent_HTML);
163 }
164 $tempContent_HTML = str_replace('###SYS_TABLE_NAME###', $tableNameChar, $tempContent_HTML); // Put in the tablename of the userinformation
165 $tempContent_HTML = str_replace('###SYS_MAIL_ID###', $this->dmailer['sys_dmail_uid'], $tempContent_HTML); // Put in the uid of the mail-record
166 $tempContent_HTML = str_replace('###SYS_AUTHCODE###', $authCode, $tempContent_HTML);
167 $tempContent_HTML = str_replace($this->dmailer['messageID'], $uniqMsgId, $tempContent_HTML); // Put in the unique message id in HTML-code
168 $this->theParts['html']['content'] = $this->encodeMsg($tempContent_HTML);
169 $returnCode|=1;
170 } else $this->theParts['html']['content'] = '';
171
172 // Plain
173 if ($this->flag_plain) {
174 $tempContent_Plain = $this->dmailer_getBoundaryParts($this->dmailer['boundaryParts_plain'],$recipRow['module_sys_dmail_category']);
175 reset($rowFieldsArray);
176 while(list(,$substField)=each($rowFieldsArray)) {
177 $tempContent_Plain = str_replace('###USER_'.$substField.'###', $recipRow[$substField], $tempContent_Plain);
178 }
179 reset($uppercaseFieldsArray);
180 while(list(,$substField)=each($uppercaseFieldsArray)) {
181 $tempContent_Plain = str_replace('###USER_'.strtoupper($substField).'###', strtoupper($recipRow[$substField]), $tempContent_Plain);
182 }
183 $tempContent_Plain = str_replace('###SYS_TABLE_NAME###', $tableNameChar, $tempContent_Plain); // Put in the tablename of the userinformation
184 $tempContent_Plain = str_replace('###SYS_MAIL_ID###', $this->dmailer['sys_dmail_uid'], $tempContent_Plain); // Put in the uid of the mail-record
185 $tempContent_Plain = str_replace('###SYS_AUTHCODE###', $authCode, $tempContent_Plain);
186
187 if (trim($this->dmailer['sys_dmail_rec']['long_link_rdct_url'])) {
188 $tempContent_Plain = t3lib_div::substUrlsInPlainText($tempContent_Plain,$this->dmailer['sys_dmail_rec']['long_link_mode']?'all':'76',trim($this->dmailer['sys_dmail_rec']['long_link_rdct_url']));
189 }
190
191 $this->theParts['plain']['content'] = $this->encodeMsg($tempContent_Plain);
192 $returnCode|=2;
193 } else $this->theParts['plain']['content'] = '';
194
195 // Set content
196 $this->Xid = $midRidId.'-'.md5($midRidId);
197 $this->returnPath = str_replace('###XID###',$midRidId,$this->dmailer['sys_dmail_rec']['return_path']);
198
199 $this->part=0;
200 $this->setHeaders();
201 $this->setContent();
202 $this->setRecipient($recipRow['email']);
203
204 $this->message = str_replace($this->dmailer['messageID'], $uniqMsgId, $this->message); // Put in the unique message id in whole message body
205 $this->sendtheMail();
206 }
207 return $returnCode;
208 }
209
210 /**
211 * [Describe function...]
212 *
213 * @param [type] $addressList: ...
214 * @return [type] ...
215 */
216 function dmailer_sendSimple($addressList) {
217 if ($this->theParts['html']['content']) {
218 $this->theParts['html']['content'] = $this->encodeMsg($this->dmailer_getBoundaryParts($this->dmailer['boundaryParts_html'],-1));
219 } else $this->theParts['html']['content'] = '';
220 if ($this->theParts['plain']['content']) {
221 $this->theParts['plain']['content'] = $this->encodeMsg($this->dmailer_getBoundaryParts($this->dmailer['boundaryParts_plain'],-1));
222 } else $this->theParts['plain']['content'] = '';
223
224 $this->setHeaders();
225 $this->setContent();
226 $this->setRecipient($addressList);
227 $this->sendtheMail();
228 return true;
229 }
230
231 /**
232 * [Describe function...]
233 *
234 * @param [type] $cArray: ...
235 * @param [type] $userCategories: ...
236 * @return [type] ...
237 */
238 function dmailer_getBoundaryParts($cArray,$userCategories) {
239 $userCategories = intval($userCategories);
240 reset($cArray);
241 $returnVal='';
242 while(list(,$cP)=each($cArray)) {
243 $key=substr($cP[0],1);
244 if ($key=='END' || !$key || $userCategories<0 || (intval($key) & $userCategories)>0) {
245 $returnVal.=$cP[1];
246 $this->mediaList.=$cP['mediaList'];
247 }
248 }
249 return $returnVal;
250 }
251
252 /**
253 * [Describe function...]
254 *
255 * @param [type] $query_info: ...
256 * @param [type] $table: ...
257 * @param [type] $mid: ...
258 * @return [type] ...
259 */
260 function dmailer_masssend($query_info,$table,$mid) {
261 $enableFields['tt_address']='NOT tt_address.deleted AND NOT tt_address.hidden';
262 $enableFields['fe_users']='NOT fe_users.deleted AND NOT fe_users.disable';
263 $tKey = substr($table,0,1);
264 $begin=intval($this->dmailer_howManySendMails($mid,$tKey));
265 if ($query_info[$table]) {
266 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($table.'.*', $table, $enableFields[$table].' AND ('.$query_info[$table].')', '', 'tstamp DESC', intval($begin).','.$this->sendPerCycle); // This way, we select newest edited records first. So if any record is added or changed in between, it'll end on top and do no harm
267 if ($GLOBALS['TYPO3_DB']->sql_error()) {
268 die ($GLOBALS['TYPO3_DB']->sql_error());
269 }
270 $numRows = $GLOBALS['TYPO3_DB']->sql_num_rows($res);
271 $cc=0;
272 while($recipRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
273 if (!$this->dmailer_isSend($mid,$recipRow['uid'],$tKey)) {
274 $pt = t3lib_div::milliseconds();
275 if ($recipRow['telephone']) $recipRow['phone'] = $recipRow['telephone']; // Compensation for the fact that fe_users has the field, 'telephone' instead of 'phone'
276 $recipRow['firstname']=strtok(trim($recipRow['name']),' ');
277
278 $rC = $this->dmailer_sendAdvanced($recipRow,$tKey);
279 $this->dmailer_addToMailLog($mid,$tKey.'_'.$recipRow['uid'],strlen($this->message),t3lib_div::milliseconds()-$pt,$rC);
280 }
281 $cc++;
282 }
283 $this->logArray[]='Sending '.$cc.' mails to table '.$table;
284 if ($numRows < $this->sendPerCycle) return true;
285 }
286 return false;
287 }
288
289 /**
290 * [Describe function...]
291 *
292 * @param [type] $query_info: ...
293 * @param [type] $mid: ...
294 * @return [type] ...
295 */
296 function dmailer_masssend_list($query_info,$mid) {
297 $enableFields['tt_address']='NOT tt_address.deleted AND NOT tt_address.hidden';
298 $enableFields['fe_users']='NOT fe_users.deleted AND NOT fe_users.disable';
299
300 $c=0;
301 $returnVal=true;
302 if (is_array($query_info['id_lists'])) {
303 reset($query_info['id_lists']);
304 while(list($table,$listArr)=each($query_info['id_lists'])) {
305 if (is_array($listArr)) {
306 $ct=0;
307 // FInd tKey
308 if ($table=='tt_address' || $table=='fe_users') {
309 $tKey = substr($table,0,1);
310 } elseif ($table=='PLAINLIST') {
311 $tKey='P';
312 } else {$tKey='u';}
313
314 // Send mails
315 $sendIds=$this->dmailer_getSentMails($mid,$tKey);
316 if ($table=='PLAINLIST') {
317 $sendIdsArr=explode(',',$sendIds);
318 reset($listArr);
319 while(list($kval,$recipRow)=each($listArr)) {
320 $kval++;
321 if (!in_array($kval,$sendIdsArr)) {
322 if ($c>=$this->sendPerCycle) {$returnVal = false; break;} // We are NOT finished!
323 $recipRow['uid']=$kval;
324 $this->shipOfMail($mid,$recipRow,$tKey);
325 $ct++;
326 $c++;
327 }
328 }
329 } else {
330 $idList = implode(',',$listArr);
331 if ($idList) {
332 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($table.'.*', $table, 'uid IN ('.$idList.') AND uid NOT IN ('.($sendIds?$sendIds:0).') AND '.($enableFields[$table]?$enableFields[$table]:'1=1'), '', '', $this->sendPerCycle+1);
333 if ($GLOBALS['TYPO3_DB']->sql_error()) {die ($GLOBALS['TYPO3_DB']->sql_error());}
334 while($recipRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
335 if ($c>=$this->sendPerCycle) {$returnVal = false; break;} // We are NOT finished!
336 $this->shipOfMail($mid,$recipRow,$tKey);
337 $ct++;
338 $c++;
339 }
340 }
341 }
342 $this->logArray[]='Sending '.$ct.' mails to table '.$table;
343 }
344 }
345 }
346 return $returnVal;
347 }
348
349 /**
350 * [Describe function...]
351 *
352 * @param [type] $mid: ...
353 * @param [type] $recipRow: ...
354 * @param [type] $tKey: ...
355 * @return [type] ...
356 */
357 function shipOfMail($mid,$recipRow,$tKey) {
358 if (!$this->dmailer_isSend($mid,$recipRow['uid'],$tKey)) {
359 $pt = t3lib_div::milliseconds();
360 $recipRow=$this->convertFields($recipRow);
361
362 // debug('->'.$recipRow['uid'],1);
363 // $recipRow['email']='kasper@typo3.com';
364 $rC=$this->dmailer_sendAdvanced($recipRow,$tKey);
365 $this->dmailer_addToMailLog($mid,$tKey.'_'.$recipRow['uid'],strlen($this->message),t3lib_div::milliseconds()-$pt,$rC);
366 }
367 }
368
369 /**
370 * [Describe function...]
371 *
372 * @param [type] $recipRow: ...
373 * @return [type] ...
374 */
375 function convertFields($recipRow) {
376 if ($recipRow['telephone']) $recipRow['phone'] = $recipRow['telephone']; // Compensation for the fact that fe_users has the field, 'telephone' instead of 'phone'
377 $recipRow['firstname']=trim(strtok(trim($recipRow['name']),' '));
378 if (strlen($recipRow['firstname'])<2 || ereg('[^[:alnum:]]$',$recipRow['firstname'])) $recipRow['firstname']=$recipRow['name']; // Firstname must be more that 1 character
379 if (!trim($recipRow['firstname'])) $recipRow['firstname']=$recipRow['email'];
380 return $recipRow;
381 }
382
383 /**
384 * [Describe function...]
385 *
386 * @param [type] $mid: ...
387 * @param [type] $key: ...
388 * @return [type] ...
389 */
390 function dmailer_setBeginEnd($mid,$key) {
391 $GLOBALS['TYPO3_DB']->exec_UPDATEquery('sys_dmail', 'uid='.intval($mid), array('scheduled_'.$key => time()));
392
393 switch($key) {
394 case 'begin':
395 $subject = 'DMAILER mid:'.$mid.' JOB BEGIN';
396 $message = ': '.date('d-m-y h:i:s');
397 break;
398 case 'end':
399 $subject = 'DMAILER mid:'.$mid.' JOB END';
400 $message = ': '.date('d-m-y h:i:s');
401 break;
402 }
403 $this->logArray[] = $subject.': '.$message;
404 mail($this->from_email, $subject, $message);
405 }
406
407 /**
408 * [Describe function...]
409 *
410 * @param [type] $mid: ...
411 * @param [type] $rtbl: ...
412 * @return [type] ...
413 */
414 function dmailer_howManySendMails($mid,$rtbl='') {
415 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('count(*)', 'sys_dmail_maillog', 'mid='.intval($mid).' AND response_type=0'.($rtbl ? ' AND rtbl="'.$GLOBALS['TYPO3_DB']->quoteStr($rtbl, 'sys_dmail_maillog').'"' : ''));
416 $row = $GLOBALS['TYPO3_DB']->sql_fetch_row($res);
417 return $row[0];
418 }
419
420 /**
421 * [Describe function...]
422 *
423 * @param [type] $mid: ...
424 * @param [type] $rid: ...
425 * @param [type] $rtbl: ...
426 * @return [type] ...
427 */
428 function dmailer_isSend($mid,$rid,$rtbl) {
429 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'sys_dmail_maillog', 'rid='.intval($rid).' AND rtbl="'.$GLOBALS['TYPO3_DB']->quoteStr($rtbl, 'sys_dmail_maillog').'" AND mid='.intval($mid).' AND response_type=0');
430 return $GLOBALS['TYPO3_DB']->sql_num_rows($res);
431 }
432
433 /**
434 * [Describe function...]
435 *
436 * @param [type] $mid: ...
437 * @param [type] $rtbl: ...
438 * @return [type] ...
439 */
440 function dmailer_getSentMails($mid,$rtbl) {
441 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('rid', 'sys_dmail_maillog', 'mid='.intval($mid).' AND rtbl="'.$GLOBALS['TYPO3_DB']->quoteStr($rtbl, 'sys_dmail_maillog').'" AND response_type=0');
442 $list = array();
443 while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
444 $list[] = $row['rid'];
445 }
446 return implode(',', $list);
447 }
448
449 /**
450 * [Describe function...]
451 *
452 * @param [type] $mid: ...
453 * @param [type] $rid: ...
454 * @param [type] $size: ...
455 * @param [type] $parsetime: ...
456 * @param [type] $html: ...
457 * @return [type] ...
458 */
459 function dmailer_addToMailLog($mid,$rid,$size,$parsetime,$html) {
460 $temp_recip = explode('_',$rid);
461
462 $insertFields = array(
463 'mid' => intval($mid),
464 'rtbl' => $temp_recip[0],
465 'rid' => intval($temp_recip[1]),
466 'tstamp' => time(),
467 'url' => '',
468 'size' => $size,
469 'parsetime' => $parsetime,
470 'html_sent' => intval($html)
471 );
472
473 $GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_dmail_maillog', $insertFields);
474 }
475
476 /**
477 * [Describe function...]
478 *
479 * @return [type] ...
480 */
481 function runcron() {
482 $pt = t3lib_div::milliseconds();
483
484 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'sys_dmail', 'scheduled!=0 AND scheduled<'.time().' AND scheduled_end=0', '', 'scheduled');
485 if ($GLOBALS['TYPO3_DB']->sql_error()) {
486 die ($GLOBALS['TYPO3_DB']->sql_error());
487 }
488 $this->logArray[]='Invoked at '.date('h:i:s d-m-Y');
489
490 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
491 $this->logArray[]='sys_dmail record '.$row['uid'].", '".$row['subject']."' processed...";
492 $this->dmailer_prepare($row);
493 $query_info=unserialize($row['query_info']);
494 if (!$row['scheduled_begin']) {$this->dmailer_setBeginEnd($row['uid'],'begin');}
495 /*
496 $finished = $this->dmailer_masssend($query_info,'tt_address',$row['uid']);
497 if ($finished) {
498 $finished = $this->dmailer_masssend($query_info,'fe_users',$row['uid']);
499 }*/
500 $finished = $this->dmailer_masssend_list($query_info,$row['uid']);
501
502 if ($finished) {$this->dmailer_setBeginEnd($row['uid'],'end');}
503 } else {
504 $this->logArray[]='Nothing to do.';
505 }
506
507 $parsetime=t3lib_div::milliseconds()-$pt;
508 $this->logArray[]='Ending, parsetime: '.$parsetime.' ms';;
509 }
510 }
511
512
513 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_dmailer.php']) {
514 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_dmailer.php']);
515 }
516 ?>