aboutsummaryrefslogtreecommitdiff
path: root/mail.php
diff options
context:
space:
mode:
authorCamil Staps2020-02-03 09:47:21 +0100
committerCamil Staps2020-02-03 09:47:21 +0100
commit2af4ffce19df7cdb34d4b509a66bc916ffcb88d1 (patch)
tree481bc542d1298e1bcb3e39c107a22b39f13f0395 /mail.php
Initial commit
Diffstat (limited to 'mail.php')
-rw-r--r--mail.php196
1 files changed, 196 insertions, 0 deletions
diff --git a/mail.php b/mail.php
new file mode 100644
index 0000000..6d2d425
--- /dev/null
+++ b/mail.php
@@ -0,0 +1,196 @@
+<?php
+require_once ('config.php');
+require_once ('db.php');
+
+$imap_options=['DISABLE_AUTHENTICATOR' => 'CRAM_MD5'];
+$imap=imap_open (IMAP_CONN,IMAP_USER,IMAP_PASS,NULL,1,$imap_options);
+
+if (!$imap){
+ echo 'IMAP errors:<br/>';
+ foreach (imap_errors() as $err)
+ echo $err.'<br/>';
+ die();
+}
+
+function verify_signature ($data,$sig)
+{
+ $gnupg=gnupg_init();
+ $sig_details=gnupg_verify ($gnupg,$data,$sig);
+ if (!$sig_details)
+ throw new Exception ('signature verification failed');
+
+ $summary=$sig_details[0]['summary'];
+ if ($summary & 0x0004)
+ throw new Exception ('bad signature');
+ if ($summary & 0x0010)
+ throw new Exception ('key has been revoked');
+ if ($summary & 0x0020)
+ throw new Exception ('key has expired');
+ if ($summary & 0x0040)
+ throw new Exception ('signature has expired');
+ if ($summary & 0x0080)
+ throw new Exception ('can\'t verify: key missing');
+ if ($summary!=3)
+ throw new Exception ('unknown signature verification problem ('.$summary.')');
+
+ return $sig_details[0]['fingerprint'];
+}
+
+function mail_fetch_message ($msg)
+{
+ global $imap;
+
+ $guessed_source=null;
+
+ /* Fetch user */
+ $info=imap_headerinfo ($imap,$msg);
+ $from=$info->from[0]->mailbox.'@'.$info->from[0]->host;
+ $user=get_user_by_email ($from);
+
+ /* Guess source */
+ if (strpos (imap_utf8 ($info->subject),'[agade]')!==false)
+ $guessed_source='Agade';
+
+ /* Fetch the multipart tree */
+ $structure=imap_fetchstructure ($imap,$msg);
+ if ($structure->type!=TYPEMULTIPART)
+ throw new Exception ('not a multipart message');
+ if ($structure->subtype!='SIGNED')
+ throw new Exception ('not a signed message');
+
+ /* Find the body and signature */
+ $body_id=null;
+ $sig_id=null;
+ foreach ($structure->parts as $id => $part){
+ if ($part->type==TYPEAPPLICATION && $part->subtype=='PGP-SIGNATURE')
+ $sig_id=$id+1;
+ else
+ $body_id=$id+1;
+ }
+ if (is_null ($sig_id))
+ throw new Exception ('no signature attachment');
+ if (is_null ($body_id))
+ throw new Exception ('no message body');
+
+ /* Get contents */
+ $headers=imap_fetchmime ($imap,$msg,1,FT_INTERNAL | FT_PEEK);
+ $body=imap_fetchbody ($imap,$msg,$body_id,FT_INTERNAL | FT_PEEK);
+ $sig=imap_fetchbody ($imap,$msg,$sig_id,FT_PEEK);
+
+ /* Verify signature */
+ $fpr=verify_signature ($headers.$body,$sig);
+ if ($fpr!=$user['pgp_fingerprint'])
+ throw new Exception ('illegal key used for signature');
+
+ /* Fetch plain-text body */
+ $body_part=$structure->parts[$body_id-1];
+ $plain_body=null;
+ if ($body_part->type==TYPETEXT && $body_part->subtype=='PLAIN'){
+ $plain_body=$body;
+ } else if ($body_part->type==TYPEMULTIPART){
+ foreach ($body_part->parts as $id => $part)
+ if ($part->type==TYPETEXT && $part->subtype=='PLAIN')
+ $plain_body=imap_fetchbody ($imap,$msg,$body_id.'.'.($id+1),FT_PEEK);
+ } else {
+ throw new Exception ('unknown body part type '.$body_part->type);
+ }
+ if (is_null ($plain_body))
+ throw new Exception ('no plain-text body');
+
+ $plain_body=imap_qprint ($plain_body);
+
+ return [
+ 'user' => $user,
+ 'body' => $plain_body,
+ 'guessed_source' => $guessed_source
+ ];
+}
+
+function mail_get_unseen_messages ()
+{
+ global $imap;
+
+ $unseen_msgs=imap_search ($imap,'UNSEEN');
+ if (!$unseen_msgs)
+ $unseen_msgs=[];
+
+ return $unseen_msgs;
+}
+
+function mail_mark_seen ($msg)
+{
+ global $imap;
+ imap_setflag_full ($imap,$msg,'\Seen');
+}
+
+function mail_finish ()
+{
+ global $imap;
+ imap_close ($imap);
+}
+
+function mail_parse_message ($body,$prefill_info=[])
+{
+ $info=[
+ 'title' => null,
+ 'location' => null,
+ 'start_date' => null,
+ 'end_date' => null,
+ 'keywords' => [],
+ 'source' => null,
+ 'description' => null
+ ];
+ $warnings=[];
+
+ foreach ($prefill_info as $key => $val)
+ $info[$key]=$val;
+
+ $lines=explode ("\n",$body);
+ $i=0;
+ foreach ($lines as $line){
+ $i++;
+ if (trim ($line)=='')
+ break;
+
+ $parts=explode (':',$line,2);
+ $key=trim ($parts[0]);
+ $val=trim ($parts[1]);
+
+ switch ($key){
+ case 'Title':
+ $info['title']=$val;
+ break;
+ case 'Location':
+ $info['location']=$val;
+ break;
+ case 'Source':
+ $info['source']=$val;
+ break;
+ case 'Dates':
+ $parts=explode ('to',$val);
+ if (count ($parts)==2){
+ $info['start_date']=trim ($parts[0]);
+ $info['end_date']=trim ($parts[1]);
+ } else {
+ $info['start_date']=$info['end_date']=$val;
+ }
+ break;
+ case 'Keywords':
+ $info['keywords']=array_map ('trim',explode (';',$val));
+ break;
+ default:
+ $warnings[]='Unknown key '.$key;
+ }
+ }
+
+ $info['description']=trim (implode ("\n",array_slice ($lines,$i)));
+
+ foreach (array_keys ($info) as $key)
+ if (is_null ($info[$key]))
+ $warnings[]='No '.$key.' found';
+
+ return [
+ 'info' => $info,
+ 'warnings' => $warnings
+ ];
+}