MythTV  0.25-pre
util.cpp
Go to the documentation of this file.
00001 
00002 #include "util.h"
00003 
00004 // C++ headers
00005 #include <iostream>
00006 
00007 using namespace std;
00008 
00009 // C headers
00010 #include <cerrno>
00011 #include <stdlib.h>
00012 #include <time.h>
00013 
00014 // POSIX
00015 #include <unistd.h>
00016 #include <fcntl.h>
00017 #include <sched.h>
00018 
00019 // System specific C headers
00020 #include "compat.h"
00021 
00022 #ifdef linux
00023 #include <sys/vfs.h>
00024 #include <sys/sysinfo.h>
00025 #endif
00026 
00027 #if CONFIG_DARWIN
00028 #include <mach/mach.h>
00029 #endif
00030 
00031 #ifdef BSD
00032 #include <sys/mount.h>  // for struct statfs
00033 #include <sys/sysctl.h>
00034 #endif
00035 
00036 // Qt headers
00037 #include <QReadWriteLock>
00038 #include <QNetworkProxy>
00039 #include <QFileInfo>
00040 #include <QFile>
00041 #include <QDir>
00042 #include <QUrl>
00043 
00044 // Myth headers
00045 #include "mythcorecontext.h"
00046 #include "exitcodes.h"
00047 #include "mythlogging.h"
00048 #include "msocketdevice.h"
00049 #include "mythsocket.h"
00050 #include "mythcoreutil.h"
00051 #include "mythsystem.h"
00052 
00053 #include "mythconfig.h" // for CONFIG_DARWIN
00054 
00058 QDateTime mythCurrentDateTime()
00059 {
00060     QDateTime rettime = QDateTime::currentDateTime();
00061     QTime orig = rettime.time();
00062     rettime.setTime(orig.addMSecs(-orig.msec()));
00063     return rettime;
00064 }
00065 
00066 QDateTime myth_dt_from_string(const QString &dtstr)
00067 {
00068     if (dtstr.isEmpty())
00069         return QDateTime();
00070 
00071     if (!dtstr.contains("-") && dtstr.length() == 14)
00072     {
00073         // must be in yyyyMMddhhmmss format
00074         return QDateTime::fromString(dtstr, "yyyyMMddhhmmss");
00075     }
00076 
00077     return QDateTime::fromString(dtstr, Qt::ISODate);
00078 }
00079 
00086 QString MythDateTimeToString(const QDateTime& datetime, uint format)
00087 {
00088     QString result;
00089 
00090     if (format & (kDateFull | kDateShort))
00091         result += MythDateToString(datetime.date(), format);
00092 
00093     if (format & kTime)
00094     {
00095         if (!result.isEmpty())
00096             result.append(", ");
00097         
00098         result += MythTimeToString(datetime.time(), format);
00099     }
00100     
00101     return result;
00102 }
00103 
00110 QString MythDateToString(const QDate& date, uint format)
00111 {
00112     QString result;
00113 
00114     if (format & (kDateFull | kDateShort))
00115     {
00116         QDate now = QDate::currentDate();
00117 
00118         QString stringformat;
00119         if (format & kDateShort)
00120             stringformat = gCoreContext->GetSetting("ShortDateFormat", "ddd d");
00121         else
00122             stringformat = gCoreContext->GetSetting("DateFormat", "ddd d MMMM");
00123         
00124         if (format & kAddYear)
00125         {
00126             if (!stringformat.contains("yy")) // Matches both 2 or 4 digit year
00127                 stringformat.append(" yyyy");
00128         }
00129         
00130         if (format & ~kDateShort)
00131         {
00132             if ((format & kSimplify) && (now == date))
00133                 result = QObject::tr("Today");
00134             else if ((format & kSimplify) && (now.addDays(-1) == date))
00135                 result = QObject::tr("Yesterday");
00136             else if ((format & kSimplify) && (now.addDays(1) == date))
00137                 result = QObject::tr("Tomorrow");
00138         }
00139         
00140         if (result.isEmpty())
00141             result = date.toString(stringformat);
00142     }
00143     
00144     return result;
00145 }
00146 
00153 QString MythTimeToString(const QTime& time, uint format)
00154 {
00155     QString result;
00156 
00157     if (format & kTime)
00158     {
00159         QString timeformat = gCoreContext->GetSetting("TimeFormat", "h:mm AP");
00160         result = time.toString(timeformat);
00161     }    
00162     
00163     return result;
00164 }
00165 
00166 int calc_utc_offset(void)
00167 {
00168     QDateTime loc = QDateTime::currentDateTime();
00169     QDateTime utc = QDateTime::currentDateTime().toUTC();
00170 
00171     int utc_offset = MythSecsTo(utc, loc);
00172 
00173     // clamp to nearest minute if within 10 seconds
00174     int off = utc_offset % 60;
00175     if (abs(off) < 10)
00176         utc_offset -= off;
00177     if (off < -50 && off > -60)
00178         utc_offset -= 60 + off;
00179     if (off > +50 && off < +60)
00180         utc_offset += 60 - off;
00181 
00182     return utc_offset;
00183 }
00184 
00185 static bool compare_zone_files(QFileInfo first_file_info,
00186                                QFileInfo second_file_info)
00187 {
00188     if (!first_file_info.isFile() || !second_file_info.isFile() ||
00189         !first_file_info.isReadable() || !second_file_info.isReadable())
00190         return false;
00191 
00192     qint64 first_file_size = first_file_info.size();
00193     // sanity check - zoneinfo files should typically be less than
00194     // about 4kB, but leave room for growth
00195     if ((first_file_size > 200 * 1024) ||
00196         (second_file_info.size() != first_file_size))
00197         return false;
00198 
00199     QFile first_file(first_file_info.absoluteFilePath());
00200     QByteArray first_file_data;
00201     first_file_data.resize(first_file_size);
00202     QFile second_file(second_file_info.absoluteFilePath());
00203     QByteArray second_file_data;
00204     second_file_data.resize(first_file_size);
00205     if (first_file.open(QIODevice::ReadOnly))
00206     {
00207         QDataStream in(&first_file);
00208         if (in.readRawData(first_file_data.data(),
00209                            first_file_size) != first_file_size)
00210         {
00211             first_file.close();
00212             return false;
00213         }
00214         first_file.close();
00215     }
00216     if (second_file.open(QIODevice::ReadOnly))
00217     {
00218         QDataStream in(&second_file);
00219         if (in.readRawData(second_file_data.data(),
00220                            first_file_size) != first_file_size)
00221         {
00222             second_file.close();
00223             return false;
00224         }
00225         second_file.close();
00226     }
00227     if (first_file_data == second_file_data)
00228         return true;
00229 
00230     return false;
00231 }
00232 
00233 #ifndef USING_MINGW
00234 /* Helper function for getSystemTimeZoneID() that compares the
00235    zoneinfo_file_path (regular) file with files in the zoneinfo_dir_path until
00236    it finds a match.  The matching file's name is used to determine the time
00237    zone ID. */
00238 static QString findZoneinfoFile(QString zoneinfo_file_path,
00239                                 QString zoneinfo_dir_path)
00240 {
00241     QString zone_id("UNDEF");
00242     QDir zoneinfo_dir(zoneinfo_dir_path);
00243     QFileInfoList dirlist = zoneinfo_dir.entryInfoList();
00244     QFileInfo info;
00245     QString basename;
00246     QFileInfo zoneinfo_file_info(zoneinfo_file_path);
00247 
00248     for (QFileInfoList::const_iterator it = dirlist.begin();
00249          it != dirlist.end(); ++it)
00250     {
00251         info = *it;
00252          // Skip '.' and '..' and other files starting with "." and
00253          // skip localtime (which is often a link to zoneinfo_file_path)
00254         basename = info.baseName();
00255         if (basename.isEmpty() || (basename == "localtime")) {
00256             continue;
00257         }
00258         if (info.isDir())
00259         {
00260             zone_id = findZoneinfoFile(zoneinfo_file_path,
00261                                        info.absoluteFilePath());
00262             if (zone_id != "UNDEF")
00263                 return zone_id;
00264         }
00265         else if (compare_zone_files(zoneinfo_file_info, info))
00266         {
00267             zone_id = info.absoluteFilePath();
00268             break;
00269         }
00270     }
00271     return zone_id;
00272 }
00273 #endif
00274 
00275 /* helper fuction to find the zone ID in a configuration string
00276    allows NIS-format /etc/timezone , which contains extra information:
00277    <time zone ID> <host or NIS domain name> # optional comments
00278 */
00279 static bool parse_zone_id_config_string(QString& zone_id)
00280 {
00281     bool found = false;
00282     QString zoneinfo_dir_path("/usr/share/zoneinfo/");
00283     QRegExp sep("\\s+");
00284     QFileInfo file_info;
00285 
00286     while (!found)
00287     {
00288         QString temp_zone_id = zone_id;
00289         temp_zone_id.replace(' ', '_');
00290         file_info.setFile(zoneinfo_dir_path + temp_zone_id);
00291         if (file_info.exists())
00292         {
00293             found = true;
00294         }
00295         else
00296         {
00297             zone_id = zone_id.section(sep, 0, -2);
00298             if (zone_id.isEmpty())
00299                 break;
00300         }
00301     }
00302     return found;
00303 }
00304 
00305 /* helper fuction to read time zone id from a file
00306    Debian's /etc/timezone or Red Hat's /etc/sysconfig/clock */
00307 static bool read_time_zone_id(QString filename, QString& zone_id)
00308 {
00309     bool found = false;
00310     QFile file(filename);
00311     QFileInfo info(file);
00312     if (info.exists() && info.isFile() && info.isReadable())
00313     {
00314         if (file.open(QIODevice::ReadOnly | QIODevice::Text))
00315         {
00316             QString line;
00317             QTextStream in(&file);
00318             // Handle whitespace and quotes
00319             QRegExp re("^(?:ZONE\\s*=)?\\s*(['\"]?)([\\w\\s/-\\+]+)\\1\\s*(?:#.*)?$");
00320             re.setPatternSyntax(QRegExp::RegExp2);
00321             while (!in.atEnd())
00322             {
00323                 line = in.readLine();
00324                 if (re.indexIn(line) != -1)
00325                 {
00326                     zone_id = re.cap(2);
00327                     if (parse_zone_id_config_string(zone_id))
00328                         found = true;
00329                     break;
00330                 }
00331             }
00332             file.close();
00333         }
00334     }
00335     return found;
00336 }
00337 
00338 /* Helper function for getTimeZoneID() that provides an unprocessed time zone
00339    id obtained using system-dependent means of identifying the system's time
00340    zone. */
00341 static QString getSystemTimeZoneID(void)
00342 {
00343     QString zone_id("UNDEF");
00344 #ifdef USING_MINGW
00345     // typedef struct _TIME_ZONE_INFORMATION { ...
00346     // GetTimeZoneInformation();
00347     // ...
00348     // Sadly, Windows zone names are different to the (probably Unix)
00349     // backend's names - "AUS Eastern Standard Time" vs "Australia/Sydney".
00350     // Translation is not worthwhile. Leave it as UNDEF to check the offset.
00351 #else
00352     // Try to determine the time zone information by inspecting the system
00353     // configuration
00354     QString time_zone_file_path("/etc/timezone");
00355     QString clock_file_path("/etc/sysconfig/clock");
00356     QString zoneinfo_file_path("/etc/localtime");
00357     QString zoneinfo_dir_path("/usr/share/zoneinfo");
00358 
00359     // First, check time_zone_file_path (used by Debian-based systems)
00360     if (read_time_zone_id(time_zone_file_path, zone_id))
00361         return zone_id;
00362 
00363     // Next, look for the ZONE entry in clock_file_path (used by Red Hat-based
00364     // systems)
00365     if (read_time_zone_id(clock_file_path, zone_id))
00366         return zone_id;
00367 
00368     // Next check zoneinfo_file_path
00369     QFile zoneinfo_file(zoneinfo_file_path);
00370     QFileInfo info(zoneinfo_file);
00371 
00372     if (info.exists() && info.isFile())
00373     {
00374         QString tz;
00375         if (info.isSymLink())
00376         {
00377             // The symlink refers to a file whose name contains the zone ID
00378             tz = info.symLinkTarget();
00379         }
00380         else
00381         {
00382             // The zoneinfo_file is a copy of the file in the
00383             // zoneinfo_dir_path, so search for the same file in
00384             // zoneinfo_dir_path
00385             tz = findZoneinfoFile(zoneinfo_file_path, zoneinfo_dir_path);
00386         }
00387         if (tz != "UNDEF")
00388         {
00389             int pos = 0;
00390             // Get the zone ID from the filename
00391             // Look for the basename of zoneinfo_dir_path in case it's a
00392             // relative link
00393             QString zoneinfo_dirname = zoneinfo_dir_path.section('/', -1);
00394             if ((pos = tz.indexOf(zoneinfo_dirname)) != -1)
00395             {
00396                 zone_id = tz.right(tz.size() - (pos + 1) -
00397                                    zoneinfo_dirname.size());
00398             }
00399         }
00400         else
00401         {
00402             // If we still haven't found a time zone, try localtime_r() to at
00403             // least get the zone name/abbreviation (as opposed to the
00404             // identifier for the set of rules governing the zone)
00405             char name[64];
00406             time_t t;
00407             struct tm *result = (struct tm *)malloc(sizeof(*result));
00408 
00409             if (result != NULL)
00410             {
00411                 t = time(NULL);
00412                 localtime_r(&t, result);
00413                 if (result != NULL)
00414                 {
00415                     if (strftime(name, sizeof(name), "%Z", result) > 0)
00416                         zone_id = name;
00417                     free(result);
00418                 }
00419             }
00420         }
00421     }
00422 
00423 #endif
00424     return zone_id;
00425 }
00426 
00431 QString getTimeZoneID(void)
00432 {
00433     QString zone_id("UNDEF");
00434 #ifndef USING_MINGW
00435     // First, try the TZ environment variable to check for environment-specific
00436     // overrides
00437     QString tz = getenv("TZ");
00438     if (tz.isEmpty())
00439     {
00440         // No TZ, so attempt to determine the system-configured time zone ID
00441         tz = getSystemTimeZoneID();
00442     }
00443 
00444     if (!tz.isEmpty())
00445     {
00446         zone_id = tz;
00447         if (zone_id.startsWith("\"") || zone_id.startsWith("'"))
00448                 zone_id.remove(0, 1);
00449         if (zone_id.endsWith("\"") || zone_id.endsWith("'"))
00450                 zone_id.chop(1);
00451         if (zone_id.startsWith(":"))
00452             zone_id.remove(0, 1);
00453         // the "posix/" subdirectory typically contains the same files as the
00454         // "zoneinfo/" parent directory, but are not typically what are in use
00455         if (zone_id.startsWith("posix/"))
00456             zone_id.remove(0, 6);
00457     }
00458 
00459 #endif
00460     return zone_id;
00461 }
00462 
00463 /* Helper function for checkTimeZone() that compares zone ID's.
00464    In the event that the zone ID's differ, checks to see if the local
00465    zoneinfo database has both zone ID's and if they're equivalent. */
00466 static bool compare_zone_IDs(QString firstZoneID, QString secondZoneID)
00467 {
00468     // Some distros use spaces rather than underscores in the zone ID, so
00469     // allow matches where the only difference is space vs. underscore.
00470     firstZoneID.replace(' ', '_');
00471     secondZoneID.replace(' ', '_');
00472     if (firstZoneID == secondZoneID)
00473         return true;
00474 
00475     // Although the zone ID names don't match, they may refer to equivalent
00476     // rules, so compare the files
00477     QString zoneinfo_dir_path("/usr/share/zoneinfo");
00478     QFileInfo firstInfo(zoneinfo_dir_path + "/" + firstZoneID);
00479     QFileInfo secondInfo(zoneinfo_dir_path + "/" + secondZoneID);
00480     if (compare_zone_files(firstInfo, secondInfo))
00481         return true;
00482 
00483     return false;
00484 }
00485 
00486 static void print_timezone_info(QString master_zone_id, QString local_zone_id,
00487                                 int master_utc_offset, int local_utc_offset,
00488                                 QString master_time, QString local_time)
00489 {
00490     LOG(VB_GENERAL, LOG_NOTICE,
00491         QString("Detected time zone settings:\n"
00492             "    Master: Zone ID: '%1', UTC Offset: '%2', Current Time: '%3'\n"
00493             "     Local: Zone ID: '%4', UTC Offset: '%5', Current Time: '%6'\n")
00494             .arg(master_zone_id).arg(master_utc_offset).arg(master_time)
00495             .arg(local_zone_id).arg(local_utc_offset).arg(local_time));
00496 }
00497 
00502 bool checkTimeZone(void)
00503 {
00504     if (gCoreContext->IsMasterBackend())
00505         return true;
00506 
00507     QStringList master_settings(QString("QUERY_TIME_ZONE"));
00508     if (!gCoreContext->SendReceiveStringList(master_settings))
00509     {
00510         LOG(VB_GENERAL, LOG_CRIT,
00511             "Unable to determine master backend time zone "
00512             "settings.  If those settings differ from local "
00513             "settings, some functionality will fail.");
00514         return true;
00515     }
00516 
00517     return checkTimeZone(master_settings);
00518 }
00519 
00522 bool checkTimeZone(const QStringList &master_settings)
00523 {
00524     QDateTime local_time = mythCurrentDateTime();
00525     QString local_time_string = local_time.toString(Qt::ISODate);
00526 
00527     bool have_zone_IDs = true;
00528 
00529     QString master_time_zone_ID = master_settings[0];
00530     int master_utc_offset       = master_settings[1].toInt();
00531     QString master_time_string  = master_settings[2];
00532     QString local_time_zone_ID  = getTimeZoneID();
00533     int local_utc_offset        = calc_utc_offset();
00534 
00535     if (master_time_zone_ID == "UNDEF")
00536     {
00537         LOG(VB_GENERAL, LOG_CRIT,
00538             "Unable to determine master backend time zone "
00539             "settings. If local time zone settings differ "
00540             "from master backend settings, some functionality will fail.");
00541         have_zone_IDs = false;
00542     }
00543     if (local_time_zone_ID == "UNDEF")
00544     {
00545         LOG(VB_GENERAL, LOG_CRIT,
00546              "Unable to determine local time zone settings. "
00547              "If local time zone settings differ from "
00548              "master backend settings, some functionality will fail.");
00549         have_zone_IDs = false;
00550     }
00551 
00552     if (have_zone_IDs &&
00553         !compare_zone_IDs(master_time_zone_ID, local_time_zone_ID))
00554     {
00555         LOG(VB_GENERAL, LOG_CRIT, "Time zone settings on the master backend "
00556                                   "differ from those on this system.");
00557 
00558         print_timezone_info(master_time_zone_ID, local_time_zone_ID,
00559                             master_utc_offset, local_utc_offset,
00560                             master_time_string, local_time_string);
00561         return false;
00562     }
00563 
00564     // Verify offset
00565     if (master_utc_offset != local_utc_offset)
00566     {
00567         LOG(VB_GENERAL, LOG_CRIT, "UTC offset on the master backend differs "
00568                                   "from offset on this system.");
00569 
00570         print_timezone_info(master_time_zone_ID, local_time_zone_ID,
00571                             master_utc_offset, local_utc_offset,
00572                             master_time_string, local_time_string);
00573         return false;
00574     }
00575 
00576     // Verify current time
00577     if (master_time_string == "UNDEF")
00578     {
00579         LOG(VB_GENERAL, LOG_CRIT, 
00580             "Unable to determine current time on the master "
00581             "backend . If local time or time zone settings "
00582             "differ from those on the master backend, some "
00583             "functionality will fail.");
00584     }
00585     else
00586     {
00587         QDateTime master_time = QDateTime::fromString(master_time_string,
00588                                                       Qt::ISODate);
00589         uint timediff = abs(master_time.secsTo(local_time));
00590         if (timediff > 300)
00591         {
00592             LOG(VB_GENERAL, LOG_CRIT, "Current time on the master backend "
00593                                       "differs from time on this system.");
00594             print_timezone_info(master_time_zone_ID, local_time_zone_ID,
00595                                 master_utc_offset, local_utc_offset,
00596                                 master_time_string, local_time_string);
00597             return false;
00598         }
00599         else if (timediff > 20)
00600         {
00601             LOG(VB_GENERAL, LOG_CRIT,
00602                     QString("Warning! Time difference between the master "
00603                             "backend and this system is %1 seconds.")
00604                     .arg(timediff));
00605         }
00606     }
00607 
00608     return true;
00609 }
00610 
00614 int MythSecsTo(const QDateTime &from, const QDateTime &to)
00615 {
00616    return (from.time().secsTo(to.time()) +
00617            from.date().daysTo(to.date()) * 60 * 60 * 24);
00618 }
00619 
00623 QDateTime MythUTCToLocal(const QDateTime &utc)
00624 {
00625     QDateTime local = QDateTime(QDate(1970, 1, 1));
00626 
00627     int timesecs = MythSecsTo(local, utc);
00628     QDateTime localdt;
00629     localdt.setTime_t(timesecs);
00630 
00631     return localdt;
00632 }
00633 
00638 bool getUptime(time_t &uptime)
00639 {
00640 #ifdef __linux__
00641     struct sysinfo sinfo;
00642     if (sysinfo(&sinfo) == -1)
00643     {
00644         LOG(VB_GENERAL, LOG_ERR, "sysinfo() error");
00645         return false;
00646     }
00647     else
00648         uptime = sinfo.uptime;
00649 
00650 #elif defined(__FreeBSD__) || CONFIG_DARWIN
00651 
00652     int            mib[2];
00653     struct timeval bootTime;
00654     size_t         len;
00655 
00656     // Uptime is calculated. Get this machine's boot time
00657     // and subtract it from the current machine time
00658     len    = sizeof(bootTime);
00659     mib[0] = CTL_KERN;
00660     mib[1] = KERN_BOOTTIME;
00661     if (sysctl(mib, 2, &bootTime, &len, NULL, 0) == -1)
00662     {
00663         LOG(VB_GENERAL, LOG_ERR, "sysctl() error");
00664         return false;
00665     }
00666     else
00667         uptime = time(NULL) - bootTime.tv_sec;
00668 #elif defined(USING_MINGW)
00669     uptime = ::GetTickCount() / 1000;
00670 #else
00671     // Hmmm. Not Linux, not FreeBSD or Darwin. What else is there :-)
00672     LOG(VB_GENERAL, LOG_NOTICE, "Unknown platform. How do I get the uptime?");
00673     return false;
00674 #endif
00675 
00676     return true;
00677 }
00678 
00685 bool getMemStats(int &totalMB, int &freeMB, int &totalVM, int &freeVM)
00686 {
00687 #ifdef __linux__
00688     size_t MB = (1024*1024);
00689     struct sysinfo sinfo;
00690     if (sysinfo(&sinfo) == -1)
00691     {
00692         LOG(VB_GENERAL, LOG_ERR,
00693             "getMemStats(): Error, sysinfo() call failed.");
00694         return false;
00695     }
00696     else
00697         totalMB = (int)((sinfo.totalram  * sinfo.mem_unit)/MB),
00698         freeMB  = (int)((sinfo.freeram   * sinfo.mem_unit)/MB),
00699         totalVM = (int)((sinfo.totalswap * sinfo.mem_unit)/MB),
00700         freeVM  = (int)((sinfo.freeswap  * sinfo.mem_unit)/MB);
00701 
00702 #elif CONFIG_DARWIN
00703     mach_port_t             mp;
00704     mach_msg_type_number_t  count;
00705     vm_size_t               pageSize;
00706     vm_statistics_data_t    s;
00707 
00708     mp = mach_host_self();
00709 
00710     // VM page size
00711     if (host_page_size(mp, &pageSize) != KERN_SUCCESS)
00712         pageSize = 4096;   // If we can't look it up, 4K is a good guess
00713 
00714     count = HOST_VM_INFO_COUNT;
00715     if (host_statistics(mp, HOST_VM_INFO,
00716                         (host_info_t)&s, &count) != KERN_SUCCESS)
00717     {
00718         LOG(VB_GENERAL, LOG_ERR, "getMemStats(): Error, "
00719             "failed to get virtual memory statistics.");
00720         return false;
00721     }
00722 
00723     pageSize >>= 10;  // This gives usages in KB
00724     totalMB = (s.active_count + s.inactive_count +
00725                s.wire_count + s.free_count) * pageSize / 1024;
00726     freeMB  = s.free_count * pageSize / 1024;
00727 
00728 
00729     // This is a real hack. I have not found a way to ask the kernel how much
00730     // swap it is using, and the dynamic_pager daemon doesn't even seem to be
00731     // able to report what filesystem it is using for the swapfiles. So, we do:
00732     int64_t total, used, free;
00733     free = getDiskSpace("/private/var/vm", total, used);
00734     totalVM = (int)(total >> 10);
00735     freeVM = (int)(free >> 10);
00736 
00737 #else
00738     LOG(VB_GENERAL, LOG_NOTICE, "getMemStats(): Unknown platform. "
00739         "How do I get the memory stats?");
00740     return false;
00741 #endif
00742 
00743     return true;
00744 }
00745 
00753 bool hasUtf8(const char *str)
00754 {
00755     const uchar *c = (uchar *) str;
00756 
00757     while (*c++)
00758     {
00759         // ASCII is < 0x80.
00760         // 0xC2..0xF4 is probably UTF-8.
00761         // Anything else probably ISO-8859-1 (Latin-1, Unicode)
00762 
00763         if (*c > 0xC1 && *c < 0xF5)
00764         {
00765             int bytesToCheck = 2;  // Assume  0xC2-0xDF (2 byte sequence)
00766 
00767             if (*c > 0xDF)         // Maybe   0xE0-0xEF (3 byte sequence)
00768                 ++bytesToCheck;
00769             if (*c > 0xEF)         // Matches 0xF0-0xF4 (4 byte sequence)
00770                 ++bytesToCheck;
00771 
00772             while (bytesToCheck--)
00773             {
00774                 ++c;
00775 
00776                 if (! *c)                    // String ended in middle
00777                     return false;            // Not valid UTF-8
00778 
00779                 if (*c < 0x80 || *c > 0xBF)  // Bad UTF-8 sequence
00780                     break;                   // Keep checking in outer loop
00781             }
00782 
00783             if (!bytesToCheck)  // Have checked all the bytes in the sequence
00784                 return true;    // Hooray! We found valid UTF-8!
00785         }
00786     }
00787 
00788     return false;
00789 }
00790 
00798 bool ping(const QString &host, int timeout)
00799 {
00800 #ifdef USING_MINGW
00801     QString cmd = QString("%systemroot%\\system32\\ping.exe -i %1 -n 1 %2>NUL")
00802                   .arg(timeout).arg(host);
00803 
00804     if (myth_system(cmd, kMSDontBlockInputDevs | kMSDontDisableDrawing |
00805                          kMSProcessEvents) != GENERIC_EXIT_OK)
00806         return false;
00807 #else
00808     QString cmd = QString("ping -t %1 -c 1  %2  >/dev/null 2>&1")
00809                   .arg(timeout).arg(host);
00810 
00811     if (myth_system(cmd, kMSDontBlockInputDevs | kMSDontDisableDrawing |
00812                          kMSProcessEvents) != GENERIC_EXIT_OK)
00813     {
00814         // ping command may not like -t argument, or the host might not
00815         // be listening. Try to narrow down with a quick ping to localhost:
00816 
00817         cmd = "ping -t 1 -c 1 localhost >/dev/null 2>&1";
00818 
00819         if (myth_system(cmd, kMSDontBlockInputDevs | kMSDontDisableDrawing |
00820                              kMSProcessEvents) != GENERIC_EXIT_OK)
00821         {
00822             // Assume -t is bad - do a ping that might cause a timeout:
00823             cmd = QString("ping -c 1 %1 >/dev/null 2>&1").arg(host);
00824 
00825             if (myth_system(cmd, kMSDontBlockInputDevs | kMSDontDisableDrawing |
00826                                  kMSProcessEvents) != GENERIC_EXIT_OK)
00827                 return false;  // it failed with or without the -t
00828 
00829             return true;
00830         }
00831         else  // Pinging localhost worked, so targeted host wasn't listening
00832             return false;
00833     }
00834 #endif
00835 
00836     return true;
00837 }
00838 
00842 bool telnet(const QString &host, int port)
00843 {
00844     MythSocket *s = new MythSocket();
00845 
00846     bool connected = s->connect(host, port);
00847     s->DownRef();
00848 
00849     return connected;
00850 }
00851 
00873 long long copy(QFile &dst, QFile &src, uint block_size)
00874 {
00875     uint buflen = (block_size < 1024) ? (16 * 1024) : block_size;
00876     char *buf = new char[buflen];
00877     bool odst = false, osrc = false;
00878 
00879     if (!buf)
00880         return -1LL;
00881 
00882     if (!dst.isWritable() && !dst.isOpen())
00883         odst = dst.open(QIODevice::Unbuffered |
00884                         QIODevice::WriteOnly  |
00885                         QIODevice::Truncate);
00886 
00887     if (!src.isReadable() && !src.isOpen())
00888         osrc = src.open(QIODevice::Unbuffered|QIODevice::ReadOnly);
00889 
00890     bool ok = dst.isWritable() && src.isReadable();
00891     long long total_bytes = 0LL;
00892     while (ok)
00893     {
00894         long long rlen, wlen, off = 0;
00895         rlen = src.read(buf, buflen);
00896         if (rlen<0)
00897         {
00898             LOG(VB_GENERAL, LOG_ERR, "read error");
00899             ok = false;
00900             break;
00901         }
00902         if (rlen==0)
00903             break;
00904 
00905         total_bytes += (long long) rlen;
00906 
00907         while ((rlen-off>0) && ok)
00908         {
00909             wlen = dst.write(buf + off, rlen - off);
00910             if (wlen>=0)
00911                 off+= wlen;
00912             if (wlen<0)
00913             {
00914                 LOG(VB_GENERAL, LOG_ERR, "write error");
00915                 ok = false;
00916             }
00917         }
00918     }
00919     delete[] buf;
00920 
00921     if (odst)
00922         dst.close();
00923 
00924     if (osrc)
00925         src.close();
00926 
00927     return (ok) ? total_bytes : -1LL;
00928 }
00929 
00930 QString createTempFile(QString name_template, bool dir)
00931 {
00932     int ret = -1;
00933 
00934 #ifdef USING_MINGW
00935     char temppath[MAX_PATH] = ".";
00936     char tempfilename[MAX_PATH] = "";
00937     // if GetTempPath fails, use current dir
00938     GetTempPathA(MAX_PATH, temppath);
00939     if (GetTempFileNameA(temppath, "mth", 0, tempfilename))
00940     {
00941         if (dir)
00942         {
00943             // GetTempFileNameA creates the file, so delete it before mkdir
00944             unlink(tempfilename);
00945             ret = mkdir(tempfilename);
00946         }
00947         else
00948             ret = open(tempfilename, O_CREAT | O_RDWR, S_IREAD | S_IWRITE);
00949     }
00950     QString tmpFileName(tempfilename);
00951 #else
00952     QByteArray safe_name_template = name_template.toAscii();
00953     const char *tmp = safe_name_template.constData();
00954     char *ctemplate = strdup(tmp);
00955 
00956     if (dir)
00957     {
00958         ret = (mkdtemp(ctemplate)) ? 0 : -1;
00959     }
00960     else
00961     {
00962         mode_t cur_umask = umask(S_IRWXO | S_IRWXG);
00963         ret = mkstemp(ctemplate);
00964         umask(cur_umask);
00965     }
00966 
00967     QString tmpFileName(ctemplate);
00968     free(ctemplate);
00969 #endif
00970 
00971     if (ret == -1)
00972     {
00973         LOG(VB_GENERAL, LOG_ERR, QString("createTempFile(%1), Error ")
00974                 .arg(name_template) + ENO);
00975         return name_template;
00976     }
00977 
00978     if (!dir && (ret >= 0))
00979         close(ret);
00980 
00981     return tmpFileName;
00982 }
00983 
01002 void makeFileAccessible(QString filename)
01003 {
01004     QByteArray fname = filename.toAscii();
01005     chmod(fname.constData(), 0666);
01006 }
01007 
01011 QString getResponse(const QString &query, const QString &def)
01012 {
01013     QByteArray tmp = query.toLocal8Bit();
01014     cout << tmp.constData();
01015 
01016     tmp = def.toLocal8Bit();
01017     if (def.size())
01018         cout << " [" << tmp.constData() << "]  ";
01019     else
01020         cout << "  ";
01021 
01022     if (!isatty(fileno(stdin)) || !isatty(fileno(stdout)))
01023     {
01024         cout << endl << "[console is not interactive, using default '"
01025              << tmp.constData() << "']" << endl;
01026         return def;
01027     }
01028 
01029     char response[80];
01030     cin.clear();
01031     cin.getline(response, 80);
01032     if (!cin.good())
01033     {
01034         cout << endl;
01035         LOG(VB_GENERAL, LOG_ERR, "Read from stdin failed");
01036         return NULL;
01037     }
01038 
01039     QString qresponse = response;
01040 
01041     if (qresponse.isEmpty())
01042         qresponse = def;
01043 
01044     return qresponse;
01045 }
01046 
01050 int intResponse(const QString &query, int def)
01051 {
01052     QString str_resp = getResponse(query, QString("%1").arg(def));
01053     if (str_resp.isEmpty())
01054         return def;
01055     bool ok;
01056     int resp = str_resp.toInt(&ok);
01057     return (ok ? resp : def);
01058 }
01059 
01060 
01061 QString getSymlinkTarget(const QString &start_file,
01062                          QStringList   *intermediaries,
01063                          unsigned       maxLinks)
01064 {
01065 #if 0
01066     LOG(VB_GENERAL, LOG_DEBUG,
01067             QString("getSymlinkTarget('%1', 0x%2, %3)")
01068             .arg(start_file).arg((uint64_t)intermediaries,0,16)
01069             .arg(maxLinks));
01070 #endif
01071 
01072     QString   link     = QString::null;
01073     QString   cur_file = start_file; cur_file.detach();
01074     QFileInfo fi(cur_file);
01075 
01076     if (intermediaries)
01077     {
01078         intermediaries->clear();
01079         intermediaries->push_back(start_file);
01080     }
01081 
01082     for (uint i = 0; (i <= maxLinks) && fi.isSymLink() &&
01083              !(link = fi.readLink()).isEmpty(); i++)
01084     {
01085         cur_file = (link[0] == '/') ?
01086             link : // absolute link
01087             fi.absoluteDir().absolutePath() + "/" + link; // relative link
01088 
01089         if (intermediaries && !intermediaries->contains(cur_file))
01090             intermediaries->push_back(cur_file);
01091 
01092         fi = QFileInfo(cur_file);
01093     }
01094 
01095     if (intermediaries)
01096         intermediaries->detach();
01097 
01098 #if 0
01099     if (intermediaries)
01100     {
01101         for (uint i = 0; i < intermediaries->size(); i++)
01102         {
01103             LOG(VB_GENERAL, LOG_DEBUG, QString("    inter%1: %2")
01104                     .arg(i).arg((*intermediaries)[i]));
01105         }
01106     }
01107 
01108     LOG(VB_GENERAL, LOG_DEBUG,
01109             QString("getSymlinkTarget() -> '%1'")
01110             .arg((!fi.isSymLink()) ? cur_file : QString::null));
01111 #endif
01112 
01113     return (!fi.isSymLink()) ? cur_file : QString::null;
01114 }
01115 
01116 void sendPlaybackStart(void)
01117 {
01118     MythEvent me(QString("PLAYBACK_START %1").arg(gCoreContext->GetHostName()));
01119     gCoreContext->dispatchNow(me);
01120 }
01121 
01122 void sendPlaybackEnd(void)
01123 {
01124     MythEvent me(QString("PLAYBACK_END %1").arg(gCoreContext->GetHostName()));
01125     gCoreContext->dispatchNow(me);
01126 }
01127 
01128 bool IsMACAddress(QString MAC)
01129 {
01130     QStringList tokens = MAC.split(':');
01131     if (tokens.size() != 6)
01132     {
01133         LOG(VB_NETWORK, LOG_ERR,
01134             QString("IsMACAddress(%1) = false, doesn't have 6 parts").arg(MAC));
01135         return false;
01136     }
01137 
01138     int y;
01139     bool ok;
01140     int value;
01141     for (y = 0; y < 6; y++)
01142     {
01143         if (tokens[y].isEmpty())
01144         {
01145             LOG(VB_NETWORK, LOG_ERR,
01146                 QString("IsMACAddress(%1) = false, part #%2 is empty.")
01147                     .arg(MAC).arg(y));
01148             return false;
01149         }
01150 
01151         value = tokens[y].toInt(&ok, 16);
01152         if (!ok)
01153         {
01154             LOG(VB_NETWORK, LOG_ERR,
01155                 QString("IsMACAddress(%1) = false, unable to "
01156                         "convert part '%2' to integer.")
01157                     .arg(MAC).arg(tokens[y]));
01158             return false;
01159         }
01160 
01161         if (value > 255)
01162         {
01163             LOG(VB_NETWORK, LOG_ERR,
01164                 QString("IsMACAddress(%1) = false, part #%2 "
01165                         "evaluates to %3 which is higher than 255.")
01166                     .arg(MAC).arg(y).arg(value));
01167             return false;
01168         }
01169     }
01170 
01171     LOG(VB_NETWORK, LOG_DEBUG, QString("IsMACAddress(%1) = true").arg(MAC));
01172     return true;
01173 }
01174 
01175 QString FileHash(QString filename)
01176 {
01177     QFile file(filename);
01178     QFileInfo fileinfo(file);
01179     qint64 initialsize = fileinfo.size();
01180     quint64 hash = 0;
01181 
01182     if (initialsize == 0)
01183         return QString("NULL");
01184 
01185     if (file.open(QIODevice::ReadOnly))
01186         hash = initialsize;
01187     else
01188     {
01189         LOG(VB_GENERAL, LOG_ERR, 
01190             "Error: Unable to open selected file, missing read permissions?");
01191         return QString("NULL");
01192     }
01193 
01194     file.seek(0);
01195     QDataStream stream(&file);
01196     stream.setByteOrder(QDataStream::LittleEndian);
01197     for (quint64 tmp = 0, i = 0; i < 65536/sizeof(tmp); i++)
01198     {
01199         stream >> tmp;
01200         hash += tmp;
01201     }
01202 
01203     file.seek(initialsize - 65536);
01204     for (quint64 tmp = 0, i = 0; i < 65536/sizeof(tmp); i++)
01205     {
01206         stream >> tmp;
01207         hash += tmp;
01208     }
01209 
01210     file.close();
01211 
01212     QString output = QString("%1").arg(hash, 0, 16);
01213     return output;
01214 }
01215 
01216 bool WakeOnLAN(QString MAC)
01217 {
01218     char msg[1024] = "\xFF\xFF\xFF\xFF\xFF\xFF";
01219     int  msglen = 6;
01220     int  x, y;
01221     QStringList tokens = MAC.split(':');
01222     int macaddr[6];
01223     bool ok;
01224 
01225     if (tokens.size() != 6)
01226     {
01227         LOG(VB_GENERAL, LOG_ERR,
01228                 QString( "WakeOnLan(%1): Incorrect MAC length").arg(MAC));
01229         return false;
01230     }
01231 
01232     for (y = 0; y < 6; y++)
01233     {
01234         macaddr[y] = tokens[y].toInt(&ok, 16);
01235 
01236         if (!ok)
01237         {
01238             LOG(VB_GENERAL, LOG_ERR,
01239                     QString( "WakeOnLan(%1): Invalid MAC address").arg(MAC));
01240             return false;
01241         }
01242     }
01243 
01244     for (x = 0; x < 16; x++)
01245         for (y = 0; y < 6; y++)
01246             msg[msglen++] = macaddr[y];
01247 
01248     LOG(VB_NETWORK, LOG_INFO,
01249             QString("WakeOnLan(): Sending WOL packet to %1").arg(MAC));
01250 
01251     MSocketDevice socket(MSocketDevice::Datagram);
01252     socket.setBroadcast(true);
01253     socket.writeBlock(msg, msglen, QHostAddress("255.255.255.255"), 32767);
01254 
01255     return true;
01256 }
01257 
01258 bool IsPulseAudioRunning(void)
01259 {
01260 #ifdef USING_MINGW
01261     return false;
01262 #else
01263 
01264 #if CONFIG_DARWIN || (__FreeBSD__) || defined(__OpenBSD__)
01265     const char *command = "ps -ax | grep -i pulseaudio | grep -v grep > /dev/null";
01266 #else
01267     const char *command = "ps ch -C pulseaudio -o pid > /dev/null";
01268 #endif
01269     // Do NOT use kMSProcessEvents here, it will cause deadlock
01270     uint res = myth_system(command, kMSDontBlockInputDevs |
01271                                     kMSDontDisableDrawing);
01272     return (res == GENERIC_EXIT_OK);
01273 #endif // USING_MINGW
01274 }
01275 
01276 bool myth_nice(int val)
01277 {
01278     errno = 0;
01279     int ret = nice(val);
01280 
01281     if ((-1 == ret) && (0 != errno) && (val >= 0))
01282     {
01283         LOG(VB_GENERAL, LOG_ERR, "Failed to nice process" + ENO);
01284         return false;
01285     }
01286 
01287     return true;
01288 }
01289 
01290 void myth_yield(void)
01291 {
01292 #ifdef _POSIX_PRIORITY_SCHEDULING
01293     if (sched_yield()<0)
01294         usleep(5000);
01295 #else
01296     usleep(5000);
01297 #endif
01298 }
01299 
01317 #if defined(__linux__) && ( defined(__i386__) || defined(__ppc__) || \
01318                             defined(__x86_64__) || defined(__ia64__) )
01319 
01320 #include <stdio.h>
01321 #include <stdlib.h>
01322 #include <errno.h>
01323 #include <getopt.h>
01324 #include <unistd.h>
01325 #include <sys/ptrace.h>
01326 #include <asm/unistd.h>
01327 
01328 #if defined(__i386__)
01329 # define __NR_ioprio_set  289
01330 # define __NR_ioprio_get  290
01331 #elif defined(__ppc__)
01332 # define __NR_ioprio_set  273
01333 # define __NR_ioprio_get  274
01334 #elif defined(__x86_64__)
01335 # define __NR_ioprio_set  251
01336 # define __NR_ioprio_get  252
01337 #elif defined(__ia64__)
01338 # define __NR_ioprio_set  1274
01339 # define __NR_ioprio_get  1275
01340 #endif
01341 
01342 #define IOPRIO_BITS             (16)
01343 #define IOPRIO_CLASS_SHIFT      (13)
01344 #define IOPRIO_PRIO_MASK        ((1UL << IOPRIO_CLASS_SHIFT) - 1)
01345 #define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT)
01346 #define IOPRIO_PRIO_DATA(mask)  ((mask) & IOPRIO_PRIO_MASK)
01347 #define IOPRIO_PRIO_VALUE(class, data)  (((class) << IOPRIO_CLASS_SHIFT) | data)
01348 
01349 enum { IOPRIO_CLASS_NONE,IOPRIO_CLASS_RT,IOPRIO_CLASS_BE,IOPRIO_CLASS_IDLE, };
01350 enum { IOPRIO_WHO_PROCESS = 1, IOPRIO_WHO_PGRP, IOPRIO_WHO_USER, };
01351 
01352 bool myth_ioprio(int val)
01353 {
01354     int new_ioclass = (val < 0) ? IOPRIO_CLASS_RT :
01355         (val > 7) ? IOPRIO_CLASS_IDLE : IOPRIO_CLASS_BE;
01356     int new_iodata = (new_ioclass == IOPRIO_CLASS_BE) ? val : 0;
01357     int new_ioprio = IOPRIO_PRIO_VALUE(new_ioclass, new_iodata);
01358 
01359     int pid = getpid();
01360     int old_ioprio = syscall(__NR_ioprio_get, IOPRIO_WHO_PROCESS, pid);
01361     if (old_ioprio == new_ioprio)
01362         return true;
01363 
01364     int ret = syscall(__NR_ioprio_set, IOPRIO_WHO_PROCESS, pid, new_ioprio);
01365 
01366     if (-1 == ret && EPERM == errno && IOPRIO_CLASS_BE != new_ioclass)
01367     {
01368         new_iodata = (new_ioclass == IOPRIO_CLASS_RT) ? 0 : 7;
01369         new_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, new_iodata);
01370         ret = syscall(__NR_ioprio_set, IOPRIO_WHO_PROCESS, pid, new_ioprio);
01371     }
01372 
01373     return 0 == ret;
01374 }
01375 
01376 #else
01377 
01378 bool myth_ioprio(int) { return true; }
01379 
01380 #endif
01381 
01382 bool MythRemoveDirectory(QDir &aDir)
01383 {
01384     if (!aDir.exists())//QDir::NoDotAndDotDot
01385         return false;
01386 
01387     QFileInfoList entries = aDir.entryInfoList(QDir::NoDotAndDotDot |
01388                                                QDir::Dirs | QDir::Files);
01389     int count = entries.size();
01390     bool has_err = false;
01391 
01392     for (int idx = 0; idx < count && !has_err; idx++)
01393     {
01394         QFileInfo entryInfo = entries[idx];
01395         QString path = entryInfo.absoluteFilePath();
01396         if (entryInfo.isDir())
01397         {
01398             QDir dir(path);
01399             has_err = MythRemoveDirectory(dir);
01400         }
01401         else
01402         {
01403             QFile file(path);
01404             if (!file.remove())
01405                 has_err = true;
01406         }
01407     }
01408 
01409     if (!has_err && !aDir.rmdir(aDir.absolutePath()))
01410         has_err = true;
01411 
01412     return(has_err);
01413 }
01414 
01415 QString &ShellEscape(QString &string)
01416 {
01417     if (string.contains("\""))
01418         string = string.replace("\"", "\\\"");
01419 
01420     if (string.contains("\'"))
01421         string = string.replace("\'", "\\\'");
01422 
01423     if (string.contains(" "))
01424     {
01425         string.prepend("\"");
01426         string.append("\"");
01427     }
01428 
01429     return string;
01430 }
01431 
01443 void setHttpProxy(void)
01444 {
01445     QString       LOC = "setHttpProxy() - ";
01446     QNetworkProxy p;
01447 
01448 
01449     // Set http proxy for the application if specified in environment variable
01450     QString var(getenv("http_proxy"));
01451     if (var.isEmpty())
01452         var = getenv("HTTP_PROXY");  // Sadly, some OS envs are case sensitive
01453     if (var.length())
01454     {
01455         if (!var.startsWith("http://"))   // i.e. just a host name
01456             var.prepend("http://");
01457 
01458         QUrl    url  = QUrl(var, QUrl::TolerantMode);
01459         QString host = url.host();
01460         int     port = url.port();
01461 
01462         if (port == -1)   // Parsing error
01463         {
01464             port = 0;   // The default when creating a QNetworkProxy
01465 
01466             if (telnet(host, 1080))  // Socks?
01467                 port = 1080;
01468             if (telnet(host, 3128))  // Squid
01469                 port = 3128;
01470             if (telnet(host, 8080))  // MS ISA
01471                 port = 8080;
01472 
01473             LOG(VB_NETWORK, LOG_INFO, LOC + 
01474                 QString("assuming port %1 on host %2") .arg(port).arg(host));
01475             url.setPort(port);
01476         }
01477         else if (!ping(host, 1))
01478             LOG(VB_GENERAL, LOG_ERR, LOC +
01479                 QString("cannot locate host %1").arg(host) +
01480                 "\n\t\t\tPlease check HTTP_PROXY environment variable!");
01481         else if (!telnet(host,port))
01482             LOG(VB_GENERAL, LOG_ERR, LOC +
01483                 QString("%1:%2 - cannot connect!").arg(host).arg(port) +
01484                 "\n\t\t\tPlease check HTTP_PROXY environment variable!");
01485 
01486 #if 0
01487         LOG(VB_NETWORK, LOG_DEBUG, LOC + QString("using http://%1:%2@%3:%4")
01488                 .arg(url.userName()).arg(url.password())
01489                 .arg(host).arg(port));
01490 #endif
01491         p = QNetworkProxy(QNetworkProxy::HttpCachingProxy,
01492                           host, port, url.userName(), url.password());
01493         QNetworkProxy::setApplicationProxy(p);
01494         return;
01495     }
01496 
01497     LOG(VB_NETWORK, LOG_DEBUG, LOC + "no HTTP_PROXY environment var.");
01498 
01499     // Use Qt to look for user proxy settings stored by the OS or browser:
01500 
01501     QList<QNetworkProxy> proxies;
01502     QNetworkProxyQuery   query(QUrl("http://www.mythtv.org"));
01503 
01504     proxies = QNetworkProxyFactory::systemProxyForQuery(query);
01505 
01506     Q_FOREACH (p, proxies)
01507     {
01508         QString host = p.hostName();
01509         int     port = p.port();
01510 
01511         if (p.type() == QNetworkProxy::NoProxy)
01512             continue;
01513 
01514         if (!telnet(host, port))
01515         {
01516             LOG(VB_NETWORK, LOG_ERR, LOC +
01517                 "failed to contact proxy host " + host);
01518             continue;
01519         }
01520 
01521         LOG(VB_NETWORK, LOG_INFO, LOC + QString("using proxy host %1:%2")
01522                             .arg(host).arg(port));
01523         QNetworkProxy::setApplicationProxy(p);
01524 
01525         // Allow sub-commands to use this proxy
01526         // via myth_system(command), by setting HTTP_PROXY
01527         QString url;
01528 
01529         if (p.user().length())
01530             url = "http://%1:%2@%3:%4",
01531             url = url.arg(p.user()).arg(p.password());
01532         else
01533             url = "http://%1:%2";
01534 
01535         url = url.arg(p.hostName()).arg(p.port());
01536         setenv("HTTP_PROXY", url.toAscii(), 1);
01537         setenv("http_proxy", url.toAscii(), 0);
01538 
01539         return;
01540     }
01541 
01542     LOG(VB_NETWORK, LOG_ERR, LOC + "failed to find a network proxy");
01543 }
01544 
01545 void wrapList(QStringList &list, int width)
01546 {
01547     int i;
01548 
01549     for(i = 0; i < list.size(); i++)
01550     {
01551         QString string = list.at(i);
01552 
01553         if( string.size() <= width )
01554             continue;
01555 
01556         QString left   = string.left(width);
01557         bool inserted  = false;
01558 
01559         while( !inserted && left.right(1) != " " )
01560         {
01561             if( string.mid(left.size(), 1) == " " )
01562             {
01563                 list.replace(i, left);
01564                 list.insert(i+1, string.mid(left.size()).trimmed());
01565                 inserted = true;
01566             }
01567             else
01568             { 
01569                 left.chop(1);
01570                 if( !left.contains(" ") )
01571                 {
01572                     // Line is too long, just hyphenate it
01573                     list.replace(i, left + "-");
01574                     list.insert(i+1, string.mid(left.size()));
01575                     inserted = true;
01576                 }
01577             }
01578         }
01579 
01580         if( !inserted )
01581         {
01582             left.chop(1);
01583             list.replace(i, left);
01584             list.insert(i+1, string.mid(left.size()).trimmed());
01585         }
01586     }
01587 }
01588 
01589 QString xml_indent(uint level)
01590 {
01591     static QReadWriteLock rw_lock;
01592     static QMap<uint,QString> cache;
01593 
01594     rw_lock.lockForRead();
01595     QMap<uint,QString>::const_iterator it = cache.find(level);
01596     if (it != cache.end())
01597     {
01598         QString tmp = *it;
01599         rw_lock.unlock();
01600         return tmp;
01601     }
01602     rw_lock.unlock();
01603 
01604     QString ret = "";
01605     for (uint i = 0; i < level; i++)
01606         ret += "    ";
01607 
01608     rw_lock.lockForWrite();
01609     cache[level] = ret;
01610     rw_lock.unlock();
01611 
01612     return ret;
01613 }
01614 
01615 /* vim: set expandtab tabstop=4 shiftwidth=4: */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends