diff --git a/tags/zentaopms_0.5.0_beta_20100221/Makefile b/tags/zentaopms_0.5.0_beta_20100221/Makefile new file mode 100644 index 0000000000..48283cc45e --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/Makefile @@ -0,0 +1,31 @@ +VERSION=$(shell head -n 1 VERSION) + +all: tgz + +clean: + rm -fr pms + rm -fr *.tar.gz + rm -fr *.zip +tgz: + mkdir -p pms/lib + mkdir -p pms/db + mkdir -p pms/bin + mkdir -p pms/config + cp -fr db pms/ + cp -fr doc/* pms/ + cp -fr lib/ pms/ + cp -fr config/config.php pms/config/ + cp -fr www pms/ + cp -fr module pms/ + cp bin/computeburn.php pms/bin + find pms -name .svn |xargs rm -fr + find pms -name tests |xargs rm -fr + mkdir -p pms/tmp/cache + mkdir -p pms/tmp/log + chmod 777 -R pms/tmp/ + tar czvf ZenTaoPMS.$(VERSION).tar.gz pms + zip -r -9 ZenTaoPMS.$(VERSION).zip pms + rm -fr pms +pmsdoc: + phpdoc -d config,lib,module,www -t zentaopms -o HTML:frames:phphtmllib -ti ZenTaoPMSAPI参考手册 -s on -pp on -i *test* + phpdoc -d config,lib,module,www -t zentaopms.chm -o chm:default:default -ti ZenTaoPMSAPI参考手册 -s on -pp on -i *test* diff --git a/tags/zentaopms_0.5.0_beta_20100221/VERSION b/tags/zentaopms_0.5.0_beta_20100221/VERSION new file mode 100644 index 0000000000..92c30a097e --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/VERSION @@ -0,0 +1 @@ +0.5.beta diff --git a/tags/zentaopms_0.5.0_beta_20100221/bin/computeburn.php b/tags/zentaopms_0.5.0_beta_20100221/bin/computeburn.php new file mode 100644 index 0000000000..232e0b13a4 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/bin/computeburn.php @@ -0,0 +1,41 @@ +#!/usr/bin/env php += CURRENT_DATE() OR end = '0000-00-00'"); +while($row = mysql_fetch_assoc($result)) $projects[] = $row['id']; + +/* 璁$畻burndown銆*/ +$date = date('Y-m-d'); +$sql = "SELECT project, sum(`left`) AS totalLeft, SUM(consumed) AS totalConsumed FROM $tableTask + WHERE project IN(" . join(',', $projects) . ') AND status !="cancel" GROUP BY project'; +$result = mysql_query($sql) or die(mysql_error()); +while($row = mysql_fetch_assoc($result)) +{ + $sql = "REPLACE INTO $tableBurn VALUES($row[project], '$date', $row[totalLeft], $row[totalConsumed])"; + mysql_query($sql); +} +?> diff --git a/tags/zentaopms_0.5.0_beta_20100221/bin/copylang.php b/tags/zentaopms_0.5.0_beta_20100221/bin/copylang.php new file mode 100755 index 0000000000..bb1290c434 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/bin/copylang.php @@ -0,0 +1,12 @@ +#!/usr/bin/env php + diff --git a/tags/zentaopms_0.5.0_beta_20100221/bin/exportactions.php b/tags/zentaopms_0.5.0_beta_20100221/bin/exportactions.php new file mode 100644 index 0000000000..3bf58bdd0b --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/bin/exportactions.php @@ -0,0 +1,29 @@ +getMethods(); + foreach($methods as $method) + { + $methodRef = new ReflectionMethod($method->class, $method->name); + if($methodRef->isPublic() and strpos($method->name, '__') === false) + { + echo "\$lang['action']['$moduleName']['$method->name'] = '$method->name';\n"; + } + } + echo "\n"; + } + } +} +?> diff --git a/tags/zentaopms_0.5.0_beta_20100221/config/config.php b/tags/zentaopms_0.5.0_beta_20100221/config/config.php new file mode 100644 index 0000000000..0050a00aab --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/config/config.php @@ -0,0 +1,98 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package ZenTaoMS + * @version $Id$ + * @link http://www.zentao.cn + */ +$config->version = '0.5 beta'; // 版本号,切勿修改。 +$config->encoding = 'UTF-8'; // 网站的编码。 +$config->cookiePath = '/'; // cookie的有效路径。 +$config->cookieLife = time() + 2592000; // cookie的生命周期。 + +$config->requestType = 'PATH_INFO'; // 如何获取当前请求的信息,可选值:PATH_INFO|GET +$config->pathType = 'clean'; // requestType=PATH_INFO: 请求url的格式,可选值为full|clean,full格式会带有参数名称,clean则只有取值。 +$config->requestFix = '-'; // requestType=PATH_INFO: 请求url的分隔符,可选值为斜线、下划线、减号。后面两种形式有助于SEO。 +$config->moduleVar = 'm'; // requestType=GET: 模块变量名。 +$config->methodVar = 'f'; // requestType=GET: 方法变量名。 +$config->viewVar = 't'; // requestType=GET: 模板变量名。 + +$config->views = ',html,'; // 支持的视图列表。 +$config->langs = 'zh-cn'; // 支持的语言列表。 +$config->themes = 'default'; // 支持的主题列表。 + +$config->super2OBJ = true; // 是否通过对象来访问全局变量。 + +$config->default->view = 'html'; // 默认的视图格式。 +$config->default->lang = 'zh-cn'; // 默认的语言。 +$config->default->theme = 'default'; // 默认的主题。 +$config->default->module = 'index'; // 默认的模块。当请求中没有指定模块时,加载该模块。 +$config->default->method = 'index'; // 默认的方法。当请求中没有指定方法或者指定的方法不存在时,调用该方法。 + +$config->file->dangers = 'php,jsp,py,rb,asp,'; // 不允许上传的文件类型列表。 +$config->file->maxSize = 1024 * 1024; // 允许上传的文件大小,单位为字节。 + +$config->db->persistant = false; // 是否打开持久连接。 +$config->db->driver = 'mysql'; // pdo的驱动类型,目前暂时只支持mysql。 +$config->db->dao = true; // 是否使用DAO。 +$config->db->encoding = 'UTF8'; // 数据库的编码。 +$config->db->strictMode = false; // 关闭MySQL的严格模式。 + +/* 包含自定义配置文件。*/ +$myConfig = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'my.php'; +if(file_exists($myConfig)) include $myConfig; +if(!isset($config->db->prefix)) $config->db->prefix = 'zt_'; + +/* 数据表的定义。*/ +define('TABLE_COMPANY', $config->db->prefix . 'company'); +define('TABLE_DEPT', $config->db->prefix . 'dept'); +define('TABLE_CONFIG', $config->db->prefix . 'config'); +define('TABLE_USER', $config->db->prefix . 'user'); +define('TABLE_TODO', $config->db->prefix . 'todo'); +define('TABLE_GROUP', $config->db->prefix . 'group'); +define('TABLE_GROUPPRIV', $config->db->prefix . 'groupPriv'); +define('TABLE_USERGROUP', $config->db->prefix . 'userGroup'); + +define('TABLE_BUG', $config->db->prefix . 'bug'); +define('TABLE_CASE', $config->db->prefix . 'case'); +define('TABLE_CASESTEP', $config->db->prefix . 'caseStep'); +define('TABLE_TESTTASK', $config->db->prefix . 'testTask'); +define('TABLE_TESTRUN', $config->db->prefix . 'testRun'); +define('TABLE_TESTRESULT', $config->db->prefix . 'testResult'); + +define('TABLE_PRODUCT', $config->db->prefix . 'product'); +define('TABLE_STORY', $config->db->prefix . 'story'); +define('TABLE_STORYSPEC', $config->db->prefix . 'storySpec'); +define('TABLE_PRODUCTPLAN', $config->db->prefix . 'productPlan'); +define('TABLE_RELEASE', $config->db->prefix . 'release'); + +define('TABLE_PROJECT', $config->db->prefix . 'project'); +define('TABLE_TASK', $config->db->prefix . 'task'); +define('TABLE_TEAM', $config->db->prefix . 'team'); +define('TABLE_PROJECTPRODUCT', $config->db->prefix . 'projectProduct'); +define('TABLE_PROJECTSTORY', $config->db->prefix . 'projectStory'); +define('TABLE_TASKESTIMATE', $config->db->prefix . 'taskEstimate'); +define('TABLE_EFFORT', $config->db->prefix . 'effort'); +define('TABLE_BURN', $config->db->prefix . 'burn'); +define('TABLE_BUILD', $config->db->prefix . 'build'); + +define('TABLE_MODULE', $config->db->prefix . 'module'); +define('TABLE_ACTION', $config->db->prefix . 'action'); +define('TABLE_FILE', $config->db->prefix . 'file'); +define('TABLE_HISTORY', $config->db->prefix . 'history'); diff --git a/tags/zentaopms_0.5.0_beta_20100221/db/update0.1.sql b/tags/zentaopms_0.5.0_beta_20100221/db/update0.1.sql new file mode 100644 index 0000000000..23556d395e --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/db/update0.1.sql @@ -0,0 +1,152 @@ +-- story浼樺厛绾х殑榛樿鍊笺 +ALTER TABLE `zt_story` CHANGE `pri` `pri` TINYINT( 3 ) UNSIGNED NOT NULL DEFAULT '3' + +-- 淇敼project code瀛楁鐨勯暱搴︺ +ALTER TABLE `zt_project` CHANGE `code` `code` VARCHAR( 20 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL + +-- task 鏆傛椂澧炲姞left瀛楁锛 + ALTER TABLE `zt_task` ADD `left` tinyINT(3) NOT NULL AFTER `consumed` + +-- 淇敼鏃ユ湡瀛楁 +ALTER TABLE `zt_bug` CHANGE `openedDate` `openedDate` DATETIME NOT NULL , +CHANGE `assignedDate` `assignedDate` DATETIME NOT NULL , +CHANGE `resolvedDate` `resolvedDate` DATETIME NOT NULL , +CHANGE `closedDate` `closedDate` DATETIME NOT NULL , +CHANGE `lastEditedDate` `lastEditedDate` DATETIME NOT NULL + +RENAME TABLE `zentao`.`zt_division` TO `zentao`.`zt_dept` ; +ALTER TABLE `zt_user` CHANGE `division` `dept` MEDIUMINT( 8 ) UNSIGNED NOT NULL DEFAULT '0' + + +-- 0.2鐗堟湰锛 +-- +-- 淇敼task琛╪ame瀛楁鐨勯暱搴︺ +-- 淇敼task琛ㄧ殑鏃堕棿鐨勭被鍨嬶紝鍙互鏄诞鐐规暟銆 +ALTER TABLE `zt_task` CHANGE `estimate` `estimate` FLOAT UNSIGNED NOT NULL , +CHANGE `consumed` `consumed` FLOAT UNSIGNED NOT NULL , +CHANGE `left` `left` FLOAT UNSIGNED NOT NULL + +-- todo琛 + +CREATE TABLE IF NOT EXISTS `zt_todo` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `account` char(30) NOT NULL, + `date` date NOT NULL default '0000-00-00', + `begin` smallint(4) unsigned zerofill NOT NULL, + `end` smallint(4) unsigned zerofill NOT NULL, + `type` char(10) NOT NULL, + `idvalue` mediumint(8) unsigned NOT NULL default '0', + `pri` tinyint(3) unsigned NOT NULL, + `name` char(90) NOT NULL, + `desc` char(255) NOT NULL default '', + `status` enum('wait','doing','done') NOT NULL default 'wait', + PRIMARY KEY (`id`), + KEY `user` (`account`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- 鏇存柊product, project琛ㄤ腑鐨刢ompany瀛楁锛 +update zt_product set company = 1; +update zt_project set company = 1; + + -- 鏇存柊story瀛楁閲岄潰鐨別stimate瀛楁锛 +ALTER TABLE `zt_story` CHANGE `estimate` `estimate` FLOAT UNSIGNED NOT NULL + +-- 杩樻槸浣跨敤datetime瀛楁銆 +ALTER TABLE `zt_story` CHANGE `openedDate` `openedDate` DATETIME NOT NULL , +CHANGE `assignedDate` `assignedDate` DATETIME NOT NULL , +CHANGE `lastEditedDate` `lastEditedDate` DATETIME NOT NULL , +CHANGE `closedDate` `closedDate` DATETIME NOT NULL + +-- 澧炲姞diff瀛楁銆 +ALTER TABLE `zt_history` ADD `diff` TEXT NOT NULL + +-- 10.27 +ALTER TABLE `zt_todo` CHANGE `desc` `desc` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL +ALTER TABLE `zt_task` CHANGE `name` `name` VARCHAR( 90 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL + +ALTER TABLE `zt_task` CHANGE `estimate` `estimate` FLOAT UNSIGNED NOT NULL , +CHANGE `consumed` `consumed` FLOAT UNSIGNED NOT NULL , +CHANGE `left` `left` FLOAT UNSIGNED NOT NULL + + +-- 11.2 todo琛ㄥ鍔爌rivate瀛楁锛 +ALTER TABLE `zt_todo` ADD `private` BOOL NOT NULL + +-- 11.4 澧炲姞娑堣楄〃銆 +CREATE TABLE IF NOT EXISTS `zt_burn` ( + `project` mediumint(8) unsigned NOT NULL, + `date` date NOT NULL, + `left` float NOT NULL, + `consumed` float NOT NULL, + PRIMARY KEY (`project`,`date`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- 11.5 project status瀛楁鏇存敼銆 +ALTER TABLE `zt_project` CHANGE `status` `status` VARCHAR( 10 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL + +-- 11.10. + +ALTER TABLE `zt_bug` CHANGE `openedDate` `openedDate` DATETIME NOT NULL , +CHANGE `assignedDate` `assignedDate` DATETIME NOT NULL , +CHANGE `resolvedDate` `resolvedDate` DATETIME NOT NULL , +CHANGE `closedDate` `closedDate` DATETIME NOT NULL , +CHANGE `lastEditedDate` `lastEditedDate` DATETIME NOT NULL + +-- 11.12 + +ALTER TABLE `zt_bug` ADD `duplicateBug` MEDIUMINT UNSIGNED NOT NULL AFTER `closedDate` , +ADD `linkBug` VARCHAR( 255 ) NOT NULL AFTER `duplicateBug` , +ADD `case` MEDIUMINT UNSIGNED NOT NULL AFTER `linkBug` , +ADD `result` MEDIUMINT UNSIGNED NOT NULL AFTER `case` + +-- 11.13 +ALTER TABLE `zt_case` CHANGE `openedDate` `openedDate` DATETIME NOT NULL , +CHANGE `lastEditedDate` `lastEditedDate` DATETIME NOT NULL + +-- 11.16 +ALTER TABLE `zt_file` CHANGE `addedDate` `addedDate` DATETIME NOT NULL; +ALTER TABLE `zt_file` ADD `title` CHAR( 90 ) NOT NULL AFTER `file`; +ALTER TABLE `zt_file` ADD `objectType` CHAR( 10 ) NOT NULL AFTER `size` , +ADD `objectID` MEDIUMINT NOT NULL AFTER `objectType` ; + +ALTER TABLE `zt_file` CHANGE `file` `pathname` CHAR( 50 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL; +ALTER TABLE `zt_file` CHANGE `type` `extension` CHAR( 30 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL; + +ALTER TABLE `zt_task` CHANGE `status` `status` ENUM( 'wait', 'doing', 'done', 'cancel' ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'wait' + +ALTER TABLE `zt_todo` CHANGE `name` `name` CHAR( 150 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL + + +-- 12.10 鏂板productPlan琛ㄣ +CREATE TABLE `zentao`.`zt_productPlan` ( + `id` MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY , + `product` MEDIUMINT UNSIGNED NOT NULL , + `title` VARCHAR( 90 ) NOT NULL , + `desc` VARCHAR( 255 ) NOT NULL , + `begin` DATE NOT NULL , + `end` DATE NOT NULL +) ENGINE = MYISAM ; + +-- 灏唞t_story涓殑release鏀逛负plan銆 +ALTER TABLE `zt_story` CHANGE `replease` `plan` MEDIUMINT( 8 ) UNSIGNED NOT NULL DEFAULT '0' + +-- 12.11 淇敼case琛ㄣ + +ALTER TABLE `zt_case` CHANGE `type` `type` CHAR( 30 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '1', +CHANGE `status` `status` CHAR( 30 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '1', +CHANGE `openedDate` `openedDate` DATETIME NOT NULL , +CHANGE `lastEditedDate` `lastEditedDate` DATETIME NOT NULL + +ALTER TABLE `zt_case` CHANGE `title` `title` CHAR( 90 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL + +-- 12.28 zt_task瀛楁澧炲姞鑷畾涔夋帓搴忓瓧娈点 +ALTER TABLE `zt_task` ADD `statusCustom` TINYINT UNSIGNED NOT NULL AFTER `status` , +ADD INDEX ( statusCustom ); +update zt_task set statusCustom = locate(status, 'wait,doing,done,cancel') + +-- 澧炲姞绫诲瀷瀛楁銆-- +ALTER TABLE `zt_task` ADD `type` VARCHAR( 20 ) NOT NULL AFTER `name` , +ADD INDEX ( TYPE ) + +-- todo 澧炲姞鐘舵-- +ALTER TABLE `zt_todo` CHANGE `status` `status` CHAR( 20 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'wait' diff --git a/tags/zentaopms_0.5.0_beta_20100221/db/update0.3.sql b/tags/zentaopms_0.5.0_beta_20100221/db/update0.3.sql new file mode 100644 index 0000000000..3e34b220ea --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/db/update0.3.sql @@ -0,0 +1,35 @@ +-- 20100114: 閲嶆柊淇敼build鐨勭粨鏋勩 +DROP TABLE IF EXISTS `zt_build`; +CREATE TABLE IF NOT EXISTS `zt_build` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `product` mediumint(8) unsigned NOT NULL default '0', + `project` mediumint(8) unsigned NOT NULL default '0', + `name` char(30) NOT NULL default '', + `scmPath` char(255) NOT NULL, + `filePath` char(255) NOT NULL, + `date` date NOT NULL, + `builder` char(30) NOT NULL default '', + `desc` char(255) NOT NULL default '', + PRIMARY KEY (`id`), + UNIQUE KEY `name` (`name`) + ) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- 20100115: 閲嶆柊淇敼release鐨勭粨鏋勩 +DROP TABLE IF EXISTS `zt_release`; +CREATE TABLE IF NOT EXISTS `zt_release` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `product` mediumint(8) unsigned NOT NULL default '0', + `build` mediumint(8) unsigned NOT NULL, + `name` char(30) NOT NULL default '', + `date` date NOT NULL, + `desc` text NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `name` (`name`) + ) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- 20100115: fix bug 14 +ALTER TABLE `zt_productPlan` CHANGE `title` `title` VARCHAR( 90 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL , +CHANGE `desc` `desc` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL; + +-- 20100125 user琛ㄥ鍔爏tatus瀛楁銆 +ALTER TABLE `zt_user` ADD `status` VARCHAR( 30 ) NOT NULL DEFAULT 'active', +ADD INDEX ( STATUS ) diff --git a/tags/zentaopms_0.5.0_beta_20100221/db/update0.4.sql b/tags/zentaopms_0.5.0_beta_20100221/db/update0.4.sql new file mode 100644 index 0000000000..ba344d1287 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/db/update0.4.sql @@ -0,0 +1,114 @@ +-- 20100128 淇敼user琛ㄤ腑ip瀛楁鐨勯粯璁ゅ硷紝瑙e喅install澶辫触鐨勯棶棰樸 +ALTER TABLE `zt_user` CHANGE `ip` `ip` CHAR( 15 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ''; + +-- 20100128: 璋冩暣casestep琛ㄣ +ALTER TABLE `zt_caseStep` CHANGE `caseVersion` `version` SMALLINT( 3 ) UNSIGNED NOT NULL DEFAULT '0'; +ALTER TABLE `zt_caseStep` CHANGE `step` `desc` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ''; +ALTER TABLE `zt_caseStep` CHANGE `expect` `expect` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ''; +ALTER TABLE `zt_caseStep` ADD INDEX ( `case` , `version` ) ; + +-- 20100128 杞崲case涓殑step瀛楁 +update zt_case set version = 1 where version = 0; +insert into zt_caseStep select '', id,version,steps, '' from zt_case; +ALTER TABLE `zt_case` DROP `steps`; + +DROP TABLE `zt_testPlan`; +CREATE TABLE IF NOT EXISTS `zt_testTask` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `name` char(90) NOT NULL, + `product` mediumint(8) unsigned NOT NULL, + `project` mediumint(8) unsigned NOT NULL default '0', + `build` char(30) NOT NULL, + `begin` date NOT NULL, + `end` date NOT NULL, + `desc` text NOT NULL, + `status` char(30) NOT NULL, + PRIMARY KEY (`id`) + ) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +DROP TABLE `zt_planCase`; +CREATE TABLE IF NOT EXISTS `zt_testRun` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `task` mediumint(8) unsigned NOT NULL default '0', + `case` mediumint(8) unsigned NOT NULL default '0', + `version` tinyint(3) unsigned NOT NULL default '0', + `assignedTo` char(30) NOT NULL default '', + `lastRun` datetime NOT NULL, + `lastResult` char(30) NOT NULL, + `status` char(30) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `task` (`task`,`case`) + ) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +DROP TABLE `zt_caseResult`; +DROP TABLE `zt_resultStep`; +CREATE TABLE IF NOT EXISTS `zt_testResult` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `run` mediumint(8) unsigned NOT NULL, + `case` mediumint(8) unsigned NOT NULL, + `version` smallint(5) unsigned NOT NULL, + `caseResult` char(30) NOT NULL, + `stepResults` text NOT NULL, + `date` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `run` (`run`), + KEY `case` (`case`,`version`) + ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +-- 20100204 adjust the story. +ALTER TABLE `zt_story` DROP `attatchment`; +ALTER TABLE `zt_story` CHANGE `version` `version` SMALLINT NOT NULL DEFAULT '1'; +ALTER TABLE `zt_story` ADD `closedReason` VARCHAR( 30 ) NOT NULL AFTER `closedDate`; +ALTER TABLE `zt_story` ADD `stage` VARCHAR( 30 ) NOT NULL AFTER `status`; +ALTER TABLE `zt_story` ADD `reviewedBy` VARCHAR( 30 ) NOT NULL AFTER `lastEditedDate`; +ALTER TABLE `zt_story` ADD `reviewedDate` DATETIME NOT NULL AFTER `reviewedBy`; +UPDATE zt_story SET version = 1 WHERE version = 0; +UPDATE zt_story SET status = 'closed', closedReason = 'done', stage='released', closedBy = lastEditedBy, closedDate = lastEditedDate, assignedTo = 'closed' WHERE status = 'done'; +UPDATE zt_story SET status = 'draft' WHERE status = 'wait'; +UPDATE zt_story SET status = 'active' WHERE status = 'doing'; +ALTER TABLE `zt_story` CHANGE `bug` `fromBug` MEDIUMINT( 8 ) UNSIGNED NOT NULL DEFAULT '0'; +ALTER TABLE `zt_story` ADD `toBug` MEDIUMINT NOT NULL AFTER `closedReason`; +ALTER TABLE `zt_story` ADD `childStories` VARCHAR( 255 ) NOT NULL AFTER `toBug` , +ADD `linkStories` VARCHAR( 255 ) NOT NULL AFTER `childStories`; +ALTER TABLE `zt_story` ADD `duplicateStory` MEDIUMINT UNSIGNED NOT NULL AFTER `linkStories`; + +CREATE TABLE IF NOT EXISTS `zt_storySpec` ( + `story` mediumint(9) NOT NULL, + `version` smallint(6) NOT NULL, + `title` VARCHAR( 90 ) NOT NULL, + `spec` text NOT NULL, + UNIQUE KEY `story` (`story`,`version`) + ) ENGINE=MyISAM DEFAULT CHARSET=utf8; +INSERT INTO zt_storySpec select id,version,title,spec FROM zt_story; +ALTER TABLE `zt_story` DROP `spec`; +ALTER TABLE `zt_file` ADD `extra` VARCHAR( 255 ) NOT NULL ; +update `zt_file` set extra = 1 where objectType = 'story'; + +ALTER TABLE `zt_bug` ADD `storyVersion` SMALLINT NOT NULL DEFAULT '1' AFTER `story`; +ALTER TABLE `zt_bug` ADD `caseVersion` SMALLINT NOT NULL DEFAULT '1' AFTER `case`; +ALTER TABLE `zt_bug` DROP `field1` , +DROP `field2` , +DROP `feild3` ; + +ALTER TABLE `zt_case` DROP `field1` , +DROP `field2` , +DROP `feidl3` ; +ALTER TABLE `zt_case` ADD `storyVersion` SMALLINT NOT NULL DEFAULT '1' AFTER `story`; +ALTER TABLE `zt_projectStory` ADD `version` SMALLINT NOT NULL DEFAULT '1'; +ALTER TABLE `zt_task` ADD `storyVersion` SMALLINT NOT NULL DEFAULT '1' AFTER `story`; + +-- delete releation. +DROP TABLE `zt_releation`; + +-- 20100208 adjust action table. +ALTER TABLE `zt_action` ADD `extra` VARCHAR( 255 ) NOT NULL; +UPDATE zt_action SET extra = substr( ACTION , 13 ) , ACTION = 'Resolved' WHERE ACTION LIKE 'Resolved%'; + +--20100210 adjust the reviewedDate +ALTER TABLE `zt_story` CHANGE `reviewedDate` `reviewedDate` DATE NOT NULL; + +--20100220 action: convert the date from timestamp to datetime +ALTER TABLE `zt_action` ADD `datetmp` VARCHAR( 255 ) NOT NULL AFTER `date`; +UPDATE zt_action SET datetmp = FROM_UNIXTIME( date ) ; +ALTER TABLE `zt_action` DROP `date`; +ALTER TABLE `zt_action` CHANGE `datetmp` `date` DATETIME NOT NULL; diff --git a/tags/zentaopms_0.5.0_beta_20100221/db/zentao.sql b/tags/zentaopms_0.5.0_beta_20100221/db/zentao.sql new file mode 100644 index 0000000000..849ffba87b --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/db/zentao.sql @@ -0,0 +1,992 @@ +-- DROP TABLE IF EXISTS `zt_action`; +CREATE TABLE IF NOT EXISTS `zt_action` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `company` mediumint(8) unsigned NOT NULL default '0', + `objectType` varchar(30) NOT NULL default '', + `objectID` mediumint(8) unsigned NOT NULL default '0', + `actor` varchar(30) NOT NULL default '', + `action` varchar(30) NOT NULL default '', + `date` datetime NOT NULL, + `comment` text NOT NULL, + `extra` varchar(255) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_bug`; +CREATE TABLE IF NOT EXISTS `zt_bug` ( + `id` mediumint(8) NOT NULL auto_increment, + `product` mediumint(8) unsigned NOT NULL default '0', + `module` mediumint(8) unsigned NOT NULL default '0', + `project` mediumint(8) unsigned NOT NULL default '0', + `story` mediumint(8) unsigned NOT NULL default '0', + `storyVersion` smallint(6) NOT NULL default '1', + `task` mediumint(8) unsigned NOT NULL default '0', + `title` varchar(150) NOT NULL default '', + `severity` tinyint(4) NOT NULL default '0', + `type` varchar(30) NOT NULL default '', + `os` varchar(30) NOT NULL default '', + `browser` varchar(30) NOT NULL default '', + `hardware` varchar(30) NOT NULL, + `found` varchar(30) NOT NULL default '', + `steps` text NOT NULL, + `status` enum('active','resolved','closed') NOT NULL default 'active', + `mailto` varchar(255) NOT NULL default '', + `openedBy` varchar(30) NOT NULL default '', + `openedDate` datetime NOT NULL, + `openedBuild` varchar(30) NOT NULL default '', + `assignedTo` varchar(30) NOT NULL default '', + `assignedDate` datetime NOT NULL, + `resolvedBy` varchar(30) NOT NULL default '', + `resolution` varchar(30) NOT NULL default '', + `resolvedBuild` varchar(30) NOT NULL default '', + `resolvedDate` datetime NOT NULL, + `closedBy` varchar(30) NOT NULL default '', + `closedDate` datetime NOT NULL, + `duplicateBug` mediumint(8) unsigned NOT NULL, + `linkBug` varchar(255) NOT NULL, + `case` mediumint(8) unsigned NOT NULL, + `caseVersion` smallint(6) NOT NULL default '1', + `result` mediumint(8) unsigned NOT NULL, + `lastEditedBy` varchar(30) NOT NULL default '', + `lastEditedDate` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_build`; +CREATE TABLE IF NOT EXISTS `zt_build` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `product` mediumint(8) unsigned NOT NULL default '0', + `project` mediumint(8) unsigned NOT NULL default '0', + `name` char(30) NOT NULL default '', + `scmPath` char(255) NOT NULL, + `filePath` char(255) NOT NULL, + `date` date NOT NULL, + `builder` char(30) NOT NULL default '', + `desc` char(255) NOT NULL default '', + PRIMARY KEY (`id`), + UNIQUE KEY `name` (`name`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_burn`; +CREATE TABLE IF NOT EXISTS `zt_burn` ( + `project` mediumint(8) unsigned NOT NULL, + `date` date NOT NULL, + `left` float NOT NULL, + `consumed` float NOT NULL, + PRIMARY KEY (`project`,`date`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_case`; +CREATE TABLE IF NOT EXISTS `zt_case` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `product` mediumint(8) unsigned NOT NULL default '0', + `module` mediumint(8) unsigned NOT NULL default '0', + `path` mediumint(8) unsigned NOT NULL default '0', + `story` mediumint(30) unsigned NOT NULL default '0', + `storyVersion` smallint(6) NOT NULL default '1', + `title` char(90) NOT NULL, + `pri` tinyint(3) unsigned NOT NULL default '0', + `type` char(30) NOT NULL default '1', + `status` char(30) NOT NULL default '1', + `frequency` enum('1','2','3') NOT NULL default '1', + `order` tinyint(30) unsigned NOT NULL default '0', + `openedBy` char(30) NOT NULL default '', + `openedDate` datetime NOT NULL, + `lastEditedBy` char(30) NOT NULL default '', + `lastEditedDate` datetime NOT NULL, + `version` tinyint(3) unsigned NOT NULL default '0', + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_caseStep`; +CREATE TABLE IF NOT EXISTS `zt_caseStep` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `case` mediumint(8) unsigned NOT NULL default '0', + `version` smallint(3) unsigned NOT NULL default '0', + `desc` text NOT NULL, + `expect` text NOT NULL, + PRIMARY KEY (`id`), + KEY `case` (`case`,`version`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_company`; +CREATE TABLE IF NOT EXISTS `zt_company` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `name` char(120) default NULL, + `phone` char(20) default NULL, + `fax` char(20) default NULL, + `address` char(120) default NULL, + `zipcode` char(10) default NULL, + `website` char(120) default NULL, + `backyard` char(120) default NULL, + `pms` char(120) default NULL, + `guest` enum('1','0') NOT NULL default '0', + `admins` char(255) default NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `pms` (`pms`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_config`; +CREATE TABLE IF NOT EXISTS `zt_config` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `company` mediumint(8) unsigned NOT NULL default '0', + `owner` char(30) NOT NULL default '', + `section` char(30) NOT NULL default '', + `key` char(30) NOT NULL default '', + `value` char(255) NOT NULL default '', + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_dept`; +CREATE TABLE IF NOT EXISTS `zt_dept` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `company` mediumint(8) unsigned NOT NULL default '0', + `name` char(30) NOT NULL default '', + `parent` mediumint(8) unsigned NOT NULL default '0', + `path` char(255) NOT NULL default '', + `grade` tinyint(3) unsigned NOT NULL default '0', + `order` tinyint(3) unsigned NOT NULL default '0', + `position` char(30) NOT NULL default '', + `function` char(255) NOT NULL default '', + `manager` char(30) NOT NULL default '', + PRIMARY KEY (`id`), + KEY `company` (`company`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_effort`; +CREATE TABLE IF NOT EXISTS `zt_effort` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `user` char(30) NOT NULL default '', + `todo` enum('1','0') NOT NULL default '1', + `date` date NOT NULL default '0000-00-00', + `begin` datetime NOT NULL default '0000-00-00 00:00:00', + `end` datetime NOT NULL default '0000-00-00 00:00:00', + `type` enum('1','2','3') NOT NULL default '1', + `idvalue` mediumint(8) unsigned NOT NULL default '0', + `name` char(30) NOT NULL default '', + `desc` char(255) NOT NULL default '', + `status` enum('1','2','3') NOT NULL default '1', + PRIMARY KEY (`id`), + KEY `user` (`user`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_file`; +CREATE TABLE IF NOT EXISTS `zt_file` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `company` mediumint(8) unsigned NOT NULL default '0', + `pathname` char(50) NOT NULL, + `title` char(90) NOT NULL, + `extension` char(30) NOT NULL, + `size` mediumint(8) unsigned NOT NULL default '0', + `objectType` char(30) NOT NULL, + `objectID` mediumint(9) NOT NULL, + `addedBy` char(30) NOT NULL default '', + `addedDate` datetime NOT NULL, + `downloads` mediumint(8) unsigned NOT NULL default '0', + `extra` varchar(255) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_group`; +CREATE TABLE IF NOT EXISTS `zt_group` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `company` mediumint(8) unsigned NOT NULL, + `name` char(30) NOT NULL, + `desc` char(255) NOT NULL default '', + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_groupPriv`; +CREATE TABLE IF NOT EXISTS `zt_groupPriv` ( + `group` mediumint(8) unsigned NOT NULL default '0', + `module` char(30) NOT NULL default '', + `method` char(30) NOT NULL default '', + UNIQUE KEY `group` (`group`,`module`,`method`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_history`; +CREATE TABLE IF NOT EXISTS `zt_history` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `action` mediumint(8) unsigned NOT NULL default '0', + `field` varchar(30) NOT NULL default '', + `old` text NOT NULL, + `new` text NOT NULL, + `diff` text NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_module`; +CREATE TABLE IF NOT EXISTS `zt_module` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `product` mediumint(8) unsigned NOT NULL default '0', + `name` char(30) NOT NULL default '', + `parent` mediumint(8) unsigned NOT NULL default '0', + `path` char(255) NOT NULL default '', + `grade` tinyint(3) unsigned NOT NULL default '0', + `order` tinyint(3) unsigned NOT NULL default '0', + `view` char(30) NOT NULL default '', + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_product`; +CREATE TABLE IF NOT EXISTS `zt_product` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `company` mediumint(8) unsigned NOT NULL default '0', + `name` varchar(30) NOT NULL default '', + `code` varchar(10) NOT NULL default '', + `order` tinyint(3) unsigned NOT NULL default '0', + `status` varchar(30) NOT NULL default '', + `desc` text NOT NULL, + PRIMARY KEY (`id`), + KEY `company` (`company`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_productPlan`; +CREATE TABLE IF NOT EXISTS `zt_productPlan` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `product` mediumint(8) unsigned NOT NULL, + `title` varchar(90) NOT NULL, + `desc` varchar(255) NOT NULL, + `begin` date NOT NULL, + `end` date NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_project`; +CREATE TABLE IF NOT EXISTS `zt_project` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `company` mediumint(8) unsigned NOT NULL default '0', + `isCat` enum('1','0') NOT NULL default '0', + `catID` mediumint(8) unsigned NOT NULL, + `type` enum('sprint','project') NOT NULL default 'sprint', + `parent` mediumint(8) unsigned NOT NULL default '0', + `name` varchar(30) NOT NULL default '', + `code` varchar(20) NOT NULL, + `begin` date NOT NULL, + `end` date NOT NULL, + `status` varchar(10) NOT NULL, + `statge` enum('1','2','3','4','5') NOT NULL default '1', + `pri` enum('1','2','3','4') NOT NULL default '1', + `desc` text NOT NULL, + `goal` text NOT NULL, + `openedBy` varchar(30) NOT NULL default '', + `openedDate` int(10) unsigned NOT NULL default '0', + `closedBy` varchar(30) NOT NULL default '', + `closedDate` int(10) unsigned NOT NULL default '0', + `canceledBy` varchar(30) NOT NULL default '', + `canceledDate` int(10) unsigned NOT NULL default '0', + `PO` varchar(30) NOT NULL default '', + `PM` varchar(30) NOT NULL default '', + `QM` varchar(30) NOT NULL default '', + `team` varchar(30) NOT NULL, + PRIMARY KEY (`id`), + KEY `company` (`company`,`type`,`parent`,`begin`,`end`,`status`,`statge`,`pri`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_projectProduct`; +CREATE TABLE IF NOT EXISTS `zt_projectProduct` ( + `project` mediumint(8) unsigned NOT NULL, + `product` mediumint(8) unsigned NOT NULL, + PRIMARY KEY (`project`,`product`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_projectStory`; +CREATE TABLE IF NOT EXISTS `zt_projectStory` ( + `project` mediumint(8) unsigned NOT NULL default '0', + `product` mediumint(8) unsigned NOT NULL, + `story` mediumint(8) unsigned NOT NULL default '0', + `version` smallint(6) NOT NULL default '1', + UNIQUE KEY `project` (`project`,`story`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_release`; +CREATE TABLE IF NOT EXISTS `zt_release` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `product` mediumint(8) unsigned NOT NULL default '0', + `build` mediumint(8) unsigned NOT NULL, + `name` char(30) NOT NULL default '', + `date` date NOT NULL, + `desc` text NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `name` (`name`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_story`; +CREATE TABLE IF NOT EXISTS `zt_story` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `product` mediumint(8) unsigned NOT NULL default '0', + `module` mediumint(8) unsigned NOT NULL default '0', + `plan` mediumint(8) unsigned NOT NULL default '0', + `fromBug` mediumint(8) unsigned NOT NULL default '0', + `title` varchar(90) NOT NULL default '', + `type` varchar(30) NOT NULL default '', + `pri` tinyint(3) unsigned NOT NULL default '3', + `estimate` float unsigned NOT NULL, + `status` varchar(30) NOT NULL default '', + `stage` varchar(30) NOT NULL, + `mailto` varchar(255) NOT NULL default '', + `openedBy` varchar(30) NOT NULL default '', + `openedDate` datetime NOT NULL, + `assignedTo` varchar(30) NOT NULL default '', + `assignedDate` datetime NOT NULL, + `lastEditedBy` varchar(30) NOT NULL default '', + `lastEditedDate` datetime NOT NULL, + `reviewedBy` varchar(30) NOT NULL, + `reviewedDate` date NOT NULL, + `closedBy` varchar(30) NOT NULL default '', + `closedDate` datetime NOT NULL, + `closedReason` varchar(30) NOT NULL, + `toBug` mediumint(9) NOT NULL, + `childStories` varchar(255) NOT NULL, + `linkStories` varchar(255) NOT NULL, + `duplicateStory` mediumint(8) unsigned NOT NULL, + `version` smallint(6) NOT NULL default '1', + PRIMARY KEY (`id`), + KEY `product` (`product`,`module`,`plan`,`type`,`pri`), + KEY `status` (`status`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_storySpec`; +CREATE TABLE IF NOT EXISTS `zt_storySpec` ( + `story` mediumint(9) NOT NULL, + `version` smallint(6) NOT NULL, + `title` varchar(90) NOT NULL, + `spec` text NOT NULL, + UNIQUE KEY `story` (`story`,`version`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_task`; +CREATE TABLE IF NOT EXISTS `zt_task` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `project` mediumint(8) unsigned NOT NULL default '0', + `story` mediumint(8) unsigned NOT NULL default '0', + `storyVersion` smallint(6) NOT NULL default '1', + `name` varchar(90) NOT NULL, + `type` varchar(20) NOT NULL, + `pri` tinyint(3) unsigned NOT NULL default '0', + `owner` char(30) NOT NULL default '', + `estimate` float unsigned NOT NULL, + `consumed` float unsigned NOT NULL, + `left` float unsigned NOT NULL, + `status` enum('wait','doing','done','cancel') NOT NULL default 'wait', + `statusCustom` tinyint(3) unsigned NOT NULL, + `desc` text NOT NULL, + PRIMARY KEY (`id`), + KEY `statusOrder` (`statusCustom`), + KEY `type` (`type`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_taskEstimate`; +CREATE TABLE IF NOT EXISTS `zt_taskEstimate` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `task` mediumint(8) unsigned NOT NULL default '0', + `date` int(10) unsigned NOT NULL default '0', + `estimate` tinyint(3) unsigned NOT NULL default '0', + `estimater` char(30) NOT NULL default '', + PRIMARY KEY (`id`), + KEY `task` (`task`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_team`; +CREATE TABLE IF NOT EXISTS `zt_team` ( + `project` mediumint(8) unsigned NOT NULL default '0', + `account` char(30) NOT NULL default '', + `role` char(30) NOT NULL default '', + `joinDate` date NOT NULL default '0000-00-00', + `workingHour` tinyint(3) unsigned NOT NULL default '0', + PRIMARY KEY (`project`,`account`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_testResult`; +CREATE TABLE IF NOT EXISTS `zt_testResult` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `run` mediumint(8) unsigned NOT NULL, + `case` mediumint(8) unsigned NOT NULL, + `version` smallint(5) unsigned NOT NULL, + `caseResult` char(30) NOT NULL, + `stepResults` text NOT NULL, + `date` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `run` (`run`), + KEY `case` (`case`,`version`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_testRun`; +CREATE TABLE IF NOT EXISTS `zt_testRun` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `task` mediumint(8) unsigned NOT NULL default '0', + `case` mediumint(8) unsigned NOT NULL default '0', + `version` tinyint(3) unsigned NOT NULL default '0', + `assignedTo` char(30) NOT NULL default '', + `lastRun` datetime NOT NULL, + `lastResult` char(30) NOT NULL, + `status` char(30) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `task` (`task`,`case`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_testTask`; +CREATE TABLE IF NOT EXISTS `zt_testTask` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `name` char(90) NOT NULL, + `product` mediumint(8) unsigned NOT NULL, + `project` mediumint(8) unsigned NOT NULL default '0', + `build` char(30) NOT NULL, + `begin` date NOT NULL, + `end` date NOT NULL, + `desc` text NOT NULL, + `status` char(30) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_todo`; +CREATE TABLE IF NOT EXISTS `zt_todo` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `account` char(30) NOT NULL, + `date` date NOT NULL default '0000-00-00', + `begin` smallint(4) unsigned zerofill NOT NULL, + `end` smallint(4) unsigned zerofill NOT NULL, + `type` char(10) NOT NULL, + `idvalue` mediumint(8) unsigned NOT NULL default '0', + `pri` tinyint(3) unsigned NOT NULL, + `name` char(150) NOT NULL, + `desc` text NOT NULL, + `status` char(20) NOT NULL default '', + `private` tinyint(1) NOT NULL, + PRIMARY KEY (`id`), + KEY `user` (`account`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_user`; +CREATE TABLE IF NOT EXISTS `zt_user` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `company` mediumint(8) unsigned NOT NULL default '0', + `dept` mediumint(8) unsigned NOT NULL default '0', + `account` char(30) NOT NULL default '', + `password` char(32) NOT NULL default '', + `realname` char(30) NOT NULL default '', + `nickname` char(60) NOT NULL default '', + `avatar` char(30) NOT NULL default '', + `birthyear` smallint(5) unsigned NOT NULL default '0', + `birthday` date NOT NULL default '0000-00-00', + `gendar` enum('f','m') NOT NULL default 'f', + `email` char(90) NOT NULL default '', + `msn` char(90) NOT NULL default '', + `qq` char(20) NOT NULL default '', + `yahoo` char(90) NOT NULL default '', + `gtalk` char(90) NOT NULL default '', + `wangwang` char(90) NOT NULL default '', + `mobile` char(11) NOT NULL default '', + `phone` char(20) NOT NULL default '', + `address` char(120) NOT NULL default '', + `zipcode` char(10) NOT NULL default '', + `join` date NOT NULL default '0000-00-00', + `visits` mediumint(8) unsigned NOT NULL default '0', + `ip` char(15) NOT NULL default '', + `last` int(10) unsigned NOT NULL default '0', + `status` varchar(30) NOT NULL default 'active', + PRIMARY KEY (`id`), + UNIQUE KEY `account` (`account`), + KEY `company` (`company`,`dept`), + KEY `status` (`status`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_userGroup`; +CREATE TABLE IF NOT EXISTS `zt_userGroup` ( + `account` char(30) NOT NULL default '', + `group` mediumint(8) unsigned NOT NULL default '0', + UNIQUE KEY `account` (`account`,`group`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +INSERT INTO `zt_group` (id, company, name, `desc`) VALUES +(1, 1, 'admin', 'Admin'), +(2, 1, 'product', 'product'), +(3, 1, 'develop', 'develop'), +(4, 1, 'qa', 'qa'), +(5, 1, 'project manager', ''); +INSERT INTO `zt_groupPriv` (`group`, module, method) VALUES +(1, 'admin', 'browseCompany'), +(1, 'admin', 'index'), +(1, 'bug', 'activate'), +(1, 'bug', 'ajaxGetUserBugs'), +(1, 'bug', 'browse'), +(1, 'bug', 'close'), +(1, 'bug', 'create'), +(1, 'bug', 'edit'), +(1, 'bug', 'index'), +(1, 'bug', 'resolve'), +(1, 'bug', 'view'), +(1, 'build', 'ajaxGetProductBuilds'), +(1, 'build', 'ajaxGetProjectBuilds'), +(1, 'build', 'create'), +(1, 'build', 'delete'), +(1, 'build', 'edit'), +(1, 'build', 'view'), +(1, 'company', 'browse'), +(1, 'company', 'create'), +(1, 'company', 'delete'), +(1, 'company', 'edit'), +(1, 'company', 'index'), +(1, 'dept', 'browse'), +(1, 'dept', 'delete'), +(1, 'dept', 'manageChild'), +(1, 'dept', 'updateOrder'), +(1, 'group', 'browse'), +(1, 'group', 'create'), +(1, 'group', 'delete'), +(1, 'group', 'edit'), +(1, 'group', 'manageMember'), +(1, 'group', 'managePriv'), +(1, 'index', 'index'), +(1, 'index', 'ping'), +(1, 'my', 'bug'), +(1, 'my', 'editProfile'), +(1, 'my', 'index'), +(1, 'my', 'profile'), +(1, 'my', 'project'), +(1, 'my', 'story'), +(1, 'my', 'task'), +(1, 'my', 'todo'), +(1, 'product', 'ajaxGetPlans'), +(1, 'product', 'ajaxGetProjects'), +(1, 'product', 'browse'), +(1, 'product', 'create'), +(1, 'product', 'delete'), +(1, 'product', 'edit'), +(1, 'product', 'index'), +(1, 'product', 'roadmap'), +(1, 'productplan', 'browse'), +(1, 'productplan', 'create'), +(1, 'productplan', 'delete'), +(1, 'productplan', 'edit'), +(1, 'productplan', 'linkStory'), +(1, 'productplan', 'unlinkStory'), +(1, 'productplan', 'view'), +(1, 'project', 'browse'), +(1, 'project', 'bug'), +(1, 'project', 'build'), +(1, 'project', 'burn'), +(1, 'project', 'burnData'), +(1, 'project', 'create'), +(1, 'project', 'delete'), +(1, 'project', 'edit'), +(1, 'project', 'index'), +(1, 'project', 'linkStory'), +(1, 'project', 'manageChilds'), +(1, 'project', 'manageMembers'), +(1, 'project', 'manageProducts'), +(1, 'project', 'story'), +(1, 'project', 'task'), +(1, 'project', 'team'), +(1, 'project', 'unlinkMember'), +(1, 'project', 'unlinkStory'), +(1, 'project', 'view'), +(1, 'qa', 'index'), +(1, 'release', 'browse'), +(1, 'release', 'create'), +(1, 'release', 'delete'), +(1, 'release', 'edit'), +(1, 'release', 'view'), +(1, 'search', 'buildForm'), +(1, 'search', 'buildQuery'), +(1, 'story', 'activate'), +(1, 'story', 'ajaxGetProductStories'), +(1, 'story', 'ajaxGetProjectStories'), +(1, 'story', 'change'), +(1, 'story', 'close'), +(1, 'story', 'create'), +(1, 'story', 'delete'), +(1, 'story', 'edit'), +(1, 'story', 'review'), +(1, 'story', 'tasks'), +(1, 'story', 'view'), +(1, 'task', 'ajaxGetProjectTasks'), +(1, 'task', 'ajaxGetUserTasks'), +(1, 'task', 'create'), +(1, 'task', 'delete'), +(1, 'task', 'edit'), +(1, 'task', 'view'), +(1, 'testcase', 'browse'), +(1, 'testcase', 'create'), +(1, 'testcase', 'edit'), +(1, 'testcase', 'index'), +(1, 'testcase', 'view'), +(1, 'testtask', 'batchAssign'), +(1, 'testtask', 'browse'), +(1, 'testtask', 'create'), +(1, 'testtask', 'delete'), +(1, 'testtask', 'edit'), +(1, 'testtask', 'index'), +(1, 'testtask', 'linkCase'), +(1, 'testtask', 'results'), +(1, 'testtask', 'runCase'), +(1, 'testtask', 'unlinkCase'), +(1, 'testtask', 'view'), +(1, 'todo', 'create'), +(1, 'todo', 'delete'), +(1, 'todo', 'edit'), +(1, 'todo', 'import2Today'), +(1, 'todo', 'mark'), +(1, 'todo', 'view'), +(1, 'tree', 'ajaxGetOptionMenu'), +(1, 'tree', 'browse'), +(1, 'tree', 'delete'), +(1, 'tree', 'manageChild'), +(1, 'tree', 'updateOrder'), +(1, 'user', 'bug'), +(1, 'user', 'create'), +(1, 'user', 'delete'), +(1, 'user', 'edit'), +(1, 'user', 'profile'), +(1, 'user', 'project'), +(1, 'user', 'task'), +(1, 'user', 'todo'), +(1, 'user', 'view'), +(2, 'bug', 'activate'), +(2, 'bug', 'ajaxGetUserBugs'), +(2, 'bug', 'browse'), +(2, 'bug', 'close'), +(2, 'bug', 'create'), +(2, 'bug', 'edit'), +(2, 'bug', 'index'), +(2, 'bug', 'resolve'), +(2, 'bug', 'view'), +(2, 'build', 'ajaxGetProductBuilds'), +(2, 'build', 'ajaxGetProjectBuilds'), +(2, 'build', 'create'), +(2, 'build', 'delete'), +(2, 'build', 'edit'), +(2, 'build', 'view'), +(2, 'company', 'browse'), +(2, 'company', 'index'), +(2, 'index', 'index'), +(2, 'index', 'ping'), +(2, 'my', 'bug'), +(2, 'my', 'editProfile'), +(2, 'my', 'index'), +(2, 'my', 'profile'), +(2, 'my', 'project'), +(2, 'my', 'story'), +(2, 'my', 'task'), +(2, 'my', 'todo'), +(2, 'product', 'ajaxGetPlans'), +(2, 'product', 'ajaxGetProjects'), +(2, 'product', 'browse'), +(2, 'product', 'create'), +(2, 'product', 'edit'), +(2, 'product', 'index'), +(2, 'product', 'roadmap'), +(2, 'productplan', 'browse'), +(2, 'productplan', 'create'), +(2, 'productplan', 'delete'), +(2, 'productplan', 'edit'), +(2, 'productplan', 'linkStory'), +(2, 'productplan', 'unlinkStory'), +(2, 'productplan', 'view'), +(2, 'project', 'browse'), +(2, 'project', 'bug'), +(2, 'project', 'build'), +(2, 'project', 'burn'), +(2, 'project', 'burnData'), +(2, 'project', 'index'), +(2, 'project', 'linkStory'), +(2, 'project', 'manageProducts'), +(2, 'project', 'story'), +(2, 'project', 'task'), +(2, 'project', 'team'), +(2, 'project', 'unlinkStory'), +(2, 'project', 'view'), +(2, 'qa', 'index'), +(2, 'release', 'browse'), +(2, 'release', 'create'), +(2, 'release', 'delete'), +(2, 'release', 'edit'), +(2, 'release', 'view'), +(2, 'search', 'buildForm'), +(2, 'search', 'buildQuery'), +(2, 'story', 'activate'), +(2, 'story', 'ajaxGetProductStories'), +(2, 'story', 'ajaxGetProjectStories'), +(2, 'story', 'change'), +(2, 'story', 'close'), +(2, 'story', 'create'), +(2, 'story', 'delete'), +(2, 'story', 'edit'), +(2, 'story', 'review'), +(2, 'story', 'tasks'), +(2, 'story', 'view'), +(2, 'task', 'ajaxGetProjectTasks'), +(2, 'task', 'ajaxGetUserTasks'), +(2, 'task', 'create'), +(2, 'task', 'edit'), +(2, 'task', 'view'), +(2, 'testcase', 'browse'), +(2, 'testcase', 'create'), +(2, 'testcase', 'edit'), +(2, 'testcase', 'index'), +(2, 'testcase', 'view'), +(2, 'testtask', 'browse'), +(2, 'testtask', 'index'), +(2, 'testtask', 'results'), +(2, 'testtask', 'view'), +(2, 'todo', 'create'), +(2, 'todo', 'delete'), +(2, 'todo', 'edit'), +(2, 'todo', 'import2Today'), +(2, 'todo', 'mark'), +(2, 'todo', 'view'), +(2, 'tree', 'ajaxGetOptionMenu'), +(2, 'tree', 'browse'), +(2, 'tree', 'delete'), +(2, 'tree', 'manageChild'), +(2, 'tree', 'updateOrder'), +(2, 'user', 'bug'), +(2, 'user', 'profile'), +(2, 'user', 'project'), +(2, 'user', 'task'), +(2, 'user', 'todo'), +(2, 'user', 'view'), +(3, 'bug', 'activate'), +(3, 'bug', 'ajaxGetUserBugs'), +(3, 'bug', 'browse'), +(3, 'bug', 'close'), +(3, 'bug', 'create'), +(3, 'bug', 'edit'), +(3, 'bug', 'index'), +(3, 'bug', 'resolve'), +(3, 'bug', 'view'), +(3, 'build', 'ajaxGetProductBuilds'), +(3, 'build', 'ajaxGetProjectBuilds'), +(3, 'build', 'create'), +(3, 'build', 'edit'), +(3, 'build', 'view'), +(3, 'company', 'browse'), +(3, 'company', 'index'), +(3, 'index', 'index'), +(3, 'index', 'ping'), +(3, 'my', 'bug'), +(3, 'my', 'editProfile'), +(3, 'my', 'index'), +(3, 'my', 'profile'), +(3, 'my', 'project'), +(3, 'my', 'story'), +(3, 'my', 'task'), +(3, 'my', 'todo'), +(3, 'product', 'ajaxGetPlans'), +(3, 'product', 'ajaxGetProjects'), +(3, 'product', 'browse'), +(3, 'product', 'index'), +(3, 'product', 'roadmap'), +(3, 'productplan', 'browse'), +(3, 'productplan', 'view'), +(3, 'project', 'browse'), +(3, 'project', 'bug'), +(3, 'project', 'build'), +(3, 'project', 'burn'), +(3, 'project', 'burnData'), +(3, 'project', 'index'), +(3, 'project', 'story'), +(3, 'project', 'task'), +(3, 'project', 'team'), +(3, 'project', 'view'), +(3, 'qa', 'index'), +(3, 'release', 'browse'), +(3, 'release', 'view'), +(3, 'search', 'buildForm'), +(3, 'search', 'buildQuery'), +(3, 'story', 'activate'), +(3, 'story', 'ajaxGetProductStories'), +(3, 'story', 'ajaxGetProjectStories'), +(3, 'story', 'change'), +(3, 'story', 'close'), +(3, 'story', 'create'), +(3, 'story', 'edit'), +(3, 'story', 'review'), +(3, 'story', 'tasks'), +(3, 'story', 'view'), +(3, 'task', 'ajaxGetProjectTasks'), +(3, 'task', 'ajaxGetUserTasks'), +(3, 'task', 'create'), +(3, 'task', 'edit'), +(3, 'task', 'view'), +(3, 'testcase', 'browse'), +(3, 'testcase', 'index'), +(3, 'testcase', 'view'), +(3, 'testtask', 'browse'), +(3, 'testtask', 'index'), +(3, 'testtask', 'results'), +(3, 'testtask', 'view'), +(3, 'todo', 'create'), +(3, 'todo', 'delete'), +(3, 'todo', 'edit'), +(3, 'todo', 'import2Today'), +(3, 'todo', 'mark'), +(3, 'todo', 'view'), +(3, 'user', 'bug'), +(3, 'user', 'profile'), +(3, 'user', 'project'), +(3, 'user', 'task'), +(3, 'user', 'todo'), +(3, 'user', 'view'), +(4, 'bug', 'activate'), +(4, 'bug', 'ajaxGetUserBugs'), +(4, 'bug', 'browse'), +(4, 'bug', 'close'), +(4, 'bug', 'create'), +(4, 'bug', 'edit'), +(4, 'bug', 'index'), +(4, 'bug', 'resolve'), +(4, 'bug', 'view'), +(4, 'build', 'ajaxGetProductBuilds'), +(4, 'build', 'ajaxGetProjectBuilds'), +(4, 'build', 'create'), +(4, 'build', 'delete'), +(4, 'build', 'edit'), +(4, 'build', 'view'), +(4, 'company', 'browse'), +(4, 'company', 'index'), +(4, 'index', 'index'), +(4, 'index', 'ping'), +(4, 'my', 'bug'), +(4, 'my', 'editProfile'), +(4, 'my', 'index'), +(4, 'my', 'profile'), +(4, 'my', 'project'), +(4, 'my', 'story'), +(4, 'my', 'task'), +(4, 'my', 'todo'), +(4, 'product', 'ajaxGetPlans'), +(4, 'product', 'ajaxGetProjects'), +(4, 'product', 'browse'), +(4, 'product', 'index'), +(4, 'product', 'roadmap'), +(4, 'productplan', 'browse'), +(4, 'productplan', 'view'), +(4, 'project', 'browse'), +(4, 'project', 'bug'), +(4, 'project', 'build'), +(4, 'project', 'burn'), +(4, 'project', 'burnData'), +(4, 'project', 'index'), +(4, 'project', 'story'), +(4, 'project', 'task'), +(4, 'project', 'team'), +(4, 'project', 'view'), +(4, 'qa', 'index'), +(4, 'release', 'browse'), +(4, 'release', 'view'), +(4, 'search', 'buildForm'), +(4, 'search', 'buildQuery'), +(4, 'story', 'activate'), +(4, 'story', 'ajaxGetProductStories'), +(4, 'story', 'ajaxGetProjectStories'), +(4, 'story', 'change'), +(4, 'story', 'close'), +(4, 'story', 'create'), +(4, 'story', 'edit'), +(4, 'story', 'review'), +(4, 'story', 'tasks'), +(4, 'story', 'view'), +(4, 'task', 'ajaxGetProjectTasks'), +(4, 'task', 'ajaxGetUserTasks'), +(4, 'task', 'create'), +(4, 'task', 'edit'), +(4, 'task', 'view'), +(4, 'testcase', 'browse'), +(4, 'testcase', 'create'), +(4, 'testcase', 'edit'), +(4, 'testcase', 'index'), +(4, 'testcase', 'view'), +(4, 'testtask', 'batchAssign'), +(4, 'testtask', 'browse'), +(4, 'testtask', 'create'), +(4, 'testtask', 'delete'), +(4, 'testtask', 'edit'), +(4, 'testtask', 'index'), +(4, 'testtask', 'linkCase'), +(4, 'testtask', 'results'), +(4, 'testtask', 'runCase'), +(4, 'testtask', 'unlinkCase'), +(4, 'testtask', 'view'), +(4, 'todo', 'create'), +(4, 'todo', 'delete'), +(4, 'todo', 'edit'), +(4, 'todo', 'import2Today'), +(4, 'todo', 'mark'), +(4, 'todo', 'view'), +(4, 'tree', 'ajaxGetOptionMenu'), +(4, 'tree', 'browse'), +(4, 'tree', 'delete'), +(4, 'tree', 'manageChild'), +(4, 'tree', 'updateOrder'), +(4, 'user', 'bug'), +(4, 'user', 'profile'), +(4, 'user', 'project'), +(4, 'user', 'task'), +(4, 'user', 'todo'), +(4, 'user', 'view'), +(5, 'bug', 'activate'), +(5, 'bug', 'ajaxGetUserBugs'), +(5, 'bug', 'browse'), +(5, 'bug', 'close'), +(5, 'bug', 'create'), +(5, 'bug', 'edit'), +(5, 'bug', 'index'), +(5, 'bug', 'resolve'), +(5, 'bug', 'view'), +(5, 'build', 'ajaxGetProductBuilds'), +(5, 'build', 'ajaxGetProjectBuilds'), +(5, 'build', 'create'), +(5, 'build', 'delete'), +(5, 'build', 'edit'), +(5, 'build', 'view'), +(5, 'company', 'browse'), +(5, 'company', 'index'), +(5, 'index', 'index'), +(5, 'index', 'ping'), +(5, 'my', 'bug'), +(5, 'my', 'editProfile'), +(5, 'my', 'index'), +(5, 'my', 'profile'), +(5, 'my', 'project'), +(5, 'my', 'story'), +(5, 'my', 'task'), +(5, 'my', 'todo'), +(5, 'product', 'ajaxGetPlans'), +(5, 'product', 'ajaxGetProjects'), +(5, 'product', 'browse'), +(5, 'product', 'index'), +(5, 'product', 'roadmap'), +(5, 'productplan', 'browse'), +(5, 'productplan', 'linkStory'), +(5, 'productplan', 'unlinkStory'), +(5, 'productplan', 'view'), +(5, 'project', 'browse'), +(5, 'project', 'bug'), +(5, 'project', 'build'), +(5, 'project', 'burn'), +(5, 'project', 'burnData'), +(5, 'project', 'create'), +(5, 'project', 'delete'), +(5, 'project', 'edit'), +(5, 'project', 'index'), +(5, 'project', 'linkStory'), +(5, 'project', 'manageChilds'), +(5, 'project', 'manageMembers'), +(5, 'project', 'manageProducts'), +(5, 'project', 'story'), +(5, 'project', 'task'), +(5, 'project', 'team'), +(5, 'project', 'unlinkMember'), +(5, 'project', 'unlinkStory'), +(5, 'project', 'view'), +(5, 'qa', 'index'), +(5, 'release', 'browse'), +(5, 'release', 'view'), +(5, 'search', 'buildForm'), +(5, 'search', 'buildQuery'), +(5, 'story', 'activate'), +(5, 'story', 'ajaxGetProductStories'), +(5, 'story', 'ajaxGetProjectStories'), +(5, 'story', 'change'), +(5, 'story', 'close'), +(5, 'story', 'create'), +(5, 'story', 'edit'), +(5, 'story', 'review'), +(5, 'story', 'tasks'), +(5, 'story', 'view'), +(5, 'task', 'ajaxGetProjectTasks'), +(5, 'task', 'ajaxGetUserTasks'), +(5, 'task', 'create'), +(5, 'task', 'delete'), +(5, 'task', 'edit'), +(5, 'task', 'view'), +(5, 'testcase', 'browse'), +(5, 'testcase', 'edit'), +(5, 'testcase', 'index'), +(5, 'testcase', 'view'), +(5, 'testtask', 'browse'), +(5, 'testtask', 'index'), +(5, 'testtask', 'results'), +(5, 'testtask', 'view'), +(5, 'todo', 'create'), +(5, 'todo', 'delete'), +(5, 'todo', 'edit'), +(5, 'todo', 'import2Today'), +(5, 'todo', 'mark'), +(5, 'todo', 'view'), +(5, 'user', 'bug'), +(5, 'user', 'profile'), +(5, 'user', 'project'), +(5, 'user', 'task'), +(5, 'user', 'todo'), +(5, 'user', 'view'); diff --git a/tags/zentaopms_0.5.0_beta_20100221/doc/COPYING b/tags/zentaopms_0.5.0_beta_20100221/doc/COPYING new file mode 100644 index 0000000000..94a9ed024d --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/doc/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/tags/zentaopms_0.5.0_beta_20100221/doc/COPYING.LESSER b/tags/zentaopms_0.5.0_beta_20100221/doc/COPYING.LESSER new file mode 100644 index 0000000000..fc8a5de7ed --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/doc/COPYING.LESSER @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/tags/zentaopms_0.5.0_beta_20100221/doc/README b/tags/zentaopms_0.5.0_beta_20100221/doc/README new file mode 100644 index 0000000000..3104895505 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/doc/README @@ -0,0 +1,46 @@ +涓銆佷粈涔堟槸绂呴亾椤圭洰绠$悊杞欢 + +绂呴亾椤圭洰绠$悊杞欢(ZenTaoPMS)鏄竴娆惧浗浜х殑锛屽熀浜嶭GPL鍗忚锛屽紑婧愬厤璐圭殑椤圭洰绠$悊杞欢锛屽畠闆嗕骇鍝佺鐞嗐侀」鐩鐞嗐佹祴璇曠鐞嗕簬涓浣擄紝鍚屾椂杩樺寘鍚簡浜嬪姟绠$悊銆佺粍缁囩鐞嗙瓑璇稿鍔熻兘锛屾槸涓皬鍨嬩紒涓氶」鐩鐞嗙殑棣栭夈傚畼鏂圭綉绔欙細www.zentao.cn + +绂呴亾椤圭洰绠$悊杞欢浣跨敤PHP + MySQL寮鍙戯紝鍩轰簬鑷富鐨凱HP寮鍙戞鏋垛攢鈹ZenTaoPHP鑰屾垚銆傜涓夋柟寮鍙戣呮垨鑰呬紒涓氬彲浠ラ潪甯告柟渚跨殑寮鍙戞彃浠舵垨鑰呰繘琛屽畾鍒躲 + +绂呴亾鍦ㄦ墜锛岄」鐩棤蹇э紒 + +浜屻佺閬撶殑鍚箟 + +Zen鏄滅鈥濈殑鎰忔濓紝Tao鏄滈亾鈥濈殑鎰忔濄俍enTao鍚堟剰涓虹涓庨亾銆傝繖涓悕绉版槸鎴戝湪璇汇婄紪绋嬩箣绂呫嬪拰銆婄紪绋嬩箣閬撱嬬殑鏃跺欏彈鍒板惎鍙戯紝鍐冲畾閲囩敤杩欎釜姣旇緝鏈変腑鍥藉懗閬撶殑鍚嶅瓧銆 + +涓夈佺閬撻」鐩鐞嗚蒋浠剁殑鏉ョ敱锛 + +璇村埌杩欎釜闂锛岃浠嶣ugFree璋堣捣銆傝嚜浠04骞村彂甯傿ugFree浠ユ潵鍒2007骞达紝BugFree闄嗙画鍙戝竷浜嗕簲鍏釜鐗堟湰锛屽湪Bug绠$悊鏂归潰鍩烘湰涓婂凡缁忓畬澶囥備絾杩欎釜鏃跺欎骇鐢熶簡涓浜涙柊鐨勯棶棰樸傚緢澶氱綉鍙嬫嬁鐫BugFree杩涜鏀瑰姩锛屾敼閫犱负鍏朵粬鐨勭鐞嗙郴缁熴傝繕缁忓父鏈夌綉鍙嬮棶锛孊ugFree鍙互涓嶅彲浠ュ姞鍏ラ」鐩鐞嗙殑鍔熻兘銆傛垜涔熶竴鐩村湪鎬濊冭繖浜涢棶棰樸傚悗鏉ユ垜鍔犲叆浜嗛樋閲屽反宸达紝鍦ㄤ腑鍥介泤铏庘樸侀樋閲屽濡堛佹窐瀹濅笁骞寸殑宸ヤ綔缁忓巻涓紝鍙傚姞浜嗗ぇ澶у皬灏忕殑椤圭洰銆備篃娣变负椤圭洰绠$悊鎵鍥版儜銆備簬鏄氨浜х敓浜嗗仛涓涓伐鍏锋潵瑙e喅椤圭洰绠$悊鐨勯棶棰樸 + +鐢变簬绉嶇鍘熷洜锛屾垜杩欎釜鎰挎湜鍦ㄩ樋閲屽反宸村苟娌℃湁瀹炵幇銆傝鏉ヤ篃鏄竴浠跺垢浜嬶紝杩欐牱鎴戝彲浠ユ妸瀹冨紑婧愭潵鍙戝竷銆備粠浠婂勾鍒濇垜灏卞紑濮嬬潃鎵嬭冭檻杩欏绠$悊杞欢鐨勮璁°傛暣鏁磋姳浜嗗崐骞寸殑鏃堕棿鍦ㄨ冭檻銆7鏈堜唤浠庨樋閲屽反宸磋緸鑱屼箣鍚庯紝鎴戝紑濮嬫湁鏈変簡鐩稿姣旇緝澶氱殑涓鐐规椂闂存潵杩涜杩欏绯荤粺鐨勫紑鍙戙傚悓鏃朵篃闈炲父鎰熻阿鐜板湪鐨勮繖瀹跺崟浣嶏紝涓烘垜寮鍙戠閬撻」鐩鐞嗚蒋浠舵彁渚涗簡澶у姏鐨勬敮鎸併 + +鍥涖佷负浠涔堣繕瑕佸仛绂呴亾椤圭洰绠$悊杞欢锛 + +寰堝鏈嬪弸浼氶棶锛屽凡缁忔湁寰堝鐨勫紑婧愰」鐩鐞嗚蒋浠舵垨鑰呯郴缁熶簡锛屼负浠涔堣繕瑕佽嚜宸卞仛涓涓憿锛熶富瑕佸師鍥犳槸鎴戣涓虹幇鍦ㄧ殑寮婧愰」鐩鐞嗚蒋浠跺杩欎釜闂瑙e喅鐨勫苟涓嶅ソ锛屾瘮濡傜己涔忛渶姹傜鐞嗭紝bug绠$悊绛夊姛鑳姐傝屼笖寰堝寮婧愮殑椤圭洰绠$悊杞欢浣跨敤璧锋潵涔熶笉鏂逛究銆 + +甯傚満涓婁篃鏈夊緢澶氬晢涓氱殑杞欢锛屼絾鏀惰垂閮戒笉鑿诧紝鑰屼笖涔熸湭蹇呰寰楀ソ鐢ㄣ + +鐜板湪涔熸湁寰堝鍦ㄧ嚎鐨勯」鐩鐞嗘湇鍔★紝姣斿鍥藉鐨刡asecamp锛屽浗鍐呯殑鏄撳害锛屽繖鍚х瓑銆備絾鎴戠殑瑙傜偣锛岃繖浜涘湪绾跨殑椤圭洰绠$悊杞欢鍔熻兘鏈夐檺锛岀己涔忓畾鍒讹紝璁块棶閫熷害鏃犳硶淇濊瘉锛岃屼笖缂轰箯淇濆瘑銆 + +浜斻佺閬撻」鐩鐞嗚蒋浠剁殑鐗圭偣锛 + +闆嗘垚浜嗕骇鍝佺鐞嗐侀」鐩鐞嗐佹祴璇曠鐞嗐佷汉鍛樼鐞嗐佸彂甯冪鐞嗐佷簨鍔$鐞嗙瓑鍔熻兘浜庝竴浣撱備綘鍙渶瑕佷竴涓蒋浠跺氨鍙互瀹屾垚椤圭洰绠$悊鐨勬渶鏍稿績鐨勪换鍔° +寮婧愬厤璐癸紝闄嶄綆浼佷笟閮ㄧ讲鐨勬垚鏈 +鍔熻兘娉ㄩ噸瀹炴晥锛屼娇鐢ㄦ柟渚匡紝娌℃湁澶澶嶆潅鐨勬蹇点傛垜璁捐鐨勭悊蹇垫槸涓涓病鏈夊仛杩囬」鐩鐞嗙殑浜虹粡杩10鍒嗛挓鐨勫煿璁彲浠ヤ娇鐢ㄥ畠杩涜椤圭洰绠$悊銆:) +鍩轰簬PHP+MySQL寮鍙戯紝浼佷笟鑷富鏀瑰姩鏂逛究銆傚苟涓斿熀浜嶼enTaoPHP妗嗘灦锛屼负绗笁鏂瑰紑鍙戣呯殑鍔犲叆鎵撲笅浜嗗潥瀹炵殑鍩虹銆 +涓昏鐞嗗康鍩轰簬scrum锛屽悓鏃剁粨鍚堜簡PMP閲岄潰鐨勫緢澶氭蹇点 +鏀寔澶氬叕鍙革紝澶氶」鐩紝澶氫骇鍝侊紝澶氬洟闃熺殑寮鍙戙 +鐏垫椿鐨勬潈闄愯缃 +鏀寔浜у搧涓庨」鐩箣闂寸殑鐭╅樀鍏崇郴銆 + +鍏佺閬撻」鐩鐞嗚蒋浠剁殑鐜扮姸鍙婂紑鍙戣鍒掞細 + +绂呴亾椤圭洰绠$悊杞欢鐩墠姝e湪绱у瘑寮鍙戜腑锛岃缁嗚繘灞曟儏鍐碉紝璇峰ぇ瀹惰闂 pms.zentao.cn + +涓冦佺閬撻」鐩鐞嗚蒋浠堕渶瑕佹偍鐨勫府鍔 + +绂呴亾椤圭洰绠$悊杞欢闇瑕佹偍鐨勫府鍔╋紝鏃犺鎮ㄦ槸寮鍙戜汉鍛橈紝鎶戞垨鏄」鐩粡鐞嗭紝鎴栬呮槸浜у搧缁忕悊锛岃繕鏄祴璇曚汉鍛橈紝鍙堟垨鑰呮槸寮婧愮埍濂借咃紝鎮ㄩ兘鍙互鍦ㄧ閬撻」鐩鐞嗚蒋浠舵壘鍒板弬涓庣殑鍦版柟銆傛垜浠細浠ラ潪甯竜pen鐨勫績鎬佹墦閫犱竴涓閬撻」鐩鐞嗚蒋浠剁殑绀惧尯銆傛垜鐩镐俊锛岀閬撶ぞ鍖虹殑鎴愬姛锛屾墠鏄閬撻」鐩鐞嗚蒋浠剁殑鎴愬姛銆 + +澶у鐜板湪鍙互璁块棶http://pms.zentao.cn鏉ユ煡鐪嬭繖涓」鐩鐞嗚蒋浠惰嚜韬殑杩涘睍鎯呭喌銆傚ぇ瀹跺鏋滄兂鍔犲叆锛屽彲浠ュ拰鎴戣仈绯伙細wwccss#gmail.com銆 diff --git a/tags/zentaopms_0.5.0_beta_20100221/doc/THANKS b/tags/zentaopms_0.5.0_beta_20100221/doc/THANKS new file mode 100644 index 0000000000..4cb9a41c94 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/doc/THANKS @@ -0,0 +1,6 @@ +楦h阿 + +绂呴亾椤圭洰绠$悊杞欢鍦ㄥ紑鍙戣繃绋嬩腑寰楀埌浜嗘櫘鍔犵綉锛堥潚宀涙櫘鍔犳櫤鑳戒俊鎭湁闄愬叕鍙)鐨勫ぇ鍔涙敮鎸侊紝鍦ㄦ琛ㄧず鎰熻阿锛 娆㈣繋澶у璁块棶鏅姞缃 www.pujia.com 锛岃幏鍙栨渶閰风殑姘戠敓淇℃伅锛 + + 鐜嬫槬鐢 鏄撹蒋寮婧愯蒋浠剁爺鍙戜腑蹇 + 2009-10-25 diff --git a/tags/zentaopms_0.5.0_beta_20100221/doc/THIRDPARTY b/tags/zentaopms_0.5.0_beta_20100221/doc/THIRDPARTY new file mode 100644 index 0000000000..b6d9ad5c9d --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/doc/THIRDPARTY @@ -0,0 +1,7 @@ +绂呴亾椤圭洰绠$悊杞欢浣跨敤鍒扮殑绗笁鏂圭被搴撳垪琛 + +CSS妗嗘灦 锛歒UI 3 beta 涓殑 CSS濂椾欢锛屽寘鎷琤asic.css, reset.css, font.css鍜実rid.css銆傚畼鏂圭綉绔欙細http://developer.yahoo.com/yui/3/ +JS妗嗘灦 锛欽QUERY 1.3鐗堟湰銆傚畼鏂圭綉绔欙細http://www.jquery.com +JQUER鎻掍欢锛歛utocomplete colorbox colorize incsearch tablesorter treeview +MAIL绫 锛歱hpmailer 5.1锛屽畼鏂圭綉绔欙細 http://phpmailer.sourceforge.net +鎶ヨ〃妗嗘灦锛歠ushioncharts free 瀹樻柟缃戠珯锛歨ttp://www.fusioncharts.com/free/ diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/front/front.class.php b/tags/zentaopms_0.5.0_beta_20100221/lib/front/front.class.php new file mode 100644 index 0000000000..adf63c9da7 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/front/front.class.php @@ -0,0 +1,457 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package ZenTaoMS + * @version $Id$ + * @link http://www.zentao.cn + */ +class html +{ + /** + * create tags like text + * + * @param string $href the link url. + * @param string $title the link title. + * @param string $target the target window + * @param string $misc other params. + */ + static public function a($href = '', $title = '', $target = "_self", $misc = '') + { + if(empty($title)) $title = $href; + if($target == '_self') return "$title\n"; + return "$title\n"; + } + + /** + * create tags like text + * + * @param string $mail the email address + * @param string $title the email title. + */ + static public function mailto($mail = '', $title = '') + { + if(empty($title)) $title = $mail; + return "$title"; + } + + /** + * create tags like "" + * + * @param string $name the name of the select tag. + * @param array $options the array to create select tag from. + * @param string $selectedItems the item(s) to be selected, can like item1,item2. + * @param string $attrib other params such as multiple, size and style. + */ + static public function select($name = '', $options = array(), $selectedItems = "", $attrib = "") + { + $options = (array)($options); + if(!is_array($options) or empty($options)) return false; + + /* The begin. */ + $id = $name; + if($pos = strpos($name, '[')) $id = substr($name, 0, $pos); + $string = "\n"; + } + + /** + * create select with optgroup. + * + * @param string $name the name of the select tag. + * @param array $groups the option groups. + * @param string $selectedItems the item(s) to be selected, can like item1,item2. + * @param string $attrib other params such as multiple, size and style. + */ + static public function selectGroup($name = '', $groups = array(), $selectedItems = "", $attrib = "") + { + if(!is_array($groups) or empty($groups)) return false; + + /* The begin. */ + $id = $name; + if($pos = strpos($name, '[')) $id = substr($name, 0, $pos); + $string = "\n"; + } + + /** + * Create tags like "" + * + * @param string $name the name of the radio tag. + * @param array $options the array to create radio tag from. + * @param string $checked the value to checked by default. + * @param string $attrib other attribs. + */ + static public function radio($name = '', $options = array(), $checked = '', $attrib = '') + { + $options = (array)($options); + if(!is_array($options) or empty($options)) return false; + + $string = ''; + foreach($options as $key => $value) + { + $string .= "" + * + * @param string $name the name of the checkbox tag. + * @param array $options the array to create checkbox tag from. + * @param string $checked the value to checked by default, can be item1,item2 + * @param string $attrib other attribs. + */ + static public function checkbox($name, $options, $checked = "", $attrib = "") + { + $options = (array)($options); + if(!is_array($options) or empty($options)) return false; + $string = ''; + $checked = ",$checked,"; + + foreach($options as $key => $value) + { + $key = str_replace('item', '', $key); // 鍥犱负瀵硅薄鐨勫厓绱犱笉鑳戒负鏁板瓧锛屾墍浠ラ渶瑕佸湪閰嶇疆閲岄潰浼氬湪鏁板瓧鍓嶉潰娣诲姞item锛岃繖涓湴鏂瑰皢item鍘绘帀銆 + $string .= "" + * + * @param string $name the name of the text input tag. + * @param string $value the default value. + * @param string $attrib other attribs. + */ + static public function input($name, $value = "", $attrib = "") + { + return "\n"; + } + + /** + * create tags like "" + * + * @param string $name the name of the text input tag. + * @param string $value the default value. + * @param string $attrib other attribs. + */ + static public function hidden($name, $value = "", $attrib = "") + { + return "\n"; + } + + /** + * create tags like "" + * + * @param string $name the name of the text input tag. + * @param string $value the default value. + * @param string $attrib other attribs. + */ + static public function password($name, $value = "", $attrib = "") + { + return "\n"; + } + + /** + * create tags like "" + * + * @param string $name the name of the textarea tag. + * @param string $value the default value of the textarea tag. + * @param string $attrib other attribs. + */ + static public function textarea($name, $value = "", $attrib = "") + { + return "\n"; + } + + /** + * create tags like "". + * + * @param string $name the name of the file name. + * @param string $attrib other attribs. + */ + static public function file($name, $attrib = "") + { + return "\n"; + } + + /** + * create submit button. + * + * @static + * @access public + * @return string the submit button tag. + */ + public static function submitButton($label = '', $misc = '') + { + if(empty($label)) + { + global $lang; + $label = $lang->save; + } + return " "; + } + + /** + * create reset button. + * + * @static + * @access public + * @return string the reset button tag. + */ + public static function resetButton() + { + global $lang; + return " "; + } + + /** + * create common button. + * + * @static + * @access public + * @return string the reset button tag. + */ + public static function commonButton($label = '', $misc = '') + { + return " "; + } + + /** + * create a button with a link. + * + * @static + * @access public + * @return string the reset button tag. + */ + public static function linkButton($label = '', $link = '', $misc = '') + { + return " "; + } +} + +class js +{ + /* The start of javascript. */ + static private function start() + { + return << + + \n"; + } + + /* Show a alert box. */ + static public function alert($message = '') + { + return self::start() . "alert('" . $message . "')" . self::end(); + } + + /* 寮瑰嚭閿欒銆傚叾涓璵essage鍙互鏄竴鏉″瓧绗︿覆锛屼篃鍙互鏄竴缁存垨鑰呬簩缁存暟缁勩*/ + static public function error($message) + { + $alertMessage = ''; + if(is_array($message)) + { + foreach($message as $item) + { + is_array($item) ? $alertMessage .= join('\n', $item) . '\n' : $alertMessage .= $item . '\n'; + } + } + else + { + $alertMessage = $message; + } + return self::alert($alertMessage); + } + + /** + * show a confirm box, press ok go to okURL, else go to cancleURL. + * + * @param string $message the text to be showed. + * @param string $okURL the url to go to when press 'ok'. + * @param string $cancleURL the url to go to when press 'cancle'. + * @param string $okTarget the target to go to when press 'ok'. + * @param string $cancleTarget the target to go to when press 'cancle'. + */ + static public function confirm($message = '', $okURL = '', $cancleURL = '', $okTarget = "self", $cancleTarget = "self", $Echo = true) + { + $js = self::start(); + + $confirmAction = ''; + if(strtolower($okURL) == "back") + { + $confirmAction = "history.back(-1);"; + } + elseif(!empty($okURL)) + { + $confirmAction = "$okTarget.location = '$okURL';"; + } + + $cancleAction = ''; + if(strtolower($cancleURL) == "back") + { + $cancleAction = "history.back(-1);"; + } + elseif(!empty($cancleURL)) + { + $cancleAction = "$cancleTarget.location = '$cancleURL';"; + } + + $js .= <<getViewType(); + $themeRoot = $app->getWebRoot() . 'theme/'; + $js = << +webRoot = '$config->webRoot'; +requestType = '$config->requestType'; +pathType = '$config->pathType'; +requestFix = '$config->requestFix'; +moduleVar = '$config->moduleVar'; +methodVar = '$config->methodVar'; +viewVar = '$config->viewVar'; +defaultView = '$defaultViewType'; +themeRoot = '$themeRoot'; + + +EOT; + return $js; + } +} diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/front/tests/html_checkbox.expect b/tags/zentaopms_0.5.0_beta_20100221/lib/front/tests/html_checkbox.expect new file mode 100644 index 0000000000..d7d9f7377b --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/front/tests/html_checkbox.expect @@ -0,0 +1,21 @@ +texta +textb +textc + +texta +textb +textc + +texta +textb +textc + +texta +textb +textc + +texta +textb +textc + +bool(false) diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/front/tests/html_checkbox.php b/tags/zentaopms_0.5.0_beta_20100221/lib/front/tests/html_checkbox.php new file mode 100644 index 0000000000..ec9612c2a5 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/front/tests/html_checkbox.php @@ -0,0 +1,31 @@ +#!/usr/bin/env php + + * @version $Id$ + */ +include '../front.class.php'; + +$options['a'] = 'texta'; +$options['b'] = 'textb'; +$options['c'] = 'textc'; + +echo html::checkbox('checkbox', $options) . "\n"; +echo html::checkbox('checkbox', $options, 'a') . "\n"; +echo html::checkbox('checkbox', $options, 'a,b') . "\n"; +echo html::checkbox('checkbox', $options, 'ab') . "\n"; +echo html::checkbox('checkbox', $options, '', 'style="color:red"') . "\n"; +var_dump(html::checkbox('checkbox', array())); +<< diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/front/tests/html_radio.expect b/tags/zentaopms_0.5.0_beta_20100221/lib/front/tests/html_radio.expect new file mode 100644 index 0000000000..6f4a26ff0f --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/front/tests/html_radio.expect @@ -0,0 +1,13 @@ +texta +textb +textc +texta +textb +textc +texta +textb +textc +texta +textb +textc +bool(false) diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/front/tests/html_radio.php b/tags/zentaopms_0.5.0_beta_20100221/lib/front/tests/html_radio.php new file mode 100644 index 0000000000..20b4635e1d --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/front/tests/html_radio.php @@ -0,0 +1,29 @@ +#!/usr/bin/env php + + * @version $Id$ + */ +include '../front.class.php'; + +$options['a'] = 'texta'; +$options['b'] = 'textb'; +$options['c'] = 'textc'; + +echo html::radio('radio', $options); +echo html::radio('radio', $options, 'a'); +echo html::radio('radio', $options, 'a,b'); +echo html::radio('radio', $options, '', 'style="color:red"'); +var_dump(html::radio('radio', array())); +<< diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/front/tests/html_select.expect b/tags/zentaopms_0.5.0_beta_20100221/lib/front/tests/html_select.expect new file mode 100644 index 0000000000..a1ef188bb4 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/front/tests/html_select.expect @@ -0,0 +1,31 @@ + + + + + + +bool(false) diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/front/tests/html_select.php b/tags/zentaopms_0.5.0_beta_20100221/lib/front/tests/html_select.php new file mode 100644 index 0000000000..1d2595c101 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/front/tests/html_select.php @@ -0,0 +1,34 @@ +#!/usr/bin/env php + + * @version $Id$ + */ +include '../front.class.php'; + +$options['a'] = 'texta'; +$options['b'] = 'textb'; +$options['c'] = 'textc'; + +echo html::select('select', $options); +echo html::select('select[]', $options); +echo html::select('select', $options, 'a'); +echo html::select('select', $options, 'a,c'); +echo html::select('select', $options, 'ab'); +echo html::select('select', $options, '', 'style="color:red"'); +var_dump(html::select('select', array())); +<< diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/front/tests/html_selectgroup.php b/tags/zentaopms_0.5.0_beta_20100221/lib/front/tests/html_selectgroup.php new file mode 100644 index 0000000000..5cd601c7a3 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/front/tests/html_selectgroup.php @@ -0,0 +1,26 @@ +#!/usr/bin/env php + + * @version $Id$ + */ +include '../front.class.php'; + +$groups['group1']['a'] = 'texta'; +$groups['group1']['b'] = 'textb'; +$groups['group2']['c'] = 'textc'; +$groups['group2']['d'] = 'textd'; + +echo html::selectgroup('select', $groups); +?> diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/LICENSE b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/LICENSE new file mode 100644 index 0000000000..03851a3383 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/LICENSE @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/README b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/README new file mode 100644 index 0000000000..2d79f38622 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/README @@ -0,0 +1,218 @@ +/******************************************************************* +* The http://phpmailer.codeworxtech.com/ website now carries a few * +* advertisements through the Google Adsense network. Please visit * +* the advertiser sites and help us offset some of our costs. * +* Thanks .... * +********************************************************************/ + +PHPMailer +Full Featured Email Transfer Class for PHP +========================================== + +Version 5.0.0 (April 02, 2009) + +With the release of this version, we are initiating a new version numbering +system to differentiate from the PHP4 version of PHPMailer. + +Most notable in this release is fully object oriented code. + +We now have available the PHPDocumentor (phpdocs) documentation. This is +separate from the regular download to keep file sizes down. Please see the +download area of http://phpmailer.codeworxtech.com. + +We also have created a new test script (see /test_script) that you can use +right out of the box. Copy the /test_script folder directly to your server (in +the same structure ... with class.phpmailer.php and class.smtp.php in the +folder above it. Then launch the test script with: +http://www.yourdomain.com/phpmailer/test_script/index.php +from this one script, you can test your server settings for mail(), sendmail (or +qmail), and SMTP. This will email you a sample email (using contents.html for +the email body) and two attachments. One of the attachments is used as an inline +image to demonstrate how PHPMailer will automatically detect if attachments are +the same source as inline graphics and only include one version. Once you click +the Submit button, the results will be displayed including any SMTP debug +information and send status. We will also display a version of the script that +you can cut and paste to include in your projects. Enjoy! + +Version 2.3 (November 08, 2008) + +We have removed the /phpdoc from the downloads. All documentation is now on +the http://phpmailer.codeworxtech.com website. + +The phpunit.php has been updated to support PHP5. + +For all other changes and notes, please see the changelog. + +Donations are accepted at PayPal with our id "paypal@worxteam.com". + +Version 2.2 (July 15 2008) + +- see the changelog. + +Version 2.1 (June 04 2008) + +With this release, we are announcing that the development of PHPMailer for PHP5 +will be our focus from this date on. We have implemented all the enhancements +and fixes from the latest release of PHPMailer for PHP4. + +Far more important, though, is that this release of PHPMailer (v2.1) is +fully tested with E_STRICT error checking enabled. + +** NOTE: WE HAVE A NEW LANGUAGE VARIABLE FOR DIGITALLY SIGNED S/MIME EMAILS. + IF YOU CAN HELP WITH LANGUAGES OTHER THAN ENGLISH AND SPANISH, IT WOULD BE + APPRECIATED. + +We have now added S/MIME functionality (ability to digitally sign emails). +BIG THANKS TO "sergiocambra" for posting this patch back in November 2007. +The "Signed Emails" functionality adds the Sign method to pass the private key +filename and the password to read it, and then email will be sent with +content-type multipart/signed and with the digital signature attached. + +A quick note on E_STRICT: + +- In about half the test environments the development version was subjected + to, an error was thrown for the date() functions (used at line 1565 and 1569). + This is NOT a PHPMailer error, it is the result of an incorrectly configured + PHP5 installation. The fix is to modify your 'php.ini' file and include the + date.timezone = America/New York + directive, (for your own server timezone) +- If you do get this error, and are unable to access your php.ini file, there is + a workaround. In your PHP script, add + date_default_timezone_set('America/Toronto'); + + * do NOT try to use + $myVar = date_default_timezone_get(); + as a test, it will throw an error. + +We have also included more example files to show the use of "sendmail", "mail()", +"smtp", and "gmail". + +We are also looking for more programmers to join the volunteer development team. +If you have an interest in this, please let us know. + +Enjoy! + + +Version 2.1.0beta1 & beta2 + +please note, this is BETA software +** DO NOT USE THIS IN PRODUCTION OR LIVE PROJECTS +INTENDED STRICTLY FOR TESTING + +** NOTE: + +As of November 2007, PHPMailer has a new project team headed by industry +veteran Andy Prevost (codeworxtech). The first release in more than two +years will focus on fixes, adding ease-of-use enhancements, provide +basic compatibility with PHP4 and PHP5 using PHP5 backwards compatibility +features. A new release is planned before year-end 2007 that will provide +full compatiblity with PHP4 and PHP5, as well as more bug fixes. + +We are looking for project developers to assist in restoring PHPMailer to +its leadership position. Our goals are to simplify use of PHPMailer, provide +good documentation and examples, and retain backward compatibility to level +1.7.3 standards. + +If you are interested in helping out, visit http://sourceforge.net/projects/phpmailer +and indicate your interest. + +** + +http://phpmailer.sourceforge.net/ + +This software is licenced under the LGPL. Please read LICENSE for information on the +software availability and distribution. + +Class Features: +- Send emails with multiple TOs, CCs, BCCs and REPLY-TOs +- Redundant SMTP servers +- Multipart/alternative emails for mail clients that do not read HTML email +- Support for 8bit, base64, binary, and quoted-printable encoding +- Uses the same methods as the very popular AspEmail active server (COM) component +- SMTP authentication +- Native language support +- Word wrap, and more! + +Why you might need it: + +Many PHP developers utilize email in their code. The only PHP function +that supports this is the mail() function. However, it does not expose +any of the popular features that many email clients use nowadays like +HTML-based emails and attachments. There are two proprietary +development tools out there that have all the functionality built into +easy to use classes: AspEmail(tm) and AspMail. Both of these +programs are COM components only available on Windows. They are also a +little pricey for smaller projects. + +Since I do Linux development I锟絭e missed these tools for my PHP coding. +So I built a version myself that implements the same methods (object +calls) that the Windows-based components do. It is open source and the +LGPL license allows you to place the class in your proprietary PHP +projects. + + +Installation: + +Copy class.phpmailer.php into your php.ini include_path. If you are +using the SMTP mailer then place class.smtp.php in your path as well. +In the language directory you will find several files like +phpmailer.lang-en.php. If you look right before the .php extension +that there are two letters. These represent the language type of the +translation file. For instance "en" is the English file and "br" is +the Portuguese file. Chose the file that best fits with your language +and place it in the PHP include path. If your language is English +then you have nothing more to do. If it is a different language then +you must point PHPMailer to the correct translation. To do this, call +the PHPMailer SetLanguage method like so: + +// To load the Portuguese version +$mail->SetLanguage("br", "/optional/path/to/language/directory/"); + +That's it. You should now be ready to use PHPMailer! + + +A Simple Example: + +IsSMTP(); // set mailer to use SMTP +$mail->Host = "smtp1.example.com;smtp2.example.com"; // specify main and backup server +$mail->SMTPAuth = true; // turn on SMTP authentication +$mail->Username = "jswan"; // SMTP username +$mail->Password = "secret"; // SMTP password + +$mail->From = "from@example.com"; +$mail->FromName = "Mailer"; +$mail->AddAddress("josh@example.net", "Josh Adams"); +$mail->AddAddress("ellen@example.com"); // name is optional +$mail->AddReplyTo("info@example.com", "Information"); + +$mail->WordWrap = 50; // set word wrap to 50 characters +$mail->AddAttachment("/var/tmp/file.tar.gz"); // add attachments +$mail->AddAttachment("/tmp/image.jpg", "new.jpg"); // optional name +$mail->IsHTML(true); // set email format to HTML + +$mail->Subject = "Here is the subject"; +$mail->Body = "This is the HTML message body in bold!"; +$mail->AltBody = "This is the body in plain text for non-HTML mail clients"; + +if(!$mail->Send()) +{ + echo "Message could not be sent.

