1<?php 2 3require_once dirname(__FILE__).'/inc/userlib.php'; 4include_once dirname(__FILE__).'/inc/maillib.php'; 5include_once dirname(__FILE__).'/inc/php_compat.php'; 6 7// set some variables 8if (!isset($_GET['pi'])) { 9 $_GET['pi'] = ''; 10} 11 12$GLOBALS['mail_error'] = ''; 13$GLOBALS['mail_error_count'] = 0; 14$organisation_name = getConfig('organisation_name'); 15$domain = getConfig('domain'); 16$website = getConfig('website'); 17if (empty($domain)) { 18 $domain = $_SERVER['SERVER_NAME']; 19} 20if (empty($website)) { 21 $website = $_SERVER['SERVER_NAME']; 22} 23if (empty($organisation_name)) { 24 $organisation_name = $_SERVER['SERVER_NAME']; 25} 26 27$xormask = getConfig('xormask'); 28if (empty($xormask)) { 29 $xormask = md5(uniqid(rand(), true)); 30 SaveConfig('xormask', $xormask, 0, 1); 31} 32define('XORmask', str_repeat($xormask, 20)); 33$hmackey = getConfig('hmackey'); 34if (empty($hmackey)) { 35 $hmackey = bin2hex(random_bytes(256)); 36 SaveConfig('hmackey', $hmackey, 0, 1); 37} 38define('HMACKEY', $hmackey); 39 40if (empty($_SESSION[$GLOBALS['installation_name'].'_csrf_token'])) { 41 $_SESSION[$GLOBALS['installation_name'].'_csrf_token'] = bin2hex(random_bytes(16)); 42} 43if (isset($_SESSION['lastactivity'])) { 44 $_SESSION['session_age'] = time() - $_SESSION['lastactivity']; 45} 46$_SESSION['lastactivity'] = time(); 47 48$GLOBALS['img_tick'] = '<span class="yes">Yes</span>'; 49$GLOBALS['img_cross'] = '<span class="no">No</span>'; 50$GLOBALS['img_view'] = '<span class="view">View</span>'; 51$GLOBALS['img_busy'] = '<img src="images/busy.gif" with="34" height="34" border="0" alt="Please wait" id="busyimage" />'; 52 53// if keys need expanding with 0-s 54$checkboxgroup_storesize = 1; // this will allow 10000 options for checkboxes 55 56// identify pages that can be run on commandline 57$commandline_pages = array( 58 'initialise', 59 'dbcheck', 60 'send', 61 'processqueue', 62 'processbounces', 63 'import', 64 'upgrade', 65 'convertstats', 66 'reindex', 67 'blacklistemail', 68 'systemstats', 69 'converttoutf8', 70 'initlanguages', 71 'cron', 72 'updatetlds', 73 'export', 74 'runcommand', 75); 76 77if (isset($message_envelope)) { 78 $envelope = "-f$message_envelope"; 79} 80 81include_once dirname(__FILE__).'/pluginlib.php'; 82 83//# this needs more testing, and docs on how to set the Timezones in the DB 84if (defined('SYSTEM_TIMEZONE')) { 85 // print('set time_zone = "'.SYSTEM_TIMEZONE.'"<br/>'); 86 Sql_Query('set time_zone = "'.SYSTEM_TIMEZONE.'"'); 87 //# verify that it applied correctly 88 $tz = Sql_Fetch_Row_Query('select @@session.time_zone'); 89 if ($tz[0] != SYSTEM_TIMEZONE) { 90 //# I18N doesn't exist yet, @@TODO need better error catching here 91 echo 'Error setting timezone in Sql Database'.'<br/>'; 92 } else { 93 // print "Mysql timezone set to $tz[0]<br/>"; 94 } 95 $phptz_set = date_default_timezone_set(SYSTEM_TIMEZONE); 96 $phptz = date_default_timezone_get(); 97 if (!$phptz_set || $phptz != SYSTEM_TIMEZONE) { 98 //# I18N doesn't exist yet, @@TODO need better error catching here 99 echo 'Error setting timezone in PHP'.'<br/>'; 100 } else { 101 // print "PHP system timezone set to $phptz<br/>"; 102 } 103// print "Time now: ".date('Y-m-d H:i:s').'<br/>'; 104} 105 106//# build a list of themes that are available 107$themedir = dirname(__FILE__).'/ui'; 108$themeNames = array(); // avoid duplicate theme names 109$d = opendir($themedir); 110 111while (false !== ($th = readdir($d))) { 112 if (is_dir($themedir.'/'.$th) && is_file($themedir.'/'.$th.'/theme_info')) { 113 $themeData = parse_ini_file($themedir.'/'.$th.'/theme_info'); 114 115 if (false === $themeData || null === $themeData) { 116 // unable to parse the theme info file so choose the first theme found 117 $THEMES[$th] = array( 118 'name' => 'unknown', 119 'dir' => $th, 120 ); 121 break; 122 } 123 124 if (!empty($themeData['name']) && !empty($themeData['dir']) && !isset($themeNames[$themeData['name']])) { 125 $THEMES[$th] = $themeData; 126 $themeNames[$themeData['name']] = $th; 127 } 128 } 129} 130if (count($THEMES) > 1 && THEME_SWITCH) { 131 unset($THEMES['default']); // the default theme can be hidden if others are available 132 unset($themeNames['phpList Default']); 133 134 $default_config['UITheme'] = array( 135 'value' => isset($_SESSION['ui']) ? $_SESSION['ui'] : '', 136 'values' => array_flip($themeNames), 137 'description' => s('Theme for phpList'), 138 'type' => 'select', 139 'allowempty' => false, 140 'category' => 'general', 141 'hidden' => false, 142 ); 143} 144unset($themeNames); 145 146 147if (!empty($GLOBALS['SessionTableName'])) { // rather undocumented feature, but seems to be used by some 148 include_once dirname(__FILE__).'/sessionlib.php'; 149} 150 151if (!isset($table_prefix)) { 152 $table_prefix = ''; 153} 154if (!isset($usertable_prefix)) { 155 $usertable_prefix = $table_prefix; 156} 157 158/* set session name, without revealing version 159 * but with version included, so that upgrading works more smoothly 160 */ 161 162/* hmm, won't work, going around in circles. Session is started in languages, where the DB 163 * is not known yet, so we can't read xormask from the DB yet*/ 164//ini_set('session.name','phpList-'.$GLOBALS['installation_name'].VERSION | $xormask); 165 166$redfont = ''; 167$efont = ''; 168$GLOBALS['coderoot'] = dirname(__FILE__).'/'; 169$GLOBALS['mail_error'] = ''; 170$GLOBALS['mail_error_count'] = 0; 171 172function SaveConfig($item, $value, $editable = 1, $ignore_errors = 0) 173{ 174 global $tables; 175 //# in case DB hasn't been initialised 176 if (empty($_SESSION['hasconf'])) { 177 $_SESSION['hasconf'] = Sql_Table_Exists($tables['config']); 178 } 179 if (empty($_SESSION['hasconf'])) { 180 return; 181 } 182 if (isset($GLOBALS['default_config'][$item])) { 183 $configInfo = $GLOBALS['default_config'][$item]; 184 } else { 185 $configInfo = array( 186 'type' => 'unknown', 187 'allowempty' => true, 188 'value' => '', 189 ); 190 } 191 //# to validate we need the actual values 192 $value = str_ireplace('[domain]', $GLOBALS['domain'], $value); 193 $value = str_ireplace('[website]', $GLOBALS['website'], $value); 194 195 switch ($configInfo['type']) { 196 case 'boolean': 197 if ($value == 'false' || $value == 'no') { 198 $value = 0; 199 } elseif ($value == 'true' || $value == 'yes') { 200 $value = 1; 201 } 202 break; 203 case 'integer': 204 $value = sprintf('%d', $value); 205 if ($value < $configInfo['min']) { 206 $value = $configInfo['min']; 207 } 208 if ($value > $configInfo['max']) { 209 $value = $configInfo['max']; 210 } 211 break; 212 case 'email': 213 if (!empty($value) && !is_email($value)) { 214 //# hmm, this is displayed only later 215 // $_SESSION['action_result'] = s('Invalid value for email address'); 216 return $configInfo['description'].': '.s('Invalid value for email address'); 217 $value = ''; 218 } 219 break; 220 case 'emaillist': 221 if (!empty($value)) { 222 $valid = array(); 223 $hasError = false; 224 $emails = explode(',', $value); 225 foreach ($emails as $email) { 226 if (is_email($email)) { 227 $valid[] = $email; 228 } else { 229 $hasError = true; 230 } 231 } 232 $value = implode(',', $valid); 233 /* 234 * hmm, not sure this is good or bad for UX 235 * 236 */ 237 if ($hasError) { 238 return $configInfo['description'].': '.s('Invalid value for email address'); 239 } 240 } 241 break; 242 case 'image': 243 include 'class.image.inc'; 244 $image = new imageUpload(); 245 $imageId = $image->uploadImage($item, 0); 246# if ($imageId) { 247 $value = $imageId; 248# } 249 //# we only use the image type for the logo 250 flushLogoCache(); 251 break; 252 default: 253 if (isset($configInfo['allowtags'])) { ## allowtags can be set but empty 254 $value = strip_tags($value,$configInfo['allowtags']); 255 } 256 if (isset($configInfo['allowJS']) && !$configInfo['allowJS']) { ## it needs to be set and false 257 $value = disableJavascript($value); 258 } 259 } 260 //# reset to default if not set, and required 261 if (empty($configInfo['allowempty']) && empty($value)) { 262 $value = $configInfo['value']; 263 } 264 if (!empty($configInfo['hidden'])) { 265 $editable = 0; 266 } 267 268 //# force reloading config values in session 269 unset($_SESSION['config']); 270 //# and refresh the config immediately https://mantis.phplist.com/view.php?id=16693 271 unset($GLOBALS['config']); 272 273 Sql_Query(sprintf('replace into %s set item = "%s", value = "%s", editable = %d', $tables['config'], 274 sql_escape($item), sql_escape($value), $editable)); 275 276 return false; //# true indicates error, and which one 277} 278 279/* 280 We request you retain the $PoweredBy variable including the links. 281 This not only gives respect to the large amount of time given freely 282 by the developers but also helps build interest, traffic and use of 283 PHPlist, which is beneficial to it's future development. 284 285 You can configure your PoweredBy options in your config file 286 287 Michiel Dethmers, phpList Ltd 2001-2015 288*/ 289if (DEVVERSION) { 290 $v = 'dev'; 291} else { 292 $v = VERSION; 293} 294if (REGISTER) { 295 $PoweredByImage = '<p class="poweredby" style="text-align:center"><a href="https://www.phplist.com/poweredby?utm_source=pl'.$v.'&utm_medium=poweredhostedimg&utm_campaign=phpList" title="visit the phpList website" ><img src="'.PHPLIST_POWEREDBY_URLROOT.'/'.$v.'/power-phplist.png" title="powered by phpList version '.$v.', © phpList ltd" alt="powered by phpList '.$v.', © phpList ltd" border="0" /></a></p>'; 296} else { 297 $PoweredByImage = '<p class="poweredby" style="text-align:center"><a href="https://www.phplist.com/poweredby?utm_source=pl'.$v.'&utm_medium=poweredlocalimg&utm_campaign=phpList" title="visit the phpList website"><img src="images/power-phplist.png" title="powered by phpList version '.$v.', © phpList ltd" alt="powered by phpList '.$v.', © phpList ltd" border="0"/></a></p>'; 298} 299$PoweredByText = '<div style="clear: both; font-family: arial, verdana, sans-serif; font-size: 8px; font-variant: small-caps; font-weight: normal; padding: 2px; padding-left:10px;padding-top:20px;">powered by <a href="https://www.phplist.com/poweredby?utm_source=download'.$v.'&utm_medium=poweredtxt&utm_campaign=phpList" target="_blank" title="powered by phpList version '.$v.', © phpList ltd">phpList</a></div>'; 300 301if (!TEST && REGISTER) { 302 if (!PAGETEXTCREDITS) { 303 $PoweredBy = $PoweredByImage; 304 } else { 305 $PoweredBy = $PoweredByText; 306 } 307} else { 308 if (!PAGETEXTCREDITS) { 309 $PoweredBy = $PoweredByImage; 310 } else { 311 $PoweredBy = $PoweredByText; 312 } 313} 314// some other configuration variables, which need less tweaking 315// number of users to show per page if there are more 316if (!defined('MAX_USER_PP')) { 317 define('MAX_USER_PP', 50); 318} 319if (!defined('MAX_MSG_PP')) { 320 define('MAX_MSG_PP', 5); 321} 322// Used by e.g. mviews.php 323if (!defined('MAX_OPENS_PP')) { 324 define('MAX_OPENS_PP', 20); 325} 326 327function formStart($additional = '') 328{ 329 global $form_action, $page, $p; 330 // depending on server software we can post to the directory, or need to pass on the page 331 if ($form_action) { 332 $html = sprintf('<form method="post" action="%s" %s>', $form_action, $additional); 333 // retain all get variables as hidden ones 334 foreach (array( 335 'p', 336 'page', 337 ) as $key) { 338 $val = $_REQUEST[$key]; 339 if ($val) { 340 $html .= sprintf('<input type="hidden" name="%s" value="%s" />', $key, htmlspecialchars($val)); 341 } 342 } 343 } else { 344 $html = sprintf('<form method="post" action="" %s>', $additional); 345 } 346 347 if (!empty($_SESSION['logindetails']['id'])) { 348 //# create the token table, if necessary 349 if (!Sql_Check_For_Table('admintoken')) { 350 createTable('admintoken'); 351 } 352 $key = bin2hex(random_bytes(16)); 353 Sql_Query(sprintf('insert into %s (adminid,value,entered,expires) values(%d,"%s",%d,date_add(now(),interval 1 hour))', 354 $GLOBALS['tables']['admintoken'], $_SESSION['logindetails']['id'], $key, time()), 1); 355 $html .= sprintf('<input type="hidden" name="formtoken" value="%s" />', $key); 356 357 //# keep the token table empty 358 Sql_Query(sprintf('delete from %s where expires < now()', 359 $GLOBALS['tables']['admintoken']), 1); 360 } 361 362 return $html; 363} 364 365function checkAccess($page, $pluginName = '') 366{ 367 if (empty($pluginName)) { 368 if (!$GLOBALS['commandline'] && isset($GLOBALS['disallowpages']) && in_array($page, 369 $GLOBALS['disallowpages']) 370 ) { 371 return 0; 372 } 373 } else { 374 if (!$GLOBALS['commandline'] && isset($GLOBALS['disallowpages']) && in_array($page.'&pi='.$pluginName, 375 $GLOBALS['disallowpages']) 376 ) { 377 return 0; 378 } 379 } 380 381 /* 382 if (isSuperUser()) 383 return 1; 384 */ 385 //# we allow all that haven't been disallowed 386 //# might be necessary to turn that around 387 return 1; 388} 389 390//@@TODO centralise the reporting and who gets what 391function sendReport($subject, $message) 392{ 393 $report_addresses = getConfig('report_address'); 394 if ($report_addresses) { 395 foreach (explode(',', $report_addresses) as $address) { 396 sendMail($address, $GLOBALS['installation_name'].' '.$subject, $message); 397 } 398 } 399 foreach ($GLOBALS['plugins'] as $pluginname => $plugin) { 400 $plugin->sendReport($GLOBALS['installation_name'].' '.$subject, $message); 401 } 402} 403 404function sendError($message, $to, $subject) 405{ 406 foreach ($GLOBALS['plugins'] as $pluginname => $plugin) { 407 $plugin->sendError($GLOBALS['installation_name'].' Error: '.$subject, $message); 408 } 409// Error($msg); 410} 411 412function sendMessageStats($msgid) 413{ 414 global $stats_collection_address, $tables; 415 $msg = ''; 416 if (defined('NOSTATSCOLLECTION') && NOSTATSCOLLECTION) { 417 return; 418 } 419 if (!isset($stats_collection_address)) { 420 $stats_collection_address = 'phplist-stats@phplist.com'; 421 } 422 $data = Sql_Fetch_Array_Query(sprintf('select * from %s where id = %d', $tables['message'], $msgid)); 423 $msg .= 'phpList version '.VERSION."\n"; 424 $msg .= 'phpList url '.getConfig("website")."\n"; 425 426 $diff = timeDiff($data['sendstart'], $data['sent']); 427 428 if ($data['id'] && $data['processed'] > 10 && $diff != 'very little time') { 429 $msg .= "\n".'Time taken: '.$diff; 430 foreach (array( 431 'entered', 432 'processed', 433 'sendstart', 434 'sent', 435 'htmlformatted', 436 'sendformat', 437 'template', 438 'astext', 439 'ashtml', 440 'astextandhtml', 441 'aspdf', 442 'astextandpdf', 443 ) as $item) { 444 $msg .= "\n".$item.' => '.$data[$item]; 445 } 446 sendMail($stats_collection_address, 'phpList stats', $msg, '', '', true); 447 } 448} 449 450function normalize($var) 451{ 452 $var = str_replace(' ', '_', $var); 453 $var = str_replace(';', '', $var); 454 455 return $var; 456} 457 458function ClineSignature() 459{ 460 return 'phpList version '.VERSION.' (c) 2000-'.date('Y')." phpList Ltd, https://www.phplist.com"; 461} 462 463function ClineError($msg) 464{ 465 ob_end_clean(); 466 echo "\nError: $msg\n"; 467 exit; 468} 469 470function clineUsage($line = '') 471{ 472 cl_output( 'Usage: '.$_SERVER['SCRIPT_FILENAME']." -p page $line".PHP_EOL); 473} 474 475function Error($msg, $documentationURL = '') 476{ 477 if ($GLOBALS['commandline']) { 478 clineError($msg); 479 480 return; 481 } 482 echo '<div class="error">'.$GLOBALS['I18N']->get('error').": $msg "; 483 if (!empty($documentationURL)) { 484 echo resourceLink($documentationURL); 485 } 486 echo '</div>'; 487 488 $GLOBALS['mail_error'] .= 'Error: '.$msg."\n"; 489 ++$GLOBALS['mail_error_count']; 490 if (is_array($_POST) && count($_POST)) { 491 $GLOBALS['mail_error'] .= "\nPost vars:\n"; 492 foreach ($_POST as $key => $val) { 493 if ($key != 'password') { 494 if (is_array($val)) { 495 $GLOBALS['mail_error'] .= $key.'='.serialize($val)."\n"; 496 } else { 497 $GLOBALS['mail_error'] .= $key.'='.$val."\n"; 498 } 499 } else { 500 $GLOBALS['mail_error'] .= "password=********\n"; 501 } 502 } 503 } 504} 505 506function clean($value) 507{ 508 $value = trim($value); 509 $value = preg_replace("/\r/", '', $value); 510 $value = preg_replace("/\n/", '', $value); 511 $value = str_replace('"', '"', $value); 512 $value = str_replace("'", '’', $value); 513 $value = str_replace('`', '‘', $value); 514 $value = stripslashes($value); 515 516 return $value; 517} 518 519function join_clean($sep, $array) 520{ 521 // join values without leaving a , at the end 522 $arr2 = array(); 523 foreach ($array as $key => $val) { 524 if ($val) { 525 $arr2[$key] = $val; 526 } 527 } 528 529 return implode($sep, $arr2); 530} 531 532function Fatal_Error($msg, $documentationURL = '') 533{ 534 if (empty($_SESSION['fatalerror'])) { 535 $_SESSION['fatalerror'] = 0; 536 } 537 ++$_SESSION['fatalerror']; 538 header('HTTP/1.0 500 Fatal error'); 539 if ($_SESSION['fatalerror'] > 5) { 540 $_SESSION['logout_error'] = s('Too many errors, please login again'); 541 $_SESSION['adminloggedin'] = ''; 542 $_SESSION['logindetails'] = ''; 543 session_destroy(); 544 Redirect('logout&err=2'); 545 exit; 546 } 547 548 if ($GLOBALS['commandline']) { 549 @ob_end_clean(); 550 echo "\n".$GLOBALS['I18N']->get('fatalerror').': '.strip_tags($msg)."\n"; 551 @ob_start(); 552 } else { 553 @ob_end_clean(); 554 if (isset($GLOBALS['I18N']) && is_object($GLOBALS['I18N'])) { 555 echo '<div align="center" class="error">'.$GLOBALS['I18N']->get('fatalerror').": $msg "; 556 } else { 557 echo '<div align="center" class="error">'."Fatal Error: $msg "; 558 } 559 if (!empty($documentationURL)) { 560 echo resourceLink($documentationURL); 561 } 562 echo '</div>'; 563 564 foreach ($GLOBALS['plugins'] as $pluginname => $plugin) { 565 $plugin->processError($msg); 566 } 567 } 568 // include "footer.inc"; 569 // exit; 570 return 0; 571} 572 573function resourceLink($url, $title = '') 574{ 575 if (empty($title)) { 576 $title = s('Documentation about this error'); 577 } 578 579 return ' <span class="resourcelink"><a href="'.$url.'" title="'.htmlspecialchars($title).'" target="_blank" class="resourcelink">'.snbr('More information').'</a></span>'; 580} 581 582function Warn($msg) 583{ 584 if ($GLOBALS['commandline']) { 585 @ob_end_clean(); 586 echo "\n".strip_tags($GLOBALS['I18N']->get('warning').': '.$msg)."\n"; 587 @ob_start(); 588 } else { 589 echo '<div align=center class="error">'."$msg </div>"; 590 $message = ' 591 592 An warning has occurred in the Mailinglist System 593 594 ' .$msg; 595 } 596// sendMail(getConfig("report_address"),"Mail list warning",$message,""); 597} 598 599function Info($msg, $noClose = false) 600{ 601 if (!empty($GLOBALS['commandline'])) { 602 @ob_end_clean(); 603 echo "\n".strip_tags($msg)."\n"; 604 @ob_start(); 605 } else { 606 //# generate some ID for the info div 607 $id = substr(md5($msg), 0, 15); 608 $pageinfo = new pageInfo($id); 609 $pageinfo->setContent('<p>'.$msg.'</p>'); 610 if ($noClose && method_exists($pageinfo, 'suppressHide')) { 611 $pageinfo->suppressHide(); 612 } 613 echo $pageinfo->show(); 614 } 615} 616 617function ActionResult($msg) 618{ 619 if ($GLOBALS['commandline']) { 620 @ob_end_clean(); 621 echo "\n".strip_tags($msg)."\n"; 622 @ob_start(); 623 } else { 624 return '<div class="actionresult">'.$msg.'</div>'; 625 } 626} 627 628function pageTitle($page) 629{ 630 return $GLOBALS['I18N']->pageTitle($page); 631} 632 633$GLOBALS['pagecategories'] = array( 634 //# category title => array( 635 // toplink => page to link top menu to 636 // pages => pages in this category 637 'dashboard' => array( 638 'toplink'=> 'home', 639 'pages' => array(), 640 'menulinks' => array(), 641 ), 642 'subscribers' => array( 643 'toplink' => 'list', 644 'pages' => array( 645 'users', 646 'usermgt', 647 'members', 648 'import', 649 'import1', 650 'import2', 651 'import3', 652 'import4', 653 'importsimple', 654 'dlusers', 655 'export', 656 'listbounces', 657 'massremove', 658 'suppressionlist', 659 'reconcileusers', 660 'usercheck', 661 'user', 662 'adduser', 663 'attributes', 664 665 ), 666 'menulinks' => array( 667 'users', 668 'usermgt', 669 'attributes', 670 'list', 671 'import', 672 'export', 673 'listbounces', 674 'suppressionlist', 675 'reconcileusers', 676 ), 677 678 ), 679 'campaigns' => array( 680 'toplink' => 'messages', 681 'pages' => array( 682 'send', 683 'sendprepared', 684 'message', 685 'messages', 686 'viewmessage', 687 'templates', 688 'template', 689 'viewtemplate', 690 ), 691 'menulinks' => array( 692 'send', 693 'messages', 694 'templates', 695 ), 696 ), 697 'statistics' => array( 698 'toplink' => 'statsmgt', 699 'pages' => array( 700 'mviews', 701 'mclicks', 702 'uclicks', 703 'userclicks', 704 'statsmgt', 705 'statsoverview', 706 'domainstats', 707 'msgbounces', 708 ), 709 'menulinks' => array( 710 'statsoverview', 711 'mviews', 712 'mclicks', 713 'uclicks', 714 'domainstats', 715 'msgbounces', 716 ), 717 ), 718 'system' => array( 719 'toplink' => 'system', 720 'pages' => array( 721 'bounce', 722 'bounces', 723 'convertstats', 724 'dbcheck', 725 'eventlog', 726 'bouncemgt', 727 'generatebouncerules', 728 'initialise', 729 'upgrade', 730 'processqueue', 731 'processbounces', 732 'reindex', 733 'resetstats', 734 'updatetranslation', 735 ), 736 'menulinks' => array( 737 // 'bounces', 738 'updatetranslation', 739 'dbcheck', 740 'eventlog', 741 'initialise', 742 'upgrade', 743 'bouncemgt', 744 'processqueue', 745 // 'processbounces', 746 'reindex', 747 ), 748 ), 749 'config' => array( 750 'toplink' => 'setup', 751 'pages' => array( 752 'setup', 753 'configure', 754 'plugins', 755 'catlists', 756 'spage', 757 'spageedit', 758 'admins', 759 'admin', 760 'importadmin', 761 'adminattributes', 762 'editattributes', 763 'defaults', 764 'bouncerules', 765 'bouncerule', 766 'checkbouncerules', 767 ), 768 'menulinks' => array( 769 'setup', 770 'configure', 771 'plugins', 772 'spage', 773 'admins', 774 'importadmin', 775 'adminattributes', 776 'bouncerules', 777 'checkbouncerules', 778 'catlists', 779 ), 780 ), 781 //'info' => array( 782 //'toplink' => 'about', 783 //'pages' => array( 784 //'about', 785 //'community', 786 //'home', 787 // 'translate', 788 //'vote', 789 //), 790 //'menulinks' => array( 791 // 'about', 792 //'community', 793 // 'translate', 794 //'home', 795 //), 796 //), 797 798 //'plugins' => array( 799 //'toplink' => 'plugins', 800 //'pages' => array(), 801 //'menulinks' => array(), 802 //), 803); 804if (isSuperUser() && ALLOW_UPDATER) { 805 $GLOBALS['pagecategories']['system']['pages'][] = 'update'; 806 $GLOBALS['pagecategories']['system']['menulinks'][] = 'update'; 807} 808if (DEVVERSION) { 809 $GLOBALS['pagecategories']['develop'] = array( 810 'toplink' => 'develop', 811 'pages' => array( 812 // 'checki18n', 813 'stresstest', 814 'subscriberstats', 815 'tests', 816 ), 817 'menulinks' => array( 818 // 'checki18n', 819 'stresstest', 820 'subscriberstats', 821 'tests', 822 ), 823 ); 824} 825function pageCategory($page) 826{ 827 foreach ($GLOBALS['pagecategories'] as $category => $cat_details) { 828 if (in_array($page, $cat_details['pages'])) { 829 return $category; 830 } 831 } 832 833 return ''; 834} 835 836/* 837$main_menu = array( 838 "configure" => "Configure", 839 "community" => "Help", 840 "about" => "About", 841 "div1" => "<hr />", 842 "list" => "Lists", 843 "send"=>"Send a message", 844 "users" => "Users", 845 "usermgt" => "Manage Users", 846 "spage" => "Subscribe Pages", 847 "messages" => "Messages", 848 'statsmgt' => 'Statistics', 849 "div2" => "<hr />", 850 "templates" => "Templates", 851 "preparesend"=>"Prepare a message", 852 "sendprepared"=>"Send a prepared message", 853 "processqueue"=>"Process Queue", 854 "processbounces"=>"Process Bounces", 855 "bouncemgt" => 'Manage Bounces', 856 "bounces"=>"View Bounces", 857 "eventlog"=>"Eventlog" 858); 859*/ 860$GLOBALS['context_menu'] = array( 861 'home' => 'home', 862 'community' => 'help', 863 'about' => 'about', 864 'logout' => 'logout', 865); 866 867function contextMenu() 868{ 869 if (isset($GLOBALS['firsttime']) || (isset($_GET['page']) && $_GET['page'] == 'initialise')) { 870 return; 871 } 872 if (!CLICKTRACK) { 873 unset($GLOBALS['context_menu']['statsmgt']); 874 } 875 $shade = 1; 876 $spb = '<li class="shade0">'; 877// $spb = '<li class="shade2">'; 878 $spe = '</li>'; 879 $nm = mb_strtolower(NAME); 880 if ($nm != 'phplist') { 881 $GLOBALS['context_menu']['community'] = ''; 882 } 883 // if (USE_ADVANCED_BOUNCEHANDLING) { 884 $GLOBALS['context_menu']['bounces'] = ''; 885 $GLOBALS['context_menu']['processbounces'] = ''; 886 // } else { 887 // $GLOBALS["context_menu"]["bouncemgt"] = ''; 888 // } 889 890 if (!isset($_SESSION['adminloggedin']) || !$_SESSION['adminloggedin']) { 891 return '<ul class="contextmenu">'.$spb.PageLink2('home', 892 $GLOBALS['I18N']->get('Main Page')).'<br />'.$spe.$spb.PageLink2('about', 893 $GLOBALS['I18N']->get('about').' phplist').'<br />'.$spe.'</ul>'; 894 } 895 896 $access = accessLevel('spage'); 897 switch ($access) { 898 case 'owner': 899 $subselect = sprintf(' where owner = %d', $_SESSION['logindetails']['id']); 900 break; 901 case 'all': 902 case 'view': 903 $subselect = ''; 904 break; 905 case 'none': 906 default: 907 $subselect = ' where id = 0'; 908 break; 909 } 910 if (TEST && REGISTER) { 911 $pixel = '<img src="https://d3u7tsw7cvar0t.cloudfront.net/images/pixel.gif" width="1" height="1" alt="" />'; 912 } else { 913 $pixel = ''; 914 } 915 global $tables; 916 $html = ''; 917 918 if (isset($_GET['page'])) { 919 $thispage = $_GET['page']; 920 } else { 921 $thispage = 'home'; 922 } 923 $thispage_category = pageCategory($thispage); 924 925 if (empty($thispage_category) && empty($_GET['pi'])) { 926 $thispage_category = ''; 927 } elseif (!empty($_GET['pi'])) { 928 $thispage_category = 'plugins'; 929 } 930 931 if (!empty($thispage_category) && !empty($GLOBALS['pagecategories'][$thispage_category]['menulinks'])) { 932 if (count($GLOBALS['pagecategories'][$thispage_category]['menulinks'])) { 933 foreach ($GLOBALS['pagecategories'][$thispage_category]['menulinks'] as $category_page) { 934 $GLOBALS['context_menu'][$category_page] = $category_page; 935 } 936 } else { 937 unset($GLOBALS['context_menu']['categoryheader']); 938 } 939 } elseif (!empty($_GET['pi'])) { 940 if (isset($GLOBALS['plugins'][$_GET['pi']]) && method_exists($GLOBALS['plugins'][$_GET['pi']], 'adminmenu')) { 941 $GLOBALS['context_menu']['categoryheader'] = $GLOBALS['plugins'][$_GET['pi']]->name; 942 $GLOBALS['context_menu'] = $GLOBALS['plugins'][$_GET['pi']]->adminMenu(); 943 } 944 } 945 946 foreach ($GLOBALS['context_menu'] as $page => $desc) { 947 if (!$desc) { 948 continue; 949 } 950 $link = PageLink2($page, $GLOBALS['I18N']->pageTitle($desc)); 951 if ($link) { 952 if ($page == 'preparesend' || $page == 'sendprepared') { 953 if (USE_PREPARE) { 954 $html .= $spb.$link.$spe; 955 } 956 } // don't use the link for a rule 957 elseif ($desc == '<hr />') { 958 $html .= '<li>'.$desc.'</li>'; 959 } elseif ($page == 'categoryheader') { 960 // $html .= '<li><h3>'.$GLOBALS['I18N']->get($thispage_category).'</h3></li>'; 961 $html .= '<li><h3>'.$GLOBALS['I18N']->get('In this section').'</h3></li>'; 962 } else { 963 $html .= $spb.$link.$spe; 964 } 965 } 966 } 967 /* 968 if (sizeof($GLOBALS["plugins"])) { 969 $html .= $spb."<hr/>".$spe; 970 foreach ($GLOBALS["plugins"] as $pluginName => $plugin) { 971 $html .= $spb.PageLink2("main&pi=$pluginName",$pluginName).$spe; 972 } 973 } 974 */ 975 976 if ($html) { 977 return '<ul class="contextmenu">'.$html.'</ul>'.$pixel; 978 } else { 979 return ''; 980 } 981} 982 983function recentlyVisited() 984{ 985 $html = ''; 986 if (!isset($_SESSION['browsetrail']) || !is_array($_SESSION['browsetrail'])) { 987 $_SESSION['browsetrail'] = array(); 988 } 989 if (empty($_SESSION['adminloggedin'])) { 990 return ''; 991 } 992 if (isset($_SESSION['browsetrail']) && is_array($_SESSION['browsetrail'])) { 993 if (!empty($_COOKIE['browsetrail'])) { 994 // if (!in_array($_COOKIE['browsetrail'],$_SESSION['browsetrail'])) { 995 array_unshift($_SESSION['browsetrail'], $_COOKIE['browsetrail']); 996// } 997 } 998 999 $shade = 0; 1000 $html .= '<h3>'.$GLOBALS['I18N']->get('Recently visited').'</h3><ul class="recentlyvisited">'; 1001 $browsetrail = array_unique($_SESSION['browsetrail']); 1002 1003// $browsetrail = array_reverse($browsetrail); 1004 $browsetaildone = array(); 1005 $num = 0; 1006 foreach ($browsetrail as $pageid => $visitedpage) { 1007 if (strpos($visitedpage, 1008 'SEP')) { //# old method, store page title in cookie. However, that breaks on multibyte languages 1009 list($pageurl, $pagetitle) = explode('SEP', strip_tags($visitedpage)); 1010 if ($pagetitle != 'phplist') { //# pages with no title 1011// $pagetitle = str_replace('%',' ',$pagetitle); 1012 if (strpos($pagetitle, ' ') > 20) { 1013 $pagetitle = substr($pagetitle, 0, 10).' ...'; 1014 } 1015 $html .= '<li class="shade'.$shade.'"><a href="./'.$pageurl.'" title="'.htmlspecialchars($pagetitle).'"><!--'.$pageid.'-->'.$pagetitle.'</a></li>'; 1016 $shade = !$shade; 1017 } 1018 } else { 1019 if (@preg_match('/\?page=([\w]+)/', $visitedpage, $regs)) { 1020 $p = $regs[1]; 1021 $urlparams = array(); 1022 $pairs = explode('&', $visitedpage); 1023 foreach ($pairs as $pair) { 1024 if (strpos($pair, '=')) { 1025 list($var, $val) = explode('=', $pair); 1026 $urlparams[$var] = $val; 1027 } 1028 } 1029 //# pass on ID 1030 if (isset($urlparams['id'])) { 1031 $urlparams['id'] = sprintf('%d', $urlparams['id']); 1032 } 1033 $url = 'page='.$p; 1034 if (!empty($urlparams['id'])) { 1035 $url .= '&id='.$urlparams['id']; 1036 } 1037 //# check for plugin 1038 if (isset($urlparams['pi']) && isset($GLOBALS['plugins'][$urlparams['pi']])) { 1039 $url .= '&pi='.$urlparams['pi']; 1040 $title = $GLOBALS['plugins'][$urlparams['pi']]->pageTitle($p); 1041 $titlehover = $GLOBALS['plugins'][$urlparams['pi']]->pageTitleHover($p); 1042 } else { 1043 unset($urlparams['pi']); 1044 $title = $GLOBALS['I18N']->pageTitle($p); 1045 $titlehover = $GLOBALS['I18N']->pageTitleHover($p); 1046 } 1047 if (!empty($p) && !empty($title) && !in_array($url, $browsetaildone)) { 1048 $html .= '<li class="shade'.$shade.'"><a href="./?'.htmlspecialchars($url).addCsrfGetToken().'" title="'.htmlspecialchars($titlehover).'"><!--'.$pageid.'-->'.$title.'</a></li>'; 1049 $shade = !$shade; 1050 $browsetaildone[] = $url; 1051 ++$num; 1052 } 1053 } 1054 } 1055 if ($num >= 3) { 1056 break; 1057 } 1058 } 1059 1060 $html .= '</ul>'; 1061 $_SESSION['browsetrail'] = array_slice($_SESSION['browsetrail'], 0, 20); 1062 } 1063 1064 return $html; 1065} 1066 1067function topMenu() 1068{ 1069 if (empty($_SESSION['logindetails'])) { 1070 return ''; 1071 } 1072 1073 if ($_SESSION['logindetails']['superuser']) { // we don't have a system yet to distinguish access to plugins 1074 if (count($GLOBALS['plugins'])) { 1075 foreach ($GLOBALS['plugins'] as $pluginName => $plugin) { 1076 //if (isset($GLOBALS['pagecategories']['plugins'])) { 1077 //array_push($GLOBALS['pagecategories']['plugins']['menulinks'],'main&pi='.$pluginName); 1078 //} 1079 $menulinks = $plugin->topMenuLinks; 1080 foreach ($menulinks as $link => $linkDetails) { 1081 if (isset($GLOBALS['pagecategories'][$linkDetails['category']])) { 1082 array_push($GLOBALS['pagecategories'][$linkDetails['category']]['menulinks'], 1083 $link.'&pi='.$pluginName); 1084 } 1085 } 1086 } 1087 } 1088 } 1089 1090 $topmenu = ''; 1091 $topmenu .= '<div id="menuTop">'; 1092 if (!DEVVERSION) { 1093 unset($GLOBALS['pagecategories']['develop']); 1094 } 1095 1096 foreach ($GLOBALS['pagecategories'] as $category => $categoryDetails) { 1097 if ($category == 'hide' 1098 //# hmm, this also suppresses the "dashboard" item 1099 // || count($categoryDetails['menulinks']) == 0 1100 ) { 1101 continue; 1102 } 1103 1104 $thismenu = ''; 1105 foreach ($categoryDetails['menulinks'] as $page) { 1106 $title = $GLOBALS['I18N']->pageTitle($page); 1107 1108 $link = PageLink2($page, $title, '', true); 1109 if ($link) { 1110 $thismenu .= '<li>'.$link.'</li>'; 1111 } 1112 } 1113 if (!empty($thismenu)) { 1114 $thismenu = '<ul>'.$thismenu.'</ul>'; 1115 } 1116 1117 if (!empty($categoryDetails['toplink'])) { 1118 $categoryurl = PageUrl2($categoryDetails['toplink'], '', '', true); 1119 if ($categoryurl) { 1120 $topmenu .= '<ul><li><a href="'.$categoryurl.'" title="'.$GLOBALS['I18N']->pageTitleHover($category).'">'.ucfirst($GLOBALS['I18N']->get($category)).'</a>'.$thismenu.'</li></ul>'; 1121 } else { 1122 $topmenu .= '<ul><li><span>'.$GLOBALS['I18N']->get($category).$categoryurl.'</span>'.$thismenu.'</li></ul>'; 1123 } 1124 } 1125 } 1126 1127 $topmenu .= '</div>'; 1128 1129 return $topmenu; 1130} 1131 1132//## hmm, these really should become objects 1133function PageLink2($name, $desc = '', $url = '', $no_plugin = false, $title = '') 1134{ 1135 $plugin = ''; 1136 if ($url) { 1137 $url = '&'.$url; 1138 } 1139 1140 if (in_array($name, $GLOBALS['disallowpages'])) { 1141 return ''; 1142 } 1143 if (strpos($name, '&') !== false) { 1144 preg_match('/([^&]+)&/', $name, $regs); 1145 $page = $regs[1]; 1146 if (preg_match('/&pi=([^&]+)/', $name, $regs)) { 1147 $plugin = $regs[1]; 1148 } 1149 if (in_array($page, $GLOBALS['disallowpages'])) { 1150 return ''; 1151 } 1152 } else { 1153 $page = $name; 1154 } 1155 1156 $access = accessLevel($page); 1157 if (empty($plugin) || !is_object($GLOBALS['plugins'][$plugin])) { 1158 $name = str_replace('&', '&', $name); 1159 $name = str_replace('&', '&', $name); 1160 } else { 1161 if (isset($GLOBALS['plugins'][$plugin]->pageTitles[$page])) { 1162 $desc = $GLOBALS['plugins'][$plugin]->pageTitles[$page]; 1163 } else { 1164 $desc = $plugin.' - '.$page; 1165 } 1166 } 1167 1168 if (empty($desc)) { 1169 $desc = $name; 1170 } 1171 if (empty($title)) { 1172 $title = $GLOBALS['I18N']->pageTitleHover($page); 1173 if (empty($title)) { 1174 $title = $desc; 1175 } 1176 } 1177 1178 $pqChoice = getConfig('pqchoice'); 1179 $hideProcessQueue = !MANUALLY_PROCESS_QUEUE; 1180 1181 if ($access == 'owner' || $access == 'all' || $access == 'view') { 1182 if ($name == 'processqueue' && $hideProcessQueue) { 1183 return ''; 1184 }//'<!-- '.$desc.'-->'; 1185 elseif ($name == 'processbounces' && !MANUALLY_PROCESS_BOUNCES) { 1186 return ''; 1187 } //'<!-- '.$desc.'-->'; 1188 else { 1189 if (!$no_plugin && !preg_match('/&pi=/i', 1190 $name) && isset($_GET['pi']) && isset($GLOBALS['plugins'][$_GET['pi']]) && is_object($GLOBALS['plugins'][$_GET['pi']]) 1191 ) { 1192 $pi = '&pi='.$_GET['pi']; 1193 } else { 1194 $pi = ''; 1195 } 1196 1197 if (!empty($_SESSION[$GLOBALS['installation_name'].'_csrf_token'])) { 1198 $token = '&tk='.$_SESSION[$GLOBALS['installation_name'].'_csrf_token']; 1199 } else { 1200 $token = ''; 1201 } 1202 $linktext = $desc; 1203 $linktext = str_ireplace('phplist', 'phpList', $linktext); 1204 1205 return sprintf('<a href="./?page=%s%s%s%s" title="%s">%s</a>', $name, $url, $pi, $token, 1206 htmlspecialchars(strip_tags($title)), $linktext); 1207 } 1208 } 1209 1210 return ''; 1211// return "\n<!--$name disabled $access -->\n"; 1212// return "\n$name disabled $access\n"; 1213} 1214 1215//# hmm actually should rename to PageLinkDialogButton 1216function PageLinkDialog($name, $desc = '', $url = '', $extraclass = '') 1217{ 1218 //# as PageLink2, but add the option to ajax it in a popover window 1219 $link = PageLink2($name, $desc, $url); 1220 if ($link) { 1221 $link = str_replace('<a ', '<a class="button opendialog '.$extraclass.'" ', $link); 1222 $link .= ''; 1223 } 1224 1225 return $link; 1226} 1227 1228function PageLinkDialogOnly($name, $desc = '', $url = '', $extraclass = '') 1229{ 1230 //# as PageLink2, but add the option to ajax it in a popover window 1231 $link = PageLink2($name, $desc, $url); 1232 if ($link) { 1233 $link = str_replace('<a ', '<a class="opendialog '.$extraclass.'" ', $link); 1234 $link .= ''; 1235 } 1236 1237 return $link; 1238} 1239 1240function PageLinkAjax($name, $desc = '', $url = '', $extraclass = '') 1241{ 1242 //# as PageLink2, but add the option to ajax it in a popover window 1243 $link = PageLink2($name, $desc, $url); 1244 if ($link) { 1245 $link = str_replace('<a ', '<a class="ajaxable '.$extraclass.'" ', $link); 1246 $link .= ''; 1247 } 1248 1249 return $link; 1250} 1251 1252function PageLinkClass($name, $desc = '', $url = '', $class = '', $title = '') 1253{ 1254 $link = PageLink2($name, $desc, $url, false, $title); 1255 if (empty($class)) { 1256 $class = 'link'; 1257 } 1258 if ($link) { 1259 $link = str_replace('<a ', '<a class="'.$class.'" ', $link); 1260 $link .= ''; 1261 } 1262 1263 return $link; 1264} 1265 1266function PageLinkButton($name, $desc = '', $url = '', $extraclass = '', $title = '') 1267{ 1268 return PageLinkClass($name, $desc, $url, 'button '.$extraclass, $title); 1269} 1270 1271function PageLinkActionButton($name, $desc = '', $url = '', $extraclass = '', $title = '') 1272{ 1273 //# as PageLink2, but add the option to ajax it in a popover window 1274 $link = PageLink2($name, $desc, $url); 1275 if ($link) { 1276 $link = str_replace('<a ', '<a class="action-button '.$extraclass.'" ', $link); 1277 $link .= ''; 1278 } 1279 1280 return $link; 1281} 1282 1283function SidebarLink($name, $desc, $url = '') 1284{ 1285 if ($url) { 1286 $url = '&'.$url; 1287 } 1288 $access = accessLevel($name); 1289 if ($access == 'owner' || $access == 'all') { 1290 if ($name == 'processqueue' && !MANUALLY_PROCESS_QUEUE) { 1291 return '<!-- '.$desc.'-->'; 1292 } elseif ($name == 'processbounces' && !MANUALLY_PROCESS_BOUNCES) { 1293 return '<!-- '.$desc.'-->'; 1294 } else { 1295 return sprintf('<a href="./?page=%s%s" target="phplistwindow">%s</a>', $name, $url, mb_strtolower($desc)); 1296 } 1297 } else { 1298 return "\n<!--$name disabled $access -->\n"; 1299 } 1300// return "\n$name disabled $access\n"; 1301} 1302 1303function PageURL2($name, $desc = '', $url = '', $no_plugin = false) 1304{ 1305 if (empty($name)) { 1306 return ''; 1307 } 1308 if ($url) { 1309 $url = '&'.$url; 1310 } 1311 $access = accessLevel($name); 1312 if ($access == 'owner' || $access == 'all' || $access == 'view') { 1313 if (!$no_plugin && !preg_match('/&pi=/i', 1314 $name) && $_GET['pi'] && is_object($GLOBALS['plugins'][$_GET['pi']]) 1315 ) { 1316 $pi = '&pi='.$_GET['pi']; 1317 } else { 1318 $pi = ''; 1319 } 1320 1321 return sprintf('./?page=%s%s%s%s', $name, $url, $pi, addCsrfGetToken()); 1322 } else { 1323 return ''; 1324 } 1325} 1326 1327function ListofLists($current, $fieldname, $subselect) 1328{ 1329 //# @@TODO, this is slow on more than 150 lists. We should add caching or optimise 1330 $GLOBALS['systemTimer']->interval(); 1331 $categoryhtml = array(); 1332 //# add a hidden field, so that all checkboxes can be unchecked while keeping the field in POST to process it 1333 // $categoryhtml['unselect'] = '<input type="hidden" name="'.$fieldname.'[unselect]" value="1" />'; 1334 1335 $categoryhtml['selected'] = ''; 1336 1337 $categoryhtml['all'] = '<input type="hidden" name="' .$fieldname.'[unselect]" value="-1" />'; 1338 if ($fieldname == 'targetlist') { 1339 $categoryhtml['all'] .= ' 1340 <li><input type="checkbox" name="'.$fieldname.'[all]"'; 1341 if (!empty($current['all'])) { 1342 $categoryhtml['all'] .= 'checked'; 1343 } 1344 $categoryhtml['all'] .= ' />'.s('All Lists').'</li>'; 1345 1346 $categoryhtml['all'] .= '<li><input type="checkbox" name="'.$fieldname.'[allactive]"'; 1347 if (!empty($current['allactive'])) { 1348 $categoryhtml['all'] .= 'checked="checked"'; 1349 } 1350 $categoryhtml['all'] .= ' />'.s('All Public Lists').'</li>'; 1351 } 1352 1353 //# need a better way to suppress this 1354 if ($_GET['page'] != 'send') { 1355 $categoryhtml['all'] .= '<li>'.PageLinkDialog('addlist', s('Add a list')).'</li>'; 1356 } 1357 1358 $result = Sql_query('select * from '.$GLOBALS['tables']['list'].$subselect.' order by category, name'); 1359 $numLists = Sql_Affected_Rows(); 1360 1361 while ($list = Sql_fetch_array($result)) { 1362 if (empty($list['category'])) { 1363 if ($numLists < 5) { //# for a small number of lists, add them to the @ tab 1364 $list['category'] = 'all'; 1365 } else { 1366 $list['category'] = s('Uncategorised'); 1367 } 1368 } 1369 if (!isset($categoryhtml[$list['category']])) { 1370 $categoryhtml[$list['category']] = ''; 1371 } 1372 if (isset($current[$list['id']]) && $current[$list['id']]) { 1373 $list['category'] = 'selected'; 1374 } 1375 $categoryhtml[$list['category']] .= sprintf('<li><input type="checkbox" name="'.$fieldname.'[%d]" value="%d" ', 1376 $list['id'], $list['id']); 1377 // check whether this message has been marked to send to a list (when editing) 1378 if (isset($current[$list['id']]) && $current[$list['id']]) { 1379 $categoryhtml[$list['category']] .= 'checked'; 1380 } 1381 $categoryhtml[$list['category']] .= ' />'.htmlspecialchars(cleanListName(stripslashes($list['name']))); 1382 if ($list['active']) { 1383 $categoryhtml[$list['category']] .= ' <span class="activelist">'.s('Public list').'</span>'; 1384 } else { 1385 $categoryhtml[$list['category']] .= ' <span class="inactivelist">'.s('Private list').'</span>'; 1386 } 1387 1388 if (!empty($list['description'])) { 1389 $desc = nl2br(stripslashes(disableJavascript($list['description']))); 1390 $categoryhtml[$list['category']] .= "<br />$desc"; 1391 } 1392 $categoryhtml[$list['category']] .= '</li>'; 1393 $some = 1; 1394 } 1395 if (empty($categoryhtml['selected'])) { 1396 unset($categoryhtml['selected']); 1397 } 1398// file_put_contents('/tmp/timer.log','ListOfLists '.$GLOBALS['systemTimer']->interval(). "\n",FILE_APPEND); 1399 return $categoryhtml; 1400} 1401 1402function listSelectHTML($current, $fieldname, $subselect, $alltab = '') 1403{ 1404 $GLOBALS['systemTimer']->interval(); 1405 $categoryhtml = ListofLists($current, $fieldname, $subselect); 1406 1407 $tabno = 1; 1408 $listindex = $listhtml = ''; 1409 $some = count($categoryhtml); 1410 1411 if (!empty($alltab)) { 1412 //&& $some > 1) { 1413 // unset($categoryhtml['all']); 1414 //## @@@TODO this has a weird effect when categories are numbers only eg years, because PHP renumbers them to 0,1,2 1415 // array_unshift($categoryhtml,$alltab); 1416 } 1417 1418 if ($some > 0) { 1419 foreach ($categoryhtml as $category => $content) { 1420 if ($category == 'all') { 1421 $category = '@'; 1422 } 1423/* "if" commented on 2017-5-8 to show tabs always fixing UI bugs on all themes with jQuery in checkboxes. I suggest to remove it permanently. */ 1424// if ($some > 1) { //# don't show tabs, when there's just one 1425 $listindex .= sprintf('<li><a href="#%s%d">%s</a></li>', $fieldname, $tabno, $category); 1426 // } 1427 if ($fieldname == 'targetlist') { 1428 // Add select all checkbox in every category to select all lists in that category. 1429 if ($category == 'selected') { 1430 $content = sprintf('<li class="selectallcategory"><input type="checkbox" name="all-lists-'.$fieldname.'-cat-'.str_replace(' ', 1431 '-', 1432 strtolower($category)).'" checked="checked">'.s('Select all').'</li>').$content; 1433 } elseif ($category != '@') { 1434 $content = sprintf('<li class="selectallcategory"><input type="checkbox" name="all-lists-'.$fieldname.'-cat-'.str_replace(' ', 1435 '-', strtolower($category)).'">'.s('Select all').'</li>').$content; 1436 } 1437 } 1438 $listhtml .= sprintf('<div class="%s" id="%s%d"><ul>%s</ul></div>', 1439 str_replace(' ', '-', strtolower($category)), $fieldname, $tabno, $content); 1440 ++$tabno; 1441 } 1442 } 1443 1444 $html = '<div class="tabbed"><ul>'.$listindex.'</ul>'; 1445 $html .= $listhtml; 1446 $html .= '</div><!-- end of tabbed -->'; //# close tabbed 1447 1448 if (!$some) { 1449 $html = s('There are no lists available'); 1450 } 1451// file_put_contents('/tmp/timer.log','ListSelectHTML '.$GLOBALS['systemTimer']->interval(). "\n",FILE_APPEND); 1452 return $html; 1453} 1454 1455function getSelectedLists($fieldname) 1456{ 1457 $lists = array(); 1458 if (!empty($_POST['addnewlist'])) { 1459 include 'editlist.php'; 1460 $lists[$_SESSION['newlistid']] = $_SESSION['newlistid']; 1461 1462 return $lists; 1463 } 1464 if (!isset($_POST[$fieldname])) { 1465 return array(); 1466 } 1467 if (!empty($_POST[$fieldname]['all'])) { 1468 //# load all lists 1469 $req = Sql_Query(sprintf('select id from %s', $GLOBALS['tables']['list'])); 1470 while ($row = Sql_Fetch_Row($req)) { 1471 $lists[$row[0]] = $row[0]; 1472 } 1473 } elseif (!empty($_POST[$fieldname]['allactive'])) { 1474 //# load all active lists 1475 $req = Sql_Query(sprintf('select id from %s where active', $GLOBALS['tables']['list'])); 1476 while ($row = Sql_Fetch_Row($req)) { 1477 $lists[$row[0]] = $row[0]; 1478 } 1479 } else { 1480 //# verify the lists are actually allowed 1481 $req = Sql_Query(sprintf('select id from %s', $GLOBALS['tables']['list'])); 1482 while ($row = Sql_Fetch_Row($req)) { 1483 if (in_array($row[0], $_POST[$fieldname])) { 1484 $lists[$row[0]] = $row[0]; 1485 } 1486 } 1487 } 1488 1489 return $lists; 1490} 1491 1492function hostName() 1493{ 1494 if (HTTP_HOST) { 1495 return HTTP_HOST; 1496 } elseif (!empty($_SERVER['HTTP_HOST'])) { 1497 return $_SERVER['HTTP_HOST']; 1498 } else { 1499 //# could check SERVER_NAME as well 1500 return getConfig('website'); 1501 } 1502} 1503 1504function Redirect($page) 1505{ 1506 $website = hostName(); 1507 header('Location: '.$GLOBALS['admin_scheme'].'://'.$website.$GLOBALS['adminpages']."/?page=$page"); 1508 exit; 1509} 1510 1511function formatBytes($value) 1512{ 1513 $gb = 1024 * 1024 * 1024; 1514 $mb = 1024 * 1024; 1515 $kb = 1024; 1516 $gbs = $value / $gb; 1517 if ($gbs > 1) { 1518 return sprintf('%2.2fGb', $gbs); 1519 } 1520 $mbs = $value / $mb; 1521 if ($mbs > 1) { 1522 return sprintf('%2.2fMb', $mbs); 1523 } 1524 $kbs = $value / $kb; 1525 if ($kbs > 1) { 1526 return sprintf('%dKb', $kbs); 1527 } else { 1528 return sprintf('%dBytes', $value); 1529 } 1530} 1531 1532function phpcfgsize2bytes($val) 1533{ 1534 $val = trim($val); 1535 $last = mb_strtolower($val[strlen($val) - 1]); 1536 $result = substr($val, 0, -1); 1537 switch ($last) { 1538 case 'g': 1539 $result *= 1024; 1540 case 'm': 1541 $result *= 1024; 1542 case 'k': 1543 $result *= 1024; 1544 } 1545 1546 return $result; 1547} 1548 1549function Help($topic, $text = '?') 1550{ 1551 return sprintf('<a href="help/?topic=%s" class="helpdialog" target="_blank">%s</a>', $topic, $text); 1552} 1553 1554/** 1555 * Checks if the list is private based on if the specified list id is active or not. 1556 * 1557 * @param int $listid 1558 * @return bool 1559 */ 1560function isPrivateList($listid) { 1561 1562 $activeList = Sql_Fetch_Row_Query(sprintf(' 1563 SELECT active 1564 FROM %s 1565 WHERE id = %d', 1566 $GLOBALS['tables']['list'], sql_escape($listid)) 1567 ); 1568 1569 return $activeList[0] == 0; 1570} 1571 1572// Debugging system, needs $debug = TRUE and $verbose = TRUE or $debug_log = {path} in config.php 1573// Hint: When using log make sure the file gets write permissions 1574 1575function dbg($variable, $description = 'Value', $nestingLevel = 0) 1576{ 1577 // smartDebug($variable, $description, $nestingLevel); //TODO Fix before release! 1578// return; 1579 1580 global $config; 1581 1582 if (isset($config['debug']) && !$config['debug']) { 1583 return; 1584 } 1585 1586 if (is_array($variable)) { 1587 $tmp = $variable; 1588 $variable = ''; 1589 foreach ($tmp as $key => $val) { 1590 $variable .= $key.'='.$val.';'; 1591 } 1592 } 1593 1594 $msg = $description.': '.$variable; 1595 1596 if (isset($config['verbose']) && $config['verbose']) { 1597 echo "\n".'DBG: '.$msg.'<br/>'."\n"; 1598 } elseif (isset($config['debug_log']) && $config['debug_log']) { 1599 $fp = @fopen($config['debug_log'], 'a'); 1600 $line = '['.date('d M Y, H:i:s').'] '.$_SERVER['REQUEST_METHOD'].'-'.$_SERVER['REQUEST_URI'].'('.$GLOBALS['pagestats']['number_of_queries'].") $msg \n"; 1601 @fwrite($fp, $line); 1602 @fclose($fp); 1603 // $fp = fopen($config["sql_log"],"a"); 1604 // fwrite($fp,"$line"); 1605 // fclose($fp); 1606 } 1607} 1608 1609function PageData($id) 1610{ 1611 global $tables; 1612 $req = Sql_Query(sprintf('select * from %s where id = %d', $tables['subscribepage_data'], $id)); 1613 if (!Sql_Affected_Rows()) { 1614 $data = array(); 1615 $data['header'] = getConfig('pageheader'); 1616 $data['footer'] = getConfig('pagefooter'); 1617 $data['button'] = 'Subscribe'; 1618 $data['attributes'] = ''; 1619 $req = Sql_Query(sprintf('select * from %s order by listorder', $GLOBALS['tables']['attribute'])); 1620 while ($row = Sql_Fetch_Array($req)) { 1621 $data['attributes'] .= $row['id'].'+'; 1622 $data[sprintf('attribute%03d', $row['id'])] = ''; 1623 foreach (array( 1624 'id', 1625 'default_value', 1626 'listorder', 1627 'required', 1628 ) as $key) { 1629 $data[sprintf('attribute%03d', $row['id'])] .= $row[$key].'###'; 1630 } 1631 } 1632 $data['attributes'] = substr($data['attributes'], 0, -1); 1633 $data['htmlchoice'] = 'checkforhtml'; 1634 $lists = array(); 1635 $req = Sql_Query(sprintf('select * from %s where active order by listorder', $GLOBALS['tables']['list'])); 1636 while ($row = Sql_Fetch_Array($req)) { 1637 array_push($lists, $row['id']); 1638 } 1639 $data['lists'] = implode(',', $lists); 1640 $data['intro'] = $GLOBALS['strSubscribeInfo']; 1641 $data['emaildoubleentry'] = 'yes'; 1642 $data['thankyoupage'] = ''; 1643 foreach ($data as $key => $val) { 1644 $data[$key] = str_ireplace('[organisation_name]', $GLOBALS['organisation_name'], $val); 1645 } 1646 1647 return $data; 1648 } 1649 while ($row = Sql_Fetch_Array($req)) { 1650 if (in_array($row['name'], array( 1651 'title', 1652 'language_file', 1653 'intro', 1654 'header', 1655 'footer', 1656 'thankyoupage', 1657 'button', 1658 'htmlchoice', 1659 'emaildoubleentry', 1660 'ajax_subscribeconfirmation', 1661 ))) { 1662 $data[$row['name']] = stripslashes($row['data']); 1663 } else { 1664 $data[$row['name']] = $row['data']; 1665 } 1666 $data[$row['name']] = preg_replace('/<\?=VERSION\?>/i', VERSION, $data[$row['name']]); 1667 $data[$row['name']] = str_ireplace('[organisation_name]', $GLOBALS['organisation_name'], $data[$row['name']]); 1668 $data[$row['name']] = str_ireplace('[website]', $GLOBALS['website'], $data[$row['name']]); 1669 $data[$row['name']] = str_ireplace('[website]', $GLOBALS['domain'], $data[$row['name']]); 1670 //@@ TODO, add call to plugins here? 1671 } 1672 if (!isset($data['lists'])) { 1673 $data['lists'] = ''; 1674 } 1675 if (!isset($data['emaildoubleentry'])) { 1676 $data['emaildoubleentry'] = ''; 1677 } 1678 if (!isset($data['rssdefault'])) { 1679 $data['rssdefault'] = ''; 1680 } 1681 if (!isset($data['rssintro'])) { 1682 $data['rssintro'] = ''; 1683 } 1684 if (!isset($data['rss'])) { 1685 $data['rss'] = ''; 1686 } 1687 if (!isset($data['lists'])) { 1688 $data['lists'] = ''; 1689 } 1690 1691 return $data; 1692} 1693 1694function PageAttributes($data) 1695{ 1696 $attributes = explode('+', $data['attributes']); 1697 $attributedata = array(); 1698 if (is_array($attributes)) { 1699 foreach ($attributes as $attribute) { 1700 if (isset($data[sprintf('attribute%03d', $attribute)])) { 1701 list($attributedata[$attribute]['id'], $attributedata[$attribute]['default_value'], $attributedata[$attribute]['listorder'], $attributedata[$attribute]['required']) = explode('###', 1702 $data[sprintf('attribute%03d', $attribute)]); 1703 if (!isset($sorted) || !is_array($sorted)) { 1704 $sorted = array(); 1705 } 1706 $sorted[$attributedata[$attribute]['id']] = $attributedata[$attribute]['listorder']; 1707 } 1708 } 1709 if (isset($sorted) && is_array($sorted)) { 1710 $attributes = $sorted; 1711 asort($attributes); 1712 } 1713 } 1714 1715 return array( 1716 $attributes, 1717 $attributedata, 1718 ); 1719} 1720 1721/** 1722 * Return either the short or long representation of a month in the language for the current admin. 1723 * Cache the set of month translations to avoid repeating the translations. 1724 * 1725 * @param string $month month number 01-12 1726 * @param bool $short generate short or long representation of the month 1727 * 1728 * @return string 1729 */ 1730function monthName($month, $short = 0) 1731{ 1732 static $shortmonths; 1733 static $months; 1734 1735 if ($short) { 1736 if ($shortmonths === null) { 1737 $shortmonths = array( 1738 '', 1739 s('Jan'), 1740 s('Feb'), 1741 s('Mar'), 1742 s('Apr'), 1743 s('May'), 1744 s('Jun'), 1745 s('Jul'), 1746 s('Aug'), 1747 s('Sep'), 1748 s('Oct'), 1749 s('Nov'), 1750 s('Dec'), 1751 ); 1752 } 1753 1754 return $shortmonths[(int) $month]; 1755 } 1756 1757 if ($months === null) { 1758 $months = array( 1759 '', 1760 s('January'), 1761 s('February'), 1762 s('March'), 1763 s('April'), 1764 s('May'), 1765 s('June'), 1766 s('July'), 1767 s('August'), 1768 s('September'), 1769 s('October'), 1770 s('November'), 1771 s('December'), 1772 ); 1773 } 1774 1775 return $months[(int) $month]; 1776} 1777 1778/** 1779 * Format a date using a configurable format string. 1780 * d 2-digit day with leading zero 1781 * j day without leading zero 1782 * F long representation of month 1783 * m 2-digit month with leading zero 1784 * n month without leading zero 1785 * M short representation of month 1786 * y 2-digit year 1787 * Y 4-digit year 1788 * Optionally force a short representation to be used for the month. 1789 * 1790 * @param string $date date as YYYY-MM-DD 1791 * @param bool $short force short representation of the month 1792 * 1793 * @return string 1794 */ 1795function formatDate($date, $short = 0) 1796{ 1797 if ($date == '') { 1798 return ''; 1799 } 1800 $format = getConfig('date_format'); 1801 $year = substr($date, 0, 4); 1802 $month = substr($date, 5, 2); 1803 $day = substr($date, 8, 2); 1804 $specifiers = array( 1805 'Y' => $year, 1806 'y' => substr($year, 2, 2), 1807 'F' => monthName($month, $short), 1808 'M' => monthName($month, true), 1809 'm' => $month, 1810 'n' => +$month, 1811 'd' => $day, 1812 'j' => +$day, 1813 ); 1814 $result = strtr($format, $specifiers); 1815 1816 return $result; 1817} 1818 1819function formatTime($time, $short = 0) 1820{ 1821 return $time; 1822} 1823 1824function formatDateTime($datetime, $short = 0) 1825{ 1826 if ($datetime == '') { 1827 return ''; 1828 } 1829 $date = substr($datetime, 0, 10); 1830 $time = substr($datetime, 11, 8); 1831 1832 return formatDate($date, $short).' '.formatTime($time, $short); 1833} 1834 1835$oldestpoweredimage = 'iVBORw0KGgoAAAANSUhEUgAAAFgAAAAfCAMAAABUFvrSAAAABGdBTUEAALGPC/xhBQAAAMBQTFRFmQAAZgAAmgICmwUFnAgInQsLnxAQbw4OohYWcBERpBwcpiIiqCcnqiwsfCAgrDAwrjU1rzg4sTs7iTAws0FBtEVFtklJuU9Pu1VVn0pKkEREvltbtFxcwWRkw2trm1ZWrGNjx3V1y3x8zoWFqW5u0I6O15ycuoqK3aysxZqa3rm55s3N8t3d9+zs+fHx5t/f/Pf3/fr6////7+/vz8/PtbW1j4+Pb29vVVVVRkZGKioqExMTDg4OBwcHAwMDAAAAB4LGQwAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfSBAITGhB/UY5ZAAAD2ElEQVR4nI2VC3uiOhCGoVqq9YbcZHGxIoI0SLGhIJdt8///1c4kHnVPhTpPK4TPvEzmpkTvsiK/73vckmAuSdJ93/26G5wEhsQN7uuaVTSrWP1BGT1WtCpgUWUf7FhVX1WWVZ/Hz/Qu6ltoSf8ZLFnxwfKypPBXZ02dsrQss7oovnJ+PZa0au6gHqJFT5KuwDmjGctZzp09lux4pF911RRFTT/x+geU8ifqe2T3pX8MEsM+ioY2BThHyyavm5TWRQbhKMS1KVJQOo24ivR/o/RY101Oi4Yd4SUVBoTmNaCqnOYV0POqKLtyR7zBNyoHVz+402nxZqI83uIi+KdSWjtOfFPYh+boeaB8D4N0Xx3LsnzjaRK5hqZOkNwK7u4rIsv6Nyrxl0t7YRmc3ApmneCdLK//efAWhxvPW63cpc3JreCU1QyrNj/31+tul5K1s+brtSzv0p3j7IS0ffHW+lT3kO3aljYbP7eBcyhk6BAKnXGJ6gv8y0NMmg4eD3G1pe97iIvs4OIpCjbearkw1PGoDQzFm7OU5U124sbI3G6HIriIcXY6pnAf+VzCF+kHCIhrm/NJK7iqM+gKdmmvV+Er8hPMHcY44bURrbn0HqGU+OAyxKIV3JQweWh9dphu8dgiCARzNwXujrsfvfCIkGiKUrBBsMvnpAl4xTThBm10qeO8uTQgBDE+XQkF1I4eyBr9fiM6SntC+DsjDqY+d9CTzAQcmHGCdwFX58xdOmKIlClHRQ7yee4gRoQ84VMOnp/BJFaUfcRvpZudF5/AcB2eYns6+z4QKxKgREOevDPYo6E7kjrAkDtw57B38PTgowOIULi65RIhXDpAVUC5ncGSBwF0O8C4W08xqk+pSOQ+XInc/bqWYlEUZ7BtSkpEO8DgzlTm9koPOn7G/i90MQn1a8kX/UFDKAMe48S2430b+BDjqVNsvCmBcPIERp6OuYuDaykCLrYH34a0WQTBmt0EH8hm6f7mhRu8QsCSEGYNFJHvuitYktW15AJX6x6bwt7JSlWNxRJO/ULf/E0QBjDAwGy05dJdeSfJ55INXJhAg9ZfEGHEfVaexzPNssWpcSyCTwvLsngvWQt76QqJzzUcmXPO7QLHq4H00FcGo8ncsHjFRq4Y5NocTFXVuWYAWkh8EoO76onbbwHHHh+oCAaX54aubxPqA9U0tNlsMpmMwSYzVTNMIeErTXCXx/fxsd+7Cd6MTzcPvcfBYIRkKwxD2KnB1vFo9CxsNJ6A2yZItmWdNOT2+73b4LMBGFzG/RrYXBU7uSkKfKA0UyEwVyJwe72Hh1u4v1tVRVPPqSx/AAAAAElFTkSuQmCC'; 1836$olderpoweredimage = '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'; 1837$oldpoweredimage = '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'; 1838$newpoweredimage = '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'; 1839 1840function FileNotFound($msg = '') 1841{ 1842 ob_end_clean(); 1843 header('HTTP/1.0 404 File Not Found', true, 404); 1844 if (defined('ERROR404PAGE') && is_file($_SERVER['DOCUMENT_ROOT'].'/'.ERROR404PAGE)) { 1845 echo file_get_contents($_SERVER['DOCUMENT_ROOT'].'/'.ERROR404PAGE); 1846 exit; 1847 } 1848 1849 printf('<html><head><title>404 Not Found</title></head><body><h1>Not Found</h1>The requested document was not found on this server<br/>%s<br/>Please contact the <a href="mailto:%s?subject=File not Found: %s">Administrator</a><p><hr><address><a href="http://phplist.com" target="_phplist">phpList</a> version %s</address></body></html>', 1850 $msg, getConfig('admin_address'), 1851 strip_tags($_SERVER['REQUEST_URI']), VERSION); 1852 exit; 1853} 1854 1855function findMime($filename) 1856{ 1857 list($name, $ext) = explode('.', $filename); 1858 if (!$ext || !is_file(MIMETYPES_FILE)) { 1859 return DEFAULT_MIMETYPE; 1860 } 1861 $fp = @fopen(MIMETYPES_FILE, 'r'); 1862 $contents = fread($fp, filesize(MIMETYPES_FILE)); 1863 fclose($fp); 1864 $lines = explode("\n", $contents); 1865 foreach ($lines as $line) { 1866 if (!preg_match("/^\s*#/", $line) && !preg_match("/^\s*$/", $line)) { 1867 $line = preg_replace("/\t/", ' ', $line); 1868 $items = explode(' ', $line); 1869 $mime = array_shift($items); 1870 foreach ($items as $extension) { 1871 $extension = trim($extension); 1872 if ($ext == $extension) { 1873 return $mime; 1874 } 1875 } 1876 } 1877 } 1878 1879 return DEFAULT_MIMETYPE; 1880} 1881 1882function excludedDateForRepetition($date) 1883{ 1884 if (!is_array($GLOBALS['repeat_exclude'])) { 1885 return 0; 1886 } 1887 foreach ($GLOBALS['repeat_exclude'] as $exclusion) { 1888 $formatted_value = Sql_Fetch_Row_Query(sprintf('select date_format("%s","%s")', $date, $exclusion['format'])); 1889 foreach ($exclusion['values'] as $disallowed) { 1890 if ($formatted_value[0] == $disallowed) { 1891 return 1; 1892 } 1893 } 1894 } 1895 1896 return 0; 1897} 1898 1899function delimited($data) 1900{ 1901 $delimitedData = ''; 1902 reset($data); 1903 foreach ($data as $key => $val) { 1904 $delimitedData .= $key.'KEYVALSEP'.$val.'ITEMSEP'; 1905 } 1906 $length = strlen($delimitedData); 1907 1908 return substr($delimitedData, 0, -7); 1909} 1910 1911function parseDelimitedData($value) 1912{ 1913 $data = array(); 1914 $rawdata = explode('ITEMSEP', $value); 1915 foreach ($rawdata as $item) { 1916 list($key, $val) = explode('KEYVALSEP', $item); 1917 $data[$key] = ltrim($val); 1918 } 1919 1920 return $data; 1921} 1922 1923function repeatMessage($msgid) 1924{ 1925 // if (!USE_REPETITION && !USE_rss) return; 1926 1927 $data = loadMessageData($msgid); 1928 //# do not repeat when it has already been done 1929 if ($data['repeatinterval'] == 0 || !empty($data['repeatedid'])) { 1930 return; 1931 } 1932 1933 // calculate the future embargo, a multiple of repeatinterval minutes after the current embargo 1934 1935 $msgdata = Sql_Fetch_Array_Query( 1936 sprintf( 1937 'SELECT *, 1938 embargo + 1939 INTERVAL (FLOOR(TIMESTAMPDIFF(MINUTE, embargo, GREATEST(embargo, NOW())) / repeatinterval) + 1) * repeatinterval MINUTE AS newembargo 1940 FROM %s 1941 WHERE id = %d AND now() < repeatuntil', 1942 $GLOBALS['tables']['message'], 1943 $msgid 1944 ) 1945 ); 1946 1947 if (!$msgdata) { 1948 logEvent("Message $msgid not repeated due to reaching the repeatuntil date"); 1949 1950 return; 1951 } 1952 1953 // check whether the new embargo is not on an exclusion 1954 if (isset($GLOBALS['repeat_exclude']) && is_array($GLOBALS['repeat_exclude'])) { 1955 $loopcnt = 0; 1956 1957 while (excludedDateForRepetition($msgdata['newembargo'])) { 1958 if (++$loopcnt > 15) { 1959 logEvent("Unable to find new embargo date too many exclusions? for message $msgid"); 1960 1961 return; 1962 } 1963 $result = Sql_Fetch_Array_Query( 1964 sprintf( 1965 "SELECT '%s' + INTERVAL repeatinterval MINUTE AS newembargo 1966 FROM %s 1967 WHERE id = %d", 1968 $msgdata['newembargo'], 1969 $GLOBALS['tables']['message'], 1970 $msgid 1971 ) 1972 ); 1973 $msgdata['newembargo'] = $result['newembargo']; 1974 } 1975 } 1976 1977 // copy the new message 1978 Sql_Query(sprintf(' 1979 insert into %s (entered) values(now())', $GLOBALS['tables']['message'])); 1980 $newid = Sql_Insert_id(); 1981 require dirname(__FILE__).'/structure.php'; 1982 if (!is_array($DBstruct['message'])) { 1983 logEvent("Error including structure when trying to duplicate message $msgid"); 1984 1985 return; 1986 } 1987 1988 // Do not copy columns that use default values or are explicitly set, or indices 1989 $columnsToCopy = array_diff( 1990 array_keys($DBstruct['message']), 1991 array( 1992 'id', 'entered', 'modified', 'embargo', 'status', 'sent', 'processed', 'astext', 'ashtml', 1993 'astextandhtml', 'aspdf', 'astextandpdf', 'viewed', 'bouncecount', 'sendstart', 'uuid', 1994 ) 1995 ); 1996 $columnsToCopy = preg_grep('/^index_/', $columnsToCopy, PREG_GREP_INVERT); 1997 1998 foreach ($columnsToCopy as $column) { 1999 Sql_Query(sprintf('update %s set %s = "%s" where id = %d', 2000 $GLOBALS['tables']['message'], $column, addslashes($msgdata[$column]), $newid)); 2001 } 2002 Sql_Query(sprintf( 2003 'update %s set embargo = "%s",status = "submitted", uuid="%s" where id = %d', 2004 $GLOBALS['tables']['message'], 2005 $msgdata['newembargo'], 2006 (string) UUID::generate(4), 2007 $newid 2008 )); 2009 2010 // copy rows in messagedata except those that are explicitly set 2011 $req = Sql_Query(sprintf( 2012 "SELECT * 2013 FROM %s 2014 WHERE id = %d AND name NOT IN ('id', 'embargo', 'finishsending')", 2015 $GLOBALS['tables']['messagedata'], $msgid 2016 )); 2017 while ($row = Sql_Fetch_Array($req)) { 2018 setMessageData($newid, $row['name'], $row['data']); 2019 } 2020 2021 list($e['year'], $e['month'], $e['day'], $e['hour'], $e['minute'], $e['second']) = 2022 sscanf($msgdata['newembargo'], '%04d-%02d-%02d %02d:%02d:%02d'); 2023 unset($e['second']); 2024 setMessageData($newid, 'embargo', $e); 2025 2026 $finishSending = time() + DEFAULT_MESSAGEAGE; 2027 $finish = array( 2028 'year' => date('Y', $finishSending), 2029 'month' => date('m', $finishSending), 2030 'day' => date('d', $finishSending), 2031 'hour' => date('H', $finishSending), 2032 'minute' => date('i', $finishSending), 2033 ); 2034 setMessageData($newid, 'finishsending', $finish); 2035 2036 // lists 2037 $req = Sql_Query(sprintf('select listid from %s where messageid = %d', $GLOBALS['tables']['listmessage'], $msgid)); 2038 while ($row = Sql_Fetch_Row($req)) { 2039 Sql_Query(sprintf('insert into %s (messageid,listid,entered) values(%d,%d,now())', 2040 $GLOBALS['tables']['listmessage'], $newid, $row[0])); 2041 } 2042 2043 // attachments 2044 $req = Sql_Query(sprintf('select * from %s,%s where %s.messageid = %d and %s.attachmentid = %s.id', 2045 $GLOBALS['tables']['message_attachment'], $GLOBALS['tables']['attachment'], 2046 $GLOBALS['tables']['message_attachment'], $msgid, $GLOBALS['tables']['message_attachment'], 2047 $GLOBALS['tables']['attachment'])); 2048 while ($row = Sql_Fetch_Array($req)) { 2049 if (is_file($row['remotefile'])) { 2050 // if the "remote file" is actually local, we want to refresh the attachment, so we set 2051 // filename to nothing 2052 $row['filename'] = ''; 2053 } 2054 2055 Sql_Query(sprintf('insert into %s (filename,remotefile,mimetype,description,size) 2056 values("%s","%s","%s","%s",%d)', 2057 $GLOBALS['tables']['attachment'], addslashes($row['filename']), addslashes($row['remotefile']), 2058 addslashes($row['mimetype']), addslashes($row['description']), $row['size'])); 2059 $attid = Sql_Insert_id(); 2060 Sql_Query(sprintf('insert into %s (messageid,attachmentid) values(%d,%d)', 2061 $GLOBALS['tables']['message_attachment'], $newid, $attid)); 2062 } 2063 logEvent("Message $msgid was successfully rescheduled as message $newid"); 2064 //# remember we duplicated, in order to avoid doing it again (eg when requeuing) 2065 setMessageData($msgid, 'repeatedid', $newid); 2066 if (getConfig('pqchoice') == 'phplistdotcom') { 2067 activateRemoteQueue(); 2068 } 2069} 2070 2071function versionCompare($thisversion, $latestversion) 2072{ 2073 // return 1 if $thisversion is larger or equal to $latestversion 2074 2075 list($major1, $minor1, $sub1) = sscanf($thisversion, '%d.%d.%d'); 2076 list($major2, $minor2, $sub2) = sscanf($latestversion, '%d.%d.%d'); 2077 if ($major1 > $major2) { 2078 return 1; 2079 } 2080 if ($major1 == $major2 && $minor1 > $minor2) { 2081 return 1; 2082 } 2083 if ($major1 == $major2 && $minor1 == $minor2 && $sub1 >= $sub2) { 2084 return 1; 2085 } 2086 2087 return 0; 2088} 2089 2090function cleanArray($array) 2091{ 2092 $result = array(); 2093 if (!is_array($array)) { 2094 return $array; 2095 } 2096 foreach ($array as $key => $val) { 2097 //# 0 is a valid key 2098 if (isset($key) && !empty($val)) { 2099 $result[$key] = $val; 2100 } 2101 } 2102 2103 return $result; 2104} 2105 2106function cl_processtitle($title) 2107{ 2108 $title = preg_replace('/[^\w-]/', '', $title); 2109 if (function_exists('cli_set_process_title')) { // PHP5.5 and up 2110 cli_set_process_title('phpList:'.$GLOBALS['installation_name'].':'.$title); 2111 } elseif (function_exists('setproctitle')) { // pecl extension 2112 setproctitle('phpList:'.$GLOBALS['installation_name'].':'.$title); 2113 } 2114} 2115 2116function cl_output($message) 2117{ 2118 if (!empty($GLOBALS['commandline'])) { 2119 @ob_end_clean(); 2120 echo $GLOBALS['installation_name'].' - '.strip_tags($message)."\n"; 2121 @ob_start(); 2122 } 2123} 2124 2125function cl_progress($message) 2126{ 2127 if ($GLOBALS['commandline']) { 2128 @ob_end_clean(); 2129 echo $GLOBALS['installation_name'].' - '.strip_tags($message)."\r"; 2130 @ob_start(); 2131 } 2132} 2133 2134function phplist_shutdown() 2135{ 2136 // output( "Script status: ".connection_status(),0); # with PHP 4.2.1 buggy. http://bugs.php.net/bug.php?id=17774 2137 $status = connection_status(); 2138 if ($GLOBALS['mail_error_count']) { 2139 $message = "Some errors occurred in the phpList Mailinglist System\n" 2140 .'URL: '.$GLOBALS['admin_scheme'].'://'.hostName()."{$_SERVER['REQUEST_URI']}\n" 2141 ."Error message(s):\n\n" 2142 2143 .$GLOBALS['mail_error']; 2144 $message .= "\n==== debugging information\n\nSERVER Vars\n"; 2145 if (is_array($_SERVER)) { 2146 foreach ($_SERVER as $key => $val) { 2147 if (stripos($key, 'password') === false) { 2148 $message .= $key.'='.serialize($val)."\n"; 2149 } 2150 } 2151 } 2152 foreach ($GLOBALS['plugins'] as $pluginname => $plugin) { 2153 $plugin->processError($message); 2154 } 2155// sendMail(getConfig("report_address"),$GLOBALS["installation_name"]." Mail list error",$message); 2156 } 2157 2158// print "Phplist shutdown $status"; 2159// exit; 2160} 2161 2162function trimArray($array) 2163{ 2164 $result = array(); 2165 if (!is_array($array)) { 2166 return $array; 2167 } 2168 foreach ($array as $key => $val) { 2169 $testval = trim($val); 2170 if (isset($key) && !empty($testval)) { 2171 $result[$key] = $val; 2172 } 2173 } 2174 2175 return $result; 2176} 2177 2178register_shutdown_function('phplist_shutdown'); 2179 2180function secs2time($secs) 2181{ 2182 $years = $days = $hours = $mins = 0; 2183 $hours = (int) ($secs / 3600); 2184 $secs = $secs - ($hours * 3600); 2185 if ($hours > 24) { 2186 $days = (int) ($hours / 24); 2187 $hours = $hours - (24 * $days); 2188 } 2189 if ($days > 365) { //# a well, an estimate 2190 $years = (int) ($days / 365); 2191 $days = $days - ($years * 365); 2192 } 2193 $mins = (int) ($secs / 60); 2194 $secs = (int) ($secs % 60); 2195 2196 $format = compact('years', 'days', 'hours', 'mins'); 2197 2198 $output = ''; 2199 2200 foreach($format as $unit => $value) { 2201 if ($value > 0) { 2202 $output .= ' '.$value.' '.s($unit); 2203 } 2204 } 2205 2206 if ($secs) { 2207 $output .= ' '.sprintf('%02d', $secs).' '.s('secs'); 2208 } 2209 2210 return $output; 2211} 2212 2213function listPlaceHolders() 2214{ 2215 $html = '<table border="1"><tr><td><strong>'.s('Attribute').'</strong></td><td><strong>'.s('Placeholder').'</strong></td></tr>'; 2216 $req = Sql_query(' 2217 select 2218 name 2219 from 2220 '.$GLOBALS['tables']['attribute'].' 2221 order by 2222 listorder 2223 '); 2224 while ($row = Sql_Fetch_Row($req)) { 2225 if (strlen($row[0]) <= 30) { 2226 $html .= sprintf('<tr><td>%s</td><td>[%s]</td></tr>', $row[0], strtoupper(cleanAttributeName($row[0]))); 2227 } 2228 } 2229 $html .= '</table>'; 2230 2231 return $html; 2232} 2233 2234//# clean out chars that make preg choke 2235//# primarily used for parsing the placeholders in emails. 2236function cleanAttributeName($name) 2237{ 2238 $name = str_replace('(', '', $name); 2239 $name = str_replace(')', '', $name); 2240 $name = str_replace('/', '', $name); 2241 $name = str_replace('\\', '', $name); 2242 $name = str_replace('*', '', $name); 2243 $name = str_replace('.', '', $name); 2244 2245 return $name; 2246} 2247 2248function cleanCommaList($sList) 2249{ 2250 if (strpos($sList, ',') === false) { 2251 return $sList; 2252 } 2253 $aList = explode(',', $sList); 2254 2255 return implode(',', trimArray($aList)); 2256} 2257 2258function printobject($object) 2259{ 2260 if (!is_object($object)) { 2261 echo 'Not an object'; 2262 2263 return; 2264 } 2265 $class = get_class($object); 2266 echo "Class: $class<br/>"; 2267 $vars = get_object_vars($object); 2268 echo 'Vars:'; 2269 printArray($vars); 2270} 2271 2272function printarray($array) 2273{ 2274 if (is_object($array)) { 2275 return printObject($array); 2276 } 2277 if (!is_array($array)) { 2278 return; 2279 } 2280 foreach ($array as $key => $value) { 2281 if (is_array($value)) { 2282 echo $key.'(array):<blockquote>'; 2283 printarray($value); //recursief!! 2284 echo '</blockquote>'; 2285 } elseif (is_object($value)) { 2286 echo $key.'(object):<blockquote>'; 2287 printobject($value); 2288 echo '</blockquote>'; 2289 } else { 2290 echo $key.'==>'.$value.'<br />'; 2291 } 2292 } 2293} 2294 2295function simplePaging($baseurl, $start, $total, $numpp, $itemname = '') 2296{ 2297 $start = max(0, $start); 2298 $end = min($total, $start + $numpp); 2299 2300 if (!empty($itemname)) { 2301 $text = $GLOBALS['I18N']->get('Listing %d to %d of %d'); 2302 } else { 2303 $text = $GLOBALS['I18N']->get('Listing %d to %d'); 2304 } 2305 $listing = sprintf($text, $start + 1, $end, $total).' '.$itemname; 2306 2307 if ($total < $numpp) { 2308 return $listing; 2309 } 2310 // The last page displays the remaining items 2311 $remainingItems = $total % $numpp; 2312 2313 if ($remainingItems == 0) { 2314 $remainingItems = $numpp; 2315 } 2316 $startLast = $total - $remainingItems; 2317 2318 return '<div class="paging"> 2319 <p class="range">' .$listing.'</p><div class="controls"> 2320 <a title="' .$GLOBALS['I18N']->get('First Page').'" class="first" href="'.PageUrl2($baseurl.'&start=0').'"></a> 2321 <a title="' .$GLOBALS['I18N']->get('Previous').'" class="previous" href="'.PageUrl2($baseurl.sprintf('&start=%d', 2322 max(0, $start - $numpp))).'"></a> 2323 <a title="' .$GLOBALS['I18N']->get('Next').'" class="next" href="'.PageUrl2($baseurl.sprintf('&start=%d', 2324 min($startLast, $start + $numpp))).'"></a> 2325 <a title="' .$GLOBALS['I18N']->get('Last Page').'" class="last" href="'.PageUrl2($baseurl.sprintf('&start=%d', 2326 $startLast)).'"></a> 2327 </div></div> 2328 '; 2329} 2330 2331function Paging($base_url, $start, $total, $numpp = 10, $label = '') 2332{ 2333 $page = 1; 2334 $window = 8; //# size left and right of current 2335 $data = ''; //PagingPrevious($base_url,$start,$total,$numpp,$label);#.' | '; 2336 if (!isset($GLOBALS['config']['paginglabeltitle'])) { 2337 $labeltitle = $label; 2338 } else { 2339 $labeltitle = $GLOBALS['config']['paginglabeltitle']; 2340 } 2341 if ($total < $numpp) { 2342 return ''; 2343 } 2344 2345 for ($i = 0; $i <= $total; $i += $numpp) { 2346 if ($i == $start) { 2347 $data .= sprintf('<a class="current paging-item" title="%s %s" class="paging-item">%s%s</a>', $labeltitle, 2348 $page, $label, $page); 2349 } //# only show 5 left and right of current 2350 elseif ($i > $start - $window * $numpp && $i < $start + $window * $numpp) { 2351 // else 2352 $data .= sprintf('<a href="%s&s=%d" title="%s %s" rel="nofollow" class="paging-item">%s%s</a>', 2353 $base_url, $i, $labeltitle, $page, $label, $page); 2354 } 2355 ++$page; 2356 } 2357 if ($page == 1) { 2358 return ''; 2359 } 2360 // $data .= PagingNext($base_url,$start,$total,$numpp,$label,$page); 2361 return '<div class="paging">'.PagingPrevious($base_url, $start, $total, $numpp, 2362 $label).'<div class="items">'.$data.'</div>'.PagingNext($base_url, $start, $total, $numpp, 2363 $label).'</div>'; 2364 2365 return '<div class="paging"><a class="prev browse left"><<</a><div class="items">'.$data.'</div><a class="next browse right">>></a></div>'; 2366} 2367 2368function PagingNext($base_url, $start, $total, $numpp, $label = '') 2369{ 2370 if (!isset($GLOBALS['config']['pagingnext'])) { 2371 $GLOBALS['config']['pagingnext'] = '>>'; 2372 } 2373 if (($start + $numpp - 1) < $total) { 2374 $data = sprintf('<a href="%s&s=%d" title="Next" class="pagingnext paging-item" rel="nofollow">%s</a>', 2375 $base_url, $start + $numpp, $GLOBALS['config']['pagingnext']); 2376 } else { 2377 $data = sprintf('<a class="pagingnext paging-item">%s</a>', $GLOBALS['config']['pagingnext']); 2378 } 2379 2380 return $data; 2381} 2382 2383function PagingPrevious($base_url, $start, $total, $numpp, $label = '') 2384{ 2385 if (!isset($GLOBALS['config']['pagingback'])) { 2386 $GLOBALS['config']['pagingback'] = '<<'; 2387 } 2388 $page = 1; 2389 if ($start > 1) { 2390 $data = sprintf('<a href="%s&s=%d" title="Previous" class="pagingprevious paging-item" rel="nofollow">%s</a>', 2391 $base_url, $start - $numpp, $GLOBALS['config']['pagingback']); 2392 } else { 2393 $data = sprintf('<a class="pagingprevious paging-item">%s</a>', $GLOBALS['config']['pagingback']); 2394 } 2395 2396 return $data; 2397} 2398 2399class timer 2400{ 2401 public $start; 2402 public $previous = 0; 2403 2404 public function __construct() 2405 { 2406 $now = gettimeofday(); 2407 $this->start = $now['sec'] * 1000000 + $now['usec']; 2408 } 2409 2410 public function elapsed($seconds = 0) 2411 { 2412 $now = gettimeofday(); 2413 $end = $now['sec'] * 1000000 + $now['usec']; 2414 $elapsed = $end - $this->start; 2415 if ($seconds) { 2416 return sprintf('%0.10f', $elapsed / 1000000); 2417 } else { 2418 return sprintf('%0.10f', $elapsed); 2419 } 2420 } 2421 2422 public function interval($seconds = 0) 2423 { 2424 $now = gettimeofday(); 2425 $end = $now['sec'] * 1000000 + $now['usec']; 2426 if (!$this->previous) { 2427 $elapsed = $end - $this->start; 2428 } else { 2429 $elapsed = $end - $this->previous; 2430 } 2431 $this->previous = $end; 2432 2433 if ($seconds) { 2434 return sprintf('%0.10f', $elapsed / 1000000); 2435 } else { 2436 return sprintf('%0.10f', $elapsed); 2437 } 2438 } 2439} 2440