'/path/to/tmp',
// IMAP username
'imap_username' => 'user@example.com',
// IMAP password
'imap_password' => 'SecretPassword',
// IMAP server
'imap_hostname' => '{mail.example.com/imap/ssl/novalidate-cert}INBOX',
// bugify API url
'bugify_url' => 'http://bugify.example.com/api/',
// API key of a bugify admin user; used to lookup users.
// the sender's email address will be used to lookup the bugify user creating the ticket,
// but we need an initial API key to lookup the user list
'bugify_api_key' => 'SampleApiKey',
// unique identifier of this project; call Bugify::projects to see a list
'project_id' => 1
*
*
* You could use a cronjob to call a short script like the following:
*
-----------------------------------------------------------
#!/usr/local/bin/php
'/path/to/tmp',
'imap_username' => 'user@example.com',
'imap_password' => 'SecretPassword',
'imap_hostname' => '{mail.example.com/imap/ssl/novalidate-cert}INBOX',
'bugify_url' => 'http://bugify.example.com/api/',
'bugify_api_key' => 'SampleApiKey',
'project_id' => 1
));
-----------------------------------------------------------
*
*
*
* The IMAP code is from https://github.com/gotha/PHP-IMAP-library
*
*
*/
class Bugify
{
private $tmp = '/tmp';
private $inbox;
private $emails;
function __construct($config)
{
foreach ($config as $k => $v)
{
$this->$k = $v;
}
}
/**
* connect to the IMAP server
*
* @access public
* @param string $username
* @param string $password
* @param string $server
* @param int $port
* @param true $ssl
* @return void
*/
function connect()
{
$this->inbox = imap_open($this->imap_hostname, $this->imap_username, $this->imap_password)
or die('Cannot connect to mail server: ' . imap_last_error());
return (bool)$this->inbox;
}
/**
* getMails
*
* @access public
* @param string $type (which mails to be retrieved)
* @param mixed $limit
* @param string int
* @return voi
*/
function getMails($type = false, $limit = null, $order='DESC'){
if (!$this->inbox){
throw new Exception('No IMAP connection established');
}
if ($type == false){
$type = 'ALL';
}
$this->emails = null;
$emails = imap_search($this->inbox, $type);
// set an empty array if we don't have any messages.
// all other functions expect $this->emails to be an array, and Bad Things
// seem to happen if it isn't.
if (! $emails) {
$this->emails = array();
return $this->emails;
}
if (strtoupper($order) == "DESC"){
rsort($emails);
}
if ($limit != null){
/* last|first X emails */
if ((int)$limit !== 0 && !is_array($limit)){
$count = 0;
foreach($emails as $k=>$i){
if ($count <= $limit){
$this->emails[$k] = $i;
} else {
break;
}
$count++;
}
}
/* limit between X and Y */
if (is_array($limit)){
$start = current(array_keys($limit));
$end = current($limit);
foreach($emails as $k=>$i){
if ($k >$start && $k <= $end){
$this->emails[$k] = $i;
}
}
}
} else {
/* all emails */
$this->emails = $emails;
}
return $this->emails;
}
/**
* getMail
*
* @access public
* @param int $email_id
* @return array
*/
function getMail($email_id){
$header = $this->getHeader($email_id);
if (empty($header)){
throw new Exception('Cannot retrieve header');
}
$email = array();
$email['id'] = $email_id;
$email['sender'] = $this->getSender($header);
$email['recipient'] = $this->getRecipient();
$email['subject'] = $this->getSubject($header);
$email['date'] = $header->udate;
$email['body'] = $this->getBody($email_id);
$email['attachments'] = $this->getAttachments($email_id);
return $email;
}
/**
* getOverview
*
* @access public
* @param resource $inbox
* @param int $email_id
* @return void
*/
function getOverview($inbox, $email_id){
$overview = imap_fetch_overview($inbox, $email_id, 0);
return $overview;
}
/**
* getHeader
*
* @access private
* @param int $email_id
* @return object
*/
private function getHeader($email_id){
$header = imap_headerinfo($this->inbox, $email_id);
return $header;
}
/**
* getSender
*
* @access private
* @param object $header
* @return string
*/
private function getSender($header){
$mailbox = $header->from[0]->mailbox;
$host = $header->from[0]->host;
$sender = $mailbox . "@" . $host;
return $sender;
}
/**
* getRecipient
*
* @access private
* @param void
* @return string
*/
private function getRecipient(){
$recipient = $this->username;
return $recipient;
}
/**
* getSubject
*
* @access public
* @param object $header
* @return string
*/
private function getSubject($header){
if (isset($header->subject)){
$subject = $header->subject;
$subject = imap_mime_header_decode($subject);
if (!empty($subject)){
$encoding = $subject[0]->charset;
if ($encoding == "default"){ // i have no idea why
$encoding = "US-ASCII";
}
$text = $subject[0]->text;
$subject_text = iconv($encoding, 'UTF-8', $text);
return $subject_text;
}
}
}
/**
* getBody
*
* @access private
* @param int $email_id
* @return string
*/
private function getBody($email_id){
$structure = imap_fetchstructure($this->inbox, $email_id);
$txt = $this->get_part($this->inbox, $email_id, 'TEXT/PLAIN');
$html = $this->get_part($this->inbox, $email_id, 'TEXT/HTML');
if ($html != ""){
$body = $html;
} else {
$body = str_replace("\n", '
', $txt);
}
echo "RAW TEXT WAS $txt\n";
return $txt;
return $body;
}
/**
* getAttachments
* @author Kevin Steffer
* http://www.linuxscope.net/articles/mailAttachmentsPHP.html
* slightly modified
*
* @access private
* @param int $email_id
* @return array
*/
private function getAttachments($email_id){
$struct = imap_fetchstructure($this->inbox, $email_id);
$contentParts = isset($struct->parts) ? count($struct->parts) : 0;
if ($contentParts >= 2) {
for ($i=2;$i<=$contentParts;$i++) {
$att[$i-2] = imap_bodystruct($this->inbox, $email_id, $i);
}
for ($k=0;$kparameters[0]->value == "us-ascii" || $att[$k]->parameters[0]->value == "US-ASCII") {
if ($att[$k]->parameters[1]->value != "") {
$selectBoxDisplay[$k] = $att[$k]->parameters[1]->value;
}
} elseif ($att[$k]->parameters[0]->value != "iso-8859-1" && $att[$k]->parameters[0]->value != "ISO-8859-1") {
$selectBoxDisplay[$k] = $att[$k]->parameters[0]->value;
}
}
}
if (isset($selectBoxDisplay)){
return $selectBoxDisplay;
}
return false;
}
/**
* getAttachment
*
* @access public
* @param string $file
* @param string $type
* @param int $email_id
* @return res
*/
public function getAttachment($file, $email_id){
// get in which part of the mail is the required attachment
$struct = imap_fetchstructure($this->inbox, $email_id);
$attachment_part = null;
foreach($struct->parts as $part_id => $p){
if (isset($p->parameters[0]->value) && $p->parameters[0]->value == $file){
$attachment_part = $part_id + 1;
}
}
if ($attachment_part == null){
return false;
}
// get attached file
$att = imap_fetchbody($this->inbox, $email_id, $attachment_part);
$att = base64_decode($att);
return $att;
}
/**
* get_mime_type
* @author Kevin Steffer
* http://www.linuxscope.net/articles/mailAttachmentsPHP.html
*
* @access private
* @param resource $structure
* @return string
*/
private function get_mime_type(&$structure) {
$primary_mime_type = array("TEXT", "MULTIPART","MESSAGE", "APPLICATION", "AUDIO","IMAGE", "VIDEO", "OTHER");
if ($structure->subtype) {
return $primary_mime_type[(int) $structure->type] . '/' .$structure->subtype;
}
return "TEXT/PLAIN";
}
/**
* get_part
* @author Kevin Steffer
* http://www.linuxscope.net/articles/mailAttachmentsPHP.html
*
* @access private
* @param resource $stream
* @param int $msg_number
* @param mixed $mime_type
* @param resource $structure
* @param int $part_number
*/
private function get_part($stream, $msg_number, $mime_type, $structure = false, $part_number = false)
{
if (!$structure) {
$structure = imap_fetchstructure($stream, $msg_number);
}
if ($structure) {
if ($mime_type == $this->get_mime_type($structure)) {
if (!$part_number) {
$part_number = "1";
}
$text = imap_fetchbody($stream, $msg_number, $part_number);
if ($structure->encoding == 3) {
return imap_base64($text);
} else if ($structure->encoding == 4) {
return imap_qprint($text);
} else {
return $text;
}
}
$prefix = '';
if ($structure->type == 1) /* multipart */ {
while(list($index, $sub_structure) = each($structure->parts)) {
if ($part_number) {
$prefix = $part_number . '.';
}
$data = $this->get_part($stream, $msg_number, $mime_type, $sub_structure,$prefix . ($index + 1));
if ($data) {
return $data;
}
} // END OF WHILE
} // END OF MULTIPART
} // END OF STRUTURE
return false;
} // END OF FUNCTION
/**
* parse an email message into a new ticket, and mark the message for deletion.
*
*/
private function message_to_ticket($msg)
{
// zap HTML, leaving links in place.
//$msg->body = strip_tags($msg->body, '');
$msg->body = htmlspecialchars($msg->body);
echo "msg body was \n{$msg->body}\n";
$fields = array(
'project' => $this->project_id,
'subject' => $msg->subject,
'description' => $msg->body,
);
if (array_key_exists($msg->sender, $this->users))
{
$user = $this->users[$msg->sender];
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, $user['api_key'].':');
curl_setopt($ch, CURLOPT_URL, $this->bugify_url . 'issues.php');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
$result = unserialize(curl_exec($ch));
$this->ticket_attachment($user, $msg, $result['issue_id']);
imap_delete($this->inbox, $msg->id);
}
}
/**
* add message attachments to the ticket
*/
private function ticket_attachment($user, $msg, $ticket_id)
{
if (! $msg->attachments)
{
return;
}
foreach ($msg->attachments as $i)
{
$tmpfname = $this->tmp . '/' . md5(uniqid(mt_rand())) . '-' . str_replace(' ', '', $i);
$handle = fopen($tmpfname, "w");
fwrite($handle, $this->getAttachment($i, $msg->id));
fclose($handle);
$fields = array(
'attachment[1]' => '@' . $tmpfname,
'method' => 'addattachment',
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, $user['api_key'].':');
curl_setopt($ch, CURLOPT_URL, $this->bugify_url . 'issues/' . $ticket_id . '.php');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
$result = unserialize(curl_exec($ch));
unlink($tmpfname);
}
}
/**
* Retrieve Bugify Users
* set $this->users to a hash mapping email => bugify username
* useful for creating new tickets
*/
public function users()
{
// use the cache if available
if ($this->users)
{
return;
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, $this->bugify_api_key.':');
curl_setopt($ch, CURLOPT_URL, $this->bugify_url . 'users.php');
$result = unserialize(curl_exec($ch));
$this->users = array();
foreach ($result['users'] as $i)
{
$this->users[$i['email']] = array(
'username' => $i['username'],
'api_key' => $i['api_key'],
)
;
}
}
/**
* Check for new messages and convert them into tickets. Delete tickets which
* were successfully converted.
*
*/
public function convert_messages()
{
$this->users();
$this->connect();
$this->getMails();
foreach ($this->emails as $i)
{
$this->message_to_ticket((object) $this->getMail($i));
}
imap_expunge($this->inbox);
}
/**
* convert all email messages into tickets
*/
public static function main($config)
{
$o = new self($config);
$o->convert_messages();
}
/**
* list projects and their IDs
*/
public static function projects($config)
{
$o = new self($config);
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, $o->bugify_api_key.':');
curl_setopt($ch, CURLOPT_URL, $o->bugify_url . 'projects.php');
$result = unserialize(curl_exec($ch));
foreach ($result['projects'] as $i)
{
echo "{$i['id']} => {$i['name']}\n";
}
}
}