├── .gitattributes ├── .github └── ISSUE_TEMPLATE │ └── bug_report.md ├── .gitignore ├── README.md ├── front └── config.form.php ├── hook.php ├── inc ├── config.class.php └── mailcollector.class.php ├── mailanalyzer.xml ├── plugin.png ├── scripts └── threadindex.php └── setup.php /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto !eol 2 | /README.md -text 3 | /hook.php -text 4 | /mailanalyzer.xml -text 5 | /plugin.png -text 6 | /setup.php -text 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 24 | 25 | **Describe the bug** 26 | 27 | A clear and concise description of what the bug is. 28 | 29 | **Page(s) URL** 30 | 31 | If applicable, page(s) URL where the bug happens. 32 | 33 | **To reproduce** 34 | 35 | Steps to reproduce the behavior: 36 | 1. Go to '...' 37 | 2. Click on '....' 38 | 3. Scroll down to '....' 39 | 4. See error 40 | 41 | **Expected behavior** 42 | 43 | A clear and concise description of what you expected to happen. 44 | 45 | **Logs** 46 | 47 | ``` 48 | paste logs here 49 | Find them in *-error.log files under glpi/files/_log/ 50 | ``` 51 | 52 | **Screenshots** 53 | 54 | If applicable, add screenshots to help explain your problem. 55 | 56 | 57 | **Your GLPI setup (you can find it in Setup > General menu, System tab)** 58 | 59 | ``` 60 | paste here 61 | ``` 62 | 63 | **Additional context** 64 | 65 | Add any other context about the problem here. 66 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # This .gitignore file was automatically created by Microsoft(R) Visual Studio. 3 | ################################################################################ 4 | 5 | .vshistory 6 | .vs -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mailanalyzer 2 | Mail Analyzer GLPI Plugin aims at keeping track of email conversations. 3 | It will combine emails from the same conversation into one Ticket. 4 | 5 | It is currently tested with GLPI 0.83.8, 0.85.5, 0.90, 9.1, 9.2, 9.3, 9.4, 9.5 and 10.0 6 | 7 | Must be copied into *glpifolder*/plugins/mailanalyzer, or it can be downloaded from the GLPI plugin marketplace. 8 | 9 | To be installed and enabled via the plugins configuration page in GLPI. 10 | 11 | It creates a new table in the DB with the purpose of storing email guid (generated by email servers) in order to be able (if possible) to match emails in mailgate which have been sent using 'CC' and 'Reply to all'. 12 | It cannot keeps track of forwarded emails and replies to them. 13 | 14 | This solves the problem of duplicated Tickets when an email is sent to GLPI and CC (carbon copy) to others. And when those CC users use 'Reply to All', GLPI by default will create a new ticket. See: http://glpi.userecho.com/topic/1090667-new-rule-criteria-for-mail-receivers/ 15 | 16 | 17 | Please report any question/problem in the issue section. 18 | -------------------------------------------------------------------------------- /front/config.form.php: -------------------------------------------------------------------------------- 1 | . 26 | -------------------------------------------------------------------------- 27 | */ 28 | 29 | include ( "../../../inc/includes.php"); 30 | 31 | Session::setActiveTab('Config', 'PluginMailanalyzerConfig$1'); 32 | Html::redirect($CFG_GLPI["root_doc"]."/front/config.form.php"); 33 | -------------------------------------------------------------------------------- /hook.php: -------------------------------------------------------------------------------- 1 | . 26 | -------------------------------------------------------------------------- 27 | */ 28 | /** 29 | * Summary of plugin_mailanalyzer_install 30 | * @return boolean 31 | */ 32 | function plugin_mailanalyzer_install() { 33 | global $DB; 34 | 35 | if (!$DB->tableExists("glpi_plugin_mailanalyzer_message_id")) { 36 | $query = "CREATE TABLE `glpi_plugin_mailanalyzer_message_id` ( 37 | `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, 38 | `message_id` VARCHAR(255) NOT NULL DEFAULT '0', 39 | `tickets_id` INT UNSIGNED NOT NULL DEFAULT '0', 40 | `mailcollectors_id` int UNSIGNED NOT NULL DEFAULT '0', 41 | PRIMARY KEY (`id`), 42 | UNIQUE INDEX `message_id` (`message_id`,`mailcollectors_id`), 43 | INDEX `tickets_id` (`tickets_id`) 44 | ) 45 | COLLATE='utf8mb4_unicode_ci' 46 | ENGINE=innoDB; 47 | "; 48 | 49 | $DB->query($query) or die("error creating glpi_plugin_mailanalyzer_message_id " . $DB->error()); 50 | } else { 51 | if (count($DB->listTables('glpi_plugin_mailanalyzer_message_id', ['engine' => 'MyIsam'])) > 0) { 52 | $query = "ALTER TABLE glpi_plugin_mailanalyzer_message_id ENGINE = InnoDB"; 53 | $DB->query($query) or die("error updating ENGINE in glpi_plugin_mailanalyzer_message_id " . $DB->error()); 54 | } 55 | } 56 | if ($DB->fieldExists("glpi_plugin_mailanalyzer_message_id","mailgate_id")) 57 | { 58 | //STEP - UPDATE MAILGATE_ID INTO MAILCOLLECTORS_ID 59 | $query = "ALTER TABLE `glpi_plugin_mailanalyzer_message_id` 60 | CHANGE COLUMN `mailgate_id` `mailcollectors_id` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `message_id`, 61 | DROP INDEX `message_id`, 62 | ADD UNIQUE INDEX `message_id` (`message_id`, `mailcollectors_id`) USING BTREE;"; 63 | $DB->query($query) or die("error updating ENGINE in glpi_plugin_mailanalyzer_message_id " . $DB->error()); 64 | } 65 | if (!$DB->fieldExists("glpi_plugin_mailanalyzer_message_id","mailcollectors_id")) 66 | { 67 | //STEP - ADD mailcollectors_id 68 | $query = "ALTER TABLE glpi_plugin_mailanalyzer_message_id ADD COLUMN `mailcollectors_id` int UNSIGNED NOT NULL DEFAULT 0 AFTER `message_id`"; 69 | $DB->query($query) or die("error updating ENGINE in glpi_plugin_mailanalyzer_message_id " . $DB->error()); 70 | 71 | //STEP - REMOVE UNICITY CONSTRAINT 72 | $query = "ALTER TABLE glpi_plugin_mailanalyzer_message_id DROP INDEX `message_id`"; 73 | $DB->query($query) or die("error updating ENGINE in glpi_plugin_mailanalyzer_message_id " . $DB->error()); 74 | //STEP - ADD NEW UNICITY CONSTRAINT 75 | $query = "ALTER TABLE glpi_plugin_mailanalyzer_message_id ADD UNIQUE KEY `message_id` (`message_id`,`mailcollectors_id`);"; 76 | $DB->query($query) or die("error updating ENGINE in glpi_plugin_mailanalyzer_message_id " . $DB->error()); 77 | } 78 | 79 | if (!$DB->fieldExists('glpi_plugin_mailanalyzer_message_id', 'tickets_id')) { 80 | // then we must change the name and the length of id and ticket_id to 11 81 | $query = "ALTER TABLE `glpi_plugin_mailanalyzer_message_id` 82 | CHANGE COLUMN `id` `id` INT UNSIGNED NOT NULL AUTO_INCREMENT FIRST, 83 | CHANGE COLUMN `ticket_id` `tickets_id` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `message_id`, 84 | DROP INDEX `ticket_id`, 85 | ADD INDEX `ticket_id` (`tickets_id`);"; 86 | $DB->query($query) or die('Cannot alter glpi_plugin_mailanalyzer_message_id table! ' . $DB->error()); 87 | } 88 | 89 | return true; 90 | } 91 | 92 | 93 | /** 94 | * Summary of plugin_mailanalyzer_uninstall 95 | * @return boolean 96 | */ 97 | function plugin_mailanalyzer_uninstall() { 98 | 99 | // nothing to uninstall 100 | // do not delete table 101 | 102 | return true; 103 | } 104 | 105 | 106 | /** 107 | * Summary of PluginMailAnalyzer 108 | */ 109 | class PluginMailAnalyzer { 110 | 111 | /** 112 | * Create default mailgate 113 | * @param int $mailcollectors_id is the id of the mail collector in GLPI DB 114 | * @return bool|MailCollector 115 | */ 116 | static function openMailgate($mailcollectors_id) : PluginMailanalyzerMailCollector { 117 | 118 | $mailgate = new PluginMailanalyzerMailCollector(); 119 | $mailgate->getFromDB($mailcollectors_id); 120 | $mailgate->uid = -1; 121 | $mailgate->connect(); 122 | 123 | return $mailgate; 124 | } 125 | 126 | 127 | /** 128 | * Summary of plugin_pre_item_add_mailanalyzer 129 | * @param mixed $parm 130 | * @return void 131 | */ 132 | public static function plugin_pre_item_add_mailanalyzer($parm) { 133 | global $DB, $mailgate; 134 | 135 | $mailgateId = $parm->input['_mailgate'] ?? false; 136 | if ($mailgateId) { 137 | // this ticket have been created via email receiver. 138 | // Analyzes emails to establish conversation 139 | 140 | // search for 'Thread-Index'? 141 | $config = Config::getConfigurationValues('plugin:mailanalyzer'); 142 | $use_threadindex = isset($config['use_threadindex']) && $config['use_threadindex']; 143 | 144 | if (isset($mailgate)) { 145 | // mailgate has been open by web page call, then use it 146 | $local_mailgate = $mailgate; 147 | // if use of threadindex is true then must open a new mailgate 148 | // to be able to get the threadindex of the email 149 | if ($use_threadindex) { 150 | $local_mailgate = PluginMailAnalyzer::openMailgate($mailgateId); 151 | } 152 | } else { 153 | // mailgate is not open. Called by cron 154 | // then locally create a mailgate 155 | $local_mailgate = PluginMailAnalyzer::openMailgate($mailgateId); 156 | if ($local_mailgate === false) { 157 | // can't connect to the mail server, then cancel ticket creation 158 | $parm->input = false;// []; // empty array... 159 | return; 160 | } 161 | } 162 | 163 | if ($use_threadindex) { 164 | $local_message = $local_mailgate->getMessage($parm->input['_uid']); 165 | $threadindex = $local_mailgate->getThreadIndex($local_message); 166 | if ($threadindex) { 167 | // add threadindex to the '_head' of the input 168 | $parm->input['_head']['threadindex'] = $threadindex; 169 | } 170 | } 171 | 172 | 173 | // we must check if this email has not been received yet! 174 | // test if 'message-id' is in the DB 175 | $messageId = html_entity_decode($parm->input['_head']['message_id']); 176 | $uid = $parm->input['_uid']; 177 | $res = $DB->request( 178 | 'glpi_plugin_mailanalyzer_message_id', 179 | [ 180 | 'AND' => 181 | [ 182 | 'tickets_id' => ['!=', 0], 183 | 'message_id' => $messageId, 184 | 'mailcollectors_id' => $mailgateId 185 | ] 186 | ] 187 | ); 188 | if ($row = $res->current()) { 189 | // email already received 190 | // must prevent ticket creation 191 | $parm->input = false; //[ ]; 192 | 193 | // as Ticket creation is cancelled, then email is not deleted from mailbox 194 | // then we need to set deletion flag to true to this email from mailbox folder 195 | $local_mailgate->deleteMails($uid, MailCollector::REFUSED_FOLDER); // NOK Folder 196 | 197 | return; 198 | } 199 | 200 | // search for 'Thread-Index' and 'References' 201 | $messages_id = self::getMailReferences( 202 | $parm->input['_head']['threadindex'] ?? '', 203 | html_entity_decode($parm->input['_head']['references'] ?? '') 204 | ); 205 | 206 | if (count($messages_id) > 0) { 207 | $res = $DB->request( 208 | 'glpi_plugin_mailanalyzer_message_id', 209 | ['AND' => 210 | [ 211 | 'tickets_id' => ['!=',0], 212 | 'message_id' => $messages_id, 213 | 'mailcollectors_id' => $mailgateId 214 | ], 215 | 'ORDER' => 'tickets_id DESC' 216 | ] 217 | ); 218 | if ($row = $res->current()) { 219 | // TicketFollowup creation only if ticket status is not closed 220 | $locTicket = new Ticket(); 221 | $locTicket->getFromDB((integer)$row['tickets_id']); 222 | if ($locTicket->fields['status'] != CommonITILObject::CLOSED) { 223 | $ticketfollowup = new ITILFollowup(); 224 | $input = $parm->input; 225 | $input['items_id'] = $row['tickets_id']; 226 | $input['users_id'] = $parm->input['_users_id_requester']; 227 | $input['add_reopen'] = 1; 228 | $input['itemtype'] = 'Ticket'; 229 | 230 | unset($input['urgency']); 231 | unset($input['entities_id']); 232 | unset($input['_ruleid']); 233 | 234 | $ticketfollowup->add($input); 235 | 236 | // add message id to DB in case of another email will use it 237 | $DB->insert( 238 | 'glpi_plugin_mailanalyzer_message_id', 239 | [ 240 | 'message_id' => $messageId, 241 | 'tickets_id' => $input['items_id'], 242 | 'mailcollectors_id' => $mailgateId 243 | ] 244 | ); 245 | 246 | // prevent Ticket creation. Unfortunately it will return an error to receiver when started manually from web page 247 | $parm->input = false; // []; // empty array... 248 | 249 | // as Ticket creation is cancelled, then email is not deleted from mailbox 250 | // then we need to set deletion flag to true to this email from mailbox folder 251 | $local_mailgate->deleteMails($uid, MailCollector::ACCEPTED_FOLDER); // OK folder 252 | 253 | return; 254 | 255 | } else { 256 | // ticket creation, but linked to the closed one... 257 | $parm->input['_link'] = ['link' => '1', 'tickets_id_1' => '0', 'tickets_id_2' => $row['tickets_id']]; 258 | } 259 | } 260 | } 261 | 262 | // can't find ref into DB, then this is a new ticket, in this case insert refs and message_id into DB 263 | $messages_id[] = $messageId; 264 | 265 | // this is a new ticket 266 | // then add references and message_id to DB 267 | foreach ($messages_id as $ref) { 268 | $res = $DB->request('glpi_plugin_mailanalyzer_message_id', ['message_id' => $ref, 'mailcollectors_id' => $mailgateId]); 269 | if (count($res) <= 0) { 270 | $DB->insert('glpi_plugin_mailanalyzer_message_id', ['message_id' => $ref, 'mailcollectors_id' => $mailgateId]); 271 | } 272 | } 273 | } 274 | } 275 | 276 | 277 | /** 278 | * Summary of plugin_item_add_mailanalyzer 279 | * @param mixed $parm 280 | */ 281 | public static function plugin_item_add_mailanalyzer($parm) { 282 | global $DB; 283 | if (isset($parm->input['_mailgate'])) { 284 | // this ticket have been created via email receiver. 285 | // update the ticket ID for the message_id only for newly created tickets (tickets_id == 0) 286 | 287 | // Are 'Thread-Index' or 'Refrences' present? 288 | $messages_id = self::getMailReferences( 289 | $parm->input['_head']['threadindex'] ?? '', 290 | html_entity_decode($parm->input['_head']['references'] ?? '') 291 | ); 292 | $messages_id[] = html_entity_decode($parm->input['_head']['message_id']); 293 | 294 | $DB->update( 295 | 'glpi_plugin_mailanalyzer_message_id', 296 | [ 297 | 'tickets_id' => $parm->fields['id'] 298 | ], 299 | [ 300 | 'WHERE' => 301 | [ 302 | 'AND' => 303 | [ 304 | 'tickets_id' => 0, 305 | 'message_id' => $messages_id 306 | ] 307 | ] 308 | ] 309 | ); 310 | } 311 | } 312 | 313 | 314 | /** 315 | * Summary of getMailReferences 316 | * @param string $threadindex 317 | * @param string $references 318 | * @return string[] 319 | */ 320 | private static function getMailReferences(string $threadindex, string $references) { 321 | 322 | $messages_id = []; // by default 323 | 324 | if (!empty($threadindex)) { 325 | $messages_id[] = $threadindex; 326 | } 327 | 328 | // search for 'References' 329 | if (!empty($references)) { 330 | // we may have a forwarded email that looks like reply-to 331 | if (preg_match_all('/<.*?>/', $references, $matches)) { 332 | $messages_id = array_merge($messages_id, $matches[0]); 333 | } 334 | } 335 | 336 | // clean $messages_id array 337 | return array_filter($messages_id, function($val) {return $val != trim('', '< >');}); 338 | } 339 | 340 | 341 | /** 342 | * Summary of plugin_item_purge_mailanalyzer 343 | * @param mixed $item 344 | */ 345 | static function plugin_item_purge_mailanalyzer($item) { 346 | global $DB; 347 | // the ticket is purged, then we are going to purge the matching rows in glpi_plugin_mailanalyzer_message_id table 348 | // DELETE FROM glpi_plugin 349 | $DB->delete('glpi_plugin_mailanalyzer_message_id', ['tickets_id' => $item->getID()]); 350 | } 351 | } 352 | 353 | -------------------------------------------------------------------------------- /inc/config.class.php: -------------------------------------------------------------------------------- 1 | . 26 | -------------------------------------------------------------------------- 27 | */ 28 | 29 | class PluginMailanalyzerConfig extends CommonDBTM { 30 | 31 | /** 32 | * Summary of getTypeName 33 | * @param mixed $nb plural 34 | * @return mixed 35 | */ 36 | static function getTypeName($nb = 0) { 37 | return __('Mail Analyzer setup', 'mailanalyzer'); 38 | } 39 | 40 | /** 41 | * Summary of getName 42 | * @param mixed $with_comment with comment 43 | * @return mixed 44 | */ 45 | function getName($with_comment = 0) { 46 | return __('MailAnalyzer', 'mailanalyzer'); 47 | } 48 | 49 | 50 | /** 51 | * Summary of showConfigForm 52 | * @param mixed $item is the config 53 | * @return boolean 54 | */ 55 | static function showConfigForm($item) { 56 | $config = Config::getConfigurationValues('plugin:mailanalyzer'); 57 | 58 | echo "
"; 59 | echo "
"; 60 | echo ""; 61 | 62 | echo ""; 63 | 64 | echo ""; 65 | echo ""; 71 | 72 | echo ""; 73 | 74 | echo ""; 75 | echo ""; 78 | echo "
" . __('Mail Analyzer setup', 'mailanalyzer') . "
".__('Use of Thread index', 'mailanalyzer') .""; 66 | if (!isset($config['use_threadindex'])) { 67 | $config['use_threadindex'] = 0; 68 | } 69 | Dropdown::showYesNo("use_threadindex", $config['use_threadindex']); 70 | echo "
"; 76 | echo ""; 77 | echo "
"; 79 | 80 | echo ""; 81 | echo ""; 82 | 83 | Html::closeForm(); 84 | 85 | return false; 86 | } 87 | 88 | 89 | function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) { 90 | if ($item->getType()=='Config') { 91 | return __('Mail Analyzer', 'mailanalyzer'); 92 | } 93 | return ''; 94 | } 95 | 96 | 97 | static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) { 98 | 99 | if ($item->getType()=='Config') { 100 | self::showConfigForm($item); 101 | } 102 | return true; 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /inc/mailcollector.class.php: -------------------------------------------------------------------------------- 1 | . 26 | -------------------------------------------------------------------------- 27 | -*/ 28 | 29 | use Laminas\Mail\Storage\Message; 30 | 31 | class PluginMailanalyzerMailCollector extends CommonDBTM 32 | { 33 | private $storage; 34 | public $uid = -1; 35 | 36 | public static function getTable($classname = null) { 37 | return MailCollector::getTable(); 38 | } 39 | 40 | public function connect() 41 | { 42 | $config = Toolbox::parseMailServerConnectString($this->fields['host']); 43 | 44 | $params = [ 45 | 'host' => $config['address'], 46 | 'user' => $this->fields['login'], 47 | 'password' => (new GLPIKey())->decrypt($this->fields['passwd']), 48 | 'port' => $config['port'] 49 | ]; 50 | 51 | if ($config['ssl']) { 52 | $params['ssl'] = 'SSL'; 53 | } 54 | 55 | if ($config['tls']) { 56 | $params['ssl'] = 'TLS'; 57 | } 58 | 59 | if (!empty($config['mailbox'])) { 60 | $params['folder'] = mb_convert_encoding($config['mailbox'], 'UTF7-IMAP', 'UTF-8'); 61 | } 62 | 63 | if ($config['validate-cert'] === false) { 64 | $params['novalidatecert'] = true; 65 | } 66 | 67 | try { 68 | $storage = Toolbox::getMailServerStorageInstance($config['type'], $params); 69 | if ($storage === null) { 70 | throw new \Exception(sprintf(__('Unsupported mail server type:%s.'), $config['type'])); 71 | } 72 | $this->storage = $storage; 73 | if ($this->fields['errors'] > 0) { 74 | $this->update([ 75 | 'id' => $this->getID(), 76 | 'errors' => 0 77 | ]); 78 | } 79 | } catch (\Throwable $e) { 80 | $this->update([ 81 | 'id' => $this->getID(), 82 | 'errors' => ($this->fields['errors'] + 1) 83 | ]); 84 | // Any errors will cause an Exception. 85 | throw $e; 86 | } 87 | } 88 | 89 | /** 90 | * Summary of getThreadIndex 91 | * @param Message $message 92 | * @return string|null 93 | */ 94 | public function getThreadIndex(Message $message) { 95 | if (isset($message->threadindex)) { 96 | if ($val = $message->getHeader('threadindex')) { 97 | return bin2hex(substr(base64_decode($val->getFieldValue()), 6, 16 )); 98 | } 99 | } 100 | return null; 101 | } 102 | 103 | /** 104 | * Summary of getMessage 105 | * @param mixed $uid 106 | * @return Message 107 | */ 108 | public function getMessage($uid) : Message { 109 | return $this->storage->getMessage($this->storage->getNumberByUniqueId($uid)); 110 | } 111 | 112 | /** 113 | * Delete mail from that mail box 114 | * 115 | * @param string $uid mail UID 116 | * @param string $folder Folder to move (delete if empty) (default '') 117 | * 118 | * @return boolean 119 | **/ 120 | public function deleteMails($uid, $folder = '') 121 | { 122 | 123 | // Disable move support, POP protocol only has the INBOX folder 124 | if (strstr($this->fields['host'], "/pop")) { 125 | $folder = ''; 126 | } 127 | 128 | if (!empty($folder) && isset($this->fields[$folder]) && !empty($this->fields[$folder])) { 129 | $name = mb_convert_encoding($this->fields[$folder], "UTF7-IMAP", "UTF-8"); 130 | try { 131 | $this->storage->moveMessage($this->storage->getNumberByUniqueId($uid), $name); 132 | return true; 133 | } catch (\Throwable $e) { 134 | // raise an error and fallback to delete 135 | trigger_error( 136 | sprintf( 137 | //TRANS: %1$s is the name of the folder, %2$s is the name of the receiver 138 | __('Invalid configuration for %1$s folder in receiver %2$s'), 139 | $folder, 140 | $this->getName() 141 | ) 142 | ); 143 | } 144 | } 145 | $this->storage->removeMessage($this->storage->getNumberByUniqueId($uid)); 146 | return true; 147 | } 148 | 149 | } 150 | 151 | -------------------------------------------------------------------------------- /mailanalyzer.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Mail Analyzer 4 | mailanalyzer 5 | stable 6 | https://raw.githubusercontent.com/tomolimo/mailanalyzer/master/plugin.png 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 17 | 18 | 19 | https://github.com/tomolimo/mailanalyzer 20 | https://github.com/tomolimo/mailanalyzer/releases 21 | https://github.com/tomolimo/mailanalyzer/issues 22 | https://github.com/tomolimo/mailanalyzer/wiki 23 | 24 | Olivier Moron 25 | 26 | 27 | 28 | 3.2.2 29 | ~10.0.18 30 | https://github.com/tomolimo/mailanalyzer/releases/download/3.2.2/mailanalyzer-3.2.2.zip 31 | 32 | 33 | 3.2.0 34 | ~10.0.0 35 | https://github.com/tomolimo/mailanalyzer/releases/download/3.2.0/mailanalyzer-3.2.0.zip 36 | 37 | 38 | 2.1.0 39 | ~9.5 40 | https://github.com/tomolimo/mailanalyzer/releases/download/2.1.0/mailanalyzer-2.1.0.zip 41 | 42 | 43 | 1.6.5 44 | 9.4 45 | https://github.com/tomolimo/mailanalyzer/releases/download/1.6.5/mailanalyzer-1.6.5.zip 46 | 47 | 48 | 1.5.2 49 | 9.3 50 | 51 | 52 | 1.4.3 53 | 9.2 54 | 55 | 56 | 1.3.8 57 | 9.1 58 | 59 | 60 | 1.2.5 61 | 0.90 62 | 63 | 64 | 1.2.5 65 | 0.85 66 | 67 | 68 | 1.2.5 69 | 0.84 70 | 71 | 72 | 1.2.5 73 | 0.83 74 | 75 | 76 | 77 | Any 78 | 79 | 80 | 81 | 82 | E-mail 83 | E-mailový sběrač 84 | E-mailová brána 85 | 86 | 87 | Mail 88 | Mail collector 89 | Mailgate 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomolimo/mailanalyzer/f09754a0399315d904a2b1ab2013d5e84665dde2/plugin.png -------------------------------------------------------------------------------- /scripts/threadindex.php: -------------------------------------------------------------------------------- 1 | . 26 | -------------------------------------------------------------------------- 27 | */ 28 | 29 | echo bin2hex(substr(base64_decode($argv[1]), 6, 16 )) . "\n"; 30 | -------------------------------------------------------------------------------- /setup.php: -------------------------------------------------------------------------------- 1 | . 26 | -------------------------------------------------------------------------- 27 | */ 28 | 29 | define ("PLUGIN_MAILANALYZER_VERSION", "3.2.2"); 30 | // Minimal GLPI version, inclusive 31 | define('PLUGIN_MAILANALYZER_MIN_GLPI', '10.0.18'); 32 | // Maximum GLPI version, exclusive 33 | define('PLUGIN_MAILANALYZER_MAX_GLPI', '10.1'); 34 | 35 | /** 36 | * Summary of plugin_init_mailanalyzer 37 | * Init the hooks of the plugins 38 | */ 39 | function plugin_init_mailanalyzer() { 40 | 41 | global $PLUGIN_HOOKS; 42 | 43 | Plugin::registerClass('PluginMailAnalyzer'); 44 | 45 | $PLUGIN_HOOKS['csrf_compliant']['mailanalyzer'] = true; 46 | 47 | $PLUGIN_HOOKS['pre_item_add']['mailanalyzer'] = [ 48 | 'Ticket' => ['PluginMailAnalyzer', 'plugin_pre_item_add_mailanalyzer'], 49 | ]; 50 | 51 | $PLUGIN_HOOKS['item_add']['mailanalyzer'] = [ 52 | 'Ticket' => ['PluginMailAnalyzer', 'plugin_item_add_mailanalyzer'] 53 | ]; 54 | 55 | $PLUGIN_HOOKS['item_purge']['mailanalyzer'] = [ 56 | 'Ticket' => ['PluginMailAnalyzer', 'plugin_item_purge_mailanalyzer'] 57 | ]; 58 | 59 | if (Session::haveRightsOr("config", [READ, UPDATE])) { 60 | Plugin::registerClass('PluginMailanalyzerConfig', ['addtabon' => 'Config']); 61 | $PLUGIN_HOOKS['config_page']['mailanalyzer'] = 'front/config.form.php'; 62 | } 63 | 64 | } 65 | 66 | 67 | /** 68 | * Summary of plugin_version_mailanalyzer 69 | * Get the name and the version of the plugin 70 | * @return array 71 | */ 72 | function plugin_version_mailanalyzer() { 73 | return [ 74 | 'name' => __('Mail Analyzer'), 75 | 'version' => PLUGIN_MAILANALYZER_VERSION, 76 | 'author' => 'Olivier Moron', 77 | 'license' => 'GPLv2+', 78 | 'homepage' => 'https://github.com/tomolimo/mailanalyzer', 79 | 'requirements' => [ 80 | 'glpi' => [ 81 | 'min' => PLUGIN_MAILANALYZER_MIN_GLPI, 82 | 'max' => PLUGIN_MAILANALYZER_MAX_GLPI 83 | ] 84 | ] 85 | ]; 86 | } 87 | 88 | 89 | /** 90 | * Summary of plugin_mailanalyzer_check_prerequisites 91 | * check prerequisites before install : may print errors or add to message after redirect 92 | * @return bool 93 | */ 94 | function plugin_mailanalyzer_check_prerequisites() { 95 | if (version_compare(GLPI_VERSION, PLUGIN_MAILANALYZER_MIN_GLPI, 'lt') 96 | && version_compare(GLPI_VERSION, PLUGIN_MAILANALYZER_MAX_GLPI, 'ge')) { 97 | echo "This plugin requires GLPI >= " . PLUGIN_MAILANALYZER_MIN_GLPI ." and < " . PLUGIN_MAILANALYZER_MAX_GLPI; 98 | return false; 99 | } else { 100 | if (!class_exists('mailanalyzer_check_prerequisites')) { 101 | class mailanalyzer_check_prerequisites { public $attr = 'value'; function __toString() { 102 | return 'empty';}}; 103 | } 104 | $loc = new mailanalyzer_check_prerequisites; 105 | $loc2 = Toolbox::addslashes_deep($loc); 106 | if (is_object($loc2) && $loc->attr === $loc2->attr) { 107 | return true; 108 | } else { 109 | echo "This plugin requires upgraded versions of mailcollector.class.php and toolbox.class.php"; 110 | return false; 111 | } 112 | } 113 | } 114 | 115 | 116 | /** 117 | * Summary of plugin_mailanalyzer_check_config 118 | * @return bool 119 | */ 120 | function plugin_mailanalyzer_check_config() { 121 | return true; 122 | } 123 | 124 | --------------------------------------------------------------------------------