1 /* 2 Copyright (c) 2020, Lukas Holecek <hluk@email.cz> 3 4 This file is part of CopyQ. 5 6 CopyQ is free software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 CopyQ is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with CopyQ. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #ifndef SCRIPTABLE_H 21 #define SCRIPTABLE_H 22 23 #include "common/clipboardmode.h" 24 #include "common/command.h" 25 #include "common/mimetypes.h" 26 27 #include <QObject> 28 #include <QString> 29 #include <QJSValue> 30 #include <QVariantMap> 31 #include <QVector> 32 33 #include "platform/platformnativeinterface.h" 34 35 class Action; 36 class ClipboardBrowser; 37 class ItemFactory; 38 class NetworkReply; 39 class ScriptableProxy; 40 41 class QFile; 42 class QMimeData; 43 class QNetworkReply; 44 class QNetworkAccessManager; 45 class QJSEngine; 46 class QTextCodec; 47 48 enum class ClipboardOwnership; 49 50 class Scriptable final : public QObject 51 { 52 Q_OBJECT 53 Q_PROPERTY(QJSValue inputSeparator READ getInputSeparator WRITE setInputSeparator) 54 Q_PROPERTY(QJSValue mimeText READ getMimeText CONSTANT) 55 Q_PROPERTY(QJSValue mimeHtml READ getMimeHtml CONSTANT) 56 Q_PROPERTY(QJSValue mimeUriList READ getMimeUriList CONSTANT) 57 Q_PROPERTY(QJSValue mimeWindowTitle READ getMimeWindowTitle CONSTANT) 58 Q_PROPERTY(QJSValue mimeItems READ getMimeItems CONSTANT) 59 Q_PROPERTY(QJSValue mimeItemNotes READ getMimeItemNotes CONSTANT) 60 Q_PROPERTY(QJSValue mimeIcon READ getMimeIcon CONSTANT) 61 Q_PROPERTY(QJSValue mimeOwner READ getMimeOwner CONSTANT) 62 Q_PROPERTY(QJSValue mimeClipboardMode READ getMimeClipboardMode CONSTANT) 63 Q_PROPERTY(QJSValue mimeCurrentTab READ getMimeCurrentTab CONSTANT) 64 Q_PROPERTY(QJSValue mimeSelectedItems READ getMimeSelectedItems CONSTANT) 65 Q_PROPERTY(QJSValue mimeCurrentItem READ getMimeCurrentItem CONSTANT) 66 Q_PROPERTY(QJSValue mimeHidden READ getMimeHidden CONSTANT) 67 Q_PROPERTY(QJSValue mimeShortcut READ getMimeShortcut CONSTANT) 68 Q_PROPERTY(QJSValue mimeColor READ getMimeColor CONSTANT) 69 Q_PROPERTY(QJSValue mimeOutputTab READ getMimeOutputTab CONSTANT) 70 71 Q_PROPERTY(QJSValue plugins READ getPlugins CONSTANT) 72 73 Q_PROPERTY(QJSValue _copyqUncaughtException READ uncaughtException WRITE setUncaughtException) 74 Q_PROPERTY(QJSValue _copyqHasUncaughtException READ hasUncaughtException) 75 Q_PROPERTY(QJSValue _initItemSelection WRITE initItemSelection) 76 77 public: 78 explicit Scriptable( 79 QJSEngine *engine, 80 ScriptableProxy *proxy, 81 QObject *parent = nullptr); 82 83 enum class Abort { 84 None, 85 CurrentEvaluation, 86 AllEvaluations, 87 }; 88 89 QJSValue argumentsArray() const; 90 int argumentCount() const; 91 QJSValue argument(int index) const; 92 93 QJSValue newByteArray(const QByteArray &bytes) const; 94 95 QByteArray fromString(const QString &value) const; 96 QVariant toVariant(const QJSValue &value); 97 bool toInt(const QJSValue &value, int *number) const; 98 QVariantMap toDataMap(const QJSValue &value) const; 99 QJSValue fromDataMap(const QVariantMap &dataMap) const; 100 101 QByteArray makeByteArray(const QJSValue &value) const; 102 103 /** 104 * Set data for item converted from @a value. 105 * Return true if data was successfully converted and set. 106 * 107 * If mime starts with "text/" or isn't byte array the value is re-encoded 108 * from local encoding to UTF8. 109 */ 110 bool toItemData(const QJSValue &value, const QString &mime, QVariantMap *data) const; 111 112 QJSValue getInputSeparator() const; 113 void setInputSeparator(const QJSValue &separator); 114 115 QString getCurrentPath() const; 116 void setCurrentPath(const QString &path); 117 118 QString getAbsoluteFilePath(const QString &fileName) const; 119 120 QString arg(int i, const QString &defaultValue = QString()); 121 122 QJSValue throwError(const QString &errorMessage); 123 QJSValue throwSaveError(const QString &filePath); 124 QJSValue throwImportError(const QString &filePath); 125 126 bool hasUncaughtException() const; 127 void clearExceptions(); uncaughtException()128 QJSValue uncaughtException() const { return m_uncaughtException; } 129 void setUncaughtException(const QJSValue &exc); 130 engine()131 QJSEngine *engine() const { return m_engine; } 132 canContinue()133 bool canContinue() const { return m_abort == Abort::None && !m_failed; } 134 135 void installObject(QObject *fromObj, const QMetaObject *metaObject, QJSValue &toObject); 136 getMimeText()137 QJSValue getMimeText() const { return mimeText; } getMimeHtml()138 QJSValue getMimeHtml() const { return mimeHtml; } getMimeUriList()139 QJSValue getMimeUriList() const { return mimeUriList; } getMimeWindowTitle()140 QJSValue getMimeWindowTitle() const { return mimeWindowTitle; } getMimeItems()141 QJSValue getMimeItems() const { return mimeItems; } getMimeItemNotes()142 QJSValue getMimeItemNotes() const { return mimeItemNotes; } getMimeIcon()143 QJSValue getMimeIcon() const { return mimeIcon; } getMimeOwner()144 QJSValue getMimeOwner() const { return mimeOwner; } getMimeClipboardMode()145 QJSValue getMimeClipboardMode() const { return mimeClipboardMode; } getMimeCurrentTab()146 QJSValue getMimeCurrentTab() const { return mimeCurrentTab; } getMimeSelectedItems()147 QJSValue getMimeSelectedItems() const { return mimeSelectedItems; } getMimeCurrentItem()148 QJSValue getMimeCurrentItem() const { return mimeCurrentItem; } getMimeHidden()149 QJSValue getMimeHidden() const { return mimeHidden; } getMimeShortcut()150 QJSValue getMimeShortcut() const { return mimeShortcut; } getMimeColor()151 QJSValue getMimeColor() const { return mimeColor; } getMimeOutputTab()152 QJSValue getMimeOutputTab() const { return mimeOutputTab; } 153 154 QJSValue getPlugins(); 155 156 QJSValue eval(const QString &script, const QString &label); 157 158 QJSValue call(const QString &label, QJSValue *fn, const QVariantList &arguments); 159 QJSValue call(const QString &label, QJSValue *fn, const QJSValueList &arguments = QJSValueList()); 160 161 void setActionId(int actionId); 162 void setActionName(const QString &actionName); 163 int executeArguments(const QStringList &args); 164 int executeArgumentsSimple(const QStringList &args); 165 166 void abortEvaluation(Abort abort = Abort::AllEvaluations); 167 168 public slots: 169 QJSValue version(); 170 QJSValue help(); 171 172 void show(); 173 void showAt(); 174 void hide(); 175 QJSValue toggle(); 176 QJSValue menu(); 177 void exit(); 178 void disable(); 179 void enable(); 180 QJSValue monitoring(); 181 QJSValue visible(); 182 QJSValue focused(); 183 184 QJSValue focusPrevious(); 185 186 QJSValue preview(); 187 188 QJSValue filter(); 189 190 void ignore(); 191 192 QJSValue clipboard(); 193 QJSValue selection(); 194 QJSValue hasClipboardFormat(); 195 QJSValue hasSelectionFormat(); 196 QJSValue isClipboard(); 197 QJSValue copy(); 198 QJSValue copySelection(); 199 QJSValue paste(); 200 201 QJSValue tab(); 202 QJSValue removeTab(); removetab()203 QJSValue removetab() { return removeTab(); } 204 QJSValue renameTab(); renametab()205 QJSValue renametab() { return renameTab(); } 206 QJSValue tabIcon(); tabicon()207 QJSValue tabicon() { return tabIcon(); } 208 QJSValue unload(); 209 void forceUnload(); 210 211 QJSValue length(); size()212 QJSValue size() { return length(); } count()213 QJSValue count() { return length(); } 214 215 QJSValue select(); 216 void next(); 217 void previous(); 218 void add(); 219 void insert(); 220 QJSValue remove(); 221 void edit(); 222 QJSValue move(); 223 224 QJSValue read(); 225 QJSValue write(); 226 QJSValue change(); 227 void separator(); 228 229 void action(); 230 void popup(); 231 QJSValue notification(); 232 233 QJSValue exportTab(); exporttab()234 void exporttab() { exportTab(); } 235 QJSValue importTab(); importtab()236 void importtab() { importTab(); } 237 238 QJSValue importData(); 239 QJSValue exportData(); 240 241 QJSValue config(); 242 QJSValue toggleConfig(); 243 244 QJSValue info(); 245 246 QJSValue eval(); 247 248 QJSValue source(); 249 250 QJSValue currentPath(); currentpath()251 QJSValue currentpath() { return currentPath(); } 252 253 QJSValue str(); 254 QJSValue input(); 255 QJSValue toUnicode(); 256 QJSValue fromUnicode(); 257 258 QJSValue dataFormats(); 259 QJSValue data(); 260 QJSValue setData(); 261 QJSValue removeData(); 262 void print(); 263 void abort(); 264 void fail(); 265 266 QJSValue keys(); 267 QJSValue testSelected(); 268 void serverLog(); 269 QJSValue logs(); 270 271 void setCurrentTab(); 272 273 QJSValue selectItems(); selectitems()274 QJSValue selectitems() { return selectItems(); } 275 276 QJSValue selectedTab(); selectedtab()277 QJSValue selectedtab() { return selectedTab(); } 278 QJSValue selectedItems(); selecteditems()279 QJSValue selecteditems() { return selectedItems(); } 280 QJSValue currentItem(); currentitem()281 QJSValue currentitem() { return currentItem(); } index()282 QJSValue index() { return currentItem(); } 283 284 QJSValue selectedItemData(); 285 QJSValue setSelectedItemData(); 286 QJSValue selectedItemsData(); 287 void setSelectedItemsData(); 288 289 QJSValue escapeHtml(); escapeHTML()290 QJSValue escapeHTML() { return escapeHtml(); } 291 292 QJSValue unpack(); 293 QJSValue pack(); 294 295 QJSValue getItem(); getitem()296 QJSValue getitem() { return getItem(); } 297 void setItem(); setitem()298 void setitem() { setItem(); } 299 300 QJSValue toBase64(); tobase64()301 QJSValue tobase64() { return toBase64(); } 302 QJSValue fromBase64(); frombase64()303 QJSValue frombase64() { return fromBase64(); } 304 305 QJSValue md5sum(); 306 QJSValue sha1sum(); 307 QJSValue sha256sum(); 308 QJSValue sha512sum(); 309 310 QJSValue open(); 311 QJSValue execute(); 312 313 QJSValue currentWindowTitle(); 314 315 QJSValue dialog(); 316 317 QJSValue menuItems(); 318 319 QJSValue settings(); 320 321 QJSValue dateString(); 322 323 QJSValue commands(); 324 void setCommands(); 325 void addCommands(); 326 QJSValue importCommands(); 327 QJSValue exportCommands(); 328 329 QJSValue networkGet(); 330 QJSValue networkPost(); 331 QJSValue networkGetAsync(); 332 QJSValue networkPostAsync(); 333 334 QJSValue env(); 335 QJSValue setEnv(); 336 337 QJSValue sleep(); 338 QJSValue afterMilliseconds(); 339 340 // Call scriptable method. 341 QVariant call(const QString &method, const QVariantList &arguments); 342 QVariantList currentArguments(); 343 void throwException(const QString &errorMessage); 344 345 QJSValue screenshot(); 346 QJSValue screenshotSelect(); 347 QJSValue screenNames(); 348 349 QJSValue queryKeyboardModifiers(); 350 QJSValue pointerPosition(); 351 QJSValue setPointerPosition(); 352 353 QJSValue iconColor(); 354 355 QJSValue iconTag(); 356 357 QJSValue iconTagColor(); 358 359 QJSValue loadTheme(); 360 361 void onClipboardChanged(); 362 void onOwnClipboardChanged(); 363 void onHiddenClipboardChanged(); 364 void onClipboardUnchanged(); 365 onStart()366 void onStart() {} onExit()367 void onExit() {} 368 369 void synchronizeToSelection(); 370 void synchronizeFromSelection(); 371 372 void setClipboardData(); 373 void updateTitle(); 374 void setTitle(); 375 void saveData(); 376 QJSValue hasData(); 377 void showDataNotification(); 378 void hideDataNotification(); 379 void updateClipboardData(); 380 void clearClipboardData(); 381 QJSValue runAutomaticCommands(); 382 383 void runDisplayCommands(); 384 385 void runMenuCommandFilters(); 386 387 void monitorClipboard(); 388 void provideClipboard(); 389 void provideSelection(); 390 391 QJSValue clipboardFormatsToSave(); 392 393 QJSValue styles(); 394 395 signals: 396 void finished(); 397 void dataReceived(const QByteArray &data); 398 void receiveData(); 399 400 private: 401 void onExecuteOutput(const QByteArray &output); 402 void onMonitorClipboardChanged(const QVariantMap &data, ClipboardOwnership ownership); 403 void onMonitorClipboardUnchanged(const QVariantMap &data); 404 void onSynchronizeSelection(ClipboardMode sourceMode, const QString &text, uint targetTextHash); 405 406 bool sourceScriptCommands(); 407 void callDisplayFunctions(QJSValueList displayFunctions); 408 void processUncaughtException(const QString &cmd); 409 void showExceptionMessage(const QString &message); 410 QVector<int> getRows() const; 411 412 /** 413 * Parses arguments as one of these or raises an argument error: 414 * - item... 415 * - mimeType, data, [mimeType, data]... 416 * - list of items 417 * - text 418 */ 419 QVector<QVariantMap> getItemArguments(int begin, int end, QString *error); 420 QVector<QVariantMap> getItemList(int begin, int end, const QJSValue &arguments); 421 422 QJSValue copy(ClipboardMode mode); 423 QJSValue changeItem(bool create); 424 void nextToClipboard(int where); 425 QJSValue screenshot(bool select); 426 QByteArray serialize(const QJSValue &value); 427 QJSValue eval(const QString &script); 428 QTextCodec *codecFromNameOrThrow(const QJSValue &codecName); 429 bool runAction(Action *action); 430 bool runCommands(CommandType::CommandType type); 431 bool canExecuteCommand(const Command &command); 432 bool canExecuteCommandFilter(const QString &matchCommand); 433 bool canAccessClipboard() const; 434 bool verifyClipboardAccess(); 435 void provideClipboard(ClipboardMode mode); 436 437 void insert(int argumentsEnd); 438 void insert(int row, int argumentsBegin, int argumentsEnd); 439 440 QStringList arguments(); 441 QVariantList argumentsAsVariants(); 442 443 void print(const QByteArray &message); 444 void printError(const QByteArray &message); 445 446 void getActionData(); 447 void getActionData(int actionId); 448 void setActionData(); 449 450 QByteArray getClipboardData(const QString &mime, ClipboardMode mode = ClipboardMode::Clipboard); 451 bool hasClipboardFormat(const QString &mime, ClipboardMode mode = ClipboardMode::Clipboard); 452 453 void synchronizeSelection(ClipboardMode targetMode); 454 455 void saveData(const QString &tab); 456 457 QJSValue readInput(); 458 459 PlatformClipboard *clipboardInstance(); 460 const QMimeData *mimeData(ClipboardMode mode); 461 462 void interruptibleSleep(int msec); 463 464 NetworkReply *networkGetHelper(); 465 NetworkReply *networkPostHelper(); 466 467 QJSValue initItemSelection(const QJSValue &obj); 468 469 ScriptableProxy *m_proxy; 470 QJSEngine *m_engine; 471 QJSValue m_temporaryFileClass; 472 QString m_inputSeparator; 473 QJSValue m_input; 474 QVariantMap m_data; 475 QVariantMap m_oldData; 476 int m_actionId = -1; 477 QString m_actionName; 478 Abort m_abort = Abort::None; 479 int m_skipArguments = 0; 480 481 // FIXME: Parameters for execute() shouldn't be global. 482 QByteArray m_executeStdoutData; 483 QString m_executeStdoutLastLine; 484 QJSValue m_executeStdoutCallback; 485 486 bool m_displayFunctionsLock = false; 487 488 QJSValue m_plugins; 489 490 Action *m_action = nullptr; 491 bool m_failed = false; 492 493 QString m_tabName; 494 495 PlatformClipboardPtr m_clipboard; 496 497 QJSValue m_uncaughtException; 498 bool m_hasUncaughtException = false; 499 500 QStringList m_stack; 501 QStringList m_uncaughtExceptionStack; 502 503 QJSValue m_safeCall; 504 QJSValue m_safeEval; 505 QJSValue m_createFn; 506 QJSValue m_createFnB; 507 QJSValue m_createProperty; 508 }; 509 510 class NetworkReply final : public QObject { 511 Q_OBJECT 512 Q_PROPERTY(QJSValue data READ data CONSTANT) 513 Q_PROPERTY(QJSValue error READ error CONSTANT) 514 Q_PROPERTY(QJSValue status READ status CONSTANT) 515 Q_PROPERTY(QJSValue redirect READ redirect CONSTANT) 516 Q_PROPERTY(QJSValue headers READ headers CONSTANT) 517 Q_PROPERTY(QJSValue finished READ finished CONSTANT) 518 519 public: 520 static NetworkReply *get(const QString &url, Scriptable *scriptable); 521 static NetworkReply *post(const QString &url, const QByteArray &postData, Scriptable *scriptable); 522 523 ~NetworkReply(); 524 525 QJSValue data(); 526 527 QJSValue error(); 528 529 QJSValue status(); 530 QJSValue redirect(); 531 QJSValue headers(); 532 533 QJSValue finished(); 534 535 QJSValue toScriptValue(); 536 537 private: 538 explicit NetworkReply(const QString &url, const QByteArray &postData, Scriptable *scriptable); 539 540 Scriptable *m_scriptable; 541 QNetworkAccessManager *m_manager; 542 QNetworkReply *m_reply; 543 QJSValue m_data; 544 QJSValue m_self; 545 QByteArray m_rawData; 546 }; 547 548 class ScriptablePlugins final : public QObject { 549 Q_OBJECT 550 551 public: 552 explicit ScriptablePlugins(Scriptable *scriptable); 553 554 public slots: 555 QJSValue load(const QString &name); 556 557 private: 558 ItemFactory *m_factory = nullptr; 559 Scriptable *m_scriptable; 560 QMap<QString, QJSValue> m_plugins; 561 }; 562 563 #endif // SCRIPTABLE_H 564