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