* Added Karsten D.s patches for DBAL.
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_dmailer.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2004 Kasper Skaarhoj (kasperYYYY@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 <kasperYYYY@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 * 147: function dmailer_sendAdvanced($recipRow,$tableNameChar)
43 * 218: function dmailer_sendSimple($addressList)
44 * 241: function dmailer_getBoundaryParts($cArray,$userCategories)
45 * 263: function dmailer_masssend($query_info,$table,$mid)
46 * 299: function dmailer_masssend_list($query_info,$mid)
47 * 360: function shipOfMail($mid,$recipRow,$tKey)
48 * 377: function convertFields($recipRow)
49 * 392: function dmailer_setBeginEnd($mid,$key)
50 * 416: function dmailer_howManySendMails($mid,$rtbl='')
51 * 430: function dmailer_isSend($mid,$rid,$rtbl)
52 * 442: function dmailer_getSentMails($mid,$rtbl)
53 * 461: function dmailer_addToMailLog($mid,$rid,$size,$parsetime,$html)
54 * 483: 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 <kasperYYYY@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 if($row["encoding"] == "base64") {
100 $this->useBase64();
101 }
102 $this->theParts = unserialize($row['mailContent']);
103 $this->messageid = $this->theParts['messageid'];
104 $this->subject = $row['subject'];
105 $this->from_email = $row['from_email'];
106 $this->from_name = ($row['from_name']) ? $row['from_name'] : '';
107 $this->replyto_email = ($row['replyto_email']) ? $row['replyto_email'] : '';
108 $this->replyto_name = ($row['replyto_name']) ? $row['replyto_name'] : '';
109 $this->organisation = ($row['organisation']) ? $row['organisation'] : '';
110 $this->priority = t3lib_div::intInRange($row['priority'],1,5);
111 $this->mailer = 'TYPO3 Direct Mail module';
112
113 $this->dmailer['sectionBoundary'] = '<!--DMAILER_SECTION_BOUNDARY';
114 $this->dmailer['html_content'] = base64_decode($this->theParts['html']['content']);
115 $this->dmailer['plain_content'] = base64_decode($this->theParts['plain']['content']);
116 $this->dmailer['messageID'] = $this->messageid;
117 $this->dmailer['sys_dmail_uid'] = $sys_dmail_uid;
118 $this->dmailer['sys_dmail_rec'] = $row;
119
120 $this->dmailer['boundaryParts_html'] = explode($this->dmailer['sectionBoundary'], '_END-->'.$this->dmailer['html_content']);
121 while(list($bKey,$bContent)=each($this->dmailer['boundaryParts_html'])) {
122 $this->dmailer['boundaryParts_html'][$bKey] = explode('-->',$bContent,2);
123 // Now, analyzing which media files are used in this part of the mail:
124 $mediaParts = explode('cid:part',$this->dmailer['boundaryParts_html'][$bKey][1]);
125 reset($mediaParts);
126 next($mediaParts);
127 while(list(,$part)=each($mediaParts)) {
128 $this->dmailer['boundaryParts_html'][$bKey]['mediaList'].=','.strtok($part,'.');
129 }
130 }
131 $this->dmailer['boundaryParts_plain'] = explode($this->dmailer['sectionBoundary'], '_END-->'.$this->dmailer['plain_content']);
132 while(list($bKey,$bContent)=each($this->dmailer['boundaryParts_plain'])) {
133 $this->dmailer['boundaryParts_plain'][$bKey] = explode('-->',$bContent,2);
134 }
135
136 $this->flag_html = $this->theParts['html']['content'] ? 1 : 0;
137 $this->flag_plain = $this->theParts['plain']['content'] ? 1 : 0;
138 }
139
140 /**
141 * [Describe function...]
142 *
143 * @param [type] $recipRow: ...
144 * @param [type] $tableNameChar: ...
145 * @return [type] ...
146 */
147 function dmailer_sendAdvanced($recipRow,$tableNameChar) {
148 $returnCode=0;
149 if ($recipRow['email']) {
150 $midRidId = 'MID'.$this->dmailer['sys_dmail_uid'].'_'.$tableNameChar.$recipRow['uid'];
151 $uniqMsgId = md5(microtime()).'_'.$midRidId;
152 $rowFieldsArray = explode(',', 'uid,name,title,email,phone,www,address,company,city,zip,country,fax,firstname');
153 $uppercaseFieldsArray = explode(',', 'name,firstname');
154 $authCode = t3lib_div::stdAuthCode($recipRow['uid']);
155 $this->mediaList='';
156 if ($this->flag_html && $recipRow['module_sys_dmail_html']) {
157 $tempContent_HTML = $this->dmailer_getBoundaryParts($this->dmailer['boundaryParts_html'],$recipRow['module_sys_dmail_category']);
158 reset($rowFieldsArray);
159 while(list(,$substField)=each($rowFieldsArray)) {
160 $tempContent_HTML = str_replace('###USER_'.$substField.'###', $recipRow[$substField], $tempContent_HTML);
161 }
162 reset($uppercaseFieldsArray);
163 while(list(,$substField)=each($uppercaseFieldsArray)) {
164 $tempContent_HTML = str_replace('###USER_'.strtoupper($substField).'###', strtoupper($recipRow[$substField]), $tempContent_HTML);
165 }
166 $tempContent_HTML = str_replace('###SYS_TABLE_NAME###', $tableNameChar, $tempContent_HTML); // Put in the tablename of the userinformation
167 $tempContent_HTML = str_replace('###SYS_MAIL_ID###', $this->dmailer['sys_dmail_uid'], $tempContent_HTML); // Put in the uid of the mail-record
168 $tempContent_HTML = str_replace('###SYS_AUTHCODE###', $authCode, $tempContent_HTML);
169 $tempContent_HTML = str_replace($this->dmailer['messageID'], $uniqMsgId, $tempContent_HTML); // Put in the unique message id in HTML-code
170 $this->theParts['html']['content'] = $this->encodeMsg($tempContent_HTML);
171 $returnCode|=1;
172 } else $this->theParts['html']['content'] = '';
173
174 // Plain
175 if ($this->flag_plain) {
176 $tempContent_Plain = $this->dmailer_getBoundaryParts($this->dmailer['boundaryParts_plain'],$recipRow['module_sys_dmail_category']);
177 reset($rowFieldsArray);
178 while(list(,$substField)=each($rowFieldsArray)) {
179 $tempContent_Plain = str_replace('###USER_'.$substField.'###', $recipRow[$substField], $tempContent_Plain);
180 }
181 reset($uppercaseFieldsArray);
182 while(list(,$substField)=each($uppercaseFieldsArray)) {
183 $tempContent_Plain = str_replace('###USER_'.strtoupper($substField).'###', strtoupper($recipRow[$substField]), $tempContent_Plain);
184 }
185 $tempContent_Plain = str_replace('###SYS_TABLE_NAME###', $tableNameChar, $tempContent_Plain); // Put in the tablename of the userinformation
186 $tempContent_Plain = str_replace('###SYS_MAIL_ID###', $this->dmailer['sys_dmail_uid'], $tempContent_Plain); // Put in the uid of the mail-record
187 $tempContent_Plain = str_replace('###SYS_AUTHCODE###', $authCode, $tempContent_Plain);
188
189 if (trim($this->dmailer['sys_dmail_rec']['long_link_rdct_url'])) {
190 $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']));
191 }
192
193 $this->theParts['plain']['content'] = $this->encodeMsg($tempContent_Plain);
194 $returnCode|=2;
195 } else $this->theParts['plain']['content'] = '';
196
197 // Set content
198 $this->Xid = $midRidId.'-'.md5($midRidId);
199 $this->returnPath = str_replace('###XID###',$midRidId,$this->dmailer['sys_dmail_rec']['return_path']);
200
201 $this->part=0;
202 $this->setHeaders();
203 $this->setContent();
204 $this->setRecipient($recipRow['email']);
205
206 $this->message = str_replace($this->dmailer['messageID'], $uniqMsgId, $this->message); // Put in the unique message id in whole message body
207 $this->sendtheMail();
208 }
209 return $returnCode;
210 }
211
212 /**
213 * [Describe function...]
214 *
215 * @param [type] $addressList: ...
216 * @return [type] ...
217 */
218 function dmailer_sendSimple($addressList) {
219 $this->useBase64();
220 if ($this->theParts['html']['content']) {
221 $this->theParts['html']['content'] = $this->encodeMsg($this->dmailer_getBoundaryParts($this->dmailer['boundaryParts_html'],-1));
222 } else $this->theParts['html']['content'] = '';
223 if ($this->theParts['plain']['content']) {
224 $this->theParts['plain']['content'] = $this->encodeMsg($this->dmailer_getBoundaryParts($this->dmailer['boundaryParts_plain'],-1));
225 } else $this->theParts['plain']['content'] = '';
226
227 $this->setHeaders();
228 $this->setContent();
229 $this->setRecipient($addressList);
230 $this->sendtheMail();
231 return true;
232 }
233
234 /**
235 * [Describe function...]
236 *
237 * @param [type] $cArray: ...
238 * @param [type] $userCategories: ...
239 * @return [type] ...
240 */
241 function dmailer_getBoundaryParts($cArray,$userCategories) {
242 $userCategories = intval($userCategories);
243 reset($cArray);
244 $returnVal='';
245 while(list(,$cP)=each($cArray)) {
246 $key=substr($cP[0],1);
247 if ($key=='END' || !$key || $userCategories<0 || (intval($key) & $userCategories)>0) {
248 $returnVal.=$cP[1];
249 $this->mediaList.=$cP['mediaList'];
250 }
251 }
252 return $returnVal;
253 }
254
255 /**
256 * [Describe function...]
257 *
258 * @param [type] $query_info: ...
259 * @param [type] $table: ...
260 * @param [type] $mid: ...
261 * @return [type] ...
262 */
263 function dmailer_masssend($query_info,$table,$mid) {
264 $enableFields['tt_address']='tt_address.deleted=0 AND tt_address.hidden=0';
265 $enableFields['fe_users']='fe_users.deleted=0 AND fe_users.disable=0';
266 $tKey = substr($table,0,1);
267 $begin=intval($this->dmailer_howManySendMails($mid,$tKey));
268 if ($query_info[$table]) {
269 $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
270 if ($GLOBALS['TYPO3_DB']->sql_error()) {
271 die ($GLOBALS['TYPO3_DB']->sql_error());
272 }
273 $numRows = $GLOBALS['TYPO3_DB']->sql_num_rows($res);
274 $cc=0;
275 while($recipRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
276 if (!$this->dmailer_isSend($mid,$recipRow['uid'],$tKey)) {
277 $pt = t3lib_div::milliseconds();
278 if ($recipRow['telephone']) $recipRow['phone'] = $recipRow['telephone']; // Compensation for the fact that fe_users has the field, 'telephone' instead of 'phone'
279 $recipRow['firstname']=strtok(trim($recipRow['name']),' ');
280
281 $rC = $this->dmailer_sendAdvanced($recipRow,$tKey);
282 $this->dmailer_addToMailLog($mid,$tKey.'_'.$recipRow['uid'],strlen($this->message),t3lib_div::milliseconds()-$pt,$rC);
283 }
284 $cc++;
285 }
286 $this->logArray[]='Sending '.$cc.' mails to table '.$table;
287 if ($numRows < $this->sendPerCycle) return true;
288 }
289 return false;
290 }
291
292 /**
293 * [Describe function...]
294 *
295 * @param [type] $query_info: ...
296 * @param [type] $mid: ...
297 * @return [type] ...
298 */
299 function dmailer_masssend_list($query_info,$mid) {
300 $enableFields['tt_address']='tt_address.deleted=0 AND tt_address.hidden=0';
301 $enableFields['fe_users']='fe_users.deleted=0 AND fe_users.disable=0';
302
303 $c=0;
304 $returnVal=true;
305 if (is_array($query_info['id_lists'])) {
306 reset($query_info['id_lists']);
307 while(list($table,$listArr)=each($query_info['id_lists'])) {
308 if (is_array($listArr)) {
309 $ct=0;
310 // FInd tKey
311 if ($table=='tt_address' || $table=='fe_users') {
312 $tKey = substr($table,0,1);
313 } elseif ($table=='PLAINLIST') {
314 $tKey='P';
315 } else {$tKey='u';}
316
317 // Send mails
318 $sendIds=$this->dmailer_getSentMails($mid,$tKey);
319 if ($table=='PLAINLIST') {
320 $sendIdsArr=explode(',',$sendIds);
321 reset($listArr);
322 while(list($kval,$recipRow)=each($listArr)) {
323 $kval++;
324 if (!in_array($kval,$sendIdsArr)) {
325 if ($c>=$this->sendPerCycle) {$returnVal = false; break;} // We are NOT finished!
326 $recipRow['uid']=$kval;
327 $this->shipOfMail($mid,$recipRow,$tKey);
328 $ct++;
329 $c++;
330 }
331 }
332 } else {
333 $idList = implode(',',$listArr);
334 if ($idList) {
335 $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);
336 if ($GLOBALS['TYPO3_DB']->sql_error()) {die ($GLOBALS['TYPO3_DB']->sql_error());}
337 while($recipRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
338 if ($c>=$this->sendPerCycle) {$returnVal = false; break;} // We are NOT finished!
339 $this->shipOfMail($mid,$recipRow,$tKey);
340 $ct++;
341 $c++;
342 }
343 }
344 }
345 $this->logArray[]='Sending '.$ct.' mails to table '.$table;
346 }
347 }
348 }
349 return $returnVal;
350 }
351
352 /**
353 * [Describe function...]
354 *
355 * @param [type] $mid: ...
356 * @param [type] $recipRow: ...
357 * @param [type] $tKey: ...
358 * @return [type] ...
359 */
360 function shipOfMail($mid,$recipRow,$tKey) {
361 if (!$this->dmailer_isSend($mid,$recipRow['uid'],$tKey)) {
362 $pt = t3lib_div::milliseconds();
363 $recipRow=$this->convertFields($recipRow);
364
365 // debug('->'.$recipRow['uid'],1);
366 $rC=$this->dmailer_sendAdvanced($recipRow,$tKey);
367 $this->dmailer_addToMailLog($mid,$tKey.'_'.$recipRow['uid'],strlen($this->message),t3lib_div::milliseconds()-$pt,$rC);
368 }
369 }
370
371 /**
372 * [Describe function...]
373 *
374 * @param [type] $recipRow: ...
375 * @return [type] ...
376 */
377 function convertFields($recipRow) {
378 if ($recipRow['telephone']) $recipRow['phone'] = $recipRow['telephone']; // Compensation for the fact that fe_users has the field, 'telephone' instead of 'phone'
379 $recipRow['firstname']=trim(strtok(trim($recipRow['name']),' '));
380 if (strlen($recipRow['firstname'])<2 || ereg('[^[:alnum:]]$',$recipRow['firstname'])) $recipRow['firstname']=$recipRow['name']; // Firstname must be more that 1 character
381 if (!trim($recipRow['firstname'])) $recipRow['firstname']=$recipRow['email'];
382 return $recipRow;
383 }
384
385 /**
386 * [Describe function...]
387 *
388 * @param [type] $mid: ...
389 * @param [type] $key: ...
390 * @return [type] ...
391 */
392 function dmailer_setBeginEnd($mid,$key) {
393 $GLOBALS['TYPO3_DB']->exec_UPDATEquery('sys_dmail', 'uid='.intval($mid), array('scheduled_'.$key => time()));
394
395 switch($key) {
396 case 'begin':
397 $subject = 'DMAILER mid:'.$mid.' JOB BEGIN';
398 $message = ': '.date('d-m-y h:i:s');
399 break;
400 case 'end':
401 $subject = 'DMAILER mid:'.$mid.' JOB END';
402 $message = ': '.date('d-m-y h:i:s');
403 break;
404 }
405 $this->logArray[] = $subject.': '.$message;
406 mail($this->from_email, $subject, $message);
407 }
408
409 /**
410 * [Describe function...]
411 *
412 * @param [type] $mid: ...
413 * @param [type] $rtbl: ...
414 * @return [type] ...
415 */
416 function dmailer_howManySendMails($mid,$rtbl='') {
417 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('count(*)', 'sys_dmail_maillog', 'mid='.intval($mid).' AND response_type=0'.($rtbl ? ' AND rtbl='.$GLOBALS['TYPO3_DB']->fullQuoteStr($rtbl, 'sys_dmail_maillog') : ''));
418 $row = $GLOBALS['TYPO3_DB']->sql_fetch_row($res);
419 return $row[0];
420 }
421
422 /**
423 * [Describe function...]
424 *
425 * @param [type] $mid: ...
426 * @param [type] $rid: ...
427 * @param [type] $rtbl: ...
428 * @return [type] ...
429 */
430 function dmailer_isSend($mid,$rid,$rtbl) {
431 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'sys_dmail_maillog', 'rid='.intval($rid).' AND rtbl='.$GLOBALS['TYPO3_DB']->fullQuoteStr($rtbl, 'sys_dmail_maillog').' AND mid='.intval($mid).' AND response_type=0');
432 return $GLOBALS['TYPO3_DB']->sql_num_rows($res);
433 }
434
435 /**
436 * [Describe function...]
437 *
438 * @param [type] $mid: ...
439 * @param [type] $rtbl: ...
440 * @return [type] ...
441 */
442 function dmailer_getSentMails($mid,$rtbl) {
443 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('rid', 'sys_dmail_maillog', 'mid='.intval($mid).' AND rtbl='.$GLOBALS['TYPO3_DB']->fullQuoteStr($rtbl, 'sys_dmail_maillog').' AND response_type=0');
444 $list = array();
445 while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
446 $list[] = $row['rid'];
447 }
448 return implode(',', $list);
449 }
450
451 /**
452 * [Describe function...]
453 *
454 * @param [type] $mid: ...
455 * @param [type] $rid: ...
456 * @param [type] $size: ...
457 * @param [type] $parsetime: ...
458 * @param [type] $html: ...
459 * @return [type] ...
460 */
461 function dmailer_addToMailLog($mid,$rid,$size,$parsetime,$html) {
462 $temp_recip = explode('_',$rid);
463
464 $insertFields = array(
465 'mid' => intval($mid),
466 'rtbl' => $temp_recip[0],
467 'rid' => intval($temp_recip[1]),
468 'tstamp' => time(),
469 'url' => '',
470 'size' => $size,
471 'parsetime' => $parsetime,
472 'html_sent' => intval($html)
473 );
474
475 $GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_dmail_maillog', $insertFields);
476 }
477
478 /**
479 * [Describe function...]
480 *
481 * @return [type] ...
482 */
483 function runcron() {
484 $pt = t3lib_div::milliseconds();
485
486 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'sys_dmail', 'scheduled!=0 AND scheduled<'.time().' AND scheduled_end=0', '', 'scheduled');
487 if ($GLOBALS['TYPO3_DB']->sql_error()) {
488 die ($GLOBALS['TYPO3_DB']->sql_error());
489 }
490 $this->logArray[]='Invoked at '.date('h:i:s d-m-Y');
491
492 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
493 $this->logArray[]='sys_dmail record '.$row['uid'].", '".$row['subject']."' processed...";
494 $this->dmailer_prepare($row);
495 $query_info=unserialize($row['query_info']);
496 if (!$row['scheduled_begin']) {$this->dmailer_setBeginEnd($row['uid'],'begin');}
497 /*
498 $finished = $this->dmailer_masssend($query_info,'tt_address',$row['uid']);
499 if ($finished) {
500 $finished = $this->dmailer_masssend($query_info,'fe_users',$row['uid']);
501 }*/
502 $finished = $this->dmailer_masssend_list($query_info,$row['uid']);
503
504 if ($finished) {$this->dmailer_setBeginEnd($row['uid'],'end');}
505 } else {
506 $this->logArray[]='Nothing to do.';
507 }
508
509 $parsetime=t3lib_div::milliseconds()-$pt;
510 $this->logArray[]='Ending, parsetime: '.$parsetime.' ms';;
511 }
512 }
513
514
515 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_dmailer.php']) {
516 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_dmailer.php']);
517 }
518 ?>