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