"; + echo "Mailer Error: " . $mail->ErrorInfo; + exit; +} + +echo "Message has been sent"; +?> + +CHANGELOG + +See ChangeLog.txt + +Download: http://sourceforge.net/project/showfiles.php?group_id=26031 + +Andy Prevost diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/class.pop3.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/class.pop3.php new file mode 100644 index 0000000000..f9fd3b2edb --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/class.pop3.php @@ -0,0 +1,407 @@ +pop_conn = 0; + $this->connected = false; + $this->error = null; + } + + /** + * Combination of public events - connect, login, disconnect + * @access public + * @param string $host + * @param integer $port + * @param integer $tval + * @param string $username + * @param string $password + */ + public function Authorise ($host, $port = false, $tval = false, $username, $password, $debug_level = 0) { + $this->host = $host; + + // If no port value is passed, retrieve it + if ($port == false) { + $this->port = $this->POP3_PORT; + } else { + $this->port = $port; + } + + // If no port value is passed, retrieve it + if ($tval == false) { + $this->tval = $this->POP3_TIMEOUT; + } else { + $this->tval = $tval; + } + + $this->do_debug = $debug_level; + $this->username = $username; + $this->password = $password; + + // Refresh the error log + $this->error = null; + + // Connect + $result = $this->Connect($this->host, $this->port, $this->tval); + + if ($result) { + $login_result = $this->Login($this->username, $this->password); + + if ($login_result) { + $this->Disconnect(); + + return true; + } + + } + + // We need to disconnect regardless if the login succeeded + $this->Disconnect(); + + return false; + } + + /** + * Connect to the POP3 server + * @access public + * @param string $host + * @param integer $port + * @param integer $tval + * @return boolean + */ + public function Connect ($host, $port = false, $tval = 30) { + // Are we already connected? + if ($this->connected) { + return true; + } + + /* + On Windows this will raise a PHP Warning error if the hostname doesn't exist. + Rather than supress it with @fsockopen, let's capture it cleanly instead + */ + + set_error_handler(array(&$this, 'catchWarning')); + + // Connect to the POP3 server + $this->pop_conn = fsockopen($host, // POP3 Host + $port, // Port # + $errno, // Error Number + $errstr, // Error Message + $tval); // Timeout (seconds) + + // Restore the error handler + restore_error_handler(); + + // Does the Error Log now contain anything? + if ($this->error && $this->do_debug >= 1) { + $this->displayErrors(); + } + + // Did we connect? + if ($this->pop_conn == false) { + // It would appear not... + $this->error = array( + 'error' => "Failed to connect to server $host on port $port", + 'errno' => $errno, + 'errstr' => $errstr + ); + + if ($this->do_debug >= 1) { + $this->displayErrors(); + } + + return false; + } + + // Increase the stream time-out + + // Check for PHP 4.3.0 or later + if (version_compare(phpversion(), '5.0.0', 'ge')) { + stream_set_timeout($this->pop_conn, $tval, 0); + } else { + // Does not work on Windows + if (substr(PHP_OS, 0, 3) !== 'WIN') { + socket_set_timeout($this->pop_conn, $tval, 0); + } + } + + // Get the POP3 server response + $pop3_response = $this->getResponse(); + + // Check for the +OK + if ($this->checkResponse($pop3_response)) { + // The connection is established and the POP3 server is talking + $this->connected = true; + return true; + } + + } + + /** + * Login to the POP3 server (does not support APOP yet) + * @access public + * @param string $username + * @param string $password + * @return boolean + */ + public function Login ($username = '', $password = '') { + if ($this->connected == false) { + $this->error = 'Not connected to POP3 server'; + + if ($this->do_debug >= 1) { + $this->displayErrors(); + } + } + + if (empty($username)) { + $username = $this->username; + } + + if (empty($password)) { + $password = $this->password; + } + + $pop_username = "USER $username" . $this->CRLF; + $pop_password = "PASS $password" . $this->CRLF; + + // Send the Username + $this->sendString($pop_username); + $pop3_response = $this->getResponse(); + + if ($this->checkResponse($pop3_response)) { + // Send the Password + $this->sendString($pop_password); + $pop3_response = $this->getResponse(); + + if ($this->checkResponse($pop3_response)) { + return true; + } else { + return false; + } + } else { + return false; + } + } + + /** + * Disconnect from the POP3 server + * @access public + */ + public function Disconnect () { + $this->sendString('QUIT'); + + fclose($this->pop_conn); + } + + ///////////////////////////////////////////////// + // Private Methods + ///////////////////////////////////////////////// + + /** + * Get the socket response back. + * $size is the maximum number of bytes to retrieve + * @access private + * @param integer $size + * @return string + */ + private function getResponse ($size = 128) { + $pop3_response = fgets($this->pop_conn, $size); + + return $pop3_response; + } + + /** + * Send a string down the open socket connection to the POP3 server + * @access private + * @param string $string + * @return integer + */ + private function sendString ($string) { + $bytes_sent = fwrite($this->pop_conn, $string, strlen($string)); + + return $bytes_sent; + } + + /** + * Checks the POP3 server response for +OK or -ERR + * @access private + * @param string $string + * @return boolean + */ + private function checkResponse ($string) { + if (substr($string, 0, 3) !== '+OK') { + $this->error = array( + 'error' => "Server reported an error: $string", + 'errno' => 0, + 'errstr' => '' + ); + + if ($this->do_debug >= 1) { + $this->displayErrors(); + } + + return false; + } else { + return true; + } + + } + + /** + * If debug is enabled, display the error message array + * @access private + */ + private function displayErrors () { + echo '

