MythTV  master
mythmiscutil.cpp
Go to the documentation of this file.
1 
2 #include "mythmiscutil.h"
3 
4 // C++ headers
5 #include <cerrno>
6 #include <cstdlib>
7 #include <ctime>
8 #include <iostream>
9 
10 using namespace std;
11 
12 // POSIX
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include <sched.h>
16 
17 // System specific C headers
18 #include "compat.h"
19 
20 #ifdef linux
21 #include <sys/vfs.h>
22 #include <sys/sysinfo.h>
23 #include <sys/stat.h> // for umask, chmod
24 #endif
25 
26 #if CONFIG_DARWIN
27 #include <mach/mach.h>
28 #endif
29 
30 #ifdef BSD
31 #include <sys/mount.h> // for struct statfs
32 #include <sys/sysctl.h>
33 #include <sys/stat.h> // for umask, chmod
34 #endif
35 
36 // Qt headers
37 #include <QReadWriteLock>
38 #include <QNetworkProxy>
39 #include <QStringList>
40 #include <QDataStream>
41 #include <QUdpSocket>
42 #include <QFileInfo>
43 #include <QFile>
44 #include <QDir>
45 #include <QUrl>
46 #include <QHostAddress>
47 #include <QDataStream>
48 
49 // Myth headers
50 #include "mythcorecontext.h"
51 #include "exitcodes.h"
52 #include "mythlogging.h"
53 #include "mythsocket.h"
54 #include "mythcoreutil.h"
55 #include "mythsystemlegacy.h"
56 
57 #include "mythconfig.h" // for CONFIG_DARWIN
58 
63 bool getUptime(time_t &uptime)
64 {
65 #ifdef __linux__
66  struct sysinfo sinfo {};
67  if (sysinfo(&sinfo) == -1)
68  {
69  LOG(VB_GENERAL, LOG_ERR, "sysinfo() error");
70  return false;
71  }
72  uptime = sinfo.uptime;
73 
74 #elif defined(__FreeBSD__) || CONFIG_DARWIN
75 
76  int mib[2];
77  struct timeval bootTime;
78  size_t len;
79 
80  // Uptime is calculated. Get this machine's boot time
81  // and subtract it from the current machine time
82  len = sizeof(bootTime);
83  mib[0] = CTL_KERN;
84  mib[1] = KERN_BOOTTIME;
85  if (sysctl(mib, 2, &bootTime, &len, nullptr, 0) == -1)
86  {
87  LOG(VB_GENERAL, LOG_ERR, "sysctl() error");
88  return false;
89  }
90  uptime = time(nullptr) - bootTime.tv_sec;
91 #elif defined(_WIN32)
92  uptime = ::GetTickCount() / 1000;
93 #else
94  // Hmmm. Not Linux, not FreeBSD or Darwin. What else is there :-)
95  LOG(VB_GENERAL, LOG_NOTICE, "Unknown platform. How do I get the uptime?");
96  return false;
97 #endif
98 
99  return true;
100 }
101 
108 bool getMemStats(int &totalMB, int &freeMB, int &totalVM, int &freeVM)
109 {
110 #ifdef __linux__
111  const size_t MB = (1024*1024);
112  struct sysinfo sinfo {};
113  if (sysinfo(&sinfo) == -1)
114  {
115  LOG(VB_GENERAL, LOG_ERR,
116  "getMemStats(): Error, sysinfo() call failed.");
117  return false;
118  }
119 
120  totalMB = (int)((sinfo.totalram * sinfo.mem_unit)/MB);
121  freeMB = (int)((sinfo.freeram * sinfo.mem_unit)/MB);
122  totalVM = (int)((sinfo.totalswap * sinfo.mem_unit)/MB);
123  freeVM = (int)((sinfo.freeswap * sinfo.mem_unit)/MB);
124  return true;
125 #elif CONFIG_DARWIN
126  mach_port_t mp;
127  mach_msg_type_number_t count;
128  vm_size_t pageSize;
129  vm_statistics_data_t s;
130 
131  mp = mach_host_self();
132 
133  // VM page size
134  if (host_page_size(mp, &pageSize) != KERN_SUCCESS)
135  pageSize = 4096; // If we can't look it up, 4K is a good guess
136 
137  count = HOST_VM_INFO_COUNT;
138  if (host_statistics(mp, HOST_VM_INFO,
139  (host_info_t)&s, &count) != KERN_SUCCESS)
140  {
141  LOG(VB_GENERAL, LOG_ERR, "getMemStats(): Error, "
142  "failed to get virtual memory statistics.");
143  return false;
144  }
145 
146  pageSize >>= 10; // This gives usages in KB
147  totalMB = (s.active_count + s.inactive_count +
148  s.wire_count + s.free_count) * pageSize / 1024;
149  freeMB = s.free_count * pageSize / 1024;
150 
151 
152  // This is a real hack. I have not found a way to ask the kernel how much
153  // swap it is using, and the dynamic_pager daemon doesn't even seem to be
154  // able to report what filesystem it is using for the swapfiles. So, we do:
155  int64_t total, used, free;
156  free = getDiskSpace("/private/var/vm", total, used);
157  totalVM = (int)(total >> 10);
158  freeVM = (int)(free >> 10);
159  return true;
160 #else
161  Q_UNUSED(totalMB);
162  Q_UNUSED(freeMB);
163  Q_UNUSED(totalVM);
164  Q_UNUSED(freeVM);
165  return false;
166 #endif
167 }
168 
176 bool hasUtf8(const char *str)
177 {
178  const uchar *c = (uchar *) str;
179 
180  while (*c++)
181  {
182  // ASCII is < 0x80.
183  // 0xC2..0xF4 is probably UTF-8.
184  // Anything else probably ISO-8859-1 (Latin-1, Unicode)
185 
186  if (*c > 0xC1 && *c < 0xF5)
187  {
188  int bytesToCheck = 2; // Assume 0xC2-0xDF (2 byte sequence)
189 
190  if (*c > 0xDF) // Maybe 0xE0-0xEF (3 byte sequence)
191  ++bytesToCheck;
192  if (*c > 0xEF) // Matches 0xF0-0xF4 (4 byte sequence)
193  ++bytesToCheck;
194 
195  while (bytesToCheck--)
196  {
197  ++c;
198 
199  if (! *c) // String ended in middle
200  return false; // Not valid UTF-8
201 
202  if (*c < 0x80 || *c > 0xBF) // Bad UTF-8 sequence
203  break; // Keep checking in outer loop
204  }
205 
206  if (!bytesToCheck) // Have checked all the bytes in the sequence
207  return true; // Hooray! We found valid UTF-8!
208  }
209  }
210 
211  return false;
212 }
213 
228 bool ping(const QString &host, int timeout)
229 {
230 #ifdef _WIN32
231  QString cmd = QString("%systemroot%\\system32\\ping.exe -w %1 -n 1 %2>NUL")
232  .arg(timeout*1000).arg(host);
233 
236 #else
237  QString addrstr =
239  QHostAddress addr = QHostAddress(addrstr);
240 #if defined(__FreeBSD__) || CONFIG_DARWIN
241  QString timeoutparam("-t");
242 #else
243  // Linux, NetBSD, OpenBSD
244  QString timeoutparam("-w");
245 #endif
246  QString pingcmd =
247  addr.protocol() == QAbstractSocket::IPv6Protocol ? "ping6" : "ping";
248  QString cmd = QString("%1 %2 %3 -c 1 %4 >/dev/null 2>&1")
249  .arg(pingcmd).arg(timeoutparam).arg(timeout).arg(host);
250 
253 #endif
254 }
255 
259 bool telnet(const QString &host, int port)
260 {
261  auto *s = new MythSocket();
262 
263  bool connected = s->ConnectToHost(host, port);
264  s->DecrRef();
265 
266  return connected;
267 }
268 
290 long long copy(QFile &dst, QFile &src, uint block_size)
291 {
292  uint buflen = (block_size < 1024) ? (16 * 1024) : block_size;
293  char *buf = new char[buflen];
294  bool odst = false;
295  bool osrc = false;
296 
297  if (!buf)
298  return -1LL;
299 
300  if (!dst.isWritable() && !dst.isOpen())
301  {
302  odst = dst.open(QIODevice::Unbuffered |
303  QIODevice::WriteOnly |
304  QIODevice::Truncate);
305  }
306 
307  if (!src.isReadable() && !src.isOpen())
308  osrc = src.open(QIODevice::Unbuffered|QIODevice::ReadOnly);
309 
310  bool ok = dst.isWritable() && src.isReadable();
311  long long total_bytes = 0LL;
312  while (ok)
313  {
314  long long off = 0;
315  long long rlen = src.read(buf, buflen);
316  if (rlen<0)
317  {
318  LOG(VB_GENERAL, LOG_ERR, "read error");
319  ok = false;
320  break;
321  }
322  if (rlen==0)
323  break;
324 
325  total_bytes += rlen;
326 
327  while ((rlen-off>0) && ok)
328  {
329  long long wlen = dst.write(buf + off, rlen - off);
330  if (wlen>=0)
331  off+= wlen;
332  if (wlen<0)
333  {
334  LOG(VB_GENERAL, LOG_ERR, "write error");
335  ok = false;
336  }
337  }
338  }
339  delete[] buf;
340 
341  if (odst)
342  dst.close();
343 
344  if (osrc)
345  src.close();
346 
347  return (ok) ? total_bytes : -1LL;
348 }
349 
350 QString createTempFile(QString name_template, bool dir)
351 {
352  int ret = -1;
353 
354 #ifdef _WIN32
355  char temppath[MAX_PATH] = ".";
356  char tempfilename[MAX_PATH] = "";
357  // if GetTempPath fails, use current dir
358  GetTempPathA(MAX_PATH, temppath);
359  if (GetTempFileNameA(temppath, "mth", 0, tempfilename))
360  {
361  if (dir)
362  {
363  // GetTempFileNameA creates the file, so delete it before mkdir
364  unlink(tempfilename);
365  ret = mkdir(tempfilename);
366  }
367  else
368  ret = open(tempfilename, O_CREAT | O_RDWR, S_IREAD | S_IWRITE);
369  }
370  QString tmpFileName(tempfilename);
371 #else
372  QByteArray safe_name_template = name_template.toLatin1();
373  const char *tmp = safe_name_template.constData();
374  char *ctemplate = strdup(tmp);
375 
376  if (dir)
377  {
378  ret = (mkdtemp(ctemplate)) ? 0 : -1;
379  }
380  else
381  {
382  mode_t cur_umask = umask(S_IRWXO | S_IRWXG);
383  ret = mkstemp(ctemplate);
384  umask(cur_umask);
385  }
386 
387  QString tmpFileName(ctemplate);
388  free(ctemplate);
389 #endif
390 
391  if (ret == -1)
392  {
393  LOG(VB_GENERAL, LOG_ERR, QString("createTempFile(%1), Error ")
394  .arg(name_template) + ENO);
395  return name_template;
396  }
397 
398  if (!dir && (ret >= 0))
399  close(ret);
400 
401  return tmpFileName;
402 }
403 
422 bool makeFileAccessible(const QString& filename)
423 {
424  QByteArray fname = filename.toLatin1();
425  int ret = chmod(fname.constData(), 0666);
426  if (ret == -1)
427  {
428  LOG(VB_GENERAL, LOG_ERR, QString("Unable to change permissions on file. (%1)").arg(filename));
429  return false;
430  }
431  return true;
432 }
433 
437 QString getResponse(const QString &query, const QString &def)
438 {
439  QByteArray tmp = query.toLocal8Bit();
440  cout << tmp.constData();
441 
442  tmp = def.toLocal8Bit();
443  if (def.size())
444  cout << " [" << tmp.constData() << "] ";
445  else
446  cout << " ";
447 
448  if (!isatty(fileno(stdin)) || !isatty(fileno(stdout)))
449  {
450  cout << endl << "[console is not interactive, using default '"
451  << tmp.constData() << "']" << endl;
452  return def;
453  }
454 
455  QTextStream stream(stdin);
456  QString qresponse = stream.readLine();
457 
458  if (qresponse.isEmpty())
459  qresponse = def;
460 
461  return qresponse;
462 }
463 
467 int intResponse(const QString &query, int def)
468 {
469  QString str_resp = getResponse(query, QString("%1").arg(def));
470  if (str_resp.isEmpty())
471  return def;
472  bool ok = false;
473  int resp = str_resp.toInt(&ok);
474  return (ok ? resp : def);
475 }
476 
477 
478 QString getSymlinkTarget(const QString &start_file,
479  QStringList *intermediaries,
480  unsigned maxLinks)
481 {
482 #if 0
483  LOG(VB_GENERAL, LOG_DEBUG,
484  QString("getSymlinkTarget('%1', 0x%2, %3)")
485  .arg(start_file).arg((uint64_t)intermediaries,0,16)
486  .arg(maxLinks));
487 #endif
488 
489  QString link;
490  QString cur_file = start_file;
491  QFileInfo fi(cur_file);
492 
493  if (intermediaries)
494  {
495  intermediaries->clear();
496  intermediaries->push_back(start_file);
497  }
498 
499  for (uint i = 0; (i <= maxLinks) && fi.isSymLink() &&
500  !(link = fi.symLinkTarget()).isEmpty(); i++)
501  {
502  cur_file = (link[0] == '/') ?
503  link : // absolute link
504  fi.absoluteDir().absolutePath() + "/" + link; // relative link
505 
506  if (intermediaries && !intermediaries->contains(cur_file))
507  intermediaries->push_back(cur_file);
508 
509  fi = QFileInfo(cur_file);
510  }
511 
512 #if 0
513  if (intermediaries)
514  {
515  for (uint i = 0; i < intermediaries->size(); i++)
516  {
517  LOG(VB_GENERAL, LOG_DEBUG, QString(" inter%1: %2")
518  .arg(i).arg((*intermediaries)[i]));
519  }
520  }
521 
522  LOG(VB_GENERAL, LOG_DEBUG,
523  QString("getSymlinkTarget() -> '%1'")
524  .arg((!fi.isSymLink()) ? cur_file : QString()));
525 #endif
526 
527  return (!fi.isSymLink()) ? cur_file : QString();
528 }
529 
530 bool IsMACAddress(const QString& MAC)
531 {
532  QStringList tokens = MAC.split(':');
533  if (tokens.size() != 6)
534  {
535  LOG(VB_NETWORK, LOG_ERR,
536  QString("IsMACAddress(%1) = false, doesn't have 6 parts").arg(MAC));
537  return false;
538  }
539 
540  for (int y = 0; y < 6; y++)
541  {
542  if (tokens[y].isEmpty())
543  {
544  LOG(VB_NETWORK, LOG_ERR,
545  QString("IsMACAddress(%1) = false, part #%2 is empty.")
546  .arg(MAC).arg(y));
547  return false;
548  }
549 
550  bool ok = false;
551  int value = tokens[y].toInt(&ok, 16);
552  if (!ok)
553  {
554  LOG(VB_NETWORK, LOG_ERR,
555  QString("IsMACAddress(%1) = false, unable to "
556  "convert part '%2' to integer.")
557  .arg(MAC).arg(tokens[y]));
558  return false;
559  }
560 
561  if (value > 255)
562  {
563  LOG(VB_NETWORK, LOG_ERR,
564  QString("IsMACAddress(%1) = false, part #%2 "
565  "evaluates to %3 which is higher than 255.")
566  .arg(MAC).arg(y).arg(value));
567  return false;
568  }
569  }
570 
571  LOG(VB_NETWORK, LOG_DEBUG, QString("IsMACAddress(%1) = true").arg(MAC));
572  return true;
573 }
574 
575 QString FileHash(const QString& filename)
576 {
577  QFile file(filename);
578  QFileInfo fileinfo(file);
579  qint64 initialsize = fileinfo.size();
580  quint64 hash = 0;
581 
582  if (initialsize == 0)
583  return QString("NULL");
584 
585  if (file.open(QIODevice::ReadOnly))
586  hash = initialsize;
587  else
588  {
589  LOG(VB_GENERAL, LOG_ERR,
590  "Error: Unable to open selected file, missing read permissions?");
591  return QString("NULL");
592  }
593 
594  file.seek(0);
595  QDataStream stream(&file);
596  stream.setByteOrder(QDataStream::LittleEndian);
597  for (quint64 tmp = 0, i = 0; i < 65536/sizeof(tmp); i++)
598  {
599  stream >> tmp;
600  hash += tmp;
601  }
602 
603  file.seek(initialsize - 65536);
604  for (quint64 tmp = 0, i = 0; i < 65536/sizeof(tmp); i++)
605  {
606  stream >> tmp;
607  hash += tmp;
608  }
609 
610  file.close();
611 
612  QString output = QString("%1").arg(hash, 0, 16);
613  return output;
614 }
615 
616 bool WakeOnLAN(const QString& MAC)
617 {
618  char msg[1024] = "\xFF\xFF\xFF\xFF\xFF\xFF";
619  int msglen = 6;
620  QStringList tokens = MAC.split(':');
621  int macaddr[6];
622 
623  if (tokens.size() != 6)
624  {
625  LOG(VB_GENERAL, LOG_ERR,
626  QString( "WakeOnLan(%1): Incorrect MAC length").arg(MAC));
627  return false;
628  }
629 
630  for (int y = 0; y < 6; y++)
631  {
632  bool ok = false;
633  macaddr[y] = tokens[y].toInt(&ok, 16);
634 
635  if (!ok)
636  {
637  LOG(VB_GENERAL, LOG_ERR,
638  QString( "WakeOnLan(%1): Invalid MAC address").arg(MAC));
639  return false;
640  }
641  }
642 
643  for (int x = 0; x < 16; x++)
644  for (int y : macaddr)
645  msg[msglen++] = y;
646 
647  LOG(VB_NETWORK, LOG_INFO,
648  QString("WakeOnLan(): Sending WOL packet to %1").arg(MAC));
649 
650  QUdpSocket udp_socket;
651  return udp_socket.writeDatagram(
652  msg, msglen, QHostAddress::Broadcast, 32767) == msglen;
653 }
654 
655 // Wake up either by command or by MAC address
656 // return true = success
657 bool MythWakeup(const QString &wakeUpCommand, uint flags, uint timeout)
658 {
659  if (!IsMACAddress(wakeUpCommand))
660  return myth_system(wakeUpCommand, flags, timeout) == 0U;
661 
662  return WakeOnLAN(wakeUpCommand);
663 }
664 
666 {
667 #ifdef _WIN32
668  return false;
669 #else
670 
671 #if CONFIG_DARWIN || (__FreeBSD__) || defined(__OpenBSD__)
672  const char *command = "ps -ax | grep -i pulseaudio | grep -v grep > /dev/null";
673 #else
674  const char *command = "ps ch -C pulseaudio -o pid > /dev/null";
675 #endif
676  // Do NOT use kMSProcessEvents here, it will cause deadlock
677  uint res = myth_system(command, kMSDontBlockInputDevs |
679  return (res == GENERIC_EXIT_OK);
680 #endif // _WIN32
681 }
682 
683 bool myth_nice(int val)
684 {
685  errno = 0;
686  int ret = nice(val);
687 
688  if ((-1 == ret) && (0 != errno) && (val >= 0))
689  {
690  LOG(VB_GENERAL, LOG_ERR, "Failed to nice process" + ENO);
691  return false;
692  }
693 
694  return true;
695 }
696 
697 void myth_yield(void)
698 {
699 #ifdef _POSIX_PRIORITY_SCHEDULING
700  if (sched_yield()<0)
701  usleep(5000);
702 #else
703  usleep(5000);
704 #endif
705 }
706 
724 #if defined(__linux__) && ( defined(__i386__) || defined(__ppc__) || \
725  defined(__x86_64__) || defined(__ia64__) )
726 
727 #include <cstdio>
728 #include <cstdlib>
729 #include <cerrno>
730 #include <getopt.h>
731 #include <unistd.h>
732 #include <sys/ptrace.h>
733 #include <asm/unistd.h>
734 
735 #if defined(__i386__)
736 # define __NR_ioprio_set 289
737 # define __NR_ioprio_get 290
738 #elif defined(__ppc__)
739 # define __NR_ioprio_set 273
740 # define __NR_ioprio_get 274
741 #elif defined(__x86_64__)
742 # define __NR_ioprio_set 251
743 # define __NR_ioprio_get 252
744 #elif defined(__ia64__)
745 # define __NR_ioprio_set 1274
746 # define __NR_ioprio_get 1275
747 #endif
748 
749 #define IOPRIO_BITS (16)
750 #define IOPRIO_CLASS_SHIFT (13)
751 #define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1)
752 #define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT)
753 #define IOPRIO_PRIO_DATA(mask) ((mask) & IOPRIO_PRIO_MASK)
754 #define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | (data))
755 
756 enum { IOPRIO_CLASS_NONE,IOPRIO_CLASS_RT,IOPRIO_CLASS_BE,IOPRIO_CLASS_IDLE, };
757 enum { IOPRIO_WHO_PROCESS = 1, IOPRIO_WHO_PGRP, IOPRIO_WHO_USER, };
758 
759 bool myth_ioprio(int val)
760 {
761  int new_ioclass = (val < 0) ? IOPRIO_CLASS_RT :
762  (val > 7) ? IOPRIO_CLASS_IDLE : IOPRIO_CLASS_BE;
763  int new_iodata = (new_ioclass == IOPRIO_CLASS_BE) ? val : 0;
764  int new_ioprio = IOPRIO_PRIO_VALUE(new_ioclass, new_iodata);
765 
766  int pid = getpid();
767  int old_ioprio = syscall(__NR_ioprio_get, IOPRIO_WHO_PROCESS, pid);
768  if (old_ioprio == new_ioprio)
769  return true;
770 
771  int ret = syscall(__NR_ioprio_set, IOPRIO_WHO_PROCESS, pid, new_ioprio);
772 
773  if (-1 == ret && EPERM == errno && IOPRIO_CLASS_BE != new_ioclass)
774  {
775  new_iodata = (new_ioclass == IOPRIO_CLASS_RT) ? 0 : 7;
776  new_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, new_iodata);
777  ret = syscall(__NR_ioprio_set, IOPRIO_WHO_PROCESS, pid, new_ioprio);
778  }
779 
780  return 0 == ret;
781 }
782 
783 #else
784 
785 bool myth_ioprio(int) { return true; }
786 
787 #endif
788 
789 bool MythRemoveDirectory(QDir &aDir)
790 {
791  if (!aDir.exists())//QDir::NoDotAndDotDot
792  return false;
793 
794  QFileInfoList entries = aDir.entryInfoList(QDir::NoDotAndDotDot |
795  QDir::Dirs | QDir::Files);
796  int count = entries.size();
797  bool has_err = false;
798 
799  for (int idx = 0; idx < count && !has_err; idx++)
800  {
801  QFileInfo entryInfo = entries[idx];
802  QString path = entryInfo.absoluteFilePath();
803  if (entryInfo.isDir())
804  {
805  QDir dir(path);
806  has_err = MythRemoveDirectory(dir);
807  }
808  else
809  {
810  QFile file(path);
811  if (!file.remove())
812  has_err = true;
813  }
814  }
815 
816  if (!has_err && !aDir.rmdir(aDir.absolutePath()))
817  has_err = true;
818 
819  return(has_err);
820 }
821 
833 void setHttpProxy(void)
834 {
835  QString LOC = "setHttpProxy() - ";
836  QNetworkProxy p;
837 
838 
839  // Set http proxy for the application if specified in environment variable
840  QString var(getenv("http_proxy"));
841  if (var.isEmpty())
842  var = getenv("HTTP_PROXY"); // Sadly, some OS envs are case sensitive
843  if (var.length())
844  {
845  if (!var.startsWith("http://")) // i.e. just a host name
846  var.prepend("http://");
847 
848  QUrl url = QUrl(var, QUrl::TolerantMode);
849  QString host = url.host();
850  int port = url.port();
851 
852  if (port == -1) // Parsing error
853  {
854  port = 0; // The default when creating a QNetworkProxy
855 
856  if (telnet(host, 1080)) // Socks?
857  port = 1080;
858  if (telnet(host, 3128)) // Squid
859  port = 3128;
860  if (telnet(host, 8080)) // MS ISA
861  port = 8080;
862 
863  LOG(VB_NETWORK, LOG_INFO, LOC +
864  QString("assuming port %1 on host %2") .arg(port).arg(host));
865  url.setPort(port);
866  }
867  else if (!ping(host, 1))
868  {
869  LOG(VB_GENERAL, LOG_ERR, LOC +
870  QString("cannot locate host %1").arg(host) +
871  "\n\t\t\tPlease check HTTP_PROXY environment variable!");
872  }
873  else if (!telnet(host,port))
874  {
875  LOG(VB_GENERAL, LOG_ERR, LOC +
876  QString("%1:%2 - cannot connect!").arg(host).arg(port) +
877  "\n\t\t\tPlease check HTTP_PROXY environment variable!");
878  }
879 
880 #if 0
881  LOG(VB_NETWORK, LOG_DEBUG, LOC + QString("using http://%1:%2@%3:%4")
882  .arg(url.userName()).arg(url.password())
883  .arg(host).arg(port));
884 #endif
885  p = QNetworkProxy(QNetworkProxy::HttpCachingProxy,
886  host, port, url.userName(), url.password());
887  QNetworkProxy::setApplicationProxy(p);
888  return;
889  }
890 
891  LOG(VB_NETWORK, LOG_DEBUG, LOC + "no HTTP_PROXY environment var.");
892 
893  // Use Qt to look for user proxy settings stored by the OS or browser:
894 
895  QList<QNetworkProxy> proxies;
896  QNetworkProxyQuery query(QUrl("http://www.mythtv.org"));
897 
898  proxies = QNetworkProxyFactory::systemProxyForQuery(query);
899 
900  Q_FOREACH (p, proxies)
901  {
902  QString host = p.hostName();
903  int port = p.port();
904 
905  if (p.type() == QNetworkProxy::NoProxy)
906  continue;
907 
908  if (!telnet(host, port))
909  {
910  LOG(VB_NETWORK, LOG_ERR, LOC +
911  "failed to contact proxy host " + host);
912  continue;
913  }
914 
915  LOG(VB_NETWORK, LOG_INFO, LOC + QString("using proxy host %1:%2")
916  .arg(host).arg(port));
917  QNetworkProxy::setApplicationProxy(p);
918 
919  // Allow sub-commands to use this proxy
920  // via myth_system(command), by setting HTTP_PROXY
921  QString url;
922 
923  if (!p.user().isEmpty())
924  {
925  url = "http://%1:%2@%3:%4",
926  url = url.arg(p.user()).arg(p.password());
927  }
928  else
929  {
930  url = "http://%1:%2";
931  }
932 
933  url = url.arg(p.hostName()).arg(p.port());
934  setenv("HTTP_PROXY", url.toLatin1(), 1);
935  setenv("http_proxy", url.toLatin1(), 0);
936 
937  return;
938  }
939 
940  LOG(VB_NETWORK, LOG_ERR, LOC + "failed to find a network proxy");
941 }
942 
943 void wrapList(QStringList &list, int width)
944 {
945  // if this is triggered, something has gone seriously wrong
946  // the result won't really be usable, but at least it won't crash
947  width = max(width, 5);
948 
949  for (int i = 0; i < list.size(); i++)
950  {
951  QString string = list.at(i);
952 
953  if( string.size() <= width )
954  continue;
955 
956  QString left = string.left(width);
957  bool inserted = false;
958 
959  while( !inserted && !left.endsWith(" " ))
960  {
961  if( string.mid(left.size(), 1) == " " )
962  {
963  list.replace(i, left);
964  list.insert(i+1, string.mid(left.size()).trimmed());
965  inserted = true;
966  }
967  else
968  {
969  left.chop(1);
970  if( !left.contains(" ") )
971  {
972  // Line is too long, just hyphenate it
973  list.replace(i, left + "-");
974  list.insert(i+1, string.mid(left.size()));
975  inserted = true;
976  }
977  }
978  }
979 
980  if( !inserted )
981  {
982  left.chop(1);
983  list.replace(i, left);
984  list.insert(i+1, string.mid(left.size()).trimmed());
985  }
986  }
987 }
988 
989 QString xml_indent(uint level)
990 {
991  static QReadWriteLock s_rwLock;
992  static QMap<uint,QString> s_cache;
993 
994  s_rwLock.lockForRead();
995  QMap<uint,QString>::const_iterator it = s_cache.find(level);
996  if (it != s_cache.end())
997  {
998  QString tmp = *it;
999  s_rwLock.unlock();
1000  return tmp;
1001  }
1002  s_rwLock.unlock();
1003 
1004  QString ret = "";
1005  for (uint i = 0; i < level; i++)
1006  ret += " ";
1007 
1008  s_rwLock.lockForWrite();
1009  s_cache[level] = ret;
1010  s_rwLock.unlock();
1011 
1012  return ret;
1013 }
1014 
1015 int naturalCompare(const QString &_a, const QString &_b, Qt::CaseSensitivity caseSensitivity)
1016 {
1017  // This method chops the input a and b into pieces of
1018  // digits and non-digits (a1.05 becomes a | 1 | . | 05)
1019  // and compares these pieces of a and b to each other
1020  // (first with first, second with second, ...).
1021  //
1022  // This is based on the natural sort order code code by Martin Pool
1023  // http://sourcefrog.net/projects/natsort/
1024  // Martin Pool agreed to license this under LGPL or GPL.
1025 
1026  // FIXME: Using toLower() to implement case insensitive comparison is
1027  // sub-optimal, but is needed because we compare strings with
1028  // localeAwareCompare(), which does not know about case sensitivity.
1029  // A task has been filled for this in Qt Task Tracker with ID 205990.
1030  // http://trolltech.com/developer/task-tracker/index_html?method=entry&id=205990
1031 
1032  QString a;
1033  QString b;
1034 
1035  if (caseSensitivity == Qt::CaseSensitive)
1036  {
1037  a = _a;
1038  b = _b;
1039  }
1040  else
1041  {
1042  a = _a.toLower();
1043  b = _b.toLower();
1044  }
1045 
1046  const QChar* currA = a.unicode(); // iterator over a
1047  const QChar* currB = b.unicode(); // iterator over b
1048 
1049  if (currA == currB)
1050  {
1051  return 0;
1052  }
1053 
1054  while (!currA->isNull() && !currB->isNull())
1055  {
1056  const QChar* begSeqA = currA; // beginning of a new character sequence of a
1057  const QChar* begSeqB = currB;
1058 
1059  if (currA->unicode() == QChar::ObjectReplacementCharacter)
1060  {
1061  return 1;
1062  }
1063 
1064  if (currB->unicode() == QChar::ObjectReplacementCharacter)
1065  {
1066  return -1;
1067  }
1068 
1069  if (currA->unicode() == QChar::ReplacementCharacter)
1070  {
1071  return 1;
1072  }
1073 
1074  if (currB->unicode() == QChar::ReplacementCharacter)
1075  {
1076  return -1;
1077  }
1078 
1079  // find sequence of characters ending at the first non-character
1080  while (!currA->isNull() && !currA->isDigit() && !currA->isPunct() &&
1081  !currA->isSpace())
1082  {
1083  ++currA;
1084  }
1085 
1086  while (!currB->isNull() && !currB->isDigit() && !currB->isPunct() &&
1087  !currB->isSpace())
1088  {
1089  ++currB;
1090  }
1091 
1092  // compare these sequences
1093  const QStringRef& subA(a.midRef(begSeqA - a.unicode(), currA - begSeqA));
1094  const QStringRef& subB(b.midRef(begSeqB - b.unicode(), currB - begSeqB));
1095  const int cmp = QStringRef::localeAwareCompare(subA, subB);
1096 
1097  if (cmp != 0)
1098  {
1099  return cmp < 0 ? -1 : +1;
1100  }
1101 
1102  if (currA->isNull() || currB->isNull())
1103  {
1104  break;
1105  }
1106 
1107  // find sequence of characters ending at the first non-character
1108  while ((currA->isPunct() || currA->isSpace()) &&
1109  (currB->isPunct() || currB->isSpace()))
1110  {
1111  if (*currA != *currB)
1112  {
1113  return (*currA < *currB) ? -1 : +1;
1114  }
1115  ++currA;
1116  ++currB;
1117  if (currA->isNull() || currB->isNull())
1118  {
1119  break;
1120  }
1121  }
1122 
1123  // now some digits follow...
1124  if ((*currA == QLatin1Char('0')) || (*currB == QLatin1Char('0')))
1125  {
1126  // one digit-sequence starts with 0 -> assume we are in a fraction part
1127  // do left aligned comparison (numbers are considered left aligned)
1128  while (true)
1129  {
1130  if (!currA->isDigit() && !currB->isDigit())
1131  {
1132  break;
1133  }
1134  if (!currA->isDigit())
1135  {
1136  return +1;
1137  }
1138  if (!currB->isDigit())
1139  {
1140  return -1;
1141  }
1142  if (*currA < *currB)
1143  {
1144  return -1;
1145  }
1146  if (*currA > *currB)
1147  {
1148  return + 1;
1149  }
1150  ++currA;
1151  ++currB;
1152  }
1153  }
1154  else
1155  {
1156  // No digit-sequence starts with 0 -> assume we are looking at some integer
1157  // do right aligned comparison.
1158  //
1159  // The longest run of digits wins. That aside, the greatest
1160  // value wins, but we can't know that it will until we've scanned
1161  // both numbers to know that they have the same magnitude.
1162 
1163  bool isFirstRun = true;
1164  int weight = 0;
1165 
1166  while (true)
1167  {
1168  if (!currA->isDigit() && !currB->isDigit())
1169  {
1170  if (weight != 0)
1171  {
1172  return weight;
1173  }
1174  break;
1175  }
1176  if (!currA->isDigit())
1177  {
1178  if (isFirstRun)
1179  {
1180  return *currA < *currB ? -1 : +1;
1181  }
1182  return -1;
1183  }
1184  if (!currB->isDigit())
1185  {
1186  if (isFirstRun)
1187  {
1188  return *currA < *currB ? -1 : +1;
1189  }
1190  return +1;
1191  }
1192  if ((*currA < *currB) && (weight == 0))
1193  {
1194  weight = -1;
1195  }
1196  else if ((*currA > *currB) && (weight == 0))
1197  {
1198  weight = + 1;
1199  }
1200  ++currA;
1201  ++currB;
1202  isFirstRun = false;
1203  }
1204  }
1205  }
1206 
1207  if (currA->isNull() && currB->isNull())
1208  {
1209  return 0;
1210  }
1211 
1212  return currA->isNull() ? -1 : + 1;
1213 }
1214 
1215 /* vim: set expandtab tabstop=4 shiftwidth=4: */
int intResponse(const QString &query, int def)
In an interactive shell, prompt the user to input a number.
#define GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:10
void setHttpProxy(void)
Get network proxy settings from OS, and use for [Q]Http[Comms].
bool WakeOnLAN(const QString &MAC)
#define LOC
bool myth_ioprio(int)
Allows setting the I/O priority of the current process/thread.
QString getSymlinkTarget(const QString &start_file, QStringList *intermediaries, unsigned maxLinks)
bool MythWakeup(const QString &wakeUpCommand, uint flags, uint timeout)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
bool getMemStats(int &totalMB, int &freeMB, int &totalVM, int &freeVM)
Returns memory statistics in megabytes.
long long copy(QFile &dst, QFile &src, uint block_size)
Copies src file to dst file.
static guint32 * tmp
Definition: goom_core.c:35
bool telnet(const QString &host, int port)
Can we talk to port on host?
unsigned int block_size
bool makeFileAccessible(const QString &filename)
#define close
Definition: compat.h:16
bool ping(const QString &host, int timeout)
Can we ping host within timeout seconds?
bool IsPulseAudioRunning(void)
Is A/V Sync destruction daemon is running on this host?
static QString resolveAddress(const QString &host, ResolveType type=ResolveAny, bool keepscope=false)
if host is an IP address, it will be returned or resolved otherwise.
#define nice(x)
Definition: compat.h:195
unsigned int uint
Definition: compat.h:140
QString getResponse(const QString &query, const QString &def)
In an interactive shell, prompt the user to input a string.
uint myth_system(const QString &command, uint flags, uint timeout)
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:99
int64_t getDiskSpace(const QString &file_on_disk, int64_t &total, int64_t &used)
QString createTempFile(QString name_template, bool dir)
bool myth_nice(int val)
process events while waiting
Definition: mythsystem.h:37
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
void wrapList(QStringList &list, int width)
avoid disabling UI drawing
Definition: mythsystem.h:35
bool hasUtf8(const char *str)
Guess whether a string is UTF-8.
Class for communcating between myth backends and frontends.
Definition: mythsocket.h:26
#define setenv(x, y, z)
Definition: compat.h:156
bool MythRemoveDirectory(QDir &aDir)
void myth_yield(void)
string temppath
Definition: mythburn.py:161
QString FileHash(const QString &filename)
int naturalCompare(const QString &_a, const QString &_b, Qt::CaseSensitivity caseSensitivity)
avoid blocking LIRC & Joystick Menu
Definition: mythsystem.h:34
bool getUptime(time_t &uptime)
Returns uptime statistics.
bool IsMACAddress(const QString &MAC)
QString xml_indent(uint level)
#define output