MythTV  0.27pre
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
mythmiscutil.cpp
Go to the documentation of this file.
1 
2 #include "mythmiscutil.h"
3 
4 // C++ headers
5 #include <iostream>
6 
7 using namespace std;
8 
9 // C headers
10 #include <cerrno>
11 #include <stdlib.h>
12 #include <time.h>
13 
14 // POSIX
15 #include <unistd.h>
16 #include <fcntl.h>
17 #include <sched.h>
18 
19 // System specific C headers
20 #include "compat.h"
21 
22 #ifdef linux
23 #include <sys/vfs.h>
24 #include <sys/sysinfo.h>
25 #endif
26 
27 #if CONFIG_DARWIN
28 #include <mach/mach.h>
29 #endif
30 
31 #ifdef BSD
32 #include <sys/mount.h> // for struct statfs
33 #include <sys/sysctl.h>
34 #endif
35 
36 // Qt headers
37 #include <QReadWriteLock>
38 #include <QNetworkProxy>
39 #include <QStringList>
40 #include <QUdpSocket>
41 #include <QFileInfo>
42 #include <QFile>
43 #include <QDir>
44 #include <QUrl>
45 
46 // Myth headers
47 #include "mythcorecontext.h"
48 #include "exitcodes.h"
49 #include "mythlogging.h"
50 #include "mythsocket.h"
51 #include "mythcoreutil.h"
52 #include "mythsystemlegacy.h"
53 
54 #include "mythconfig.h" // for CONFIG_DARWIN
55 
60 bool getUptime(time_t &uptime)
61 {
62 #ifdef __linux__
63  struct sysinfo sinfo;
64  if (sysinfo(&sinfo) == -1)
65  {
66  LOG(VB_GENERAL, LOG_ERR, "sysinfo() error");
67  return false;
68  }
69  else
70  uptime = sinfo.uptime;
71 
72 #elif defined(__FreeBSD__) || CONFIG_DARWIN
73 
74  int mib[2];
75  struct timeval bootTime;
76  size_t len;
77 
78  // Uptime is calculated. Get this machine's boot time
79  // and subtract it from the current machine time
80  len = sizeof(bootTime);
81  mib[0] = CTL_KERN;
82  mib[1] = KERN_BOOTTIME;
83  if (sysctl(mib, 2, &bootTime, &len, NULL, 0) == -1)
84  {
85  LOG(VB_GENERAL, LOG_ERR, "sysctl() error");
86  return false;
87  }
88  else
89  uptime = time(NULL) - bootTime.tv_sec;
90 #elif defined(USING_MINGW)
91  uptime = ::GetTickCount() / 1000;
92 #else
93  // Hmmm. Not Linux, not FreeBSD or Darwin. What else is there :-)
94  LOG(VB_GENERAL, LOG_NOTICE, "Unknown platform. How do I get the uptime?");
95  return false;
96 #endif
97 
98  return true;
99 }
100 
107 bool getMemStats(int &totalMB, int &freeMB, int &totalVM, int &freeVM)
108 {
109 #ifdef __linux__
110  size_t MB = (1024*1024);
111  struct sysinfo sinfo;
112  if (sysinfo(&sinfo) == -1)
113  {
114  LOG(VB_GENERAL, LOG_ERR,
115  "getMemStats(): Error, sysinfo() call failed.");
116  return false;
117  }
118  else
119  totalMB = (int)((sinfo.totalram * sinfo.mem_unit)/MB),
120  freeMB = (int)((sinfo.freeram * sinfo.mem_unit)/MB),
121  totalVM = (int)((sinfo.totalswap * sinfo.mem_unit)/MB),
122  freeVM = (int)((sinfo.freeswap * sinfo.mem_unit)/MB);
123 
124 #elif CONFIG_DARWIN
125  mach_port_t mp;
126  mach_msg_type_number_t count;
127  vm_size_t pageSize;
128  vm_statistics_data_t s;
129 
130  mp = mach_host_self();
131 
132  // VM page size
133  if (host_page_size(mp, &pageSize) != KERN_SUCCESS)
134  pageSize = 4096; // If we can't look it up, 4K is a good guess
135 
136  count = HOST_VM_INFO_COUNT;
137  if (host_statistics(mp, HOST_VM_INFO,
138  (host_info_t)&s, &count) != KERN_SUCCESS)
139  {
140  LOG(VB_GENERAL, LOG_ERR, "getMemStats(): Error, "
141  "failed to get virtual memory statistics.");
142  return false;
143  }
144 
145  pageSize >>= 10; // This gives usages in KB
146  totalMB = (s.active_count + s.inactive_count +
147  s.wire_count + s.free_count) * pageSize / 1024;
148  freeMB = s.free_count * pageSize / 1024;
149 
150 
151  // This is a real hack. I have not found a way to ask the kernel how much
152  // swap it is using, and the dynamic_pager daemon doesn't even seem to be
153  // able to report what filesystem it is using for the swapfiles. So, we do:
154  int64_t total, used, free;
155  free = getDiskSpace("/private/var/vm", total, used);
156  totalVM = (int)(total >> 10);
157  freeVM = (int)(free >> 10);
158 
159 #else
160  LOG(VB_GENERAL, LOG_NOTICE, "getMemStats(): Unknown platform. "
161  "How do I get the memory stats?");
162  return false;
163 #endif
164 
165  return true;
166 }
167 
175 bool hasUtf8(const char *str)
176 {
177  const uchar *c = (uchar *) str;
178 
179  while (*c++)
180  {
181  // ASCII is < 0x80.
182  // 0xC2..0xF4 is probably UTF-8.
183  // Anything else probably ISO-8859-1 (Latin-1, Unicode)
184 
185  if (*c > 0xC1 && *c < 0xF5)
186  {
187  int bytesToCheck = 2; // Assume 0xC2-0xDF (2 byte sequence)
188 
189  if (*c > 0xDF) // Maybe 0xE0-0xEF (3 byte sequence)
190  ++bytesToCheck;
191  if (*c > 0xEF) // Matches 0xF0-0xF4 (4 byte sequence)
192  ++bytesToCheck;
193 
194  while (bytesToCheck--)
195  {
196  ++c;
197 
198  if (! *c) // String ended in middle
199  return false; // Not valid UTF-8
200 
201  if (*c < 0x80 || *c > 0xBF) // Bad UTF-8 sequence
202  break; // Keep checking in outer loop
203  }
204 
205  if (!bytesToCheck) // Have checked all the bytes in the sequence
206  return true; // Hooray! We found valid UTF-8!
207  }
208  }
209 
210  return false;
211 }
212 
220 bool ping(const QString &host, int timeout)
221 {
222 #ifdef USING_MINGW
223  QString cmd = QString("%systemroot%\\system32\\ping.exe -i %1 -n 1 %2>NUL")
224  .arg(timeout).arg(host);
225 
227  kMSProcessEvents) != GENERIC_EXIT_OK)
228  return false;
229 #else
230  QString cmd = QString("ping -t %1 -c 1 %2 >/dev/null 2>&1")
231  .arg(timeout).arg(host);
232 
234  kMSProcessEvents) != GENERIC_EXIT_OK)
235  {
236  // ping command may not like -t argument, or the host might not
237  // be listening. Try to narrow down with a quick ping to localhost:
238 
239  cmd = "ping -t 1 -c 1 localhost >/dev/null 2>&1";
240 
242  kMSProcessEvents) != GENERIC_EXIT_OK)
243  {
244  // Assume -t is bad - do a ping that might cause a timeout:
245  cmd = QString("ping -c 1 %1 >/dev/null 2>&1").arg(host);
246 
248  kMSProcessEvents) != GENERIC_EXIT_OK)
249  return false; // it failed with or without the -t
250 
251  return true;
252  }
253  else // Pinging localhost worked, so targeted host wasn't listening
254  return false;
255  }
256 #endif
257 
258  return true;
259 }
260 
264 bool telnet(const QString &host, int port)
265 {
266  MythSocket *s = new MythSocket();
267 
268  bool connected = s->ConnectToHost(host, port);
269  s->DecrRef();
270 
271  return connected;
272 }
273 
295 long long copy(QFile &dst, QFile &src, uint block_size)
296 {
297  uint buflen = (block_size < 1024) ? (16 * 1024) : block_size;
298  char *buf = new char[buflen];
299  bool odst = false, osrc = false;
300 
301  if (!buf)
302  return -1LL;
303 
304  if (!dst.isWritable() && !dst.isOpen())
305  odst = dst.open(QIODevice::Unbuffered |
306  QIODevice::WriteOnly |
307  QIODevice::Truncate);
308 
309  if (!src.isReadable() && !src.isOpen())
310  osrc = src.open(QIODevice::Unbuffered|QIODevice::ReadOnly);
311 
312  bool ok = dst.isWritable() && src.isReadable();
313  long long total_bytes = 0LL;
314  while (ok)
315  {
316  long long rlen, wlen, off = 0;
317  rlen = src.read(buf, buflen);
318  if (rlen<0)
319  {
320  LOG(VB_GENERAL, LOG_ERR, "read error");
321  ok = false;
322  break;
323  }
324  if (rlen==0)
325  break;
326 
327  total_bytes += (long long) rlen;
328 
329  while ((rlen-off>0) && ok)
330  {
331  wlen = dst.write(buf + off, rlen - off);
332  if (wlen>=0)
333  off+= wlen;
334  if (wlen<0)
335  {
336  LOG(VB_GENERAL, LOG_ERR, "write error");
337  ok = false;
338  }
339  }
340  }
341  delete[] buf;
342 
343  if (odst)
344  dst.close();
345 
346  if (osrc)
347  src.close();
348 
349  return (ok) ? total_bytes : -1LL;
350 }
351 
352 QString createTempFile(QString name_template, bool dir)
353 {
354  int ret = -1;
355 
356 #ifdef USING_MINGW
357  char temppath[MAX_PATH] = ".";
358  char tempfilename[MAX_PATH] = "";
359  // if GetTempPath fails, use current dir
360  GetTempPathA(MAX_PATH, temppath);
361  if (GetTempFileNameA(temppath, "mth", 0, tempfilename))
362  {
363  if (dir)
364  {
365  // GetTempFileNameA creates the file, so delete it before mkdir
366  unlink(tempfilename);
367  ret = mkdir(tempfilename);
368  }
369  else
370  ret = open(tempfilename, O_CREAT | O_RDWR, S_IREAD | S_IWRITE);
371  }
372  QString tmpFileName(tempfilename);
373 #else
374  QByteArray safe_name_template = name_template.toLatin1();
375  const char *tmp = safe_name_template.constData();
376  char *ctemplate = strdup(tmp);
377 
378  if (dir)
379  {
380  ret = (mkdtemp(ctemplate)) ? 0 : -1;
381  }
382  else
383  {
384  mode_t cur_umask = umask(S_IRWXO | S_IRWXG);
385  ret = mkstemp(ctemplate);
386  umask(cur_umask);
387  }
388 
389  QString tmpFileName(ctemplate);
390  free(ctemplate);
391 #endif
392 
393  if (ret == -1)
394  {
395  LOG(VB_GENERAL, LOG_ERR, QString("createTempFile(%1), Error ")
396  .arg(name_template) + ENO);
397  return name_template;
398  }
399 
400  if (!dir && (ret >= 0))
401  close(ret);
402 
403  return tmpFileName;
404 }
405 
425 {
426  QByteArray fname = filename.toLatin1();
427  int ret = chmod(fname.constData(), 0666);
428  if (ret == -1)
429  {
430  LOG(VB_GENERAL, LOG_ERR, QString("Unable to change permissions on file. (%1)").arg(filename));
431  return false;
432  }
433  return true;
434 }
435 
439 QString getResponse(const QString &query, const QString &def)
440 {
441  QByteArray tmp = query.toLocal8Bit();
442  cout << tmp.constData();
443 
444  tmp = def.toLocal8Bit();
445  if (def.size())
446  cout << " [" << tmp.constData() << "] ";
447  else
448  cout << " ";
449 
450  if (!isatty(fileno(stdin)) || !isatty(fileno(stdout)))
451  {
452  cout << endl << "[console is not interactive, using default '"
453  << tmp.constData() << "']" << endl;
454  return def;
455  }
456 
457  char response[80];
458  cin.clear();
459  cin.getline(response, 80);
460  if (!cin.good())
461  {
462  cout << endl;
463  LOG(VB_GENERAL, LOG_ERR, "Read from stdin failed");
464  return NULL;
465  }
466 
467  QString qresponse = response;
468 
469  if (qresponse.isEmpty())
470  qresponse = def;
471 
472  return qresponse;
473 }
474 
478 int intResponse(const QString &query, int def)
479 {
480  QString str_resp = getResponse(query, QString("%1").arg(def));
481  if (str_resp.isEmpty())
482  return def;
483  bool ok;
484  int resp = str_resp.toInt(&ok);
485  return (ok ? resp : def);
486 }
487 
488 
489 QString getSymlinkTarget(const QString &start_file,
490  QStringList *intermediaries,
491  unsigned maxLinks)
492 {
493 #if 0
494  LOG(VB_GENERAL, LOG_DEBUG,
495  QString("getSymlinkTarget('%1', 0x%2, %3)")
496  .arg(start_file).arg((uint64_t)intermediaries,0,16)
497  .arg(maxLinks));
498 #endif
499 
500  QString link = QString::null;
501  QString cur_file = start_file; cur_file.detach();
502  QFileInfo fi(cur_file);
503 
504  if (intermediaries)
505  {
506  intermediaries->clear();
507  intermediaries->push_back(start_file);
508  }
509 
510  for (uint i = 0; (i <= maxLinks) && fi.isSymLink() &&
511  !(link = fi.readLink()).isEmpty(); i++)
512  {
513  cur_file = (link[0] == '/') ?
514  link : // absolute link
515  fi.absoluteDir().absolutePath() + "/" + link; // relative link
516 
517  if (intermediaries && !intermediaries->contains(cur_file))
518  intermediaries->push_back(cur_file);
519 
520  fi = QFileInfo(cur_file);
521  }
522 
523  if (intermediaries)
524  intermediaries->detach();
525 
526 #if 0
527  if (intermediaries)
528  {
529  for (uint i = 0; i < intermediaries->size(); i++)
530  {
531  LOG(VB_GENERAL, LOG_DEBUG, QString(" inter%1: %2")
532  .arg(i).arg((*intermediaries)[i]));
533  }
534  }
535 
536  LOG(VB_GENERAL, LOG_DEBUG,
537  QString("getSymlinkTarget() -> '%1'")
538  .arg((!fi.isSymLink()) ? cur_file : QString::null));
539 #endif
540 
541  return (!fi.isSymLink()) ? cur_file : QString::null;
542 }
543 
545 {
546  MythEvent me(QString("PLAYBACK_START %1").arg(gCoreContext->GetHostName()));
548 }
549 
550 void sendPlaybackEnd(void)
551 {
552  MythEvent me(QString("PLAYBACK_END %1").arg(gCoreContext->GetHostName()));
554 }
555 
556 bool IsMACAddress(QString MAC)
557 {
558  QStringList tokens = MAC.split(':');
559  if (tokens.size() != 6)
560  {
561  LOG(VB_NETWORK, LOG_ERR,
562  QString("IsMACAddress(%1) = false, doesn't have 6 parts").arg(MAC));
563  return false;
564  }
565 
566  int y;
567  bool ok;
568  int value;
569  for (y = 0; y < 6; y++)
570  {
571  if (tokens[y].isEmpty())
572  {
573  LOG(VB_NETWORK, LOG_ERR,
574  QString("IsMACAddress(%1) = false, part #%2 is empty.")
575  .arg(MAC).arg(y));
576  return false;
577  }
578 
579  value = tokens[y].toInt(&ok, 16);
580  if (!ok)
581  {
582  LOG(VB_NETWORK, LOG_ERR,
583  QString("IsMACAddress(%1) = false, unable to "
584  "convert part '%2' to integer.")
585  .arg(MAC).arg(tokens[y]));
586  return false;
587  }
588 
589  if (value > 255)
590  {
591  LOG(VB_NETWORK, LOG_ERR,
592  QString("IsMACAddress(%1) = false, part #%2 "
593  "evaluates to %3 which is higher than 255.")
594  .arg(MAC).arg(y).arg(value));
595  return false;
596  }
597  }
598 
599  LOG(VB_NETWORK, LOG_DEBUG, QString("IsMACAddress(%1) = true").arg(MAC));
600  return true;
601 }
602 
603 QString FileHash(QString filename)
604 {
605  QFile file(filename);
606  QFileInfo fileinfo(file);
607  qint64 initialsize = fileinfo.size();
608  quint64 hash = 0;
609 
610  if (initialsize == 0)
611  return QString("NULL");
612 
613  if (file.open(QIODevice::ReadOnly))
614  hash = initialsize;
615  else
616  {
617  LOG(VB_GENERAL, LOG_ERR,
618  "Error: Unable to open selected file, missing read permissions?");
619  return QString("NULL");
620  }
621 
622  file.seek(0);
623  QDataStream stream(&file);
624  stream.setByteOrder(QDataStream::LittleEndian);
625  for (quint64 tmp = 0, i = 0; i < 65536/sizeof(tmp); i++)
626  {
627  stream >> tmp;
628  hash += tmp;
629  }
630 
631  file.seek(initialsize - 65536);
632  for (quint64 tmp = 0, i = 0; i < 65536/sizeof(tmp); i++)
633  {
634  stream >> tmp;
635  hash += tmp;
636  }
637 
638  file.close();
639 
640  QString output = QString("%1").arg(hash, 0, 16);
641  return output;
642 }
643 
644 bool WakeOnLAN(QString MAC)
645 {
646  char msg[1024] = "\xFF\xFF\xFF\xFF\xFF\xFF";
647  int msglen = 6;
648  int x, y;
649  QStringList tokens = MAC.split(':');
650  int macaddr[6];
651  bool ok;
652 
653  if (tokens.size() != 6)
654  {
655  LOG(VB_GENERAL, LOG_ERR,
656  QString( "WakeOnLan(%1): Incorrect MAC length").arg(MAC));
657  return false;
658  }
659 
660  for (y = 0; y < 6; y++)
661  {
662  macaddr[y] = tokens[y].toInt(&ok, 16);
663 
664  if (!ok)
665  {
666  LOG(VB_GENERAL, LOG_ERR,
667  QString( "WakeOnLan(%1): Invalid MAC address").arg(MAC));
668  return false;
669  }
670  }
671 
672  for (x = 0; x < 16; x++)
673  for (y = 0; y < 6; y++)
674  msg[msglen++] = macaddr[y];
675 
676  LOG(VB_NETWORK, LOG_INFO,
677  QString("WakeOnLan(): Sending WOL packet to %1").arg(MAC));
678 
679  QUdpSocket udp_socket;
680  return udp_socket.writeDatagram(
681  msg, msglen, QHostAddress::Broadcast, 32767) == msglen;
682 }
683 
685 {
686 #ifdef USING_MINGW
687  return false;
688 #else
689 
690 #if CONFIG_DARWIN || (__FreeBSD__) || defined(__OpenBSD__)
691  const char *command = "ps -ax | grep -i pulseaudio | grep -v grep > /dev/null";
692 #else
693  const char *command = "ps ch -C pulseaudio -o pid > /dev/null";
694 #endif
695  // Do NOT use kMSProcessEvents here, it will cause deadlock
696  uint res = myth_system(command, kMSDontBlockInputDevs |
698  return (res == GENERIC_EXIT_OK);
699 #endif // USING_MINGW
700 }
701 
702 bool myth_nice(int val)
703 {
704  errno = 0;
705  int ret = nice(val);
706 
707  if ((-1 == ret) && (0 != errno) && (val >= 0))
708  {
709  LOG(VB_GENERAL, LOG_ERR, "Failed to nice process" + ENO);
710  return false;
711  }
712 
713  return true;
714 }
715 
716 void myth_yield(void)
717 {
718 #ifdef _POSIX_PRIORITY_SCHEDULING
719  if (sched_yield()<0)
720  usleep(5000);
721 #else
722  usleep(5000);
723 #endif
724 }
725 
743 #if defined(__linux__) && ( defined(__i386__) || defined(__ppc__) || \
744  defined(__x86_64__) || defined(__ia64__) )
745 
746 #include <stdio.h>
747 #include <stdlib.h>
748 #include <errno.h>
749 #include <getopt.h>
750 #include <unistd.h>
751 #include <sys/ptrace.h>
752 #include <asm/unistd.h>
753 
754 #if defined(__i386__)
755 # define __NR_ioprio_set 289
756 # define __NR_ioprio_get 290
757 #elif defined(__ppc__)
758 # define __NR_ioprio_set 273
759 # define __NR_ioprio_get 274
760 #elif defined(__x86_64__)
761 # define __NR_ioprio_set 251
762 # define __NR_ioprio_get 252
763 #elif defined(__ia64__)
764 # define __NR_ioprio_set 1274
765 # define __NR_ioprio_get 1275
766 #endif
767 
768 #define IOPRIO_BITS (16)
769 #define IOPRIO_CLASS_SHIFT (13)
770 #define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1)
771 #define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT)
772 #define IOPRIO_PRIO_DATA(mask) ((mask) & IOPRIO_PRIO_MASK)
773 #define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data)
774 
777 
778 bool myth_ioprio(int val)
779 {
780  int new_ioclass = (val < 0) ? IOPRIO_CLASS_RT :
781  (val > 7) ? IOPRIO_CLASS_IDLE : IOPRIO_CLASS_BE;
782  int new_iodata = (new_ioclass == IOPRIO_CLASS_BE) ? val : 0;
783  int new_ioprio = IOPRIO_PRIO_VALUE(new_ioclass, new_iodata);
784 
785  int pid = getpid();
786  int old_ioprio = syscall(__NR_ioprio_get, IOPRIO_WHO_PROCESS, pid);
787  if (old_ioprio == new_ioprio)
788  return true;
789 
790  int ret = syscall(__NR_ioprio_set, IOPRIO_WHO_PROCESS, pid, new_ioprio);
791 
792  if (-1 == ret && EPERM == errno && IOPRIO_CLASS_BE != new_ioclass)
793  {
794  new_iodata = (new_ioclass == IOPRIO_CLASS_RT) ? 0 : 7;
795  new_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, new_iodata);
796  ret = syscall(__NR_ioprio_set, IOPRIO_WHO_PROCESS, pid, new_ioprio);
797  }
798 
799  return 0 == ret;
800 }
801 
802 #else
803 
804 bool myth_ioprio(int) { return true; }
805 
806 #endif
807 
808 bool MythRemoveDirectory(QDir &aDir)
809 {
810  if (!aDir.exists())//QDir::NoDotAndDotDot
811  return false;
812 
813  QFileInfoList entries = aDir.entryInfoList(QDir::NoDotAndDotDot |
814  QDir::Dirs | QDir::Files);
815  int count = entries.size();
816  bool has_err = false;
817 
818  for (int idx = 0; idx < count && !has_err; idx++)
819  {
820  QFileInfo entryInfo = entries[idx];
821  QString path = entryInfo.absoluteFilePath();
822  if (entryInfo.isDir())
823  {
824  QDir dir(path);
825  has_err = MythRemoveDirectory(dir);
826  }
827  else
828  {
829  QFile file(path);
830  if (!file.remove())
831  has_err = true;
832  }
833  }
834 
835  if (!has_err && !aDir.rmdir(aDir.absolutePath()))
836  has_err = true;
837 
838  return(has_err);
839 }
840 
852 void setHttpProxy(void)
853 {
854  QString LOC = "setHttpProxy() - ";
855  QNetworkProxy p;
856 
857 
858  // Set http proxy for the application if specified in environment variable
859  QString var(getenv("http_proxy"));
860  if (var.isEmpty())
861  var = getenv("HTTP_PROXY"); // Sadly, some OS envs are case sensitive
862  if (var.length())
863  {
864  if (!var.startsWith("http://")) // i.e. just a host name
865  var.prepend("http://");
866 
867  QUrl url = QUrl(var, QUrl::TolerantMode);
868  QString host = url.host();
869  int port = url.port();
870 
871  if (port == -1) // Parsing error
872  {
873  port = 0; // The default when creating a QNetworkProxy
874 
875  if (telnet(host, 1080)) // Socks?
876  port = 1080;
877  if (telnet(host, 3128)) // Squid
878  port = 3128;
879  if (telnet(host, 8080)) // MS ISA
880  port = 8080;
881 
882  LOG(VB_NETWORK, LOG_INFO, LOC +
883  QString("assuming port %1 on host %2") .arg(port).arg(host));
884  url.setPort(port);
885  }
886  else if (!ping(host, 1))
887  LOG(VB_GENERAL, LOG_ERR, LOC +
888  QString("cannot locate host %1").arg(host) +
889  "\n\t\t\tPlease check HTTP_PROXY environment variable!");
890  else if (!telnet(host,port))
891  LOG(VB_GENERAL, LOG_ERR, LOC +
892  QString("%1:%2 - cannot connect!").arg(host).arg(port) +
893  "\n\t\t\tPlease check HTTP_PROXY environment variable!");
894 
895 #if 0
896  LOG(VB_NETWORK, LOG_DEBUG, LOC + QString("using http://%1:%2@%3:%4")
897  .arg(url.userName()).arg(url.password())
898  .arg(host).arg(port));
899 #endif
900  p = QNetworkProxy(QNetworkProxy::HttpCachingProxy,
901  host, port, url.userName(), url.password());
902  QNetworkProxy::setApplicationProxy(p);
903  return;
904  }
905 
906  LOG(VB_NETWORK, LOG_DEBUG, LOC + "no HTTP_PROXY environment var.");
907 
908  // Use Qt to look for user proxy settings stored by the OS or browser:
909 
910  QList<QNetworkProxy> proxies;
911  QNetworkProxyQuery query(QUrl("http://www.mythtv.org"));
912 
913  proxies = QNetworkProxyFactory::systemProxyForQuery(query);
914 
915  Q_FOREACH (p, proxies)
916  {
917  QString host = p.hostName();
918  int port = p.port();
919 
920  if (p.type() == QNetworkProxy::NoProxy)
921  continue;
922 
923  if (!telnet(host, port))
924  {
925  LOG(VB_NETWORK, LOG_ERR, LOC +
926  "failed to contact proxy host " + host);
927  continue;
928  }
929 
930  LOG(VB_NETWORK, LOG_INFO, LOC + QString("using proxy host %1:%2")
931  .arg(host).arg(port));
932  QNetworkProxy::setApplicationProxy(p);
933 
934  // Allow sub-commands to use this proxy
935  // via myth_system(command), by setting HTTP_PROXY
936  QString url;
937 
938  if (p.user().length())
939  url = "http://%1:%2@%3:%4",
940  url = url.arg(p.user()).arg(p.password());
941  else
942  url = "http://%1:%2";
943 
944  url = url.arg(p.hostName()).arg(p.port());
945  setenv("HTTP_PROXY", url.toLatin1(), 1);
946  setenv("http_proxy", url.toLatin1(), 0);
947 
948  return;
949  }
950 
951  LOG(VB_NETWORK, LOG_ERR, LOC + "failed to find a network proxy");
952 }
953 
954 void wrapList(QStringList &list, int width)
955 {
956  int i;
957 
958  for(i = 0; i < list.size(); i++)
959  {
960  QString string = list.at(i);
961 
962  if( string.size() <= width )
963  continue;
964 
965  QString left = string.left(width);
966  bool inserted = false;
967 
968  while( !inserted && !left.endsWith(" " ))
969  {
970  if( string.mid(left.size(), 1) == " " )
971  {
972  list.replace(i, left);
973  list.insert(i+1, string.mid(left.size()).trimmed());
974  inserted = true;
975  }
976  else
977  {
978  left.chop(1);
979  if( !left.contains(" ") )
980  {
981  // Line is too long, just hyphenate it
982  list.replace(i, left + "-");
983  list.insert(i+1, string.mid(left.size()));
984  inserted = true;
985  }
986  }
987  }
988 
989  if( !inserted )
990  {
991  left.chop(1);
992  list.replace(i, left);
993  list.insert(i+1, string.mid(left.size()).trimmed());
994  }
995  }
996 }
997 
999 {
1000  static QReadWriteLock rw_lock;
1001  static QMap<uint,QString> cache;
1002 
1003  rw_lock.lockForRead();
1004  QMap<uint,QString>::const_iterator it = cache.find(level);
1005  if (it != cache.end())
1006  {
1007  QString tmp = *it;
1008  rw_lock.unlock();
1009  return tmp;
1010  }
1011  rw_lock.unlock();
1012 
1013  QString ret = "";
1014  for (uint i = 0; i < level; i++)
1015  ret += " ";
1016 
1017  rw_lock.lockForWrite();
1018  cache[level] = ret;
1019  rw_lock.unlock();
1020 
1021  return ret;
1022 }
1023 
1024 /* vim: set expandtab tabstop=4 shiftwidth=4: */