';
+
+    foreach ($this->error as $single_error) {
+      print_r($single_error);
+    }
+
+    echo '
'; + } + + /** + * Takes over from PHP for the socket warning handler + * @access private + * @param integer $errno + * @param string $errstr + * @param string $errfile + * @param integer $errline + */ + private function catchWarning ($errno, $errstr, $errfile, $errline) { + $this->error[] = array( + 'error' => "Connecting to the POP3 server raised a PHP warning: ", + 'errno' => $errno, + 'errstr' => $errstr + ); + } + + // End of class +} +?> \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/class.smtp.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/class.smtp.php new file mode 100644 index 0000000000..c2ca1cb3b8 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/class.smtp.php @@ -0,0 +1,814 @@ +smtp_conn = 0; + $this->error = null; + $this->helo_rply = null; + + $this->do_debug = 0; + } + + ///////////////////////////////////////////////// + // CONNECTION FUNCTIONS + ///////////////////////////////////////////////// + + /** + * Connect to the server specified on the port specified. + * If the port is not specified use the default SMTP_PORT. + * If tval is specified then a connection will try and be + * established with the server for that number of seconds. + * If tval is not specified the default is 30 seconds to + * try on the connection. + * + * SMTP CODE SUCCESS: 220 + * SMTP CODE FAILURE: 421 + * @access public + * @return bool + */ + public function Connect($host, $port = 0, $tval = 30) { + // set the error val to null so there is no confusion + $this->error = null; + + // make sure we are __not__ connected + if($this->connected()) { + // already connected, generate error + $this->error = array("error" => "Already connected to a server"); + return false; + } + + if(empty($port)) { + $port = $this->SMTP_PORT; + } + + // connect to the smtp server + $this->smtp_conn = @fsockopen($host, // the host of the server + $port, // the port to use + $errno, // error number if any + $errstr, // error message if any + $tval); // give up after ? secs + // verify we connected properly + if(empty($this->smtp_conn)) { + $this->error = array("error" => "Failed to connect to server", + "errno" => $errno, + "errstr" => $errstr); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . ": $errstr ($errno)" . $this->CRLF . '
'; + } + return false; + } + + // SMTP server can take longer to respond, give longer timeout for first read + // Windows does not have support for this timeout function + if(substr(PHP_OS, 0, 3) != "WIN") + socket_set_timeout($this->smtp_conn, $tval, 0); + + // get any announcement + $announce = $this->get_lines(); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $announce . $this->CRLF . '
'; + } + + return true; + } + + /** + * Initiate a TLS communication with the server. + * + * SMTP CODE 220 Ready to start TLS + * SMTP CODE 501 Syntax error (no parameters allowed) + * SMTP CODE 454 TLS not available due to temporary reason + * @access public + * @return bool success + */ + public function StartTLS() { + $this->error = null; # to avoid confusion + + if(!$this->connected()) { + $this->error = array("error" => "Called StartTLS() without being connected"); + return false; + } + + fputs($this->smtp_conn,"STARTTLS" . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'; + } + + if($code != 220) { + $this->error = + array("error" => "STARTTLS not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; + } + return false; + } + + // Begin encrypted connection + if(!stream_socket_enable_crypto($this->smtp_conn, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) { + return false; + } + + return true; + } + + /** + * Performs SMTP authentication. Must be run after running the + * Hello() method. Returns true if successfully authenticated. + * @access public + * @return bool + */ + public function Authenticate($username, $password) { + // Start authentication + fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($code != 334) { + $this->error = + array("error" => "AUTH not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; + } + return false; + } + + // Send encoded username + fputs($this->smtp_conn, base64_encode($username) . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($code != 334) { + $this->error = + array("error" => "Username not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; + } + return false; + } + + // Send encoded password + fputs($this->smtp_conn, base64_encode($password) . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($code != 235) { + $this->error = + array("error" => "Password not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; + } + return false; + } + + return true; + } + + /** + * Returns true if connected to a server otherwise false + * @access public + * @return bool + */ + public function Connected() { + if(!empty($this->smtp_conn)) { + $sock_status = socket_get_status($this->smtp_conn); + if($sock_status["eof"]) { + // the socket is valid but we are not connected + if($this->do_debug >= 1) { + echo "SMTP -> NOTICE:" . $this->CRLF . "EOF caught while checking if connected"; + } + $this->Close(); + return false; + } + return true; // everything looks good + } + return false; + } + + /** + * Closes the socket and cleans up the state of the class. + * It is not considered good to use this function without + * first trying to use QUIT. + * @access public + * @return void + */ + public function Close() { + $this->error = null; // so there is no confusion + $this->helo_rply = null; + if(!empty($this->smtp_conn)) { + // close the connection and cleanup + fclose($this->smtp_conn); + $this->smtp_conn = 0; + } + } + + ///////////////////////////////////////////////// + // SMTP COMMANDS + ///////////////////////////////////////////////// + + /** + * Issues a data command and sends the msg_data to the server + * finializing the mail transaction. $msg_data is the message + * that is to be send with the headers. Each header needs to be + * on a single line followed by a with the message headers + * and the message body being seperated by and additional . + * + * Implements rfc 821: DATA + * + * SMTP CODE INTERMEDIATE: 354 + * [data] + * . + * SMTP CODE SUCCESS: 250 + * SMTP CODE FAILURE: 552,554,451,452 + * SMTP CODE FAILURE: 451,554 + * SMTP CODE ERROR : 500,501,503,421 + * @access public + * @return bool + */ + public function Data($msg_data) { + $this->error = null; // so no confusion is caused + + if(!$this->connected()) { + $this->error = array( + "error" => "Called Data() without being connected"); + return false; + } + + fputs($this->smtp_conn,"DATA" . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'; + } + + if($code != 354) { + $this->error = + array("error" => "DATA command not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; + } + return false; + } + + /* the server is ready to accept data! + * according to rfc 821 we should not send more than 1000 + * including the CRLF + * characters on a single line so we will break the data up + * into lines by \r and/or \n then if needed we will break + * each of those into smaller lines to fit within the limit. + * in addition we will be looking for lines that start with + * a period '.' and append and additional period '.' to that + * line. NOTE: this does not count towards limit. + */ + + // normalize the line breaks so we know the explode works + $msg_data = str_replace("\r\n","\n",$msg_data); + $msg_data = str_replace("\r","\n",$msg_data); + $lines = explode("\n",$msg_data); + + /* we need to find a good way to determine is headers are + * in the msg_data or if it is a straight msg body + * currently I am assuming rfc 822 definitions of msg headers + * and if the first field of the first line (':' sperated) + * does not contain a space then it _should_ be a header + * and we can process all lines before a blank "" line as + * headers. + */ + + $field = substr($lines[0],0,strpos($lines[0],":")); + $in_headers = false; + if(!empty($field) && !strstr($field," ")) { + $in_headers = true; + } + + $max_line_length = 998; // used below; set here for ease in change + + while(list(,$line) = @each($lines)) { + $lines_out = null; + if($line == "" && $in_headers) { + $in_headers = false; + } + // ok we need to break this line up into several smaller lines + while(strlen($line) > $max_line_length) { + $pos = strrpos(substr($line,0,$max_line_length)," "); + + // Patch to fix DOS attack + if(!$pos) { + $pos = $max_line_length - 1; + $lines_out[] = substr($line,0,$pos); + $line = substr($line,$pos); + } else { + $lines_out[] = substr($line,0,$pos); + $line = substr($line,$pos + 1); + } + + /* if processing headers add a LWSP-char to the front of new line + * rfc 822 on long msg headers + */ + if($in_headers) { + $line = "\t" . $line; + } + } + $lines_out[] = $line; + + // send the lines to the server + while(list(,$line_out) = @each($lines_out)) { + if(strlen($line_out) > 0) + { + if(substr($line_out, 0, 1) == ".") { + $line_out = "." . $line_out; + } + } + fputs($this->smtp_conn,$line_out . $this->CRLF); + } + } + + // message data has been sent + fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'; + } + + if($code != 250) { + $this->error = + array("error" => "DATA not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; + } + return false; + } + return true; + } + + /** + * Sends the HELO command to the smtp server. + * This makes sure that we and the server are in + * the same known state. + * + * Implements from rfc 821: HELO + * + * SMTP CODE SUCCESS: 250 + * SMTP CODE ERROR : 500, 501, 504, 421 + * @access public + * @return bool + */ + public function Hello($host = '') { + $this->error = null; // so no confusion is caused + + if(!$this->connected()) { + $this->error = array( + "error" => "Called Hello() without being connected"); + return false; + } + + // if hostname for HELO was not specified send default + if(empty($host)) { + // determine appropriate default to send to server + $host = "localhost"; + } + + // Send extended hello first (RFC 2821) + if(!$this->SendHello("EHLO", $host)) { + if(!$this->SendHello("HELO", $host)) { + return false; + } + } + + return true; + } + + /** + * Sends a HELO/EHLO command. + * @access private + * @return bool + */ + private function SendHello($hello, $host) { + fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER: " . $rply . $this->CRLF . '
'; + } + + if($code != 250) { + $this->error = + array("error" => $hello . " not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; + } + return false; + } + + $this->helo_rply = $rply; + + return true; + } + + /** + * Starts a mail transaction from the email address specified in + * $from. Returns true if successful or false otherwise. If True + * the mail transaction is started and then one or more Recipient + * commands may be called followed by a Data command. + * + * Implements rfc 821: MAIL FROM: + * + * SMTP CODE SUCCESS: 250 + * SMTP CODE SUCCESS: 552,451,452 + * SMTP CODE SUCCESS: 500,501,421 + * @access public + * @return bool + */ + public function Mail($from) { + $this->error = null; // so no confusion is caused + + if(!$this->connected()) { + $this->error = array( + "error" => "Called Mail() without being connected"); + return false; + } + + $useVerp = ($this->do_verp ? "XVERP" : ""); + fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'; + } + + if($code != 250) { + $this->error = + array("error" => "MAIL not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; + } + return false; + } + return true; + } + + /** + * Sends the quit command to the server and then closes the socket + * if there is no error or the $close_on_error argument is true. + * + * Implements from rfc 821: QUIT + * + * SMTP CODE SUCCESS: 221 + * SMTP CODE ERROR : 500 + * @access public + * @return bool + */ + public function Quit($close_on_error = true) { + $this->error = null; // so there is no confusion + + if(!$this->connected()) { + $this->error = array( + "error" => "Called Quit() without being connected"); + return false; + } + + // send the quit command to the server + fputs($this->smtp_conn,"quit" . $this->CRLF); + + // get any good-bye messages + $byemsg = $this->get_lines(); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $byemsg . $this->CRLF . '
'; + } + + $rval = true; + $e = null; + + $code = substr($byemsg,0,3); + if($code != 221) { + // use e as a tmp var cause Close will overwrite $this->error + $e = array("error" => "SMTP server rejected quit command", + "smtp_code" => $code, + "smtp_rply" => substr($byemsg,4)); + $rval = false; + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $e["error"] . ": " . $byemsg . $this->CRLF . '
'; + } + } + + if(empty($e) || $close_on_error) { + $this->Close(); + } + + return $rval; + } + + /** + * Sends the command RCPT to the SMTP server with the TO: argument of $to. + * Returns true if the recipient was accepted false if it was rejected. + * + * Implements from rfc 821: RCPT TO: + * + * SMTP CODE SUCCESS: 250,251 + * SMTP CODE FAILURE: 550,551,552,553,450,451,452 + * SMTP CODE ERROR : 500,501,503,421 + * @access public + * @return bool + */ + public function Recipient($to) { + $this->error = null; // so no confusion is caused + + if(!$this->connected()) { + $this->error = array( + "error" => "Called Recipient() without being connected"); + return false; + } + + fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'; + } + + if($code != 250 && $code != 251) { + $this->error = + array("error" => "RCPT not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; + } + return false; + } + return true; + } + + /** + * Sends the RSET command to abort and transaction that is + * currently in progress. Returns true if successful false + * otherwise. + * + * Implements rfc 821: RSET + * + * SMTP CODE SUCCESS: 250 + * SMTP CODE ERROR : 500,501,504,421 + * @access public + * @return bool + */ + public function Reset() { + $this->error = null; // so no confusion is caused + + if(!$this->connected()) { + $this->error = array( + "error" => "Called Reset() without being connected"); + return false; + } + + fputs($this->smtp_conn,"RSET" . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'; + } + + if($code != 250) { + $this->error = + array("error" => "RSET failed", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; + } + return false; + } + + return true; + } + + /** + * Starts a mail transaction from the email address specified in + * $from. Returns true if successful or false otherwise. If True + * the mail transaction is started and then one or more Recipient + * commands may be called followed by a Data command. This command + * will send the message to the users terminal if they are logged + * in and send them an email. + * + * Implements rfc 821: SAML FROM: + * + * SMTP CODE SUCCESS: 250 + * SMTP CODE SUCCESS: 552,451,452 + * SMTP CODE SUCCESS: 500,501,502,421 + * @access public + * @return bool + */ + public function SendAndMail($from) { + $this->error = null; // so no confusion is caused + + if(!$this->connected()) { + $this->error = array( + "error" => "Called SendAndMail() without being connected"); + return false; + } + + fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'; + } + + if($code != 250) { + $this->error = + array("error" => "SAML not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; + } + return false; + } + return true; + } + + /** + * This is an optional command for SMTP that this class does not + * support. This method is here to make the RFC821 Definition + * complete for this class and __may__ be implimented in the future + * + * Implements from rfc 821: TURN + * + * SMTP CODE SUCCESS: 250 + * SMTP CODE FAILURE: 502 + * SMTP CODE ERROR : 500, 503 + * @access public + * @return bool + */ + public function Turn() { + $this->error = array("error" => "This method, TURN, of the SMTP ". + "is not implemented"); + if($this->do_debug >= 1) { + echo "SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF . '
'; + } + return false; + } + + /** + * Get the current error + * @access public + * @return array + */ + public function getError() { + return $this->error; + } + + ///////////////////////////////////////////////// + // INTERNAL FUNCTIONS + ///////////////////////////////////////////////// + + /** + * Read in as many lines as possible + * either before eof or socket timeout occurs on the operation. + * With SMTP we can tell if we have more lines to read if the + * 4th character is '-' symbol. If it is a space then we don't + * need to read anything else. + * @access private + * @return string + */ + private function get_lines() { + $data = ""; + while($str = @fgets($this->smtp_conn,515)) { + if($this->do_debug >= 4) { + echo "SMTP -> get_lines(): \$data was \"$data\"" . $this->CRLF . '
'; + echo "SMTP -> get_lines(): \$str is \"$str\"" . $this->CRLF . '
'; + } + $data .= $str; + if($this->do_debug >= 4) { + echo "SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF . '
'; + } + // if 4th character is a space, we are done reading, break the loop + if(substr($str,3,1) == " ") { break; } + } + return $data; + } + +} + +?> \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-ar.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-ar.php new file mode 100644 index 0000000000..b7c5057d0c --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-ar.php @@ -0,0 +1,27 @@ + +*/ + +$PHPMAILER_LANG['authenticate'] = 'SMTP Error: 賱賲 賳爻鬲胤毓 鬲兀賰賷丿 丕賱賴賵賷丞.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP Error: 賱賲 賳爻鬲胤毓 丕賱丕鬲氐丕賱 亘賲禺丿賲 SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Error: 賱賲 賷鬲賲 賯亘賵賱 丕賱賲毓賱賵賲丕鬲 .'; +//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; +$PHPMAILER_LANG['encoding'] = '鬲乇賲賷夭 睾賷乇 賲毓乇賵賮: '; +$PHPMAILER_LANG['execute'] = '賱賲 兀爻鬲胤毓 鬲賳賮賷匕 : '; +$PHPMAILER_LANG['file_access'] = '賱賲 賳爻鬲胤毓 丕賱賵氐賵賱 賱賱賲賱賮: '; +$PHPMAILER_LANG['file_open'] = 'File Error: 賱賲 賳爻鬲胤毓 賮鬲丨 丕賱賲賱賮: '; +$PHPMAILER_LANG['from_failed'] = '丕賱亘乇賷丿 丕賱鬲丕賱賷 賱賲 賳爻鬲胤毓 丕乇爻丕賱 丕賱亘乇賷丿 賱賴 : '; +$PHPMAILER_LANG['instantiate'] = '賱賲 賳爻鬲胤毓 鬲賵賮賷乇 禺丿賲丞 丕賱亘乇賷丿.'; +//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer 睾賷乇 賲丿毓賵賲.'; +//$PHPMAILER_LANG['provide_address'] = 'You must provide at least one recipient email address.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP Error: 丕賱兀禺胤丕亍 丕賱鬲丕賱賷丞 ' . + '賮卮賱 賮賷 丕賱丕乇爻丕賱 賱賰賱 賲賳 : '; +$PHPMAILER_LANG['signing'] = '禺胤兀 賮賷 丕賱鬲賵賯賷毓: '; +//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; +//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: '; +//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: '; +?> \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-br.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-br.php new file mode 100644 index 0000000000..7d64ce4d4c --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-br.php @@ -0,0 +1,26 @@ + \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-ca.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-ca.php new file mode 100644 index 0000000000..1127567dc8 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-ca.php @@ -0,0 +1,26 @@ + \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-ch.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-ch.php new file mode 100644 index 0000000000..31ebd861cb --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-ch.php @@ -0,0 +1,26 @@ + \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-cz.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-cz.php new file mode 100644 index 0000000000..f9589ca19d --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-cz.php @@ -0,0 +1,25 @@ + \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-de.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-de.php new file mode 100644 index 0000000000..165a86f4f7 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-de.php @@ -0,0 +1,25 @@ + \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-dk.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-dk.php new file mode 100644 index 0000000000..59b58c0fce --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-dk.php @@ -0,0 +1,26 @@ + +*/ + +$PHPMAILER_LANG['authenticate'] = 'SMTP fejl: Kunne ikke logge p氓.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP fejl: Kunne ikke tilslutte SMTP serveren.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP fejl: Data kunne ikke accepteres.'; +//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; +$PHPMAILER_LANG['encoding'] = 'Ukendt encode-format: '; +$PHPMAILER_LANG['execute'] = 'Kunne ikke k酶re: '; +$PHPMAILER_LANG['file_access'] = 'Ingen adgang til fil: '; +$PHPMAILER_LANG['file_open'] = 'Fil fejl: Kunne ikke 氓bne filen: '; +$PHPMAILER_LANG['from_failed'] = 'F酶lgende afsenderadresse er forkert: '; +$PHPMAILER_LANG['instantiate'] = 'Kunne ikke initialisere email funktionen.'; +//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer underst酶ttes ikke.'; +$PHPMAILER_LANG['provide_address'] = 'Du skal indtaste mindst en modtagers emailadresse.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP fejl: F酶lgende modtagere er forkerte: '; +//$PHPMAILER_LANG['signing'] = 'Signing Error: '; +//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; +//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: '; +//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: '; +?> \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-es.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-es.php new file mode 100644 index 0000000000..0b6982509c --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-es.php @@ -0,0 +1,26 @@ + \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-et.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-et.php new file mode 100644 index 0000000000..cf61779b08 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-et.php @@ -0,0 +1,26 @@ + \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-fi.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-fi.php new file mode 100644 index 0000000000..6d7dccee51 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-fi.php @@ -0,0 +1,27 @@ + \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-fo.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-fo.php new file mode 100644 index 0000000000..704c4772da --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-fo.php @@ -0,0 +1,27 @@ + \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-fr.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-fr.php new file mode 100644 index 0000000000..52e9ae2b99 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-fr.php @@ -0,0 +1,25 @@ + \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-hu.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-hu.php new file mode 100644 index 0000000000..a26648484b --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-hu.php @@ -0,0 +1,25 @@ + \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-it.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-it.php new file mode 100644 index 0000000000..59bf4fb978 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-it.php @@ -0,0 +1,27 @@ + +*/ + +$PHPMAILER_LANG['authenticate'] = 'SMTP Error: Impossibile autenticarsi.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP Error: Impossibile connettersi all\'host SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Error: Data non accettati dal server.'; +//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; +$PHPMAILER_LANG['encoding'] = 'Encoding set dei caratteri sconosciuto: '; +$PHPMAILER_LANG['execute'] = 'Impossibile eseguire l\'operazione: '; +$PHPMAILER_LANG['file_access'] = 'Impossibile accedere al file: '; +$PHPMAILER_LANG['file_open'] = 'File Error: Impossibile aprire il file: '; +$PHPMAILER_LANG['from_failed'] = 'I seguenti indirizzi mittenti hanno generato errore: '; +$PHPMAILER_LANG['instantiate'] = 'Impossibile istanziare la funzione mail'; +//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: '; +$PHPMAILER_LANG['provide_address'] = 'Deve essere fornito almeno un indirizzo ricevente'; +$PHPMAILER_LANG['mailer_not_supported'] = 'Mailer non supportato'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP Error: I seguenti indirizzi destinatari hanno generato errore: '; +//$PHPMAILER_LANG['signing'] = 'Signing Error: '; +//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; +//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: '; +//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: '; +?> \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-ja.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-ja.php new file mode 100644 index 0000000000..66da1b6a1d --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-ja.php @@ -0,0 +1,26 @@ + \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-nl.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-nl.php new file mode 100644 index 0000000000..355dcdc499 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-nl.php @@ -0,0 +1,25 @@ + \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-no.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-no.php new file mode 100644 index 0000000000..bf2f84ee9b --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-no.php @@ -0,0 +1,25 @@ + \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-pl.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-pl.php new file mode 100644 index 0000000000..e8bd5124d7 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-pl.php @@ -0,0 +1,25 @@ + \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-ro.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-ro.php new file mode 100644 index 0000000000..17cddb76b9 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-ro.php @@ -0,0 +1,27 @@ + +*/ + +$PHPMAILER_LANG['authenticate'] = 'Eroare SMTP: Nu a functionat autentificarea.'; +$PHPMAILER_LANG['connect_host'] = 'Eroare SMTP: Nu m-am putut conecta la adresa SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Eroare SMTP: Continutul mailului nu a fost acceptat.'; +//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; +$PHPMAILER_LANG['encoding'] = 'Encodare necunoscuta: '; +$PHPMAILER_LANG['execute'] = 'Nu pot executa: '; +$PHPMAILER_LANG['file_access'] = 'Nu pot accesa fisierul: '; +$PHPMAILER_LANG['file_open'] = 'Eroare de fisier: Nu pot deschide fisierul: '; +$PHPMAILER_LANG['from_failed'] = 'Urmatoarele adrese From au dat eroare: '; +$PHPMAILER_LANG['instantiate'] = 'Nu am putut instantia functia mail.'; +//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer nu este suportat.'; +$PHPMAILER_LANG['provide_address'] = 'Trebuie sa adaugati cel putin un recipient (adresa de mail).'; +$PHPMAILER_LANG['recipients_failed'] = 'Eroare SMTP: Urmatoarele adrese de mail au dat eroare: '; +//$PHPMAILER_LANG['signing'] = 'Signing Error: '; +//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; +//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: '; +//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: '; +?> \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-ru.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-ru.php new file mode 100644 index 0000000000..295a56ef49 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-ru.php @@ -0,0 +1,25 @@ + +*/ + +$PHPMAILER_LANG['authenticate'] = '袨褕懈斜泻邪 SMTP: 芯褕懈斜泻邪 邪胁褌芯褉懈蟹邪褑懈懈.'; +$PHPMAILER_LANG['connect_host'] = '袨褕懈斜泻邪 SMTP: 薪械 褍写邪械褌褋褟 锌芯写泻谢褞褔懈褌褜褋褟 泻 褋械褉胁械褉褍 SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = '袨褕懈斜泻邪 SMTP: 写邪薪薪褘械 薪械 锌褉懈薪褟褌褘.'; +//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; +$PHPMAILER_LANG['encoding'] = '袧械懈蟹胁械褋褌薪褘泄 胁懈写 泻芯写懈褉芯胁泻懈: '; +$PHPMAILER_LANG['execute'] = '袧械胁芯蟹屑芯卸薪芯 胁褘锌芯谢薪懈褌褜 泻芯屑邪薪写褍: '; +$PHPMAILER_LANG['file_access'] = '袧械褌 写芯褋褌褍锌邪 泻 褎邪泄谢褍: '; +$PHPMAILER_LANG['file_open'] = '肖邪泄谢芯胁邪褟 芯褕懈斜泻邪: 薪械 褍写邪械褌褋褟 芯褌泻褉褘褌褜 褎邪泄谢: '; +$PHPMAILER_LANG['from_failed'] = '袧械胁械褉薪褘泄 邪写褉械褋 芯褌锌褉邪胁懈褌械谢褟: '; +$PHPMAILER_LANG['instantiate'] = '袧械胁芯蟹屑芯卸薪芯 蟹邪锌褍褋褌懈褌褜 褎褍薪泻褑懈褞 mail.'; +//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: '; +$PHPMAILER_LANG['provide_address'] = '袩芯卸邪谢褍泄褋褌邪, 胁胁械写懈褌械 褏芯褌褟 斜褘 芯写懈薪 邪写褉械褋 e-mail 锌芯谢褍褔邪褌械谢褟.'; +$PHPMAILER_LANG['mailer_not_supported'] = ' - 锌芯褔褌芯胁褘泄 褋械褉胁械褉 薪械 锌芯写写械褉卸懈胁邪械褌褋褟.'; +$PHPMAILER_LANG['recipients_failed'] = '袨褕懈斜泻邪 SMTP: 芯褌锌褉邪胁泻邪 锌芯 褋谢械写褍褞褖懈屑 邪写褉械褋邪屑 锌芯谢褍褔邪褌械谢械泄 薪械 褍写邪谢邪褋褜: '; +//$PHPMAILER_LANG['signing'] = 'Signing Error: '; +//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; +//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: '; +//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: '; +?> \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-se.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-se.php new file mode 100644 index 0000000000..d459667f7d --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-se.php @@ -0,0 +1,26 @@ + +*/ + +$PHPMAILER_LANG['authenticate'] = 'SMTP fel: Kunde inte autentisera.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP fel: Kunde inte ansluta till SMTP-server.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP fel: Data accepterades inte.'; +//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; +$PHPMAILER_LANG['encoding'] = 'Ok盲nt encode-format: '; +$PHPMAILER_LANG['execute'] = 'Kunde inte k枚ra: '; +$PHPMAILER_LANG['file_access'] = 'Ingen 氓tkomst till fil: '; +$PHPMAILER_LANG['file_open'] = 'Fil fel: Kunde inte 枚ppna fil: '; +$PHPMAILER_LANG['from_failed'] = 'F枚ljande avs盲ndaradress 盲r felaktig: '; +$PHPMAILER_LANG['instantiate'] = 'Kunde inte initiera e-postfunktion.'; +//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: '; +$PHPMAILER_LANG['provide_address'] = 'Du m氓ste ange minst en mottagares e-postadress.'; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer st枚ds inte.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP fel: F枚ljande mottagare 盲r felaktig: '; +//$PHPMAILER_LANG['signing'] = 'Signing Error: '; +//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; +//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: '; +//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: '; +?> \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-tr.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-tr.php new file mode 100644 index 0000000000..8a069d14d0 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-tr.php @@ -0,0 +1,27 @@ + \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-zh.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-zh.php new file mode 100644 index 0000000000..fef66f8cb1 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-zh.php @@ -0,0 +1,26 @@ + +*/ + +$PHPMAILER_LANG['authenticate'] = 'SMTP 閷锛氱櫥閷勫け鏁椼'; +$PHPMAILER_LANG['connect_host'] = 'SMTP 閷锛氱劇娉曢f帴鍒 SMTP 涓绘銆'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP 閷锛氭暩鎿氫笉琚帴鍙椼'; +//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; +$PHPMAILER_LANG['encoding'] = '鏈煡绶ㄧ⒓: '; +$PHPMAILER_LANG['file_access'] = '鐒℃硶瑷晱鏂囦欢锛'; +$PHPMAILER_LANG['file_open'] = '鏂囦欢閷锛氱劇娉曟墦闁嬫枃浠讹細'; +$PHPMAILER_LANG['from_failed'] = '鐧奸佸湴鍧閷锛'; +$PHPMAILER_LANG['execute'] = '鐒℃硶鍩疯锛'; +$PHPMAILER_LANG['instantiate'] = '鏈煡鍑芥暩瑾跨敤銆'; +//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: '; +$PHPMAILER_LANG['provide_address'] = '蹇呴爤鎻愪緵鑷冲皯涓鍊嬫敹浠朵汉鍦板潃銆'; +$PHPMAILER_LANG['mailer_not_supported'] = '鐧间俊瀹㈡埗绔笉琚敮鎸併'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP 閷锛氭敹浠朵汉鍦板潃閷锛'; +//$PHPMAILER_LANG['signing'] = 'Signing Error: '; +//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; +//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: '; +//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: '; +?> \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-zh_cn.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-zh_cn.php new file mode 100644 index 0000000000..b188404359 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/language/phpmailer.lang-zh_cn.php @@ -0,0 +1,26 @@ + +*/ + +$PHPMAILER_LANG['authenticate'] = 'SMTP 閿欒锛氱櫥褰曞け璐ャ'; +$PHPMAILER_LANG['connect_host'] = 'SMTP 閿欒锛氭棤娉曡繛鎺ュ埌 SMTP 涓绘満銆'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP 閿欒锛氭暟鎹笉琚帴鍙椼'; +//$P$PHPMAILER_LANG['empty_message'] = 'Message body empty'; +$PHPMAILER_LANG['encoding'] = '鏈煡缂栫爜: '; +$PHPMAILER_LANG['execute'] = '鏃犳硶鎵ц锛'; +$PHPMAILER_LANG['file_access'] = '鏃犳硶璁块棶鏂囦欢锛'; +$PHPMAILER_LANG['file_open'] = '鏂囦欢閿欒锛氭棤娉曟墦寮鏂囦欢锛'; +$PHPMAILER_LANG['from_failed'] = '鍙戦佸湴鍧閿欒锛'; +$PHPMAILER_LANG['instantiate'] = '鏈煡鍑芥暟璋冪敤銆'; +//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: '; +$PHPMAILER_LANG['mailer_not_supported'] = '鍙戜俊瀹㈡埛绔笉琚敮鎸併'; +$PHPMAILER_LANG['provide_address'] = '蹇呴』鎻愪緵鑷冲皯涓涓敹浠朵汉鍦板潃銆'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP 閿欒锛氭敹浠朵汉鍦板潃閿欒锛'; +//$PHPMAILER_LANG['signing'] = 'Signing Error: '; +//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; +//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: '; +//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: '; +?> \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/phpmailer.class.php b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/phpmailer.class.php new file mode 100644 index 0000000000..09479239bf --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/lib/phpmailer/phpmailer.class.php @@ -0,0 +1,2320 @@ +exceptions = ($exceptions == true); + } + + /** + * Sets message type to HTML. + * @param bool $ishtml + * @return void + */ + public function IsHTML($ishtml = true) { + if ($ishtml) { + $this->ContentType = 'text/html'; + } else { + $this->ContentType = 'text/plain'; + } + } + + /** + * Sets Mailer to send message using SMTP. + * @return void + */ + public function IsSMTP() { + $this->Mailer = 'smtp'; + } + + /** + * Sets Mailer to send message using PHP mail() function. + * @return void + */ + public function IsMail() { + $this->Mailer = 'mail'; + } + + /** + * Sets Mailer to send message using the $Sendmail program. + * @return void + */ + public function IsSendmail() { + if (!stristr(ini_get('sendmail_path'), 'sendmail')) { + $this->Sendmail = '/var/qmail/bin/sendmail'; + } + $this->Mailer = 'sendmail'; + } + + /** + * Sets Mailer to send message using the qmail MTA. + * @return void + */ + public function IsQmail() { + if (stristr(ini_get('sendmail_path'), 'qmail')) { + $this->Sendmail = '/var/qmail/bin/sendmail'; + } + $this->Mailer = 'sendmail'; + } + + ///////////////////////////////////////////////// + // METHODS, RECIPIENTS + ///////////////////////////////////////////////// + + /** + * Adds a "To" address. + * @param string $address + * @param string $name + * @return boolean true on success, false if address already used + */ + public function AddAddress($address, $name = '') { + return $this->AddAnAddress('to', $address, $name); + } + + /** + * Adds a "Cc" address. + * Note: this function works with the SMTP mailer on win32, not with the "mail" mailer. + * @param string $address + * @param string $name + * @return boolean true on success, false if address already used + */ + public function AddCC($address, $name = '') { + return $this->AddAnAddress('cc', $address, $name); + } + + /** + * Adds a "Bcc" address. + * Note: this function works with the SMTP mailer on win32, not with the "mail" mailer. + * @param string $address + * @param string $name + * @return boolean true on success, false if address already used + */ + public function AddBCC($address, $name = '') { + return $this->AddAnAddress('bcc', $address, $name); + } + + /** + * Adds a "Reply-to" address. + * @param string $address + * @param string $name + * @return boolean + */ + public function AddReplyTo($address, $name = '') { + return $this->AddAnAddress('ReplyTo', $address, $name); + } + + /** + * Adds an address to one of the recipient arrays + * Addresses that have been added already return false, but do not throw exceptions + * @param string $kind One of 'to', 'cc', 'bcc', 'ReplyTo' + * @param string $address The email address to send to + * @param string $name + * @return boolean true on success, false if address already used or invalid in some way + * @access private + */ + private function AddAnAddress($kind, $address, $name = '') { + if (!preg_match('/^(to|cc|bcc|ReplyTo)$/', $kind)) { + echo 'Invalid recipient array: ' . kind; + return false; + } + $address = trim($address); + $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim + if (!self::ValidateAddress($address)) { + $this->SetError($this->Lang('invalid_address').': '. $address); + if ($this->exceptions) { + throw new phpmailerException($this->Lang('invalid_address').': '.$address); + } + echo $this->Lang('invalid_address').': '.$address; + return false; + } + if ($kind != 'ReplyTo') { + if (!isset($this->all_recipients[strtolower($address)])) { + array_push($this->$kind, array($address, $name)); + $this->all_recipients[strtolower($address)] = true; + return true; + } + } else { + if (!array_key_exists(strtolower($address), $this->ReplyTo)) { + $this->ReplyTo[strtolower($address)] = array($address, $name); + return true; + } + } + return false; +} + +/** + * Set the From and FromName properties + * @param string $address + * @param string $name + * @return boolean + */ + public function SetFrom($address, $name = '',$auto=1) { + $address = trim($address); + $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim + if (!self::ValidateAddress($address)) { + $this->SetError($this->Lang('invalid_address').': '. $address); + if ($this->exceptions) { + throw new phpmailerException($this->Lang('invalid_address').': '.$address); + } + echo $this->Lang('invalid_address').': '.$address; + return false; + } + $this->From = $address; + $this->FromName = $name; + if ($auto) { + if (empty($this->ReplyTo)) { + $this->AddAnAddress('ReplyTo', $address, $name); + } + if (empty($this->Sender)) { + $this->Sender = $address; + } + } + return true; + } + + /** + * Check that a string looks roughly like an email address should + * Static so it can be used without instantiation + * Tries to use PHP built-in validator in the filter extension (from PHP 5.2), falls back to a reasonably competent regex validator + * Conforms approximately to RFC2822 + * @link http://www.hexillion.com/samples/#Regex Original pattern found here + * @param string $address The email address to check + * @return boolean + * @static + * @access public + */ + public static function ValidateAddress($address) { + if (function_exists('filter_var')) { //Introduced in PHP 5.2 + if(filter_var($address, FILTER_VALIDATE_EMAIL) === FALSE) { + return false; + } else { + return true; + } + } else { + return preg_match('/^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!\.)){0,61}[a-zA-Z0-9_-]?\.)+[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!$)){0,61}[a-zA-Z0-9_]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/', $address); + } + } + + ///////////////////////////////////////////////// + // METHODS, MAIL SENDING + ///////////////////////////////////////////////// + + /** + * Creates message and assigns Mailer. If the message is + * not sent successfully then it returns false. Use the ErrorInfo + * variable to view description of the error. + * @return bool + */ + public function Send() { + try { + if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) { + throw new phpmailerException($this->Lang('provide_address'), self::STOP_CRITICAL); + } + + // Set whether the message is multipart/alternative + if(!empty($this->AltBody)) { + $this->ContentType = 'multipart/alternative'; + } + + $this->error_count = 0; // reset errors + $this->SetMessageType(); + $header = $this->CreateHeader(); + $body = $this->CreateBody(); + + if (empty($this->Body)) { + throw new phpmailerException($this->Lang('empty_message'), self::STOP_CRITICAL); + } + + // digitally sign with DKIM if enabled + if ($this->DKIM_domain && $this->DKIM_private) { + $header_dkim = $this->DKIM_Add($header,$this->Subject,$body); + $header = str_replace("\r\n","\n",$header_dkim) . $header; + } + + // Choose the mailer and send through it + switch($this->Mailer) { + case 'sendmail': + return $this->SendmailSend($header, $body); + case 'smtp': + return $this->SmtpSend($header, $body); + default: + return $this->MailSend($header, $body); + } + + } catch (phpmailerException $e) { + $this->SetError($e->getMessage()); + if ($this->exceptions) { + throw $e; + } + echo $e->getMessage()."\n"; + return false; + } + } + + /** + * Sends mail using the $Sendmail program. + * @param string $header The message headers + * @param string $body The message body + * @access protected + * @return bool + */ + protected function SendmailSend($header, $body) { + if ($this->Sender != '') { + $sendmail = sprintf("%s -oi -f %s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender)); + } else { + $sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail)); + } + if ($this->SingleTo === true) { + foreach ($this->SingleToArray as $key => $val) { + if(!@$mail = popen($sendmail, 'w')) { + throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + fputs($mail, "To: " . $val . "\n"); + fputs($mail, $header); + fputs($mail, $body); + $result = pclose($mail); + // implement call back function if it exists + $isSent = ($result == 0) ? 1 : 0; + $this->doCallback($isSent,$val,$this->cc,$this->bcc,$this->Subject,$body); + if($result != 0) { + throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + } + } else { + if(!@$mail = popen($sendmail, 'w')) { + throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + fputs($mail, $header); + fputs($mail, $body); + $result = pclose($mail); + // implement call back function if it exists + $isSent = ($result == 0) ? 1 : 0; + $this->doCallback($isSent,$this->to,$this->cc,$this->bcc,$this->Subject,$body); + if($result != 0) { + throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + } + return true; + } + + /** + * Sends mail using the PHP mail() function. + * @param string $header The message headers + * @param string $body The message body + * @access protected + * @return bool + */ + protected function MailSend($header, $body) { + $toArr = array(); + foreach($this->to as $t) { + $toArr[] = $this->AddrFormat($t); + } + $to = implode(', ', $toArr); + + $params = sprintf("-oi -f %s", $this->Sender); + if ($this->Sender != '' && strlen(ini_get('safe_mode'))< 1) { + $old_from = ini_get('sendmail_from'); + ini_set('sendmail_from', $this->Sender); + if ($this->SingleTo === true && count($toArr) > 1) { + foreach ($toArr as $key => $val) { + $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params); + // implement call back function if it exists + $isSent = ($rt == 1) ? 1 : 0; + $this->doCallback($isSent,$val,$this->cc,$this->bcc,$this->Subject,$body); + } + } else { + $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params); + // implement call back function if it exists + $isSent = ($rt == 1) ? 1 : 0; + $this->doCallback($isSent,$to,$this->cc,$this->bcc,$this->Subject,$body); + } + } else { + if ($this->SingleTo === true && count($toArr) > 1) { + foreach ($toArr as $key => $val) { + $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params); + // implement call back function if it exists + $isSent = ($rt == 1) ? 1 : 0; + $this->doCallback($isSent,$val,$this->cc,$this->bcc,$this->Subject,$body); + } + } else { + $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header); + // implement call back function if it exists + $isSent = ($rt == 1) ? 1 : 0; + $this->doCallback($isSent,$to,$this->cc,$this->bcc,$this->Subject,$body); + } + } + if (isset($old_from)) { + ini_set('sendmail_from', $old_from); + } + if(!$rt) { + throw new phpmailerException($this->Lang('instantiate'), self::STOP_CRITICAL); + } + return true; + } + + /** + * Sends mail via SMTP using PhpSMTP + * Returns false if there is a bad MAIL FROM, RCPT, or DATA input. + * @param string $header The message headers + * @param string $body The message body + * @uses SMTP + * @access protected + * @return bool + */ + protected function SmtpSend($header, $body) { + require_once $this->PluginDir . 'class.smtp.php'; + $bad_rcpt = array(); + + if(!$this->SmtpConnect()) { + throw new phpmailerException($this->Lang('smtp_connect_failed'), self::STOP_CRITICAL); + } + $smtp_from = ($this->Sender == '') ? $this->From : $this->Sender; + if(!$this->smtp->Mail($smtp_from)) { + throw new phpmailerException($this->Lang('from_failed') . $smtp_from, self::STOP_CRITICAL); + } + + // Attempt to send attach all recipients + foreach($this->to as $to) { + if (!$this->smtp->Recipient($to[0])) { + $bad_rcpt[] = $to[0]; + // implement call back function if it exists + $isSent = 0; + $this->doCallback($isSent,$to[0],'','',$this->Subject,$body); + } else { + // implement call back function if it exists + $isSent = 1; + $this->doCallback($isSent,$to[0],'','',$this->Subject,$body); + } + } + foreach($this->cc as $cc) { + if (!$this->smtp->Recipient($cc[0])) { + $bad_rcpt[] = $cc[0]; + // implement call back function if it exists + $isSent = 0; + $this->doCallback($isSent,'',$cc[0],'',$this->Subject,$body); + } else { + // implement call back function if it exists + $isSent = 1; + $this->doCallback($isSent,'',$cc[0],'',$this->Subject,$body); + } + } + foreach($this->bcc as $bcc) { + if (!$this->smtp->Recipient($bcc[0])) { + $bad_rcpt[] = $bcc[0]; + // implement call back function if it exists + $isSent = 0; + $this->doCallback($isSent,'','',$bcc[0],$this->Subject,$body); + } else { + // implement call back function if it exists + $isSent = 1; + $this->doCallback($isSent,'','',$bcc[0],$this->Subject,$body); + } + } + + + if (count($bad_rcpt) > 0 ) { //Create error message for any bad addresses + $badaddresses = implode(', ', $bad_rcpt); + throw new phpmailerException($this->Lang('recipients_failed') . $badaddresses); + } + if(!$this->smtp->Data($header . $body)) { + throw new phpmailerException($this->Lang('data_not_accepted'), self::STOP_CRITICAL); + } + if($this->SMTPKeepAlive == true) { + $this->smtp->Reset(); + } + return true; + } + + /** + * Initiates a connection to an SMTP server. + * Returns false if the operation failed. + * @uses SMTP + * @access public + * @return bool + */ + public function SmtpConnect() { + if(is_null($this->smtp)) { + $this->smtp = new SMTP(); + } + + $this->smtp->do_debug = $this->SMTPDebug; + $hosts = explode(';', $this->Host); + $index = 0; + $connection = $this->smtp->Connected(); + + // Retry while there is no connection + try { + while($index < count($hosts) && !$connection) { + $hostinfo = array(); + if (preg_match('/^(.+):([0-9]+)$/', $hosts[$index], $hostinfo)) { + $host = $hostinfo[1]; + $port = $hostinfo[2]; + } else { + $host = $hosts[$index]; + $port = $this->Port; + } + + $tls = ($this->SMTPSecure == 'tls'); + $ssl = ($this->SMTPSecure == 'ssl'); + + if ($this->smtp->Connect(($ssl ? 'ssl://':'').$host, $port, $this->Timeout)) { + + $hello = ($this->Helo != '' ? $this->Helo : $this->ServerHostname()); + $this->smtp->Hello($hello); + + if ($tls) { + if (!$this->smtp->StartTLS()) { + throw new phpmailerException($this->Lang('tls')); + } + + //We must resend HELO after tls negotiation + $this->smtp->Hello($hello); + } + + $connection = true; + if ($this->SMTPAuth) { + if (!$this->smtp->Authenticate($this->Username, $this->Password)) { + throw new phpmailerException($this->Lang('authenticate')); + } + } + } + $index++; + if (!$connection) { + throw new phpmailerException($this->Lang('connect_host')); + } + } + } catch (phpmailerException $e) { + $this->smtp->Reset(); + throw $e; + } + return true; + } + + /** + * Closes the active SMTP session if one exists. + * @return void + */ + public function SmtpClose() { + if(!is_null($this->smtp)) { + if($this->smtp->Connected()) { + $this->smtp->Quit(); + $this->smtp->Close(); + } + } + } + + /** + * Sets the language for all class error messages. + * Returns false if it cannot load the language file. The default language is English. + * @param string $langcode ISO 639-1 2-character language code (e.g. Portuguese: "br") + * @param string $lang_path Path to the language file directory + * @access public + */ + function SetLanguage($langcode = 'en', $lang_path = 'language/') { + //Define full set of translatable strings + $PHPMAILER_LANG = array( + 'provide_address' => 'You must provide at least one recipient email address.', + 'mailer_not_supported' => ' mailer is not supported.', + 'execute' => 'Could not execute: ', + 'instantiate' => 'Could not instantiate mail function.', + 'authenticate' => 'SMTP Error: Could not authenticate.', + 'from_failed' => 'The following From address failed: ', + 'recipients_failed' => 'SMTP Error: The following recipients failed: ', + 'data_not_accepted' => 'SMTP Error: Data not accepted.', + 'connect_host' => 'SMTP Error: Could not connect to SMTP host.', + 'file_access' => 'Could not access file: ', + 'file_open' => 'File Error: Could not open file: ', + 'encoding' => 'Unknown encoding: ', + 'signing' => 'Signing Error: ', + 'smtp_error' => 'SMTP server error: ', + 'empty_message' => 'Message body empty', + 'invalid_address' => 'Invalid address', + 'variable_set' => 'Cannot set or reset variable: ' + ); + //Overwrite language-specific strings. This way we'll never have missing translations - no more "language string failed to load"! + $l = true; + if ($langcode != 'en') { //There is no English translation file + $l = @include $lang_path.'phpmailer.lang-'.$langcode.'.php'; + } + $this->language = $PHPMAILER_LANG; + return ($l == true); //Returns false if language not found + } + + /** + * Return the current array of language strings + * @return array + */ + public function GetTranslations() { + return $this->language; + } + + ///////////////////////////////////////////////// + // METHODS, MESSAGE CREATION + ///////////////////////////////////////////////// + + /** + * Creates recipient headers. + * @access public + * @return string + */ + public function AddrAppend($type, $addr) { + $addr_str = $type . ': '; + $addresses = array(); + foreach ($addr as $a) { + $addresses[] = $this->AddrFormat($a); + } + $addr_str .= implode(', ', $addresses); + $addr_str .= $this->LE; + + return $addr_str; + } + + /** + * Formats an address correctly. + * @access public + * @return string + */ + public function AddrFormat($addr) { + if (empty($addr[1])) { + return $this->SecureHeader($addr[0]); + } else { + return $this->EncodeHeader($this->SecureHeader($addr[1]), 'phrase') . " <" . $this->SecureHeader($addr[0]) . ">"; + } + } + + /** + * Wraps message for use with mailers that do not + * automatically perform wrapping and for quoted-printable. + * Original written by philippe. + * @param string $message The message to wrap + * @param integer $length The line length to wrap to + * @param boolean $qp_mode Whether to run in Quoted-Printable mode + * @access public + * @return string + */ + public function WrapText($message, $length, $qp_mode = false) { + $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE; + // If utf-8 encoding is used, we will need to make sure we don't + // split multibyte characters when we wrap + $is_utf8 = (strtolower($this->CharSet) == "utf-8"); + + $message = $this->FixEOL($message); + if (substr($message, -1) == $this->LE) { + $message = substr($message, 0, -1); + } + + $line = explode($this->LE, $message); + $message = ''; + for ($i=0 ;$i < count($line); $i++) { + $line_part = explode(' ', $line[$i]); + $buf = ''; + for ($e = 0; $e $length)) { + $space_left = $length - strlen($buf) - 1; + if ($e != 0) { + if ($space_left > 20) { + $len = $space_left; + if ($is_utf8) { + $len = $this->UTF8CharBoundary($word, $len); + } elseif (substr($word, $len - 1, 1) == "=") { + $len--; + } elseif (substr($word, $len - 2, 1) == "=") { + $len -= 2; + } + $part = substr($word, 0, $len); + $word = substr($word, $len); + $buf .= ' ' . $part; + $message .= $buf . sprintf("=%s", $this->LE); + } else { + $message .= $buf . $soft_break; + } + $buf = ''; + } + while (strlen($word) > 0) { + $len = $length; + if ($is_utf8) { + $len = $this->UTF8CharBoundary($word, $len); + } elseif (substr($word, $len - 1, 1) == "=") { + $len--; + } elseif (substr($word, $len - 2, 1) == "=") { + $len -= 2; + } + $part = substr($word, 0, $len); + $word = substr($word, $len); + + if (strlen($word) > 0) { + $message .= $part . sprintf("=%s", $this->LE); + } else { + $buf = $part; + } + } + } else { + $buf_o = $buf; + $buf .= ($e == 0) ? $word : (' ' . $word); + + if (strlen($buf) > $length and $buf_o != '') { + $message .= $buf_o . $soft_break; + $buf = $word; + } + } + } + $message .= $buf . $this->LE; + } + + return $message; + } + + /** + * Finds last character boundary prior to maxLength in a utf-8 + * quoted (printable) encoded string. + * Original written by Colin Brown. + * @access public + * @param string $encodedText utf-8 QP text + * @param int $maxLength find last character boundary prior to this length + * @return int + */ + public function UTF8CharBoundary($encodedText, $maxLength) { + $foundSplitPos = false; + $lookBack = 3; + while (!$foundSplitPos) { + $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack); + $encodedCharPos = strpos($lastChunk, "="); + if ($encodedCharPos !== false) { + // Found start of encoded character byte within $lookBack block. + // Check the encoded byte value (the 2 chars after the '=') + $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2); + $dec = hexdec($hex); + if ($dec < 128) { // Single byte character. + // If the encoded char was found at pos 0, it will fit + // otherwise reduce maxLength to start of the encoded char + $maxLength = ($encodedCharPos == 0) ? $maxLength : + $maxLength - ($lookBack - $encodedCharPos); + $foundSplitPos = true; + } elseif ($dec >= 192) { // First byte of a multi byte character + // Reduce maxLength to split at start of character + $maxLength = $maxLength - ($lookBack - $encodedCharPos); + $foundSplitPos = true; + } elseif ($dec < 192) { // Middle byte of a multi byte character, look further back + $lookBack += 3; + } + } else { + // No encoded character found + $foundSplitPos = true; + } + } + return $maxLength; + } + + + /** + * Set the body wrapping. + * @access public + * @return void + */ + public function SetWordWrap() { + if($this->WordWrap < 1) { + return; + } + + switch($this->message_type) { + case 'alt': + case 'alt_attachments': + $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap); + break; + default: + $this->Body = $this->WrapText($this->Body, $this->WordWrap); + break; + } + } + + /** + * Assembles message header. + * @access public + * @return string The assembled header + */ + public function CreateHeader() { + $result = ''; + + // Set the boundaries + $uniq_id = md5(uniqid(time())); + $this->boundary[1] = 'b1_' . $uniq_id; + $this->boundary[2] = 'b2_' . $uniq_id; + + $result .= $this->HeaderLine('Date', self::RFCDate()); + if($this->Sender == '') { + $result .= $this->HeaderLine('Return-Path', trim($this->From)); + } else { + $result .= $this->HeaderLine('Return-Path', trim($this->Sender)); + } + + // To be created automatically by mail() + if($this->Mailer != 'mail') { + if ($this->SingleTo === true) { + foreach($this->to as $t) { + $this->SingleToArray[] = $this->AddrFormat($t); + } + } else { + if(count($this->to) > 0) { + $result .= $this->AddrAppend('To', $this->to); + } elseif (count($this->cc) == 0) { + $result .= $this->HeaderLine('To', 'undisclosed-recipients:;'); + } + } + } + + $from = array(); + $from[0][0] = trim($this->From); + $from[0][1] = $this->FromName; + $result .= $this->AddrAppend('From', $from); + + // sendmail and mail() extract Cc from the header before sending + if(count($this->cc) > 0) { + $result .= $this->AddrAppend('Cc', $this->cc); + } + + // sendmail and mail() extract Bcc from the header before sending + if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->bcc) > 0)) { + $result .= $this->AddrAppend('Bcc', $this->bcc); + } + + if(count($this->ReplyTo) > 0) { + $result .= $this->AddrAppend('Reply-to', $this->ReplyTo); + } + + // mail() sets the subject itself + if($this->Mailer != 'mail') { + $result .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader($this->Subject))); + } + + if($this->MessageID != '') { + $result .= $this->HeaderLine('Message-ID',$this->MessageID); + } else { + $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE); + } + $result .= $this->HeaderLine('X-Priority', $this->Priority); + $result .= $this->HeaderLine('X-Mailer', 'PHPMailer '.$this->Version.' (phpmailer.sourceforge.net)'); + + if($this->ConfirmReadingTo != '') { + $result .= $this->HeaderLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>'); + } + + // Add custom headers + for($index = 0; $index < count($this->CustomHeader); $index++) { + $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), $this->EncodeHeader(trim($this->CustomHeader[$index][1]))); + } + if (!$this->sign_key_file) { + $result .= $this->HeaderLine('MIME-Version', '1.0'); + $result .= $this->GetMailMIME(); + } + + return $result; + } + + /** + * Returns the message MIME. + * @access public + * @return string + */ + public function GetMailMIME() { + $result = ''; + switch($this->message_type) { + case 'plain': + $result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding); + $result .= sprintf("Content-Type: %s; charset=\"%s\"", $this->ContentType, $this->CharSet); + break; + case 'attachments': + case 'alt_attachments': + if($this->InlineImageExists()){ + $result .= sprintf("Content-Type: %s;%s\ttype=\"text/html\";%s\tboundary=\"%s\"%s", 'multipart/related', $this->LE, $this->LE, $this->boundary[1], $this->LE); + } else { + $result .= $this->HeaderLine('Content-Type', 'multipart/mixed;'); + $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"'); + } + break; + case 'alt': + $result .= $this->HeaderLine('Content-Type', 'multipart/alternative;'); + $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"'); + break; + } + + if($this->Mailer != 'mail') { + $result .= $this->LE.$this->LE; + } + + return $result; + } + + /** + * Assembles the message body. Returns an empty string on failure. + * @access public + * @return string The assembled message body + */ + public function CreateBody() { + $body = ''; + + if ($this->sign_key_file) { + $body .= $this->GetMailMIME(); + } + + $this->SetWordWrap(); + + switch($this->message_type) { + case 'alt': + $body .= $this->GetBoundary($this->boundary[1], '', 'text/plain', ''); + $body .= $this->EncodeString($this->AltBody, $this->Encoding); + $body .= $this->LE.$this->LE; + $body .= $this->GetBoundary($this->boundary[1], '', 'text/html', ''); + $body .= $this->EncodeString($this->Body, $this->Encoding); + $body .= $this->LE.$this->LE; + $body .= $this->EndBoundary($this->boundary[1]); + break; + case 'plain': + $body .= $this->EncodeString($this->Body, $this->Encoding); + break; + case 'attachments': + $body .= $this->GetBoundary($this->boundary[1], '', '', ''); + $body .= $this->EncodeString($this->Body, $this->Encoding); + $body .= $this->LE; + $body .= $this->AttachAll(); + break; + case 'alt_attachments': + $body .= sprintf("--%s%s", $this->boundary[1], $this->LE); + $body .= sprintf("Content-Type: %s;%s" . "\tboundary=\"%s\"%s", 'multipart/alternative', $this->LE, $this->boundary[2], $this->LE.$this->LE); + $body .= $this->GetBoundary($this->boundary[2], '', 'text/plain', '') . $this->LE; // Create text body + $body .= $this->EncodeString($this->AltBody, $this->Encoding); + $body .= $this->LE.$this->LE; + $body .= $this->GetBoundary($this->boundary[2], '', 'text/html', '') . $this->LE; // Create the HTML body + $body .= $this->EncodeString($this->Body, $this->Encoding); + $body .= $this->LE.$this->LE; + $body .= $this->EndBoundary($this->boundary[2]); + $body .= $this->AttachAll(); + break; + } + + if ($this->IsError()) { + $body = ''; + } elseif ($this->sign_key_file) { + try { + $file = tempnam('', 'mail'); + file_put_contents($file, $body); //TODO check this worked + $signed = tempnam("", "signed"); + if (@openssl_pkcs7_sign($file, $signed, "file://".$this->sign_cert_file, array("file://".$this->sign_key_file, $this->sign_key_pass), NULL)) { + @unlink($file); + @unlink($signed); + $body = file_get_contents($signed); + } else { + @unlink($file); + @unlink($signed); + throw new phpmailerException($this->Lang("signing").openssl_error_string()); + } + } catch (phpmailerException $e) { + $body = ''; + if ($this->exceptions) { + throw $e; + } + } + } + + return $body; + } + + /** + * Returns the start of a message boundary. + * @access private + */ + private function GetBoundary($boundary, $charSet, $contentType, $encoding) { + $result = ''; + if($charSet == '') { + $charSet = $this->CharSet; + } + if($contentType == '') { + $contentType = $this->ContentType; + } + if($encoding == '') { + $encoding = $this->Encoding; + } + $result .= $this->TextLine('--' . $boundary); + $result .= sprintf("Content-Type: %s; charset = \"%s\"", $contentType, $charSet); + $result .= $this->LE; + $result .= $this->HeaderLine('Content-Transfer-Encoding', $encoding); + $result .= $this->LE; + + return $result; + } + + /** + * Returns the end of a message boundary. + * @access private + */ + private function EndBoundary($boundary) { + return $this->LE . '--' . $boundary . '--' . $this->LE; + } + + /** + * Sets the message type. + * @access private + * @return void + */ + private function SetMessageType() { + if(count($this->attachment) < 1 && strlen($this->AltBody) < 1) { + $this->message_type = 'plain'; + } else { + if(count($this->attachment) > 0) { + $this->message_type = 'attachments'; + } + if(strlen($this->AltBody) > 0 && count($this->attachment) < 1) { + $this->message_type = 'alt'; + } + if(strlen($this->AltBody) > 0 && count($this->attachment) > 0) { + $this->message_type = 'alt_attachments'; + } + } + } + + /** + * Returns a formatted header line. + * @access public + * @return string + */ + public function HeaderLine($name, $value) { + return $name . ': ' . $value . $this->LE; + } + + /** + * Returns a formatted mail line. + * @access public + * @return string + */ + public function TextLine($value) { + return $value . $this->LE; + } + + ///////////////////////////////////////////////// + // CLASS METHODS, ATTACHMENTS + ///////////////////////////////////////////////// + + /** + * Adds an attachment from a path on the filesystem. + * Returns false if the file could not be found + * or accessed. + * @param string $path Path to the attachment. + * @param string $name Overrides the attachment name. + * @param string $encoding File encoding (see $Encoding). + * @param string $type File extension (MIME) type. + * @return bool + */ + public function AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') { + try { + if ( !@is_file($path) ) { + throw new phpmailerException($this->Lang('file_access') . $path, self::STOP_CONTINUE); + } + $filename = basename($path); + if ( $name == '' ) { + $name = $filename; + } + + $this->attachment[] = array( + 0 => $path, + 1 => $filename, + 2 => $name, + 3 => $encoding, + 4 => $type, + 5 => false, // isStringAttachment + 6 => 'attachment', + 7 => 0 + ); + + } catch (phpmailerException $e) { + $this->SetError($e->getMessage()); + if ($this->exceptions) { + throw $e; + } + echo $e->getMessage()."\n"; + if ( $e->getCode() == self::STOP_CRITICAL ) { + return false; + } + } + return true; + } + + /** + * Return the current array of attachments + * @return array + */ + public function GetAttachments() { + return $this->attachment; + } + + /** + * Attaches all fs, string, and binary attachments to the message. + * Returns an empty string on failure. + * @access private + * @return string + */ + private function AttachAll() { + // Return text of body + $mime = array(); + $cidUniq = array(); + $incl = array(); + + // Add all attachments + foreach ($this->attachment as $attachment) { + // Check for string attachment + $bString = $attachment[5]; + if ($bString) { + $string = $attachment[0]; + } else { + $path = $attachment[0]; + } + + if (in_array($attachment[0], $incl)) { continue; } + $filename = $attachment[1]; + $name = $attachment[2]; + $encoding = $attachment[3]; + $type = $attachment[4]; + $disposition = $attachment[6]; + $cid = $attachment[7]; + $incl[] = $attachment[0]; + if ( $disposition == 'inline' && isset($cidUniq[$cid]) ) { continue; } + $cidUniq[$cid] = true; + + $mime[] = sprintf("--%s%s", $this->boundary[1], $this->LE); + $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $this->EncodeHeader($this->SecureHeader($name)), $this->LE); + $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE); + + if($disposition == 'inline') { + $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE); + } + + $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", $disposition, $this->EncodeHeader($this->SecureHeader($name)), $this->LE.$this->LE); + + // Encode as string attachment + if($bString) { + $mime[] = $this->EncodeString($string, $encoding); + if($this->IsError()) { + return ''; + } + $mime[] = $this->LE.$this->LE; + } else { + $mime[] = $this->EncodeFile($path, $encoding); + if($this->IsError()) { + return ''; + } + $mime[] = $this->LE.$this->LE; + } + } + + $mime[] = sprintf("--%s--%s", $this->boundary[1], $this->LE); + + return join('', $mime); + } + + /** + * Encodes attachment in requested format. + * Returns an empty string on failure. + * @param string $path The full path to the file + * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable' + * @see EncodeFile() + * @access private + * @return string + */ + private function EncodeFile($path, $encoding = 'base64') { + try { + if (!is_readable($path)) { + throw new phpmailerException($this->Lang('file_open') . $path, self::STOP_CONTINUE); + } + if (function_exists('get_magic_quotes')) { + function get_magic_quotes() { + return false; + } + } + if (PHP_VERSION < 6) { + $magic_quotes = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + } + $file_buffer = file_get_contents($path); + $file_buffer = $this->EncodeString($file_buffer, $encoding); + if (PHP_VERSION < 6) { set_magic_quotes_runtime($magic_quotes); } + return $file_buffer; + } catch (Exception $e) { + $this->SetError($e->getMessage()); + return ''; + } + } + + /** + * Encodes string to requested format. + * Returns an empty string on failure. + * @param string $str The text to encode + * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable' + * @access public + * @return string + */ + public function EncodeString ($str, $encoding = 'base64') { + $encoded = ''; + switch(strtolower($encoding)) { + case 'base64': + $encoded = chunk_split(base64_encode($str), 76, $this->LE); + break; + case '7bit': + case '8bit': + $encoded = $this->FixEOL($str); + //Make sure it ends with a line break + if (substr($encoded, -(strlen($this->LE))) != $this->LE) + $encoded .= $this->LE; + break; + case 'binary': + $encoded = $str; + break; + case 'quoted-printable': + $encoded = $this->EncodeQP($str); + break; + default: + $this->SetError($this->Lang('encoding') . $encoding); + break; + } + return $encoded; + } + + /** + * Encode a header string to best (shortest) of Q, B, quoted or none. + * @access public + * @return string + */ + public function EncodeHeader($str, $position = 'text') { + $x = 0; + + switch (strtolower($position)) { + case 'phrase': + if (!preg_match('/[\200-\377]/', $str)) { + // Can't use addslashes as we don't know what value has magic_quotes_sybase + $encoded = addcslashes($str, "\0..\37\177\\\""); + if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) { + return ($encoded); + } else { + return ("\"$encoded\""); + } + } + $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches); + break; + case 'comment': + $x = preg_match_all('/[()"]/', $str, $matches); + // Fall-through + case 'text': + default: + $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches); + break; + } + + if ($x == 0) { + return ($str); + } + + $maxlen = 75 - 7 - strlen($this->CharSet); + // Try to select the encoding which should produce the shortest output + if (strlen($str)/3 < $x) { + $encoding = 'B'; + if (function_exists('mb_strlen') && $this->HasMultiBytes($str)) { + // Use a custom function which correctly encodes and wraps long + // multibyte strings without breaking lines within a character + $encoded = $this->Base64EncodeWrapMB($str); + } else { + $encoded = base64_encode($str); + $maxlen -= $maxlen % 4; + $encoded = trim(chunk_split($encoded, $maxlen, "\n")); + } + } else { + $encoding = 'Q'; + $encoded = $this->EncodeQ($str, $position); + $encoded = $this->WrapText($encoded, $maxlen, true); + $encoded = str_replace('='.$this->LE, "\n", trim($encoded)); + } + + $encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded); + $encoded = trim(str_replace("\n", $this->LE, $encoded)); + + return $encoded; + } + + /** + * Checks if a string contains multibyte characters. + * @access public + * @param string $str multi-byte text to wrap encode + * @return bool + */ + public function HasMultiBytes($str) { + if (function_exists('mb_strlen')) { + return (strlen($str) > mb_strlen($str, $this->CharSet)); + } else { // Assume no multibytes (we can't handle without mbstring functions anyway) + return false; + } + } + + /** + * Correctly encodes and wraps long multibyte strings for mail headers + * without breaking lines within a character. + * Adapted from a function by paravoid at http://uk.php.net/manual/en/function.mb-encode-mimeheader.php + * @access public + * @param string $str multi-byte text to wrap encode + * @return string + */ + public function Base64EncodeWrapMB($str) { + $start = "=?".$this->CharSet."?B?"; + $end = "?="; + $encoded = ""; + + $mb_length = mb_strlen($str, $this->CharSet); + // Each line must have length <= 75, including $start and $end + $length = 75 - strlen($start) - strlen($end); + // Average multi-byte ratio + $ratio = $mb_length / strlen($str); + // Base64 has a 4:3 ratio + $offset = $avgLength = floor($length * $ratio * .75); + + for ($i = 0; $i < $mb_length; $i += $offset) { + $lookBack = 0; + + do { + $offset = $avgLength - $lookBack; + $chunk = mb_substr($str, $i, $offset, $this->CharSet); + $chunk = base64_encode($chunk); + $lookBack++; + } + while (strlen($chunk) > $length); + + $encoded .= $chunk . $this->LE; + } + + // Chomp the last linefeed + $encoded = substr($encoded, 0, -strlen($this->LE)); + return $encoded; + } + + /** + * Encode string to quoted-printable. + * Only uses standard PHP, slow, but will always work + * @access public + * @param string $string the text to encode + * @param integer $line_max Number of chars allowed on a line before wrapping + * @return string + */ + public function EncodeQPphp( $input = '', $line_max = 76, $space_conv = false) { + $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'); + $lines = preg_split('/(?:\r\n|\r|\n)/', $input); + $eol = "\r\n"; + $escape = '='; + $output = ''; + while( list(, $line) = each($lines) ) { + $linlen = strlen($line); + $newline = ''; + for($i = 0; $i < $linlen; $i++) { + $c = substr( $line, $i, 1 ); + $dec = ord( $c ); + if ( ( $i == 0 ) && ( $dec == 46 ) ) { // convert first point in the line into =2E + $c = '=2E'; + } + if ( $dec == 32 ) { + if ( $i == ( $linlen - 1 ) ) { // convert space at eol only + $c = '=20'; + } else if ( $space_conv ) { + $c = '=20'; + } + } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required + $h2 = floor($dec/16); + $h1 = floor($dec%16); + $c = $escape.$hex[$h2].$hex[$h1]; + } + if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted + $output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay + $newline = ''; + // check if newline first character will be point or not + if ( $dec == 46 ) { + $c = '=2E'; + } + } + $newline .= $c; + } // end of for + $output .= $newline.$eol; + } // end of while + return $output; + } + + /** + * Encode string to RFC2045 (6.7) quoted-printable format + * Uses a PHP5 stream filter to do the encoding about 64x faster than the old version + * Also results in same content as you started with after decoding + * @see EncodeQPphp() + * @access public + * @param string $string the text to encode + * @param integer $line_max Number of chars allowed on a line before wrapping + * @param boolean $space_conv Dummy param for compatibility with existing EncodeQP function + * @return string + * @author Marcus Bointon + */ + public function EncodeQP($string, $line_max = 76, $space_conv = false) { + if (function_exists('quoted_printable_encode')) { //Use native function if it's available (>= PHP5.3) + return quoted_printable_encode($string); + } + $filters = stream_get_filters(); + if (!in_array('convert.*', $filters)) { //Got convert stream filter? + return $this->EncodeQPphp($string, $line_max, $space_conv); //Fall back to old implementation + } + $fp = fopen('php://temp/', 'r+'); + $string = preg_replace('/\r\n?/', $this->LE, $string); //Normalise line breaks + $params = array('line-length' => $line_max, 'line-break-chars' => $this->LE); + $s = stream_filter_append($fp, 'convert.quoted-printable-encode', STREAM_FILTER_READ, $params); + fputs($fp, $string); + rewind($fp); + $out = stream_get_contents($fp); + stream_filter_remove($s); + $out = preg_replace('/^\./m', '=2E', $out); //Encode . if it is first char on a line, workaround for bug in Exchange + fclose($fp); + return $out; + } + + /** + * Encode string to q encoding. + * @link http://tools.ietf.org/html/rfc2047 + * @param string $str the text to encode + * @param string $position Where the text is going to be used, see the RFC for what that means + * @access public + * @return string + */ + public function EncodeQ ($str, $position = 'text') { + // There should not be any EOL in the string + $encoded = preg_replace('/[\r\n]*/', '', $str); + + switch (strtolower($position)) { + case 'phrase': + $encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded); + break; + case 'comment': + $encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded); + case 'text': + default: + // Replace every high ascii, control =, ? and _ characters + //TODO using /e (equivalent to eval()) is probably not a good idea + $encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e', + "'='.sprintf('%02X', ord('\\1'))", $encoded); + break; + } + + // Replace every spaces to _ (more readable than =20) + $encoded = str_replace(' ', '_', $encoded); + + return $encoded; + } + + /** + * Adds a string or binary attachment (non-filesystem) to the list. + * This method can be used to attach ascii or binary data, + * such as a BLOB record from a database. + * @param string $string String attachment data. + * @param string $filename Name of the attachment. + * @param string $encoding File encoding (see $Encoding). + * @param string $type File extension (MIME) type. + * @return void + */ + public function AddStringAttachment($string, $filename, $encoding = 'base64', $type = 'application/octet-stream') { + // Append to $attachment array + $this->attachment[] = array( + 0 => $string, + 1 => $filename, + 2 => basename($filename), + 3 => $encoding, + 4 => $type, + 5 => true, // isStringAttachment + 6 => 'attachment', + 7 => 0 + ); + } + + /** + * Adds an embedded attachment. This can include images, sounds, and + * just about any other document. Make sure to set the $type to an + * image type. For JPEG images use "image/jpeg" and for GIF images + * use "image/gif". + * @param string $path Path to the attachment. + * @param string $cid Content ID of the attachment. Use this to identify + * the Id for accessing the image in an HTML form. + * @param string $name Overrides the attachment name. + * @param string $encoding File encoding (see $Encoding). + * @param string $type File extension (MIME) type. + * @return bool + */ + public function AddEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = 'application/octet-stream') { + + if ( !@is_file($path) ) { + $this->SetError($this->Lang('file_access') . $path); + return false; + } + + $filename = basename($path); + if ( $name == '' ) { + $name = $filename; + } + + // Append to $attachment array + $this->attachment[] = array( + 0 => $path, + 1 => $filename, + 2 => $name, + 3 => $encoding, + 4 => $type, + 5 => false, // isStringAttachment + 6 => 'inline', + 7 => $cid + ); + + return true; + } + + /** + * Returns true if an inline attachment is present. + * @access public + * @return bool + */ + public function InlineImageExists() { + foreach($this->attachment as $attachment) { + if ($attachment[6] == 'inline') { + return true; + } + } + return false; + } + + ///////////////////////////////////////////////// + // CLASS METHODS, MESSAGE RESET + ///////////////////////////////////////////////// + + /** + * Clears all recipients assigned in the TO array. Returns void. + * @return void + */ + public function ClearAddresses() { + foreach($this->to as $to) { + unset($this->all_recipients[strtolower($to[0])]); + } + $this->to = array(); + } + + /** + * Clears all recipients assigned in the CC array. Returns void. + * @return void + */ + public function ClearCCs() { + foreach($this->cc as $cc) { + unset($this->all_recipients[strtolower($cc[0])]); + } + $this->cc = array(); + } + + /** + * Clears all recipients assigned in the BCC array. Returns void. + * @return void + */ + public function ClearBCCs() { + foreach($this->bcc as $bcc) { + unset($this->all_recipients[strtolower($bcc[0])]); + } + $this->bcc = array(); + } + + /** + * Clears all recipients assigned in the ReplyTo array. Returns void. + * @return void + */ + public function ClearReplyTos() { + $this->ReplyTo = array(); + } + + /** + * Clears all recipients assigned in the TO, CC and BCC + * array. Returns void. + * @return void + */ + public function ClearAllRecipients() { + $this->to = array(); + $this->cc = array(); + $this->bcc = array(); + $this->all_recipients = array(); + } + + /** + * Clears all previously set filesystem, string, and binary + * attachments. Returns void. + * @return void + */ + public function ClearAttachments() { + $this->attachment = array(); + } + + /** + * Clears all custom headers. Returns void. + * @return void + */ + public function ClearCustomHeaders() { + $this->CustomHeader = array(); + } + + ///////////////////////////////////////////////// + // CLASS METHODS, MISCELLANEOUS + ///////////////////////////////////////////////// + + /** + * Adds the error message to the error container. + * @access protected + * @return void + */ + protected function SetError($msg) { + $this->error_count++; + if ($this->Mailer == 'smtp' and !is_null($this->smtp)) { + $lasterror = $this->smtp->getError(); + if (!empty($lasterror) and array_key_exists('smtp_msg', $lasterror)) { + $msg .= '

' . $this->Lang('smtp_error') . $lasterror['smtp_msg'] . "

\n"; + } + } + $this->ErrorInfo = $msg; + } + + /** + * Returns the proper RFC 822 formatted date. + * @access public + * @return string + * @static + */ + public static function RFCDate() { + $tz = date('Z'); + $tzs = ($tz < 0) ? '-' : '+'; + $tz = abs($tz); + $tz = (int)($tz/3600)*100 + ($tz%3600)/60; + $result = sprintf("%s %s%04d", date('D, j M Y H:i:s'), $tzs, $tz); + + return $result; + } + + /** + * Returns the server hostname or 'localhost.localdomain' if unknown. + * @access private + * @return string + */ + private function ServerHostname() { + if (!empty($this->Hostname)) { + $result = $this->Hostname; + } elseif (isset($_SERVER['SERVER_NAME'])) { + $result = $_SERVER['SERVER_NAME']; + } else { + $result = 'localhost.localdomain'; + } + + return $result; + } + + /** + * Returns a message in the appropriate language. + * @access private + * @return string + */ + private function Lang($key) { + if(count($this->language) < 1) { + $this->SetLanguage('en'); // set the default language + } + + if(isset($this->language[$key])) { + return $this->language[$key]; + } else { + return 'Language string failed to load: ' . $key; + } + } + + /** + * Returns true if an error occurred. + * @access public + * @return bool + */ + public function IsError() { + return ($this->error_count > 0); + } + + /** + * Changes every end of line from CR or LF to CRLF. + * @access private + * @return string + */ + private function FixEOL($str) { + $str = str_replace("\r\n", "\n", $str); + $str = str_replace("\r", "\n", $str); + $str = str_replace("\n", $this->LE, $str); + return $str; + } + + /** + * Adds a custom header. + * @access public + * @return void + */ + public function AddCustomHeader($custom_header) { + $this->CustomHeader[] = explode(':', $custom_header, 2); + } + + /** + * Evaluates the message and returns modifications for inline images and backgrounds + * @access public + * @return $message + */ + public function MsgHTML($message, $basedir = '') { + preg_match_all("/(src|background)=\"(.*)\"/Ui", $message, $images); + if(isset($images[2])) { + foreach($images[2] as $i => $url) { + // do not change urls for absolute images (thanks to corvuscorax) + if (!preg_match('#^[A-z]+://#',$url)) { + $filename = basename($url); + $directory = dirname($url); + ($directory == '.')?$directory='':''; + $cid = 'cid:' . md5($filename); + $ext = pathinfo($filename, PATHINFO_EXTENSION); + $mimeType = self::_mime_types($ext); + if ( strlen($basedir) > 1 && substr($basedir,-1) != '/') { $basedir .= '/'; } + if ( strlen($directory) > 1 && substr($directory,-1) != '/') { $directory .= '/'; } + if ( $this->AddEmbeddedImage($basedir.$directory.$filename, md5($filename), $filename, 'base64',$mimeType) ) { + $message = preg_replace("/".$images[1][$i]."=\"".preg_quote($url, '/')."\"/Ui", $images[1][$i]."=\"".$cid."\"", $message); + } + } + } + } + $this->IsHTML(true); + $this->Body = $message; + $textMsg = trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/s','',$message))); + if (!empty($textMsg) && empty($this->AltBody)) { + $this->AltBody = html_entity_decode($textMsg); + } + if (empty($this->AltBody)) { + $this->AltBody = 'To view this email message, open it in a program that understands HTML!' . "\n\n"; + } + } + + /** + * Gets the MIME type of the embedded or inline image + * @param string File extension + * @access public + * @return string MIME type of ext + * @static + */ + public static function _mime_types($ext = '') { + $mimes = array( + 'hqx' => 'application/mac-binhex40', + 'cpt' => 'application/mac-compactpro', + 'doc' => 'application/msword', + 'bin' => 'application/macbinary', + 'dms' => 'application/octet-stream', + 'lha' => 'application/octet-stream', + 'lzh' => 'application/octet-stream', + 'exe' => 'application/octet-stream', + 'class' => 'application/octet-stream', + 'psd' => 'application/octet-stream', + 'so' => 'application/octet-stream', + 'sea' => 'application/octet-stream', + 'dll' => 'application/octet-stream', + 'oda' => 'application/oda', + 'pdf' => 'application/pdf', + 'ai' => 'application/postscript', + 'eps' => 'application/postscript', + 'ps' => 'application/postscript', + 'smi' => 'application/smil', + 'smil' => 'application/smil', + 'mif' => 'application/vnd.mif', + 'xls' => 'application/vnd.ms-excel', + 'ppt' => 'application/vnd.ms-powerpoint', + 'wbxml' => 'application/vnd.wap.wbxml', + 'wmlc' => 'application/vnd.wap.wmlc', + 'dcr' => 'application/x-director', + 'dir' => 'application/x-director', + 'dxr' => 'application/x-director', + 'dvi' => 'application/x-dvi', + 'gtar' => 'application/x-gtar', + 'php' => 'application/x-httpd-php', + 'php4' => 'application/x-httpd-php', + 'php3' => 'application/x-httpd-php', + 'phtml' => 'application/x-httpd-php', + 'phps' => 'application/x-httpd-php-source', + 'js' => 'application/x-javascript', + 'swf' => 'application/x-shockwave-flash', + 'sit' => 'application/x-stuffit', + 'tar' => 'application/x-tar', + 'tgz' => 'application/x-tar', + 'xhtml' => 'application/xhtml+xml', + 'xht' => 'application/xhtml+xml', + 'zip' => 'application/zip', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mpga' => 'audio/mpeg', + 'mp2' => 'audio/mpeg', + 'mp3' => 'audio/mpeg', + 'aif' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'ram' => 'audio/x-pn-realaudio', + 'rm' => 'audio/x-pn-realaudio', + 'rpm' => 'audio/x-pn-realaudio-plugin', + 'ra' => 'audio/x-realaudio', + 'rv' => 'video/vnd.rn-realvideo', + 'wav' => 'audio/x-wav', + 'bmp' => 'image/bmp', + 'gif' => 'image/gif', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'jpe' => 'image/jpeg', + 'png' => 'image/png', + 'tiff' => 'image/tiff', + 'tif' => 'image/tiff', + 'css' => 'text/css', + 'html' => 'text/html', + 'htm' => 'text/html', + 'shtml' => 'text/html', + 'txt' => 'text/plain', + 'text' => 'text/plain', + 'log' => 'text/plain', + 'rtx' => 'text/richtext', + 'rtf' => 'text/rtf', + 'xml' => 'text/xml', + 'xsl' => 'text/xml', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpe' => 'video/mpeg', + 'qt' => 'video/quicktime', + 'mov' => 'video/quicktime', + 'avi' => 'video/x-msvideo', + 'movie' => 'video/x-sgi-movie', + 'doc' => 'application/msword', + 'word' => 'application/msword', + 'xl' => 'application/excel', + 'eml' => 'message/rfc822' + ); + return (!isset($mimes[strtolower($ext)])) ? 'application/octet-stream' : $mimes[strtolower($ext)]; + } + + /** + * Set (or reset) Class Objects (variables) + * + * Usage Example: + * $page->set('X-Priority', '3'); + * + * @access public + * @param string $name Parameter Name + * @param mixed $value Parameter Value + * NOTE: will not work with arrays, there are no arrays to set/reset + * @todo Should this not be using __set() magic function? + */ + public function set($name, $value = '') { + try { + if (isset($this->$name) ) { + $this->$name = $value; + } else { + throw new phpmailerException($this->Lang('variable_set') . $name, self::STOP_CRITICAL); + } + } catch (Exception $e) { + $this->SetError($e->getMessage()); + if ($e->getCode() == self::STOP_CRITICAL) { + return false; + } + } + return true; + } + + /** + * Strips newlines to prevent header injection. + * @access public + * @param string $str String + * @return string + */ + public function SecureHeader($str) { + $str = str_replace("\r", '', $str); + $str = str_replace("\n", '', $str); + return trim($str); + } + + /** + * Set the private key file and password to sign the message. + * + * @access public + * @param string $key_filename Parameter File Name + * @param string $key_pass Password for private key + */ + public function Sign($cert_filename, $key_filename, $key_pass) { + $this->sign_cert_file = $cert_filename; + $this->sign_key_file = $key_filename; + $this->sign_key_pass = $key_pass; + } + + /** + * Set the private key file and password to sign the message. + * + * @access public + * @param string $key_filename Parameter File Name + * @param string $key_pass Password for private key + */ + public function DKIM_QP($txt) { + $tmp=""; + $line=""; + for ($i=0;$iDKIM_private); + if ($this->DKIM_passphrase!='') { + $privKey = openssl_pkey_get_private($privKeyStr,$this->DKIM_passphrase); + } else { + $privKey = $privKeyStr; + } + if (openssl_sign($s, $signature, $privKey)) { + return base64_encode($signature); + } + } + + /** + * Generate DKIM Canonicalization Header + * + * @access public + * @param string $s Header + */ + public function DKIM_HeaderC($s) { + $s=preg_replace("/\r\n\s+/"," ",$s); + $lines=explode("\r\n",$s); + foreach ($lines as $key=>$line) { + list($heading,$value)=explode(":",$line,2); + $heading=strtolower($heading); + $value=preg_replace("/\s+/"," ",$value) ; // Compress useless spaces + $lines[$key]=$heading.":".trim($value) ; // Don't forget to remove WSP around the value + } + $s=implode("\r\n",$lines); + return $s; + } + + /** + * Generate DKIM Canonicalization Body + * + * @access public + * @param string $body Message Body + */ + public function DKIM_BodyC($body) { + if ($body == '') return "\r\n"; + // stabilize line endings + $body=str_replace("\r\n","\n",$body); + $body=str_replace("\n","\r\n",$body); + // END stabilize line endings + while (substr($body,strlen($body)-4,4) == "\r\n\r\n") { + $body=substr($body,0,strlen($body)-2); + } + return $body; + } + + /** + * Create the DKIM header, body, as new header + * + * @access public + * @param string $headers_line Header lines + * @param string $subject Subject + * @param string $body Body + */ + public function DKIM_Add($headers_line,$subject,$body) { + $DKIMsignatureType = 'rsa-sha1'; // Signature & hash algorithms + $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body + $DKIMquery = 'dns/txt'; // Query method + $DKIMtime = time() ; // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone) + $subject_header = "Subject: $subject"; + $headers = explode("\r\n",$headers_line); + foreach($headers as $header) { + if (strpos($header,'From:') === 0) { + $from_header=$header; + } elseif (strpos($header,'To:') === 0) { + $to_header=$header; + } + } + $from = str_replace('|','=7C',$this->DKIM_QP($from_header)); + $to = str_replace('|','=7C',$this->DKIM_QP($to_header)); + $subject = str_replace('|','=7C',$this->DKIM_QP($subject_header)) ; // Copied header fields (dkim-quoted-printable + $body = $this->DKIM_BodyC($body); + $DKIMlen = strlen($body) ; // Length of body + $DKIMb64 = base64_encode(pack("H*", sha1($body))) ; // Base64 of packed binary SHA-1 hash of body + $ident = ($this->DKIM_identity == '')? '' : " i=" . $this->DKIM_identity . ";"; + $dkimhdrs = "DKIM-Signature: v=1; a=" . $DKIMsignatureType . "; q=" . $DKIMquery . "; l=" . $DKIMlen . "; s=" . $this->DKIM_selector . ";\r\n". + "\tt=" . $DKIMtime . "; c=" . $DKIMcanonicalization . ";\r\n". + "\th=From:To:Subject;\r\n". + "\td=" . $this->DKIM_domain . ";" . $ident . "\r\n". + "\tz=$from\r\n". + "\t|$to\r\n". + "\t|$subject;\r\n". + "\tbh=" . $DKIMb64 . ";\r\n". + "\tb="; + $toSign = $this->DKIM_HeaderC($from_header . "\r\n" . $to_header . "\r\n" . $subject_header . "\r\n" . $dkimhdrs); + $signed = $this->DKIM_Sign($toSign); + return "X-PHPMAILER-DKIM: phpmailer.worxware.com\r\n".$dkimhdrs.$signed."\r\n"; + } + + protected function doCallback($isSent,$to,$cc,$bcc,$subject,$body) { + if (!empty($this->action_function) && function_exists($this->action_function)) { + $params = array($isSent,$to,$cc,$bcc,$subject,$body); + call_user_func_array($this->action_function,$params); + } + } +} + +class phpmailerException extends Exception { + public function errorMessage() { + $errorMsg = '' . $this->getMessage() . "
\n"; + return $errorMsg; + } +} +?> \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/action/lang/zh-cn.php b/tags/zentaopms_0.5.0_beta_20100221/module/action/lang/zh-cn.php new file mode 100644 index 0000000000..10870d95fc --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/action/lang/zh-cn.php @@ -0,0 +1,47 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package bug + * @version $Id$ + * @link http://www.zentao.cn + */ +$lang->action->desc->common = '$date, $action by $actor'; +$lang->action->desc->extra = '$date, $action as $extra by $actor'; +$lang->action->desc->opened = '$date, 鐢 $actor 鍒涘缓銆'; +$lang->action->desc->changed = '$date, 鐢 $actor 鍙樻洿銆'; +$lang->action->desc->edited = '$date, 鐢 $actor 缂栬緫銆'; +$lang->action->desc->closed = '$date, 鐢 $actor 鍏抽棴銆'; +$lang->action->desc->commented = '$date, 鐢 $actor 鍙戣〃璇勮銆'; +$lang->action->desc->activated = '$date, 鐢 $actor 婵娲汇'; +$lang->action->desc->diff1 = '淇敼浜 %s锛屾棫鍊间负 "%s"锛屾柊鍊间负 "%s"銆
'; +$lang->action->desc->diff2 = '淇敼浜 %s锛屽尯鍒负锛
%s
'; + +$lang->action->label->opened = '鍒涘缓浜'; +$lang->action->label->changed = '鍙樻洿浜'; +$lang->action->label->edited = '缂栬緫浜'; +$lang->action->label->closed = '鍏抽棴浜'; +$lang->action->label->commented = '璇勮浜'; +$lang->action->label->activated = '婵娲讳簡'; +$lang->action->label->resolved = '瑙e喅浜'; +$lang->action->label->reviewed = '璇勫浜'; +$lang->action->label->story = '闇姹倈story|view|storyID=%s'; +$lang->action->label->task = '浠诲姟|task|view|taskID=%s'; +$lang->action->label->bug = 'Bug|bug|view|bugID=%s'; +$lang->action->label->testcase = '鐢ㄤ緥|testcase|view|caseID=%s'; +$lang->action->label->space = '銆'; diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/action/model.php b/tags/zentaopms_0.5.0_beta_20100221/module/action/model.php new file mode 100644 index 0000000000..2939561b5c --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/action/model.php @@ -0,0 +1,177 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package action + * @version $Id$ + * @link http://www.zentao.cn + */ +?> +company = $this->app->company->id; + $action->objectType = $objectType; + $action->objectID = $objectID; + $action->actor = $this->app->user->account; + $action->action = $actionType; + $action->date = date('Y-m-d H:i:s'); + $action->comment = htmlspecialchars($comment); + $action->extra = $extra; + $this->dao->insert(TABLE_ACTION)->data($action)->autoCheck()->exec(); + return $this->dbh->lastInsertID(); + } + + /* 杩斿洖鏌愪竴涓璞$殑鎵鏈塧ction鍒楄〃銆*/ + public function getList($objectType, $objectID) + { + $actions = $this->dao->select('*')->from(TABLE_ACTION)->where('objectType')->eq($objectType)->andWhere('objectID')->eq($objectID)->orderBy('id')->fetchAll('id'); + $histories = $this->getHistory(array_keys($actions)); + foreach($actions as $actionID => $action) + { + $action->history = isset($histories[$actionID]) ? $histories[$actionID] : array(); + $actions[$actionID] = $action; + } + return $actions; + } + + /* 鑾峰緱action淇℃伅銆*/ + public function getById($actionID) + { + return $this->dao->findById((int)$actionID)->from(TABLE_ACTION)->fetch(); + } + + /* 杩斿洖鏌愪竴涓猘ction鎵瀵瑰簲鐨勫瓧娈典慨鏀硅褰曘*/ + public function getHistory($actionID) + { + return $this->dao->select()->from(TABLE_HISTORY)->where('action')->in($actionID)->orderBy('id')->fetchGroup('action'); + } + + /* 璁板綍鍘嗗彶銆*/ + public function logHistory($actionID, $changes) + { + foreach($changes as $change) + { + $change['action'] = $actionID; + $this->dao->insert(TABLE_HISTORY)->data($change)->exec(); + } + } + + /* 鎵撳嵃action鏍囬銆*/ + public function printAction($action) + { + $objectType = $action->objectType; + $actionType = strtolower($action->action); + if(isset($this->lang->$objectType->action->$actionType)) + { + $desc = $this->lang->$objectType->action->$actionType; + } + elseif(isset($this->lang->action->desc->$actionType)) + { + $desc = $this->lang->action->desc->$actionType; + } + else + { + $desc = $action->extra ? $this->lang->action->desc->extra : $this->lang->action->desc->common; + } + + foreach($action as $key => $value) + { + if($key == 'history') continue; + if(is_array($desc)) + { + if($key == 'extra') continue; + $desc['main'] = str_replace('$' . $key, $value, $desc['main']); + } + else + { + $desc = str_replace('$' . $key, $value, $desc); + } + } + if(is_array($desc)) + { + $extra = strtolower($action->extra); + if(isset($desc['extra'][$extra])) + { + echo str_replace('$extra', $desc['extra'][$extra], $desc['main']); + } + else + { + echo str_replace('$extra', $action->extra, $desc['main']); + } + } + else + { + echo $desc; + } + } + + /* 鎵撳嵃鍔ㄦ佷俊鎭*/ + public function getDynamic($objectType = 'all', $count = 30) + { + $actions = $this->dao->select('*')->from(TABLE_ACTION)->onCaseOf($objectType != 'all')->where('objectType')->eq($objectType)->endCase()->orderBy('id desc')->limit($count)->fetchAll(); + if(!$actions) return array(); + foreach($actions as $action) + { + $actionType = strtolower($action->action); + $objectType = strtolower($action->objectType); + $action->date = date('H:i', strtotime($action->date)); + $action->actionLabel = isset($this->lang->action->label->$actionType) ? $this->lang->action->label->$actionType : $action->action; + $action->objectLabel = isset($this->lang->action->label->$objectType) ? $this->lang->action->label->$objectType : $objectType; + if(strpos($action->objectLabel, '|') !== false) + { + list($objectLabel, $moduleName, $methodName, $vars) = explode('|', $action->objectLabel); + $action->objectLink = html::a(helper::createLink($moduleName, $methodName, sprintf($vars, $action->objectID)), '#' . $action->objectID); + $action->objectLabel = $objectLabel; + } + else + { + $action->objectLink = '#' . $action->objectID; + } + } + return $actions; + } + + /* 鎵撳嵃淇敼璁板綍銆*/ + public function printChanges($objectType, $histories) + { + if(empty($histories)) return; + $maxLength = 0; + foreach($histories as $history) + { + $fieldName = $history->field; + $history->fieldLabel = isset($this->lang->$objectType->$fieldName) ? $this->lang->$objectType->$fieldName : $fieldName; + if(($length = strlen($history->fieldLabel)) > $maxLength) $maxLength = $length; + } + foreach($histories as $history) + { + $history->fieldLabel = str_pad($history->fieldLabel, $maxLength, $this->lang->action->label->space); + if($history->diff != '') + { + printf($this->lang->action->desc->diff2, $history->fieldLabel, nl2br($history->diff)); + } + else + { + printf($this->lang->action->desc->diff1, $history->fieldLabel, $history->old, $history->new); + } + } + } +} diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/admin/control.php b/tags/zentaopms_0.5.0_beta_20100221/module/admin/control.php new file mode 100644 index 0000000000..152463fd18 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/admin/control.php @@ -0,0 +1,56 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package admin + * @version $Id$ + * @link http://www.zentao.cn + */ +class admin extends control +{ + /* 鏋勯犲嚱鏁帮紝鍔犺浇company, user, group妯″潡銆*/ + public function __construct() + { + parent::__construct(); + $this->loadModel('company'); + $this->loadModel('user'); + $this->loadModel('group'); + } + + /* 棣栭〉銆*/ + public function index($tab = 'index') + { + $this->locate($this->createLink('admin', 'browseCompany')); + } + + /* 鍏徃鍒楄〃銆*/ + public function browseCompany() + { + $header['title'] = $this->lang->admin->common . $this->lang->colon . $this->lang->company->browse; + $position[] = $this->lang->admin->company; + $position[] = $this->lang->company->browse; + + $companies = $this->company->getList(); + + $this->assign('header', $header); + $this->assign('position', $position); + $this->assign('companies', $companies); + + $this->display(); + } +} diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/admin/lang/zh-cn.php b/tags/zentaopms_0.5.0_beta_20100221/module/admin/lang/zh-cn.php new file mode 100644 index 0000000000..e6c07f8704 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/admin/lang/zh-cn.php @@ -0,0 +1,33 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package admin + * @version $Id$ + * @link http://www.zentao.cn + */ +$lang->admin->common = '鍚庡彴绠$悊'; +$lang->admin->index = '鍚庡彴绠$悊棣栭〉'; +$lang->admin->company = '鍏徃绠$悊'; +$lang->admin->user = '鐢ㄦ埛绠$悊'; +$lang->admin->group = '鍒嗙粍绠$悊'; +$lang->admin->welcome = '娆㈣繋浣跨敤绂呴亾绠$悊杞欢鍚庡彴绠$悊绯荤粺'; + +$lang->admin->browseCompany = '娴忚鍏徃'; +$lang->admin->browseUser = '娴忚鐢ㄦ埛'; +$lang->admin->browseGroup = '娴忚鍒嗙粍'; diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/admin/model.php b/tags/zentaopms_0.5.0_beta_20100221/module/admin/model.php new file mode 100644 index 0000000000..b979e98b15 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/admin/model.php @@ -0,0 +1,44 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package admin + * @version $Id$ + * @link http://www.zentao.cn + */ +?> +dbh->query($sql)->fetchALL(); + } + + /* 鑾峰緱鏌愪竴涓叕鍙哥殑缁熻淇℃伅銆*/ + public function getStatOfCompany($companyID) + { + } + + /* 鑾峰緱绯荤粺鐨勮繍琛屼俊鎭*/ + public function getStatOfSys() + { + } +} diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/admin/view/browsecompany.html.php b/tags/zentaopms_0.5.0_beta_20100221/module/admin/view/browsecompany.html.php new file mode 100644 index 0000000000..92f2c91066 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/admin/view/browsecompany.html.php @@ -0,0 +1,61 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package admin + * @version $Id$ + * @link http://www.zentao.cn + */ +?> + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
company->id;?>company->name;?>company->phone;?>company->fax;?>company->address;?>company->zipcode;?>company->website;?>company->backyard;?>company->pms;?>company->guest;?>actions;?>
id;?>name;?>phone;?>fax;?>address;?>zipcode;?>website, $company->website, '_blank');?>backyard,$company->backyard, '_blank');?>pms, $company->pms, '_blank');?>company->guestList[(int)$company->guest];?> + createLink('company', 'edit', "companyID=$company->id"), $this->lang->company->edit);?> + createLink('company', 'delete', "companyID=$company->id"), $this->lang->company->delete, "hiddenwin");?> +
+
+ diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/admin/view/browsegroup.html.php b/tags/zentaopms_0.5.0_beta_20100221/module/admin/view/browsegroup.html.php new file mode 100644 index 0000000000..fc2489693c --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/admin/view/browsegroup.html.php @@ -0,0 +1,68 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package admin + * @version $Id$ + * @link http://www.zentao.cn + */ +?> + +
+
+ +
+
+
+ + + + + + + + + + + + + + + + + + +
group->browse;?>
group->id;?>group->name;?>group->desc;?>group->users;?>actions;?>
id;?>name;?>desc;?> + id] as $user) + { + echo $user . ' '; + } + ?> + + createLink('group', 'edit', "groupID=$group->id"), $lang->group->edit);?> + createLink('group', 'managepriv', "groupID=$group->id"), $lang->group->managePriv);?> + createLink('group', 'managemember', "groupID=$group->id"), $lang->group->manageMember);?> + createLink('group', 'delete', "groupID=$group->id"), $lang->group->delete, "hiddenwin");?> + +
+
createLink('group', 'create'), $lang->group->create);?>
+
+
+
+ diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/admin/view/browseuser.html.php b/tags/zentaopms_0.5.0_beta_20100221/module/admin/view/browseuser.html.php new file mode 100644 index 0000000000..42cbf58637 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/admin/view/browseuser.html.php @@ -0,0 +1,72 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package admin + * @version $Id$ + * @link http://www.zentao.cn + */ +?> + +
+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
user->browse;?>
user->id;?>user->account;?>user->realname;?>user->nickname;?>user->email;?>user->gendar;?>user->phone;?>user->join;?>user->visits;?>actions;?>
id;?>realname;?>createLink('user', 'view', "account=$user->account"), $user->account); else echo $user->account;?>nickname;?>email);?>user->gendarList->{$user->gendar})) echo $lang->user->gendarList->{$user->gendar};?>phone;?>join;?>visits;?> + createLink('user', 'edit', "userID=$user->id&from=company"), $lang->user->edit);?> + createLink('user', 'delete', "userID=$user->id"), $lang->user->delete, "hiddenwin");?> +
+
createLink('user', 'create'), $lang->user->create);?>
+
+
+
+ diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/admin/view/index.html.php b/tags/zentaopms_0.5.0_beta_20100221/module/admin/view/index.html.php new file mode 100644 index 0000000000..38d60b0e0c --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/admin/view/index.html.php @@ -0,0 +1,41 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package admin + * @version $Id$ + * @link http://www.zentao.cn + */ +?> + +
+
+ +
+
+
+ + + + + +
admin->welcome;?>
admin->welcome;?>
+
+
+
+ diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/admin/view/menu.html.php b/tags/zentaopms_0.5.0_beta_20100221/module/admin/view/menu.html.php new file mode 100644 index 0000000000..c42ff8837e --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/admin/view/menu.html.php @@ -0,0 +1,29 @@ +company->id}";?> + + + + + +
admin->company;?>
+ createLink('admin', 'browsecompany'), $lang->company->browse);?>
+ createLink('company', 'create'), $lang->company->create);?>
+ createLink('company', 'edit', $companyVar ), $lang->company->edit);?>
+
+ + + + + +
admin->user;?>
+ createLink('admin', 'browseuser', $companyVar), $lang->user->browse);?>
+ createLink('user', 'create', $companyVar), $lang->user->create);?>
+
+ + + + +
admin->group;?>
+ createLink('admin', 'browsegroup', $companyVar), $lang->group->browse);?>
+ createLink('group', 'create', $companyVar), $lang->group->create);?>
+
+ diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/bug/config.php b/tags/zentaopms_0.5.0_beta_20100221/module/bug/config.php new file mode 100644 index 0000000000..9f935c6779 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/bug/config.php @@ -0,0 +1,45 @@ +bug->search['module'] = 'bug'; +$config->bug->search['fields']['id'] = $lang->bug->id; +$config->bug->search['fields']['title'] = $lang->bug->title; +$config->bug->search['fields']['steps'] = $lang->bug->steps; +$config->bug->search['fields']['assignedTo'] = $lang->bug->assignedTo; +$config->bug->search['fields']['resolvedBy'] = $lang->bug->resolvedBy; +$config->bug->search['fields']['openedBy'] = $lang->bug->openedBy; +$config->bug->search['fields']['module'] = $lang->bug->module; +$config->bug->search['fields']['project'] = $lang->bug->project; +$config->bug->search['fields']['closedBy'] = $lang->bug->closedBy; +$config->bug->search['fields']['lastEditedBy'] = $lang->bug->lastEditedBy; +$config->bug->search['fields']['status'] = $lang->bug->status; +$config->bug->search['fields']['severity'] = $lang->bug->severity; +$config->bug->search['fields']['type'] = $lang->bug->type; +$config->bug->search['fields']['os'] = $lang->bug->os; +$config->bug->search['fields']['browser'] = $lang->bug->browser; +$config->bug->search['fields']['resolution'] = $lang->bug->resolution; +$config->bug->search['fields']['mailto'] = $lang->bug->mailto; +$config->bug->search['fields']['openedDate'] = $lang->bug->openedDate; +$config->bug->search['fields']['openedBuild'] = $lang->bug->openedBuild; +$config->bug->search['fields']['resolvedBuild'] = $lang->bug->resolvedBuild; +$config->bug->search['fields']['assignedDate'] = $lang->bug->assignedDate; +$config->bug->search['fields']['closedDate'] = $lang->bug->closedDate; +$config->bug->search['fields']['lastEditedDate'] = $lang->bug->lastEditedDate; + +$config->bug->search['params']['title'] = array('operator' => 'include', 'control' => 'input', 'values' => ''); +$config->bug->search['params']['steps'] = array('operator' => 'include', 'control' => 'input', 'values' => ''); +$config->bug->search['params']['module'] = array('operator' => '=', 'control' => 'select', 'values' => 'modules'); +$config->bug->search['params']['project'] = array('operator' => '=', 'control' => 'select', 'values' => 'projects'); +$config->bug->search['params']['assignedTo'] = array('operator' => '=', 'control' => 'select', 'values' => 'users'); +$config->bug->search['params']['resolvedBy'] = array('operator' => '=', 'control' => 'select', 'values' => 'users'); +$config->bug->search['params']['openedBy'] = array('operator' => '=', 'control' => 'select', 'values' => 'users'); +$config->bug->search['params']['closedBy'] = array('operator' => '=', 'control' => 'select', 'values' => 'users'); +$config->bug->search['params']['lastEditedBy'] = array('operator' => '=', 'control' => 'select', 'values' => 'users'); +$config->bug->search['params']['status'] = array('operator' => '=', 'control' => 'select', 'values' => $lang->bug->statusList); +$config->bug->search['params']['severity'] = array('operator' => '=', 'control' => 'select', 'values' => $lang->bug->severityList); +$config->bug->search['params']['type'] = array('operator' => '=', 'control' => 'select', 'values' => $lang->bug->typeList); +$config->bug->search['params']['os'] = array('operator' => '=', 'control' => 'select', 'values' => $lang->bug->osList); +$config->bug->search['params']['browser'] = array('operator' => '=', 'control' => 'select', 'values' => $lang->bug->browserList); +$config->bug->search['params']['resolution'] = array('operator' => '=', 'control' => 'select', 'values' => $lang->bug->resolutionList); +$config->bug->search['params']['mailto'] = array('operator' => 'include', 'control' => 'select', 'values' => 'users'); +$config->bug->search['params']['openedBuild'] = array('operator' => '=', 'control' => 'select', 'values' => 'builds'); +$config->bug->search['params']['resolvedBuild']= array('operator' => '=', 'control' => 'select', 'values' => 'builds'); diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/bug/control.php b/tags/zentaopms_0.5.0_beta_20100221/module/bug/control.php new file mode 100644 index 0000000000..89502839db --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/bug/control.php @@ -0,0 +1,420 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package bug + * @version $Id$ + * @link http://www.zentao.cn + */ +class bug extends control +{ + private $products = array(); + + /* 鏋勯犲嚱鏁帮紝鍔犺浇story, release, tree绛夋ā鍧椼*/ + public function __construct() + { + parent::__construct(); + $this->loadModel('product'); + $this->loadModel('tree'); + $this->loadModel('user'); + $this->loadModel('action'); + $this->loadModel('story'); + $this->loadModel('task'); + $this->products = $this->product->getPairs(); + if(empty($this->products)) $this->locate($this->createLink('product', 'create')); + $this->assign('products', $this->products); + } + + /* bug棣栭〉銆*/ + public function index() + { + $this->locate($this->createLink('bug', 'browse')); + } + + /* 娴忚涓涓骇鍝佷笅闈㈢殑bug銆*/ + public function browse($productID = 0, $browseType = 'byModule', $param = 0, $orderBy = 'id|desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + /* 璁剧疆浜у搧id鍜屾ā鍧梚d銆*/ + $browseType = strtolower($browseType); + $productID = common::saveProductState($productID, key($this->products)); + $moduleID = ($browseType == 'bymodule') ? (int)$param : 0; + + /* 璁剧疆鎼滅储琛ㄥ崟銆*/ + $this->config->bug->search['actionURL'] = $this->createLink('bug', 'browse', "productID=$productID&browseType=bySearch"); + $this->config->bug->search['params']['module']['values'] = $this->tree->getOptionMenu($productID, $viewType = 'bug', $rooteModuleID = 0); + $this->config->bug->search['params']['project']['values'] = $this->product->getProjectPairs($productID); + $this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getProductBuildPairs($productID); + $this->config->bug->search['params']['resolvedBuild']['values'] = $this->build->getProductBuildPairs($productID); + $this->view->searchForm = $this->fetch('search', 'buildForm', $this->config->bug->search); + + /* 璁剧疆鑿滃崟锛岀櫥璁皊ession銆*/ + $this->bug->setMenu($this->products, $productID); + $this->session->set('bugList', $this->app->getURI(true)); + + /* 鍔犺浇鍒嗛〉绫汇*/ + $this->app->loadClass('pager', $static = true); + $pager = pager::init($recTotal, $recPerPage, $pageID); + + $bugs = array(); + if($browseType == 'all') + { + $bugs = $this->dao->select('*')->from(TABLE_BUG)->where('product')->eq($productID)->orderBy($orderBy)->page($pager)->fetchAll(); + } + elseif($browseType == "bymodule") + { + $childModuleIds = $this->tree->getAllChildId($moduleID); + $bugs = $this->bug->getModuleBugs($productID, $childModuleIds, $orderBy, $pager); + } + elseif($browseType == 'assigntome') + { + $bugs = $this->dao->findByAssignedTo($this->app->user->account)->from(TABLE_BUG)->andWhere('product')->eq($productID)->orderBy($orderBy)->page($pager)->fetchAll(); + } + elseif($browseType == 'openedbyme') + { + $bugs = $this->dao->findByOpenedBy($this->app->user->account)->from(TABLE_BUG)->andWhere('product')->eq($productID)->orderBy($orderBy)->page($pager)->fetchAll(); + } + elseif($browseType == 'resolvedbyme') + { + $bugs = $this->dao->findByResolvedBy($this->app->user->account)->from(TABLE_BUG)->andWhere('product')->eq($productID)->orderBy($orderBy)->page($pager)->fetchAll(); + } + elseif($browseType == 'assigntonull') + { + $bugs = $this->dao->findByAssignedTo('')->from(TABLE_BUG)->andWhere('product')->eq($productID)->orderBy($orderBy)->page($pager)->fetchAll(); + } + elseif($browseType == 'longlifebugs') + { + $bugs = $this->dao->findByLastEditedDate("<", date('Y-m-d', strtotime('-7 days')))->from(TABLE_BUG)->andWhere('product')->eq($productID)->andWhere('status')->ne('closed')->orderBy($orderBy)->page($pager)->fetchAll(); + } + elseif($browseType == 'postponedbugs') + { + $bugs = $this->dao->findByResolution('postponed')->from(TABLE_BUG)->andWhere('product')->eq($productID)->orderBy($orderBy)->page($pager)->fetchAll(); + } + elseif($browseType == 'bysearch') + { + if($this->session->bugQuery == false) $this->session->set('bugQuery', ' 1 = 1'); + $bugs = $this->dao->select('*')->from(TABLE_BUG)->where($this->session->bugQuery)->andWhere('product')->eq($productID)->orderBy($orderBy)->page($pager)->fetchAll(); + } + + $users = $this->user->getPairs('noletter'); + + $header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->bug->common; + $position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]); + $position[] = $this->lang->bug->common; + + $this->assign('header', $header); + $this->assign('position', $position); + $this->assign('productID', $productID); + $this->assign('productName', $this->products[$productID]); + $this->assign('moduleTree', $this->tree->getTreeMenu($productID, $viewType = 'bug', $rooteModuleID = 0, array('treeModel', 'createBugLink'))); + $this->assign('browseType', $browseType); + $this->assign('bugs', $bugs); + $this->assign('users', $users); + $this->assign('pager', $pager); + $this->assign('param', $param); + $this->assign('orderBy', $orderBy); + $this->assign('moduleID', $moduleID); + + $this->display(); + } + + /* 鍒涘缓Bug銆俥xtras鏄叾浠栫殑鍙傛暟锛宬ey鍜寁alue涔嬮棿浣跨敤=杩炴帴锛屽涓敭鍊煎涔嬮棿浣跨敤,闅斿紑銆*/ + public function create($productID, $extras = '') + { + if(empty($this->products)) $this->locate($this->createLink('product', 'create')); + + if(!empty($_POST)) + { + $bugID = $this->bug->create(); + if(dao::isError()) die(js::error(dao::getError())); + $actionID = $this->action->create('bug', $bugID, 'Opened'); + $this->sendmail($bugID, $actionID); + die(js::locate($this->createLink('bug', 'browse', "productID={$this->post->product}&type=byModule¶m={$this->post->module}"), 'parent')); + } + + /* 璁剧疆褰撳墠鐨勪骇鍝侊紝璁剧疆鑿滃崟銆*/ + $productID = common::saveProductState($productID, key($this->products)); + $this->bug->setMenu($this->products, $productID); + + /* 鍒濆鍖栧彉閲忋*/ + $moduleID = 0; + $projectID = 0; + $taskID = 0; + $storyID = 0; + $buildID = 0; + $caseID = 0; + $runID = 0; + $title = ''; + $steps = ''; + + /* 瑙f瀽extra鍙傛暟銆*/ + $extras = str_replace(array(',', ' '), array('&', ''), $extras); + parse_str($extras); + + /* 濡傛灉璁剧疆浜唕unID锛岃幏寰楁渶鍚庝竴娆$殑resultID銆*/ + if($runID > 0) $resultID = $this->dao->select('id')->from(TABLE_TESTRESULT)->where('run')->eq($runID)->orderBy('id desc')->limit(1)->fetch('id'); + if(isset($resultID) and $resultID > 0) extract($this->bug->getBugInfoFromResult($resultID)); + + /* 浣嶇疆淇℃伅銆*/ + $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->create; + $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]); + $this->view->position[] = $this->lang->bug->create; + + $this->view->productID = $productID; + $this->view->productName = $this->products[$productID]; + $this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'bug', $rooteModuleID = 0); + $this->view->stories = $this->story->getProductStoryPairs($productID); + $this->view->users = $this->user->getPairs('noclosed'); + $this->view->projects = $this->product->getProjectPairs($productID); + $this->view->builds = $this->loadModel('build')->getProductBuildPairs($productID); + $this->view->moduleID = $moduleID; + $this->view->projectID = $projectID; + $this->view->taskID = $taskID; + $this->view->storyID = $storyID; + $this->view->buildID = $buildID; + $this->view->caseID = $caseID; + $this->view->title = $title; + $this->view->steps = $steps; + $this->display(); + } + + /* 鏌ョ湅涓涓猙ug銆*/ + public function view($bugID) + { + /* 鏌ユ壘bug淇℃伅鍙婄浉鍏充骇鍝佷俊鎭*/ + $bug = $this->bug->getById($bugID); + $productID = $bug->product; + $productName = $this->products[$productID]; + + /* 璁剧疆鑿滃崟銆*/ + $this->bug->setMenu($this->products, $productID); + + /* 浣嶇疆淇℃伅銆*/ + $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->view; + $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $productName); + $this->view->position[] = $this->lang->bug->view; + + /* 璧嬪笺*/ + $this->view->productName = $productName; + $this->view->modulePath = $this->tree->getParents($bug->module); + $this->view->bug = $bug; + $this->view->users = $this->user->getPairs('noletter'); + $this->view->actions = $this->action->getList('bug', $bugID); + $this->view->builds = $this->loadModel('build')->getProductBuildPairs($productID); + + $this->display(); + } + + /* 缂栬緫涓涓狟ug銆*/ + public function edit($bugID) + { + /* 鏇存柊bug淇℃伅銆*/ + if(!empty($_POST)) + { + $changes = $this->bug->update($bugID); + if(dao::isError()) die(js::error(dao::getError())); + $files = $this->loadModel('file')->saveUpload('bug', $bugID); + if($this->post->comment != '' or !empty($changes) or !empty($files)) + { + $action = !empty($changes) ? 'Edited' : 'Commented'; + $fileAction = ''; + if(!empty($files)) $fileAction = $this->lang->addFiles . join(',', $files) . "\n" ; + $actionID = $this->action->create('bug', $bugID, $action, $fileAction . $this->post->comment); + $this->action->logHistory($actionID, $changes); + $this->sendmail($bugID, $actionID); + } + die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent')); + } + + /* 鏌ユ壘褰撳墠bug淇℃伅鍜屼骇鍝佹ā鍧椾俊鎭*/ + $bug = $this->bug->getById($bugID); + $productID = $bug->product; + $currentModuleID = $bug->module; + + /* 璁剧疆鑿滃崟銆*/ + $this->bug->setMenu($this->products, $productID); + + /* 浣嶇疆銆*/ + $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->edit; + $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]); + $this->view->position[] = $this->lang->bug->edit; + + /* 璧嬪笺*/ + $this->view->bug = $bug; + $this->view->productID = $productID; + $this->view->productName = $this->products[$productID]; + $this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'bug', $rooteModuleID = 0); + $this->view->currentModuleID = $currentModuleID; + $this->view->projects = $this->product->getProjectPairs($bug->product); + $this->view->stories = $bug->project ? $this->story->getProjectStoryPairs($bug->project) : $this->story->getProductStoryPairs($bug->product); + $this->view->tasks = $this->task->getProjectTaskPairs($bug->project); + $this->view->users = $this->user->getPairs(); + $this->view->builds = $this->loadModel('build')->getProductBuildPairs($productID); + $this->view->actions = $this->action->getList('bug', $bugID); + + $this->display(); + } + + /* 瑙e喅bug銆*/ + public function resolve($bugID) + { + /* 鏇存柊bug淇℃伅銆*/ + if(!empty($_POST)) + { + $this->bug->resolve($bugID); + if(dao::isError()) die(js::error(dao::getError())); + $actionID = $this->action->create('bug', $bugID, 'Resolved', $this->post->comment, $this->post->resolution); + $this->sendmail($bugID, $actionID); + die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent')); + } + + /* 鏌ユ壘bug鍜屼骇鍝佷俊鎭*/ + $bug = $this->bug->getById($bugID); + $productID = $bug->product; + + /* 璁剧疆鑿滃崟銆*/ + $this->bug->setMenu($this->products, $productID); + + /* 浣嶇疆銆*/ + $this->view->header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->bug->resolve; + $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]); + $this->view->position[] = $this->lang->bug->resolve; + + /* 璧嬪笺*/ + $this->view->bug = $bug; + $this->view->users = $this->user->getPairs(); + $this->view->builds = $this->loadModel('build')->getProductBuildPairs($productID); + $this->view->actions = $this->action->getList('bug', $bugID); + $this->display(); + } + + /* 婵娲籦ug銆*/ + public function activate($bugID) + { + /* 鏇存柊bug淇℃伅銆*/ + if(!empty($_POST)) + { + $this->bug->activate($bugID); + if(dao::isError()) die(js::error(dao::getError())); + $files = $this->loadModel('file')->saveUpload('bug', $bugID); + $actionID = $this->action->create('bug', $bugID, 'Activated', $this->post->comment); + $this->sendmail($bugID, $actionID); + die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent')); + } + + /* 鑾峰緱bug鍜屼骇鍝佷俊鎭*/ + $bug = $this->bug->getById($bugID); + $productID = $bug->product; + + /* 璁剧疆鑿滃崟銆*/ + $this->bug->setMenu($this->products, $productID); + + /* 褰撳墠浣嶇疆銆*/ + $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->activate; + $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]); + $this->view->position[] = $this->lang->bug->activate; + + /* 璧嬪笺*/ + $this->view->bug = $bug; + $this->view->users = $this->user->getPairs(); + $this->view->builds = $this->loadModel('build')->getProductBuildPairs($productID); + $this->view->actions = $this->action->getList('bug', $bugID); + + $this->display(); + } + + /* 婵娲籦ug銆*/ + public function close($bugID) + { + /* 鏇存柊bug淇℃伅銆*/ + if(!empty($_POST)) + { + $this->bug->close($bugID); + if(dao::isError()) die(js::error(dao::getError())); + $actionID = $this->action->create('bug', $bugID, 'Closed', $this->post->comment); + $this->sendmail($bugID, $actionID); + die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent')); + } + + /* bug鍜屼骇鍝佷俊鎭*/ + $bug = $this->bug->getById($bugID); + $productID = $bug->product; + + /* 璁剧疆鑿滃崟銆*/ + $this->bug->setMenu($this->products, $productID); + + $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->activate; + $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]); + $this->view->position[] = $this->lang->bug->activate; + + $this->view->bug = $bug; + $this->view->users = $this->user->getPairs(); + $this->view->actions = $this->action->getList('bug', $bugID); + $this->display(); + } + + /* 鑾峰緱鐢ㄦ埛鐨刡ug鍒楄〃銆*/ + public function ajaxGetUserBugs($account = '') + { + if($account == '') $account = $this->app->user->account; + $bugs = $this->bug->getUserBugPairs($account); + die(html::select('bug', $bugs, '', 'class=select-1')); + } + + /* 鍙戦侀偖浠躲*/ + private function sendmail($bugID, $actionID) + { + /* 璁惧畾toList鍜宑cList銆*/ + $bug = $this->bug->getByID($bugID); + $toList = $bug->assignedTo; + $ccList = trim($bug->mailto, ','); + if($toList == '') + { + if($ccList == '') return; + if(strpos($ccList, ',') === false) + { + $toList = $ccList; + $ccList = ''; + } + else + { + $commaPos = strpos($ccList, ','); + $toList = substr($ccList, 0, $commaPos); + $ccList = substr($ccList, $commaPos + 1); + } + } + elseif(strtolower($toList) == 'closed') + { + $toList = $bug->resolvedBy; + } + + /* 鑾峰緱action淇℃伅銆*/ + $action = $this->action->getById($actionID); + $history = $this->action->getHistory($actionID); + $action->history = isset($history[$actionID]) ? $history[$actionID] : array(); + if(strtolower($action->action) == 'opened') $action->comment = $bug->steps; + + /* 璧嬪硷紝鑾峰緱閭欢鍐呭銆*/ + $this->assign('bug', $bug); + $this->assign('action', $action); + $mailContent = $this->parse($this->moduleName, 'sendmail'); + + /* 鍙戜俊銆*/ + $this->loadModel('mail')->send($toList, 'BUG #' . $bug->id . $this->lang->colon . $bug->title, $mailContent, $ccList); + if($this->mail->isError()) echo js::error($this->mail->getError()); + } +} diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/bug/lang/en.php b/tags/zentaopms_0.5.0_beta_20100221/module/bug/lang/en.php new file mode 100644 index 0000000000..3d123482fb --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/bug/lang/en.php @@ -0,0 +1,63 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package bug + * @version $Id$ + * @link http://www.zentao.cn + */ +$lang['page']['common'] = 'bug'; +$lang['page']['index'] = "{$lang['page']['common']}/index"; +$lang['page']['create'] = "{$lang['page']['common']}/create"; +$lang['page']['read'] = "{$lang['page']['common']}/read"; +$lang['page']['update'] = "{$lang['page']['common']}/update"; +$lang['page']['delete'] = "{$lang['page']['common']}/delete"; +$lang['bug']['id'] = 'id'; +$lang['bug']['product'] = 'product'; +$lang['bug']['module'] = 'module'; +$lang['bug']['path'] = 'path'; +$lang['bug']['project'] = 'project'; +$lang['bug']['sprint'] = 'sprint'; +$lang['bug']['story'] = 'story'; +$lang['bug']['task'] = 'task'; +$lang['bug']['title'] = 'title'; +$lang['bug']['severity'] = 'severity'; +$lang['bug']['type'] = 'type'; +$lang['bug']['os'] = 'os'; +$lang['bug']['browser'] = 'browser'; +$lang['bug']['machine'] = 'machine'; +$lang['bug']['found'] = 'found'; +$lang['bug']['steps'] = 'steps'; +$lang['bug']['status'] = 'status'; +$lang['bug']['mailto'] = 'mailto'; +$lang['bug']['openedBy'] = 'openedBy'; +$lang['bug']['openedDate'] = 'openedDate'; +$lang['bug']['openedBuild'] = 'openedBuild'; +$lang['bug']['assignedTo'] = 'assignedTo'; +$lang['bug']['assignedDate'] = 'assignedDate'; +$lang['bug']['resolvedBy'] = 'resolvedBy'; +$lang['bug']['resolution'] = 'resolution'; +$lang['bug']['resolvedBuild'] = 'resolvedBuild'; +$lang['bug']['resolvedDate'] = 'resolvedDate'; +$lang['bug']['closedBy'] = 'closedBy'; +$lang['bug']['closedDate'] = 'closedDate'; +$lang['bug']['lastEditedBy'] = 'lastEditedBy'; +$lang['bug']['lastEditedDate'] = 'lastEditedDate'; +$lang['bug']['field1'] = 'field1'; +$lang['bug']['field2'] = 'field2'; +$lang['bug']['feild3'] = 'feild3'; diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/bug/lang/zh-cn.php b/tags/zentaopms_0.5.0_beta_20100221/module/bug/lang/zh-cn.php new file mode 100644 index 0000000000..0c7517f40f --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/bug/lang/zh-cn.php @@ -0,0 +1,169 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package bug + * @version $Id$ + * @link http://www.zentao.cn + */ +$lang->bug->common = '缂洪櫡绠$悊'; +$lang->bug->index = '棣栭〉'; +$lang->bug->create = '鍒涘缓Bug'; +$lang->bug->edit = '缂栬緫Bug'; +$lang->bug->browse = 'Bug鍒楄〃'; +$lang->bug->view = 'Bug璇︽儏'; +$lang->bug->resolve = '瑙e喅Bug'; +$lang->bug->close = '鍏抽棴Bug'; +$lang->bug->activate = '婵娲籅ug'; +$lang->bug->ajaxGetUserBugs = '鎺ュ彛:鎴戠殑Bug'; + +$lang->bug->selectProduct = '璇烽夋嫨浜у搧'; +$lang->bug->byModule = '鎸夋ā鍧'; +$lang->bug->assignToMe = '鎸囨淳缁欐垜'; +$lang->bug->openedByMe = '鐢辨垜鍒涘缓'; +$lang->bug->resolvedByMe = '鐢辨垜瑙e喅'; +$lang->bug->assignToNull = '鏈寚娲'; +$lang->bug->longLifeBugs = '涔呮湭澶勭悊'; +$lang->bug->postponedBugs = '琚欢鏈'; +$lang->bug->allBugs = '鎵鏈塀ug'; +$lang->bug->moduleBugs = '鎸夋ā鍧楁祻瑙'; +$lang->bug->byQuery = '鎼滅储'; + +$lang->bug->lblProductAndModule = '浜у搧妯″潡'; +$lang->bug->lblProjectAndTask = '椤圭洰浠诲姟'; +$lang->bug->lblStory = '鐩稿叧闇姹'; +$lang->bug->lblTypeAndSeverity = '绫诲瀷/涓ラ噸绋嬪害'; +$lang->bug->lblSystemBrowserAndHardware = '绯荤粺/娴忚鍣'; +$lang->bug->lblAssignedTo = '褰撳墠鎸囨淳'; +$lang->bug->lblMailto = '鎶勯佺粰'; +$lang->bug->lblLastEdited = '鏈鍚庝慨鏀'; +$lang->bug->lblResolved = '鐢辫皝瑙e喅'; + +$lang->bug->confirmChangeProduct = '淇敼浜у搧浼氬鑷寸浉搴旂殑椤圭洰銆侀渶姹傚拰浠诲姟鍙戠敓鍙樺寲锛岀‘瀹氬悧锛'; + +$lang->bug->legendBasicInfo = '鍩烘湰淇℃伅'; +$lang->bug->legendMailto = '鎶勯佺粰'; +$lang->bug->legendAttatch = '闄勪欢'; +$lang->bug->legendLinkBugs = '鐩稿叧Bug'; +$lang->bug->legendPrjStoryTask= '椤圭洰/闇姹/浠诲姟'; +$lang->bug->legendCases = '鐩稿叧鐢ㄤ緥'; +$lang->bug->legendSteps = '閲嶇幇姝ラ'; +$lang->bug->legendAction = '鎿嶄綔'; +$lang->bug->legendHistory = '鍘嗗彶璁板綍'; +$lang->bug->legendComment = '澶囨敞'; +$lang->bug->legendLife = 'BUG鐨勪竴鐢'; +$lang->bug->legendMisc = '鍏剁浉鍏充粬'; + +$lang->bug->buttonEdit = '缂栬緫'; +$lang->bug->buttonActivate = '婵娲'; +$lang->bug->buttonResolve = '瑙e喅'; +$lang->bug->buttonClose = '鍏抽棴'; +$lang->bug->buttonToList = '杩斿洖'; + +$lang->bug->severityList[3] = 3; +$lang->bug->severityList[1] = 1; +$lang->bug->severityList[2] = 2; +$lang->bug->severityList[4] = 4; + +/* Define the OS list. */ +$lang->bug->osList['all'] = '鍏ㄩ儴'; +$lang->bug->osList['winxp'] = 'Windows XP'; +$lang->bug->osList['win7'] = 'Windows 7'; +$lang->bug->osList['vista'] = 'Windows Vista'; +$lang->bug->osList['win2000'] = 'Windows 2000'; +$lang->bug->osList['winnt'] = 'Windows NT'; +$lang->bug->osList['win98'] = 'Windows 98'; +$lang->bug->osList['linux'] = 'Linux'; +$lang->bug->osList['unix'] = 'Unix'; +$lang->bug->osList['others'] = '鍏朵粬'; + +/* Define the OS list. */ +$lang->bug->browserList['all'] = '鍏ㄩ儴'; +$lang->bug->browserList['ie6'] = 'IE6'; +$lang->bug->browserList['ie7'] = 'IE7'; +$lang->bug->browserList['ie8'] = 'IE8'; +$lang->bug->browserList['firefox2'] = 'firefox2'; +$lang->bug->browserList['firefx3'] = 'firefox3'; +$lang->bug->browserList['opera9'] = 'opera9'; +$lang->bug->browserList['oprea10'] = 'opera10'; +$lang->bug->browserList['safari'] = 'safari'; +$lang->bug->browserList['chrome'] = 'chrome'; +$lang->bug->browserList['other'] = '鍏朵粬'; + +/* Define the types. */ +$lang->bug->typeList[''] = ''; +$lang->bug->typeList['codeerror'] = '浠g爜閿欒'; +$lang->bug->typeList['interface'] = '鐣岄潰浼樺寲'; +$lang->bug->typeList['designchange'] = '璁捐鍙樻洿'; +$lang->bug->typeList['Others'] = '鍏朵粬'; + +$lang->bug->statusList[''] = ''; +$lang->bug->statusList['active'] = '婵娲'; +$lang->bug->statusList['resolved'] = '宸茶В鍐'; +$lang->bug->statusList['closed'] = '宸插叧闂'; + +$lang->bug->resolutionList[''] = ''; +$lang->bug->resolutionList['bydesign'] = '璁捐濡傛'; +$lang->bug->resolutionList['duplicate'] = '閲嶅Bug'; +$lang->bug->resolutionList['external'] = '澶栭儴鍘熷洜'; +$lang->bug->resolutionList['fixed'] = '宸茶В鍐'; +$lang->bug->resolutionList['notrepro'] = '鏃犳硶閲嶇幇'; +$lang->bug->resolutionList['postponed'] = '寤舵湡澶勭悊'; +$lang->bug->resolutionList['willnotfix'] = "涓嶄簣瑙e喅"; + +$lang->bug->id = 'Bug缂栧彿'; +$lang->bug->product = '鎵灞炰骇鍝'; +$lang->bug->module = '鎵灞炴ā鍧'; +$lang->bug->path = '妯″潡璺緞'; +$lang->bug->project = '鎵灞為」鐩'; +$lang->bug->story = '鐩稿叧闇姹'; +$lang->bug->storyVersion = '闇姹傜増鏈'; +$lang->bug->task = '鐩稿叧浠诲姟'; +$lang->bug->title = 'Bug鏍囬'; +$lang->bug->severity = '涓ラ噸绋嬪害'; +$lang->bug->type = 'Bug绫诲瀷'; +$lang->bug->os = '鎿嶄綔绯荤粺'; +$lang->bug->browser = '娴忚鍣'; +$lang->bug->machine = '鏈哄櫒纭欢'; +$lang->bug->found = '濡備綍鍙戠幇'; +$lang->bug->steps = '閲嶇幇姝ラ'; +$lang->bug->status = 'Bug鐘舵'; +$lang->bug->mailto = '鎶勯佺粰'; +$lang->bug->openedBy = '鐢辫皝鍒涘缓'; +$lang->bug->openedDate = '鍒涘缓鏃ユ湡'; +$lang->bug->openedBuild = '褰卞搷鐗堟湰'; +$lang->bug->assignedTo = '鎸囨淳缁'; +$lang->bug->assignedDate = '鎸囨淳鏃ユ湡'; +$lang->bug->resolvedBy = '瑙e喅鑰'; +$lang->bug->resolution = '瑙e喅鏂规'; +$lang->bug->resolvedBuild = '瑙e喅鐗堟湰'; +$lang->bug->resolvedDate = '瑙e喅鏃ユ湡'; +$lang->bug->closedBy = '鐢辫皝鍏抽棴'; +$lang->bug->closedDate = '鍏抽棴鏃ユ湡'; +$lang->bug->duplicateBug = '閲嶅Bug'; +$lang->bug->lastEditedBy = '鏈鍚庝慨鏀硅'; +$lang->bug->lastEditedDate = '鏈鍚庝慨鏀规棩鏈'; +$lang->bug->linkBug = '鐩稿叧Bug'; +$lang->bug->case = '鐩稿叧鐢ㄤ緥'; +$lang->bug->files = '闄勪欢'; + +$lang->bug->tblStep = "[姝ラ]\n"; +$lang->bug->tblResult = "[缁撴灉]\n"; +$lang->bug->tblExpect = "[鏈熸湜]\n"; + +$lang->bug->action->resolved = array('main' => '$date, 鐢 $actor 瑙e喅锛屾柟妗堜负 $extra銆', 'extra' => $lang->bug->resolutionList); diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/bug/model.php b/tags/zentaopms_0.5.0_beta_20100221/module/bug/model.php new file mode 100644 index 0000000000..d4454ac0c1 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/bug/model.php @@ -0,0 +1,278 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package bug + * @version $Id$ + * @link http://www.zentao.cn + */ +?> +lang->bug->menu, 'product', $selectHtml . $this->lang->arrow); + common::setMenuVars($this->lang->bug->menu, 'bug', $productID); + common::setMenuVars($this->lang->bug->menu, 'testcase', $productID); + common::setMenuVars($this->lang->bug->menu, 'testtask', $productID); + } + + /* 鍒涘缓涓涓狟ug銆*/ + public function create() + { + $now = date('Y-m-d H:i:s'); + $bug = fixer::input('post') + ->add('openedBy', $this->app->user->account) + ->add('openedDate', $now) + ->setDefault('project,story,task', 0) + ->setIF($this->post->assignedTo != '', 'assignedDate', $now) + ->setIF($this->post->story != false, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story)) + ->stripTags('title') + ->cleanInt('product, module, severity') + ->specialChars('steps') + ->join('mailto', ',') + ->remove('files, labels') + ->get(); + $this->dao->insert(TABLE_BUG)->data($bug)->autoCheck()->batchCheck('title,type,openedBuild', 'notempty')->exec(); + if(!dao::isError()) + { + $bugID = $this->dao->lastInsertID(); + $this->loadModel('file')->saveUpload('bug', $bugID); + return $bugID; + } + return false; + } + + /* 鑾峰緱鏌愪竴涓骇鍝侊紝鏌愪竴涓ā鍧椾笅闈㈢殑鎵鏈塨ug銆*/ + public function getModuleBugs($productID, $moduleIds = 0, $orderBy = 'id|desc', $pager = null) + { + $sql = $this->dao->select('*')->from(TABLE_BUG)->where('product')->eq((int)$productID); + if(!empty($moduleIds)) $sql->andWhere('module')->in($moduleIds); + return $sql->orderBy($orderBy)->page($pager)->fetchAll(); + } + + /* 鑾峰彇涓涓猙ug鐨勮缁嗕俊鎭*/ + public function getById($bugID) + { + $bug = $this->dao->select('t1.*, t2.name AS projectName, t3.title AS storyTitle, t4.name AS taskName') + ->from(TABLE_BUG)->alias('t1') + ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') + ->leftJoin(TABLE_STORY)->alias('t3')->on('t1.story = t3.id') + ->leftJoin(TABLE_TASK)->alias('t4')->on('t1.task = t4.id') + ->where('t1.id')->eq((int)$bugID)->fetch(); + foreach($bug as $key => $value) if(strpos($key, 'Date') !== false and !(int)substr($value, 0, 4)) $bug->$key = ''; + $bug->mailto = ltrim(trim($bug->mailto), ','); + if($bug->duplicateBug) $bug->duplicateBugTitle = $this->dao->findById($bug->duplicateBug)->from(TABLE_BUG)->fields('title')->fetch('title'); + if($bug->case) $bug->caseTitle = $this->dao->findById($bug->case)->from(TABLE_CASE)->fields('title')->fetch('title'); + if($bug->linkBug) $bug->linkBugTitles = $this->dao->select('id,title')->from(TABLE_BUG)->where('id')->in($bug->linkBug)->fetchPairs(); + $bug->files = $this->loadModel('file')->getByObject('bug', $bugID); + return $bug; + } + + /* 鏇存柊bug淇℃伅銆*/ + public function update($bugID) + { + $oldBug = $this->getById($bugID); + $now = date('Y-m-d H:i:s'); + $bug = fixer::input('post') + ->cleanInt('product,module,severity,project,story,task') + ->stripTags('title') + ->specialChars('steps') + ->remove('comment,fiels,labels') + ->setDefault('project,module,project,story,task,duplicateBug', 0) + ->add('lastEditedBy', $this->app->user->account) + ->add('lastEditedDate', $now) + ->setIF($this->post->assignedTo != $oldBug->assignedTo, 'assignedDate', $now) + ->setIF($this->post->resolvedBy != '' and $this->post->resolvedDate == '', 'resolvedDate', $now) + ->setIF($this->post->resolution != '' and $this->post->resolvedDate == '', 'resolvedDate', $now) + ->setIF($this->post->resolution != '' and $this->post->resolvedBy == '', 'resolvedBy', $this->app->user->account) + ->setIF($this->post->closedBy != '' and $this->post->closedDate == '', 'closedDate', $now) + ->setIF($this->post->closedDate != '' and $this->post->closedBy == '', 'closedBy', $this->app->user->account) + ->setIF($this->post->closedBy != '' or $this->post->closedDate != '', 'assignedTo', 'closed') + ->setIF($this->post->closedBy != '' or $this->post->closedDate != '', 'assignedDate', $now) + ->setIF($this->post->resolution != '' or $this->post->resolvedDate != '', 'status', 'resolved') + ->setIF($this->post->closedBy != '' or $this->post->closedDate != '', 'status', 'closed') + ->setIF(($this->post->resolution != '' or $this->post->resolvedDate != '') and $this->post->assignedTo == '', 'assignedTo', $oldBug->openedBy) + ->setIF(($this->post->resolution != '' or $this->post->resolvedDate != '') and $this->post->assignedTo == '', 'assignedDate', $now) + ->setIF($this->post->resolution == '' and $this->post->resolvedDate =='', 'status', 'active') + ->setIF($this->post->story != false and $this->post->story != $oldBug->story, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story)) + ->get(); + + $this->dao->update(TABLE_BUG)->data($bug) + ->autoCheck() + ->batchCheck('title,type', 'notempty') + ->checkIF($bug->resolvedBy, 'resolution', 'notempty') + ->checkIF($bug->closedBy, 'resolution', 'notempty') + ->checkIF($bug->resolution == 'duplicate', 'duplicateBug', 'notempty') + ->where('id')->eq((int)$bugID) + ->exec(); + if(!dao::isError()) return common::createChanges($oldBug, $bug); + } + + /* 瑙e喅Bug銆*/ + public function resolve($bugID) + { + $oldBug = $this->getById($bugID); + $now = date('Y-m-d H:i:s'); + $bug = fixer::input('post') + ->add('resolvedBy', $this->app->user->account) + ->add('resolvedDate', $now) + ->add('status', 'resolved') + ->add('assignedDate', $now) + ->add('lastEditedBy', $this->app->user->account) + ->add('lastEditedDate', $now) + ->setDefault('duplicateBug', 0) + ->setDefault('assignedTo', $oldBug->openedBy) + ->remove('comment') + ->get(); + + $this->dao->update(TABLE_BUG)->data($bug) + ->autoCheck() + ->check('resolution', 'notempty') + ->checkIF($bug->resolution == 'duplicate', 'duplicateBug', 'notempty') + ->where('id')->eq((int)$bugID) + ->exec(); + } + + /* 婵娲籅ug銆*/ + public function activate($bugID) + { + $oldBug = $this->getById($bugID); + $now = date('Y-m-d H:i:s'); + $bug = fixer::input('post') + ->add('assignedTo', $oldBug->resolvedBy) + ->add('assignedDate', $now) + ->add('resolution', '') + ->add('status', 'active') + ->add('resolvedDate', '0000-00-00') + ->add('resolvedBy', '') + ->add('resolvedBuild', '') + ->add('closedBy', '') + ->add('closedDate', '0000-00-00') + ->add('duplicateBug', 0) + ->add('lastEditedBy', $this->app->user->account) + ->add('lastEditedDate', $now) + ->remove('comment,files,labels') + ->get(); + + $this->dao->update(TABLE_BUG)->data($bug)->autoCheck()->where('id')->eq((int)$bugID)->exec(); + } + + /* 鍏抽棴Bug銆*/ + public function close($bugID) + { + $oldBug = $this->getById($bugID); + $now = date('Y-m-d H:i:s'); + $bug = fixer::input('post') + ->add('assignedTo', 'closed') + ->add('assignedDate', $now) + ->add('status', 'closed') + ->add('closedBy', $this->app->user->account) + ->add('closedDate', $now) + ->add('lastEditedBy', $this->app->user->account) + ->add('lastEditedDate', $now) + ->remove('comment') + ->get(); + + $this->dao->update(TABLE_BUG)->data($bug)->autoCheck()->where('id')->eq((int)$bugID)->exec(); + } + + /* 浠巄ug鍒楄〃涓彁鍙栨墍鏈夊嚭鐜拌繃鐨勮处鎴枫*/ + public function extractAccountsFromList($bugs) + { + $accounts = array(); + foreach($bugs as $bug) + { + if(!empty($bug->openedBy)) $accounts[] = $bug->openedBy; + if(!empty($bug->assignedTo)) $accounts[] = $bug->assignedTo; + if(!empty($bug->resolvedBy)) $accounts[] = $bug->resolvedBy; + if(!empty($bug->closedBy)) $accounts[] = $bug->closedBy; + if(!empty($bug->lastEditedBy)) $accounts[] = $bug->lastEditedBy; + } + return array_unique($accounts); + } + + /* 浠庝竴鏉ug涓彁鍙栨墍鏈夊嚭鐜拌繃鐨勮处鎴枫*/ + public function extractAccountsFromSingle($bug) + { + $accounts = array(); + if(!empty($bug->openedBy)) $accounts[] = $bug->openedBy; + if(!empty($bug->assignedTo)) $accounts[] = $bug->assignedTo; + if(!empty($bug->resolvedBy)) $accounts[] = $bug->resolvedBy; + if(!empty($bug->closedBy)) $accounts[] = $bug->closedBy; + if(!empty($bug->lastEditedBy)) $accounts[] = $bug->lastEditedBy; + return array_unique($accounts); + } + + /* 鑾峰緱鐢ㄦ埛鐨凚ug id=>title鍒楄〃銆*/ + public function getUserBugPairs($account) + { + $bugs = array(); + $stmt = $this->dao->select('t1.id, t1.title, t2.name as product') + ->from(TABLE_BUG)->alias('t1') + ->leftJoin(TABLE_PRODUCT)->alias('t2') + ->on('t1.product=t2.id') + ->where('t1.assignedTo')->eq($account) + ->query(); + while($bug = $stmt->fetch()) + { + $bug->title = $bug->product . ' / ' . $bug->title; + $bugs[$bug->id] = $bug->title; + } + return $bugs; + } + + /* 鑾峰緱鏌愪釜椤圭洰鐨刡ug鍒楄〃銆*/ + public function getProjectBugs($projectID, $orderBy = 'id|desc', $pager = null) + { + return $this->dao->select('*')->from(TABLE_BUG)->where('project')->eq((int)$projectID)->orderBy($orderBy)->page($pager)->fetchAll(); + } + + /* 閫氳繃鏌愪竴娆℃祴璇曠粨鏋滆幏寰梑ug鐨勬爣棰樺拰姝ラ銆*/ + public function getBugInfoFromResult($resultID) + { + $title = ''; + $bugSteps = ''; + + $result = $this->dao->findById($resultID)->from(TABLE_TESTRESULT)->fetch(); + $run = $this->loadModel('testtask')->getRunById($result->run); + if($result and $result->caseResult == 'fail') + { + $title = $run->case->title; + $caseSteps = $run->case->steps; + $stepResults = unserialize($result->stepResults); + $bugSteps = $this->lang->bug->tblStep; + foreach($caseSteps as $key => $step) + { + $bugSteps .= ($key + 1) . '. ' .$step->desc . "\n"; + if($stepResults[$step->id]['result'] == 'fail') + { + $bugSteps .= $this->lang->bug->tblResult; + $bugSteps .= $stepResults[$step->id]['real'] . "\n"; + $bugSteps .= $this->lang->bug->tblExpect; + $bugSteps .= $step->expect; + break; + } + } + } + return array('title' => $title, 'steps' => $bugSteps); + } +} diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/activate.html.php b/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/activate.html.php new file mode 100644 index 0000000000..62462435fb --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/activate.html.php @@ -0,0 +1,56 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package bug + * @version $Id$ + * @link http://www.zentao.cn + */ +?> + +
+
+ + + + + + + + + + + + + + + + + + + + + +
title;?>
bug->assignedTo;?>resolvedBy, 'class=select-3');?>
bug->openedBuild;?>resolvedBuild, 'class=select-3');?>
comment;?>
bug->files;?>fetch('file', 'buildform');?>
+ + +
+ +
+ diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/browse.html.php b/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/browse.html.php new file mode 100644 index 0000000000..2233c93aed --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/browse.html.php @@ -0,0 +1,121 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package bug + * @version $Id$ + * @link http://www.zentao.cn + */ +?> + + + + + +
+
+
+ " . $lang->bug->moduleBugs . " "; + echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=assignToMe¶m=0"), $lang->bug->assignToMe) . ""; + echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=openedByMe¶m=0"), $lang->bug->openedByMe) . ""; + echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=resolvedByMe¶m=0"), $lang->bug->resolvedByMe) . ""; + echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=assignToNull¶m=0"), $lang->bug->assignToNull) . ""; + echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=longLifeBugs¶m=0"), $lang->bug->longLifeBugs) . ""; + echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=postponedBugs¶m=0"), $lang->bug->postponedBugs) . ""; + echo "{$lang->bug->byQuery} "; + echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=all¶m=0&orderBy=$orderBy&recTotal=0&recPerPage=200"), $lang->bug->allBugs) . ""; + ?> +
+
+ bug->create); ?> +
+
+
'>
+
+ +
' id='mainbox'> +
' id='treebox'> +
+
+ +
+ createLink('tree', 'browse', "productID=$productID&view=bug"), $lang->tree->manage);?> +
+
+
+ +
+
+ recTotal}&recPerPage={$pager->recPerPage}"; ?> + + + + + + + + + + + + + + + + + + + + + + + + + +
bug->id);?>bug->severity);?>bug->title);?>bug->openedBy);?>bug->assignedTo);?>bug->resolvedBy);?>bug->resolution);?>
createLink('bug', 'view', "bugID=$bug->id"), sprintf('%03d', $bug->id));?>severity?>title;?>openedBy];?>assignedTo == $this->app->user->account) echo 'style=color:red';?>>assignedTo];?>resolvedBy];?>bug->resolutionList[$bug->resolution];?>
+ show();?> +
+
+
+ + diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/close.html.php b/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/close.html.php new file mode 100644 index 0000000000..4f8580afe3 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/close.html.php @@ -0,0 +1,44 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package bug + * @version $Id$ + * @link http://www.zentao.cn + */ +?> + + +
+ + + + + + + + + +
title;?>
comment;?>
+ + +
+ +
+ diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/create.html.php b/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/create.html.php new file mode 100644 index 0000000000..40e704da61 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/create.html.php @@ -0,0 +1,179 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package bug + * @version $Id$ + * @link http://www.zentao.cn + */ +?> + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
bug->create;?>
bug->lblProductAndModule;?> + + +
bug->lblProjectAndTask;?> + + +
bug->lblStory;?> + +
bug->openedBuild;?> + +
bug->lblTypeAndSeverity;?> + bug->typeList, 'codeerror', 'class=select-2');?> + bug->severityList, '', 'class=select-2');?> +
bug->lblSystemBrowserAndHardware;?> + bug->osList, '', 'class=select-2');?> + bug->browserList, '', 'class=select-2');?> +
bug->lblAssignedTo;?>
bug->lblMailto;?>
bug->title;?>
bug->steps;?>
bug->files;?>fetch('file', 'buildform');?>
+ +
+ +
+ diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/edit.html.php b/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/edit.html.php new file mode 100644 index 0000000000..38e81742d5 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/edit.html.php @@ -0,0 +1,298 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package bug + * @version $Id$ + * @link http://www.zentao.cn + */ +?> + + + +
+
+
+
+ BUG #id . $lang->colon;?> + title, 'class=text-1');?> +
+
+
+
+ +
+
+
+ + +
+
+ bug->legendSteps;?> + +
+
+ bug->legendComment;?> + +
+
+ bug->legendAttatch;?> + fetch('file', 'buildform', 'filecount=2');?> +
+
+ + "' /> +
+
+ +
+
+ +
+
+ bug->legendBasicInfo;?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
bug->product;?> + +
bug->module;?> + +
bug->type;?>bug->typeList, $bug->type, 'class=select-3');?> +
bug->severity;?>bug->severityList, $bug->severity, 'class=select-3');?> +
bug->status;?>bug->statusList, $bug->status, 'class=select-3');?>
bug->assignedTo;?>assignedTo, 'class=select-3');?>
bug->os;?>bug->osList, $bug->os, 'class=select-3');?>
bug->browser;?>bug->browserList, $bug->browser, 'class=select-3');?>
+
+ +
+ bug->legendPrjStoryTask;?> + + + + + + + + + + + + + +
bug->project;?>project, 'class=select-3 onchange=loadProjectRelated(this.value)');?>
bug->story;?>story, 'class=select-3');?>
bug->task;?>task, 'class=select-3');?>
+
+ +
+ bug->legendLife;?> + + + + + + + + + + + + + + + + + + + + + + + + + + resolution != 'duplicate') echo "style='display:none'";?>> + + + + + + + + + + + +
bug->openedBy;?>openedBy];?>
bug->openedBuild;?>openedBuild, 'class=select-3');?>
bug->resolvedBy;?>resolvedBy, 'class=select-3');?>
bug->resolvedDate;?>resolvedDate, 'class=text-3');?>
bug->resolvedBuild;?>resolvedBuild, 'class=select-3');?>
bug->resolution;?>bug->resolutionList, $bug->resolution, 'class=select-3 onchange=setDuplicate(this.value)');?>
bug->duplicateBug;?>duplicateBug, 'class=text-3');?>
bug->closedBy;?>closedBy, 'class=select-3');?>
bug->closedDate;?>closedDate, 'class=text-3');?>
+
+
+ bug->legendMisc;?> + + + + + + + + + + + + + +
bug->mailto;?>mailto, 'class="text-3"');?>
bug->linkBug;?>linkBug, 'class="text-3"');?>
bug->case;?>case, 'class="text-3"');?>
+
+
+
+ diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/index.html.php b/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/index.html.php new file mode 100644 index 0000000000..ef4e0b46ab --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/index.html.php @@ -0,0 +1,28 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package bug + * @version $Id$ + * @link http://www.zentao.cn + */ +?> + +
+
+ \ No newline at end of file diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/resolve.html.php b/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/resolve.html.php new file mode 100644 index 0000000000..059ee35915 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/resolve.html.php @@ -0,0 +1,73 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package bug + * @version $Id$ + * @link http://www.zentao.cn + */ +?> + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
title;?>
bug->resolution;?>bug->resolutionList, '', 'class=select-3 onchange=setDuplicate(this.value)');?>
bug->resolvedBuild;?>
bug->assignedTo;?>openedBy, 'class=select-3');?>
comment;?>
+ + +
+ +
+ diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/sendmail.html.php b/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/sendmail.html.php new file mode 100644 index 0000000000..beff93d25e --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/sendmail.html.php @@ -0,0 +1,34 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package bug + * @version $Id$ + * @link http://www.zentao.cn + */ +?> + + + + + + + +
+ BUG #id . "=>$bug->assignedTo " . html::a(common::getSysURL() . $this->createLink('bug', 'view', "bugID=$bug->id"), $bug->title);?> +
diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/view.html.php b/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/view.html.php new file mode 100644 index 0000000000..07d9a4be43 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/bug/view/view.html.php @@ -0,0 +1,201 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package bug + * @version $Id$ + * @link http://www.zentao.cn + */ +?> + + +
+
+
BUG #id . $lang->colon . $bug->title;?>
+
+ id"; + common::printLink('bug', 'edit', $params, $lang->bug->buttonEdit); + if(!($bug->status == 'active' and common::printLink('bug', 'resolve', $params, $lang->bug->buttonResolve))) echo $lang->bug->buttonResolve . ' '; + if(!($bug->status == 'resolved' and common::printLink('bug', 'close', $params, $lang->bug->buttonClose))) echo $lang->bug->buttonClose . ' '; + if(!(($bug->status == 'closed' or $bug->status == 'resolved') and common::printLink('bug', 'activate', $params, $lang->bug->buttonActivate))) echo $lang->bug->buttonActivate . ' '; + common::printLink('bug', 'browse', '', $lang->bug->buttonToList); + ?> +
+
+
+ +
+
+
+
+ bug->legendSteps;?> +
steps);?>
+
+
+ bug->legendAttatch;?> +
files as $file) echo html::a($file->fullPath, $file->title, '_blank');?>
+
+ +
+ bug->buttonEdit); + if(!($bug->status == 'active' and common::printLink('bug', 'resolve', $params, $lang->bug->buttonResolve))) echo $lang->bug->buttonResolve . ' '; + if(!($bug->status == 'resolved' and common::printLink('bug', 'close', $params, $lang->bug->buttonClose))) echo $lang->bug->buttonClose . ' '; + if(!(($bug->status == 'closed' or $bug->status == 'resolved') and common::printLink('bug', 'activate', $params, $lang->bug->buttonActivate))) echo $lang->bug->buttonActivate . ' '; + common::printLink('bug', 'browse', '', $lang->bug->buttonToList); + ?> +
+
+
+ +
+
+ bug->legendBasicInfo;?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
bug->product;?>product", $productName)) echo $productName;?> +
bug->module;?> + $module) + { + if(!common::printLink('bug', 'browse', "productID=$bug->product&browseType=byModule¶m=$module->id", $module->name)) echo $module->name; + if(isset($modulePath[$key + 1])) echo $lang->arrow; + } + ?> +
bug->type;?>bug->typeList[$bug->type])) echo $lang->bug->typeList[$bug->type]; else echo $bug->type;?>
bug->severity;?>severity;?>
bug->status;?>bug->statusList[$bug->status];?>
bug->lblAssignedTo;?>assignedTo) echo $users[$bug->assignedTo] . $lang->at . $bug->assignedDate;?>
bug->os;?>bug->osList[$bug->os];?>
bug->browser;?>bug->browserList[$bug->browser];?>
+
+ +
+ bug->legendLife;?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
bug->openedBy;?> openedBy] . $lang->at . $bug->openedDate;?>
bug->openedBuild;?>openedBuild])) echo $builds[$bug->openedBuild]; else echo $bug->openedBuild;?>
bug->lblResolved;?>resolvedBy) echo $users[$bug->resolvedBy] . $lang->at . $bug->resolvedDate;?> +
bug->resolvedBuild;?>resolvedBuild])) echo $builds[$bug->resolvedBuild]; else echo $bug->resolvedBuild;?>
bug->resolution;?> + bug->resolutionList[$bug->resolution]; + if(isset($bug->duplicateBugTitle)) echo " #$bug->duplicateBug:" . html::a($this->createLink('bug', 'view', "bugID=$bug->duplicateBug"), $bug->duplicateBugTitle); + ?> +
bug->closedBy;?>closedBy) echo $users[$bug->closedBy] . $lang->at . $bug->closedDate;?>
bug->lblLastEdited;?>lastEditedBy) echo $users[$bug->lastEditedBy] . $lang->at . $bug->lastEditedDate?>
+
+ +
+ bug->legendPrjStoryTask;?> + + + + + + + + + + + + + +
bug->project;?>project) echo html::a($this->createLink('project', 'browse', "projectid=$bug->project"), $bug->projectName);?>
bug->story;?>story) echo html::a($this->createLink('story', 'view', "storyID=$bug->story"), $bug->storyTitle);?>
bug->task;?>task) echo html::a($this->createLink('task', 'view', "taskID=$bug->task"), $bug->taskName);?>
+
+
+ bug->legendMisc;?> + + + + + + + + + + + + + +
bug->mailto;?>mailto); foreach($mailto as $account) echo ' ' . $users[$account]; ?>
bug->linkBug;?> + linkBugTitles)) + { + foreach($bug->linkBugTitles as $linkBugID => $linkBugTitle) + { + echo html::a($this->createLink('bug', 'view', "bugID=$linkBugID"), "#$linkBugID $linkBugTitle", '_blank') . '
'; + } + } + ?> +
bug->case;?>caseTitle)) echo html::a($this->createLink('testcase', 'view', "caseID=$bug->case"), "#$bug->case $bug->caseTitle", '_blank');?>
+
+
+
+ diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/build/control.php b/tags/zentaopms_0.5.0_beta_20100221/module/build/control.php new file mode 100644 index 0000000000..8a87c4749e --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/build/control.php @@ -0,0 +1,112 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package build + * @version $Id$ + * @link http://www.zentao.cn + */ +class build extends control +{ + /* 娣诲姞build銆*/ + public function create($projectID) + { + if(!empty($_POST)) + { + $this->build->create($projectID); + if(dao::isError()) die(js::error(dao::getError())); + die(js::locate($this->createLink('project', 'build', "project=$projectID"), 'parent')); + } + + /* 璁剧疆鑿滃崟銆*/ + $this->loadModel('project')->setMenu($this->project->getPairs(), $projectID); + + /* 璧嬪笺*/ + $this->view->header->title = $this->lang->build->create; + $this->view->products = $this->project->getProducts($projectID); + $this->view->users = $this->loadModel('user')->getPairs(); + $this->display(); + } + + /* 缂栬緫build銆*/ + public function edit($buildID) + { + if(!empty($_POST)) + { + $this->build->update($buildID); + if(dao::isError()) die(js::error(dao::getError())); + die(js::locate($this->createLink('project', 'build', "projectID={$this->post->project}"), 'parent')); + } + + /* 璁剧疆鑿滃崟銆*/ + $build = $this->build->getById((int)$buildID); + $this->loadModel('project')->setMenu($this->project->getPairs(), $build->project); + + /* 璧嬪笺*/ + $this->view->header->title = $this->lang->build->edit; + $this->view->position[] = $this->lang->build->edit; + $this->view->products = $this->project->getProducts($build->project); + $this->view->users = $this->loadModel('user')->getPairs(); + $this->view->build = $build; + $this->display(); + } + + /* 鏌ョ湅build銆*/ + public function view($buildID) + { + /* 璁剧疆鑿滃崟銆*/ + $build = $this->build->getById((int)$buildID); + $this->loadModel('project')->setMenu($this->project->getPairs(), $build->project); + + /* 璧嬪笺*/ + $this->view->header->title = $this->lang->build->view; + $this->view->position[] = $this->lang->build->view; + $this->view->products = $this->project->getProducts($build->project); + $this->view->users = $this->loadModel('user')->getPairs(); + $this->view->build = $build; + $this->display(); + } + + /* 鍒犻櫎build銆*/ + public function delete($buildID, $confirm = 'no') + { + if($confirm == 'no') + { + die(js::confirm($this->lang->build->confirmDelete, $this->createLink('build', 'delete', "buildID=$buildID&confirm=yes"))); + } + else + { + $build = $this->build->getById($buildID); + $this->build->delete($buildID); + die(js::locate($this->createLink('project', 'build', "projectID=$build->project"), 'parent')); + } + } + + /* AJAX鎺ュ彛锛氳幏寰椾骇鍝佺殑build鍒楄〃銆*/ + public function ajaxGetProductBuilds($productID, $varName, $build = '') + { + die(html::select($varName, $this->build->getProductBuildPairs($productID), $build)); + } + + /* AJAX鎺ュ彛锛氳幏寰楅」鐩殑build鍒楄〃銆*/ + public function ajaxGetProjectBuilds($projectID, $varName, $build = '') + { + die(html::select($varName, $this->build->getProjectBuildPairs($projectID), $build)); + } + +} diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/build/lang/zh-cn.php b/tags/zentaopms_0.5.0_beta_20100221/module/build/lang/zh-cn.php new file mode 100644 index 0000000000..2ab6428ce6 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/build/lang/zh-cn.php @@ -0,0 +1,42 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package build + * @version $Id$ + * @link http://www.zentao.cn + */ +$lang->build->common = 'Build'; +$lang->build->create = "鍒涘缓Build"; +$lang->build->edit = "缂栬緫Build"; +$lang->build->delete = "鍒犻櫎Build"; +$lang->build->view = "Build璇︽儏"; +$lang->build->ajaxGetProductBuilds = '鎺ュ彛:浜у搧Build鍒楄〃'; +$lang->build->ajaxGetProjectBuilds = '鎺ュ彛:椤圭洰Build鍒楄〃'; + +$lang->build->confirmDelete = "鎮ㄧ‘璁ゅ垹闄よbuild鍚楋紵"; + +$lang->build->id = 'ID'; +$lang->build->product = '浜у搧'; +$lang->build->project = '椤圭洰'; +$lang->build->name = '鍚嶇О缂栧彿'; +$lang->build->date = 'Build鏃ユ湡'; +$lang->build->builder = '鏋勫缓鑰'; +$lang->build->scmPath = '婧愪唬鐮佸湴鍧'; +$lang->build->filePath = '瀛樺偍鍦板潃'; +$lang->build->desc = '鎻忚堪'; diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/build/model.php b/tags/zentaopms_0.5.0_beta_20100221/module/build/model.php new file mode 100644 index 0000000000..5a142e3440 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/build/model.php @@ -0,0 +1,101 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package build + * @version $Id$ + * @link http://www.zentao.cn + */ +?> +dao->select('t1.*, t2.name as projectName, t3.name as productName') + ->from(TABLE_BUILD)->alias('t1') + ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') + ->leftJoin(TABLE_PRODUCT)->alias('t3')->on('t1.product = t3.id') + ->where('t1.id')->eq((int)$buildID) + ->orderBy('t1.id DESC') + ->fetch(); + } + + /* 鏌ユ壘椤圭洰涓殑build鍒楄〃銆*/ + public function getProjectBuilds($projectID) + { + return $this->dao->select('t1.*, t2.name as projectName, t3.name as productName') + ->from(TABLE_BUILD)->alias('t1') + ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') + ->leftJoin(TABLE_PRODUCT)->alias('t3')->on('t1.product = t3.id') + ->where('t1.project')->eq((int)$projectID) + ->orderBy('t1.id DESC') + ->fetchAll(); + } + + /* 鏌ユ壘椤圭洰涓殑build key=>value瀵广*/ + public function getProjectBuildPairs($projectID) + { + $sysBuilds = array('' => '', 'trunk' => 'Trunk'); + $builds = $this->dao->select('id,name')->from(TABLE_BUILD)->where('project')->eq((int)$projectID)->orderBy('id desc')->fetchPairs(); + if(!$builds) return $sysBuilds; + $releases = $this->dao->select('build,name')->from(TABLE_RELEASE)->where('build')->in(array_keys($builds))->fetchPairs(); + foreach($releases as $buildID => $releaseName) $builds[$buildID] = $releaseName; + return $sysBuilds + $builds; + } + + /* 鏌ユ壘浜у搧涓殑build鍒楄〃銆*/ + public function getProductBuildPairs($productID) + { + $sysBuilds = array('' => '', 'trunk' => 'Trunk'); + $builds = $this->dao->select('id,name')->from(TABLE_BUILD)->where('product')->eq((int)$productID)->orderBy('id desc')->fetchPairs(); + if(!$builds) return $sysBuilds; + $releases = $this->dao->select('build,name')->from(TABLE_RELEASE)->where('build')->in(array_keys($builds))->fetchPairs(); + foreach($releases as $buildID => $releaseName) $builds[$buildID] = $releaseName; + return $sysBuilds + $builds; + } + + /* 鍒涘缓銆*/ + public function create($projectID) + { + $build = fixer::input('post') + ->stripTags('name') + ->specialChars('desc') + ->add('project', (int)$projectID) + ->get(); + $this->dao->insert(TABLE_BUILD)->data($build)->autoCheck()->batchCheck('name,date,builder', 'notempty')->exec(); + if(!dao::isError()) return $this->dao->lastInsertID(); + } + + /* 缂栬緫銆*/ + public function update($buildID) + { + $build = fixer::input('post') + ->stripTags('name') + ->specialChars('desc') + ->get(); + $this->dao->update(TABLE_BUILD)->data($build)->autoCheck()->batchCheck('name,date,builder', 'notempty')->where('id')->eq((int)$buildID)->exec(); + } + + /* 鍒犻櫎build銆*/ + public function delete($buildID) + { + return $this->dao->delete()->from(TABLE_BUILD)->where('id')->eq((int)$buildID)->exec(); + } +} diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/build/view/create.html.php b/tags/zentaopms_0.5.0_beta_20100221/module/build/view/create.html.php new file mode 100644 index 0000000000..057d81b4f3 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/build/view/create.html.php @@ -0,0 +1,65 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package build + * @version $Id$ + * @link http://www.zentao.cn + */ +?> + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
build->create;?>
build->product;?>
build->name;?>
build->builder;?>user->account, 'class="select-3"');?>
build->date;?>' />
build->scmPath;?>
build->filePath;?>
build->desc;?>
+ +
+ diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/build/view/edit.html.php b/tags/zentaopms_0.5.0_beta_20100221/module/build/view/edit.html.php new file mode 100644 index 0000000000..05b2f7204b --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/build/view/edit.html.php @@ -0,0 +1,64 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package build + * @version $Id$ + * @link http://www.zentao.cn + */ +?> + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
build->edit;?>
build->product;?>product);?>
build->name;?>
build->builder;?>builder, 'class="select-3"');?>
build->date;?>
build->scmPath;?>
build->filePath;?>
build->desc;?>
project);?>
+
+
+ diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/build/view/view.html.php b/tags/zentaopms_0.5.0_beta_20100221/module/build/view/view.html.php new file mode 100644 index 0000000000..130087aa2f --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/build/view/view.html.php @@ -0,0 +1,70 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package build + * @version $Id$ + * @link http://www.zentao.cn + */ +?> + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
build->view;?>
build->product;?>productName;?>
build->name;?>name;?>
build->builder;?>builder];?>
build->date;?>date;?>
build->scmPath;?>scmPath, 'http') === 0 ? printf(html::a($build->scmPath)) : printf($build->scmPath);?>
build->filePath;?>filePath, 'http') === 0 ? printf(html::a($build->filePath)) : printf($build->filePath);?>
build->desc;?>desc);?>
+ id", $lang->edit); + common::printLink('build', 'delete', "buildID=$build->id", $lang->delete); + ?> +
+
+
+ diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/common/action.html.php b/tags/zentaopms_0.5.0_beta_20100221/module/common/action.html.php new file mode 100644 index 0000000000..55655ba844 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/common/action.html.php @@ -0,0 +1,24 @@ + +
+
+ history . $lang->reverse;?> +
    + + +
  1. + actor])) $action->actor = $users[$action->actor]; + if(strpos($action->actor, ':') !== false) $action->actor = substr($action->actor, strpos($action->actor, ':') + 1); + ?> + action->printAction($action);?> + comment) or !empty($action->history)):?> +
    +
    action->printChanges($action->objectType, $action->history);?>
    + comment and $action->history) echo '
    '; echo nl2br($action->comment);?> +
    + +
  2. + +
