Content Creation with SMS

The SMSs are sent to an old Ericsson R520 mobile phone which is connected to a Linux box running gsmsmsd from gsmlib. New SMSs are forwarded to Routa MC as emails, which are imported into Midgard using fetchmail and the OpenPSA mail import script

Then the SMSs are handled by a Midgard page which has the following code:

Routa MC Travel Journals
SMS logbook upload handler

Henri Bergius <>

Based on snippet /TechSupport/UI/Handlers/Email-import
from OpenPSA (

2004-06-30: Adapted from the Paska-G:n Sprintti upload handled (bergie)

Each topic to be handled by this system must have parameters
RoutaSMS/number/name set for matching the incoming SMSs to
articles and authors.

If notifications are required, they are handled by adding
parameters in format RoutaSMSsubscribe/name/email to the
root topic.

Note: the mail transfer agent expects to receive uppercase
OK when the mail has been successfully processed. If that is
missing or uppercase ERROR has been transmitted the email
will not be removed from server.

// GUID to the topic where log topics reside
$routasms_topic_guid = "c4b2f1bead1f8a25f4c553ef4fe5a546";

// GUID of article where unrecognized messages are sent or NULL
$routasms_misc_article = null;

// User account for updating log articles
$routasms_username = "USERNAME";
$routasms_password = "PASSWORD";

// SMS receiver email address to remove from messages
$routasms_email_receive = "";

// Whether to enable email notifications
$routasms_notifications_enabled = true;
$routasms_notifications = array();

// Start buffering for the log
echo "=================================================\n";
echo "DEBUG: Started email handling on ".date("Y-m-d H:i",time())."\n";
echo "DEBUG: User-Agent: ".$_SERVER['HTTP_USER_AGENT']."\n";

// Load the log topic
$routasms_topic = mgd_get_object_by_guid($routasms_topic_guid);
echo "DEBUG: Loaded topic ".$routasms_topic->name." (#".$routasms_topic->id.")\n";

// Function for logging the output
function routasms_log() {
$data = ob_get_contents();
//write the contents to a file
$fp = fopen("/tmp/routasms-upload.log","a");
// Output the status

// Don't bother to even initialize anything if we don't have anything to process
if (!$_REQUEST["mailbody"]) {
echo "ERROR: No body received\n";
} else {

// Check that we got the whole email
echo "DEBUG: got body, reported size=".$bodysize."b actual size=".strlen($mailbody)."b\n";
if ($_REQUEST["bodysize"] != strlen($_REQUEST["mailbody"])) {
echo "ERROR: Reported and actual bodysize different, transfer error ?\n";

// Load Mail class from OpenPSA

// Load NemeinRCS revision control script
global $rcsroot;
$rcsroot = $set["rcsroot"];
if (!$rcsroot) {
$rcsroot = "/var/lib/aegir/cvs";
echo "DEBUG: Set revision control root to ".$rcsroot." (got ".$set["rcsroot"]." from Aegir)\n";

// Load NemeinJournal classes

// Authenticate the user if needed
if (!$midgard->user) {
mgd_auth_midgard($routasms_username, $routasms_password, 0);
$midgard = mgd_get_midgard();
if (!$midgard->user) {
echo "ERROR: No user authenticated (or authentication error)\n";
$user = mgd_get_person($midgard->user);
echo "DEBUG: Authenticated user ".$user->name." (#".$midgard->user.")\n";

// Parse the email
$mail=new nemeinnet_mail();
echo "DEBUG: decoded body size ".strlen($mail->body)."b\n";

// Get the sending phone number
preg_match($name_preg, $mail->from, $name_matches);
$routasms_number = preg_replace("/\.|_/", " ", $name_matches[1]);
echo "DEBUG: SMS sent by number ".$routasms_number."\n";

// Get the log message
$routasms_message = $mail->body;

// Remove receiver email address from message
$routasms_message = str_replace($routasms_email_receive." ","",$routasms_message);

// Get the log time
// TODO: read from the email
$routasms_time = time();

// Log article object
$routasms_log = false;

// Name of the sender
$routasms_sender = false;

// Load the log topics
$log_topics = mgd_list_topics($routasms_topic->id);
if ($log_topics) {
while ($log_topics->fetch()) {

// Load phone numbers
$number_params = $log_topics->listparameters("RoutaSMS");
if ($number_params) {
while ($number_params->fetch()) {

// Match with sending number
if ($number_params->name == $routasms_number) {
echo "DEBUG: SMS number matched with topic ".$log_topics->title." (#".$log_topics->id.")\n";
$routasms_sender = $log_topics->parameter("RoutaSMS",$number_params->name);

$routasms_log_topic = mgd_get_topic($log_topics->id);

// Load notification subscriber list
$notification_params = $routasms_log_topic->listparameters("RoutaSMSsubscribe");
if ($notification_params) {
while ($notification_params->fetch()) {
$routasms_notifications[$notification_params->name] = $routasms_log_topic->parameter("RoutaSMSsubscribe",$notification_params->name);
echo "DEBUG: Loaded ".count($routasms_notifications)." notification subscribers\n";

// Check if sender wants to create new entry
if (stristr(substr($routasms_message,0,6),"NEWLOG")) {

// Read the title of the new entry
$routasms_newlog_title = substr($routasms_message,7);
echo "DEBUG: Received NEWLOG command for entry \"".$routasms_newlog_title."\"\n";

// Create new NemeinJournal entry
$routasms_newlog = new journal_entry();
$routasms_newlog->topic = $routasms_log_topic->id;
$routasms_newlog->title = $routasms_newlog_title;
$routasms_newlog_id = $routasms_newlog->save();
if ($routasms_newlog_id) {
echo "DEBUG: Created new NemeinJournal entry #".$routasms_newlog_id."\n";

// Send notifications on the new journal entry
if ($routasms_notifications_enabled && count($routasms_notifications)) {
foreach ($routasms_notifications as $name => $email) {
// Send the notification in format supported by Nemein's SMS gateway
mail('"'.$name.'" <'.$email.'>','New journal entry '.$routasms_log->title.' ('.$routasms_log_topic->name.') was created by '.$routasms_sender,$routasms_log_topic->name.": New entry \"".substr($routasms_message,7)."\"",'From: "'.$routasms_topic->extra.'" <'.$routasms_email_receive.'>');
echo "DEBUG: mailed notification to \"".$name."\" <".$email.">\n";

// Entry has been created, exit
echo "OK\n";
} else {
echo "ERROR: Failed to create NemeinJournal entry, reason ".mgd_errstr()."\n";

} else {
// Fetch the latest log entry article
$log_topics_articles = mgd_list_topic_articles($routasms_log_topic->id);
if ($log_topics_articles) {
if ($log_topics_articles->fetch()) {
echo "DEBUG: Loaded latest NemeinJournal entry #".$log_topics_articles->id."\n";
$routasms_log = new journal_entry($log_topics_articles->id);
} else {
echo "ERROR: No NemeinJournal entries found in topic\n";
// TODO: create empty log item??


} else {
echo "ERROR: No log topics under root topic\n";

// Load the misc article if possible
if (!$routasms_log && $routasms_misc_article) {
echo "DEBUG: SMS number didn't match, loading misc article\n";
$routasms_log = mgd_get_object_by_guid($routasms_misc_article);

// Default to sending number as sender name
if (!$routasms_sender) {
$routasms_sender = $routasms_number;

// Store the message to the log
if ($routasms_log) {
// Start the message block
$routasms_log->content .= "<p>\n";
// Store message
$routasms_log->content .= $routasms_message;
// Store date
$routasms_log->content .= "\n <em>(".date("Y-m-d H:i",$routasms_time);
// Store sender
$routasms_log->content .= " - ".$routasms_sender.")</em>\n";
// End the message block
$routasms_log->content .= "</p>\n";
// Save the log
if (get_class($routasms_log) == "journal_entry") {
// NemeinJournal uses save() method instead of Midgard's standard update()
$status = $routasms_log->save();
} else {
$status = $routasms_log->update();
if ($status) {

// Send notifications on the journal entry update
if ($routasms_notifications_enabled && count($routasms_notifications)) {
foreach ($routasms_notifications as $name => $email) {
// Send the notification in format supported by Nemein's SMS gateway
mail('"'.$name.'" <'.$email.'>','Journal entry '.$routasms_log->title.' ('.$routasms_log_topic->name.') updated by '.$routasms_sender,$routasms_log_topic->name.": ".$routasms_message,'From: "'.$routasms_topic->extra.'" <'.$routasms_email_receive.'>');
echo "DEBUG: mailed notification to \"".$name."\" <".$email.">\n";

// Update revision control information

// Message was saved successfully, say OK
echo "OK\n";

} else {
echo "ERROR: Failed to save log article, reason ".mgd_errstr()."\n";
} else {
echo "ERROR: No log article found\n";
// Log status

The phone has had a tendency to crash, but Rambo is looking to fix that.

Read more Midgard posts.