00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00031
00032 #ifdef HAVE_CONFIG_H
00033 #include "autoconfig.h"
00034 #endif
00035
00036 #include <stdio.h>
00037 #include "uuid/uuid.h"
00038 #include "common.h"
00039 #include "config_manager.h"
00040 #include "storage.h"
00041 #include <sys/types.h>
00042 #include <sys/stat.h>
00043 #include "tools.h"
00044 #include "string_converter.h"
00045 #include "metadata_handler.h"
00046
00047 #ifdef HAVE_INOTIFY
00048 #include "mt_inotify.h"
00049 #endif
00050
00051 #ifdef YOUTUBE
00052 #include "youtube_service.h"
00053 #endif
00054
00055 #ifdef WEBORAMA
00056 #include "weborama_service.h"
00057 #endif
00058
00059 #if defined(HAVE_LANGINFO_H) && defined(HAVE_LOCALE_H)
00060 #include <langinfo.h>
00061 #include <locale.h>
00062 #endif
00063
00064 #ifdef HAVE_CURL
00065 #include <curl/curl.h>
00066 #endif
00067
00068 using namespace zmm;
00069 using namespace mxml;
00070
00071 SINGLETON_MUTEX(ConfigManager, false);
00072
00073 String ConfigManager::filename = nil;
00074 String ConfigManager::userhome = nil;
00075 String ConfigManager::config_dir = _(DEFAULT_CONFIG_HOME);
00076 String ConfigManager::prefix_dir = _(PACKAGE_DATADIR);
00077 String ConfigManager::magic = nil;
00078 bool ConfigManager::debug_logging = false;
00079
00080 ConfigManager::~ConfigManager()
00081 {
00082 filename = nil;
00083 userhome = nil;
00084 config_dir = _(DEFAULT_CONFIG_HOME);
00085 prefix_dir = _(PACKAGE_DATADIR);
00086 magic = nil;
00087 }
00088
00089 void ConfigManager::setStaticArgs(String _filename, String _userhome,
00090 String _config_dir, String _prefix_dir,
00091 String _magic, bool _debug_logging)
00092 {
00093 filename = _filename;
00094 userhome = _userhome;
00095 config_dir = _config_dir;
00096 prefix_dir = _prefix_dir;
00097 magic = _magic;
00098 debug_logging = _debug_logging;
00099 }
00100
00101 ConfigManager::ConfigManager() : Singleton<ConfigManager>()
00102 {
00103 options = Ref<Array<ConfigOption> > (new Array<ConfigOption>(CFG_MAX));
00104
00105 String home = userhome + DIR_SEPARATOR + config_dir;
00106 bool home_ok = true;
00107
00108 if (filename == nil)
00109 {
00110
00111 if (home_ok && (!check_path(userhome + DIR_SEPARATOR + config_dir + DIR_SEPARATOR + DEFAULT_CONFIG_NAME)))
00112 {
00113 home_ok = false;
00114 }
00115 else
00116 {
00117 filename = home + DIR_SEPARATOR + DEFAULT_CONFIG_NAME;
00118 }
00119
00120 if ((!home_ok) && (string_ok(userhome)))
00121 {
00122 userhome = normalizePath(userhome);
00123 filename = createDefaultConfig(userhome);
00124 }
00125
00126 }
00127
00128 if (filename == nil)
00129 {
00130 throw _Exception(_("\nThe server configuration file could not be found in ~/.mediatomb\n") +
00131 "MediaTomb could not determine your home directory - automatic setup failed.\n" +
00132 "Try specifying an alternative configuration file on the command line.\n" +
00133 "For a list of options run: mediatomb -h\n");
00134 }
00135
00136 log_info("Loading configuration from: %s\n", filename.c_str());
00137 load(filename);
00138
00139 prepare_udn();
00140 validate(home);
00141 #ifdef TOMBDEBUG
00142
00143 #endif
00144
00145 root = nil;
00146 }
00147
00148 String ConfigManager::construct_path(String path)
00149 {
00150 String home = getOption(CFG_SERVER_HOME);
00151
00152 if (path.charAt(0) == '/')
00153 return path;
00154 #if defined(__CYGWIN__)
00155
00156 if ((path.length() > 1) && (path.charAt(1) == ':'))
00157 return path;
00158 #endif
00159 if (home == "." && path.charAt(0) == '.')
00160 return path;
00161
00162 if (home == "")
00163 return _(".") + DIR_SEPARATOR + path;
00164 else
00165 return home + DIR_SEPARATOR + path;
00166 }
00167
00168 Ref<Element> ConfigManager::map_from_to(String from, String to)
00169 {
00170 Ref<Element> map(new Element(_("map")));
00171 map->setAttribute(_("from"), from);
00172 map->setAttribute(_("to"), to);
00173 return map;
00174 }
00175
00176 Ref<Element> ConfigManager::treat_as(String mimetype, String as)
00177 {
00178 Ref<Element> treat(new Element(_("treat")));
00179 treat->setAttribute(_("mimetype"), mimetype);
00180 treat->setAttribute(_("as"), as);
00181 return treat;
00182 }
00183
00184 #ifdef EXTERNAL_TRANSCODING
00185 Ref<Element> ConfigManager::renderTranscodingSection()
00186 {
00187 Ref<Element> transcoding(new Element(_("transcoding")));
00188 transcoding->setAttribute(_("enabled"), _(DEFAULT_TRANSCODING_ENABLED));
00189
00190 Ref<Element> mt_prof_map(new Element(_("mimetype-profile-mappings")));
00191
00192 Ref<Element> prof_flv(new Element(_("transcode")));
00193 prof_flv->setAttribute(_("mimetype"), _("video/x-flv"));
00194 prof_flv->setAttribute(_("using"), _("vlcmpeg"));
00195
00196 mt_prof_map->appendElementChild(prof_flv);
00197
00198 Ref<Element> prof_theora(new Element(_("transcode")));
00199 prof_theora->setAttribute(_("mimetype"), _("application/ogg"));
00200 prof_theora->setAttribute(_("using"), _("vlcmpeg"));
00201 mt_prof_map->appendElementChild(prof_theora);
00202
00203 Ref<Element> prof_ogg(new Element(_("transcode")));
00204 prof_ogg->setAttribute(_("mimetype"), _("application/ogg"));
00205 prof_ogg->setAttribute(_("using"), _("oggflac2raw"));
00206 mt_prof_map->appendElementChild(prof_ogg);
00207
00208 Ref<Element> prof_flac(new Element(_("transcode")));
00209 prof_flac->setAttribute(_("mimetype"), _("audio/x-flac"));
00210 prof_flac->setAttribute(_("using"), _("oggflac2raw"));
00211 mt_prof_map->appendElementChild(prof_flac);
00212
00213 transcoding->appendElementChild(mt_prof_map);
00214
00215 Ref<Element> profiles(new Element(_("profiles")));
00216
00217 Ref<Element> oggflac(new Element(_("profile")));
00218 oggflac->setAttribute(_("name"), _("oggflac2raw"));
00219 oggflac->setAttribute(_("enabled"), _(NO));
00220 oggflac->setAttribute(_("type"), _("external"));
00221
00222 oggflac->appendTextChild(_("mimetype"), _("audio/L16"));
00223 oggflac->appendTextChild(_("accept-url"), _(NO));
00224 oggflac->appendTextChild(_("first-resource"), _(YES));
00225 oggflac->appendTextChild(_("accept-ogg-theora"), _(NO));
00226
00227 Ref<Element> oggflac_agent(new Element(_("agent")));
00228 oggflac_agent->setAttribute(_("command"), _("ogg123"));
00229 oggflac_agent->setAttribute(_("arguments"), _("-d raw -o byteorder:big -f %out %in"));
00230 oggflac->appendElementChild(oggflac_agent);
00231
00232 Ref<Element> oggflac_buffer(new Element(_("buffer")));
00233 oggflac_buffer->setAttribute(_("size"),
00234 String::from(DEFAULT_AUDIO_BUFFER_SIZE));
00235 oggflac_buffer->setAttribute(_("chunk-size"),
00236 String::from(DEFAULT_AUDIO_CHUNK_SIZE));
00237 oggflac_buffer->setAttribute(_("fill-size"),
00238 String::from(DEFAULT_AUDIO_FILL_SIZE));
00239 oggflac->appendElementChild(oggflac_buffer);
00240
00241 profiles->appendElementChild(oggflac);
00242
00243 Ref<Element> vlcmpeg(new Element(_("profile")));
00244 vlcmpeg->setAttribute(_("name"), _("vlcmpeg"));
00245 vlcmpeg->setAttribute(_("enabled"), _(NO));
00246 vlcmpeg->setAttribute(_("type"), _("external"));
00247
00248 vlcmpeg->appendTextChild(_("mimetype"), _("video/mpeg"));
00249 vlcmpeg->appendTextChild(_("accept-url"), _(YES));
00250 vlcmpeg->appendTextChild(_("first-resource"), _(YES));
00251 vlcmpeg->appendTextChild(_("accept-ogg-theora"), _(YES));
00252
00253 Ref<Element> vlcmpeg_agent(new Element(_("agent")));
00254 vlcmpeg_agent->setAttribute(_("command"), _("vlc"));
00255 vlcmpeg_agent->setAttribute(_("arguments"), _("-I dummy %in --sout #transcode{venc=ffmpeg,vcodec=mp2v,vb=4096,fps=25,aenc=ffmpeg,acodec=mpga,ab=192,samplerate=44100,channels=2}:standard{access=file,mux=ps,dst=%out} vlc:quit"));
00256 vlcmpeg->appendElementChild(vlcmpeg_agent);
00257
00258 Ref<Element> vlcmpeg_buffer(new Element(_("buffer")));
00259 vlcmpeg_buffer->setAttribute(_("size"),
00260 String::from(DEFAULT_VIDEO_BUFFER_SIZE));
00261 vlcmpeg_buffer->setAttribute(_("chunk-size"),
00262 String::from(DEFAULT_VIDEO_CHUNK_SIZE));
00263 vlcmpeg_buffer->setAttribute(_("fill-size"),
00264 String::from(DEFAULT_VIDEO_FILL_SIZE));
00265 vlcmpeg->appendElementChild(vlcmpeg_buffer);
00266
00267 profiles->appendElementChild(vlcmpeg);
00268
00269 transcoding->appendElementChild(profiles);
00270
00271 return transcoding;
00272 }
00273 #endif
00274
00275 Ref<Element> ConfigManager::renderExtendedRuntimeSection()
00276 {
00277 Ref<Element> extended(new Element(_("extended-runtime-options")));
00278 #if defined(HAVE_FFMPEG) && defined(HAVE_FFMPEGTHUMBNAILER)
00279 Ref<Element> ffth(new Element(_("ffmpegthumbnailer")));
00280 ffth->setAttribute(_("enabled"), _(DEFAULT_FFMPEGTHUMBNAILER_ENABLED));
00281
00282 ffth->appendTextChild(_("thumbnail-size"),
00283 String::from(DEFAULT_FFMPEGTHUMBNAILER_THUMBSIZE));
00284 ffth->appendTextChild(_("seek-percentage"),
00285 String::from(DEFAULT_FFMPEGTHUMBNAILER_SEEK_PERCENTAGE));
00286 ffth->appendTextChild(_("filmstrip-overlay"),
00287 _(DEFAULT_FFMPEGTHUMBNAILER_FILMSTRIP_OVERLAY));
00288 ffth->appendTextChild(_("workaround-bugs"),
00289 _(DEFAULT_FFMPEGTHUMBNAILER_WORKAROUND_BUGS));
00290 ffth->appendTextChild(_("image-quality"),
00291 String::from(DEFAULT_FFMPEGTHUMBNAILER_IMAGE_QUALITY));
00292
00293 extended->appendElementChild(ffth);
00294 #endif
00295
00296 Ref<Element> mark(new Element(_("mark-played-items")));
00297 mark->setAttribute(_("enabled"), _(DEFAULT_MARK_PLAYED_ITEMS_ENABLED));
00298 mark->setAttribute(_("suppress-cds-updates"),
00299 _(DEFAULT_MARK_PLAYED_ITEMS_SUPPRESS_CDS_UPDATES));
00300 Ref<Element> mark_string(new Element(_("string")));
00301 mark_string->setAttribute(_("mode"),
00302 _(DEFAULT_MARK_PLAYED_ITEMS_STRING_MODE));
00303 mark_string->setText(_(DEFAULT_MARK_PLAYED_ITEMS_STRING));
00304 mark->appendElementChild(mark_string);
00305
00306 Ref<Element> mark_content_section(new Element(_("mark")));
00307 Ref<Element> content_video(new Element(_("content")));
00308 content_video->setText(_(DEFAULT_MARK_PLAYED_CONTENT_VIDEO));
00309 mark_content_section->appendElementChild(content_video);
00310 mark->appendElementChild(mark_content_section);
00311 extended->appendElementChild(mark);
00312
00313 #ifdef HAVE_LASTFMLIB
00314 Ref<Element> lastfm(new Element(_("lastfm")));
00315 lastfm->setAttribute(_("enabled"), _(DEFAULT_LASTFM_ENABLED));
00316 lastfm->appendTextChild(_("username"), _(DEFAULT_LASTFM_USERNAME));
00317 lastfm->appendTextChild(_("password"), _(DEFAULT_LASTFM_PASSWORD));
00318 extended->appendElementChild(lastfm);
00319 #endif
00320
00321 return extended;
00322 }
00323
00324 #ifdef ONLINE_SERVICES
00325 Ref<Element> ConfigManager::renderOnlineSection()
00326 {
00327 Ref<Element> onlinecontent(new Element(_("online-content")));
00328 #ifdef YOUTUBE
00329
00330
00331
00332 Ref<Element> yt(new Element(_("YouTube")));
00333 yt->setAttribute(_("enabled"), _(DEFAULT_YOUTUBE_ENABLED));
00334
00335 yt->setAttribute(_("refresh"), String::from(DEFAULT_YOUTUBE_REFRESH));
00336 yt->setAttribute(_("update-at-start"), _(DEFAULT_YOUTUBE_UPDATE_AT_START));
00337
00338 yt->setAttribute(_("purge-after"),
00339 String::from(DEFAULT_YOUTUBE_PURGE_AFTER));
00340 yt->setAttribute(_("racy-content"), _(DEFAULT_YOUTUBE_RACY_CONTENT));
00341 yt->setAttribute(_("format"), _(DEFAULT_YOUTUBE_FORMAT));
00342 yt->setAttribute(_("hd"), _(DEFAULT_YOUTUBE_HD));
00343
00344 Ref<Element> favs(new Element(_("favorites")));
00345 favs->setAttribute(_("user"), _("mediatomb"));
00346 yt->appendElementChild(favs);
00347
00348 Ref<Element> most_viewed(new Element(_("standardfeed")));
00349 most_viewed->setAttribute(_("feed"), _("most_viewed"));
00350 most_viewed->setAttribute(_("time-range"), _("today"));
00351 yt->appendElementChild(most_viewed);
00352
00353 Ref<Element> playlist(new Element(_("playlists")));
00354 playlist->setAttribute(_("user"), _("mediatomb"));
00355 yt->appendElementChild(playlist);
00356
00357 Ref<Element> ytuser(new Element(_("uploads")));
00358 ytuser->setAttribute(_("user"), _("mediatomb"));
00359 yt->appendElementChild(ytuser);
00360
00361 Ref<Element> ytfeatured(new Element(_("standardfeed")));
00362 ytfeatured->setAttribute(_("feed"), _("recently_featured"));
00363 ytfeatured->setAttribute(_("time-range"), _("today"));
00364 yt->appendElementChild(ytfeatured);
00365
00366 onlinecontent->appendElementChild(yt);
00367 #endif
00368 #ifdef WEBORAMA
00369 Ref<Element> wb(new Element(_("Weborama")));
00370 wb->setAttribute(_("enabled"), _(DEFAULT_WEBORAMA_ENABLED));
00371 wb->setAttribute(_("refresh"), String::from(DEFAULT_WEBORAMA_REFRESH));
00372 wb->setAttribute(_("update-at-start"), _(DEFAULT_WEBORAMA_UPDATE_AT_START));
00373
00374 Ref<Element> play1(new Element(_("playlist")));
00375 play1->setAttribute(_("name"), _("Active"));
00376 play1->setAttribute(_("type"), _("playlist"));
00377 play1->setAttribute(_("mood"), _("active"));
00378 wb->appendElementChild(play1);
00379
00380 Ref<Element> play2(new Element(_("playlist")));
00381 play2->setAttribute(_("name"), _("Metal"));
00382 play2->setAttribute(_("type"), _("playlist"));
00383
00384 Ref<Element> filter(new Element(_("filter")));
00385 Ref<Element> genres(new Element(_("genres")));
00386 genres->setText(_("metal"));
00387 filter->appendElementChild(genres);
00388 play2->appendElementChild(filter);
00389 wb->appendElementChild(play2);
00390
00391 onlinecontent->appendElementChild(wb);
00392 #endif
00393
00394 #ifdef ATRAILERS
00395 Ref<Element> at(new Element(_("AppleTrailers")));
00396 at->setAttribute(_("enabled"), _(DEFAULT_ATRAILERS_ENABLED));
00397 at->setAttribute(_("refresh"), String::from(DEFAULT_ATRAILERS_REFRESH));
00398 at->setAttribute(_("update-at-start"), _(DEFAULT_ATRAILERS_UPDATE_AT_START));
00399 at->setAttribute(_("resolution"), String::from(DEFAULT_ATRAILERS_RESOLUTION));
00400 onlinecontent->appendElementChild(at);
00401 #endif
00402 return onlinecontent;
00403 }
00404
00405 #endif
00406
00407 String ConfigManager::createDefaultConfig(String userhome)
00408 {
00409 bool mysql_flag = false;
00410
00411 String homepath = userhome + DIR_SEPARATOR + config_dir;
00412
00413 if (!check_path(homepath, true))
00414 {
00415 if (mkdir(homepath.c_str(), 0777) < 0)
00416 {
00417 throw _Exception(_("Could not create directory ") + homepath +
00418 " : " + strerror(errno));
00419 }
00420 }
00421
00422 String config_filename = homepath + DIR_SEPARATOR + DEFAULT_CONFIG_NAME;
00423
00424 Ref<Element> config(new Element(_("config")));
00425 config->setAttribute(_("version"), String::from(CONFIG_XML_VERSION));
00426 config->setAttribute(_("xmlns"), _(XML_XMLNS) + CONFIG_XML_VERSION);
00427 config->setAttribute(_("xmlns:xsi"), _(XML_XMLNS_XSI));
00428 config->setAttribute(_("xsi:schemaLocation"), _(XML_XMLNS) + CONFIG_XML_VERSION + " " + XML_XMLNS + CONFIG_XML_VERSION + ".xsd");
00429 Ref<Element> server(new Element(_("server")));
00430
00431 Ref<Element> ui(new Element(_("ui")));
00432 ui->setAttribute(_("enabled"), _(DEFAULT_UI_EN_VALUE));
00433 ui->setAttribute(_("show-tooltips"), _(DEFAULT_UI_SHOW_TOOLTIPS_VALUE));
00434
00435 Ref<Element>accounts(new Element(_("accounts")));
00436 accounts->setAttribute(_("enabled"), _(DEFAULT_ACCOUNTS_EN_VALUE));
00437 accounts->setAttribute(_("session-timeout"), String::from(DEFAULT_SESSION_TIMEOUT));
00438
00439 Ref<Element> account(new Element(_("account")));
00440 account->setAttribute(_("user"), _(DEFAULT_ACCOUNT_USER));
00441 account->setAttribute(_("password"), _(DEFAULT_ACCOUNT_PASSWORD));
00442 accounts->appendElementChild(account);
00443
00444 ui->appendElementChild(accounts);
00445
00446 server->appendElementChild(ui);
00447 server->appendTextChild(_("name"), _(PACKAGE_NAME));
00448
00449 Ref<Element> udn(new Element(_("udn")));
00450 server->appendElementChild(udn);
00451
00452 server->appendTextChild(_("home"), homepath);
00453 server->appendTextChild(_("webroot"), prefix_dir +
00454 DIR_SEPARATOR +
00455 _(DEFAULT_WEB_DIR));
00456
00457 Ref<Element> storage(new Element(_("storage")));
00458 #ifdef HAVE_SQLITE3
00459 Ref<Element> sqlite3(new Element(_("sqlite3")));
00460 sqlite3->setAttribute(_("enabled"), _(DEFAULT_SQLITE_ENABLED));
00461 sqlite3->appendTextChild(_("database-file"), _(DEFAULT_SQLITE3_DB_FILENAME));
00462 #ifdef SQLITE_BACKUP_ENABLED
00463
00464 Ref<Element> backup(new Element(_("backup")));
00465 backup->setAttribute(_("enabled"), _(YES));
00466 backup->setAttribute(_("interval"), String::from(DEFAULT_SQLITE_BACKUP_INTERVAL));
00467 sqlite3->appendElementChild(backup);
00468 #endif
00469 storage->appendElementChild(sqlite3);
00470 #endif
00471 #ifdef HAVE_MYSQL
00472 Ref<Element>mysql(new Element(_("mysql")));
00473 #ifndef HAVE_SQLITE3
00474 mysql->setAttribute(_("enabled"), _(DEFAULT_MYSQL_ENABLED));
00475 mysql_flag = true;
00476 #else
00477 mysql->setAttribute(_("enabled"), _("no"));
00478 #endif
00479 mysql->appendTextChild(_("host"), _(DEFAULT_MYSQL_HOST));
00480 mysql->appendTextChild(_("username"), _(DEFAULT_MYSQL_USER));
00481
00482 mysql->appendTextChild(_("database"), _(DEFAULT_MYSQL_DB));
00483
00484 storage->appendElementChild(mysql);
00485 #endif
00486 server->appendElementChild(storage);
00487
00488 Ref<Element> protocolinfo(new Element(_("protocolInfo")));
00489 protocolinfo->setAttribute(_("extend"), _(DEFAULT_EXTEND_PROTOCOLINFO));
00490
00491 server->appendElementChild(protocolinfo);
00492
00493 Ref<Comment> ps3protinfo(new Comment(_(" For PS3 support change to \"yes\" ")));
00494 server->appendChild(RefCast(ps3protinfo, Node));
00495
00496 Ref<Comment> redinfo(new Comment(_("\n\
00497 Uncomment the lines below to get rid of jerky avi playback on the\n\
00498 DSM320 or to enable subtitles support on the DSM units\n\
00499 "), true));
00500
00501 Ref<Comment> redsonic(new Comment(_("\n\
00502 <custom-http-headers>\n\
00503 <add header=\"X-User-Agent: redsonic\"/>\n\
00504 </custom-http-headers>\n\
00505 \n\
00506 <manufacturerURL>redsonic.com</manufacturerURL>\n\
00507 <modelNumber>105</modelNumber>\n\
00508 "), true));
00509
00510 Ref<Comment> tg100info(new Comment(_(" Uncomment the line below if you have a Telegent TG100 "), true));
00511 Ref<Comment> tg100(new Comment(_("\n\
00512 <upnp-string-limit>101</upnp-string-limit>\n\
00513 "), true));
00514
00515 server->appendChild(RefCast(redinfo, Node));
00516 server->appendChild(RefCast(redsonic, Node));
00517 server->appendChild(RefCast(tg100info, Node));
00518 server->appendChild(RefCast(tg100, Node));
00519
00520
00521 server->appendElementChild(renderExtendedRuntimeSection());
00522
00523 config->appendElementChild(server);
00524
00525 Ref<Element> import(new Element(_("import")));
00526 import->setAttribute(_("hidden-files"), _(DEFAULT_HIDDEN_FILES_VALUE));
00527
00528 #ifdef HAVE_MAGIC
00529 if (string_ok(magic))
00530 {
00531 Ref<Element> magicfile(new Element(_("magic-file")));
00532 magicfile->setText(magic);
00533 import->appendElementChild(magicfile);
00534 }
00535 #endif
00536
00537 Ref<Element> scripting(new Element(_("scripting")));
00538 scripting->setAttribute(_("script-charset"), _(DEFAULT_JS_CHARSET));
00539 import->appendElementChild(scripting);
00540
00541 Ref<Element> layout(new Element(_("virtual-layout")));
00542 layout->setAttribute(_("type"), _(DEFAULT_LAYOUT_TYPE));
00543 #ifdef HAVE_JS
00544 layout->appendTextChild(_("import-script"), prefix_dir +
00545 DIR_SEPARATOR +
00546 _(DEFAULT_JS_DIR) +
00547 DIR_SEPARATOR +
00548 _(DEFAULT_IMPORT_SCRIPT));
00549 #ifdef HAVE_LIBDVDNAV
00550 layout->appendTextChild(_("dvd-script"), prefix_dir +
00551 DIR_SEPARATOR +
00552 _(DEFAULT_JS_DIR) +
00553 DIR_SEPARATOR +
00554 _(DEFAULT_DVD_SCRIPT));
00555 #endif
00556 scripting->appendTextChild(_("common-script"),
00557 prefix_dir +
00558 DIR_SEPARATOR +
00559 _(DEFAULT_JS_DIR) +
00560 DIR_SEPARATOR +
00561 _(DEFAULT_COMMON_SCRIPT));
00562
00563 scripting->appendTextChild(_("playlist-script"),
00564 prefix_dir +
00565 DIR_SEPARATOR +
00566 _(DEFAULT_JS_DIR) +
00567 DIR_SEPARATOR +
00568 _(DEFAULT_PLAYLISTS_SCRIPT));
00569
00570 #endif
00571 scripting->appendElementChild(layout);
00572
00573 String map_file = prefix_dir + DIR_SEPARATOR + CONFIG_MAPPINGS_TEMPLATE;
00574
00575 Ref<Element> mappings(new Element(_("mappings")));
00576 Ref<Element> ext2mt(new Element(_("extension-mimetype")));
00577 ext2mt->setAttribute(_("ignore-unknown"), _(DEFAULT_IGNORE_UNKNOWN_EXTENSIONS));
00578 ext2mt->appendElementChild(map_from_to(_("mp3"), _("audio/mpeg")));
00579 ext2mt->appendElementChild(map_from_to(_("ogx"), _("application/ogg")));
00580 ext2mt->appendElementChild(map_from_to(_("ogv"), _("video/ogg")));
00581 ext2mt->appendElementChild(map_from_to(_("oga"), _("audio/ogg")));
00582 ext2mt->appendElementChild(map_from_to(_("ogg"), _("audio/ogg")));
00583 ext2mt->appendElementChild(map_from_to(_("ogm"), _("video/ogg")));
00584 ext2mt->appendElementChild(map_from_to(_("asf"), _("video/x-ms-asf")));
00585 ext2mt->appendElementChild(map_from_to(_("asx"), _("video/x-ms-asf")));
00586 ext2mt->appendElementChild(map_from_to(_("wma"), _("audio/x-ms-wma")));
00587 ext2mt->appendElementChild(map_from_to(_("wax"), _("audio/x-ms-wax")));
00588 ext2mt->appendElementChild(map_from_to(_("wmv"), _("video/x-ms-wmv")));
00589 ext2mt->appendElementChild(map_from_to(_("wvx"), _("video/x-ms-wvx")));
00590 ext2mt->appendElementChild(map_from_to(_("wm"), _("video/x-ms-wm")));
00591 ext2mt->appendElementChild(map_from_to(_("wmx"), _("video/x-ms-wmx")));
00592 ext2mt->appendElementChild(map_from_to(_("m3u"), _("audio/x-mpegurl")));
00593 ext2mt->appendElementChild(map_from_to(_("pls"), _("audio/x-scpls")));
00594 ext2mt->appendElementChild(map_from_to(_("flv"), _("video/x-flv")));
00595 ext2mt->appendElementChild(map_from_to(_("mkv"), _("video/x-matroska")));
00596 ext2mt->appendElementChild(map_from_to(_("mka"), _("audio/x-matroska")));
00597
00598 Ref<Comment> ps3info(new Comment(_(" Uncomment the line below for PS3 divx support "), true));
00599 Ref<Comment> ps3avi(new Comment(_(" <map from=\"avi\" to=\"video/divx\"/> "), true));
00600 ext2mt->appendChild(RefCast(ps3info, Node));
00601 ext2mt->appendChild(RefCast(ps3avi, Node));
00602
00603 Ref<Comment> dsmzinfo(new Comment(_(" Uncomment the line below for D-Link DSM / ZyXEL DMA-1000 "), true));
00604 Ref<Comment> dsmzavi(new Comment(_(" <map from=\"avi\" to=\"video/avi\"/> "), true));
00605 ext2mt->appendChild(RefCast(dsmzinfo, Node));
00606 ext2mt->appendChild(RefCast(dsmzavi, Node));
00607
00608 mappings->appendElementChild(ext2mt);
00609
00610 Ref<Element> mtupnp(new Element(_("mimetype-upnpclass")));
00611 mtupnp->appendElementChild(map_from_to(_("audio/*"),
00612 _(UPNP_DEFAULT_CLASS_MUSIC_TRACK)));
00613 mtupnp->appendElementChild(map_from_to(_("video/*"),
00614 _(UPNP_DEFAULT_CLASS_VIDEO_ITEM)));
00615 mtupnp->appendElementChild(map_from_to(_("image/*"),
00616 _("object.item.imageItem")));
00617
00618 mappings->appendElementChild(mtupnp);
00619
00620 Ref<Element> mtcontent(new Element(_("mimetype-contenttype")));
00621 mtcontent->appendElementChild(treat_as(_("audio/mpeg"),
00622 _(CONTENT_TYPE_MP3)));
00623 mtcontent->appendElementChild(treat_as(_("application/ogg"),
00624 _(CONTENT_TYPE_OGG)));
00625 mtcontent->appendElementChild(treat_as(_("audio/x-flac"),
00626 _(CONTENT_TYPE_FLAC)));
00627 mtcontent->appendElementChild(treat_as(_("image/jpeg"),
00628 _(CONTENT_TYPE_JPG)));
00629 mtcontent->appendElementChild(treat_as(_("audio/x-mpegurl"),
00630 _(CONTENT_TYPE_PLAYLIST)));
00631 mtcontent->appendElementChild(treat_as(_("audio/x-scpls"),
00632 _(CONTENT_TYPE_PLAYLIST)));
00633 mtcontent->appendElementChild(treat_as(_("audio/x-wav"),
00634 _(CONTENT_TYPE_PCM)));
00635 mtcontent->appendElementChild(treat_as(_("audio/L16"),
00636 _(CONTENT_TYPE_PCM)));
00637 mtcontent->appendElementChild(treat_as(_("video/x-msvideo"),
00638 _(CONTENT_TYPE_AVI)));
00639 mtcontent->appendElementChild(treat_as(_("video/mp4"),
00640 _(CONTENT_TYPE_MP4)));
00641 mtcontent->appendElementChild(treat_as(_("audio/mp4"),
00642 _(CONTENT_TYPE_MP4)));
00643 mtcontent->appendElementChild(treat_as(_("application/x-iso9660"),
00644 _(CONTENT_TYPE_DVD)));
00645 mtcontent->appendElementChild(treat_as(_("application/x-iso9660-image"),
00646 _(CONTENT_TYPE_DVD)));
00647
00648 mappings->appendElementChild(mtcontent);
00649 import->appendElementChild(mappings);
00650
00651 #ifdef ONLINE_SERVICES
00652 import->appendElementChild(renderOnlineSection());
00653 #endif
00654
00655 config->appendElementChild(import);
00656
00657 #ifdef EXTERNAL_TRANSCODING
00658 config->appendElementChild(renderTranscodingSection());
00659 #endif
00660
00661 config->indent();
00662 save_text(config_filename, config->print());
00663 log_info("MediaTomb configuration was created in: %s\n",
00664 config_filename.c_str());
00665
00666 if (mysql_flag)
00667 {
00668 throw _Exception(_("You are using MySQL! Please edit ") + config_filename +
00669 " and enter your MySQL host/username/password!");
00670 }
00671
00672 return config_filename;
00673 }
00674
00675 void ConfigManager::migrate()
00676 {
00677 bool migrated_flag = false;
00678 String version = root->getAttribute(_("version"));
00679
00680
00681 if (!string_ok(version))
00682 {
00683 log_info("Migrating server configuration to config version 1\n");
00684 root->setAttribute(_("version"),
00685 String::from(CONFIG_XML_VERSION_0_11_0));
00686 root->setAttribute(_("xmlns"),
00687 _(XML_XMLNS) + CONFIG_XML_VERSION_0_11_0);
00688 root->setAttribute(_("xmlns:xsi"), _(XML_XMLNS_XSI));
00689 root->setAttribute(_("xsi:schemaLocation"),
00690 _(XML_XMLNS) + CONFIG_XML_VERSION_0_11_0 + " " + XML_XMLNS +
00691 CONFIG_XML_VERSION + ".xsd");
00692
00693 Ref<Element> server = root->getChildByName(_("server"));
00694 if (server == nil)
00695 throw _Exception(_("Migration failed! Could not find <server> tag!"));
00696
00697 checkOptionString(_("/server/storage/attribute::driver"));
00698 String dbDriver = getOption(_("/server/storage/attribute::driver"));
00699 Ref<Element> storage(new Element(_("storage")));
00700 #ifdef HAVE_SQLITE3
00701 if (dbDriver == "sqlite3")
00702 {
00703 String dbFile = getOption(_("/server/storage/database-file"));
00704
00705 Ref<Element> sqlite3(new Element(_("sqlite3")));
00706 sqlite3->setAttribute(_("enabled"), _(YES));
00707 sqlite3->appendTextChild(_("database-file"), dbFile);
00708 storage->appendElementChild(sqlite3);
00709 }
00710 #endif // HAVE_SQLITE3
00711
00712 #ifdef HAVE_MYSQL
00713 if (dbDriver == "mysql")
00714 {
00715 String host = getOption(_("/server/storage/host"));
00716 String db = getOption(_("/server/storage/database"));
00717 String username = getOption(_("/server/storage/username"));
00718 int port = -1;
00719
00720 if (server->getChildByName(_("storage"))->getChildByName(_("port")) != nil)
00721 port = getIntOption(_("/server/storage/port"));
00722
00723 String socket = nil;;
00724 if (server->getChildByName(_("storage"))->getChildByName(_("socket")) != nil)
00725 socket = getOption(_("/server/storage/socket"));
00726
00727 String password = nil;
00728 if (server->getChildByName(_("storage"))->getChildByName(_("password")) != nil)
00729 password = getOption(_("/server/storage/password"));
00730
00731 Ref<Element>mysql(new Element(_("mysql")));
00732 mysql->setAttribute(_("enabled"), _(YES));
00733
00734 mysql->appendTextChild(_("host"), host);
00735
00736 if (port != -1)
00737 mysql->appendTextChild(_("port"), String::from(port));
00738
00739 if (socket != nil)
00740 storage->appendTextChild(_("socket"), socket);
00741
00742 mysql->appendTextChild(_("username"), username);
00743 if (password != nil)
00744 storage->appendTextChild(_("password"), password);
00745
00746 mysql->appendTextChild(_("database"), db);
00747 storage->appendElementChild(mysql);
00748 }
00749 #endif
00750 server->removeElementChild(_("storage"), true);
00751
00752 server->appendElementChild(storage);
00753 #ifdef EXTERNAL_TRANSCODING
00754 if (root->getChildByName(_("transcoding")) == nil)
00755 root->appendElementChild(renderTranscodingSection());
00756 #endif
00757
00758 Ref<Element> import = root->getChildByName(_("import"));
00759 if (import != nil)
00760 {
00761 #ifdef ONLINE_SERVICES
00762 if (import->getChildByName(_("online-content")) == nil)
00763 import->appendElementChild(renderOnlineSection());
00764 #endif
00765 Ref<Element> map = import->getChildByName(_("mappings"));
00766 if (map != nil)
00767 {
00768 Ref<Element> mtct = map->getChildByName(_("mimetype-contenttype"));
00769 if ((mtct != nil) && (mtct->elementChildCount() > 0))
00770 {
00771 bool add_avi = true;
00772 for (int mc = 0; mc < mtct->elementChildCount(); mc++)
00773 {
00774 Ref<Element> treat = mtct->getElementChild(mc);
00775 if (treat->getAttribute(_("as")) == "avi")
00776 add_avi = false;
00777 }
00778 if (add_avi)
00779 mtct->appendElementChild(treat_as(_("video/x-msvideo"),
00780 _("avi")));
00781 }
00782 }
00783 }
00784
00785 version = String::from(CONFIG_XML_VERSION_0_11_0);
00786 migrated_flag = true;
00787 }
00788
00789
00790 if (string_ok(version) && version.toInt() == 1)
00791 {
00792 log_info("Migrating server configuration to config version 2\n");
00793 root->setAttribute(_("version"), String::from(CONFIG_XML_VERSION));
00794 root->setAttribute(_("xmlns"), _(XML_XMLNS) + CONFIG_XML_VERSION);
00795 root->setAttribute(_("xsi:schemaLocation"),
00796 _(XML_XMLNS) + CONFIG_XML_VERSION + " " + XML_XMLNS +
00797 CONFIG_XML_VERSION + ".xsd");
00798
00799 Ref<Element> server = root->getChildByName(_("server"));
00800 if (server == nil)
00801 throw _Exception(_("Migration failed! Could not find <server> tag!"));
00802
00803 String temp;
00804 try
00805 {
00806 temp = getOption(_("/server/ui/attribute::show-tooltips"));
00807 }
00808 catch (Exception e)
00809 {
00810 Ref<Element> ui = server->getChildByName(_("ui"));
00811 if (ui != nil)
00812 ui->setAttribute(_("show-tooltips"),
00813 _(DEFAULT_UI_SHOW_TOOLTIPS_VALUE));
00814 }
00815
00816 try
00817 {
00818 temp = getOption(_("/server/storage/attribute::caching"));
00819 }
00820 catch (Exception e)
00821 {
00822 Ref<Element> storage = server->getChildByName(_("storage"));
00823 if (storage != nil)
00824 storage->setAttribute(_("caching"),
00825 _(DEFAULT_STORAGE_CACHING_ENABLED));
00826 }
00827
00828 if (server->getChildByName(_("extended-runtime-options")) == nil)
00829 server->appendElementChild(renderExtendedRuntimeSection());
00830
00831 Ref<Element> import = root->getChildByName(_("import"));
00832 if (import != nil)
00833 {
00834
00835 Ref<Element> mappings = import->getChildByName(_("mappings"));
00836
00837 #ifdef ONLINE_SERVICES
00838 Ref<Element> online = import->getChildByName(_("online-content"));
00839 if (online == nil)
00840 import->appendElementChild(renderOnlineSection());
00841 #endif
00842 }
00843 migrated_flag = true;
00844 }
00845
00846 if (migrated_flag)
00847 {
00848 root->indent();
00849 save();
00850 log_info("Migration of configuration successfull\n");
00851 }
00852 }
00853
00854 #define NEW_OPTION(optval) opt = Ref<Option> (new Option(optval));
00855 #define SET_OPTION(opttype) options->set(RefCast(opt, ConfigOption), opttype);
00856
00857 #define NEW_INT_OPTION(optval) int_opt = \
00858 Ref<IntOption> (new IntOption(optval));
00859 #define SET_INT_OPTION(opttype) \
00860 options->set(RefCast(int_opt, ConfigOption), opttype);
00861
00862 #define NEW_BOOL_OPTION(optval) bool_opt = \
00863 Ref<BoolOption> (new BoolOption(optval));
00864 #define SET_BOOL_OPTION(opttype) \
00865 options->set(RefCast(bool_opt, ConfigOption), opttype);
00866
00867 #define NEW_DICT_OPTION(optval) dict_opt = \
00868 Ref<DictionaryOption> (new DictionaryOption(optval));
00869 #define SET_DICT_OPTION(opttype) \
00870 options->set(RefCast(dict_opt, ConfigOption), opttype);
00871
00872 #define NEW_STRARR_OPTION(optval) str_array_opt = \
00873 Ref<StringArrayOption> (new StringArrayOption(optval));
00874 #define SET_STRARR_OPTION(opttype) \
00875 options->set(RefCast(str_array_opt, ConfigOption), opttype);
00876
00877 #define NEW_AUTOSCANLIST_OPTION(optval) alist_opt = \
00878 Ref<AutoscanListOption> (new AutoscanListOption(optval));
00879 #define SET_AUTOSCANLIST_OPTION(opttype) \
00880 options->set(RefCast(alist_opt, ConfigOption), opttype);
00881 #ifdef EXTERNAL_TRANSCODING
00882 #define NEW_TRANSCODING_PROFILELIST_OPTION(optval) trlist_opt = \
00883 Ref<TranscodingProfileListOption> (new TranscodingProfileListOption(optval));
00884 #define SET_TRANSCODING_PROFILELIST_OPTION(opttype) \
00885 options->set(RefCast(trlist_opt, ConfigOption), opttype);
00886 #endif//TRANSCODING
00887 #ifdef ONLINE_SERVICES
00888 #define NEW_OBJARR_OPTION(optval) obj_array_opt = \
00889 Ref<ObjectArrayOption> (new ObjectArrayOption(optval));
00890 #define SET_OBJARR_OPTION(opttype) \
00891 options->set(RefCast(obj_array_opt, ConfigOption), opttype);
00892 #endif//ONLINE_SERVICES
00893
00894 #define NEW_OBJDICT_OPTION(optval) obj_dict_opt = \
00895 Ref<ObjectDictionaryOption> (new ObjectDictionaryOption(optval));
00896 #define SET_OBJDICT_OPTION(opttype) \
00897 options->set(RefCast(obj_dict_opt, ConfigOption), opttype);
00898
00899
00900 void ConfigManager::validate(String serverhome)
00901 {
00902 String temp;
00903 int temp_int;
00904 Ref<Element> tmpEl;
00905
00906 Ref<Option> opt;
00907 Ref<BoolOption> bool_opt;
00908 Ref<IntOption> int_opt;
00909 Ref<DictionaryOption> dict_opt;
00910 Ref<StringArrayOption> str_array_opt;
00911 Ref<AutoscanListOption> alist_opt;
00912 #ifdef EXTERNAL_TRANSCODING
00913 Ref<TranscodingProfileListOption> trlist_opt;
00914 #endif
00915 #ifdef ONLINE_SERVICES
00916 Ref<ObjectArrayOption> obj_array_opt;
00917 #endif
00918
00919 log_info("Checking configuration...\n");
00920
00921
00922
00923 if (root->getName() != "config")
00924 throw _Exception(_("Error in config file: <config> tag not found"));
00925
00926 if (root->getChildByName(_("server")) == nil)
00927 throw _Exception(_("Error in config file: <server> tag not found"));
00928
00929 String version = root->getAttribute(_("version"));
00930
00931
00932 if (!string_ok(version) || version.toInt() != CONFIG_XML_VERSION)
00933 migrate();
00934
00935 if (version.toInt() > CONFIG_XML_VERSION)
00936 throw _Exception(_("Config version \"") + version + "\" does not yet exist!");
00937
00938
00939
00940
00942 getOption(_("/server/home"), serverhome);
00943 NEW_OPTION(getOption(_("/server/home")));
00944 SET_OPTION(CFG_SERVER_HOME);
00945 prepare_path(_("/server/home"), true);
00946 NEW_OPTION(getOption(_("/server/home")));
00947 SET_OPTION(CFG_SERVER_HOME);
00948
00949 prepare_path(_("/server/webroot"), true);
00950 NEW_OPTION(getOption(_("/server/webroot")));
00951 SET_OPTION(CFG_SERVER_WEBROOT);
00952
00953 temp = getOption(_("/server/tmpdir"), _(DEFAULT_TMPDIR));
00954 if (!check_path(temp, true))
00955 {
00956 throw _Exception(_("Temporary directory ") + temp + " does not exist!");
00957 }
00958 temp = temp + _("/");
00959 NEW_OPTION(temp);
00960 SET_OPTION(CFG_SERVER_TMPDIR);
00961
00962
00963 if (string_ok(getOption(_("/server/servedir"), _(""))))
00964 prepare_path(_("/server/servedir"), true);
00965
00966 NEW_OPTION(getOption(_("/server/servedir")));
00967 SET_OPTION(CFG_SERVER_SERVEDIR);
00968
00969
00970 checkOptionString(_("/server/udn"));
00971 NEW_OPTION(getOption(_("/server/udn")));
00972 SET_OPTION(CFG_SERVER_UDN);
00973
00974
00975 String mysql_en = _("no");
00976 String sqlite3_en = _("no");
00977
00978 tmpEl = getElement(_("/server/storage"));
00979 if (tmpEl == nil)
00980 throw _Exception(_("Error in config file: <storage> tag not found"));
00981
00982
00983 temp = getOption(_("/server/storage/attribute::caching"),
00984 _(DEFAULT_STORAGE_CACHING_ENABLED));
00985 if (!validateYesNo(temp))
00986 throw _Exception(_("Error in config file: incorrect parameter "
00987 "for <storage caching=\"\" /> attribute"));
00988 NEW_BOOL_OPTION(temp == "yes" ? true : false);
00989 SET_BOOL_OPTION(CFG_SERVER_STORAGE_CACHING_ENABLED);
00990
00991 tmpEl = getElement(_("/server/storage/mysql"));
00992 if (tmpEl != nil)
00993 {
00994 mysql_en = getOption(_("/server/storage/mysql/attribute::enabled"),
00995 _(DEFAULT_MYSQL_ENABLED));
00996 if (!validateYesNo(mysql_en))
00997 throw _Exception(_("Invalid <mysql enabled=\"\"> value"));
00998 }
00999
01000 tmpEl = getElement(_("/server/storage/sqlite3"));
01001 if (tmpEl != nil)
01002 {
01003 sqlite3_en = getOption(_("/server/storage/sqlite3/attribute::enabled"),
01004 _(DEFAULT_SQLITE_ENABLED));
01005 if (!validateYesNo(sqlite3_en))
01006 throw _Exception(_("Invalid <sqlite3 enabled=\"\"> value"));
01007 }
01008
01009 if ((sqlite3_en == "yes") && (mysql_en == "yes"))
01010 throw _Exception(_("You enabled both, sqlite3 and mysql but "
01011 "only one database driver may be active at "
01012 "a time!"));
01013
01014 if ((sqlite3_en == "no") && (mysql_en == "no"))
01015 throw _Exception(_("You disabled both, sqlite3 and mysql but "
01016 "one database driver must be active!"));
01017
01018 #ifdef HAVE_MYSQL
01019 if (mysql_en == "yes")
01020 {
01021 NEW_OPTION(getOption(_("/server/storage/mysql/host"),
01022 _(DEFAULT_MYSQL_HOST)));
01023 SET_OPTION(CFG_SERVER_STORAGE_MYSQL_HOST);
01024
01025 NEW_OPTION(getOption(_("/server/storage/mysql/database"),
01026 _(DEFAULT_MYSQL_DB)));
01027 SET_OPTION(CFG_SERVER_STORAGE_MYSQL_DATABASE);
01028
01029 NEW_OPTION(getOption(_("/server/storage/mysql/username"),
01030 _(DEFAULT_MYSQL_USER)));
01031 SET_OPTION(CFG_SERVER_STORAGE_MYSQL_USERNAME);
01032
01033 NEW_INT_OPTION(getIntOption(_("/server/storage/mysql/port"), 0));
01034 SET_INT_OPTION(CFG_SERVER_STORAGE_MYSQL_PORT);
01035
01036 if (getElement(_("/server/storage/mysql/socket")) == nil)
01037 {
01038 NEW_OPTION(nil);
01039 }
01040 else
01041 {
01042 NEW_OPTION(getOption(_("/server/storage/mysql/socket")));
01043 }
01044
01045 SET_OPTION(CFG_SERVER_STORAGE_MYSQL_SOCKET);
01046
01047 if (getElement(_("/server/storage/mysql/password")) == nil)
01048 {
01049 NEW_OPTION(nil);
01050 }
01051 else
01052 {
01053 NEW_OPTION(getOption(_("/server/storage/mysql/password")));
01054 }
01055 SET_OPTION(CFG_SERVER_STORAGE_MYSQL_PASSWORD);
01056 }
01057 #else
01058 if (mysql_en == "yes")
01059 {
01060 throw _Exception(_("You enabled MySQL storage in configuration, "
01061 "however this version of MediaTomb was compiled "
01062 "without MySQL support!"));
01063 }
01064 #endif // HAVE_MYSQL
01065
01066 #ifdef HAVE_SQLITE3
01067
01068 if (sqlite3_en == "yes")
01069 {
01070 prepare_path(_("/server/storage/sqlite3/database-file"), false, true);
01071 NEW_OPTION(getOption(_("/server/storage/sqlite3/database-file")));
01072 SET_OPTION(CFG_SERVER_STORAGE_SQLITE_DATABASE_FILE);
01073
01074 temp = getOption(_("/server/storage/sqlite3/synchronous"),
01075 _(DEFAULT_SQLITE_SYNC));
01076
01077 temp_int = 0;
01078
01079 if (temp == "off")
01080 temp_int = MT_SQLITE_SYNC_OFF;
01081 else if (temp == "normal")
01082 temp_int = MT_SQLITE_SYNC_NORMAL;
01083 else if (temp == "full")
01084 temp_int = MT_SQLITE_SYNC_FULL;
01085 else
01086 throw _Exception(_("Invalid <synchronous> value in sqlite3 "
01087 "section"));
01088
01089 NEW_INT_OPTION(temp_int);
01090 SET_INT_OPTION(CFG_SERVER_STORAGE_SQLITE_SYNCHRONOUS);
01091
01092 temp = getOption(_("/server/storage/sqlite3/on-error"),
01093 _(DEFAULT_SQLITE_RESTORE));
01094
01095 bool tmp_bool = true;
01096
01097 if (temp == "restore")
01098 tmp_bool = true;
01099 else if (temp == "fail")
01100 tmp_bool = false;
01101 else
01102 throw _Exception(_("Invalid <on-error> value in sqlite3 "
01103 "section"));
01104
01105 NEW_BOOL_OPTION(tmp_bool);
01106 SET_BOOL_OPTION(CFG_SERVER_STORAGE_SQLITE_RESTORE);
01107 #ifdef SQLITE_BACKUP_ENABLED
01108 temp = getOption(_("/server/storage/sqlite3/backup/attribute::enabled"),
01109 _(YES));
01110 #else
01111 temp = getOption(_("/server/storage/sqlite3/backup/attribute::enabled"),
01112 _(DEFAULT_SQLITE_BACKUP_ENABLED));
01113 #endif
01114 if (!validateYesNo(temp))
01115 throw _Exception(_("Error in config file: incorrect parameter "
01116 "for <backup enabled=\"\" /> attribute"));
01117 NEW_BOOL_OPTION(temp == "yes" ? true : false);
01118 SET_BOOL_OPTION(CFG_SERVER_STORAGE_SQLITE_BACKUP_ENABLED);
01119
01120 temp_int = getIntOption(_("/server/storage/sqlite3/backup/attribute::interval"),
01121 DEFAULT_SQLITE_BACKUP_INTERVAL);
01122 if (temp_int < 1)
01123 throw _Exception(_("Error in config file: incorrect parameter for "
01124 "<backup interval=\"\" /> attribute"));
01125 NEW_INT_OPTION(temp_int);
01126 SET_INT_OPTION(CFG_SERVER_STORAGE_SQLITE_BACKUP_INTERVAL);
01127 }
01128 #else
01129 if (sqlite3_en == "yes")
01130 {
01131 throw _Exception(_("You enabled sqlite3 storage in configuration, "
01132 "however this version of MediaTomb was compiled "
01133 "without sqlite3 support!"));
01134 }
01135
01136 #endif // SQLITE3
01137
01138 String dbDriver;
01139 if (sqlite3_en == "yes")
01140 dbDriver = _("sqlite3");
01141
01142 if (mysql_en == "yes")
01143 dbDriver = _("mysql");
01144
01145 NEW_OPTION(dbDriver);
01146 SET_OPTION(CFG_SERVER_STORAGE_DRIVER);
01147
01148
01149
01150
01151
01152
01153
01154 temp = getOption(_("/server/ui/attribute::enabled"),
01155 _(DEFAULT_UI_EN_VALUE));
01156 if (!validateYesNo(temp))
01157 throw _Exception(_("Error in config file: incorrect parameter "
01158 "for <ui enabled=\"\" /> attribute"));
01159 NEW_BOOL_OPTION(temp == "yes" ? true : false);
01160 SET_BOOL_OPTION(CFG_SERVER_UI_ENABLED);
01161
01162 temp = getOption(_("/server/ui/attribute::show-tooltips"),
01163 _(DEFAULT_UI_SHOW_TOOLTIPS_VALUE));
01164 if (!validateYesNo(temp))
01165 throw _Exception(_("Error in config file: incorrect parameter "
01166 "for <ui show-tooltips=\"\" /> attribute"));
01167 NEW_BOOL_OPTION(temp == "yes" ? true : false);
01168 SET_BOOL_OPTION(CFG_SERVER_UI_SHOW_TOOLTIPS);
01169
01170 temp = getOption(_("/server/ui/attribute::poll-when-idle"),
01171 _(DEFAULT_POLL_WHEN_IDLE_VALUE));
01172 if (!validateYesNo(temp))
01173 throw _Exception(_("Error in config file: incorrect parameter "
01174 "for <ui poll-when-idle=\"\" /> attribute"));
01175 NEW_BOOL_OPTION(temp == "yes" ? true : false);
01176 SET_BOOL_OPTION(CFG_SERVER_UI_POLL_WHEN_IDLE);
01177
01178 temp_int = getIntOption(_("/server/ui/attribute::poll-interval"),
01179 DEFAULT_POLL_INTERVAL);
01180 if (temp_int < 1)
01181 throw _Exception(_("Error in config file: incorrect parameter for "
01182 "<ui poll-interval=\"\" /> attribute"));
01183 NEW_INT_OPTION(temp_int);
01184 SET_INT_OPTION(CFG_SERVER_UI_POLL_INTERVAL);
01185
01186 temp_int = getIntOption(_("/server/ui/items-per-page/attribute::default"),
01187 DEFAULT_ITEMS_PER_PAGE_2);
01188 if (temp_int < 1)
01189 throw _Exception(_("Error in config file: incorrect parameter for "
01190 "<items-per-page default=\"\" /> attribute"));
01191 NEW_INT_OPTION(temp_int);
01192 SET_INT_OPTION(CFG_SERVER_UI_DEFAULT_ITEMS_PER_PAGE);
01193
01194
01195 Ref<Element> element = getElement(_("/server/ui/items-per-page"));
01196
01197 if (element->elementChildCount() == 0)
01198 {
01199 if ((temp_int != DEFAULT_ITEMS_PER_PAGE_1) &&
01200 (temp_int != DEFAULT_ITEMS_PER_PAGE_2) &&
01201 (temp_int != DEFAULT_ITEMS_PER_PAGE_3) &&
01202 (temp_int != DEFAULT_ITEMS_PER_PAGE_4))
01203 {
01204 throw _Exception(_("Error in config file: you specified an "
01205 "<items-per-page default=\"\"> value that is "
01206 "not listed in the options"));
01207 }
01208
01209 element->appendTextChild(_("option"),
01210 String::from(DEFAULT_ITEMS_PER_PAGE_1));
01211 element->appendTextChild(_("option"),
01212 String::from(DEFAULT_ITEMS_PER_PAGE_2));
01213 element->appendTextChild(_("option"),
01214 String::from(DEFAULT_ITEMS_PER_PAGE_3));
01215 element->appendTextChild(_("option"),
01216 String::from(DEFAULT_ITEMS_PER_PAGE_4));
01217 }
01218 else
01219 {
01220 int i;
01221 bool default_found = false;
01222 for (int j = 0; j < element->elementChildCount(); j++)
01223 {
01224 Ref<Element> child = element->getElementChild(j);
01225 if (child->getName() == "option")
01226 {
01227 i = child->getText().toInt();
01228 if (i < 1)
01229 throw _Exception(_("Error in config file: incorrect "
01230 "<option> value for <items-per-page>"));
01231
01232 if (i == temp_int)
01233 default_found = true;
01234 }
01235 }
01236
01237 if (!default_found)
01238 throw _Exception(_("Error in config file: at least one <option> "
01239 "under <items-per-page> must match the "
01240 "<items-per-page default=\"\" /> attribute"));
01241
01242 }
01243
01244
01245 Ref<Array<StringBase> > menu_opts (new Array<StringBase>());
01246 for (int j = 0; j < element->elementChildCount(); j++)
01247 {
01248 Ref<Element> child = element->getElementChild(j);
01249 if (child->getName() == "option")
01250 menu_opts->append(child->getText());
01251 }
01252 NEW_STRARR_OPTION(menu_opts);
01253 SET_STRARR_OPTION(CFG_SERVER_UI_ITEMS_PER_PAGE_DROPDOWN);
01254
01255
01256 temp = getOption(_("/server/ui/accounts/attribute::enabled"),
01257 _(DEFAULT_ACCOUNTS_EN_VALUE));
01258 if (!validateYesNo(temp))
01259 throw _Exception(_("Error in config file: incorrect parameter for "
01260 "<accounts enabled=\"\" /> attribute"));
01261
01262 NEW_BOOL_OPTION(temp == "yes" ? true : false);
01263 SET_BOOL_OPTION(CFG_SERVER_UI_ACCOUNTS_ENABLED);
01264
01265 tmpEl = getElement(_("/server/ui/accounts"));
01266 NEW_DICT_OPTION(createDictionaryFromNodeset(tmpEl, _("account"), _("user"), _("password")));
01267 SET_DICT_OPTION(CFG_SERVER_UI_ACCOUNT_LIST);
01268
01269 temp_int = getIntOption(_("/server/ui/accounts/attribute::session-timeout"),
01270 DEFAULT_SESSION_TIMEOUT);
01271 if (temp_int < 1)
01272 {
01273 throw _Exception(_("Error in config file: invalid session-timeout "
01274 "(must be > 0)\n"));
01275 }
01276 NEW_INT_OPTION(temp_int);
01277 SET_INT_OPTION(CFG_SERVER_UI_SESSION_TIMEOUT);
01278
01279 temp = getOption(_("/import/attribute::hidden-files"),
01280 _(DEFAULT_HIDDEN_FILES_VALUE));
01281 if (!validateYesNo(temp))
01282 throw _Exception(_("Error in config file: incorrect parameter for "
01283 "<import hidden-files=\"\" /> attribute"));
01284 NEW_BOOL_OPTION(temp == "yes" ? true : false);
01285 SET_BOOL_OPTION(CFG_IMPORT_HIDDEN_FILES);
01286
01287 temp = getOption(
01288 _("/import/mappings/extension-mimetype/attribute::ignore-unknown"),
01289 _(DEFAULT_IGNORE_UNKNOWN_EXTENSIONS));
01290
01291 if (!validateYesNo(temp))
01292 throw _Exception(_("Error in config file: incorrect parameter for "
01293 "<extension-mimetype ignore-unknown=\"\" /> attribute"));
01294
01295 NEW_BOOL_OPTION(temp == "yes" ? true : false);
01296 SET_BOOL_OPTION(CFG_IMPORT_MAPPINGS_IGNORE_UNKNOWN_EXTENSIONS);
01297
01298 temp = getOption(
01299 _("/import/mappings/extension-mimetype/attribute::case-sensitive"),
01300 _(DEFAULT_CASE_SENSITIVE_EXTENSION_MAPPINGS));
01301
01302 if (!validateYesNo(temp))
01303 throw _Exception(_("Error in config file: incorrect parameter for "
01304 "<extension-mimetype case-sensitive=\"\" /> attribute"));
01305
01306 bool csens = false;
01307
01308 if (temp == "yes")
01309 csens = true;
01310
01311
01312 NEW_BOOL_OPTION(csens);
01313 SET_BOOL_OPTION(CFG_IMPORT_MAPPINGS_EXTENSION_TO_MIMETYPE_CASE_SENSITIVE);
01314
01315 tmpEl = getElement( _("/import/mappings/extension-mimetype"));
01316 NEW_DICT_OPTION(createDictionaryFromNodeset(tmpEl, _("map"),
01317 _("from"), _("to"), !csens));
01318 SET_DICT_OPTION(CFG_IMPORT_MAPPINGS_EXTENSION_TO_MIMETYPE_LIST);
01319
01320 tmpEl = getElement(_("/import/mappings/mimetype-contenttype"));
01321 if (tmpEl != nil)
01322 {
01323 mime_content = createDictionaryFromNodeset(tmpEl, _("treat"),
01324 _("mimetype"), _("as"));
01325 }
01326 else
01327 {
01328 mime_content = Ref<Dictionary>(new Dictionary());
01329 mime_content->put(_("audio/mpeg"), _(CONTENT_TYPE_MP3));
01330 mime_content->put(_("audio/mp4"), _(CONTENT_TYPE_MP4));
01331 mime_content->put(_("video/mp4"), _(CONTENT_TYPE_MP4));
01332 mime_content->put(_("application/ogg"), _(CONTENT_TYPE_OGG));
01333 mime_content->put(_("audio/x-flac"), _(CONTENT_TYPE_FLAC));
01334 mime_content->put(_("image/jpeg"), _(CONTENT_TYPE_JPG));
01335 mime_content->put(_("audio/x-mpegurl"), _(CONTENT_TYPE_PLAYLIST));
01336 mime_content->put(_("audio/x-scpls"), _(CONTENT_TYPE_PLAYLIST));
01337 mime_content->put(_("audio/x-wav"), _(CONTENT_TYPE_PCM));
01338 mime_content->put(_("audio/L16"), _(CONTENT_TYPE_PCM));
01339 mime_content->put(_("video/x-msvideo"), _(CONTENT_TYPE_AVI));
01340 mime_content->put(_("video/mpeg"), _(CONTENT_TYPE_MPEG));
01341 mime_content->put(_("application/x-iso9660"), _(CONTENT_TYPE_DVD));
01342 mime_content->put(_("application/x-iso9660-image"), _(CONTENT_TYPE_DVD));
01343 }
01344
01345 NEW_DICT_OPTION(mime_content);
01346 SET_DICT_OPTION(CFG_IMPORT_MAPPINGS_MIMETYPE_TO_CONTENTTYPE_LIST);
01347
01348 #if defined(HAVE_NL_LANGINFO) && defined(HAVE_SETLOCALE)
01349 if (setlocale(LC_ALL, "") != NULL)
01350 {
01351 temp = nl_langinfo(CODESET);
01352 log_debug("received %s from nl_langinfo\n", temp.c_str());
01353 }
01354
01355 if (!string_ok(temp))
01356 temp = _(DEFAULT_FILESYSTEM_CHARSET);
01357 #else
01358 temp = _(DEFAULT_FILESYSTEM_CHARSET);
01359 #endif
01360
01361 try
01362 {
01363 Ref<StringConverter> conv(new StringConverter(temp,
01364 _(DEFAULT_INTERNAL_CHARSET)));
01365 }
01366 catch (Exception e)
01367 {
01368 temp = _(DEFAULT_FALLBACK_CHARSET);
01369 }
01370 String charset = getOption(_("/import/filesystem-charset"), temp);
01371 try
01372 {
01373 Ref<StringConverter> conv(new StringConverter(charset,
01374 _(DEFAULT_INTERNAL_CHARSET)));
01375 }
01376 catch (Exception e)
01377 {
01378 throw _Exception(_("Error in config file: unsupported "
01379 "filesystem-charset specified: ") + charset);
01380 }
01381
01382 log_info("Setting filesystem import charset to %s\n", charset.c_str());
01383 NEW_OPTION(charset);
01384 SET_OPTION(CFG_IMPORT_FILESYSTEM_CHARSET);
01385
01386 charset = getOption(_("/import/metadata-charset"), temp);
01387 try
01388 {
01389 Ref<StringConverter> conv(new StringConverter(charset,
01390 _(DEFAULT_INTERNAL_CHARSET)));
01391 }
01392 catch (Exception e)
01393 {
01394 throw _Exception(_("Error in config file: unsupported "
01395 "metadata-charset specified: ") + charset);
01396 }
01397
01398 log_info("Setting metadata import charset to %s\n", charset.c_str());
01399 NEW_OPTION(charset);
01400 SET_OPTION(CFG_IMPORT_METADATA_CHARSET);
01401
01402 charset = getOption(_("/import/playlist-charset"), temp);
01403 try
01404 {
01405 Ref<StringConverter> conv(new StringConverter(charset,
01406 _(DEFAULT_INTERNAL_CHARSET)));
01407 }
01408 catch (Exception e)
01409 {
01410 throw _Exception(_("Error in config file: unsupported playlist-charset specified: ") + charset);
01411 }
01412
01413 log_info("Setting playlist charset to %s\n", charset.c_str());
01414 NEW_OPTION(charset);
01415 SET_OPTION(CFG_IMPORT_PLAYLIST_CHARSET);
01416
01417 #ifdef EXTEND_PROTOCOLINFO
01418 temp = getOption(_("/server/protocolInfo/attribute::extend"),
01419 _(DEFAULT_EXTEND_PROTOCOLINFO));
01420 if (!validateYesNo(temp))
01421 throw _Exception(_("Error in config file: extend attribute of the "
01422 "protocolInfo tag must be either \"yes\" or \"no\""));
01423
01424 NEW_BOOL_OPTION(temp == "yes" ? true : false);
01425 SET_BOOL_OPTION(CFG_SERVER_EXTEND_PROTOCOLINFO);
01426
01427
01428
01429
01430
01431
01432
01433
01434
01435
01436
01437 #endif
01438
01439 temp = getOption(_("/server/pc-directory/attribute::upnp-hide"),
01440 _(DEFAULT_HIDE_PC_DIRECTORY));
01441 if (!validateYesNo(temp))
01442 throw _Exception(_("Error in config file: hide attribute of the "
01443 "pc-directory tag must be either \"yes\" or \"no\""));
01444
01445 NEW_BOOL_OPTION(temp == "yes" ? true : false);
01446 SET_BOOL_OPTION(CFG_SERVER_HIDE_PC_DIRECTORY);
01447
01448 temp = getOption(_("/server/interface"), _(""));
01449
01450 if (string_ok(temp) && string_ok(getOption(_("/server/ip"), _(""))))
01451 throw _Exception(_("Error in config file: you can not specify interface and ip at the same time!"));
01452
01453 NEW_OPTION(temp);
01454 SET_OPTION(CFG_SERVER_NETWORK_INTERFACE);
01455
01456 temp = getOption(_("/server/ip"), _(""));
01457 NEW_OPTION(temp);
01458 SET_OPTION(CFG_SERVER_IP);
01459
01460 temp = getOption(_("/server/bookmark"), _(DEFAULT_BOOKMARK_FILE));
01461 NEW_OPTION(temp);
01462 SET_OPTION(CFG_SERVER_BOOKMARK_FILE);
01463
01464 temp = getOption(_("/server/name"), _(DESC_FRIENDLY_NAME));
01465 NEW_OPTION(temp);
01466 SET_OPTION(CFG_SERVER_NAME);
01467
01468 temp = getOption(_("/server/modelName"), _(DESC_MODEL_NAME));
01469 NEW_OPTION(temp);
01470 SET_OPTION(CFG_SERVER_MODEL_NAME);
01471
01472 temp = getOption(_("/server/modelDescription"), _(DESC_MODEL_DESCRIPTION));
01473 NEW_OPTION(temp);
01474 SET_OPTION(CFG_SERVER_MODEL_DESCRIPTION);
01475
01476 temp = getOption(_("/server/modelNumber"), _(DESC_MODEL_NUMBER));
01477 NEW_OPTION(temp);
01478 SET_OPTION(CFG_SERVER_MODEL_NUMBER);
01479
01480 temp = getOption(_("/server/serialNumber"), _(DESC_SERIAL_NUMBER));
01481 NEW_OPTION(temp);
01482 SET_OPTION(CFG_SERVER_SERIAL_NUMBER);
01483
01484 temp = getOption(_("/server/manufacturerURL"), _(DESC_MANUFACTURER_URL));
01485 NEW_OPTION(temp);
01486 SET_OPTION(CFG_SERVER_MANUFACTURER_URL);
01487
01488 temp = getOption(_("/server/presentationURL"), _(""));
01489 NEW_OPTION(temp);
01490 SET_OPTION(CFG_SERVER_PRESENTATION_URL);
01491
01492 temp = getOption(_("/server/presentationURL/attribute::append-to"),
01493 _(DEFAULT_PRES_URL_APPENDTO_ATTR));
01494
01495 if ((temp != "none") && (temp != "ip") && (temp != "port"))
01496 {
01497 throw _Exception(_("Error in config file: "
01498 "invalid \"append-to\" attribute value in "
01499 "<presentationURL> tag"));
01500 }
01501
01502 if (((temp == "ip") || (temp == "port")) &&
01503 !string_ok(getOption(_("/server/presentationURL"))))
01504 {
01505 throw _Exception(_("Error in config file: \"append-to\" attribute "
01506 "value in <presentationURL> tag is set to \"") +
01507 temp + _("\" but no URL is specified"));
01508 }
01509 NEW_OPTION(temp);
01510 SET_OPTION(CFG_SERVER_APPEND_PRESENTATION_URL_TO);
01511
01512 temp_int = getIntOption(_("/server/upnp-string-limit"),
01513 DEFAULT_UPNP_STRING_LIMIT);
01514 if ((temp_int != -1) && (temp_int < 4))
01515 {
01516 throw _Exception(_("Error in config file: invalid value for "
01517 "<upnp-string-limit>"));
01518 }
01519 NEW_INT_OPTION(temp_int);
01520 SET_INT_OPTION(CFG_SERVER_UPNP_TITLE_AND_DESC_STRING_LIMIT);
01521
01522 #ifdef HAVE_JS
01523 temp = getOption(_("/import/scripting/playlist-script"),
01524 prefix_dir +
01525 DIR_SEPARATOR +
01526 _(DEFAULT_JS_DIR) +
01527 DIR_SEPARATOR +
01528 _(DEFAULT_PLAYLISTS_SCRIPT));
01529 if (!string_ok(temp))
01530 throw _Exception(_("playlist script location invalid"));
01531 prepare_path(_("/import/scripting/playlist-script"));
01532 NEW_OPTION(getOption(_("/import/scripting/playlist-script")));
01533 SET_OPTION(CFG_IMPORT_SCRIPTING_PLAYLIST_SCRIPT);
01534
01535 temp = getOption(_("/import/scripting/common-script"),
01536 prefix_dir +
01537 DIR_SEPARATOR +
01538 _(DEFAULT_JS_DIR) +
01539 DIR_SEPARATOR +
01540 _(DEFAULT_COMMON_SCRIPT));
01541 if (!string_ok(temp))
01542 throw _Exception(_("common script location invalid"));
01543 prepare_path(_("/import/scripting/common-script"));
01544 NEW_OPTION(getOption(_("/import/scripting/common-script")));
01545 SET_OPTION(CFG_IMPORT_SCRIPTING_COMMON_SCRIPT);
01546
01547 temp = getOption(
01548 _("/import/scripting/playlist-script/attribute::create-link"),
01549 _(DEFAULT_PLAYLIST_CREATE_LINK));
01550
01551 if (!validateYesNo(temp))
01552 throw _Exception(_("Error in config file: "
01553 "invalid \"create-link\" attribute value in "
01554 "<playlist-script> tag"));
01555
01556 NEW_BOOL_OPTION(temp == "yes" ? true : false);
01557 SET_BOOL_OPTION(CFG_IMPORT_SCRIPTING_PLAYLIST_SCRIPT_LINK_OBJECTS);
01558 #endif
01559
01560 temp = getOption(_("/import/scripting/virtual-layout/attribute::type"),
01561 _(DEFAULT_LAYOUT_TYPE));
01562 if ((temp != "js") && (temp != "builtin") && (temp != "disabled"))
01563 throw _Exception(_("Error in config file: invalid virtual layout "
01564 "type specified!"));
01565 NEW_OPTION(temp);
01566 SET_OPTION(CFG_IMPORT_SCRIPTING_VIRTUAL_LAYOUT_TYPE);
01567
01568
01569 #ifndef HAVE_JS
01570 if (temp == "js")
01571 throw _Exception(_("MediaTomb was compiled without js support, "
01572 "however you specified \"js\" to be used for the "
01573 "virtual-layout."));
01574 #else
01575 charset = getOption(_("/import/scripting/attribute::script-charset"),
01576 _(DEFAULT_JS_CHARSET));
01577 if (temp == "js")
01578 {
01579 try
01580 {
01581 Ref<StringConverter> conv(new StringConverter(charset,
01582 _(DEFAULT_INTERNAL_CHARSET)));
01583 }
01584 catch (Exception e)
01585 {
01586 throw _Exception(_("Error in config file: unsupported import script charset specified: ") + charset);
01587 }
01588 }
01589
01590 NEW_OPTION(charset);
01591 SET_OPTION(CFG_IMPORT_SCRIPTING_CHARSET);
01592
01593 String script_path = getOption(
01594 _("/import/scripting/virtual-layout/import-script"),
01595 prefix_dir +
01596 DIR_SEPARATOR +
01597 _(DEFAULT_JS_DIR) +
01598 DIR_SEPARATOR +
01599 _(DEFAULT_IMPORT_SCRIPT));
01600 if (temp == "js")
01601 {
01602 if (!string_ok(script_path))
01603 throw _Exception(_("Error in config file: you specified \"js\" to "
01604 "be used for virtual layout, but script "
01605 "location is invalid."));
01606
01607 prepare_path(_("/import/scripting/virtual-layout/import-script"));
01608 script_path = getOption(
01609 _("/import/scripting/virtual-layout/import-script"));
01610 }
01611
01612 NEW_OPTION(script_path);
01613 SET_OPTION(CFG_IMPORT_SCRIPTING_IMPORT_SCRIPT);
01614 #ifdef HAVE_LIBDVDNAV
01615
01616 script_path = getOption(_("/import/scripting/virtual-layout/dvd-script"),
01617 prefix_dir + DIR_SEPARATOR + _(DEFAULT_JS_DIR) +
01618 DIR_SEPARATOR + _(DEFAULT_DVD_SCRIPT));
01619
01620 if (temp == "js")
01621 {
01622 if (!string_ok(script_path))
01623 throw _Exception(_("Error in config file: you specified \"js\" to "
01624 "be used for virtual layout, but dvd script "
01625 "location is invalid."));
01626
01627 prepare_path(_("/import/scripting/virtual-layout/dvd-script"));
01628 script_path = getOption(
01629 _("/import/scripting/virtual-layout/dvd-script"));
01630
01631 }
01632
01633 NEW_OPTION(script_path);
01634 SET_OPTION(CFG_IMPORT_SCRIPTING_DVD_SCRIPT);
01635 #endif
01636
01637 #endif
01638
01639
01640 temp_int = getIntOption(_("/server/port"), 0);
01641 NEW_INT_OPTION(temp_int);
01642 SET_INT_OPTION(CFG_SERVER_PORT);
01643
01644 temp_int = getIntOption(_("/server/alive"), DEFAULT_ALIVE_INTERVAL);
01645 NEW_INT_OPTION(temp_int);
01646 SET_INT_OPTION(CFG_SERVER_ALIVE_INTERVAL);
01647
01648 Ref<Element> el = getElement(_("/import/mappings/mimetype-upnpclass"));
01649 if (el == nil)
01650 {
01651 getOption(_("/import/mappings/mimetype-upnpclass"), _(""));
01652 }
01653 NEW_DICT_OPTION(createDictionaryFromNodeset(el, _("map"),
01654 _("from"), _("to")));
01655 SET_DICT_OPTION(CFG_IMPORT_MAPPINGS_MIMETYPE_TO_UPNP_CLASS_LIST);
01656
01657 temp = getOption(_("/import/autoscan/attribute::use-inotify"), _("auto"));
01658 if ((temp != "auto") && !validateYesNo(temp))
01659 throw _Exception(_("Error in config file: incorrect parameter for "
01660 "\"<autoscan use-inotify=\" attribute"));
01661
01662 el = getElement(_("/import/autoscan"));
01663
01664 NEW_AUTOSCANLIST_OPTION(createAutoscanListFromNodeset(el, TimedScanMode));
01665 SET_AUTOSCANLIST_OPTION(CFG_IMPORT_AUTOSCAN_TIMED_LIST);
01666
01667
01668 #ifdef HAVE_INOTIFY
01669 bool inotify_supported = false;
01670 inotify_supported = Inotify::supported();
01671 #endif
01672
01673 if (temp == _(YES))
01674 {
01675 #ifdef HAVE_INOTIFY
01676 if (!inotify_supported)
01677 throw _Exception(_("You specified "
01678 "\"yes\" in \"<autoscan use-inotify=\"\">"
01679 " however your system does not have "
01680 "inotify support"));
01681 #else
01682 throw _Exception(_("You specified"
01683 " \"yes\" in \"<autoscan use-inotify=\"\">"
01684 " however this version of MediaTomb was compiled "
01685 "without inotify support"));
01686 #endif
01687 }
01688
01689 #ifdef HAVE_INOTIFY
01690 if (temp == _("auto") || (temp == _(YES)))
01691 {
01692 if (inotify_supported)
01693 {
01694 NEW_AUTOSCANLIST_OPTION(createAutoscanListFromNodeset(el, InotifyScanMode));
01695 SET_AUTOSCANLIST_OPTION(CFG_IMPORT_AUTOSCAN_INOTIFY_LIST);
01696
01697 NEW_BOOL_OPTION(true);
01698 SET_BOOL_OPTION(CFG_IMPORT_AUTOSCAN_USE_INOTIFY);
01699 }
01700 else
01701 {
01702 NEW_BOOL_OPTION(false);
01703 SET_BOOL_OPTION(CFG_IMPORT_AUTOSCAN_USE_INOTIFY);
01704 }
01705 }
01706 else
01707 {
01708 NEW_BOOL_OPTION(false);
01709 SET_BOOL_OPTION(CFG_IMPORT_AUTOSCAN_USE_INOTIFY);
01710 }
01711 #endif
01712
01713 #ifdef EXTERNAL_TRANSCODING
01714 temp = getOption(
01715 _("/transcoding/attribute::enabled"),
01716 _(DEFAULT_TRANSCODING_ENABLED));
01717
01718 if (!validateYesNo(temp))
01719 throw _Exception(_("Error in config file: incorrect parameter "
01720 "for <transcoding enabled=\"\"> attribute"));
01721
01722
01723 if (temp == "yes")
01724 el = getElement(_("/transcoding"));
01725 else
01726 el = nil;
01727
01728 NEW_TRANSCODING_PROFILELIST_OPTION(createTranscodingProfileListFromNodeset(el));
01729 SET_TRANSCODING_PROFILELIST_OPTION(CFG_TRANSCODING_PROFILE_LIST);
01730
01731 #ifdef HAVE_CURL
01732 if (temp == "yes")
01733 {
01734 temp_int = getIntOption(
01735 _("/transcoding/attribute::fetch-buffer-size"),
01736 DEFAULT_CURL_BUFFER_SIZE);
01737 if (temp_int < CURL_MAX_WRITE_SIZE)
01738 throw _Exception(_("Error in config file: incorrect parameter "
01739 "for <transcoding fetch-buffer-size=\"\"> attribute, "
01740 "must be at least ") + CURL_MAX_WRITE_SIZE);
01741 NEW_INT_OPTION(temp_int);
01742 SET_INT_OPTION(CFG_EXTERNAL_TRANSCODING_CURL_BUFFER_SIZE);
01743
01744 temp_int = getIntOption(
01745 _("/transcoding/attribute::fetch-buffer-fill-size"),
01746 DEFAULT_CURL_INITIAL_FILL_SIZE);
01747 if (temp_int < 0)
01748 throw _Exception(_("Error in config file: incorrect parameter "
01749 "for <transcoding fetch-buffer-fill-size=\"\"> attribute"));
01750
01751 NEW_INT_OPTION(temp_int);
01752 SET_INT_OPTION(CFG_EXTERNAL_TRANSCODING_CURL_FILL_SIZE);
01753 }
01754
01755 #endif//HAVE_CURL
01756 #endif//EXTERNAL_TRANSCODING
01757
01758 el = getElement(_("/server/custom-http-headers"));
01759 NEW_STRARR_OPTION(createArrayFromNodeset(el, _("add"), _("header")));
01760 SET_STRARR_OPTION(CFG_SERVER_CUSTOM_HTTP_HEADERS);
01761
01762 #ifdef HAVE_LIBEXIF
01763
01764 el = getElement(_("/import/library-options/libexif/auxdata"));
01765 if (el == nil)
01766 {
01767 getOption(_("/import/library-options/libexif/auxdata"),
01768 _(""));
01769
01770 }
01771 NEW_STRARR_OPTION(createArrayFromNodeset(el, _("add-data"), _("tag")));
01772 SET_STRARR_OPTION(CFG_IMPORT_LIBOPTS_EXIF_AUXDATA_TAGS_LIST);
01773
01774 #endif // HAVE_LIBEXIF
01775
01776 #ifdef HAVE_LIBEXTRACTOR
01777
01778 el = getElement(_("/import/library-options/libextractor/auxdata"));
01779 if (el == nil)
01780 {
01781 getOption(_("/import/library-options/libextractor/auxdata"),
01782 _(""));
01783 }
01784 NEW_STRARR_OPTION(createArrayFromNodeset(el, _("add-data"), _("tag")));
01785 SET_STRARR_OPTION(CFG_IMPORT_LIBOPTS_EXTRACTOR_AUXDATA_TAGS_LIST);
01786 #endif // HAVE_LIBEXTRACTOR
01787
01788 #if defined(HAVE_ID3LIB) || defined(HAVE_TAGLIB)
01789 el = getElement(_("/import/library-options/id3/auxdata"));
01790 if (el == nil)
01791 {
01792 getOption(_("/import/library-options/id3/auxdata"), _(""));
01793 }
01794 NEW_STRARR_OPTION(createArrayFromNodeset(el, _("add-data"), _("tag")));
01795 SET_STRARR_OPTION(CFG_IMPORT_LIBOPTS_ID3_AUXDATA_TAGS_LIST);
01796 #endif
01797
01798 #if defined(HAVE_FFMPEG) && defined(HAVE_FFMPEGTHUMBNAILER)
01799 temp = getOption(_("/server/extended-runtime-options/ffmpegthumbnailer/"
01800 "attribute::enabled"),
01801 _(DEFAULT_FFMPEGTHUMBNAILER_ENABLED));
01802
01803 if (!validateYesNo(temp))
01804 throw _Exception(_("Error in config file: "
01805 "invalid \"enabled\" attribute value in "
01806 "<ffmpegthumbnailer> tag"));
01807
01808 NEW_BOOL_OPTION(temp == YES ? true : false);
01809 SET_BOOL_OPTION(CFG_SERVER_EXTOPTS_FFMPEGTHUMBNAILER_ENABLED);
01810
01811 if (temp == YES)
01812 {
01813 temp_int = getIntOption(_("/server/extended-runtime-options/ffmpegthumbnailer/"
01814 "thumbnail-size"),
01815 DEFAULT_FFMPEGTHUMBNAILER_THUMBSIZE);
01816
01817 if (temp_int <= 0)
01818 throw _Exception(_("Error in config file: ffmpegthumbnailer - "
01819 "invalid value attribute value in "
01820 "<thumbnail-size> tag"));
01821
01822 NEW_INT_OPTION(temp_int);
01823 SET_INT_OPTION(CFG_SERVER_EXTOPTS_FFMPEGTHUMBNAILER_THUMBSIZE);
01824
01825 temp_int = getIntOption(_("/server/extended-runtime-options/ffmpegthumbnailer/"
01826 "seek-percentage"),
01827 DEFAULT_FFMPEGTHUMBNAILER_SEEK_PERCENTAGE);
01828
01829 if (temp_int < 0)
01830 throw _Exception(_("Error in config file: ffmpegthumbnailer - "
01831 "invalid value attribute value in "
01832 "<seek-percentage> tag"));
01833
01834 NEW_INT_OPTION(temp_int);
01835 SET_INT_OPTION(CFG_SERVER_EXTOPTS_FFMPEGTHUMBNAILER_SEEK_PERCENTAGE);
01836
01837 temp = getOption(_("/server/extended-runtime-options/ffmpegthumbnailer/"
01838 "filmstrip-overlay"),
01839 _(DEFAULT_FFMPEGTHUMBNAILER_FILMSTRIP_OVERLAY));
01840
01841 if (!validateYesNo(temp))
01842 throw _Exception(_("Error in config file: ffmpegthumbnailer - "
01843 "invalid value in <filmstrip-overlay> tag"));
01844
01845
01846 NEW_BOOL_OPTION(temp == YES ? true : false);
01847 SET_BOOL_OPTION(CFG_SERVER_EXTOPTS_FFMPEGTHUMBNAILER_FILMSTRIP_OVERLAY);
01848
01849 temp = getOption(_("/server/extended-runtime-options/ffmpegthumbnailer/"
01850 "workaround-bugs"),
01851 _(DEFAULT_FFMPEGTHUMBNAILER_WORKAROUND_BUGS));
01852
01853 if (!validateYesNo(temp))
01854 throw _Exception(_("Error in config file: ffmpegthumbnailer - "
01855 "invalid value in <workaround-bugs> tag"));
01856
01857 NEW_BOOL_OPTION(temp == YES ? true : false);
01858 SET_BOOL_OPTION(CFG_SERVER_EXTOPTS_FFMPEGTHUMBNAILER_WORKAROUND_BUGS);
01859
01860 temp_int = getIntOption(_("/server/extended-runtime-options/"
01861 "ffmpegthumbnailer/image-quality"),
01862 DEFAULT_FFMPEGTHUMBNAILER_IMAGE_QUALITY);
01863
01864 if (temp_int < 0)
01865 throw _Exception(_("Error in config file: ffmpegthumbnailer - "
01866 "invalid value attribute value in "
01867 "<image-quality> tag, allowed values: 0-10"));
01868
01869 if (temp_int > 10)
01870 throw _Exception(_("Error in config file: ffmpegthumbnailer - "
01871 "invalid value attribute value in "
01872 "<image-quality> tag, allowed values: 0-10"));
01873
01874 NEW_INT_OPTION(temp_int);
01875 SET_INT_OPTION(CFG_SERVER_EXTOPTS_FFMPEGTHUMBNAILER_IMAGE_QUALITY);
01876 }
01877 #endif
01878
01879 temp = getOption(_("/server/extended-runtime-options/mark-played-items/"
01880 "attribute::enabled"),
01881 _(DEFAULT_MARK_PLAYED_ITEMS_ENABLED));
01882
01883 if (!validateYesNo(temp))
01884 throw _Exception(_("Error in config file: "
01885 "invalid \"enabled\" attribute value in "
01886 "<mark-played-items> tag"));
01887
01888 NEW_BOOL_OPTION(temp == YES ? true : false);
01889 SET_BOOL_OPTION(CFG_SERVER_EXTOPTS_MARK_PLAYED_ITEMS_ENABLED);
01890
01891 if (temp == YES)
01892 {
01893 temp = getOption(_("/server/extended-runtime-options/mark-played-items/"
01894 "attribute::suppress-cds-updates"),
01895 _(DEFAULT_MARK_PLAYED_ITEMS_SUPPRESS_CDS_UPDATES));
01896 if (!validateYesNo(temp))
01897 throw _Exception(_("Error in config file: "
01898 "invalid \":suppress-cds-updates\" attribute "
01899 "value in <mark-played-items> tag"));
01900
01901 NEW_BOOL_OPTION(temp == YES ? true : false);
01902 SET_BOOL_OPTION(CFG_SERVER_EXTOPTS_MARK_PLAYED_ITEMS_SUPPRESS_CDS_UPDATES);
01903
01904 temp = getOption(_("/server/extended-runtime-options/mark-played-items/"
01905 "string/attribute::mode"),
01906 _(DEFAULT_MARK_PLAYED_ITEMS_STRING_MODE));
01907
01908 if ((temp != "prepend") && (temp != "append"))
01909 throw _Exception(_("Error in config file: "
01910 "invalid \"mode\" attribute value in "
01911 "<string> tag in the <mark-played-items> section"));
01912
01913 NEW_BOOL_OPTION(temp == DEFAULT_MARK_PLAYED_ITEMS_STRING_MODE ? true : false);
01914 SET_BOOL_OPTION(CFG_SERVER_EXTOPTS_MARK_PLAYED_ITEMS_STRING_MODE_PREPEND);
01915
01916 temp = getOption(_("/server/extended-runtime-options/mark-played-items/"
01917 "string"),
01918 _(DEFAULT_MARK_PLAYED_ITEMS_STRING));
01919 if (!string_ok(temp))
01920 throw _Exception(_("Error in config file: "
01921 "empty string given for the <string> tag in the "
01922 "<mark-played-items> section"));
01923 NEW_OPTION(temp);
01924 SET_OPTION(CFG_SERVER_EXTOPTS_MARK_PLAYED_ITEMS_STRING);
01925
01926 Ref<Array<StringBase> > mark_content_list(new Array<StringBase>());
01927 tmpEl = getElement(_("/server/extended-runtime-options/mark-played-items/mark"));
01928
01929 if (tmpEl != nil)
01930 {
01931 for (int m = 0; m < tmpEl->elementChildCount(); m++)
01932 {
01933 Ref<Element> content = tmpEl->getElementChild(m);
01934 if (content->getName() != "content")
01935 continue;
01936
01937 String mark_content = content->getText();
01938 if (!string_ok(mark_content))
01939 throw _Exception(_("error in configuration, <mark-played-items>, empty <content> parameter!"));
01940
01941 if ((mark_content != DEFAULT_MARK_PLAYED_CONTENT_VIDEO) &&
01942 (mark_content != DEFAULT_MARK_PLAYED_CONTENT_AUDIO) &&
01943 (mark_content != DEFAULT_MARK_PLAYED_CONTENT_IMAGE))
01944 throw _Exception(_("error in configuration, <mark-played-items>, invalid <content> parameter! Allowed values are \"video\", \"audio\", \"image\""));
01945
01946 mark_content_list->append(mark_content);
01947 NEW_STRARR_OPTION(mark_content_list);
01948 SET_STRARR_OPTION(CFG_SERVER_EXTOPTS_MARK_PLAYED_ITEMS_CONTENT_LIST);
01949 }
01950 }
01951 }
01952
01953 #if defined(HAVE_LASTFMLIB)
01954 temp = getOption(_("/server/extended-runtime-options/lastfm/attribute::enabled"), _(DEFAULT_LASTFM_ENABLED));
01955
01956 if (!validateYesNo(temp))
01957 throw _Exception(_("Error in config file: "
01958 "invalid \"enabled\" attribute value in "
01959 "<lastfm> tag"));
01960
01961 NEW_BOOL_OPTION(temp == "yes" ? true : false);
01962 SET_BOOL_OPTION(CFG_SERVER_EXTOPTS_LASTFM_ENABLED);
01963
01964 if (temp == YES)
01965 {
01966 temp = getOption(_("/server/extended-runtime-options/lastfm/username"),
01967 _(DEFAULT_LASTFM_USERNAME));
01968
01969 if (!string_ok(temp))
01970 throw _Exception(_("Error in config file: lastfm - "
01971 "invalid username value in "
01972 "<username> tag"));
01973
01974 NEW_OPTION(temp);
01975 SET_OPTION(CFG_SERVER_EXTOPTS_LASTFM_USERNAME);
01976
01977 temp = getOption(_("/server/extended-runtime-options/lastfm/password"),
01978 _(DEFAULT_LASTFM_PASSWORD));
01979
01980 if (!string_ok(temp))
01981 throw _Exception(_("Error in config file: lastfm - "
01982 "invalid password value in "
01983 "<password> tag"));
01984
01985 NEW_OPTION(temp);
01986 SET_OPTION(CFG_SERVER_EXTOPTS_LASTFM_PASSWORD);
01987 }
01988 #endif
01989
01990
01991 #ifdef HAVE_MAGIC
01992 String magic_file;
01993 if (!string_ok(magic))
01994 {
01995 if (string_ok(getOption(_("/import/magic-file"), _(""))))
01996 {
01997 prepare_path(_("/import/magic-file"));
01998 }
01999
02000 magic_file = getOption(_("/import/magic-file"));
02001 }
02002 else
02003 magic_file = magic;
02004
02005 NEW_OPTION(magic_file);
02006 SET_OPTION(CFG_IMPORT_MAGIC_FILE);
02007 #endif
02008
02009 #ifdef HAVE_INOTIFY
02010 tmpEl = getElement(_("/import/autoscan"));
02011 Ref<AutoscanList> config_timed_list = createAutoscanListFromNodeset(tmpEl, TimedScanMode);
02012 Ref<AutoscanList> config_inotify_list = createAutoscanListFromNodeset(tmpEl, InotifyScanMode);
02013
02014 for (int i = 0; i < config_inotify_list->size(); i++)
02015 {
02016 Ref<AutoscanDirectory> i_dir = config_inotify_list->get(i);
02017 for (int j = 0; j < config_timed_list->size(); j++)
02018 {
02019 Ref<AutoscanDirectory> t_dir = config_timed_list->get(j);
02020 if (i_dir->getLocation() == t_dir->getLocation())
02021 throw _Exception(_("Error in config file: same path used in both inotify and timed scan modes"));
02022 }
02023 }
02024 #endif
02025
02026 #ifdef YOUTUBE
02027 temp = getOption(_("/import/online-content/YouTube/attribute::enabled"),
02028 _(DEFAULT_YOUTUBE_ENABLED));
02029
02030 if (!validateYesNo(temp))
02031 throw _Exception(_("Error in config file: "
02032 "invalid \"enabled\" attribute value in "
02033 "<YouTube> tag"));
02034
02035 NEW_BOOL_OPTION(temp == "yes" ? true : false);
02036 SET_BOOL_OPTION(CFG_ONLINE_CONTENT_YOUTUBE_ENABLED);
02037
02042
02043
02044 {
02045 temp = getOption(_("/import/online-content/YouTube/attribute::racy-content"),
02046 _(DEFAULT_YOUTUBE_RACY_CONTENT));
02047
02048 if ((temp != "include") && (temp != "exclude"))
02049 {
02050 throw _Exception(_("Error in config file: "
02051 "invalid racy-content value in <YouTube> tag"));
02052 }
02053
02054 NEW_OPTION(temp);
02055 SET_OPTION(CFG_ONLINE_CONTENT_YOUTUBE_RACY);
02056
02057 temp = getOption(_("/import/online-content/YouTube/attribute::format"),
02058 _(DEFAULT_YOUTUBE_FORMAT));
02059
02060 if ((temp != "mp4") && (temp != "flv"))
02061 {
02062 throw _Exception(_("Error in config file: "
02063 "invalid format value in <YouTube> tag"));
02064 }
02065 bool mp4 = (temp == "mp4" ? true : false);
02066 NEW_BOOL_OPTION(mp4);
02067 SET_BOOL_OPTION(CFG_ONLINE_CONTENT_YOUTUBE_FORMAT_MP4);
02068
02069 temp = getOption(_("/import/online-content/YouTube/attribute::hd"),
02070 _(DEFAULT_YOUTUBE_HD));
02071
02072 if (!validateYesNo(temp))
02073 throw _Exception(_("Error in config file: "
02074 "invalid hd value in <YouTube> tag"));
02075
02076 if ((temp == "yes") && (!mp4))
02077 log_warning("HD preference for YouTube content is only available for mp4 format selection!\n");
02078
02079 NEW_BOOL_OPTION(temp == "yes" ? true : false);
02080 SET_BOOL_OPTION(CFG_ONLINE_CONTENT_YOUTUBE_PREFER_HD);
02081
02082 temp_int = getIntOption(_("/import/online-content/YouTube/attribute::refresh"), DEFAULT_YOUTUBE_REFRESH);
02083 NEW_INT_OPTION(temp_int);
02084 SET_INT_OPTION(CFG_ONLINE_CONTENT_YOUTUBE_REFRESH);
02085
02086 temp_int = getIntOption(_("/import/online-content/YouTube/attribute::purge-after"), DEFAULT_YOUTUBE_PURGE_AFTER);
02087 if (getIntOption(_("/import/online-content/YouTube/attribute::refresh")) >= temp_int)
02088 {
02089 if (temp_int != 0)
02090 throw _Exception(_("Error in config file: YouTube purge-after value must be greater than refresh interval"));
02091 }
02092
02093 NEW_INT_OPTION(temp_int);
02094 SET_INT_OPTION(CFG_ONLINE_CONTENT_YOUTUBE_PURGE_AFTER);
02095
02096 temp = getOption(_("/import/online-content/YouTube/attribute::update-at-start"),
02097 _(DEFAULT_YOUTUBE_UPDATE_AT_START));
02098
02099 if (!validateYesNo(temp))
02100 throw _Exception(_("Error in config file: "
02101 "invalid \"update-at-start\" attribute value in "
02102 "<YouTube> tag"));
02103
02104 NEW_BOOL_OPTION(temp == "yes" ? true : false);
02105 SET_BOOL_OPTION(CFG_ONLINE_CONTENT_YOUTUBE_UPDATE_AT_START);
02106
02107 el = getElement(_("/import/online-content/YouTube"));
02108 if (el == nil)
02109 {
02110 getOption(_("/import/online-content/YouTube"),
02111 _(""));
02112 }
02113 Ref<Array<Object> > yt_opts = createServiceTaskList(OS_YouTube, el);
02114 if (getBoolOption(CFG_ONLINE_CONTENT_YOUTUBE_ENABLED) &&
02115 (yt_opts->size() == 0))
02116 throw _Exception(_("Error in config file: "
02117 "YouTube service enabled but no imports "
02118 "specified."));
02119
02120 NEW_OBJARR_OPTION(yt_opts);
02121 SET_OBJARR_OPTION(CFG_ONLINE_CONTENT_YOUTUBE_TASK_LIST);
02122
02123 log_warning("You enabled the YouTube feature, which allows you\n"
02124 " to watch YouTube videos on your UPnP device!\n"
02125 " Please check http://www.youtube.com/t/terms\n"
02126 " By using this feature you may be violating YouTube\n"
02127 " service terms and conditions!\n\n");
02128 }
02129 #endif
02130
02131 #ifdef SOPCAST
02132 temp = getOption(_("/import/online-content/SopCast/attribute::enabled"),
02133 _(DEFAULT_SOPCAST_ENABLED));
02134
02135 if (!validateYesNo(temp))
02136 throw _Exception(_("Error in config file: "
02137 "invalid \"enabled\" attribute value in "
02138 "<SopCast> tag"));
02139
02140 NEW_BOOL_OPTION(temp == "yes" ? true : false);
02141 SET_BOOL_OPTION(CFG_ONLINE_CONTENT_SOPCAST_ENABLED);
02142
02143 temp_int = getIntOption(_("/import/online-content/SopCast/attribute::refresh"), 0);
02144 NEW_INT_OPTION(temp_int);
02145 SET_INT_OPTION(CFG_ONLINE_CONTENT_SOPCAST_REFRESH);
02146
02147 temp_int = getIntOption(_("/import/online-content/SopCast/attribute::purge-after"), 0);
02148 if (getIntOption(_("/import/online-content/SopCast/attribute::refresh")) >= temp_int)
02149 {
02150 if (temp_int != 0)
02151 throw _Exception(_("Error in config file: SopCast purge-after value must be greater than refresh interval"));
02152 }
02153
02154 NEW_INT_OPTION(temp_int);
02155 SET_INT_OPTION(CFG_ONLINE_CONTENT_SOPCAST_PURGE_AFTER);
02156
02157 temp = getOption(_("/import/online-content/SopCast/attribute::update-at-start"),
02158 _(DEFAULT_SOPCAST_UPDATE_AT_START));
02159
02160 if (!validateYesNo(temp))
02161 throw _Exception(_("Error in config file: "
02162 "invalid \"update-at-start\" attribute value in "
02163 "<SopCast> tag"));
02164
02165 NEW_BOOL_OPTION(temp == "yes" ? true : false);
02166 SET_BOOL_OPTION(CFG_ONLINE_CONTENT_SOPCAST_UPDATE_AT_START);
02167 #endif
02168
02169 #ifdef WEBORAMA
02170 temp = getOption(_("/import/online-content/Weborama/attribute::enabled"),
02171 _(DEFAULT_WEBORAMA_ENABLED));
02172
02173 if (!validateYesNo(temp))
02174 throw _Exception(_("Error in config file: "
02175 "invalid \"enabled\" attribute value in "
02176 "<Weborama> tag"));
02177
02178 NEW_BOOL_OPTION(temp == "yes" ? true : false);
02179 SET_BOOL_OPTION(CFG_ONLINE_CONTENT_WEBORAMA_ENABLED);
02180
02181 if (temp == "yes")
02182 {
02183 el = getElement(_("/import/online-content/Weborama"));
02184 Ref<Array<Object> > wb_opts = createServiceTaskList(OS_Weborama, el);
02185 if (wb_opts->size() == 0)
02186 throw _Exception(_("Error in config file: "
02187 "Weborama service enabled but no imports "
02188 "specified."));
02189
02190 NEW_OBJARR_OPTION(wb_opts);
02191 SET_OBJARR_OPTION(CFG_ONLINE_CONTENT_WEBORAMA_TASK_LIST);
02192 }
02193
02194
02195 temp_int = getIntOption(_("/import/online-content/Weborama/attribute::refresh"), DEFAULT_WEBORAMA_REFRESH);
02196 NEW_INT_OPTION(temp_int);
02197 SET_INT_OPTION(CFG_ONLINE_CONTENT_WEBORAMA_REFRESH);
02198 SET_INT_OPTION(CFG_ONLINE_CONTENT_WEBORAMA_PURGE_AFTER);
02199
02200 temp = getOption(_("/import/online-content/Weborama/attribute::update-at-start"),
02201 _(DEFAULT_WEBORAMA_UPDATE_AT_START));
02202
02203 if (!validateYesNo(temp))
02204 throw _Exception(_("Error in config file: "
02205 "invalid \"update-at-start\" attribute value in "
02206 "<Weborama> tag"));
02207
02208 NEW_BOOL_OPTION(temp == "yes" ? true : false);
02209 SET_BOOL_OPTION(CFG_ONLINE_CONTENT_WEBORAMA_UPDATE_AT_START);
02210 #endif
02211
02212 #ifdef ATRAILERS
02213 temp = getOption(_("/import/online-content/AppleTrailers/attribute::enabled"),
02214 _(DEFAULT_ATRAILERS_ENABLED));
02215
02216 if (!validateYesNo(temp))
02217 throw _Exception(_("Error in config file: "
02218 "invalid \"enabled\" attribute value in "
02219 "<AppleTrailers> tag"));
02220
02221 NEW_BOOL_OPTION(temp == "yes" ? true : false);
02222 SET_BOOL_OPTION(CFG_ONLINE_CONTENT_ATRAILERS_ENABLED);
02223
02224 temp_int = getIntOption(_("/import/online-content/AppleTrailers/attribute::refresh"), DEFAULT_ATRAILERS_REFRESH);
02225 NEW_INT_OPTION(temp_int);
02226 SET_INT_OPTION(CFG_ONLINE_CONTENT_ATRAILERS_REFRESH);
02227 SET_INT_OPTION(CFG_ONLINE_CONTENT_ATRAILERS_PURGE_AFTER);
02228
02229 temp = getOption(_("/import/online-content/AppleTrailers/attribute::update-at-start"),
02230 _(DEFAULT_ATRAILERS_UPDATE_AT_START));
02231
02232 if (!validateYesNo(temp))
02233 throw _Exception(_("Error in config file: "
02234 "invalid \"update-at-start\" attribute value in "
02235 "<AppleTrailers> tag"));
02236
02237 NEW_BOOL_OPTION(temp == "yes" ? true : false);
02238 SET_BOOL_OPTION(CFG_ONLINE_CONTENT_ATRAILERS_UPDATE_AT_START);
02239
02240 temp = getOption(_("/import/online-content/AppleTrailers/attribute::resolution"),
02241 String::from(DEFAULT_ATRAILERS_RESOLUTION));
02242 if ((temp != "640") && (temp != "720p"))
02243 {
02244 throw _Exception(_("Error in config file: "
02245 "invalid \"resolution\" attribute value in "
02246 "<AppleTrailers> tag, only \"640\" and \"720p\" is "
02247 "supported"));
02248 }
02249
02250 NEW_OPTION(temp);
02251 SET_OPTION(CFG_ONLINE_CONTENT_ATRAILERS_RESOLUTION);
02252 #endif
02253
02254
02255
02256 log_info("Configuration check succeeded.\n");
02257
02258
02259
02260 log_debug("Config file dump after validation: \n%s\n", rootDoc->print().c_str());
02261 }
02262
02263 void ConfigManager::prepare_udn()
02264 {
02265 bool need_to_save = false;
02266
02267 if (root->getName() != "config")
02268 return;
02269
02270 Ref<Element> server = root->getChildByName(_("server"));
02271 if (server == nil)
02272 return;
02273
02274 Ref<Element> element = server->getChildByName(_("udn"));
02275 if (element == nil || element->getText() == nil || element->getText() == "")
02276 {
02277 char uuid_str[37];
02278 uuid_t uuid;
02279
02280 uuid_generate(uuid);
02281 uuid_unparse(uuid, uuid_str);
02282
02283 log_info("UUID generated: %s\n", uuid_str);
02284
02285 getOption(_("/server/udn"), _("uuid:") + uuid_str);
02286
02287 need_to_save = true;
02288 }
02289
02290 if (need_to_save)
02291 save();
02292 }
02293
02294 void ConfigManager::prepare_path(String xpath, bool needDir, bool existenceUnneeded)
02295 {
02296 String temp;
02297
02298 temp = checkOptionString(xpath);
02299
02300 temp = construct_path(temp);
02301
02302 check_path_ex(temp, needDir, existenceUnneeded);
02303
02304 Ref<Element> script = getElement(xpath);
02305 if (script != nil)
02306 script->setText(temp);
02307 }
02308
02309 void ConfigManager::save()
02310 {
02311 save_text(filename, rootDoc->print());
02312 }
02313
02314 void ConfigManager::save_text(String filename, String content)
02315 {
02316 FILE *file = fopen(filename.c_str(), "wb");
02317 if (file == NULL)
02318 {
02319 throw _Exception(_("could not open file ") +
02320 filename + " for writing : " + strerror(errno));
02321 }
02322
02323 size_t bytesWritten = fwrite(XML_HEADER, sizeof(char),
02324 strlen(XML_HEADER), file);
02325
02326 bytesWritten = fwrite(content.c_str(), sizeof(char),
02327 content.length(), file);
02328 if (bytesWritten < (size_t)content.length())
02329 {
02330 throw _Exception(_("could not write to config file ") +
02331 filename + " : " + strerror(errno));
02332 }
02333
02334 fclose(file);
02335 }
02336
02337 void ConfigManager::load(String filename)
02338 {
02339 this->filename = filename;
02340 Ref<Parser> parser(new Parser());
02341 rootDoc = parser->parseFile(filename);
02342 root = rootDoc->getRoot();
02343
02344 if (rootDoc == nil)
02345 {
02346 throw _Exception(_("Unable to parse server configuration!"));
02347 }
02348 }
02349
02350 String ConfigManager::getOption(String xpath, String def)
02351 {
02352 Ref<XPath> rootXPath(new XPath(root));
02353 String value = rootXPath->getText(xpath);
02354 if (string_ok(value))
02355 return trim_string(value);
02356
02357 log_debug("Config: option not found: %s using default value: %s\n",
02358 xpath.c_str(), def.c_str());
02359
02360 String pathPart = XPath::getPathPart(xpath);
02361 String axisPart = XPath::getAxisPart(xpath);
02362
02363 Ref<Array<StringBase> >parts = split_string(pathPart, '/');
02364
02365 Ref<Element> cur = root;
02366 String attr = nil;
02367
02368 int i;
02369 Ref<Element> child;
02370 for (i = 0; i < parts->size(); i++)
02371 {
02372 String part = parts->get(i);
02373 child = cur->getChildByName(part);
02374 if (child == nil)
02375 break;
02376 cur = child;
02377 }
02378
02379 for (; i < parts->size(); i++)
02380 {
02381 String part = parts->get(i);
02382 child = Ref<Element>(new Element(part));
02383 cur->appendElementChild(child);
02384 cur = child;
02385 }
02386
02387 if (axisPart != nil)
02388 {
02389 String axis = XPath::getAxis(axisPart);
02390 String spec = XPath::getSpec(axisPart);
02391 if (axis != "attribute")
02392 {
02393 throw _Exception(_("ConfigManager::getOption: only attribute:: axis supported"));
02394 }
02395 cur->setAttribute(spec, def);
02396 }
02397 else
02398 cur->setText(def);
02399
02400 return def;
02401 }
02402
02403 int ConfigManager::getIntOption(String xpath, int def)
02404 {
02405 String sDef;
02406
02407 sDef = String::from(def);
02408
02409 String sVal = getOption(xpath, sDef);
02410 return sVal.toInt();
02411 }
02412
02413 String ConfigManager::getOption(String xpath)
02414 {
02415 Ref<XPath> rootXPath(new XPath(root));
02416 String value = rootXPath->getText(xpath);
02417
02419
02420
02421 if (value != nil)
02422 return trim_string(value);
02423 throw _Exception(_("Config: option not found: ") + xpath);
02424 }
02425
02426 int ConfigManager::getIntOption(String xpath)
02427 {
02428 String sVal = getOption(xpath);
02429 int val = sVal.toInt();
02430 return val;
02431 }
02432
02433
02434 Ref<Element> ConfigManager::getElement(String xpath)
02435 {
02436 Ref<XPath> rootXPath(new XPath(root));
02437 return rootXPath->getElement(xpath);
02438 }
02439
02440 void ConfigManager::writeBookmark(String ip, String port)
02441 {
02442 FILE *f;
02443 String filename;
02444 String path;
02445 String data;
02446 int size;
02447
02448 if (!getBoolOption(CFG_SERVER_UI_ENABLED))
02449 {
02450 data = http_redirect_to(ip, port, _("disabled.html"));
02451 }
02452 else
02453 {
02454 data = http_redirect_to(ip, port);
02455 }
02456
02457 filename = getOption(CFG_SERVER_BOOKMARK_FILE);
02458 path = construct_path(filename);
02459
02460
02461 f = fopen(path.c_str(), "w");
02462 if (f == NULL)
02463 {
02464 throw _Exception(_("writeBookmark: failed to open: ") + path);
02465 }
02466
02467 size = fwrite(data.c_str(), sizeof(char), data.length(), f);
02468 fclose(f);
02469
02470 if (size < data.length())
02471 throw _Exception(_("write_Bookmark: failed to write to: ") + path);
02472
02473 }
02474
02475 String ConfigManager::checkOptionString(String xpath)
02476 {
02477 String temp = getOption(xpath);
02478 if (!string_ok(temp))
02479 throw _Exception(_("Config: value of ") + xpath + " tag is invalid");
02480
02481 return temp;
02482 }
02483
02484 Ref<Dictionary> ConfigManager::createDictionaryFromNodeset(Ref<Element> element, String nodeName, String keyAttr, String valAttr, bool tolower)
02485 {
02486 Ref<Dictionary> dict(new Dictionary());
02487 String key;
02488 String value;
02489
02490 if (element != nil)
02491 {
02492 for (int i = 0; i < element->elementChildCount(); i++)
02493 {
02494 Ref<Element> child = element->getElementChild(i);
02495 if (child->getName() == nodeName)
02496 {
02497 key = child->getAttribute(keyAttr);
02498 value = child->getAttribute(valAttr);
02499
02500 if (string_ok(key) && string_ok(value))
02501 {
02502 if (tolower)
02503 {
02504 key = key.toLower();
02505 }
02506 dict->put(key, value);
02507 }
02508 }
02509 }
02510 }
02511
02512 return dict;
02513 }
02514
02515 #ifdef EXTERNAL_TRANSCODING
02516 Ref<TranscodingProfileList> ConfigManager::createTranscodingProfileListFromNodeset(Ref<Element> element)
02517 {
02518 size_t bs;
02519 size_t cs;
02520 size_t fs;
02521 int itmp;
02522 transcoding_type_t tr_type;
02523 Ref<Element> mtype_profile;
02524 bool set = false;
02525 zmm::String param;
02526
02527 Ref<TranscodingProfileList> list(new TranscodingProfileList());
02528 if (element == nil)
02529 return list;
02530
02531 Ref<Array<DictionaryElement> > mt_mappings(new Array<DictionaryElement>());
02532
02533 String mt;
02534 String pname;
02535
02536 mtype_profile = element->getChildByName(_("mimetype-profile-mappings"));
02537 if (mtype_profile != nil)
02538 {
02539 for (int e = 0; e < mtype_profile->elementChildCount(); e++)
02540 {
02541 Ref<Element> child = mtype_profile->getElementChild(e);
02542 if (child->getName() == "transcode")
02543 {
02544 mt = child->getAttribute(_("mimetype"));
02545 pname = child->getAttribute(_("using"));
02546
02547 if (string_ok(mt) && string_ok(pname))
02548 {
02549 Ref<DictionaryElement> del(new DictionaryElement(mt, pname));
02550 mt_mappings->append(del);
02551 }
02552 else
02553 {
02554 throw _Exception(_("error in configuration: invalid or missing mimetype to profile mapping"));
02555 }
02556 }
02557 }
02558 }
02559
02560 Ref<Element> profiles = element->getChildByName(_("profiles"));
02561 if (profiles == nil)
02562 return list;
02563
02564 for (int i = 0; i < profiles->elementChildCount(); i++)
02565 {
02566 Ref<Element> child = profiles->getElementChild(i);
02567 if (child->getName() != "profile")
02568 continue;
02569
02570 param = child->getAttribute(_("enabled"));
02571 if (!validateYesNo(param))
02572 throw _Exception(_("Error in config file: incorrect parameter "
02573 "for <profile enabled=\"\" /> attribute"));
02574
02575 if (param == "no")
02576 continue;
02577
02578 param = child->getAttribute(_("type"));
02579 if (!string_ok(param))
02580 throw _Exception(_("error in configuration: missing transcoding type in profile"));
02581
02582 if (param == "external")
02583 tr_type = TR_External;
02584
02585
02586
02587
02588 else
02589 throw _Exception(_("error in configuration: invalid transcoding type ") + param + _(" in profile"));
02590
02591 param = child->getAttribute(_("name"));
02592 if (!string_ok(param))
02593 throw _Exception(_("error in configuration: invalid transcoding profile name"));
02594
02595 Ref<TranscodingProfile> prof(new TranscodingProfile(tr_type, param));
02596
02597 param = child->getChildText(_("mimetype"));
02598 if (!string_ok(param))
02599 throw _Exception(_("error in configuration: invalid target mimetype in transcoding profile"));
02600 prof->setTargetMimeType(param);
02601
02602 if (child->getChildByName(_("resolution")) != nil)
02603 {
02604 param = child->getChildText(_("resolution"));
02605 if (string_ok(param))
02606 {
02607 if (check_resolution(param))
02608 prof->addAttribute(MetadataHandler::getResAttrName(R_RESOLUTION), param);
02609 }
02610 }
02611
02612 Ref<Element> avi_fcc = child->getChildByName(_("avi-fourcc-list"));
02613 if (avi_fcc != nil)
02614 {
02615 String mode = avi_fcc->getAttribute(_("mode"));
02616 if (!string_ok(mode))
02617 throw _Exception(_("error in configuration: avi-fourcc-list requires a valid \"mode\" attribute"));
02618
02619 avi_fourcc_listmode_t fcc_mode;
02620 if (mode == "ignore")
02621 fcc_mode = FCC_Ignore;
02622 else if (mode == "process")
02623 fcc_mode = FCC_Process;
02624 else if (mode == "disabled")
02625 fcc_mode = FCC_None;
02626 else
02627 throw _Exception(_("error in configuration: invalid mode given for avi-fourcc-list: \"") + mode + _("\""));
02628
02629 if (fcc_mode != FCC_None)
02630 {
02631 Ref<Array<StringBase> > fcc_list(new Array<StringBase>());
02632 for (int f = 0; f < avi_fcc->elementChildCount(); f++)
02633 {
02634 Ref<Element> fourcc = avi_fcc->getElementChild(f);
02635 if (fourcc->getName() != "fourcc")
02636 continue;
02637
02638 String fcc = fourcc->getText();
02639 if (!string_ok(fcc))
02640 throw _Exception(_("error in configuration: empty fourcc specified!"));
02641 fcc_list->append(fcc);
02642 }
02643
02644 prof->setAVIFourCCList(fcc_list, fcc_mode);
02645 }
02646 }
02647
02648 if (child->getChildByName(_("accept-url")) != nil)
02649 {
02650 param = child->getChildText(_("accept-url"));
02651 if (!validateYesNo(param))
02652 throw _Exception(_("Error in config file: incorrect parameter "
02653 "for <accept-url> tag"));
02654 if (param == "yes")
02655 prof->setAcceptURL(true);
02656 else
02657 prof->setAcceptURL(false);
02658 }
02659
02660 if (child->getChildByName(_("sample-frequency")) != nil)
02661 {
02662 param = child->getChildText(_("sample-frequency"));
02663 if (param == "source")
02664 prof->setSampleFreq(SOURCE);
02665 else if (param == "off")
02666 prof->setSampleFreq(OFF);
02667 else
02668 {
02669 int freq = param.toInt();
02670 if (freq <= 0)
02671 throw _Exception(_("Error in config file: incorrect "
02672 "parameter for <sample-frequency> "
02673 "tag"));
02674
02675 prof->setSampleFreq(freq);
02676 }
02677 }
02678
02679 if (child->getChildByName(_("audio-channels")) != nil)
02680 {
02681 param = child->getChildText(_("audio-channels"));
02682 if (param == "source")
02683 prof->setNumChannels(SOURCE);
02684 else if (param == "off")
02685 prof->setNumChannels(OFF);
02686 else
02687 {
02688 int chan = param.toInt();
02689 if (chan <= 0)
02690 throw _Exception(_("Error in config file: incorrect "
02691 "parameter for <number-of-channels> "
02692 "tag"));
02693 prof->setNumChannels(chan);
02694 }
02695 }
02696
02697 if (child->getChildByName(_("hide-original-resource")) != nil)
02698 {
02699 param = child->getChildText(_("hide-original-resource"));
02700 if (!validateYesNo(param))
02701 throw _Exception(_("Error in config file: incorrect parameter "
02702 "for <hide-original-resource> tag"));
02703 if (param == "yes")
02704 prof->setHideOriginalResource(true);
02705 else
02706 prof->setHideOriginalResource(false);
02707 }
02708
02709 if (child->getChildByName(_("dvd-only")) != nil)
02710 {
02711 param = child->getChildText(_("dvd-only"));
02712 if (!validateYesNo(param))
02713 throw _Exception(_("Error in config file: incorrect parameter "
02714 "for <dvd-only> tag"));
02715 if (param == "yes")
02716 prof->setOnlyDVD(true);
02717 else
02718 prof->setOnlyDVD(false);
02719 }
02720
02721 if (child->getChildByName(_("accept-dvd-mpeg")) != nil)
02722 {
02723 param = child->getChildText(_("accept-dvd-mpeg"));
02724 if (!validateYesNo(param))
02725 throw _Exception(_("Error in config file: incorrect parameter "
02726 "for <accept-dvd-mpeg> tag"));
02727 if (param == "yes")
02728 prof->setTheora(true);
02729 else
02730 prof->setTheora(false);
02731
02732 }
02733
02734 if (child->getChildByName(_("thumbnail")) != nil)
02735 {
02736 param = child->getChildText(_("thumbnail"));
02737 if (!validateYesNo(param))
02738 throw _Exception(_("Error in config file: incorrect parameter "
02739 "for <thumbnail> tag"));
02740 if (param == "yes")
02741 prof->setThumbnail(true);
02742 else
02743 prof->setThumbnail(false);
02744 }
02745
02746 if (child->getChildByName(_("first-resource")) != nil)
02747 {
02748 param = child->getChildText(_("first-resource"));
02749 if (!validateYesNo(param))
02750 throw _Exception(_("Error in config file: incorrect parameter "
02751 "for <profile first-resource=\"\" /> attribute"));
02752
02753 if (param == "yes")
02754 prof->setFirstResource(true);
02755 else
02756 prof->setFirstResource(false);
02757 }
02758
02759 if (child->getChildByName(_("use-chunked-encoding")) != nil)
02760 {
02761 param = child->getChildText(_("use-chunked-encoding"));
02762 if (!validateYesNo(param))
02763 throw _Exception(_("Error in config file: incorrect parameter "
02764 "for use-chunked-encoding tag"));
02765
02766 if (param == "yes")
02767 prof->setChunked(true);
02768 else
02769 prof->setChunked(false);
02770 }
02771
02772 Ref<Element> sub = child->getChildByName(_("agent"));
02773 if (sub == nil)
02774 throw _Exception(_("error in configuration: transcoding "
02775 "profile \"") + prof->getName() +
02776 "\" is missing the <agent> option");
02777
02778 param = sub->getAttribute(_("command"));
02779 if (!string_ok(param))
02780 throw _Exception(_("error in configuration: transcoding "
02781 "profile \"") + prof->getName() +
02782 "\" has an invalid command setting");
02783 prof->setCommand(param);
02784
02785 String tmp_path;
02786 if (param.startsWith(_(_DIR_SEPARATOR)))
02787 {
02788 if (!check_path(param))
02789 throw _Exception(_("error in configuration, transcoding "
02790 "profile \"") + prof->getName() +
02791 "\" could not find transcoding command " + param);
02792 tmp_path = param;
02793 }
02794 else
02795 {
02796 tmp_path = find_in_path(param);
02797 if (!string_ok(tmp_path))
02798 throw _Exception(_("error in configuration, transcoding "
02799 "profile \"") + prof->getName() +
02800 "\" could not find transcoding command " + param +
02801 " in $PATH");
02802 }
02803
02804 int err = 0;
02805 if (!is_executable(tmp_path, &err))
02806 throw _Exception(_("error in configuration, transcoding "
02807 "profile ") + prof->getName() +
02808 ": transcoder " + param +
02809 "is not executable - " + strerror(err));
02810
02811 param = sub->getAttribute(_("arguments"));
02812 if (!string_ok(param))
02813 throw _Exception(_("error in configuration: transcoding profile ") +
02814 prof->getName() + " has an empty argument string");
02815
02816 prof->setArguments(param);
02817
02818 sub = child->getChildByName(_("buffer"));
02819 if (sub == nil)
02820 throw _Exception(_("error in configuration: transcoding "
02821 "profile \"") + prof->getName() +
02822 "\" is missing the <buffer> option");
02823
02824 param = sub->getAttribute(_("size"));
02825 if (!string_ok(param))
02826 throw _Exception(_("error in configuration: transcoding "
02827 "profile \"") + prof->getName() +
02828 "\" <buffer> tag is missing the size attribute");
02829 itmp = param.toInt();
02830 if (itmp < 0)
02831 throw _Exception(_("error in configuration: transcoding "
02832 "profile \"") + prof->getName() +
02833 "\" buffer size can not be negative");
02834 bs = itmp;
02835
02836 param = sub->getAttribute(_("chunk-size"));
02837 if (!string_ok(param))
02838 throw _Exception(_("error in configuration: transcoding "
02839 "profile \"") + prof->getName() +
02840 "\" <buffer> tag is missing the chunk-size "
02841 "attribute");
02842 itmp = param.toInt();
02843 if (itmp < 0)
02844 throw _Exception(_("error in configuration: transcoding "
02845 "profile \"") + prof->getName() +
02846 "\" chunk size can not be negative");
02847 cs = itmp;
02848
02849 if (cs > bs)
02850 throw _Exception(_("error in configuration: transcoding "
02851 "profile \"") + prof->getName() +
02852 "\" chunk size can not be greater than "
02853 "buffer size");
02854
02855 param = sub->getAttribute(_("fill-size"));
02856 if (!string_ok(param))
02857 throw _Exception(_("error in configuration: transcoding "
02858 "profile \"") + prof->getName() +
02859 "\" <buffer> tag is missing the fill-size "
02860 "attribute");
02861 itmp = param.toInt();
02862 if (i < 0)
02863 throw _Exception(_("error in configuration: transcoding "
02864 "profile \"") + prof->getName() +
02865 "\" fill size can not be negative");
02866 fs = itmp;
02867
02868 if (fs > bs)
02869 throw _Exception(_("error in configuration: transcoding "
02870 "profile \"") + prof->getName() +
02871 "\" fill size can not be greater than "
02872 "buffer size");
02873
02874 prof->setBufferOptions(bs, cs, fs);
02875
02876 if (mtype_profile == nil)
02877 {
02878 throw _Exception(_("error in configuration: transcoding "
02879 "profiles exist, but no mimetype to profile "
02880 "mappings specified"));
02881 }
02882
02883 for (int k = 0; k < mt_mappings->size(); k++)
02884 {
02885 if (mt_mappings->get(k)->getValue() == prof->getName())
02886 {
02887 list->add(mt_mappings->get(k)->getKey(), prof);
02888 set = true;
02889 }
02890 }
02891
02892 if (!set)
02893 throw _Exception(_("error in configuration: you specified"
02894 "a mimetype to transcoding profile mapping, "
02895 "but no match for profile \"") +
02896 prof->getName() + "\" exists");
02897 else
02898 set = false;
02899 }
02900
02901 return list;
02902 }
02903 #endif//TRANSCODING
02904
02905 Ref<AutoscanList> ConfigManager::createAutoscanListFromNodeset(zmm::Ref<mxml::Element> element, scan_mode_t scanmode)
02906 {
02907 Ref<AutoscanList> list(new AutoscanList());
02908 String location;
02909 String temp;
02910 scan_level_t level;
02911 scan_mode_t mode;
02912 bool recursive;
02913 bool hidden;
02914 unsigned int interval;
02915
02916 if (element == nil)
02917 return list;
02918
02919 for (int i = 0; i < element->elementChildCount(); i++)
02920 {
02921 hidden = false;
02922 recursive = false;
02923
02924 Ref<Element> child = element->getElementChild(i);
02925 if (child->getName() == "directory")
02926 {
02927 location = child->getAttribute(_("location"));
02928 if (!string_ok(location))
02929 {
02930 throw _Exception(_("autoscan directory with invalid location!\n"));
02931 }
02932
02933 try
02934 {
02935 location = normalizePath(location);
02936 }
02937 catch (Exception e)
02938 {
02939 throw _Exception(_("autoscan directory \"") +
02940 location + "\": " + e.getMessage());
02941 }
02942
02943 if (check_path(location, false))
02944 {
02945 throw _Exception(_("autoscan ") + location +
02946 " - not a directory!");
02947 }
02948
02949 temp = child->getAttribute(_("mode"));
02950 if (!string_ok(temp) || ((temp != "timed") && (temp != "inotify")))
02951 {
02952 throw _Exception(_("autoscan directory ") + location +
02953 ": mode attribute is missing or invalid");
02954 }
02955 else if (temp == "timed")
02956 {
02957 mode = TimedScanMode;
02958 }
02959 else
02960 mode = InotifyScanMode;
02961
02962 if (mode != scanmode)
02963 continue;
02964
02965 interval = 0;
02966 if (mode == TimedScanMode)
02967 {
02968 temp = child->getAttribute(_("level"));
02969 if (!string_ok(temp))
02970 {
02971 throw _Exception(_("autoscan directory ") +
02972 location +
02973 ": level attribute is missing or invalid");
02974 }
02975 else
02976 {
02977 if (temp == "basic")
02978 level = BasicScanLevel;
02979 else if (temp == "full")
02980 level = FullScanLevel;
02981 else
02982 {
02983 throw _Exception(_("autoscan directory ")
02984 + location + ": level attribute " +
02985 temp + "is invalid");
02986 }
02987 }
02988
02989 temp = child->getAttribute(_("interval"));
02990 if (!string_ok(temp))
02991 {
02992 throw _Exception(_("autoscan directory ")
02993 + location +
02994 ": interval attribute is required for timed mode");
02995 }
02996
02997 interval = temp.toUInt();
02998
02999 if (interval == 0)
03000 {
03001 throw _Exception(_("autoscan directory ") +
03002 location + ": invalid interval attribute");
03003 continue;
03004 }
03005 }
03006
03007
03008 else
03009 level = FullScanLevel;
03010
03011 temp = child->getAttribute(_("recursive"));
03012 if (!string_ok(temp))
03013 {
03014 throw _Exception(_("autoscan directory ") + location +
03015 ": recursive attribute is missing or invalid");
03016 }
03017 else
03018 {
03019 if (temp == "yes")
03020 recursive = true;
03021 else if (temp == "no")
03022 recursive = false;
03023 else
03024 {
03025 throw _Exception(_("autoscan directory ") + location
03026 + ": recusrive attribute " + temp + " is invalid");
03027 }
03028 }
03029
03030 temp = child->getAttribute(_("hidden-files"));
03031 if (!string_ok(temp))
03032 {
03033 temp = getOption(_("/import/attribute::hidden-files"));
03034 }
03035
03036 if (temp == "yes")
03037 hidden = true;
03038 else if (temp == "no")
03039 hidden = false;
03040 else
03041 {
03042 throw _Exception(_("autoscan directory ") + location +
03043 ": hidden attribute " + temp + " is invalid");
03044 }
03045
03046 temp = child->getAttribute(_("interval"));
03047 interval = 0;
03048 if (mode == TimedScanMode)
03049 {
03050 if (!string_ok(temp))
03051 {
03052 throw _Exception(_("autoscan directory ")
03053 + location +
03054 ": interval attribute is required for timed mode");
03055 }
03056
03057 interval = temp.toUInt();
03058
03059 if (interval == 0)
03060 {
03061 throw _Exception(_("autoscan directory ") +
03062 location + ": invalid interval attribute");
03063 }
03064 }
03065
03066 Ref<AutoscanDirectory> dir(new AutoscanDirectory(location, mode, level, recursive, true, -1, interval, hidden));
03067 try
03068 {
03069 list->add(dir);
03070 }
03071 catch (Exception e)
03072 {
03073 throw _Exception(_("Could not add ") + location + ": "
03074 + e.getMessage());
03075 }
03076 }
03077 }
03078
03079 return list;
03080 }
03081
03082 void ConfigManager::dumpOptions()
03083 {
03084 #ifdef TOMBDEBUG
03085 log_debug("Dumping options!\n");
03086 for (int i = 0; i < (int)CFG_MAX; i++)
03087 {
03088 try
03089 {
03090 log_debug(" Option %02d - %s\n", i,
03091 getOption((config_option_t)i).c_str());
03092 }
03093 catch (Exception e) {}
03094 try
03095 {
03096 log_debug(" IntOption %02d - %d\n", i,
03097 getIntOption((config_option_t)i));
03098 }
03099 catch (Exception e) {}
03100 try
03101 {
03102 log_debug("BoolOption %02d - %s\n", i,
03103 (getBoolOption((config_option_t)i) ? "true" : "false"));
03104 }
03105 catch (Exception e) {}
03106 }
03107 #endif
03108 }
03109
03110 Ref<Array<StringBase> > ConfigManager::createArrayFromNodeset(Ref<mxml::Element> element, String nodeName, String attrName)
03111 {
03112 String attrValue;
03113 Ref<Array<StringBase> > arr(new Array<StringBase>());
03114
03115 if (element != nil)
03116 {
03117 for (int i = 0; i < element->elementChildCount(); i++)
03118 {
03119 Ref<Element> child = element->getElementChild(i);
03120 if (child->getName() == nodeName)
03121 {
03122 attrValue = child->getAttribute(attrName);
03123
03124 if (string_ok(attrValue))
03125 arr->append(attrValue);
03126 }
03127 }
03128 }
03129
03130 return arr;
03131 }
03132
03133
03134
03135 String ConfigManager::getOption(config_option_t option)
03136 {
03137 return options->get(option)->getOption();
03138 }
03139
03140 int ConfigManager::getIntOption(config_option_t option)
03141 {
03142 return options->get(option)->getIntOption();
03143 }
03144
03145 bool ConfigManager::getBoolOption(config_option_t option)
03146 {
03147 return options->get(option)->getBoolOption();
03148 }
03149
03150 Ref<Dictionary> ConfigManager::getDictionaryOption(config_option_t option)
03151 {
03152 return options->get(option)->getDictionaryOption();
03153 }
03154
03155 Ref<Array<StringBase> > ConfigManager::getStringArrayOption(config_option_t option)
03156 {
03157 return options->get(option)->getStringArrayOption();
03158 }
03159
03160 Ref<ObjectDictionary<zmm::Object> > ConfigManager::getObjectDictionaryOption(config_option_t option)
03161 {
03162 return options->get(option)->getObjectDictionaryOption();
03163 }
03164
03165 #ifdef ONLINE_SERVICES
03166 Ref<Array<Object> > ConfigManager::getObjectArrayOption(config_option_t option)
03167 {
03168 return options->get(option)->getObjectArrayOption();
03169 }
03170 #endif
03171
03172 Ref<AutoscanList> ConfigManager::getAutoscanListOption(config_option_t option)
03173 {
03174 return options->get(option)->getAutoscanListOption();
03175 }
03176
03177 #ifdef EXTERNAL_TRANSCODING
03178 Ref<TranscodingProfileList> ConfigManager::getTranscodingProfileListOption(config_option_t option)
03179 {
03180 return options->get(option)->getTranscodingProfileListOption();
03181 }
03182 #endif
03183
03184 #ifdef ONLINE_SERVICES
03185 Ref<Array<Object> > ConfigManager::createServiceTaskList(service_type_t service,
03186 Ref<Element> element)
03187 {
03188 Ref<Array<Object> > arr(new Array<Object>());
03189
03190 if (element == nil)
03191 return arr;
03192 #ifdef YOUTUBE
03193 if (service == OS_YouTube)
03194 {
03195 Ref<YouTubeService> yt(new YouTubeService());
03196 for (int i = 0; i < element->elementChildCount(); i++)
03197 {
03198 Ref<Object> option = yt->defineServiceTask(element->getElementChild(i), RefCast(options->get(CFG_ONLINE_CONTENT_YOUTUBE_RACY), Object));
03199 arr->append(option);
03200 }
03201 }
03202 #endif
03203 #ifdef WEBORAMA
03204 if (service == OS_Weborama)
03205 {
03206 Ref<WeboramaService> wb(new WeboramaService());
03207 for (int i = 0; i < element->elementChildCount(); i++)
03208 {
03209
03210 Ref<Option> stropt(new Option(element->getAttribute(_("userid"))));
03211
03212 Ref<Object> option = wb->defineServiceTask(element->getElementChild(i), RefCast(stropt, Object));
03213 arr->append(option);
03214 }
03215 }
03216 #endif
03217 return arr;
03218 }
03219 #endif