/** static: import a programme from the given XBMF archive */
 function importXBMF($fileName, $publish = false, $console = false)
 {
     global $db, $config, $permissions, $repository, $vocabularies;
     $pathToFile = $config['xbmfInDir'] . '/';
     // create temp folder with unique name
     $folderName = uniqid("xbmf");
     if (!mkdir($pathToFile . $folderName)) {
         logError("Could not create dir for XBMF", $pathToFile . $folderName);
         return false;
     }
     // untar contents of file to folder
     $tar = new Archive_Tar($fileName, true);
     // create archive handler
     $tar->setErrorHandling(PEAR_ERROR_PRINT);
     // enable error reporting
     $result = $tar->extract($pathToFile . $folderName);
     // untar contents
     debug("untar result", $result);
     //parse the xml file
     $metaFile = $pathToFile . $folderName . "/XBMF/Metadata.xml";
     if (!is_file($metaFile)) {
         $metaFile = $pathToFile . $folderName . "/XBMF/metadata.xml";
         if (!is_file($metaFile)) {
             logError("no metadata file found in XBMF!", $folderName);
             return false;
         }
     }
     $myPack = new unpackXML($metaFile);
     if (!$myPack->error) {
         //if the file has been found
         $metadata = $myPack->process();
     }
     if (!$metadata or $myPack->error) {
         //errors during import - stop execution
         sotf_Utils::delete($pathToFile . $folderName);
         echo "<font color=#FF0000><b>The import of {$fileName} did not succeed!</b></font>";
         logError("XML processing failed within this XBMF", $folderName);
         return false;
         //did not succeed
     } else {
         /*
         echo "Came In: " . $myPack->encoding . "<br>";
         echo "Went Out: " . $myPack->outencoding . "<br>";
         echo "<pre>";
         print_r($metadata);
         echo "</pre>";
         */
         dump($metadata, "METADATA");
         debug("METADATA", $metadata);
     }
     $db->begin();
     // Select station
     $stId = trim($metadata['stationid']);
     if (is_numeric($stId)) {
         $stId = $newPrg->makeId($config['nodeId'], 'sotf_stations', (int) $stId);
     }
     $station =& $repository->getObject($stId);
     if (!$station) {
         logError("invalid stationid: " . $metadata['stationid']);
         return false;
         // by default I put the programme into the first station
         //$stId = $db->getOne("SELECT id FROM sotf_stations ORDER BY id");
         //$station = &$repository->getObject($stId);
     }
     // select/create programme entry
     if ($metadata['identifier']) {
         $prgId = sotf_Programme::getMapping($station->id, $metadata['identifier'], 'prg');
     }
     if ($prgId) {
         // updating an exisiting programme
         debug("updating existing programme", $prgId);
         $newPrg = new sotf_Programme($prgId);
         if ($station->id != $newPrg->get('station_id')) {
             logError("station provided in metadata is different from the station saved previously!");
             return false;
         }
         //$station = &$repository->getObject($newPrg->get('station_id'));
         $updatingPrg = 1;
     } else {
         // a new programme
         $newPrg = new sotf_Programme();
         $track = $metadata['title'];
         debug("create new programme with track", $track);
         $newPrg->create($station->id, $track);
         sotf_Programme::addMapping($station->id, $metadata['identifier'], 'prg', $newPrg->id);
     }
     $newPrg->set('foreign_id', $metadata['identifier']);
     // select/create series
     if ($metadata['series'] && $metadata['series']['id']) {
         $seriesId = sotf_Programme::getMapping($station->id, $metadata['series']['id'], 'series');
         if (!$seriesId) {
             $series1 = new sotf_Series();
             $series1->set('name', $metadata['series']['title']);
             $series1->set('station_id', $station->id);
             $series1->find();
             if ($series1->exists()) {
                 $seriesId = $series1->id;
             }
         }
         if ($seriesId) {
             $newPrg->set('series_id', $seriesId);
             $series =& $repository->getObject($seriesId);
         } else {
             $newSeries = 1;
             $series = new sotf_Series();
             $series->set('station_id', $station->id);
         }
         $series->set('name', $metadata['series']['title']);
         $series->set('description', $metadata['series']['description']);
         if ($series->exists()) {
             $series->update();
         } else {
             $series->create();
             sotf_Programme::addMapping($station->id, $metadata['series']['id'], 'series', $series->id);
         }
     }
     // permissions
     foreach (array($metadata['owner'], $metadata['publishedby']) as $foreignUser) {
         if (is_array($foreignUser)) {
             $userId = sotf_User::getUserid($foreignUser['login']);
             debug("owner/publisher", $foreignUser);
             if ($userId) {
                 if ($permissions->hasPermission($station->id, 'admin', $userId) || $series && $permissions->hasPermission($series->id, 'create', $userId)) {
                     // add permission for user
                     $permissions->addPermission($newPrg->id, $userId, 'admin');
                     $admins[] = $userId;
                 }
             }
         }
     }
     // if we did not get permission info, add permissions for all station/series admins
     debug("admins2", $admins);
     if (empty($admins)) {
         if ($series) {
             $admins1 = $permissions->listUsersWithPermission($series->id, 'admin');
         }
         if (!$admins1) {
             $admins1 = $permissions->listUsersWithPermission($station->id, 'admin');
         }
         while (list(, $admin) = each($admins1)) {
             $admins[] = $admin['id'];
             $permissions->addPermission($newPrg->id, $admin['id'], 'admin');
         }
     }
     debug("admins3", $admins);
     // now create permissions
     while (list(, $adminId) = each($admins)) {
         $permissions->addPermission($newPrg->id, $adminId, 'admin');
         if ($newSeries) {
             $permissions->addPermission($series->id, $adminId, 'admin');
         }
     }
     /*
      * PART 2.2 - Insert all the relevant data from the xml file into the database
      */
     // basic metadata
     $newPrg->set('title', sotf_Programme::normalizeText($metadata['title'], 255));
     $newPrg->set('alternative_title', sotf_Programme::normalizeText($metadata['alternative'], 255));
     $newPrg->set('episode_sequence', 0);
     if (!empty($metadata['episodesequence'])) {
         $epiSeq = sotf_Programme::normalizeText($metadata['episodesequence']);
         if (is_numeric($epiSeq)) {
             $newPrg->set('episode_sequence', (int) $epiSeq);
         } else {
             logError("Bad episode sequence: " . $metadata['episodesequence']);
         }
     }
     $newPrg->set('abstract', sotf_Programme::normalizeText($metadata['description']));
     $newPrg->set('keywords', sotf_Programme::normalizeText($metadata['keywords']));
     $newPrg->set("production_date", date('Y-m-d', strtotime($metadata['created'])));
     $newPrg->set("broadcast_date", date('Y-m-d', strtotime($metadata['issued'])));
     $newPrg->set("modify_date", date('Y-m-d', strtotime($metadata['modified'])));
     $newPrg->set('language', $metadata['language']);
     if ($metadata['language'] == 'ger') {
         $newPrg->set('language', 'deu');
     }
     if ($metadata['language'] == 'English') {
         $newPrg->set('language', 'eng');
     }
     $newPrg->update();
     // topic
     if ($metadata['topic']) {
         $vocabularies->addToTopic($newPrg->id, $metadata['topic']);
     }
     // genre
     $genre = trim($metadata['genre']);
     if (is_numeric($genre)) {
         $newPrg->set('genre_id', $genre);
     } else {
         logError("invalid genre id: " . $genre);
     }
     // rights
     $rights = new sotf_NodeObject("sotf_rights");
     $rights->set('prog_id', $newPrg->id);
     $rights->set('rights_text', $metadata['rights']);
     $rights->find();
     $rights->save();
     $db->commit();
     // contacts
     //$role = 21; // Other
     foreach ($metadata['publisher'] as $contact) {
         $role = 23;
         // Publisher
         $id = sotf_Programme::importContact($contact, $role, $newPrg->id, $station->id, $admins);
     }
     foreach ($metadata['creator'] as $contact) {
         $role = 22;
         // Creator
         $id = sotf_Programme::importContact($contact, $role, $newPrg->id, $station->id, $admins);
     }
     if (is_array($metadata['contributor'])) {
         foreach ($metadata['contributor'] as $contact) {
             $role = 24;
             // Contributor
             $id = sotf_Programme::importContact($contact, $role, $newPrg->id, $station->id, $admins);
         }
     }
     /*
      * PART 2.1 - Move the audio data to the specified station folder
      */
     // insert audio
     $dirPath = $pathToFile . $folderName . "/XBMF/audio";
     $dir = dir($dirPath);
     while ($entry = $dir->read()) {
         if ($entry != "." && $entry != "..") {
             $currentFile = $dirPath . "/" . $entry;
             if (!is_dir($currentFile)) {
                 if (is_file($currentFile)) {
                     debug("insert audio", $currentFile);
                     $newPrg->setAudio($currentFile, true);
                 }
             }
         }
     }
     $dir->close();
     // insert other files
     $dirPath = $pathToFile . $folderName . "/XBMF/files";
     $dir = dir($dirPath);
     while ($entry = $dir->read()) {
         if ($entry != "." && $entry != "..") {
             $currentFile = $dirPath . "/" . $entry;
             if (!is_dir($currentFile)) {
                 $id = $newPrg->setOtherFile($currentFile, true);
                 debug("insert other", $currentFile);
                 /* by default, no need for this
                 		 if($id) {
                 			$fileInfo = &$repository->getObject($id);
                 			$fileInfo->set('public_access', 't');
                 			$fileInfo->update();
                 		 }
                 		 */
             }
         }
     }
     $dir->close();
     // insert metadata
     if (is_readable($metaFile)) {
         debug("insert meta", $metaFile);
         $target1 = $newPrg->getMetaDir() . '/metadata.xml';
         $target2 = $newPrg->getMetaDir() . '/metadata-in.xml';
         if (!copy($metaFile, $target1)) {
             logError("Could not copy metadata into {$target1}");
         }
         if (!copy($metaFile, $target2)) {
             logError("Could not copy metadata into {$target2}");
         }
     }
     // insert icon
     $logoFile = $pathToFile . $folderName . "/icon.png";
     if (is_readable($logoFile)) {
         debug("insert icon", $logoFile);
         $newPrg->setIcon($logoFile);
     }
     // convert missing formats!
     $audioFiles =& new sotf_FileList();
     $audioFiles->getAudioFromDir($newPrg->getAudioDir());
     $checker =& new sotf_AudioCheck($audioFiles);
     $checker->console = $console;
     // if we don't want progress bars
     $targets = $checker->convertAll($newPrg->id);
     if (is_array($targets)) {
         foreach ($targets as $target) {
             $newPrg->setAudio($target);
         }
     }
     /*
      * PART 2.3 - Remove (unlink) the xbmf file and the temp dir
      */
     //publish if needed
     if ($publish) {
         $newPrg->publish();
     }
     sotf_Utils::delete($pathToFile . $folderName);
     //unlink($fileName);
     return $newPrg->id;
 }
 function importTopicTree($lines, $language)
 {
     debug("START import topic tree", $language);
     // read in topic tree definition
     reset($lines);
     $more = true;
     while ($more) {
         $line = array_shift($lines);
         if (preg_match('/^\\s*$/', $line) || preg_match('/^#/', $line)) {
             $more = false;
         } else {
             if (preg_match('/^\\s*([\\w_]+)\\s*=\\s*(.*)/', $line, $items)) {
                 $treedata[$items[1]] = trim($items[2]);
             } else {
                 logError("Bad line: {$line}");
             }
         }
     }
     debug("tree data", $treedata);
     if (!$treedata['tree_id'] || !$treedata['name']) {
         raiseError("bad topic tree definition");
     }
     $treeId = $treedata['tree_id'];
     // create tree def
     $td =& new sotf_NodeObject("sotf_topic_trees");
     $td->setID(sotf_NodeObject::makeId($treeId, $td->tablename, 0));
     $td->find();
     $td->set('tree_id', $treeId);
     $td->set('name', $treedata['shortname']);
     if ($td->exists()) {
         $langs = $td->get('languages');
         if (strpos($langs, $language) === FALSE) {
             $td->set('languages', $langs . ",{$language}");
             $td->update();
         }
     } else {
         $td->set('languages', $language);
         $td->create();
     }
     // create root description
     $x = new sotf_NodeObject("sotf_topic_tree_defs");
     $x->setID(sotf_NodeObject::makeId($treeId, $x->tablename, 0));
     $x->find();
     if (!$x->exists()) {
         $x->set('supertopic', 0);
         $x->set('name', $treedata['name']);
         $x->set('tree_id', $treeId);
         $x->create();
     }
     $rootId = $x->getID();
     // create root translation
     $y = new sotf_NodeObject("sotf_topics");
     $y->setID(sotf_NodeObject::makeId($treeId, $y->tablename, '0' . $language));
     $y->find();
     if (!$y->exists()) {
         $y->set('topic_id', $rootId);
         $y->set('language', $language);
         $y->set('topic_name', $treedata['name']);
         $y->set('description', $treedata['description']);
         $y->create();
     }
     $parentId = $rootId;
     $prevId = $rootId;
     $level = 0;
     reset($lines);
     while (list(, $line) = each($lines)) {
         if (preg_match('/^\\s*$/', $line) || preg_match('/^#/', $line)) {
             continue;
         }
         if (!preg_match('/^\\s*(\\d+)\\s+(\\d+)\\s+(.*)/', $line, $items)) {
             logError("bad line syntax: {$line}");
             continue;
         }
         //$items = preg_split('/\s+/', $line, PREG_SPLIT_NO_EMPTY);
         debug("tree items", $items);
         $id = $items[1];
         $l = $items[2];
         $name = trim($items[3]);
         if ($level < $l) {
             $roots[] = $parentId;
             $parentId = $prevId;
         }
         if ($level > $l) {
             $parentId = array_pop($roots);
         }
         $level = $l;
         debug("", "LEVEL: {$level}, PARENT: {$parentId}, ROOTS: " . join(",", $roots));
         $x = new sotf_NodeObject("sotf_topic_tree_defs");
         $x->setID(sotf_NodeObject::makeId($treeId, $x->tablename, $id));
         $x->find();
         if (!$x->exists()) {
             $x->set('supertopic', $parentId);
             $x->set('name', $name);
             $x->set('tree_id', $treeId);
             $x->create();
         }
         $tid = $x->getID();
         $y = new sotf_NodeObject("sotf_topics");
         $y->setID(sotf_NodeObject::makeId($treeId, $y->tablename, $id . $language));
         //$y->find();
         $y->set('topic_id', $tid);
         $y->set('language', $language);
         $y->set('topic_name', $name);
         $y->create();
         $prevId = $tid;
     }
     debug("END import topic tree", $language);
 }
 function processPortalEvent($event)
 {
     debug("processing event", $event);
     $progId = $event['prog_id'];
     if ($progId) {
         if ($this->looksLikeId($progId)) {
             $prg =& $this->getObject($progId);
         }
         if (!$prg) {
             debug("Invalid prog_id arrived in portal event", $progId);
             return -1;
         }
     }
     switch ($event['name']) {
         case 'programme_added':
             $obj = new sotf_NodeObject('sotf_prog_refs');
             $obj->set('prog_id', $event['value']);
             $obj->set('url', $event['url']);
             $obj->find();
             $obj->set('station_id', $prg->get('station_id'));
             $obj->set('start_date', $event['timestamp']);
             $obj->set('portal_name', $event['portal_name']);
             $obj->save();
             break;
         case 'programme_deleted':
             $obj = new sotf_NodeObject('sotf_prog_refs');
             $obj->set('prog_id', $event['value']);
             $obj->set('url', $event['url']);
             $obj->find();
             if (!$obj->exists()) {
                 debug("unknown prog ref arrives: " . $event['value'] . ' - ' . $event['url']);
                 $obj->set('portal_name', $event['portal_name']);
             }
             $obj->set('station_id', $prg->get('station_id'));
             $obj->set('end_date', $event['timestamp']);
             //$obj->set('portal_name', $event['portal_name']);
             $obj->save();
             break;
         case 'visit':
             $obj = new sotf_NodeObject('sotf_prog_refs');
             $obj->set('prog_id', $event['value']['prog_id']);
             $obj->set('url', $event['url']);
             $obj->find();
             if (!$obj->exists()) {
                 // TODO: how can this happen? It happens too many times!
                 debug("unknown prog ref arrives: " . $event['value']['prog_id'] . ' - ' . $event['url']);
                 $obj->set('start_date', $event['timestamp']);
                 $obj->set('portal_name', $event['portal_name']);
             }
             $obj->set('station_id', $prg->get('station_id'));
             $obj->set('visits', (int) $obj->get('visits') + 1);
             // TODO: count unique accesses
             $obj->save();
             break;
         case 'page_impression':
             $obj = new sotf_NodeObject('sotf_portals');
             $obj->set('url', $event['url']);
             $obj->find();
             $obj->set('name', $event['portal_name']);
             $obj->set('page_impression', $event['value']);
             $obj->set('last_access', $event['timestamp']);
             $obj->save();
             break;
         case 'portal_updated':
             $obj = new sotf_NodeObject('sotf_portals');
             $obj->set('url', $event['url']);
             $obj->find();
             $obj->set('name', $event['portal_name']);
             $obj->set('last_update', $event['timestamp']);
             $obj->save();
             break;
         case 'users':
             $obj = new sotf_NodeObject('sotf_portals');
             $obj->set('url', $event['url']);
             $obj->find();
             if (!$obj->exists()) {
                 $obj->set('name', $event['portal_name']);
             }
             $obj->set('last_update', $event['timestamp']);
             $obj->set('reg_users', $event['value']);
             if (!$obj->get('name') || !$obj->get('url')) {
                 logError("Bad portal even teceived", implode(" | ", $event));
             } else {
                 $obj->save();
             }
             break;
         case 'rating':
             // first save in prog_refs
             $obj = new sotf_NodeObject('sotf_prog_refs');
             $obj->set('prog_id', $event['value']['prog_id']);
             $obj->set('url', $event['url']);
             $obj->find();
             if (!$obj->exists()) {
                 debug("unknown prog ref arrives: " . $event['url']);
                 $obj->set('start_date', $event['timestamp']);
                 $obj->set('portal_name', $event['portal_name']);
             }
             $obj->set('station_id', $prg->get('station_id'));
             $obj->set('rating', $event['value']['RATING_VALUE']);
             $obj->set('raters', $event['value']['RATING_COUNT']);
             $obj->save();
             // TODO second, put into global rating database
             /*
             $rating = new sotf_Rating();
             $id = $event['value']['prog_id'];
             $obj = & $this->getObject($id);
             if($obj->isLocal()) {
               $data = $event['value'];
               $rating->setRemoteRating($data);
             } else {
               logError("received rating for non-local object!");
             }
             */
             break;
         case 'comment':
             // first save in prog_refs
             $obj = new sotf_NodeObject('sotf_prog_refs');
             $obj->set('prog_id', $event['value']['prog_id']);
             $obj->set('url', $event['url']);
             $obj->find();
             if (!$obj->exists()) {
                 logError("unknown prog ref arrives: " . $event['value']['prog_id'] . ' - ' . $event['url']);
                 $obj->set('start_date', $event['timestamp']);
                 $obj->set('portal_name', $event['portal_name']);
             }
             $obj->set('station_id', $prg->get('station_id'));
             $obj->set('comments', (int) $obj->get('comments') + 1);
             $obj->save();
             // save comment
             $obj = new sotf_Object('sotf_comments');
             $obj->set('prog_id', $event['value']['prog_id']);
             $obj->set('portal', $event['url']);
             $obj->set('entered', $event['timestamp']);
             $obj->set('comment_title', $event['value']['title']);
             $obj->set('comment_text', $event['value']['comment']);
             $obj->set('from_name', $event['value']['user_name']);
             $obj->set('from_email', $event['value']['email']);
             $obj->create();
             // TODO forward to authors
             break;
         case 'query_added':
             //debug("query from portal", $event);
         //debug("query from portal", $event);
         case 'query_deleted':
         case 'file_uploaded':
             // silently ignored
             break;
         default:
             logError("unknown portal event: " . $event['name']);
     }
 }