gedia

cutycapt.cpp (with hacks for qt5.9999 on gentoo - cur 5.3.0)

Nov 8th, 2013
158
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ////////////////////////////////////////////////////////////////////
  2. //
  3. // CutyCapt - A Qt WebKit Web Page Rendering Capture Utility
  4. //
  5. // Copyright (C) 2003-2013 Bjoern Hoehrmann <bjoern@hoehrmann.de>
  6. //
  7. // This program is free software; you can redistribute it and/or
  8. // modify it under the terms of the GNU General Public License
  9. // as published by the Free Software Foundation; either version 2
  10. // of the License, or (at your option) any later version.
  11. //
  12. // This program is free software; you can redistribute it and/or
  13. // modify it under the terms of the GNU Lesser General Public
  14. // License as published by the Free Software Foundation; either
  15. // version 2.1 of the License, or (at your option) any later version.
  16. //
  17. // This program is distributed in the hope that it will be useful,
  18. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20. // GNU General Public License for more details.
  21. //
  22. // $Id: CutyCapt.cpp 10 2013-07-14 21:57:37Z hoehrmann $
  23. //
  24. ////////////////////////////////////////////////////////////////////
  25.  
  26. #include <QApplication>
  27. #include <QtWebKit>
  28. #include <QtGui>
  29. #include <QSvgGenerator>
  30. #include <QtPrintSupport/QPrinter>
  31.  
  32. #if QT_VERSION < 0x050000
  33. #include <QPrinter>
  34. #endif
  35.  
  36. #include <QTimer>
  37. #include <QByteArray>
  38. #include <QNetworkRequest>
  39. #include <fstream>
  40. #include <QNetworkProxy>
  41. #include "CutyCapt.hpp"
  42. #include "CookieJar.hpp"
  43.  
  44. #if QT_VERSION >= 0x040600 && 0
  45. #define CUTYCAPT_SCRIPT 1
  46. #endif
  47.  
  48. #ifdef STATIC_PLUGINS
  49.   Q_IMPORT_PLUGIN(qjpeg)
  50.   Q_IMPORT_PLUGIN(qgif)
  51.   Q_IMPORT_PLUGIN(qtiff)
  52.   Q_IMPORT_PLUGIN(qsvg)
  53.   Q_IMPORT_PLUGIN(qmng)
  54.   Q_IMPORT_PLUGIN(qico)
  55. #endif
  56.  
  57. static struct _CutyExtMap {
  58.   CutyCapt::OutputFormat id;
  59.   const char* extension;
  60.   const char* identifier;
  61. } const CutyExtMap[] = {
  62.   { CutyCapt::SvgFormat,         ".svg",        "svg"   },
  63.   { CutyCapt::PdfFormat,         ".pdf",        "pdf"   },
  64.   { CutyCapt::PsFormat,          ".ps",         "ps"    },
  65.   { CutyCapt::InnerTextFormat,   ".txt",        "itext" },
  66.   { CutyCapt::HtmlFormat,        ".html",       "html"  },
  67. #if QT_VERSION < 0x050000
  68.   { CutyCapt::RenderTreeFormat,  ".rtree",      "rtree" },
  69. #endif
  70.   { CutyCapt::JpegFormat,        ".jpeg",       "jpeg"  },
  71.   { CutyCapt::PngFormat,         ".png",        "png"   },
  72.   { CutyCapt::MngFormat,         ".mng",        "mng"   },
  73.   { CutyCapt::TiffFormat,        ".tiff",       "tiff"  },
  74.   { CutyCapt::GifFormat,         ".gif",        "gif"   },
  75.   { CutyCapt::BmpFormat,         ".bmp",        "bmp"   },
  76.   { CutyCapt::PpmFormat,         ".ppm",        "ppm"   },
  77.   { CutyCapt::XbmFormat,         ".xbm",        "xbm"   },
  78.   { CutyCapt::XpmFormat,         ".xpm",        "xpm"   },
  79.   { CutyCapt::OtherFormat,       "",            ""      }
  80. };
  81.  
  82. QString
  83. CutyPage::chooseFile(QWebFrame* /*frame*/, const QString& /*suggestedFile*/) {
  84.   return QString::null;
  85. }
  86.  
  87. bool
  88. CutyPage::javaScriptConfirm(QWebFrame* /*frame*/, const QString& /*msg*/) {
  89.   return true;
  90. }
  91.  
  92. bool
  93. CutyPage::javaScriptPrompt(QWebFrame* /*frame*/,
  94.                            const QString& /*msg*/,
  95.                            const QString& /*defaultValue*/,
  96.                            QString* /*result*/) {
  97.   return true;
  98. }
  99.  
  100. void
  101. CutyPage::javaScriptConsoleMessage(const QString& /*message*/,
  102.                                    int /*lineNumber*/,
  103.                                    const QString& /*sourceID*/) {
  104.   // noop
  105. }
  106.  
  107. void
  108. CutyPage::javaScriptAlert(QWebFrame* /*frame*/, const QString& msg) {
  109.  
  110.   if (mPrintAlerts)
  111.     qDebug() << "[alert]" << msg;
  112.  
  113.   if (mAlertString == msg) {
  114.     QTimer::singleShot(10, mCutyCapt, SLOT(Delayed()));
  115.   }
  116. }
  117.  
  118. QString
  119. CutyPage::userAgentForUrl(const QUrl& url) const {
  120.  
  121.   if (!mUserAgent.isNull())
  122.     return mUserAgent;
  123.  
  124.   return QWebPage::userAgentForUrl(url);
  125. }
  126.  
  127. void
  128. CutyPage::setUserAgent(const QString& userAgent) {
  129.   mUserAgent = userAgent;
  130. }
  131.  
  132. void
  133. CutyPage::setAlertString(const QString& alertString) {
  134.   mAlertString = alertString;
  135. }
  136.  
  137. QString
  138. CutyPage::getAlertString() {
  139.   return mAlertString;
  140. }
  141.  
  142. void
  143. CutyPage::setCutyCapt(CutyCapt* cutyCapt) {
  144.   mCutyCapt = cutyCapt;
  145. }
  146.  
  147. void
  148. CutyPage::setPrintAlerts(bool printAlerts) {
  149.   mPrintAlerts = printAlerts;
  150. }
  151.  
  152. void
  153. CutyPage::setAttribute(QWebSettings::WebAttribute option,
  154.                        const QString& value) {
  155.  
  156.   if (value == "on")
  157.     settings()->setAttribute(option, true);
  158.   else if (value == "off")
  159.     settings()->setAttribute(option, false);
  160.   else
  161.     (void)0; // TODO: ...
  162. }
  163.  
  164. // TODO: Consider merging some of main() and CutyCap
  165.  
  166.   CutyCapt::CutyCapt(CutyPage* page, const QString& output, const QString& htmlOutput, int delay, OutputFormat format,
  167.                    const QString& scriptProp, const QString& scriptCode, const QString& cookieJarPath, bool insecure,
  168.            bool smooth) {
  169.   mPage = page;
  170.   mOutput = output;
  171.   mHtmlOutput = htmlOutput;
  172.   mDelay = delay;
  173.   mInsecure = insecure;
  174.   mSmooth = smooth;
  175.   mSawInitialLayout = false;
  176.   mSawDocumentComplete = false;
  177.   mFormat = format;
  178.   mScriptProp = scriptProp;
  179.   mScriptCode = scriptCode;
  180.   mCookieJarPath = cookieJarPath;
  181.   mScriptObj = new QObject();
  182.  
  183.   // This is not really nice, but some restructuring work is
  184.   // needed anyway, so this should not be that bad for now.
  185.   mPage->setCutyCapt(this);
  186. }
  187.  
  188. CutyCapt::~CutyCapt() {
  189.     delete mScriptObj;
  190. }
  191.  
  192. void
  193. CutyCapt::InitialLayoutCompleted() {
  194.   mSawInitialLayout = true;
  195.  
  196.   if (mSawInitialLayout && mSawDocumentComplete)
  197.     TryDelayedRender();
  198. }
  199.  
  200. void
  201. CutyCapt::DocumentComplete(bool /*ok*/) {
  202.   mSawDocumentComplete = true;
  203.  
  204.   if (mSawInitialLayout && mSawDocumentComplete)
  205.     TryDelayedRender();
  206. }
  207.  
  208. void
  209. CutyCapt::JavaScriptWindowObjectCleared() {
  210.  
  211.   if (!mScriptProp.isEmpty()) {
  212.     QVariant var = mPage->mainFrame()->evaluateJavaScript(mScriptProp);
  213.     QObject* obj = var.value<QObject*>();
  214.  
  215.     if (obj == mScriptObj)
  216.       return;
  217.  
  218.     mPage->mainFrame()->addToJavaScriptWindowObject(mScriptProp, mScriptObj);
  219.   }
  220.  
  221.   mPage->mainFrame()->evaluateJavaScript(mScriptCode);
  222.  
  223. }
  224.  
  225. void
  226. CutyCapt::TryDelayedRender() {
  227.  
  228.   if (!mPage->getAlertString().isEmpty())
  229.     return;
  230.  
  231.   if (mDelay > 0) {
  232.     QTimer::singleShot(mDelay, this, SLOT(Delayed()));
  233.     return;
  234.   }
  235.  
  236.   saveSnapshot();
  237.   QApplication::exit();
  238. }
  239.  
  240. void
  241. CutyCapt::Timeout() {
  242.   saveSnapshot();
  243.   QApplication::exit();
  244. }
  245.  
  246. void
  247. CutyCapt::Delayed() {
  248.   saveSnapshot();
  249.   QApplication::exit();
  250. }
  251.  
  252. void
  253. CutyCapt::handleSslErrors(QNetworkReply* reply, QList<QSslError> errors) {
  254.   if (mInsecure) {
  255.     reply->ignoreSslErrors();
  256.   } else {
  257.     // TODO: what to do here instead of hanging?
  258.   }
  259. }
  260.  
  261. void
  262. CutyCapt::saveSnapshot() {
  263.   QWebFrame *mainFrame = mPage->mainFrame();
  264.   QPainter painter;
  265.   const char* format = NULL;
  266.  
  267.   for (int ix = 0; CutyExtMap[ix].id != OtherFormat; ++ix)
  268.     if (CutyExtMap[ix].id == mFormat)
  269.       format = CutyExtMap[ix].identifier; //, break;
  270.  
  271.   // TODO: sometimes contents/viewport can have size 0x0
  272.   // in which case saving them will fail. This is likely
  273.   // the result of the method being called too early. So
  274.   // far I've been unable to find a workaround, except
  275.   // using --delay with some substantial wait time. I've
  276.   // tried to resize multiple time, make a fake render,
  277.   // check for other events... This is primarily a problem
  278.   // under my Ubuntu virtual machine.
  279.  
  280.   mPage->setViewportSize( mainFrame->contentsSize() );
  281.  
  282.   switch (mFormat) {
  283.     case SvgFormat: {
  284.       QSvgGenerator svg;
  285.       svg.setFileName(mOutput);
  286.       svg.setSize(mPage->viewportSize());
  287.       painter.begin(&svg);
  288.       mainFrame->render(&painter);
  289.       painter.end();
  290.       break;
  291.     }
  292.     case PdfFormat:
  293.     case PsFormat: {
  294.       QPrinter printer(QPrinter::HighResolution);
  295.       printer.setPageSize(QPrinter::A4);
  296.       printer.setOutputFileName(mOutput);
  297.       // TODO: change quality here?
  298.       mainFrame->print(&printer);
  299.       break;
  300.     }
  301. #if QT_VERSION < 0x050000
  302.     case RenderTreeFormat: {
  303.       QFile file(mOutput);
  304.       file.open(QIODevice::WriteOnly | QIODevice::Text);
  305.       QTextStream s(&file);
  306.       s.setCodec("utf-8");
  307.       s << mainFrame->renderTreeDump();
  308.       break;
  309.     }
  310. #endif
  311.     case InnerTextFormat:
  312.     case HtmlFormat: {
  313.       QFile file(mOutput);
  314.       file.open(QIODevice::WriteOnly | QIODevice::Text);
  315.       QTextStream s(&file);
  316.       s.setCodec("utf-8");
  317.       s << (mFormat == InnerTextFormat  ? mainFrame->toPlainText() :
  318.             mFormat == HtmlFormat       ? mainFrame->toHtml() :
  319.             "bug");
  320.       break;
  321.     }
  322.     default: {
  323.       QImage image(mPage->viewportSize(), QImage::Format_ARGB32);
  324.       painter.begin(&image);
  325. #if QT_VERSION >= 0x050000
  326.       if (mSmooth) {
  327.         painter.setRenderHint(QPainter::SmoothPixmapTransform);
  328.         painter.setRenderHint(QPainter::Antialiasing);
  329.         painter.setRenderHint(QPainter::TextAntialiasing);
  330.         painter.setRenderHint(QPainter::HighQualityAntialiasing);
  331.       }
  332. #endif
  333.       mainFrame->render(&painter);
  334.       painter.end();
  335.       // TODO: add quality
  336.       image.save(mOutput, format);
  337.     }
  338.   };
  339.  
  340.   if(!mCookieJarPath.isEmpty()) {
  341.       CookieJar* cookieJar = static_cast<CookieJar*>(mPage->networkAccessManager()->cookieJar());
  342.       bool success = cookieJar->serialize(mCookieJarPath);
  343.  
  344.       if(!success) {
  345.           fprintf(stderr, "fatal: unable to serialize cookies to cookie jar path\n");
  346.           exit(1);
  347.       }
  348.   }
  349.  
  350.   if(!mHtmlOutput.isEmpty()) {
  351.       std::ofstream out(mHtmlOutput.toLatin1().constData());
  352.       out << mPage->currentFrame()->toHtml().toLatin1().constData();
  353.       out.close();
  354.   }
  355.  
  356.  
  357. }
  358.  
  359. void
  360. CaptHelp(void) {
  361.   printf("%s",
  362.     " -----------------------------------------------------------------------------\n"
  363.     " Usage: CutyCapt --url=http://www.example.org/ --out=localfile.png            \n"
  364.     " -----------------------------------------------------------------------------\n"
  365.     "  --help                         Print this help page and exit                \n"
  366.     "  --url=<url>                    The URL to capture (http:...|file:...|...)   \n"
  367.     "  --out=<path>                   The target file (.png|pdf|ps|svg|jpeg|...)   \n"
  368.     "  --html-out=<path>              The target file for the html of the page     \n"
  369.     "  --out-format=<f>               Like extension in --out, overrides heuristic \n"
  370. //  "  --out-quality=<int>            Output format quality from 1 to 100          \n"
  371.     "  --min-width=<int>              Minimal width for the image (default: 800)   \n"
  372.     "  --min-height=<int>             Minimal height for the image (default: 600)  \n"
  373.     "  --max-wait=<ms>                Don't wait more than (default: 90000, inf: 0)\n"
  374.     "  --delay=<ms>                   After successful load, wait (default: 0)     \n"
  375. //  "  --user-styles=<url>            Location of user style sheet (deprecated)    \n"
  376.     "  --user-style-path=<path>       Location of user style sheet file, if any    \n"
  377.     "  --user-style-string=<css>      User style rules specified as text           \n"
  378.     "  --header=<name>:<value>        request header; repeatable; some can't be set\n"
  379.     "  --method=<get|post|put>        Specifies the request method (default: get)  \n"
  380.     "  --body-string=<string>         Unencoded request body (default: none)       \n"
  381.     "  --body-base64=<base64>         Base64-encoded request body (default: none)  \n"
  382.     "  --app-name=<name>              appName used in User-Agent; default is none  \n"
  383.     "  --app-version=<version>        appVers used in User-Agent; default is none  \n"
  384.     "  --user-agent=<string>          Override the User-Agent header Qt would set  \n"
  385.     "  --javascript=<on|off>          JavaScript execution (default: on)           \n"
  386.     "  --java=<on|off>                Java execution (default: unknown)            \n"
  387.     "  --plugins=<on|off>             Plugin execution (default: unknown)          \n"
  388.     "  --private-browsing=<on|off>    Private browsing (default: unknown)          \n"
  389.     "  --auto-load-images=<on|off>    Automatic image loading (default: on)        \n"
  390.     "  --js-can-open-windows=<on|off> Script can open windows? (default: unknown)  \n"
  391.     "  --js-can-access-clipboard=<on|off> Script clipboard privs (default: unknown)\n"
  392.     "  --cookie-jar=<path>            The path to the cookie jar to use when making\n"
  393.     "                                 requests. Cookies will be read from this file\n"
  394.     "                                 and saved back to it after the request.      \n"
  395. #if QT_VERSION >= 0x040500
  396.     "  --print-backgrounds=<on|off>   Backgrounds in PDF/PS output (default: off)  \n"
  397.     "  --zoom-factor=<float>          Page zoom factor (default: no zooming)       \n"
  398.     "  --zoom-text-only=<on|off>      Whether to zoom only the text (default: off) \n"
  399.     "  --http-proxy=<url>             Address for HTTP proxy server (default: none)\n"
  400. #endif
  401. #if CUTYCAPT_SCRIPT
  402.     "  --inject-script=<path>         JavaScript that will be injected into pages  \n"
  403.     "  --script-object=<string>       Property to hold state for injected script   \n"
  404.     "  --expect-alert=<string>        Try waiting for alert(string) before capture \n"
  405.     "  --debug-print-alerts           Prints out alert(...) strings for debugging. \n"
  406. #endif
  407. #if QT_VERSION >= 0x050000
  408.     "  --smooth                       Attempt to enable Qt's high-quality settings.\n"
  409. #endif
  410.     "  --insecure                     Ignore SSL/TLS certificate errors            \n"
  411.     " -----------------------------------------------------------------------------\n"
  412.     "  <f> is svg,ps,pdf,itext,html,rtree,png,jpeg,mng,tiff,gif,bmp,ppm,xbm,xpm    \n"
  413.     " -----------------------------------------------------------------------------\n"
  414. #if CUTYCAPT_SCRIPT
  415.     " The `inject-script` option can be used to inject script code into loaded web \n"
  416.     " pages. The code is called whenever the `javaScriptWindowObjectCleared` signal\n"
  417.     " is received. When `script-object` is set, an object under the specified name \n"
  418.     " will be available to the script to maintain state across page loads. When the\n"
  419.     " `expect-alert` option is specified, the shot will be taken when a script in- \n"
  420.     " vokes alert(string) with the string if that happens before `max-wait`. These \n"
  421.     " options effectively allow you to remote control the browser and the web page.\n"
  422.     " This an experimental and easily abused and misused feature. Use with caution.\n"
  423.     " -----------------------------------------------------------------------------\n"
  424. #endif
  425.     " http://cutycapt.sf.net - (c) 2003-2013 Bjoern Hoehrmann - bjoern@hoehrmann.de\n"
  426.     "");
  427. }
  428.  
  429. int
  430. main(int argc, char *argv[]) {
  431.  
  432.   int argHelp = 0;
  433.   int argDelay = 0;
  434.   int argSilent = 0;
  435.   int argInsecure = 0;
  436.   int argMinWidth = 800;
  437.   int argMinHeight = 600;
  438.   int argMaxWait = 90000;
  439.   int argVerbosity = 0;
  440.   int argSmooth = 0;
  441.  
  442.   const char* argUrl = NULL;
  443.   const char* argUserStyle = NULL;
  444.   const char* argUserStylePath = NULL;
  445.   const char* argUserStyleString = NULL;
  446.   const char* argIconDbPath = NULL;
  447.   const char* argInjectScript = NULL;
  448.   const char* argScriptObject = NULL;
  449.   QString argOut;
  450.   QString argHtmlOut;
  451.  
  452.   CutyCapt::OutputFormat format = CutyCapt::OtherFormat;
  453.  
  454.   QApplication app(argc, argv, true);
  455.   CutyPage* page = new CutyPage;
  456.  
  457.   QNetworkAccessManager::Operation method =
  458.     QNetworkAccessManager::GetOperation;
  459.   QByteArray body;
  460.   QNetworkRequest req;
  461.   QNetworkAccessManager manager;
  462.  
  463.   QString cookieJarPath = "";
  464.   CookieJar cookieJar;
  465.  
  466.   // Parse command line parameters
  467.   for (int ax = 1; ax < argc; ++ax) {
  468.     size_t nlen;
  469.  
  470.     const char* s = argv[ax];
  471.     const char* value;
  472.  
  473.     // boolean options
  474.     if (strcmp("--silent", s) == 0) {
  475.       argSilent = 1;
  476.       continue;
  477.  
  478.     } else if (strcmp("--help", s) == 0) {
  479.       argHelp = 1;
  480.       break;
  481.  
  482.     } else if (strcmp("--verbose", s) == 0) {
  483.       argVerbosity++;
  484.       continue;
  485.  
  486.     } else if (strcmp("--insecure", s) == 0) {
  487.       argInsecure = 1;
  488.       continue;
  489.  
  490. #if QT_VERSION >= 0x050000
  491.     } else if (strcmp("--smooth", s) == 0) {
  492.       argSmooth = 1;
  493.       continue;
  494. #endif
  495.  
  496. #if CUTYCAPT_SCRIPT
  497.     } else if (strcmp("--debug-print-alerts", s) == 0) {
  498.       page->setPrintAlerts(true);
  499.       continue;
  500. #endif
  501.     }
  502.  
  503.     value = strchr(s, '=');
  504.  
  505.     if (value == NULL) {
  506.       // TODO: error
  507.       argHelp = 1;
  508.       break;
  509.     }
  510.  
  511.     nlen = value++ - s;
  512.  
  513.     // --name=value options
  514.     if (strncmp("--url", s, nlen) == 0) {
  515.       argUrl = value;
  516.  
  517.     } else if (strncmp("--min-width", s, nlen) == 0) {
  518.       // TODO: add error checking here?
  519.       argMinWidth = (unsigned int)atoi(value);
  520.  
  521.     } else if (strncmp("--min-height", s, nlen) == 0) {
  522.       // TODO: add error checking here?
  523.       argMinHeight = (unsigned int)atoi(value);
  524.  
  525.     } else if (strncmp("--delay", s, nlen) == 0) {
  526.       // TODO: see above
  527.       argDelay = (unsigned int)atoi(value);
  528.  
  529.     } else if (strncmp("--max-wait", s, nlen) == 0) {
  530.       // TODO: see above
  531.       argMaxWait = (unsigned int)atoi(value);
  532.  
  533.     } else if (strncmp("--out", s, nlen) == 0) {
  534.       argOut = value;
  535.  
  536.       if (format == CutyCapt::OtherFormat)
  537.         for (int ix = 0; CutyExtMap[ix].id != CutyCapt::OtherFormat; ++ix)
  538.           if (argOut.endsWith(CutyExtMap[ix].extension))
  539.             format = CutyExtMap[ix].id; //, break;
  540.  
  541.     } else if (strncmp("--html-out", s, nlen) == 0) {
  542.         argHtmlOut = value;
  543.      
  544.     } else if (strncmp("--user-styles", s, nlen) == 0) {
  545.       // This option is provided for backwards-compatibility only
  546.       argUserStyle = value;
  547.  
  548.     } else if (strncmp("--user-style-path", s, nlen) == 0) {
  549.       argUserStylePath = value;
  550.  
  551.     } else if (strncmp("--user-style-string", s, nlen) == 0) {
  552.       argUserStyleString = value;
  553.  
  554.     } else if (strncmp("--icon-database-path", s, nlen) == 0) {
  555.       argIconDbPath = value;
  556.  
  557.     } else if (strncmp("--auto-load-images", s, nlen) == 0) {
  558.       page->setAttribute(QWebSettings::AutoLoadImages, value);
  559.  
  560.     } else if (strncmp("--javascript", s, nlen) == 0) {
  561.       page->setAttribute(QWebSettings::JavascriptEnabled, value);
  562.  
  563.     } else if (strncmp("--java", s, nlen) == 0) {
  564.       page->setAttribute(QWebSettings::JavaEnabled, value);
  565.  
  566.     } else if (strncmp("--plugins", s, nlen) == 0) {
  567.       page->setAttribute(QWebSettings::PluginsEnabled, value);
  568.  
  569.     } else if (strncmp("--private-browsing", s, nlen) == 0) {
  570.       page->setAttribute(QWebSettings::PrivateBrowsingEnabled, value);
  571.  
  572.     } else if (strncmp("--js-can-open-windows", s, nlen) == 0) {
  573.       page->setAttribute(QWebSettings::JavascriptCanOpenWindows, value);
  574.  
  575.     } else if (strncmp("--js-can-access-clipboard", s, nlen) == 0) {
  576.       page->setAttribute(QWebSettings::JavascriptCanAccessClipboard, value);
  577.  
  578.     } else if (strncmp("--developer-extras", s, nlen) == 0) {
  579.       page->setAttribute(QWebSettings::DeveloperExtrasEnabled, value);
  580.  
  581.     } else if (strncmp("--links-included-in-focus-chain", s, nlen) == 0) {
  582.       page->setAttribute(QWebSettings::LinksIncludedInFocusChain, value);
  583.      
  584.     } else if (strncmp("--cookie-jar", s, nlen) == 0) {
  585.         cookieJarPath = value;
  586.         bool success = cookieJar.deserialize(cookieJarPath);
  587.  
  588.         if(!success) {
  589.             fprintf(stderr, "fatal: unable to deserialize cookies from cookie jar path\n");
  590.             exit(1);
  591.         }
  592.  
  593.         manager.setCookieJar(&cookieJar);
  594.         page->setNetworkAccessManager(&manager);
  595.  
  596.     #if QT_VERSION >= 0x040500
  597.     } else if (strncmp("--print-backgrounds", s, nlen) == 0) {
  598.       page->setAttribute(QWebSettings::PrintElementBackgrounds, value);
  599.  
  600.     } else if (strncmp("--zoom-factor", s, nlen) == 0) {
  601.       page->mainFrame()->setZoomFactor(QString(value).toFloat());
  602.  
  603.     } else if (strncmp("--zoom-text-only", s, nlen) == 0) {
  604.       page->setAttribute(QWebSettings::ZoomTextOnly, value);
  605.  
  606.     } else if (strncmp("--http-proxy", s, nlen) == 0) {
  607.       QUrl p = QUrl::fromEncoded(value);
  608.       QNetworkProxy proxy = QNetworkProxy(QNetworkProxy::HttpProxy,
  609.         p.host(), p.port(80), p.userName(), p.password());
  610.       manager.setProxy(proxy);
  611.       page->setNetworkAccessManager(&manager);
  612. #endif
  613.  
  614. #if CUTYCAPT_SCRIPT
  615.     } else if (strncmp("--inject-script", s, nlen) == 0) {
  616.       argInjectScript = value;
  617.  
  618.     } else if (strncmp("--script-object", s, nlen) == 0) {
  619.       argScriptObject = value;
  620.  
  621.     } else if (strncmp("--expect-alert", s, nlen) == 0) {
  622.       page->setAlertString(value);
  623. #endif
  624.  
  625.     } else if (strncmp("--app-name", s, nlen) == 0) {
  626.       app.setApplicationName(value);
  627.  
  628.     } else if (strncmp("--app-version", s, nlen) == 0) {
  629.       app.setApplicationVersion(value);
  630.  
  631.     } else if (strncmp("--body-base64", s, nlen) == 0) {
  632.       body = QByteArray::fromBase64(value);
  633.  
  634.     } else if (strncmp("--body-string", s, nlen) == 0) {
  635.       body = QByteArray(value);
  636.  
  637.     } else if (strncmp("--user-agent", s, nlen) == 0) {
  638.       page->setUserAgent(value);
  639.  
  640.     } else if (strncmp("--out-format", s, nlen) == 0) {
  641.       for (int ix = 0; CutyExtMap[ix].id != CutyCapt::OtherFormat; ++ix)
  642.         if (strcmp(value, CutyExtMap[ix].identifier) == 0)
  643.           format = CutyExtMap[ix].id; //, break;
  644.  
  645.       if (format == CutyCapt::OtherFormat) {
  646.         // TODO: error
  647.         argHelp = 1;
  648.         break;
  649.       }
  650.  
  651.     } else if (strncmp("--header", s, nlen) == 0) {
  652.       const char* hv = strchr(value, ':');
  653.  
  654.       if (hv == NULL) {
  655.         // TODO: error
  656.         argHelp = 1;
  657.         break;
  658.       }
  659.  
  660.       req.setRawHeader(QByteArray(value, hv - value), hv + 1);
  661.  
  662.     } else if (strncmp("--method", s, nlen) == 0) {
  663.       if (strcmp("value", "get") == 0)
  664.         method = QNetworkAccessManager::GetOperation;
  665.       else if (strcmp("value", "put") == 0)
  666.         method = QNetworkAccessManager::PutOperation;
  667.       else if (strcmp("value", "post") == 0)
  668.         method = QNetworkAccessManager::PostOperation;
  669.       else if (strcmp("value", "head") == 0)
  670.         method = QNetworkAccessManager::HeadOperation;
  671.       else
  672.         (void)0; // TODO: ...
  673.  
  674.     } else {
  675.       // TODO: error
  676.       argHelp = 1;
  677.     }
  678.   }
  679.  
  680.   if (argUrl == NULL || argOut == NULL || argHelp) {
  681.       CaptHelp();
  682.       return EXIT_FAILURE;
  683.   }
  684.  
  685.   // This used to use QUrl(argUrl) but that escapes %hh sequences
  686.   // even though it should not, as URLs can assumed to be escaped.
  687.   req.setUrl( QUrl::fromEncoded(argUrl) );
  688.  
  689.   QString scriptProp(argScriptObject);
  690.   QString scriptCode;
  691.  
  692.   if (argInjectScript) {
  693.     QFile file(argInjectScript);
  694.     if (file.open(QIODevice::ReadOnly)) {
  695.       QTextStream stream(&file);
  696.       stream.setCodec(QTextCodec::codecForName("UTF-8"));
  697.       stream.setAutoDetectUnicode(true);
  698.       scriptCode = stream.readAll();
  699.       file.close();
  700.     }
  701.   }
  702.  
  703.   CutyCapt main(&page, argOut, argHtmlOut, argDelay, format, scriptProp, scriptCode, cookieJarPath, !!argInsecure, !!argSmooth);
  704.  
  705.   app.connect(page,
  706.     SIGNAL(loadFinished(bool)),
  707.     &main,
  708.     SLOT(DocumentComplete(bool)));
  709.  
  710.   app.connect(page->mainFrame(),
  711.     SIGNAL(initialLayoutCompleted()),
  712.     &main,
  713.     SLOT(InitialLayoutCompleted()));
  714.  
  715.   if (argMaxWait > 0) {
  716.     // TODO: Should this also register one for the application?
  717.     QTimer::singleShot(argMaxWait, &main, SLOT(Timeout()));
  718.   }
  719.  
  720.   if (argUserStyle != NULL)
  721.     // TODO: does this need any syntax checking?
  722.     page->settings()->setUserStyleSheetUrl( QUrl::fromEncoded(argUserStyle) );
  723.  
  724.   if (argUserStylePath != NULL) {
  725.     page->settings()->setUserStyleSheetUrl( QUrl::fromLocalFile(argUserStylePath) );
  726.   }
  727.  
  728.   if (argUserStyleString != NULL) {
  729.     QUrl data("data:text/css;charset=utf-8;base64," +
  730.       QByteArray(argUserStyleString).toBase64());
  731.     page->settings()->setUserStyleSheetUrl( data );
  732.   }
  733.  
  734.   if (argIconDbPath != NULL)
  735.     // TODO: does this need any syntax checking?
  736.     page->settings()->setIconDatabasePath(argUserStyle);
  737.  
  738.   // The documentation does not say, but it seems the mainFrame
  739.   // will never change, so we can set this here. Otherwise we'd
  740.   // have to set this in snapshot and trigger an update, which
  741.   // is not currently possible (Qt 4.4.0) as far as I can tell.
  742.   page->mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
  743.   page->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
  744.   page->setViewportSize( QSize(argMinWidth, argMinHeight) );
  745.  
  746. #if CUTYCAPT_SCRIPT
  747.   // javaScriptWindowObjectCleared does not get called on the
  748.   // initial load unless some JavaScript has been executed.
  749.     page->mainFrame()->evaluateJavaScript(QString(""));
  750.  
  751.     app.connect(page->mainFrame(),
  752.     SIGNAL(javaScriptWindowObjectCleared()),
  753.     &main,
  754.     SLOT(JavaScriptWindowObjectCleared()));
  755. #endif
  756.  
  757.   app.connect(page->networkAccessManager(),
  758.     SIGNAL(sslErrors(QNetworkReply*, QList<QSslError>)),
  759.     &main,
  760.     SLOT(handleSslErrors(QNetworkReply*, QList<QSslError>)));
  761.  
  762.   if (!body.isNull())
  763.     page->mainFrame()->load(req, method, body);
  764.   else
  765.     page->mainFrame()->load(req, method);
  766.  
  767.   int status = app.exec();
  768.   delete page;
  769.   return status;
  770. }
Add Comment
Please, Sign In to add comment