+
+
diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/common/autocomplete.html.php b/tags/zentaopms_0.5.0_beta_20100221/module/common/autocomplete.html.php new file mode 100644 index 0000000000..68731f72ab --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/common/autocomplete.html.php @@ -0,0 +1,3 @@ + + + diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/common/autosuggest.html.php b/tags/zentaopms_0.5.0_beta_20100221/module/common/autosuggest.html.php new file mode 100644 index 0000000000..8cb75f7788 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/common/autosuggest.html.php @@ -0,0 +1,15 @@ + + + diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/common/colorbox.html.php b/tags/zentaopms_0.5.0_beta_20100221/module/common/colorbox.html.php new file mode 100644 index 0000000000..e1c7718bc4 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/common/colorbox.html.php @@ -0,0 +1,2 @@ + + diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/common/colorize.html.php b/tags/zentaopms_0.5.0_beta_20100221/module/common/colorize.html.php new file mode 100644 index 0000000000..1d6a9a2c26 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/common/colorize.html.php @@ -0,0 +1,2 @@ + + diff --git a/tags/zentaopms_0.5.0_beta_20100221/module/common/control.php b/tags/zentaopms_0.5.0_beta_20100221/module/common/control.php new file mode 100644 index 0000000000..ceebc32647 --- /dev/null +++ b/tags/zentaopms_0.5.0_beta_20100221/module/common/control.php @@ -0,0 +1,433 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package common + * @version $Id$ + * @link http://www.zentao.cn + */ +class common extends control +{ + /** + * 构造函数:启动会话,加载公司模块,并设置公司信息。 + * + * @access public + * @return void + */ + public function __construct() + { + parent::__construct(); + session_start(); + $this->sendHeader(); + $this->loadModel('company'); + $this->setCompany(); + $this->setUser(); + } + + /** + * 检查用户对当前的请求有没有权限。如果没有权限,则跳转到登陆界面。 + * + * @access public + * @return void + */ + public function checkPriv() + { + $module = $this->app->getModuleName(); + $method = $this->app->getMethodName(); + if($module == 'user') + { + if($method == 'login' or $method == 'logout' or $method == 'deny') return true; + } + + if(isset($this->app->user)) + { + if(!common::hasPriv($module, $method)) + { + $vars = "module=$module&method=$method"; + if(isset($_SERVER['HTTP_REFERER'])) + { + $referer = helper::safe64Encode($_SERVER['HTTP_REFERER']); + $vars .= "&referer=$referer"; + } + $denyLink = $this->createLink('user', 'deny', $vars); + + /* Fix the bug of IE: use js locate, can't get the referer. */ + if(strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) + { + echo <<