*** empty log message ***
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_dmailer.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2003 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 * 217: function dmailer_sendSimple($addressList)
44 * 239: function dmailer_getBoundaryParts($cArray,$userCategories)
45 * 261: function dmailer_masssend($query_info,$table,$mid)
46 * 298: function dmailer_masssend_list($query_info,$mid)
47 * 360: function shipOfMail($mid,$recipRow,$tKey)
48 * 378: function convertFields($recipRow)
49 * 393: function dmailer_setBeginEnd($mid,$key)
50 * 418: function dmailer_howManySendMails($mid,$rtbl='')
51 * 434: function dmailer_isSend($mid,$rid,$rtbl)
52 * 447: function dmailer_getSentMails($mid,$rtbl)
53 * 467: function dmailer_addToMailLog($mid,$rid,$size,$parsetime,$html)
54 * 479: 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->messageid = $uniqMsgId;
197 $this->Xid = $midRidId.'-'.md5($midRidId);
198 $this->returnPath = str_replace('###XID###',$midRidId,$this->dmailer['sys_dmail_rec']['return_path']);
199
200 $this->part=0;
201 $this->setHeaders();
202 $this->setContent();
203 $this->setRecipient($recipRow['email']);
204
205 $this->message = str_replace($this->dmailer['messageID'], $uniqMsgId, $this->message); // Put in the unique message id in whole message body
206 $this->sendtheMail();
207 }
208 return $returnCode;
209 }
210
211 /**
212 * [Describe function...]
213 *
214 * @param [type] $addressList: ...
215 * @return [type] ...
216 */
217 function dmailer_sendSimple($addressList) {
218 if ($this->theParts['html']['content']) {
219 $this->theParts['html']['content'] = $this->encodeMsg($this->dmailer_getBoundaryParts($this->dmailer['boundaryParts_html'],-1));
220 } else $this->theParts['html']['content'] = '';
221 if ($this->theParts['plain']['content']) {
222 $this->theParts['plain']['content'] = $this->encodeMsg($this->dmailer_getBoundaryParts($this->dmailer['boundaryParts_plain'],-1));
223 } else $this->theParts['plain']['content'] = '';
224
225 $this->setHeaders();
226 $this->setContent();
227 $this->setRecipient($addressList);
228 $this->sendtheMail();
229 return true;
230 }
231
232 /**
233 * [Describe function...]
234 *
235 * @param [type] $cArray: ...
236 * @param [type] $userCategories: ...
237 * @return [type] ...
238 */
239 function dmailer_getBoundaryParts($cArray,$userCategories) {
240 $userCategories = intval($userCategories);
241 reset($cArray);
242 $returnVal='';
243 while(list(,$cP)=each($cArray)) {
244 $key=substr($cP[0],1);
245 if ($key=='END' || !$key || $userCategories<0 || (intval($key) & $userCategories)>0) {
246 $returnVal.=$cP[1];
247 $this->mediaList.=$cP['mediaList'];
248 }
249 }
250 return $returnVal;
251 }
252
253 /**
254 * [Describe function...]
255 *
256 * @param [type] $query_info: ...
257 * @param [type] $table: ...
258 * @param [type] $mid: ...
259 * @return [type] ...
260 */
261 function dmailer_masssend($query_info,$table,$mid) {
262 $enableFields['tt_address']='NOT tt_address.deleted AND NOT tt_address.hidden';
263 $enableFields['fe_users']='NOT fe_users.deleted AND NOT fe_users.disable';
264 $tKey = substr($table,0,1);
265 $begin=intval($this->dmailer_howManySendMails($mid,$tKey));
266 if ($query_info[$table]) {
267 $query='SELECT '.$table.'.* FROM $table WHERE '.$enableFields[$table].' AND ('.$query_info[$table].') ORDER BY tstamp DESC LIMIT '.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
268 $res=mysql(TYPO3_db,$query);
269 if (mysql_error()) {
270 die (mysql_error());
271 }
272 $numRows=mysql_num_rows($res);
273 $cc=0;
274 while($recipRow=mysql_fetch_assoc($res)) {
275 if (!$this->dmailer_isSend($mid,$recipRow['uid'],$tKey)) {
276 $pt = t3lib_div::milliseconds();
277 if ($recipRow['telephone']) $recipRow['phone'] = $recipRow['telephone']; // Compensation for the fact that fe_users has the field, 'telephone' instead of 'phone'
278 $recipRow['firstname']=strtok(trim($recipRow['name']),' ');
279
280 $rC = $this->dmailer_sendAdvanced($recipRow,$tKey);
281 $this->dmailer_addToMailLog($mid,$tKey.'_'.$recipRow['uid'],strlen($this->message),t3lib_div::milliseconds()-$pt,$rC);
282 }
283 $cc++;
284 }
285 $this->logArray[]='Sending '.$cc.' mails to table '.$table;
286 if ($numRows < $this->sendPerCycle) return true;
287 }
288 return false;
289 }
290
291 /**
292 * [Describe function...]
293 *
294 * @param [type] $query_info: ...
295 * @param [type] $mid: ...
296 * @return [type] ...
297 */
298 function dmailer_masssend_list($query_info,$mid) {
299 $enableFields['tt_address']='NOT tt_address.deleted AND NOT tt_address.hidden';
300 $enableFields['fe_users']='NOT fe_users.deleted AND NOT fe_users.disable';
301
302 $c=0;
303 $returnVal=true;
304 if (is_array($query_info['id_lists'])) {
305 reset($query_info['id_lists']);
306 while(list($table,$listArr)=each($query_info['id_lists'])) {
307 if (is_array($listArr)) {
308 $ct=0;
309 // FInd tKey
310 if ($table=='tt_address' || $table=='fe_users') {
311 $tKey = substr($table,0,1);
312 } elseif ($table=='PLAINLIST') {
313 $tKey='P';
314 } else {$tKey='u';}
315
316 // Send mails
317 $sendIds=$this->dmailer_getSentMails($mid,$tKey);
318 if ($table=='PLAINLIST') {
319 $sendIdsArr=explode(',',$sendIds);
320 reset($listArr);
321 while(list($kval,$recipRow)=each($listArr)) {
322 $kval++;
323 if (!in_array($kval,$sendIdsArr)) {
324 if ($c>=$this->sendPerCycle) {$returnVal = false; break;} // We are NOT finished!
325 $recipRow['uid']=$kval;
326 $this->shipOfMail($mid,$recipRow,$tKey);
327 $ct++;
328 $c++;
329 }
330 }
331 } else {
332 $idList = implode(',',$listArr);
333 if ($idList) {
334 $query='SELECT '.$table.'.* FROM $table WHERE uid IN ('.$idList.') AND uid NOT IN ('.($sendIds?$sendIds:0).') AND '.($enableFields[$table]?$enableFields[$table]:'1=1').' LIMIT '.($this->sendPerCycle+1);
335 $res=mysql(TYPO3_db,$query);
336 if (mysql_error()) {die (mysql_error());}
337 while($recipRow=mysql_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 // $recipRow['email']='kasper@typo3.com';
367 $rC=$this->dmailer_sendAdvanced($recipRow,$tKey);
368 $this->dmailer_addToMailLog($mid,$tKey.'_'.$recipRow['uid'],strlen($this->message),t3lib_div::milliseconds()-$pt,$rC);
369 }
370 }
371
372 /**
373 * [Describe function...]
374 *
375 * @param [type] $recipRow: ...
376 * @return [type] ...
377 */
378 function convertFields($recipRow) {
379 if ($recipRow['telephone']) $recipRow['phone'] = $recipRow['telephone']; // Compensation for the fact that fe_users has the field, 'telephone' instead of 'phone'
380 $recipRow['firstname']=trim(strtok(trim($recipRow['name']),' '));
381 if (strlen($recipRow['firstname'])<2 || ereg('[^[:alnum:]]$',$recipRow['firstname'])) $recipRow['firstname']=$recipRow['name']; // Firstname must be more that 1 character
382 if (!trim($recipRow['firstname'])) $recipRow['firstname']=$recipRow['email'];
383 return $recipRow;
384 }
385
386 /**
387 * [Describe function...]
388 *
389 * @param [type] $mid: ...
390 * @param [type] $key: ...
391 * @return [type] ...
392 */
393 function dmailer_setBeginEnd($mid,$key) {
394 $query='UPDATE sys_dmail SET scheduled_'.$key.'='.time().' WHERE uid='.intval($mid);
395 $res=mysql(TYPO3_db,$query);
396 echo mysql_error();
397 switch($key) {
398 case 'begin':
399 $subject='DMAILER mid:'.$mid.' JOB BEGIN';
400 $message=': '.date('d-m-y h:i:s');
401 break;
402 case 'end':
403 $subject='DMAILER mid:'.$mid.' JOB END';
404 $message=': '.date('d-m-y h:i:s');
405 break;
406 }
407 $this->logArray[]=$subject.': '.$message;
408 mail($this->from_email, $subject, $message);
409 }
410
411 /**
412 * [Describe function...]
413 *
414 * @param [type] $mid: ...
415 * @param [type] $rtbl: ...
416 * @return [type] ...
417 */
418 function dmailer_howManySendMails($mid,$rtbl='') {
419 $tblClause = $rtbl ? ' AND rtbl="'.$rtbl.'"' : '';
420 $query='SELECT count(*) FROM sys_dmail_maillog WHERE mid='.$mid.' AND response_type=0'.$tblClause;
421 $res=mysql(TYPO3_db,$query);
422 $row= mysql_fetch_row($res);
423 return $row[0];
424 }
425
426 /**
427 * [Describe function...]
428 *
429 * @param [type] $mid: ...
430 * @param [type] $rid: ...
431 * @param [type] $rtbl: ...
432 * @return [type] ...
433 */
434 function dmailer_isSend($mid,$rid,$rtbl) {
435 $query='SELECT uid FROM sys_dmail_maillog WHERE rid='.intval($rid).' AND rtbl="'.$rtbl.'" AND mid='.intval($mid).' AND response_type=0';
436 $res=mysql(TYPO3_db,$query);
437 return mysql_num_rows($res);
438 }
439
440 /**
441 * [Describe function...]
442 *
443 * @param [type] $mid: ...
444 * @param [type] $rtbl: ...
445 * @return [type] ...
446 */
447 function dmailer_getSentMails($mid,$rtbl) {
448 $query='SELECT rid FROM sys_dmail_maillog WHERE mid='.$mid.' AND rtbl="'.$rtbl.'" AND response_type=0';
449 $res=mysql(TYPO3_db,$query);
450 $list=array();
451 while($row=mysql_fetch_assoc($res)) {
452 $list[]=$row['rid'];
453 }
454 return implode(',',$list);
455 }
456
457 /**
458 * [Describe function...]
459 *
460 * @param [type] $mid: ...
461 * @param [type] $rid: ...
462 * @param [type] $size: ...
463 * @param [type] $parsetime: ...
464 * @param [type] $html: ...
465 * @return [type] ...
466 */
467 function dmailer_addToMailLog($mid,$rid,$size,$parsetime,$html) {
468 $temp_recip=explode('_',$rid);
469 $temp_query="INSERT INTO sys_dmail_maillog (mid,rtbl,rid,tstamp,url,size,parsetime,html_sent) VALUES ('".intval($mid)."','".addslashes($temp_recip[0])."','".intval($temp_recip[1])."','".time()."','','".$size."','".$parsetime."',".intval($html).')';
470 $temp_res = mysql(TYPO3_db,$temp_query);
471 echo mysql_error();
472 }
473
474 /**
475 * [Describe function...]
476 *
477 * @return [type] ...
478 */
479 function runcron() {
480 $pt = t3lib_div::milliseconds();
481
482 $query='SELECT * FROM sys_dmail WHERE scheduled!=0 AND scheduled<'.time().' AND scheduled_end=0 ORDER BY scheduled';
483 $res=mysql(TYPO3_db,$query);
484 if (mysql_error()) {
485 die (mysql_error());
486 }
487 $this->logArray[]='Invoked at '.date('h:i:s d-m-Y');
488
489 if ($row=mysql_fetch_assoc($res)) {
490 $this->logArray[]='sys_dmail record '.$row['uid'].", '".$row['subject']."' processed...";
491 $this->dmailer_prepare($row);
492 $query_info=unserialize($row['query_info']);
493 if (!$row['scheduled_begin']) {$this->dmailer_setBeginEnd($row['uid'],'begin');}
494 /*
495 $finished = $this->dmailer_masssend($query_info,'tt_address',$row['uid']);
496 if ($finished) {
497 $finished = $this->dmailer_masssend($query_info,'fe_users',$row['uid']);
498 }*/
499 $finished = $this->dmailer_masssend_list($query_info,$row['uid']);
500
501 if ($finished) {$this->dmailer_setBeginEnd($row['uid'],'end');}
502 } else {
503 $this->logArray[]='Nothing to do.';
504 }
505
506 $parsetime=t3lib_div::milliseconds()-$pt;
507 $this->logArray[]='Ending, parsetime: '.$parsetime.' ms';;
508 }
509 }
510
511
512 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_dmailer.php']) {
513 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_dmailer.php']);
514 }
515 ?>