Also note that this will support SSL (if you have it set up with your PHP installation) just by putting "ssl:/" in front of the host name and using whatever port number has been assigned - usually 995.You can manually log into an SSL-enabled account using the OpenSSL client available from OpenSSL.org instead of telnet.
At this point, the script does not support Gmail, so don't write to me about that! I have been trying to get it to work and you can definitely log in, but it seems to give inconsistent results and the mail total includes both the inbox and sent folder somehow (which doesn't make sense to me). If anyone out there knows the trick with Gmail, please let me know. I see that there are some PHP classes available for accessing Gmail via IMAP and I will investigate these and post revised code when I can.
So, how does this script work? The script needs to run on a server with the current version of PHP running. This could be a Mac or a Linux/Windows box or it could be running on a remote webserver - assuming you have all the networking and firewall issues dealt with. There is a new project called Yaler that may help with the networking issues if your script is remotely hosted - check it out here. You need to start the script before pressing the "Connect" (or Select) button on the Arduino.
When running, the Preprocessor is a "host" for the requests from the Arduino, but is in turn acting as a "client" to the POP server. It maintains two separate PHP sockets - one to the Arduino and one to the POP server.
Arduino Sends... | Preprocessor returns... |
Arduino connects to IP/port | the ASCII "C" |
N | Current number of emails on the POP server. |
S.x (where x is an integer) | The from/subject information for email number "x" prefixed with MSG. |
D.x (where x is an integer) | Deletes email number "x". |
E | Kills the socket and ends session - currently not implemented. |
The script also provides the following error messages back (although I am not currently using these on the Arduino):
- X.1 - Could not open socket to POP server
- X.2 - Error from server
- X.3 - Authentication failure
- X.4 - Bad connection
I tend to prefer one letter protocols with the Arduino since it simplifies the text handling on the Arduino side.
And, without further ado, here is the code...
<?php /* * PHP Pre-processor script for Arduino POP Mail Manager * * this is the pre-processor script for use with the Arduino email * manager described on my blog. Complete description at: * http://opensourceprojects-torchris.blogspot.com/ * * This script can be used with SSL enabled POP services by putting * "ssl:/" infront of the host name. It does NOT currently work with * GMail POP service. * * This code is in the public domain. Please provide credit if it is used * in another project. * * written by Chris Armour, Arpil 30th, 2010 * */ //=============================IP, Port, User Info=================// //Modify to suit your network. define("HOST_POP", "your.popserver..com"); define("PORT_POP", "110"); define("USER_POP", "user.name"); define("PASS_POP", "YourPassword"); //Server settings $host_ard = "192.168.0.171"; //This is the IP of the server running the script. $port_ard = "12345"; //Port number being used by the Arduino //==========================Functions===================// //GetMailCount grabs the number of emails in the mailbox using the STAT command function GetMailCount() { $fp_pop = fsockopen (HOST_POP, PORT_POP, $errno, $errstr); // if a handle is not returned ob_implicit_flush(); if (!$fp_pop) { echo("Error: could not open socket connection\n"); return("X.1"); } else { // get the welcome message $welcome = fgets ($fp_pop, 150); // check for success code if (substr($welcome, 0, 3) == "+OK") { // send username and read response fputs ($fp_pop, "user " . USER_POP . "\n"); //fgets($fp_pop, 50); // send password and read response fputs ($fp_pop, "pass " . PASS_POP . "\n"); $ack = fgets($fp_pop, 50); // check for success code if (substr($ack, 0, 3) == "+OK") { // send status request and read response fputs ($fp_pop, "STAT\n"); $status = fgets($fp_pop, 50); if (substr($status, 0, 3) == "+OK") { // shut down connection fputs ($fp_pop, "QUIT\n"); fclose ($fp_pop); } // error getting status else { echo ("Error - server said: $status"); return("X.2"); } } // auth failure else { echo ("Error - server said: $ack"); return("X.3"); } } // bad welcome message else { echo ("Error - bad connection string\n"); return("X.4"); } // get status string // split by spaces $arr = explode(" ", $status); // the second element contains the total number of messages echo $arr[3] . " messages in mailbox\n"; $GotMail = $arr[3]; return $GotMail; } } //GetFromSubj grabs the content of the email MailNumber then passes this back to the main loop for extraction of the From & subject //You may need to check the output from your POP3 server using telnet to check on the responses. This seems to vary from POP server to POP //server. function GetFromSubj($MailNumber){ $fp_pop = fsockopen (HOST_POP, PORT_POP, $errno, $errstr); // if a handle is not returned ob_implicit_flush(); if (!$fp_pop) { echo("Error: could not open socket connection\n"); return("X.1"); } else { // get the welcome message $welcome = fgets ($fp_pop, 150); // check for success code if (substr($welcome, 0, 3) == "+OK") { // send username and read response fputs ($fp_pop, "user " . USER_POP . "\n"); fgets($fp_pop); // send password and read response fputs ($fp_pop, "pass " . PASS_POP . "\n"); $ack = fgets($fp_pop); // check for success code if (substr($ack, 0, 3) == "+OK") { // send request for email content & read response fputs ($fp_pop, "retr " . $MailNumber . "\n"); $EmailContent = fread($fp_pop, 4096); // echo $EmailContent; if (substr($EmailContent, 0, 3) == "+OK") { // shut down connection return $EmailContent; fputs ($fp_pop, "QUIT\n"); fclose ($fp_pop); } // error getting status else { echo ("Error - Server said: $EmailContent"); return("X.2"); } } // auth failure else { echo ("Error - Server said: $ack"); return("X.3"); } } // bad welcome message else { echo ("Error - Bad connection string\n"); return("X.4"); } } } //MsgDelete delets message # MailNumber using the dele command function MsgDelete($MailNumber){ $fp_pop = fsockopen (HOST_POP, PORT_POP, $errno, $errstr); // if a handle is not returned ob_implicit_flush(); if (!$fp_pop) { echo("Error: could not open socket connection\n"); return("X.1"); } else { // get the welcome message $welcome = fgets ($fp_pop, 150); // check for success code if (substr($welcome, 0, 3) == "+OK") { // send username and read response fputs ($fp_pop, "user " . USER_POP . "\n"); fgets($fp_pop); // send password and read response fputs ($fp_pop, "pass " . PASS_POP . "\n"); $ack = fgets($fp_pop); // check for success code if (substr($ack, 0, 3) == "+OK") { // send delete command fputs ($fp_pop, "dele " . $MailNumber . "\n"); $DeleteAck = fgets($fp_pop); // echo $EmailContent; if (substr($DeleteAck, 0, 3) == "+OK") { // shut down connection echo ("Message " . $MailNumber . " deleted. \n"); fputs ($fp_pop, "QUIT\n"); fclose ($fp_pop); } // error getting status else { echo ("Error - Server said: $EmailContent"); return ("X.2"); } } // auth failure else { echo ("Error - Server said: $ack"); return("X.3"); } } // bad welcome message else { echo ("Error - Bad connection string\n"); return("X.4"); } } } //=====================Create Socket to listen for Arduino======================// ob_implicit_flush(); //Open socket to listen for Arduino $socket_ard = socket_create(AF_INET, SOCK_STREAM, 0) or die ("Could not bind to socket\n"); $result_ard = socket_bind($socket_ard, $host_ard, $port_ard) or die("Could not bind to socket\n"); // start listening for connections $result_ard = socket_listen($socket_ard, 3) or die("Could not set up socket listener\n"); // accept incoming connections // spawn another socket to handle communication $spawn = socket_accept($socket_ard) or die("Could not accept incoming connection\n"); // read client input socket_write($spawn,"C\n"); echo "Device connected.\n"; //=====================Main Socket loop======================// do { $input = socket_read($spawn, 2048, PHP_NORMAL_READ) or die("Could not read input\n"); echo $input; if (trim($input[0]) == "N" || trim($input[0]) == "S" || trim($input[0]) == "D" || trim($input[0]) == "E" || trim($input[0]) == "\r\n") { //Only do anything if N, S, D or E received. if (trim($input) == "N"){ // This gets the mailcount using the GetMailCount function. $MailCount = GetMailCount(); socket_write($spawn, "Total Number of Messages:" . $MailCount . "@"); } if (trim($input[0]) == "S") { //This gets the from/subject info is an S.num is received. $MsgNum = explode (".",$input); //Use explode to break the info from the Arduino into an array. $MsgNumber = $MsgNum[1]; //Get the Message number from the array. echo ("Value of MsgNumber= " . $MsgNumber . "\n"); $MsgFromSubj = GetFromSubj($MsgNumber); //run the function to get the info from the POP server if ($MsgFromSubj[0] == "X") { //If there's an error, write back the server error text. socket_write($spawn,$MsgFromSubj); } else { $MsgFromLocn = strpos($MsgFromSubj, "From: "); $MsgFromName = substr($MsgFromSubj, ($MsgFromLocn + 6), 14); print ( "MSG". "F:" . $MsgFromName ); $MsgSubjLocn = strpos($MsgFromSubj, "Subject: "); $MsgSubj = substr($MsgFromSubj, ($MsgSubjLocn + 9), 14); echo ("S:" . $MsgSubj ); usleep(20000); socket_write ($spawn, "MSG" . "F:" . $MsgFromName . "S:" . $MsgSubj . "\n"); } } if (trim($input[0]) == "D") { //This sends the command to delete an email. $MsgNum = explode (".",$input); $MsgNumber = $MsgNum[1]; $MsgDelRet = MsgDelete($MsgNumber); if ($MsgDelRet[0] == "X") { socket_write($spawn,$MsgDelRet ."\n"); } else { socket_write($spawn, "D." . $MsgNum[1]); } } if (trim($input) == "E"){ //This isn't actually currently used by the Arduino. socket_shutdown($spawn, 2); usleep(1000); socket_close($spawn); socket_shutdown($socket_ard, 2); usleep(1000); socket_close($socket_ard); echo "Sockets terminated\n"; // break; } } } while(true); ?>
Note that this code does not provide good handling of disconnect/reconnect nor can it handle multiple connections simultaneously. In other words, if the Arduino is reset, then the script needs to be restarted. Also, if multiple connection requests are received, it will just die. If anyone can improve on this, please make the suggestions.
Next up will be the Arduino code!
No comments:
Post a Comment