1<?php
2require_once dirname(__FILE__).'/accesscheck.php';
3
4include_once dirname(__FILE__).'/date.php';
5include_once dirname(__FILE__).'/analytics.php';
6
7$errormsg = '';
8$done = 0;
9$messageid = 0;
10$forwardsubject = $forwardmessage = $forwardfooter = '';
11$placeinqueue = '';
12$sendtestresult = '';
13$duplicate_atribute = 0; // not actually used it seems @@@ check
14$embargo = new date('embargo');
15$embargo->useTime = true;
16$repeatuntil = new date('repeatuntil');
17$repeatuntil->useTime = true;
18$requeueuntil = new date('requeueuntil');
19$requeueuntil->useTime = true;
20
21if (ALLOW_ATTACHMENTS) {
22    $enctype = 'enctype="multipart/form-data"';
23} else {
24    $enctype = '';
25}
26
27//## variable initialisation and sanity checks
28if (isset($_GET['id'])) {
29    $id = sprintf('%d', $_GET['id']);
30} else {
31    $id = 0;
32}
33//# page actions
34$send = isset($_POST['send']);
35$prepare = isset($_POST['prepare']);
36$save = !empty($_POST['save']) || !empty($_POST['followupto']);
37$savedraft = !empty($_POST['savedraft']);
38$sendtest = !empty($_POST['sendtest']);
39$baseurl = PageURL2('send'.'&amp;id='.$id);
40
41if (!isset($_GET['tab'])) {
42    $_GET['tab'] = '';
43}
44$_GET['tab'] = strip_tags($_GET['tab']);
45if (!empty($_GET['tab'])) {
46    $baseurl .= '&tab='.$_GET['tab'];
47}
48
49//## if we're not working on an existing message, create one and redirect to edit it
50if (!$id) {
51    $defaulttemplate = getConfig('defaultmessagetemplate');
52    $defaultfooter = getConfig('messagefooter');
53    Sql_Query(sprintf('insert into %s (subject, status, entered, sendformat, embargo, repeatuntil, owner, template, tofield, replyto,footer, uuid)
54    values("(no title)", "draft", now(), "HTML", now(), now(), %d, %d, "", "", "%s", "%s" )',
55        $GLOBALS['tables']['message'],
56        $_SESSION['logindetails']['id'],
57        $defaulttemplate, sql_escape($defaultfooter), (string) Uuid::generate(4)));
58
59    $id = Sql_Insert_Id();
60    if (empty($id)) { // something went wrong creating the campaign
61        Fatal_Error(s('Unable to create campaign, did you forget to upgrade the database?'));
62        $done = 1;
63
64        return;
65    }
66
67    if (isset($_GET['list'])) {
68        if ($_GET['list'] == 'all') {
69            $req = Sql_Query('select id from '.$tables['list']);
70            while ($row = Sql_Fetch_Row($req)) {
71                $addlists[] = $row[0];
72            }
73        } else {
74            $addlists = explode(',', $_GET['list']);
75        }
76        $addlists = cleanArray($addlists);
77        foreach ($addlists as $listid) {
78            $query = sprintf('replace into %s (messageid,listid,entered) values(%d,%d,now())',
79                $GLOBALS['tables']['listmessage'], $id, $listid);
80            Sql_Query($query);
81        }
82    }
83
84    // 0008720: Using -p send from the commandline doesn't seem to work
85    if (!$GLOBALS['commandline']) {
86        Redirect($_GET['page'].'&id='.$id.addCsrfGetToken());
87        exit;
88    }
89}
90
91// load all message data
92$messagedata = loadMessageData($id);
93
94//# auto generate the text version if empty
95//# hmm, might want this as config
96/*
97if (empty($messagedata['textmessage'])) {
98  include 'actions/generatetext.php';
99}
100*/
101
102//var_dump($messagedata);
103//exit;
104//print '<h3>'.$messagedata['status'].'</h3>';
105
106if (!empty($_GET['deletecriterion'])) {
107    include dirname(__FILE__).'/actions/deletecriterion.php';
108    Redirect($_GET['page'].'&id='.$id.'&tab='.$_GET['tab']);
109}
110ob_end_flush();
111
112//load database data###########################
113
114if ($id) {
115    // Load message attributes / values
116    $result = Sql_query("SELECT * FROM {$tables['message']} where id = $id $ownership");
117    if (!Sql_Affected_Rows()) {
118        echo $GLOBALS['I18N']->get('Access Denied');
119        $done = 1;
120
121        return;
122    }
123
124    echo formStart($enctype.' name="sendmessageform" class="sendSend" id="sendmessageform" ');
125    if (empty($send)) {
126        $placeinqueue = '<div id="addtoqueue"><button class="submit" type="submit" name="send" id="addtoqueuebutton">'.$GLOBALS['I18N']->get('Send Campaign').'</button></div>';
127    } else {
128        //# hide the div in the final "message added to queue" page
129        //  print '<div id="addtoqueue"></div>';
130    }
131    require dirname(__FILE__).'/structure.php';  // This gets the database structures into DBStruct
132
133    include dirname(__FILE__).'/actions/storemessage.php';
134}
135
136$htmlformatted = strip_tags($messagedata['message']) != $messagedata['message'];
137
138// sanitise the header fields, what else do we need to check on?
139if (preg_match("/\n|\r/", $messagedata['fromfield'])) {
140    $messagedata['fromfield'] = '';
141}
142if (preg_match("/\n|\r/", $messagedata['forwardsubject'])) {
143    $messagedata['forwardsubject'] = '';
144}
145
146//# check that the message does not contain URLs that look like click tracking links
147//# it seems people are pasting the results of test messages back in the editor, which would duplicate
148//# tracking
149
150$hasClickTrackLinks = preg_match('/lt\.php\?id=[\w%]{22}/', $messagedata['message'],
151        $regs) || preg_match('/lt\.php\?id=[\w%]{16}/', $messagedata['message'], $regs) ||
152    (CLICKTRACK_LINKMAP && (preg_match('#'.CLICKTRACK_LINKMAP.'/[\w%]{22}#',
153                $messagedata['message']) || preg_match('#'.CLICKTRACK_LINKMAP.'/[\w%]{16}#',
154                $messagedata['message'])));
155
156if ($hasClickTrackLinks) {
157    echo Error(s('You should not paste the results of a test message back into the editor<br/>This will break the click-track statistics, and overload the server.'),
158        'http://resources.phplist.com/documentation/errors/pasteclicktrack');
159}
160// If the variable isn't filled in, then the input fields don't default to the
161// values selected.  Need to fill it in so a post will correctly display.
162
163if (!isset($_SESSION['fckeditor_height'])) {
164    $_SESSION['fckeditor_height'] = getConfig('fckeditor_height');
165}
166
167//actions and store in database#######################
168
169if ($send || $sendtest || $prepare || $save || $savedraft) {
170    verifyCsrfGetToken();
171    if ($savedraft || $save || $sendtest) {
172        // We're just saving, not sending.
173        if (!isset($messagedata['status']) || $messagedata['status'] == '') {
174            // No status - move to draft state
175            $messagedata['status'] = 'draft';
176        }
177    } elseif ($send) {
178        // We're sending - change state to "send-it" status!
179        if (is_array($messagedata['targetlist']) && count($messagedata['targetlist'])
180            && !empty($messagedata['subject']) && !empty($messagedata['fromfield']) &&
181            !empty($messagedata['message']) && empty($duplicate_attribute)
182        ) {
183            $messagedata['status'] = 'submitted';
184            setMessageData($id, 'status', 'submitted');
185        } else {
186            if (USE_PREPARE) {
187                $messagedata['status'] = 'prepared';
188            } else {
189                $messagedata['status'] = 'draft';
190            }
191        }
192    }
193
194    //## allow plugins manipulate data or save it somewhere else
195    $plugintabs = array();
196    foreach ($GLOBALS['plugins'] as $pluginname => $plugin) {
197        //  print "Saving ".$plugin->name;
198        $resultMsg = $plugin->sendMessageTabSave($id, $messagedata);
199    }
200
201    if (!$htmlformatted && strip_tags($messagedata['message']) != $messagedata['message']) {
202        $errormsg = '<span  class="error">'.$GLOBALS['I18N']->get('Warning: You indicated the content was not HTML, but there were  some HTML  tags in it. This  may  cause  errors').'</span>';
203    }
204
205    $result = Sql_Query(
206        sprintf('update %s  set
207        subject = "%s", fromfield = "%s", tofield = "%s",
208        replyto ="%s", embargo = "%s", repeatinterval = "%s", repeatuntil = "%s",
209        message = "%s", textmessage = "%s", footer = "%s", status = "%s",
210        htmlformatted = "%s", sendformat  = "%s", template  =  "%s" where id = %d',
211            $tables['message'],
212            sql_escape(strip_tags($messagedata['campaigntitle'])),
213            /* we store the title in the subject field. Better would be to rename the DB column, but this will do for now */
214            sql_escape($messagedata['fromfield']),
215            sql_escape($messagedata['tofield']),
216            sql_escape($messagedata['replyto']),
217            sprintf('%04d-%02d-%02d %02d:%02d',
218                $messagedata['embargo']['year'], $messagedata['embargo']['month'], $messagedata['embargo']['day'],
219                $messagedata['embargo']['hour'], $messagedata['embargo']['minute']), $messagedata['repeatinterval'],
220            sprintf('%04d-%02d-%02d %02d:%02d',
221                $messagedata['repeatuntil']['year'], $messagedata['repeatuntil']['month'],
222                $messagedata['repeatuntil']['day'],
223                $messagedata['repeatuntil']['hour'], $messagedata['repeatuntil']['minute']),
224            sql_escape($messagedata['message']),
225            sql_escape($messagedata['textmessage']),
226            sql_escape($messagedata['footer']),
227            sql_escape($messagedata['status']), $htmlformatted ? '1' : '0',
228            sql_escape($messagedata['sendformat']),
229            sql_escape($messagedata['template']), $id
230        )
231    );
232
233    //# do this seperately, so that the above query doesn't fail when the DB hasn't been upgraded
234    $result = Sql_Query(
235        sprintf('update %s set requeueinterval = "%s", requeueuntil = "%s" where id = %d', $tables['message'],
236            $messagedata['requeueinterval'], sprintf('%04d-%02d-%02d %02d:%02d',
237                $messagedata['requeueuntil']['year'], $messagedata['requeueuntil']['month'],
238                $messagedata['requeueuntil']['day'],
239                $messagedata['requeueuntil']['hour'], $messagedata['requeueuntil']['minute']), $id
240        )
241    );
242
243//    print "Message ID: $id";
244    //    exit;
245    if ($GLOBALS['commandline']) {
246        if (isset($_POST['targetlist']) && is_array($_POST['targetlist'])) {
247            Sql_query("delete from {$tables['listmessage']} where messageid = $id");
248            foreach ($_POST['targetlist'] as $listid => $val) {
249                $result = Sql_query("insert ignore into {$tables['listmessage']} (messageid,listid,entered) values($id,$listid,now())");
250            }
251        }
252    }
253
254// we want to create a join on tables as follows, in order to find users who have their attributes to the values chosen
255// (independent of their list membership).
256// select
257//  table1.userid from user_attribute as table1
258//  left join user_attribute as table2 on table1.userid = table2.userid
259//  left join user_attribute as table3 on table1.userid = table3.userid
260//  ...
261// where
262//  table1.attributeid = 2 and table1.value in (1,2,3,4)
263//  and table2.attributeid = 1 and table2.value in (3,15)
264//  and table3.attributeid = 3 and table3.value in (4,5,6)
265//  ...
266
267    // criteria system, add one by one:
268
269    if (ALLOW_ATTACHMENTS && isset($_FILES) && is_array($_FILES) && count($_FILES) > 0) {
270        for ($att_cnt = 1; $att_cnt <= NUMATTACHMENTS; ++$att_cnt) {
271            $fieldname = 'attachment'.$att_cnt;
272            if (isset($_FILES[$fieldname])) {
273                $tmpfile = $_FILES[$fieldname]['tmp_name'];
274                $remotename = $_FILES[$fieldname]['name'];
275                $type = $_FILES[$fieldname]['type'];
276                $newtmpfile = $remotename.time();
277                move_uploaded_file($tmpfile, $GLOBALS['tmpdir'].'/'.$newtmpfile);
278                if (is_file($GLOBALS['tmpdir'].'/'.$newtmpfile) && filesize($GLOBALS['tmpdir'].'/'.$newtmpfile)) {
279                    $tmpfile = $GLOBALS['tmpdir'].'/'.$newtmpfile;
280                }
281                if (strlen($type) > 255) {
282                    echo Warn($GLOBALS['I18N']->get('Mime Type is longer than 255 characters, this is trouble'));
283                }
284                $description = $_POST[$fieldname.'_description'];
285            } else {
286                $tmpfile = '';
287            }
288            if ($tmpfile && filesize($tmpfile) && $tmpfile != 'none') {
289                list($name, $ext) = explode('.', basename($remotename));
290                // create a temporary file to make sure to use a unique file name to store with
291                $newfile = tempnam($GLOBALS['attachment_repository'], $name);
292                $newfile .= '.'.$ext;
293                $newfile = basename($newfile);
294                $file_size = filesize($tmpfile);
295                $fd = fopen($tmpfile, 'r');
296                $contents = fread($fd, filesize($tmpfile));
297                fclose($fd);
298                if ($file_size) {
299                    // this may seem odd, but it allows for a remote (ftp) repository
300                    // also, "copy" does not work across filesystems
301                    $fd = fopen($GLOBALS['attachment_repository'].'/'.$newfile, 'w');
302                    fwrite($fd, $contents);
303                    fclose($fd);
304                    Sql_query(sprintf('insert into %s (filename,remotefile,mimetype,description,size) values("%s","%s","%s","%s",%d)',
305                            $tables['attachment'],
306                            basename($newfile), $remotename, $type, $description, $file_size)
307                    );
308                    $attachmentid = Sql_Insert_id();
309                    Sql_query(sprintf('insert into %s (messageid,attachmentid) values(%d,%d)',
310                        $tables['message_attachment'], $id, $attachmentid));
311                    if (is_file($tmpfile)) {
312                        unlink($tmpfile);
313                    }
314
315                    // do a final check
316                    if (filesize($GLOBALS['attachment_repository'].'/'.$newfile)) {
317                        echo Info(s('Attachment %d succesfully added', $att_cnt));
318                    } else {
319                        echo Info(s('Adding attachment %d failed', $att_cnt));
320                    }
321                } else {
322                    echo Warn($GLOBALS['I18N']->get('Uploaded file not properly received, empty file'));
323                }
324            } elseif (!empty($_POST['localattachment'.$att_cnt])) {
325                $type = findMime(basename($_POST['localattachment'.$att_cnt]));
326                Sql_query(sprintf('insert into %s (remotefile,mimetype,description,size) values("%s","%s","%s",%d)',
327                        $tables['attachment'],
328                        $_POST['localattachment'.$att_cnt], $type, $description,
329                        filesize($_POST['localattachment'.$att_cnt]))
330                );
331                $attachmentid = Sql_Insert_id();
332                Sql_query(sprintf('insert into %s (messageid,attachmentid) values(%d,%d)',
333                    $tables['message_attachment'], $id, $attachmentid));
334                echo Info(s('Adding attachment').' '.$att_cnt." mime: $type");
335            }
336        }
337    }
338
339    //# when followupto is set, go there
340    if (!empty($_POST['followupto']) && isValidRedirect($_POST['followupto'])) {
341        header('Location: '.$_POST['followupto']);
342        exit;
343    }
344
345    if (!empty($id) && !$send) {
346        if ($savedraft) {
347            $_SESSION['action_result'] = s('Campaign saved as draft');
348            header('Location: ./?page=messages&tab=draft');
349            exit;
350        }
351    } else {
352        //    $id = $messageid; // New ID - need to set it for later use (test email).
353        echo '<h3>'.$GLOBALS['I18N']->get('Campaign added').'</h3><br/>';
354    }
355    // var_dump($messagedata);
356
357    // If we're sending the message, just return now to the calling script
358    // we only need to check that everything is there, once we actually want to send
359    if ($send && !empty($messagedata['subject']) && !empty($messagedata['fromfield']) && !empty($messagedata['message']) && empty($duplicate_atribute) && count($messagedata['targetlist'])) {
360        if ($messagedata['status'] == 'submitted') {
361
362            //#16615, check that "send until" is in after the embargo and warn if it isn't
363            $finishSending = mktime($messagedata['finishsending']['hour'], $messagedata['finishsending']['minute'], 0,
364                $messagedata['finishsending']['month'], $messagedata['finishsending']['day'],
365                $messagedata['finishsending']['year']);
366            $embargoTime = mktime($messagedata['embargo']['hour'], $messagedata['embargo']['minute'], 0,
367                $messagedata['embargo']['month'], $messagedata['embargo']['day'], $messagedata['embargo']['year']);
368
369            if ($finishSending < $embargoTime) {
370                echo Warn(s('This campaign is scheduled to stop sending before the embargo time. No mails will be sent.'));
371                echo PageLinkButton('send&amp;id='.$messagedata['id'].'&amp;tab=Scheduling',
372                    s('Review Scheduling'));
373            }
374            //# reset any queued messages, as the selection may have changed
375            if (defined('MESSAGEQUEUE_PREPARE') && MESSAGEQUEUE_PREPARE) {
376                $query = sprintf('delete from '.$tables['usermessage'].' where messageid = %d and status = "todo"',
377                    $messagedata['id']);
378            }
379
380            echo '<h3>'.$GLOBALS['I18N']->get('Campaign queued').'</h3>';
381            foreach ($GLOBALS['plugins'] as $pluginname => $plugin) {
382                $plugin->messageQueued($id);
383            }
384            if (getConfig('pqchoice') == 'phplistdotcom') {
385                echo activateRemoteQueue();
386            } elseif (MANUALLY_PROCESS_QUEUE) {
387                echo '<p>'.PageLinkButton('processqueue', $GLOBALS['I18N']->get('processqueue')).'</p>';
388            } else {
389                echo '<p>'.PageLinkButton('messages&tab=active', $GLOBALS['I18N']->get('view progress')).'</p>';
390            }
391        }
392        $done = 1;
393
394        return;
395    } elseif ($send || $sendtest) {
396        $errormessage = '';
397        if ($messagedata['subject'] != stripslashes($messagedata['subject'])) {
398            $errormessage = $GLOBALS['I18N']->get('Sorry, you used invalid characters in the Subject field.');
399        } elseif (!empty($_POST['fromfield']) && $messagedata['fromfield'] != $_POST['fromfield']) {
400            $errormessage = $GLOBALS['I18N']->get('Sorry, you used invalid characters in the From field.');
401        } elseif (empty($messagedata['fromfield'])) {
402            $errormessage = $GLOBALS['I18N']->get('Please enter a from line.');
403        } elseif (empty($messagedata['message'])) {
404            $errormessage = $GLOBALS['I18N']->get('Please enter a message');
405        } elseif (empty($messagedata['subject'])) {
406            $errormessage = $GLOBALS['I18N']->get('Please enter a subject');
407        } elseif (!empty($duplicate_attribute)) {
408            $errormessage = $GLOBALS['I18N']->get('Error: you can use an attribute in one rule only');
409        } elseif ($send && !is_array($_POST['targetlist'])) {
410            $errormessage = $GLOBALS['I18N']->get('Please select the list(s) to send the campaign to');
411        }
412
413        //# this is now handled on the last Tab, so don't display
414//    echo "$errormessage<br/>";
415    }
416
417    // OK, the message has been saved, now check to see if we need to send a test message
418    if ($sendtest) {
419        $sendtestresult = '<br/>';
420        if (empty($_SESSION['lasttestsent'])) {
421            $_SESSION['lasttestsent'] = 0;
422        }
423
424        $sendtestAllowed = true;
425        //# check with plugins that sending a test is allowed
426        reset($GLOBALS['plugins']);
427        while ($sendtestAllowed && $plugin = current($GLOBALS['plugins'])) {
428            $sendtestAllowed = $plugin->sendTestAllowed($messagedata);
429            if (!$sendtestAllowed) {
430                if (VERBOSE) {
431                    cl_output('Sending test blocked by plugin '.$plugin->name);
432                }
433            }
434            next($GLOBALS['plugins']);
435        }
436
437        $delay = time() - $_SESSION['lasttestsent'];
438        if ($delay < SENDTEST_THROTTLE) {
439            foreach ($GLOBALS['plugins'] as $plname => $plugin) {
440                $plugin->processError('Send test throttled on '.$delay);
441            }
442            $sendtestresult .= s('You can send a test mail once every %d seconds', SENDTEST_THROTTLE).'<br/>';
443            $emailaddresses = array();
444        } elseif (!$sendtestAllowed) {
445            $sendtestresult .= s('Sending test mails is currently not available').'<br/>';
446            $emailaddresses = array();
447        } else {
448            // Let's send test messages to everyone that was specified in the
449            if ($messagedata['testtarget'] == '') {
450                $sendtestresult .= $GLOBALS['I18N']->get('No target email addresses listed for testing.').'<br/>';
451            }
452
453            if (isset($cached[$id])) {
454                unset($cached[$id]);
455            }
456            clearPageCache();
457            include 'sendemaillib.php';
458
459            // OK, let's get to sending!
460            $emailaddresses = explode(',', $messagedata['testtarget']);
461            if (count($emailaddresses) > SENDTEST_MAX) {
462                foreach ($GLOBALS['plugins'] as $plname => $plugin) {
463                    $plugin->processError('Send test capped from '.count($emailaddresses).' to '.SENDTEST_MAX);
464                }
465                $limited = array_chunk($emailaddresses, SENDTEST_MAX);
466                $emailaddresses = $limited[0];
467                $sendtestresult .= s('There is a maximum of %d test emails allowed', SENDTEST_MAX).'<br/>';
468            }
469        }
470        //  var_dump($emailaddresses);#exit;
471        $messagedata['testtarget'] = '';
472        foreach ($emailaddresses as $address) {
473            $address = trim($address);
474            if (empty($address)) {
475                continue;
476            }
477            $result = Sql_query(sprintf('select id,email,uniqid,htmlemail,rssfrequency,confirmed from %s where email = "%s"',
478                $tables['user'], sql_escape($address)));
479            //Leftover from the preplugin era
480            if ($user = Sql_fetch_array($result)) {
481                if (FORWARD_ALTERNATIVE_CONTENT && $_GET['tab'] == 'Forward') {
482                    if (SEND_ONE_TESTMAIL) {
483                        $success = sendEmail($id, $address, $user['uniqid'], $user['htmlemail'], array(),
484                            array($address));
485                    } else {
486                        $success = sendEmail($id, $address, $user['uniqid'], 1, array(),
487                                array($address)) && sendEmail($id, $address, $user['uniqid'], 0, array(),
488                                array($address));
489                    }
490                } else {
491                    if (SEND_ONE_TESTMAIL) {
492                        $success = sendEmail($id, $address, $user['uniqid'], $user['htmlemail']);
493                    } else {
494                        $success = sendEmail($id, $address, $user['uniqid'], 1) && sendEmail($id, $address,
495                                $user['uniqid'], 0);
496                    }
497                }
498                $sendtestresult .= $GLOBALS['I18N']->get('Sent test mail to').": $address ";
499                if (!$success) {
500                    $sendtestresult .= $GLOBALS['I18N']->get('failed');
501                } else {
502                    $sendtestresult .= $GLOBALS['I18N']->get('success');
503                    $_SESSION['lasttestsent'] = time();
504                }
505                $sendtestresult .= '<br/>';
506            } else {
507                $address = htmlspecialchars(substr(strip_tags($address), 0, 255));
508
509                $sendtestresult .= $GLOBALS['I18N']->get('Email address not found to send test message.').": $address";
510                $sendtestresult .= sprintf('  <div class="inline"><a href="%s&action=addemail&email=%s%s" class="button ajaxable">%s</a></div>',
511                    $baseurl, urlencode($address), addCsrfGetToken(), $GLOBALS['I18N']->get('add'));
512            }
513            $messagedata['testtarget'] .= $address.', ';
514        }
515        $messagedata['testtarget'] = substr($messagedata['testtarget'], 0, -2);
516        $sendtestresult .= '<hr/>';
517        $sendtestresult .= '<script type="text/javascript">this.location.hash="sendTest";</script>';
518    }
519} elseif (isset($_POST['deleteattachments']) && is_array($_POST['deleteattachments']) && $id) {
520    if (ALLOW_ATTACHMENTS) {
521        // Delete Attachment button hit...
522        $deleteattachments = $_POST['deleteattachments'];
523        foreach ($deleteattachments as $attid) {
524            $attDetails = Sql_fetch_assoc_query(sprintf('select filename from %s where id = %d', $tables['attachment'],
525                $attid));
526            $phys_file = $GLOBALS['attachment_repository'].'/'.$attDetails['filename'];
527            $fileParts = pathinfo($phys_file);
528            $phys_file2 = $GLOBALS['attachment_repository'].'/'.$fileParts['filename']; //# to remove the file created by tempnam
529
530            @unlink($phys_file);
531            @unlink($phys_file2);
532
533            $result = Sql_Query(sprintf('delete from %s where id = %d and messageid = %d',
534                $tables['message_attachment'],
535                $attid,
536                $id));
537            echo Info($GLOBALS['I18N']->get('Removed Attachment '));
538        }
539    }
540}
541
542//#############################
543// Stacked attributes, processing and calculation
544//#############################
545
546//# moved to plugin
547
548//#############################
549// Stacked attributes, end
550//#############################
551
552echo $errormsg;
553if (!$done) {
554
555    //$baseurl = sprintf('./?page=%s&amp;id=%d',$_GET["page"],$id);
556    if ($id) {
557        $tabs = new WebblerTabs();
558        $tabbaseurl = preg_replace('/&tab=[^&]+/', '', $baseurl);
559        $tabs->addTab(s('Content'), $tabbaseurl.'&amp;tab=Content');
560        $counttabs = 1;
561        if (USE_MANUAL_TEXT_PART) {
562            $tabs->addTab(s('Text'), $tabbaseurl.'&amp;tab=Text');
563            ++$counttabs;
564        }
565        if (FORWARD_ALTERNATIVE_CONTENT) {
566            $tabs->addTab(s('Forward'), $tabbaseurl.'&amp;tab=Forward');
567            ++$counttabs;
568        }
569        $tabs->addTab(s('Format'), $tabbaseurl.'&amp;tab=Format');
570        ++$counttabs;
571        if (ALLOW_ATTACHMENTS) {
572            $tabs->addTab(s('Attach'), $tabbaseurl.'&amp;tab=Attach');
573            ++$counttabs;
574        }
575        $tabs->addTab(s('Scheduling'), $tabbaseurl.'&amp;tab=Scheduling');
576        ++$counttabs;
577        $tabs->addTab(s('Lists'), $tabbaseurl.'&amp;tab=Lists');
578        ++$counttabs;
579
580        if ($_GET['tab']) {
581            $tabs->setCurrent(s($_GET['tab']));
582        } else {
583            $tabs->setCurrent(s('Content'));
584        }
585        $tabs->addLinkCode(' class="savechanges" ');
586
587        //## allow plugins to add tabs
588        $plugintabs = array();
589        foreach ($GLOBALS['plugins'] as $pluginname => $plugin) {
590            //   print $plugin->name;
591            $plugintab = $plugin->sendMessageTab($id, $messagedata);
592            if ($plugintab) {
593                $plugintabname = substr(strip_tags($plugin->sendMessageTabTitle()), 0, 10);
594                $plugintabs[$plugintabname] = $plugintab;
595                $tabs->addTab($GLOBALS['I18N']->get($plugintabname),
596                    "$tabbaseurl&amp;tab=".urlencode($plugintabname));
597                if ($insertBefore = $plugin->sendMessageTabInsertBefore()) {
598                    $tabs->insertTabBefore(s($insertBefore), s($plugintabname));
599                }
600                ++$counttabs;
601            }
602        }
603
604        //# this one always last
605        $tabs->addTab(s('Finish'), $tabbaseurl.'&amp;tab=Finish');
606        ++$counttabs;
607
608        // print $tabs->display();
609    } ?>
610
611    <script language="Javascript" type="text/javascript">
612        // some debugging stuff to see what happens
613        function checkForm() {
614            //  return true;
615            for (var i = 0; i < document.sendmessageform.elements.length; i++) {
616                alert(document.sendmessageform.elements[i].name + " " + document.sendmessageform.elements[i].value);
617            }
618            return true;
619        }
620
621        // detection of unsaved changes,
622        var browser = navigator.appName.substring(0, 9);
623        var changed = 1;
624        function haschanged() {
625            changed = 1;
626        }
627        function savechanges() {
628        }
629        var event_number = 0;
630        if (browser == "Microsoft") {
631            document.onkeydown = haschanged;
632            document.onchange = haschanged;
633        } else if (browser == "Netscape") {
634            document.captureEvents(Event.KEYDOWN);
635            document.captureEvents(Event.CHANGE);
636            document.onkeydown = haschanged;
637            document.onchange = haschanged;
638        }
639        function submitform() {
640            document.sendmessageform.submit()
641        }
642    </script>
643    <?php
644    //print '<form method="post" enctype="multipart/form-data" name="sendmessageform" onSubmit="return checkForm()">';
645    echo '<input type="hidden" name="workaround_fck_bug" value="1" />';
646    echo '<input type="hidden" name="followupto" value="" />';
647
648    if ($_GET['page'] == 'preparemessage') {
649        echo Help('preparemessage', $GLOBALS['I18N']->get('What is prepare a message'));
650    }
651
652    if (!defined('IN_WEBBLER')) {
653        if (empty($messagedata['fromfield'])) {
654            $defaultFrom = getConfig('campaignfrom_default');
655            if (empty($defaultFrom)) {
656                $defaultFrom = getConfig('message_from_name').' '.getConfig('message_from_address');
657            }
658            $messagedata['fromfield'] = $defaultFrom;
659
660            if (!isSuperUser() && USE_ADMIN_DETAILS_FOR_MESSAGES && is_object($GLOBALS['admin_auth'])) {
661                $adminemail = $GLOBALS['admin_auth']->adminEmail($_SESSION['logindetails']['id']);
662                if (!empty($adminemail)) {
663                    $messagedata['fromfield'] = $GLOBALS['admin_auth']->adminName($_SESSION['logindetails']['id']).' '.$adminemail;
664                }
665            }
666        }
667    }
668
669    $formatting_content = '<div id="formatcontent">';
670
671    //0013076: different content when forwarding 'to a friend'
672    //  value="'.htmlentities($subject,ENT_QUOTES,'UTF-8').'" size="40"></td></tr> --> previous code in line 1032
673    //  value="'.htmlentities($from,ENT_QUOTES,'UTF-8').'" size="40"></td></tr> --> previous code in line 1038
674
675    $tmp = '<div id="maincontent">';
676    $maincontent = $tmp;
677    $forwardcontent = $tmp;
678
679// custom code - start
680    $utf8_subject = $messagedata['subject'];
681    $utf8_from = $messagedata['fromfield'];
682    if (empty($utf8_subject)) {
683        $utf8_subject = '(no subject)';
684    }
685    if (empty($messagedata['campaigntitle'])) {
686        $messagedata['campaigntitle'] = $utf8_subject;
687    }
688    /*
689      if (0 && strcasecmp($GLOBALS['strCharSet'], 'utf-8') <> 0) {
690         $utf8_subject = iconv($GLOBALS['strCharSet'],'UTF-8',$utf8_subject);
691         $utf8_from = iconv($GLOBALS['strCharSet'],'UTF-8',$utf8_from);
692      }
693    */
694
695    $maincontent .= '
696  <div class="field">
697    <label for="subject">' .s('Campaign subject').Help('subject').'</label>'.
698    '<input type="text" name="subject"  id="subjectinput" value="' .htmlentities($utf8_subject, ENT_QUOTES, 'UTF-8').'" size="60" />
699  </div>
700
701  <div class="field"><label for="fromfield">' .$GLOBALS['I18N']->get('From Line').Help('from').'</label>'.'
702    <input type="text" name="fromfield"
703   value="' .htmlentities($utf8_from, ENT_QUOTES, 'UTF-8').'" size="60" /></div>';
704
705    if (USE_REPLY_TO) {
706        $maincontent .= '
707  <div class="field"><label for="replyto">' .$GLOBALS['I18N']->get('Reply to').Help('from').'</label>'.'
708    <input type="text" name="replyto"
709   value="' .htmlspecialchars($messagedata['replyto']).'" size="60" /></div>';
710    }
711    if (USE_MESSAGE_PREVIEW) {
712    $maincontent .= '
713        <div class="field" id="message-text-preview">
714        <label for="messagepreview">' .s('Message preview').Help('generatetextpreview').'</label>
715        <input type="text" id="messagepreview" name="messagepreview" size="60" readonly />
716        <div id="message-text-preview-button">' .
717            PageLinkAjax('send&tab=Content&id='.$id.'&action=generatetextpreview', $GLOBALS['I18N']->get('Generate')).'
718        </div>
719        </div>';
720    }
721
722    $maincontent .= sprintf('
723
724      <div id="contentchoice" class="field">
725      <label for="sendmethod">' .$GLOBALS['I18N']->get('Content').Help('sendmethod').'</label>'.'
726      <input type="radio" name="sendmethod" value="remoteurl" %s />' .$GLOBALS['I18N']->get('Send a Webpage').'
727      <input type="radio" name="sendmethod" value="inputhere" %s />' .$GLOBALS['I18N']->get('Compose Message').'
728      </div>',
729        $messagedata['sendmethod'] == 'remoteurl' ? 'checked="checked"' : '',
730        $messagedata['sendmethod'] == 'inputhere' ? 'checked="checked"' : ''
731        );
732
733    if (empty($messagedata['sendurl'])) {
734        $messagedata['sendurl'] = 'e.g. https://www.phplist.com/testcampaign.html';
735    }
736
737    $maincontent .= '
738      <div id="remoteurl" class="field"><label for="sendurl">' .$GLOBALS['I18N']->get('Send a Webpage - URL').Help('sendurl').'</label>'.'
739        <input type="text" name="sendurl" id="remoteurlinput"
740       value="' .htmlspecialchars($messagedata['sendurl']).'" size="60" /> <span id="remoteurlstatus"></span></div>';
741    if (isset($messagedata['sendmethod']) && $messagedata['sendmethod'] != 'remoteurl') {
742        $GLOBALS['pagefooter']['hideremoteurl'] = '<script type="text/javascript">$("#remoteurl").hide();</script>';
743    }
744
745// custom code - end
746    //0013076: different content when forwarding 'to a friend'
747    $forwardcontent .=
748        '<div class="field"><label for="forwardsubject">'.$GLOBALS['I18N']->get('Subject').Help('forwardsubject').'</label>'.'
749    <input type="text" name="forwardsubject" value="' .htmlentities($messagedata['forwardsubject'], ENT_QUOTES,
750            'UTF-8').'" size="40" /></div>';
751
752    $currentTime = Sql_Fetch_Row_Query('select now()');
753
754    $scheduling_content = '<div id="schedulecontent">';
755    if (defined('SYSTEM_TIMEZONE')) {
756        $scheduling_content .= '
757    <div class="field">' .s('phpList operates in the time zone "%s"', SYSTEM_TIMEZONE).'</div>';
758    } else {
759        $scheduling_content .= '
760    <div class="field">' . s('Dates and times are relative to the Server Time') . '<br/>' . s('Current Server Time is') . ' <span id="servertime">' .
761date('H:i, l j F Y', strtotime($currentTime[0])) . '</span>' . '</div>';
762    }
763
764    $scheduling_content .= '  <div class="field"><label for="embargo">'.$GLOBALS['I18N']->get('Embargoed Until').Help('embargo').'</label>'.'
765    ' .$embargo->showInput('embargo', '', $messagedata['embargo']).'</div>
766  <div class="field"><label for="finishsending">' .$GLOBALS['I18N']->get('Stop sending after').Help('finishsending').'</label>'.'
767    ' .$embargo->showInput('finishsending', '', $messagedata['finishsending']).'</div>';
768
769    if (USE_REPETITION) {
770        $repeatinterval = $messagedata['repeatinterval'];
771
772        $scheduling_content .= '
773    <div class="field"><label for="repeatinterval">' .$GLOBALS['I18N']->get('Repeat campaign every').Help('repetition').'</label>'.'
774        <select name="repeatinterval">
775      <option value="0"';
776        if ($repeatinterval == 0) {
777            $scheduling_content .= ' selected="selected"';
778        }
779        $scheduling_content .= '>-- '.$GLOBALS['I18N']->get('no repetition').'</option>
780      <option value="60"';
781        if ($repeatinterval == 60) {
782            $scheduling_content .= ' selected="selected"';
783        }
784        $scheduling_content .= '>'.$GLOBALS['I18N']->get('hour').'</option>
785      <option value="1440"';
786        if ($repeatinterval == 1440) {
787            $scheduling_content .= ' selected="selected"';
788        }
789        $scheduling_content .= '>'.$GLOBALS['I18N']->get('day').'</option>
790      <option value="10080"';
791        if ($repeatinterval == 10080) {
792            $scheduling_content .= ' selected="selected"';
793        }
794        $scheduling_content .= '>'.$GLOBALS['I18N']->get('week').'</option>
795      <option value="20160"';
796        if ($repeatinterval == 20160) {
797            $scheduling_content .= ' selected="selected"';
798        }
799        $scheduling_content .= '>'.$GLOBALS['I18N']->get('fortnight').'</option>
800      <option value="40320"';
801        //# @@@TODO adding "month" is a bit trickier, as we use minutes for value, and months have varying numbers of seconds
802        if ($repeatinterval == 40320) {
803            $scheduling_content .= ' selected="selected"';
804        }
805        $scheduling_content .= '>'.$GLOBALS['I18N']->get('four weeks').'</option>
806      </select>
807        <label for="repeatuntil">' .$GLOBALS['I18N']->get('Repeat Until').'</label>
808        ' .$repeatuntil->showInput('repeatuntil', '', $messagedata['repeatuntil']);
809        $scheduling_content .= '</div>';
810    }
811
812    $requeueinterval = $messagedata['requeueinterval'];
813    $scheduling_content .= '
814  <div class="field"><label for="requeueinterval"> ' .$GLOBALS['I18N']->get('Requeue every').Help('requeueing').'</label>'.'
815    <select name="requeueinterval">
816    <option value="0"';
817    if ($requeueinterval == 0) {
818        $scheduling_content .= ' selected="selected"';
819    }
820    $scheduling_content .= '>-- '.$GLOBALS['I18N']->get('do not requeue').'</option>
821    <option value="60"';
822    if ($requeueinterval == 60) {
823        $scheduling_content .= ' selected="selected"';
824    }
825    $scheduling_content .= '>'.$GLOBALS['I18N']->get('hour').'</option>
826    <option value="1440"';
827    if ($requeueinterval == 1440) {
828        $scheduling_content .= ' selected="selected"';
829    }
830    $scheduling_content .= '>'.$GLOBALS['I18N']->get('day').'</option>
831    <option value="10080"';
832    if ($requeueinterval == 10080) {
833        $scheduling_content .= ' selected="selected"';
834    }
835    $scheduling_content .= '>'.$GLOBALS['I18N']->get('week').'</option>
836    </select>
837
838      <label for="requeueuntil">' .$GLOBALS['I18N']->get('Requeue Until').'</label>
839      ' .$requeueuntil->showInput('requeueuntil', '', $messagedata['requeueuntil']);
840    $scheduling_content .= '</div>';
841
842    $scheduling_content .= '</div>';
843
844    $formatting_content .= '<input type="hidden" name="htmlformatted" value="auto" />';
845
846    $formatting_content .= '
847    <div class="field">
848    <label for="sendformat"> ' .$GLOBALS['I18N']->get('Send as').Help('sendformat').'</label>'.'
849  ' .$GLOBALS['I18N']->get('html').' <input type="radio" name="sendformat" value="HTML" ';
850    $formatting_content .= $messagedata['sendformat'] == 'HTML' ? 'checked="checked"' : '';
851    $formatting_content .= '/>
852  ' .$GLOBALS['I18N']->get('text').' <input type="radio" name="sendformat" value="text" ';
853    $formatting_content .= $messagedata['sendformat'] == 'text' ? 'checked="checked"' : '';
854    $formatting_content .= '/>
855  ';
856
857//  0009687: Confusing use of the word "Both", indicating one email with both text and html and not two emails
858//  $formatting_content .= $GLOBALS['I18N']->get("text and html").' <input type="radio" name="sendformat" value="text and HTML" ';
859//  $formatting_content .= $_POST["sendformat"]=="text and HTML" || !isset($_POST["sendformat"]) ?"checked":"";
860//  $formatting_content .= '/>';
861
862    foreach ($GLOBALS['plugins'] as $pluginname => $plugin) {
863        $plugins_sendformats = $plugin->sendFormats();
864        if (is_array($plugins_sendformats) && count($plugins_sendformats)) {
865            foreach ($plugins_sendformats as $val => $desc) {
866                $val = preg_replace("/\W/", '', strtolower(trim($val)));
867                if ($val[0] != '_') { //# allow a plugin to add a format that is not actually displayed
868                    $formatting_content .= sprintf('%s <input type="radio" name="sendformat" value="%s" %s />',
869                        $desc, $val, $messagedata['sendformat'] == $val ? 'checked="checked"' : '');
870                }
871            }
872        }
873    }
874    $formatting_content .= '</div>';
875
876    $req = Sql_Query("select id,title from {$tables['template']} order by listorder");
877    if (Sql_affected_Rows()) {
878        $formatting_content .= '<div class="field"><label for="template">'.$GLOBALS['I18N']->get('Use Template').Help('usetemplate').'</label>'.'
879      <select name="template"><option value="0" hidden>' .s('--Select one--').'</option>
880      <option value="0">-- ' .s('No template').'</option>';
881        $req = Sql_Query("select id,title from {$tables['template']} order by listorder");
882        while ($row = Sql_Fetch_Array($req)) {
883            if ($row['title']) {
884                $formatting_content .= sprintf('<option value="%d" %s>%s</option>', $row['id'],
885                    $row['id'] == $messagedata['template'] ? 'selected="selected"' : '', $row['title']);
886            }
887        }
888        $formatting_content .= '</select></div>';
889    }
890    $formatting_content .= '</div>';
891
892    //0013076: different content when forwarding 'to a friend'
893    $maincontent .= '<div id="messagecontent" class="field"><label for="message">'.s('Compose Message').Help('message').'</label> ';
894    $forwardcontent .= '<div id="messagecontent" class="field"><label for="forwardmessage">'.s('Compose Message').Help('forwardmessage').'</label> ';
895
896    if (!empty($GLOBALS['editorplugin'])) {
897        $maincontent .= '<div>'.$GLOBALS['plugins'][$GLOBALS['editorplugin']]->editor('message',
898                $messagedata['message']).'</div>';
899    } else {
900        $maincontent .= '
901      <div><textarea name="message" cols="65" rows="20">' .htmlspecialchars($messagedata['message']).'</textarea></div>';
902    }
903
904    //0013076: different content when forwarding 'to a friend'
905    $forwardcontent .= '<div><textarea name="forwardmessage" cols="65" rows="20">'.htmlspecialchars($messagedata['forwardmessage']).'</textarea></div>';
906
907    //0013076: different content when forwarding 'to a friend'
908    $tmp = '
909
910  </div></div> <!-- end of message content -->
911  ';
912
913    if (isset($messagedata['sendmethod']) && $messagedata['sendmethod'] != 'inputhere') {
914        $GLOBALS['pagefooter']['hidemessagecontent'] = '<script type="text/javascript">$("#messagecontent").hide()</script>';
915    }
916    $maincontent .= $tmp;
917    $forwardcontent .= $tmp;
918
919    if (USE_MANUAL_TEXT_PART) {
920        $textcontent = '<div class="field">
921    <label for="textmessage">' .$GLOBALS['I18N']->get('Plain text version of message').Help('plaintextversion').'</label>'.'
922    <div id="generatetextversion">' .PageLinkAjax('send&tab=Text&id='.$id.'&action=generatetext',
923                $GLOBALS['I18N']->get('generate from HTML')).'</a> '.Help('generatetext').'</div>
924    <textarea id="textmessage" name="textmessage" cols="65" rows="20">' .htmlentities($messagedata['textmessage']).'</textarea>
925  </div>';
926    }
927//var_dump($messagedata);
928    //0013076: different content when forwarding 'to a friend'
929    $maincontent .= '<div class="field"><label for="footer">'.$GLOBALS['I18N']->get('Footer').Help('footer').'.</label>'.'
930   <textarea name="footer" cols="65" rows="5">' .htmlspecialchars($messagedata['footer']).'</textarea></div>';
931    $forwardcontent .= '<div class="field"><label for="forwardfooter">'.$GLOBALS['I18N']->get('forwardfooter').Help('forwardfooter').'</label>'.'
932    <textarea name="forwardfooter" cols="65" rows="5">' .htmlspecialchars($messagedata['forwardfooter']).'</textarea></div>';
933
934    if (ALLOW_ATTACHMENTS) {
935        // If we have a message id saved, we want to query the attachments that are associated with this
936        // message and display that (and allow deletion of!)
937
938        $att_content = '<div class="field"><label for="attach">'.$GLOBALS['I18N']->get('Add attachments to your campaign').Help('attachments').'</label>';
939        $att_content .= '<div class="info">
940      ' .$GLOBALS['I18N']->get('The upload has the following limits set by the server').':<br/>
941      ' .$GLOBALS['I18N']->get('Maximum size of total data being sent to the server').': '.ini_get('post_max_size').'<br/>
942      ' .$GLOBALS['I18N']->get('Maximum size of each individual file').': '.ini_get('upload_max_filesize').'</div>';
943
944        if ($id) {
945            $result = Sql_Query(sprintf('Select Att.id, Att.filename, Att.remotefile, Att.mimetype, Att.description, Att.size, MsgAtt.id linkid'.
946                ' from %s Att, %s MsgAtt where Att.id = MsgAtt.attachmentid and MsgAtt.messageid = %d',
947                $tables['attachment'],
948                $tables['message_attachment'],
949                $id));
950
951            $ls = new WebblerListing($GLOBALS['I18N']->get('Current Attachments'));
952            $totalSize = 0;
953            while ($row = Sql_fetch_array($result)) {
954                $ls->addElement($row['id']);
955                $ls->addColumn($row['id'], $GLOBALS['I18N']->get('filename'), $row['remotefile']);
956                $ls->addColumn($row['id'], $GLOBALS['I18N']->get('desc'), $row['description']);
957                $ls->addColumn($row['id'], $GLOBALS['I18N']->get('size'), formatBytes($row['size']));
958                $totalSize += $row['size'];
959                $phys_file = $GLOBALS['attachment_repository'].'/'.$row['filename'];
960                if (is_file($phys_file) && filesize($phys_file)) {
961                    $ls->addColumn($row['id'], $GLOBALS['I18N']->get('file'), $GLOBALS['img_tick']);
962                } else {
963                    $ls->addColumn($row['id'], $GLOBALS['I18N']->get('file'), $GLOBALS['img_cross']);
964                }
965                $ls->addColumn($row['id'], $GLOBALS['I18N']->get('del'),
966                    sprintf('<input type="checkbox" name="deleteattachments[]" value="%s"/>', $row['linkid']));
967            }
968            $ls->addButton(s('Delete checked'), 'javascript:document.sendmessageform.submit()');
969            $att_content .= '<div>'.$ls->display().'</div>';
970        }
971        if (defined('MAX_MAILSIZE') && 3 * $totalSize > MAX_MAILSIZE) {  //# the 3 is roughly the size increase to encode the string
972            $att_content .= Warn(s('The total size of attachments is very large. Sending this campaign may fail due to resource limits.'));
973        }
974
975        for ($att_cnt = 1; $att_cnt <= NUMATTACHMENTS; ++$att_cnt) {
976            $att_content .= sprintf('<div>%s</div><div><input type="file" name="attachment%d"/>&nbsp;&nbsp;<input class="submit" type="submit" name="save" value="%s"/></div>',
977                $GLOBALS['I18N']->get('New Attachment'), $att_cnt, $GLOBALS['I18N']->get('Add (and save)'));
978            if (FILESYSTEM_ATTACHMENTS) {
979                $att_content .= sprintf('<div><b>%s</b> %s:</div><div><input type="text" name="localattachment%d" size="50"/></div>',
980                    $GLOBALS['I18N']->get('or'), $GLOBALS['I18N']->get('Path to file on server'), $att_cnt, $att_cnt);
981            }
982            $att_content .= sprintf('<div>%s:</div>
983        <div><textarea name="attachment%d_description" cols="65" rows="3" wrap="virtual"></textarea></div>',
984                $GLOBALS['I18N']->get('Description of attachment'), $att_cnt);
985        }
986        $att_content .= '</div>';
987        // $shader = new WebblerShader("Attachments");
988        // $shader->addContent($att_content);
989        // $shader->initialstate = 'closed';
990        // print $shader->display();
991    }
992
993    // Load the email address for the admin user so we can use that as the default value in the testtarget field
994    // @@@ this only works with phplist authentication, needs to be abstracted
995    if (!isset($messagedata['testtarget'])) {
996        $res = Sql_Query(sprintf('Select email from %s where id = %d', $tables['admin'],
997            $_SESSION['logindetails']['id']));
998        $admin_details = Sql_Fetch_Array($res);
999
1000        $messagedata['testtarget'] = $admin_details['email'];
1001    }
1002    // if there isn't one, load the developer one, just being lazy here :-)
1003    if (empty($messagedata['testtarget']) && isset($GLOBALS['developer_email'])) {
1004        $messagedata['testtarget'] = $GLOBALS['developer_email'];
1005    }
1006
1007    // Display the HTML for the "Send Test" button, and the input field for the email addresses
1008    $sendtest_content = '<div class="sendTest" id="sendTest">
1009    ' .$sendtestresult.Help('sendtest').' <b>'.s('to email address(es)').':</b><br />'.
1010        '<p><i>&nbsp; '.s('(comma separate addresses - all must be existing subscribers)').'</i></p>'.
1011        '<div class="input-group">
1012            <input type="text" name="testtarget" size="40" value="'.htmlspecialchars($messagedata['testtarget']).'" class="form-control blockenterkey" />
1013            <span class="input-group-btn">
1014                <input class="submit btn btn-primary" type="submit" name="sendtest" value="' .s('Send Test').'" />
1015             </span>
1016        </div>
1017    </div>';
1018
1019    // notification of progress of message sending
1020    // defaulting to admin_details['email'] gives the wrong impression that this is the
1021    // value in the database, so it is better to leave that empty instead
1022    $notify_start = isset($messagedata['notify_start']) && is_email($messagedata['notify_start']) ? $messagedata['notify_start'] : ''; //$admin_details['email'];
1023    $notify_end = isset($messagedata['notify_end']) && is_email($messagedata['notify_end']) ? $messagedata['notify_end'] : ''; //$admin_details['email'];
1024
1025    $send_content = sprintf('
1026    <div class="sendNotify">
1027    <label for="notify_start">%s<br/>%s</label><div><input type="text" name="notify_start" id="notify_start" value="%s" size="35"/></div>
1028    <label for="notify_end">%s<br/>%s</label><div><input type="text" name="notify_end" id="notify_end" value="%s" size="35"/></div>
1029    </div>',
1030        $GLOBALS['I18N']->get('email to alert when sending of this message starts'),
1031        $GLOBALS['I18N']->get('separate multiple with a comma'), $notify_start,
1032        $GLOBALS['I18N']->get('email to alert when sending of this message has finished'),
1033        $GLOBALS['I18N']->get('separate multiple with a comma'), $notify_end);
1034
1035    $send_content .= sprintf('
1036    <div class="campaignTracking">
1037    <label for="cb[google_track]">%s</label><input type="hidden" name="cb[google_track]" value="1" /><input type="checkbox" name="google_track" id="google_track" value="1" %s />
1038    </div>',
1039        Help('googletrack').' '.s('Add analytics tracking code'),
1040        !empty($messagedata['google_track']) ? 'checked="checked"' : '');
1041
1042    /* add analytics query parameters then hide if not currently enabled */
1043    $analytics = getAnalyticsQuery();
1044    $editableParameters = $analytics->editableParameters($messagedata);
1045
1046    if (count($editableParameters) > 0) {
1047        $send_content .= '<div id="analytics">';
1048
1049        foreach ($editableParameters as $field => $default) {
1050            $value =  isset($messagedata[$field]) ? $messagedata[$field] : $default;
1051            $send_content .= sprintf(
1052                '<label>%s <input type="text" name="%s" id="%s" value="%s" size="35"/></label>',
1053                $field,
1054                $field,
1055                $field,
1056                $value
1057            ) . "\n";
1058        }
1059        $send_content .= '</div>';
1060
1061        if (empty($messagedata['google_track'])) {
1062            $GLOBALS['pagefooter']['hideanalytics'] = '<script type="text/javascript">$("#analytics").hide()</script>';
1063        }
1064    }
1065    $numsent = Sql_Fetch_Row_Query(sprintf('select count(*) from %s where messageid = %d',
1066        $GLOBALS['tables']['usermessage'], $messagedata['id']));
1067    if ($numsent[0] < RESETSTATS_MAX) {
1068        $send_content .= sprintf('
1069        <div class="resetStatistics">
1070        <label for="cb[resetstats]">%s</label><input type="hidden" name="cb[resetstats]" value="1" /><input type="checkbox" name="resetstats" id="resetstats" value="1" %s />
1071        </div>',
1072            Help('resetstats').' '.s('Reset click statistics'),
1073            !empty($messagedata['resetstats']) ? 'checked="checked"' : '');
1074    } else {
1075        $send_content .= '<input type="hidden" name="resetstats" value="0" />';
1076    }
1077
1078    $send_content .= sprintf('
1079    <div class="isTestCampaign">
1080    <label for="cb[istestcampaign]">%s</label><input type="hidden" name="cb[istestcampaign]" value="1" /><input type="checkbox" name="istestcampaign" id="istestcampaign" value="1" %s />
1081    </div>',
1082        Help('istestcampaign').' '.s('This is a test campaign'),
1083        !empty($messagedata['istestcampaign']) ? 'checked="checked"' : '');
1084
1085    $show_lists = 0;
1086
1087    $send_content .= '<div class="sizeEstimate">';
1088    if (!empty($messagedata['htmlsize'])) {
1089        $send_content .= $GLOBALS['I18N']->get('Estimated size of HTML email').': '.formatBytes($messagedata['htmlsize']).'<br/>';
1090    }
1091    if (!empty($messagedata['textsize'])) {
1092        $send_content .= $GLOBALS['I18N']->get('Estimated size of text email').': '.formatBytes($messagedata['textsize']).'<br/>';
1093    }
1094    /*
1095      var_dump($messagedata['targetlist']);
1096    */
1097
1098    if (!empty($messagedata['textsize']) || !empty($messagedata['htmlsize'])) {
1099        if (is_array($messagedata['targetlist']) && count($messagedata['targetlist'])) {
1100            $lists = $messagedata['targetlist'];
1101            if (isset($messagedata['excludelist'])) {
1102                $excludelists = $messagedata['excludelist'];
1103            } else {
1104                $excludelists = array();
1105            }
1106
1107            if (!empty($lists['all']) || !empty($lists['allactive'])) {
1108                $allactive = isset($lists['allactive']);
1109                $all = isset($lists['all']);
1110                $req = Sql_Query(sprintf('select id,active from %s %s', $GLOBALS['tables']['list'], $subselect));
1111                $lists = array();
1112                while ($row = Sql_Fetch_Row($req)) {
1113                    if (($allactive && $row[1]) || $all) {
1114                        $lists[$row[0]] = $row[0];
1115                    }
1116                }
1117            }
1118            unset($lists['all']);
1119            unset($lists['allactive']);
1120            if (isset($messagedata['excludelist']) && is_array($messagedata['excludelist']) && count($messagedata['excludelist'])) {
1121                $exclude = sprintf(' and listuser.listid not in (%s)', implode(',', $messagedata['excludelist']));
1122            } else {
1123                $exclude = '';
1124            }
1125
1126            $htmlcnt = Sql_Fetch_Row_Query(sprintf('select count(distinct userid) from %s listuser,%s user where user.htmlemail and user.id = listuser.userid and listuser.listid in (%s) %s',
1127                $GLOBALS['tables']['listuser'], $GLOBALS['tables']['user'], implode(',', array_keys($lists)), $exclude),
1128                1);
1129            $textcnt = Sql_Fetch_Row_Query(sprintf('select count(distinct userid) from %s listuser,%s user where !user.htmlemail and user.id = listuser.userid and listuser.listid in (%s) %s',
1130                $GLOBALS['tables']['listuser'], $GLOBALS['tables']['user'], implode(',', array_keys($lists)), $exclude),
1131                1);
1132            if ($htmlcnt[0] || $textcnt[0]) {
1133                if (!isset($messagedata['textsize'])) {
1134                    $messagedata['textsize'] = 0;
1135                }
1136                if (!isset($messagedata['htmlsize'])) {
1137                    $messagedata['htmlsize'] = 0;
1138                }
1139
1140                $send_content .= $GLOBALS['I18N']->get('Estimated size of mailout').': '.formatBytes($htmlcnt[0] * $messagedata['htmlsize'] + $textcnt[0] * $messagedata['textsize']).'<br/>';
1141                //# remember this to see how well the estimate was
1142                Sql_Query(sprintf('replace into %s set name = "estimatedsize",id=%d,data = "%s"',
1143                    $GLOBALS['tables']['messagedata'], $id,
1144                    $htmlcnt[0] * $messagedata['htmlsize'] + $textcnt[0] * $messagedata['textsize']));
1145                $send_content .= sprintf($GLOBALS['I18N']->get('About %d users to receive HTML and %s users to receive text version of email'),
1146                        $htmlcnt[0], $textcnt[0]).'<br/>';
1147                Sql_Query(sprintf('replace into %s set name = "estimatedhtmlusers",id=%d,data = "%s"',
1148                    $GLOBALS['tables']['messagedata'], $id, $htmlcnt[0]));
1149                Sql_Query(sprintf('replace into %s set name = "estimatedtextusers",id=%d,data = "%s"',
1150                    $GLOBALS['tables']['messagedata'], $id, $textcnt[0]));
1151            }
1152        }
1153    }
1154    $send_content .= '</div>';
1155
1156    //# the button to actually send the campagin
1157    $send_content .= $placeinqueue;
1158
1159    echo '<div class="sendtabs_container">';
1160
1161    $tabs->setListClass('sendcampaign');
1162    $tabs->setId('sendtabs');
1163//  $tabs->addPrevNext();
1164    $tabs->addTabNo();
1165    echo $tabs->display();
1166    //print '<div id="tabcontent"></div>';
1167
1168    $panelcontent = '';
1169    switch ($_GET['tab']) {
1170        case 'Attach':
1171            $panelcontent = $att_content;
1172            break;
1173        //   case "Criteria": print $criteria_content; break; // moved to plugin
1174        case 'Text':
1175            $panelcontent = $textcontent;
1176            break;
1177        case 'Format':
1178            $panelcontent = $formatting_content;
1179            break;
1180        case 'Scheduling':
1181            $panelcontent = $scheduling_content;
1182            break;
1183//    case "RSS": print $rss_content;break;            //Obsolete by rssmanager plugin
1184        case 'Lists':
1185            $show_lists = 1;
1186            break;
1187        case 'Review':
1188            $panelcontent = $review_content;
1189            break;
1190        case 'Finish':
1191            $panelcontent = $send_content;
1192            break;
1193        case 'Forward':
1194            $panelcontent = $forwardcontent;
1195            break;
1196        default:
1197            $isplugin = 0;
1198            foreach ($plugintabs as $tabname => $tabcontent) {
1199                if ($_GET['tab'] == $tabname) {
1200                    $panelcontent = $tabcontent;
1201                    $isplugin = 1;
1202                }
1203            }
1204            if (!$isplugin) {
1205                $panelcontent = $maincontent;
1206            }
1207            break;
1208    }
1209}
1210
1211$GLOBALS['pagefooter']['sendtabs'] = "<script language='Javascript' type='text/javascript' src='js/jquery.cycle2.min.js'></script>
1212<script>
1213    $(document).ready(function(){
1214        var counttab = ".$counttabs.";
1215        var currenttab = $('.current').attr('id');
1216        var tabvis = (($('.sendtabs_container').width()-50)/102)+'';
1217        var arrvis = tabvis.split('.');
1218        var tabdif = currenttab-arrvis[0];
1219        if (counttab <= arrvis[0]) {arrvis[0] = counttab};
1220        $('.sendcampaign').cycle({ slides:'> li', timeout:0, fx:'carousel', allowWrap:false, carouselVisible:arrvis[0], next:'.nexttab', prev:'.prevtab' });
1221        $('.sendcampaign').cycle('goto',tabdif);
1222
1223        $(window).on('resize',function() {
1224            $('.sendcampaign').cycle('destroy');
1225            tabvis = (($('.sendtabs_container').width()-50)/102)+'';
1226            arrvis = tabvis.split('.');
1227            tabdif = currenttab-arrvis[0];
1228            if (counttab <= arrvis[0]) {arrvis[0] = counttab};
1229            $('.sendcampaign').cycle({ slides:'> li', timeout:0, fx:'carousel', allowWrap:false, carouselVisible:arrvis[0], next:'.nexttab', prev:'.prevtab' });
1230            $('.sendcampaign').cycle('goto',tabdif);
1231        });
1232    });
1233</script><style>#sendtabs ul{margin:0 1px}</style>";
1234
1235/* OLD SCRIPT:
1236
1237    "<script type='text/javascript'>\n".
1238    '$(document).ready(function() {
1239    var counttab = ' .$counttabs.";
1240    var currenttab = $('.current').attr('id');
1241    if(matchMedia('only screen and (max-width: 480px)').matches){ tabs=2; starttab=currenttab-2;  }
1242    else if(matchMedia('only screen and (max-width: 767px)').matches){ tabs=3; starttab=currenttab-3;}
1243    else if(matchMedia('only screen and (max-width: 967px)').matches){ tabs=4; starttab=currenttab-4;}
1244    else{ tabs=6; starttab=currenttab-6; if ( counttab < 7 ){ $('.nexttab').addClass('disabled'); } }
1245    if ( starttab < 1 ){ starttab=0; $('.prevtab').addClass('disabled'); }
1246    if ( currenttab>=counttab ){ $('.nexttab').addClass('disabled'); }
1247
1248    $('#sendtabs').jCarouselLite({
1249        btnNext: '.nexttab',
1250        btnPrev: '.prevtab',
1251        circular: false,
1252        visible: tabs,
1253        auto: null,
1254        speed:100,
1255        scroll:1,
1256        start: starttab
1257    });
1258});
1259$(window).resize(function(){
1260    var counttab = " .$counttabs.";
1261    var currenttab = $('.current').attr('id');
1262    if(matchMedia('only screen and (max-width: 480px)').matches){ tabs=2; $('.nexttab').removeClass('disabled'); starttab=currenttab-2;}
1263    else if(matchMedia('only screen and (max-width: 767px)').matches){ tabs=3; $('.nexttab').removeClass('disabled'); starttab=currenttab-3;}
1264    else if(matchMedia('only screen and (max-width: 967px)').matches){ tabs=4; $('.nexttab').removeClass('disabled'); starttab=currenttab-4;}
1265    else{ tabs=6; starttab=currenttab-6; if ( counttab < 7){ $('.nexttab').addClass('disabled'); } }
1266    if ( starttab < 1 ){ starttab=0; $('.prevtab').addClass('disabled'); }
1267    if ( currenttab>=counttab ){ $('.nexttab').addClass('disabled'); }
1268    $('#sendtabs').jCarouselLite({
1269        btnNext: '.nexttab',
1270        btnPrev: '.prevtab',
1271        circular: false,
1272        visible: tabs,
1273        auto: null,
1274        speed:100,
1275        scroll:1,
1276        start: starttab
1277    });
1278});
1279
1280</script>";
1281*/
1282
1283echo '<img src="ui/'.$GLOBALS['ui'].'/images/prevtab.png" id="prev" class="prevtab" />';
1284echo '<img src="ui/'.$GLOBALS['ui'].'/images/nexttab.png" id="next" class="nexttab" />';
1285echo '</div>';
1286
1287//# if all is there, we can enable the send button
1288$allReady = true;
1289$GLOBALS['pagefooter']['addtoqueue'] = '<script type="text/javascript">
1290$("#addtoqueue").html("");
1291</script>';
1292
1293$testValue = trim($messagedata['subject']);
1294if (empty($testValue) || $testValue == '(no subject)') {
1295    $allReady = false;
1296    $GLOBALS['pagefooter']['addtoqueue'] .= '<script type="text/javascript">
1297  $("#addtoqueue").append(\'<div class="missing">' .$GLOBALS['I18N']->get('subject missing').'</div>\');
1298  </script>';
1299}
1300$testValue = trim($messagedata['message']);
1301$testValue2 = trim($messagedata['sendurl']);
1302
1303if (empty($testValue) && (empty($testValue2) || $testValue2 == 'e.g. https://www.phplist.com/testcampaign.html')) {
1304    $allReady = false;
1305    $GLOBALS['pagefooter']['addtoqueue'] .= '<script type="text/javascript">
1306  $("#addtoqueue").append(\'<div class="missing">' .$GLOBALS['I18N']->get('message content missing').'</div>\');
1307  </script>';
1308}
1309
1310if ($messagedata['sendmethod'] == 'remoteurl') {
1311    $code = testUrl($messagedata['sendurl']);
1312    if ($code != 200) {
1313        $allReady = false;
1314        $GLOBALS['pagefooter']['addtoqueue'] .= '<script type="text/javascript">
1315        $("#addtoqueue").append(\'<div class="missing">' .s('Incorrect URL for sending').' ('.resourceLink('http://resources.phplist.com/documentation/errors/sendurlinvalid').')</div>\');
1316        </script>';
1317    }
1318}
1319
1320$testValue = trim($messagedata['fromfield']);
1321if (empty($testValue)) {
1322    $allReady = false;
1323    $GLOBALS['pagefooter']['addtoqueue'] .= '<script type="text/javascript">
1324  $("#addtoqueue").append(\'<div class="missing">' .$GLOBALS['I18N']->get('From missing').'</div>\');
1325  </script>';
1326}
1327
1328//#16615, check that "send until" is in after the embargo and warn if it isn't
1329$finishSending = mktime($messagedata['finishsending']['hour'], $messagedata['finishsending']['minute'], 0,
1330    $messagedata['finishsending']['month'], $messagedata['finishsending']['day'],
1331    $messagedata['finishsending']['year']);
1332$embargoTime = mktime($messagedata['embargo']['hour'], $messagedata['embargo']['minute'], 0,
1333    $messagedata['embargo']['month'], $messagedata['embargo']['day'], $messagedata['embargo']['year']);
1334$currentTime = time();
1335
1336if ($finishSending < $embargoTime) {
1337    $allReady = false;
1338    $GLOBALS['pagefooter']['addtoqueue'] .= '<script type="text/javascript">
1339  $("#addtoqueue").append(\'<div class="missing">' .s('This campaign is scheduled to stop sending before the embargo time. No mails will be sent.').'<br/>'.PageLinkButton('send&amp;id='.$messagedata['id'].'&amp;tab=Scheduling',
1340            s('Review Scheduling')).'</div>\');
1341  </script>';
1342} elseif ($finishSending < $currentTime) {
1343    $allReady = false;
1344    $GLOBALS['pagefooter']['addtoqueue'] .= '<script type="text/javascript">
1345  $("#addtoqueue").append(\'<div class="missing">' .s('This campaign is scheduled to stop sending in the past. No mails will be sent.').'<br/>'.PageLinkButton('send&amp;id='.$messagedata['id'].'&amp;tab=Scheduling',
1346            s('Review Scheduling')).'</div>\');
1347  </script>';
1348}
1349
1350if (empty($messagedata['targetlist'])) {
1351    $allReady = false;
1352    $GLOBALS['pagefooter']['addtoqueue'] .= '<script type="text/javascript">
1353  $("#addtoqueue").append(\'<div class="missing">' .$GLOBALS['I18N']->get('destination lists missing').'</div>\');
1354  </script>';
1355}
1356if ($hasClickTrackLinks && BLOCK_PASTED_CLICKTRACKLINKS) {
1357    $allReady = false;
1358    $GLOBALS['pagefooter']['addtoqueue'] .= '<script type="text/javascript">
1359  $("#addtoqueue").append(\'<div class="missing">' .s('Content contains click track links.').resourceLink('http://resources.phplist.com/documentation/errors/pasteclicktrack').'</div>\');
1360  </script>';
1361}
1362
1363foreach ($GLOBALS['plugins'] as $pluginname => $plugin) {
1364    $pluginerror = '';
1365    $pluginerror = $plugin->allowMessageToBeQueued($messagedata);
1366    if ($pluginerror) {
1367        $allReady = false;
1368        $pluginerror = preg_replace("/\n/", '', $pluginerror);
1369        $GLOBALS['pagefooter']['addtoqueue'] .= '<script type="text/javascript">
1370    $("#addtoqueue").append(\'<div class="missing">' .$pluginerror.'</div>\');
1371    </script>';
1372    }
1373}
1374
1375if ($allReady) {
1376    $GLOBALS['pagefooter']['addtoqueue'] .= '<script type="text/javascript">
1377  $("#addtoqueue").html(\'<input class="action-button" type="submit" name="send" id="addtoqueuebutton" value="' .htmlspecialchars(str_replace("'",
1378            "\'", s('Place Campaign in Queue for Sending'))).'">\');
1379  </script>';
1380} else {
1381    $GLOBALS['pagefooter']['addtoqueue'] .= '<script type="text/javascript">
1382  $("#addtoqueue").append(\'<div class="error">' .$GLOBALS['I18N']->get('Some required information is missing. The send button will be enabled when this is resolved.').'</div>\');
1383//  $("#addtoqueue").append(\'<button class="submit" type="submit" name="save" id="addtoqueuebutton" disabled="disabled">' .$GLOBALS['I18N']->get('Send Campaign').'</button>\');
1384  </script>';
1385}
1386
1387$saveDraftButton = '<div class="sendSubmit">
1388    <input class="submit" type="submit" name="savedraft" value="' .s('Save as draft').'"/>
1389    <input type="hidden" name="id" value="' .$id.'"/>
1390    <input type="hidden" name="status" value="draft"/>
1391    <input class="submit" type="submit" name="save" value="' .s('Save and continue editing').'"/>
1392  </div>
1393';
1394
1395$titleInput = '<label for="campaigntitle">'.s('Campaign Title').Help('campaigntitle').'</label>'.
1396    '<input type="text" name="campaigntitle"  id="campaigntitleinput"
1397    value="' .htmlentities($messagedata['campaigntitle'], ENT_QUOTES, 'UTF-8').'" size="60" />';
1398$metaPanel = new UIPanel(s('Meta data'), $titleInput);
1399$metaPanel->setID('metadata');
1400
1401$testpanel = new UIPanel(s('Send Test'), $sendtest_content);
1402$testpanel->setID('testpanel');
1403
1404# print $testpanel->display();
1405