├── .gitignore ├── .npmignore ├── README.md ├── binding.gyp ├── build ├── Release │ ├── addon.exp │ ├── addon.map │ └── addon.node ├── addon.vcxproj ├── addon.vcxproj.filters ├── binding.sln └── config.gypi ├── docker ├── Dockerfile └── resources │ └── docker-entrypoint.sh ├── index.js ├── index.test.js ├── package.json ├── src ├── DataHelper.cc ├── DataHelper.h ├── DocumentItem.cc ├── DocumentItem.h ├── addon.cc ├── create_database.cc ├── create_database.h ├── delete_database.cc ├── delete_database.h ├── delete_document_async.cc ├── delete_document_async.h ├── document_async.cc ├── document_async.h ├── getresponse_documents.cc ├── getresponse_documents.h ├── makeresponse_document.cc ├── makeresponse_document.h ├── notes_database.cc ├── notes_database.h ├── notes_document.cc ├── notes_document.h ├── nsf_search.cc ├── nsf_search.h ├── replicate_database_async.cc ├── replicate_database_async.h ├── save_document_async.cc ├── save_document_async.h ├── view_async.cc └── view_async.h └── test2.js /.gitignore: -------------------------------------------------------------------------------- 1 | public/ 2 | node_modules/ 3 | 4 | build/Debug/ 5 | build/Release/obj/ 6 | build/ 7 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | public/ 2 | node_modules/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Node.js driver for NSF 2 | 3 | 4 | *Disclaimer: this is not the official npm module for domino.* 5 | 6 | 7 | ## Install 8 | npm install domino-nsf 9 | 10 | ## Requirements 11 | From release 0.3.0 it's a source release only, to be able to install, you'll need to follow the instructions in the development section. 12 | 13 | Older packages is currently windows only. The binaries has been build for Win32 and tested with Node 8.9.4, 32bit. 14 | 15 | **The Notes program folder needs to be added to the system PATH.** 16 | 17 | ## Linux 18 | 19 | If you want to run on Linux, you'll need to build it from source. Check out development section for more.. 20 | 21 | 22 | 23 | 24 | 25 | 26 | ## Usage 27 | 28 | ### Async API 29 | 30 | ```js 31 | const domino = require('domino-nsf')(); 32 | 33 | let doc = { 34 | "FullName":"John Smith", 35 | "tags":["test","test2"], 36 | "age":33, 37 | "Form":"Person" 38 | }; 39 | 40 | const db = domino.use('database.nsf'); 41 | 42 | db.get("documentUNID",function(error,document) { 43 | console.log("document",document); 44 | }); 45 | 46 | db.insert(doc,function(error,document) { 47 | // returns the saved document 48 | console.log("document",document); 49 | }); 50 | 51 | db.makeResponse(doc,parentDoc,function(err,res) { 52 | 53 | }); 54 | 55 | db.view({view:"People",category:""},function(err,view) { 56 | console.log("view result",view); 57 | }); 58 | 59 | db.search("SELECT *", functoin(err,results) { 60 | //returns the search results 61 | }); 62 | 63 | db.del("documentUNID",function(error,result) { 64 | console.log("result",result); 65 | }); 66 | 67 | 68 | // to end session call 69 | domino.termSession(); 70 | ``` 71 | ### View parameters 72 | ```js 73 | { 74 | view: "the view name", 75 | max: "number, max entries to get" 76 | category: "the category to get" 77 | findByKey: "the key to search by" 78 | exact: true/false, exact or partial match when using findByKey 79 | } 80 | ``` 81 | 82 | ### Synchronous API 83 | ```js 84 | const domino = require('domino-nsf')(); 85 | 86 | // you must run sinitThread before calling any notes api. 87 | domino.sinitThread(); 88 | let db = domino.openDatabase('test.nsf'); 89 | let note = db.openNotesNote(); 90 | note.setItemText('Form','Test'); 91 | note.setItemText('Subject','Hello World!'); 92 | 93 | // save the note 94 | note.updateNote(); 95 | 96 | // close the note and db 97 | note.close(); 98 | db.close(); 99 | 100 | 101 | // terminate thread before exiting 102 | domino.stermThread(); 103 | 104 | ``` 105 | 106 | ### Avaliable methods 107 | #### Domino object 108 | 109 | sinitThread() 110 | init the notes session/thread 111 | 112 | stermThread() 113 | terminate the notes thread 114 | 115 | createDatabase('server!!path/databasename.nsf') 116 | create a new **database**, on given serve and path. If path is omitted, localhost is used. 117 | Returns a **database** object. 118 | 119 | openDatabase('server!!path/databasename.nsf') 120 | Opens a database. 121 | Returns a **database** object. 122 | 123 | deleteDatabase('server!!path/databasename.nsf'); 124 | 125 | #### Database object 126 | openNotesNote('unid') 127 | Opens a Notes note by *UNID*. 128 | Returns a **note** object. 129 | 130 | createNotesNote() 131 | Creates a new note in the database. 132 | Returns a Notes object. 133 | 134 | getDatabaseName() 135 | Return the database name / title. 136 | 137 | close() 138 | Closes the database handle. 139 | 140 | #### Notes object 141 | getItemText('itemName') 142 | returns the items value as a string, returns empty string if item does not exists. 143 | 144 | getItemNumber('itemName') 145 | returns the items value as a number 146 | 147 | getItemDate('itemName') 148 | 149 | return item date value as js date. 150 | 151 | getItemValue('itemName') 152 | returns the item value as a text,number,text array or date depending on type. 153 | 154 | getItemMime('itemName') 155 | returns the mime item. 156 | 157 | hasItem('itemName') 158 | returns true/false if note has item. 159 | 160 | getUNID() 161 | returns the note UNID 162 | 163 | updateNote() 164 | saves the note to database. 165 | 166 | setItemText('itemName','string') 167 | set a string value to an item. If the item exists, it will replace the item value. 168 | 169 | setItemDate('itemName', date) 170 | set a Date object value to an item 171 | 172 | setItemNumber('itemName,number) 173 | set a number value to an item. If the item exists, it will replace the item value. 174 | 175 | setItemValue('itemName', value); 176 | set an value to an item, value can be text,number,text array or js Date object 177 | 178 | setItemMime('itemName','header',value); 179 | set an mime item. 180 | 181 | appendItemValue('itemName','string') 182 | append a string value to an existing text array. 183 | 184 | deleteItem('itemName') 185 | delete an item from a note. 186 | Returns true if item was deleted. 187 | 188 | close() 189 | Close the note handle. After calling close, you cannot call any methods on the current **Note** object. 190 | 191 | ## Development and Contribution 192 | 193 | ### Local Development Windows 194 | To build the addon, you need the 195 | * Domino C API 196 | * Nan for Node.js. 197 | * Microsoft VisualStudio 2015/2017 or by using using Microsoft's windows-build-tools 198 | * [node-gyp](https://github.com/nodejs/node-gyp) 199 | 200 | 201 | #### Configuring enviroment for node-gyp build 202 | You must set these environment variables before you build the addon 203 | 204 | NOTES_INCLUDE must contain: 205 | * the C API header files 206 | 207 | NOTES_LIB must contain: 208 | * the path to the Notes C library folder 209 | 210 | ### Linux/Docker 211 | To set up a development enviroment using Docker, you can use this [Dockerfile](https://github.com/nthjelme/nodejs-domino/blob/master/docker/Dockerfile) 212 | 213 | 214 | #### Configuring and building 215 | node-gyp configure 216 | ..and build.. 217 | 218 | node-gyp build 219 | 220 | 221 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ 6 | "src/addon.cc", 7 | "src/document_async.cc", 8 | "src/save_document_async.cc", 9 | "src/makeresponse_document.cc", 10 | "src/delete_document_async.cc", 11 | "src/view_async.cc", 12 | "src/DocumentItem.cc", 13 | "src/DataHelper.cc", 14 | "src/create_database.cc", 15 | "src/delete_database.cc", 16 | "src/nsf_search.cc", 17 | "src/notes_document.cc", 18 | "src/notes_database.cc", 19 | ], 20 | "conditions": [ 21 | ["OS==\"linux\"",{ 22 | "include_dirs": [" 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {53EFA712-345C-0CF5-4A70-18A62C9221EE} 15 | Win32Proj 16 | addon 17 | true 18 | x64 19 | 20 | 21 | 22 | DynamicLibrary 23 | 24 | 25 | v140 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | $(ExecutablePath);$(MSBuildProjectDirectory)\..\bin\;$(MSBuildProjectDirectory)\..\bin\ 36 | true 37 | $(Configuration)\obj\$(ProjectName)\ 38 | false 39 | true 40 | $(SolutionDir)$(Configuration)\ 41 | .node 42 | .node 43 | .node 44 | .node 45 | $(ProjectName) 46 | $(OutDir)\$(ProjectName).node 47 | 48 | 49 | 50 | C:\Users\NilsTarjei\.node-gyp\6.9.1\include\node;C:\Users\NilsTarjei\.node-gyp\6.9.1\src;C:\Users\NilsTarjei\.node-gyp\6.9.1\deps\uv\include;C:\Users\NilsTarjei\.node-gyp\6.9.1\deps\v8\include;..\..\node_modules\nan;C:\notesapi\notesapi901\include;%(AdditionalIncludeDirectories) 51 | EnableFastChecks 52 | true 53 | false 54 | ProgramDatabase 55 | 4351;4355;4800;4251;%(DisableSpecificWarnings) 56 | false 57 | false 58 | false 59 | Disabled 60 | NotUsing 61 | NODE_GYP_MODULE_NAME=addon;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;W32;BUILDING_NODE_EXTENSION;DEBUG;_DEBUG;%(PreprocessorDefinitions) 62 | MultiThreadedDebug 63 | true 64 | true 65 | false 66 | Level3 67 | 68 | 69 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;DelayImp.lib;"C:\Users\NilsTarjei\.node-gyp\6.9.1\$(Configuration)\node.lib";C:\notesapi\notesapi901\lib\\mswin32\notes.lib;C:\notesapi\notesapi901\lib\\mswin32\notescpp.lib 70 | /ignore:4199 %(AdditionalOptions) 71 | true 72 | true 73 | iojs.exe;node.exe;%(DelayLoadDLLs) 74 | true 75 | true 76 | true 77 | $(OutDir)$(ProjectName).node 78 | true 79 | true 80 | .node 81 | MachineX86 82 | 83 | 84 | C:\Users\NilsTarjei\.node-gyp\6.9.1\include\node;C:\Users\NilsTarjei\.node-gyp\6.9.1\src;C:\Users\NilsTarjei\.node-gyp\6.9.1\deps\uv\include;C:\Users\NilsTarjei\.node-gyp\6.9.1\deps\v8\include;..\..\node_modules\nan;C:\notesapi\notesapi901\include;%(AdditionalIncludeDirectories) 85 | NODE_GYP_MODULE_NAME=addon;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;W32;BUILDING_NODE_EXTENSION;DEBUG;_DEBUG;%(PreprocessorDefinitions);%(PreprocessorDefinitions) 86 | 87 | 88 | 89 | 90 | C:\Users\NilsTarjei\.node-gyp\6.9.1\include\node;C:\Users\NilsTarjei\.node-gyp\6.9.1\src;C:\Users\NilsTarjei\.node-gyp\6.9.1\deps\uv\include;C:\Users\NilsTarjei\.node-gyp\6.9.1\deps\v8\include;..\..\node_modules\nan;C:\notesapi\notesapi901\include;%(AdditionalIncludeDirectories) 91 | /MP %(AdditionalOptions) 92 | true 93 | false 94 | ProgramDatabase 95 | 4351;4355;4800;4251;%(DisableSpecificWarnings) 96 | false 97 | Speed 98 | true 99 | AnySuitable 100 | true 101 | true 102 | Full 103 | NotUsing 104 | NODE_GYP_MODULE_NAME=addon;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;W32;BUILDING_NODE_EXTENSION;%(PreprocessorDefinitions) 105 | MultiThreaded 106 | false 107 | true 108 | true 109 | false 110 | Level3 111 | true 112 | 113 | 114 | /LTCG %(AdditionalOptions) 115 | 116 | 117 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;DelayImp.lib;"C:\Users\NilsTarjei\.node-gyp\6.9.1\$(Configuration)\node.lib";C:\notesapi\notesapi901\lib\\mswin32\notes.lib;C:\notesapi\notesapi901\lib\\mswin32\notescpp.lib 118 | /ignore:4199 %(AdditionalOptions) 119 | true 120 | true 121 | iojs.exe;node.exe;%(DelayLoadDLLs) 122 | true 123 | true 124 | true 125 | UseLinkTimeCodeGeneration 126 | true 127 | true 128 | $(OutDir)$(ProjectName).node 129 | true 130 | true 131 | .node 132 | MachineX86 133 | 134 | 135 | C:\Users\NilsTarjei\.node-gyp\6.9.1\include\node;C:\Users\NilsTarjei\.node-gyp\6.9.1\src;C:\Users\NilsTarjei\.node-gyp\6.9.1\deps\uv\include;C:\Users\NilsTarjei\.node-gyp\6.9.1\deps\v8\include;..\..\node_modules\nan;C:\notesapi\notesapi901\include;%(AdditionalIncludeDirectories) 136 | NODE_GYP_MODULE_NAME=addon;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;W32;BUILDING_NODE_EXTENSION;%(PreprocessorDefinitions);%(PreprocessorDefinitions) 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /build/addon.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {739DB09A-CC57-A953-A6CF-F64FA08E4FA7} 6 | 7 | 8 | {8CDEE807-BC53-E450-C8B8-4DEBB66742D4} 9 | 10 | 11 | {739DB09A-CC57-A953-A6CF-F64FA08E4FA7} 12 | 13 | 14 | {8CDEE807-BC53-E450-C8B8-4DEBB66742D4} 15 | 16 | 17 | {739DB09A-CC57-A953-A6CF-F64FA08E4FA7} 18 | 19 | 20 | {8CDEE807-BC53-E450-C8B8-4DEBB66742D4} 21 | 22 | 23 | {739DB09A-CC57-A953-A6CF-F64FA08E4FA7} 24 | 25 | 26 | {8CDEE807-BC53-E450-C8B8-4DEBB66742D4} 27 | 28 | 29 | {739DB09A-CC57-A953-A6CF-F64FA08E4FA7} 30 | 31 | 32 | {8CDEE807-BC53-E450-C8B8-4DEBB66742D4} 33 | 34 | 35 | {739DB09A-CC57-A953-A6CF-F64FA08E4FA7} 36 | 37 | 38 | {8CDEE807-BC53-E450-C8B8-4DEBB66742D4} 39 | 40 | 41 | {739DB09A-CC57-A953-A6CF-F64FA08E4FA7} 42 | 43 | 44 | {8CDEE807-BC53-E450-C8B8-4DEBB66742D4} 45 | 46 | 47 | {739DB09A-CC57-A953-A6CF-F64FA08E4FA7} 48 | 49 | 50 | {8CDEE807-BC53-E450-C8B8-4DEBB66742D4} 51 | 52 | 53 | {739DB09A-CC57-A953-A6CF-F64FA08E4FA7} 54 | 55 | 56 | {8CDEE807-BC53-E450-C8B8-4DEBB66742D4} 57 | 58 | 59 | {739DB09A-CC57-A953-A6CF-F64FA08E4FA7} 60 | 61 | 62 | {8CDEE807-BC53-E450-C8B8-4DEBB66742D4} 63 | 64 | 65 | {7B735499-E5DD-1C2B-6C26-70023832A1CF} 66 | 67 | 68 | {E9F714C1-DA89-54E2-60CF-39FEB20BF756} 69 | 70 | 71 | {92BC873D-B0F7-121B-EC88-F0153AE4D43D} 72 | 73 | 74 | {F852EB63-437C-846A-220F-8D9ED6DAEC1D} 75 | 76 | 77 | {D51E5808-912B-5C70-4BB7-475D1DBFA067} 78 | 79 | 80 | {741E0E76-39B2-B1AB-9FA1-F1A20B16F295} 81 | 82 | 83 | {56DF7A98-063D-FB9D-485C-089023B4C16A} 84 | 85 | 86 | {77348C0E-2034-7791-74D5-63C077DF5A3B} 87 | 88 | 89 | {8CDEE807-BC53-E450-C8B8-4DEBB66742D4} 90 | 91 | 92 | {739DB09A-CC57-A953-A6CF-F64FA08E4FA7} 93 | 94 | 95 | 96 | 97 | ..\src 98 | 99 | 100 | ..\src 101 | 102 | 103 | ..\src 104 | 105 | 106 | ..\src 107 | 108 | 109 | ..\src 110 | 111 | 112 | ..\src 113 | 114 | 115 | ..\src 116 | 117 | 118 | ..\src 119 | 120 | 121 | ..\src 122 | 123 | 124 | ..\src 125 | 126 | 127 | C:\Users\NilsTarjei\AppData\Roaming\npm\node_modules\node-gyp\src 128 | 129 | 130 | .. 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /build/binding.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 2015 3 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "addon", "addon.vcxproj", "{53EFA712-345C-0CF5-4A70-18A62C9221EE}" 4 | EndProject 5 | Global 6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 7 | Debug|Win32 = Debug|Win32 8 | Release|Win32 = Release|Win32 9 | EndGlobalSection 10 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 11 | {53EFA712-345C-0CF5-4A70-18A62C9221EE}.Debug|Win32.ActiveCfg = Debug|Win32 12 | {53EFA712-345C-0CF5-4A70-18A62C9221EE}.Debug|Win32.Build.0 = Debug|Win32 13 | {53EFA712-345C-0CF5-4A70-18A62C9221EE}.Release|Win32.ActiveCfg = Release|Win32 14 | {53EFA712-345C-0CF5-4A70-18A62C9221EE}.Release|Win32.Build.0 = Release|Win32 15 | EndGlobalSection 16 | GlobalSection(SolutionProperties) = preSolution 17 | HideSolutionNode = FALSE 18 | EndGlobalSection 19 | EndGlobal 20 | -------------------------------------------------------------------------------- /build/config.gypi: -------------------------------------------------------------------------------- 1 | # Do not edit. File was generated by node-gyp's "configure" step 2 | { 3 | "target_defaults": { 4 | "cflags": [], 5 | "default_configuration": "Release", 6 | "defines": [], 7 | "include_dirs": [], 8 | "libraries": [] 9 | }, 10 | "variables": { 11 | "asan": 0, 12 | "debug_devtools": "node", 13 | "force_dynamic_crt": 0, 14 | "host_arch": "x64", 15 | "icu_data_file": "icudt57l.dat", 16 | "icu_data_in": "..\\..\\deps/icu-small\\source/data/in\\icudt57l.dat", 17 | "icu_endianness": "l", 18 | "icu_gyp_path": "tools/icu/icu-generic.gyp", 19 | "icu_locales": "en,root", 20 | "icu_path": "deps/icu-small", 21 | "icu_small": "true", 22 | "icu_ver_major": "57", 23 | "node_byteorder": "little", 24 | "node_enable_d8": "false", 25 | "node_enable_v8_vtunejit": "false", 26 | "node_install_npm": "true", 27 | "node_module_version": 48, 28 | "node_no_browser_globals": "false", 29 | "node_prefix": "/usr/local", 30 | "node_release_urlbase": "https://nodejs.org/download/release/", 31 | "node_shared": "false", 32 | "node_shared_cares": "false", 33 | "node_shared_http_parser": "false", 34 | "node_shared_libuv": "false", 35 | "node_shared_openssl": "false", 36 | "node_shared_zlib": "false", 37 | "node_tag": "", 38 | "node_use_bundled_v8": "true", 39 | "node_use_dtrace": "false", 40 | "node_use_etw": "true", 41 | "node_use_lttng": "false", 42 | "node_use_openssl": "true", 43 | "node_use_perfctr": "true", 44 | "node_use_v8_platform": "true", 45 | "openssl_fips": "", 46 | "openssl_no_asm": 0, 47 | "shlib_suffix": "so.48", 48 | "target_arch": "ia32", 49 | "v8_enable_gdbjit": 0, 50 | "v8_enable_i18n_support": 1, 51 | "v8_inspector": "true", 52 | "v8_no_strict_aliasing": 1, 53 | "v8_optimized_debug": 0, 54 | "v8_random_seed": 0, 55 | "v8_use_snapshot": "true", 56 | "want_separate_host_toolset": 1, 57 | "nodedir": "C:\\Users\\NilsTarjei\\.node-gyp\\6.9.1", 58 | "copy_dev_lib": "true", 59 | "standalone_static_library": 1 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nils/domino:9.0.1-fp8 2 | 3 | EXPOSE 25 80 443 1352 4 | 5 | COPY resources/docker-entrypoint.sh / 6 | RUN chmod 775 /docker-entrypoint.sh 7 | RUN apt-get update && \ 8 | apt-get -y install nodejs npm python build-essential && \ 9 | rm -rf /var/lib/apt/lists/* && \ 10 | wget -q http://172.17.0.1:7777/notesapi.tar.gz && \ 11 | tar -xf notesapi.tar.gz -C /opt/ibm/ && \ 12 | mkdir /home/notes/samples && \ 13 | cp -a /opt/ibm/notesapi/samples/. /home/notes/samples && \ 14 | ln -s /opt/ibm/domino/notes/latest/linux/libnotes.so /usr/lib/libnotes.so && \ 15 | ln -s /opt/ibm/domino/notes/latest/linux/libndgts.so /usr/lib/libndgts.so && \ 16 | ln -s /opt/ibm/domino/notes/latest/linux/libxmlproc.so /usr/lib/libxmlproc.so && \ 17 | ln -s /opt/ibm/domino/notes/latest/linux/libgsk8iccs_64.so /usr/lib/libgsk8iccs_64.so && \ 18 | npm install -g n && \ 19 | n stable && \ 20 | npm install -g node-gyp nan 21 | 22 | 23 | USER notes 24 | WORKDIR /local/notesdata 25 | ENV LOGNAME=notes 26 | ENV LOTUS=/opt/ibm 27 | ENV Notes_ExecDirectory=/opt/ibm/domino/notes/latest/linux 28 | ENV NOTES_DATA_DIR=/local/notesdata 29 | ENV DOMINO_RES_DIR=/opt/ibm/domino/notes/latest/res/C 30 | 31 | ENV PATH=$PATH:/opt/ibm/domino/:$Notes_ExecDirectory:$NOTES_DATA_DIR:$DOMINO_RES_DIR 32 | 33 | ENTRYPOINT ["/docker-entrypoint.sh"] 34 | -------------------------------------------------------------------------------- /docker/resources/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | serverID=/local/notesdata/server.id 4 | 5 | if [ ! -f "$serverID" ]; then 6 | /opt/ibm/domino/bin/server -listen 1352 7 | else 8 | /opt/ibm/domino/rc_domino_script start 9 | /bin/bash 10 | fi 11 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = Domino; 2 | var dominoDriver = require('./build/Release/addon'); 3 | 4 | function Domino() { 5 | dominoDriver.initSession(); 6 | var dbObj = {}; 7 | var termSession = function() { 8 | dominoDriver.termSession(); 9 | }; 10 | 11 | var createDatabase = function(db,callback) { 12 | dominoDriver.createDatabase(db,function(error,response) { 13 | callback(error,response); 14 | }); 15 | }; 16 | 17 | var deleteDatabase = function(db,callback) { 18 | dominoDriver.deleteDatabase(db,function(error,status) { 19 | callback(error,status); 20 | }); 21 | }; 22 | 23 | var sinitThread = function() { 24 | dominoDriver.sinitThread(); 25 | } 26 | 27 | var stermThread = function() { 28 | dominoDriver.stermThread(); 29 | } 30 | 31 | var openDatabase = function(databaseName) { 32 | 33 | var db = {handle:0}; 34 | db.handle = dominoDriver.openDatabase(databaseName); 35 | if (db.handle==0) { 36 | throw Error("Error opening database"); 37 | } else { 38 | db.getDatabaseName = function() { 39 | return dominoDriver.getDatabaseName(db.handle); 40 | } 41 | 42 | db.close = function() { 43 | dominoDriver.closeDatabase(db.handle); 44 | db.handle=0; 45 | } 46 | 47 | var baseNote = {}; 48 | baseNote.getItemText = function(itemName) { 49 | return dominoDriver.getItemText(this.handle,itemName); 50 | } 51 | baseNote.setItemText = function(itemName,value) { 52 | dominoDriver.setItemText(this.handle, itemName, value); 53 | } 54 | baseNote.getItemNumber = function(itemName) { 55 | return dominoDriver.getItemNumber(this.handle,itemName); 56 | } 57 | baseNote.setItemNumber = function(itemName,value) { 58 | return dominoDriver.setItemNumber(this.handle,itemName,value); 59 | } 60 | baseNote.getItemDate = function(itemName) { 61 | return dominoDriver.getItemDate(this.handle,itemName); 62 | } 63 | baseNote.setItemDate = function(itemName, date) { 64 | return dominoDriver.setItemDate(this.handle,itemName,date); 65 | } 66 | 67 | baseNote.getItemValue = function(itemName) { 68 | return dominoDriver.getItemValue(this.handle,itemName); 69 | } 70 | baseNote.hasItem = function(itemName) { 71 | return dominoDriver.hasItem(this.handle,itemName); 72 | } 73 | baseNote.deleteItem = function(itemName) { 74 | return dominoDriver.deleteItem(this.handle,itemName); 75 | } 76 | baseNote.setAuthor = function(itemName,value) { 77 | return dominoDriver.setAuthor(this.handle,itemName,value); 78 | } 79 | baseNote.setItemValue = function(itemName,value) { 80 | return dominoDriver.setItemValue(this.handle,itemName,value); 81 | } 82 | 83 | 84 | baseNote.setItemMime = function(itemName, header,body) { 85 | if (!header) { 86 | header = 'Content-Type: application/json'; 87 | } 88 | return dominoDriver.setMimeItem(this.handle,itemName,body,header); 89 | } 90 | 91 | baseNote.getItemMime = function(itemName) { 92 | let mimeItem = { 93 | value: dominoDriver.getMimeItem(this.handle,itemName) 94 | } 95 | return mimeItem; 96 | } 97 | 98 | baseNote.appendItemValue = function(itemName, itemToAppend) { 99 | return dominoDriver.appendItemTextList(this.handle,itemName,itemToAppend); 100 | } 101 | 102 | baseNote.updateNote = function() { 103 | dominoDriver.updateNote(this.handle); 104 | } 105 | baseNote.close = function() { 106 | dominoDriver.closeNote(this.handle); 107 | } 108 | baseNote.getUNID = function() { 109 | return dominoDriver.getNoteUNID(this.handle); 110 | } 111 | 112 | db.createNotesNote = function() { 113 | var note = Object.create(baseNote); 114 | note.handle = dominoDriver.createNotesNote(db.handle); 115 | return note; 116 | } 117 | 118 | db.openNotesNote = function(unid) { 119 | var note = Object.create(baseNote); 120 | note.handle = dominoDriver.getNotesNote(db.handle,unid); 121 | 122 | return note; 123 | } 124 | } 125 | return db; 126 | } 127 | 128 | var use = function(db) { 129 | var localDb = {database: db}; 130 | 131 | var replicate = function(callback) { 132 | callback({error:"Not implemented"},undefined); 133 | /*dominoDriver.replicateAsync(db,function(error,result) { 134 | callback(error,result); 135 | });*/ 136 | } 137 | 138 | var get = function(unid,param1,param2) { 139 | if (typeof (param1) == 'function') { 140 | dominoDriver.getDocumentAsync(localDb,unid,function(error,document) { 141 | if (document) { 142 | document.getResponses = function(responseCallback) { 143 | dominoDriver.getResponseDocumentsAsync(localDb,this["@unid"], function(err,res) { 144 | responseCallback(err,res); 145 | }); 146 | }; 147 | document.makeResponse = function(parent,responseCallback) { 148 | dominoDriver.makeResponseDocumentAsync(localDb,this["@unid"], parent["@unid"], function(error,result) { 149 | responseCallback(error,result); 150 | }); 151 | } 152 | document.save = function(documentCallback) { 153 | dominoDriver.saveDocumentAsync(localDb,this,function(error,document) { 154 | documentCallback(error,document); 155 | }); 156 | 157 | } 158 | } 159 | param1(error,document); 160 | }); 161 | } else if (typeof (param2 == 'function')) { 162 | dominoDriver.getDocumentAsync(localDb,unid,param1,function(error,document) { 163 | if (document) { 164 | document.getResponses = function(responseCallback) { 165 | dominoDriver.getResponseDocumentsAsync(localDb,this["@unid"], function(err,res) { 166 | responseCallback(err,res); 167 | }); 168 | }; 169 | document.makeResponse = function(parent,responseCallback) { 170 | dominoDriver.makeResponseDocumentAsync(localDb,this["@unid"], parent["@unid"], function(error,result) { 171 | responseCallback(error,result); 172 | }); 173 | } 174 | document.save = function(documentCallback) { 175 | dominoDriver.saveDocumentAsync(localDb,this,function(error,document) { 176 | documentCallback(error,document); 177 | }); 178 | 179 | } 180 | } 181 | param2(error,document); 182 | }); 183 | } 184 | 185 | } 186 | 187 | 188 | var insert = function(document,callback) { 189 | dominoDriver.saveDocumentAsync(localDb,document,function(error,document) { 190 | callback(error,document); 191 | }); 192 | }; 193 | 194 | var deleteFn = function(unid,callback) { 195 | dominoDriver.deleteDocumentAsync(localDb,unid,function(error,result) { 196 | callback(error,result); 197 | }); 198 | }; 199 | 200 | var makeResponse = function(doc,parent,callback) { 201 | dominoDriver.makeResponseDocumentAsync(localDb,doc["@unid"], parent["@unid"], function(error,result) { 202 | callback(error,result); 203 | }); 204 | }; 205 | 206 | var getResponses = function(doc,callback) { 207 | callback({error: "Not implemented"},undefined) 208 | /* 209 | dominoDriver.getResponseDocumentsAsync(localDb,doc["@unid"], function(error,result) { 210 | callback(error,result); 211 | });*/ 212 | }; 213 | 214 | var view = function(view,callback) { 215 | dominoDriver.getViewAsync(localDb,view,function(err,result) { 216 | callback(err,result); 217 | }); 218 | }; 219 | 220 | var search = function(searchFormula,callback) { 221 | dominoDriver.searchNsfAsync(localDb,searchFormula,function(err,result) { 222 | callback(err,result); 223 | }); 224 | } 225 | 226 | localDb.get = get; 227 | localDb.insert = insert; 228 | localDb.del = deleteFn; 229 | localDb.view = view; 230 | localDb.replicate = replicate; 231 | localDb.makeResponse = makeResponse; 232 | localDb.search = search; 233 | 234 | return localDb; 235 | 236 | }; 237 | process.on('SIGINT', function() { 238 | dominoDriver.termSession(); 239 | process.exit(); 240 | }); 241 | 242 | dbObj.use = use; 243 | dbObj.termSession = termSession; 244 | dbObj.createDatabase = createDatabase; 245 | dbObj.deleteDatabase = deleteDatabase; 246 | dbObj.openDatabase = openDatabase; 247 | dbObj.sinitThread = sinitThread; 248 | dbObj.stermThread = stermThread; 249 | 250 | return dbObj; 251 | }; 252 | -------------------------------------------------------------------------------- /index.test.js: -------------------------------------------------------------------------------- 1 | var expect = require('chai').expect; 2 | var dominoNsf = require('./index'); 3 | var domino = dominoNsf(); 4 | 5 | var db; 6 | var savedDocumentUnid = ""; 7 | var doc = { 8 | "Form":"Test", 9 | "Name": "Test", 10 | "date": new Date(0), 11 | "number": 10, 12 | "array": ["a","b","c"] 13 | }; 14 | var test_db = { 15 | "database":"nodejs_domino9.nsf", 16 | "title":"Test database" 17 | } 18 | 19 | 20 | describe('domino-nsf',function() { 21 | 22 | before(function() { 23 | domino.createDatabase(test_db,function(error, database) { 24 | if (error) { 25 | console.error(error); 26 | } 27 | db = domino.use(database.database); 28 | }); 29 | 30 | }); 31 | 32 | after(function() { 33 | domino.deleteDatabase(test_db,function(error,status) { 34 | if (error) { 35 | console.log("error deleting database,",error); 36 | } 37 | }); 38 | domino.termSession(); 39 | }); 40 | 41 | describe('save document',function() { 42 | var savedDocument = {}; 43 | before(function(done) { 44 | db.insert(doc,function(err,result) { 45 | if(err) { 46 | done(err); 47 | } else { 48 | savedDocument = result; 49 | savedDocumentUnid = result["@unid"]; 50 | done(); 51 | } 52 | }); 53 | }); 54 | it ('should create a document with unid with length of 32', function() { 55 | expect(savedDocument).to.have.property('@unid').with.length(32); 56 | }); 57 | it ('should have a number property that equals 10', function() { 58 | expect(savedDocument).to.have.property('number').to.equal(10); 59 | }); 60 | it('should have a date property that equals ', function() { 61 | expect(savedDocument).to.have.property('date').to.eql(new Date(0)); 62 | }); 63 | it('shoud have a Name property that equals "Test"',function() { 64 | expect(savedDocument).to.have.property('Name').to.eql("Test"); 65 | }); 66 | it('shoud have a array property that equals ["a","b","c"]',function() { 67 | expect(savedDocument).to.have.property('array').to.eql(["a","b","c"]); 68 | }); 69 | }); 70 | describe('get document fields', function() { 71 | var document = {}; 72 | before(function(done) { 73 | db.get(savedDocumentUnid,{fields: ['Name','Number']},function(err,result) { 74 | if (err) { 75 | done(err); 76 | } else { 77 | document = result; 78 | done(); 79 | } 80 | }); 81 | }); 82 | it('shoud have a Name property that equals "Test"',function() { 83 | expect(document).to.have.property('Name').to.eql("Test"); 84 | }); 85 | it('shoud have not have a date property ',function() { 86 | expect(document).to.not.have.property('date'); 87 | }); 88 | }); 89 | describe('get all document items', function() { 90 | var document = {}; 91 | 92 | before(function(done) { 93 | db.get(savedDocumentUnid,function(err,result) { 94 | if (err) { 95 | done(err); 96 | } else { 97 | document = result; 98 | done(); 99 | } 100 | }); 101 | }); 102 | 103 | it ('should create a document with unid with length of 32', function() { 104 | expect(document).to.have.property('@unid').with.length(32); 105 | }); 106 | it ('should have a number property that equals 10', function() { 107 | expect(document).to.have.property('number').to.equal(10); 108 | }); 109 | it('should have a date property that equals ', function() { 110 | expect(document).to.have.property('date').to.eql(new Date(0)); 111 | }); 112 | it('shoud have a Name property that equals "Test"',function() { 113 | expect(document).to.have.property('Name').to.eql("Test"); 114 | }); 115 | it('shoud have a array property that equals ["a","b","c"]',function() { 116 | expect(document).to.have.property('array').to.eql(["a","b","c"]); 117 | }); 118 | 119 | }); 120 | 121 | describe('search database', function() { 122 | var searchResults = []; 123 | before(function(done) { 124 | db.search("SELECT *",function(err,result) { 125 | if (err) { 126 | done(err); 127 | } else { 128 | searchResults = result; 129 | done(); 130 | } 131 | }); 132 | }); 133 | 134 | it('expect a list of documents with length of 1',function() { 135 | expect(searchResults).to.have.lengthOf(1); 136 | }); 137 | 138 | }); 139 | 140 | describe('open database and get name', function() { 141 | let db = {}; 142 | let note = {}; 143 | let newNote = {}; 144 | const body = "This is a body"; 145 | before(function(done) { 146 | domino.sinitThread(); 147 | db = domino.openDatabase(test_db.database); 148 | note = db.openNotesNote(savedDocumentUnid); 149 | const header = "Content-Type: application/text"; 150 | note.setItemMime("Body",header,body); 151 | note.updateNote(); 152 | done(); 153 | }); 154 | 155 | it('should have a mime item body', function() { 156 | expect(note.getItemMime("Body").value).to.be.equal(body); 157 | }); 158 | 159 | it('should have a name equals ' + test_db.title, function() { 160 | expect(db.getDatabaseName()).to.be.equal(test_db.title); 161 | }); 162 | 163 | it('should have a note.Name equals to ' + doc.Name, function() { 164 | expect(note.getItemText("Name")).to.be.equal(doc.Name); 165 | }); 166 | 167 | it('should have a note.Number equals to ' + doc.number, function() { 168 | expect(note.getItemNumber("number")).to.be.equal(doc.number); 169 | }); 170 | 171 | it ('should return a number value', function() { 172 | expect(note.getItemValue("number")).to.be.equal(doc.number); 173 | }); 174 | 175 | it ('should return a text value', function() { 176 | expect(note.getItemValue("Name")).to.be.equal(doc.Name); 177 | }) 178 | 179 | it('should have a note.Date equals to ' + doc.date, function() { 180 | expect(new Date(note.getItemDate("date")).getTime()).to.be.equal(doc.date.getTime()); 181 | }); 182 | 183 | it('should return a date equals to ' + doc.date, function() { 184 | expect(note.getItemValue("date").toString()).to.be.equal(doc.date.toString()); 185 | }) 186 | 187 | it('should create a new note and get a handle', function() { 188 | newNote = db.createNotesNote(); 189 | expect(newNote.handle).to.not.equal(0); 190 | }); 191 | 192 | it('should create a item on newly created note', function() { 193 | newNote.setItemText("test", "test value"); 194 | expect(newNote.getItemText("test")).to.be.equal("test value"); 195 | }); 196 | 197 | 198 | it('hasItem should return true', function() { 199 | expect(newNote.hasItem("test")).to.be.true; 200 | 201 | }); 202 | 203 | it('deleted item should be empty', function() { 204 | newNote.deleteItem("test"); 205 | expect(newNote.getItemText("test")).to.be.equal(""); 206 | }); 207 | 208 | it('should create a number item on newly created note', function() { 209 | newNote.setItemNumber("tall", 33.3); 210 | expect(newNote.getItemNumber("tall")).to.be.equal(33.3); 211 | }); 212 | 213 | it('should create an array item on newly created note', function() { 214 | var text_list = ["Text1","Text2","Text3"]; 215 | newNote.setItemValue("text_list",text_list); 216 | expect(newNote.getItemValue("text_list")).to.deep.equal(text_list); 217 | }); 218 | 219 | it('should append a value to the array', function() { 220 | let text_list = ["Text1","Text2","Text3"]; 221 | let textToAppend = "Text4"; 222 | text_list.push(textToAppend); 223 | newNote.appendItemValue("text_list",textToAppend); 224 | expect(newNote.getItemValue("text_list")).to.deep.equal(text_list); 225 | 226 | }); 227 | 228 | it('should create a date item', function() { 229 | let date = new Date(); 230 | newNote.setItemDate("date_test",date); 231 | // notes does not save ms in dates, compare the date strings instead. 232 | expect(newNote.getItemDate("date_test").toString()).to.be.equal(date.toString()); 233 | }) 234 | 235 | it('should save the newnote and get the note unid', function() { 236 | newNote.updateNote(); 237 | expect(newNote.getUNID()).to.have.lengthOf(32); 238 | }); 239 | 240 | 241 | 242 | 243 | after(function(done) { 244 | note.close(); 245 | db.close(); 246 | domino.stermThread(); 247 | done(); 248 | }) 249 | }); 250 | 251 | describe('delete document', function() { 252 | var deleteResult = {}; 253 | before(function(done) { 254 | db.del(savedDocumentUnid,function(err,result) { 255 | if (err) { 256 | done(err); 257 | } else { 258 | deleteResult = result; 259 | done(); 260 | } 261 | }); 262 | }); 263 | it('should return status property that equals "deleted"',function() { 264 | expect(deleteResult).to.have.property('status').to.eql("deleted"); 265 | }); 266 | }); 267 | }); 268 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "domino-nsf", 3 | "version": "0.3.1", 4 | "description": "Nodejs driver for Domino nsf databases", 5 | "homepage": "https://github.com/nthjelme/nodejs-domino", 6 | "scripts": { 7 | "commit": "git-cz", 8 | "test": "mocha index.test.js" 9 | }, 10 | "dependencies": {}, 11 | "keywords": [ 12 | "database", 13 | "domino", 14 | "json", 15 | "nosql", 16 | "nsf" 17 | ], 18 | "os": [ 19 | "win32", 20 | "linux" 21 | ], 22 | "cpu": [ 23 | "ia32", 24 | "x64" 25 | ], 26 | "license": "MIT", 27 | "main": "index.js", 28 | "author": { 29 | "email": "nhjelme@gmail.com", 30 | "name": "Nils Tarjei Hjelme" 31 | }, 32 | "maintainers": [ 33 | { 34 | "name": "nhjelme", 35 | "email": "nhjelme@gmail.com" 36 | } 37 | ], 38 | "repository": { 39 | "type": "git", 40 | "url": "https://github.com/nthjelme/nodejs-domino.git" 41 | }, 42 | "devDependencies": { 43 | "chai": "^3.5.0", 44 | "cz-conventional-changelog": "^1.2.0", 45 | "mocha": "^3.1.2", 46 | "nan": "^2.8.0" 47 | }, 48 | "config": { 49 | "commitizen": { 50 | "path": "cz-conventional-changelog" 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/DataHelper.cc: -------------------------------------------------------------------------------- 1 | #include "DataHelper.h" 2 | #include 3 | 4 | void DataHelper::GetAPIError(STATUS api_error, char * error_text) 5 | { 6 | STATUS string_id = ERR(api_error); 7 | WORD text_len; 8 | 9 | /* Get the message for this IBM C API for Notes/Domino error code 10 | from the resource string table. */ 11 | 12 | text_len = OSLoadString(NULLHANDLE, 13 | string_id, 14 | error_text, 15 | 200); 16 | return; 17 | } 18 | 19 | void DataHelper::ToNOTEID(const char *idStr,NOTEID * noteId) { 20 | if (strlen(idStr) == 8) { 21 | char id_buffer[9]; 22 | strncpy(id_buffer,idStr,8); 23 | id_buffer[8] = '\0'; 24 | *noteId = (DWORD)strtoul(id_buffer+8,NULL,16); 25 | } 26 | } 27 | 28 | void DataHelper::ToUNID(const char *unidStr, UNID * Unid) { 29 | if (strlen(unidStr) == 32) { 30 | char unid_buffer[33]; 31 | strncpy(unid_buffer, unidStr, 32); 32 | unid_buffer[32] = '\0'; 33 | if (strlen(unid_buffer) == 32) 34 | { 35 | /* Note part second, reading backwards in buffer */ 36 | Unid->Note.Innards[0] = (DWORD)strtoul(unid_buffer + 24, NULL, 16); 37 | unid_buffer[24] = '\0'; 38 | Unid->Note.Innards[1] = (DWORD)strtoul(unid_buffer + 16, NULL, 16); 39 | unid_buffer[16] = '\0'; 40 | 41 | /* DB part first */ 42 | Unid->File.Innards[0] = (DWORD)strtoul(unid_buffer + 8, NULL, 16); 43 | unid_buffer[8] = '\0'; 44 | Unid->File.Innards[1] = (DWORD)strtoul(unid_buffer, NULL, 16); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /src/DataHelper.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Domino addon for Node.js 3 | * 4 | * Copyright (c) 2016 Nils T. Hjelme 5 | * 6 | * The MIT License (MIT) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | *******************************************************************************/ 26 | 27 | #ifndef DATA_HELPER_H_ 28 | #define DATA_HELPER_H_ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | 41 | using v8::Local; 42 | using v8::Array; 43 | using v8::Object; 44 | using v8::Number; 45 | using v8::Value; 46 | using v8::String; 47 | using Nan::New; 48 | using Nan::Null; 49 | using Nan::To; 50 | 51 | class DataHelper { 52 | public: 53 | static void GetAPIError(STATUS api_error, char * error_text); 54 | static void ToUNID(const char *unidStr, UNID * unid); 55 | static void ToNOTEID(const char *idStr,NOTEID * noteId); 56 | }; 57 | 58 | #endif // ITEM_VALUE_H_ 59 | -------------------------------------------------------------------------------- /src/DocumentItem.cc: -------------------------------------------------------------------------------- 1 | #include "DocumentItem.h" 2 | #include "nan.h" 3 | #include 4 | 5 | 6 | using v8::Function; 7 | using v8::Local; 8 | using v8::Number; 9 | using v8::Value; 10 | using v8::String; 11 | using v8::Object; 12 | using v8::Array; 13 | using Nan::AsyncQueueWorker; 14 | using Nan::AsyncWorker; 15 | using Nan::Callback; 16 | using Nan::HandleScope; 17 | using Nan::New; 18 | using Nan::Null; 19 | using Nan::To; 20 | 21 | void pack_document(v8::Local & target, std::vector items) { 22 | for (std::size_t i = 0; i < items.size(); i++) { 23 | if (items[i]->type == 1) { 24 | Nan::Set(target, New(items[i]->name).ToLocalChecked(), New(items[i]->stringValue).ToLocalChecked()); 25 | } 26 | else if (items[i]->type == 2) { 27 | Nan::Set(target, New(items[i]->name).ToLocalChecked(), New(items[i]->numberValue)); 28 | } 29 | else if (items[i]->type == 3) { 30 | Nan::Set(target, New(items[i]->name).ToLocalChecked(), New(items[i]->numberValue).ToLocalChecked()); 31 | } 32 | else if (items[i]->type == 4) { 33 | Local arr = New(); 34 | for (size_t j = 0; j < items[i]->vectorStrValue.size(); j++) { 35 | Nan::Set(arr, j, Nan::New(items[i]->vectorStrValue[j]).ToLocalChecked()); 36 | } 37 | Nan::Set(target, New(items[i]->name).ToLocalChecked(), arr); 38 | } 39 | } 40 | } 41 | 42 | std::vector unpack_document(v8::Local & document) { 43 | std::vector items; 44 | 45 | Local propNames = document->GetOwnPropertyNames(); 46 | unsigned int num_prop = propNames->Length(); 47 | for (unsigned int i = 0; i < num_prop; i++) { 48 | DocumentItem *di = new DocumentItem(); 49 | std::vector docVec; 50 | Local name = propNames->Get(i); 51 | std::string key; 52 | 53 | Local keyStr = Local::Cast(name); 54 | v8::String::Utf8Value param1(keyStr->ToString()); 55 | key = std::string(*param1); 56 | Local val = document->Get(name); 57 | 58 | if (val->IsString()) { 59 | String::Utf8Value value(val->ToString()); 60 | std::string valueStr = std::string(*value); 61 | di->stringValue = valueStr; 62 | di->name = (char*)malloc(key.size() + 1); 63 | if (di->name) { 64 | memcpy(di->name, key.c_str(), key.size()); 65 | di->name[key.size()] = '\0'; 66 | } 67 | di->type = 1; 68 | items.push_back(di); 69 | } 70 | else if (val->IsArray()) { 71 | Local arrVal = Local::Cast(val); 72 | unsigned int num_locations = arrVal->Length(); 73 | if (num_locations > 0) { 74 | 75 | for (unsigned int i = 0; i < num_locations; i++) { 76 | Local obj = Local::Cast(arrVal->Get(i)); 77 | String::Utf8Value value(obj->ToString()); 78 | std::string s_val = std::string(*value); 79 | size_t val_len = s_val.size(); 80 | char *vecValue = (char*)malloc(val_len + 1); 81 | if (vecValue) { 82 | strcpy(vecValue, s_val.c_str()); 83 | //memcpy(vecValue, s_val.c_str(), val_len); 84 | //vecValue[val_len] = '\0'; 85 | docVec.push_back(vecValue); 86 | } 87 | 88 | } 89 | di->vectorStrValue = docVec; 90 | di->name = (char*)malloc(key.size() + 1); 91 | if (di->name) { 92 | memcpy(di->name, key.c_str(), key.size()); 93 | di->name[key.size()] = '\0'; 94 | } 95 | di->type = 4; 96 | items.push_back(di); 97 | 98 | } 99 | } 100 | else if (val->IsNumber()) { 101 | di->numberValue = val->NumberValue(); 102 | di->name = (char*)malloc(key.size() + 1); 103 | if (di->name) { 104 | memcpy(di->name, key.c_str(), key.size()); 105 | di->name[key.size()] = '\0'; 106 | } 107 | di->type = 2; 108 | items.push_back(di); 109 | } 110 | else if (val->IsDate()) { 111 | di->numberValue = v8::Date::Cast(*val)->NumberValue(); 112 | di->name = (char*)malloc(key.size() + 1); 113 | if (di->name) { 114 | memcpy(di->name, key.c_str(), key.size()); 115 | di->name[key.size()] = '\0'; 116 | } 117 | di->type = 3; 118 | items.push_back(di); 119 | 120 | } 121 | } 122 | return items; 123 | 124 | } -------------------------------------------------------------------------------- /src/DocumentItem.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "nan.h" 4 | 5 | using namespace std; 6 | using v8::Local; 7 | using v8::Object; 8 | 9 | class DocumentItem { 10 | public: 11 | DocumentItem() { 12 | stringValue = ""; type = 0; name = ""; numberValue = 0.0; vectorStrValue= std::vector(); 13 | } 14 | ~DocumentItem() { 15 | printf("destructor..\n"); 16 | if (name) { 17 | printf("delete name"); 18 | delete name; 19 | } 20 | vectorStrValue.clear(); 21 | } 22 | DocumentItem(char * n, string d) { 23 | stringValue = d; 24 | type = 1; 25 | name = n; 26 | } 27 | DocumentItem(char* n, double d) { 28 | numberValue = d; 29 | type = 2; 30 | name = n; 31 | } 32 | DocumentItem(char * n, double d, double r) { 33 | numberValue = d; 34 | type = r; 35 | name = n; 36 | } 37 | DocumentItem(char* n, std::vector d) { 38 | vectorStrValue = d; 39 | type = 4; 40 | name = n; 41 | } 42 | 43 | string stringValue; 44 | string headerValue; 45 | double numberValue; 46 | std::vector vectorStrValue; 47 | char * name; 48 | double type; 49 | }; 50 | 51 | void pack_document(v8::Local & target, std::vector); 52 | std::vector unpack_document(v8::Local & document); 53 | -------------------------------------------------------------------------------- /src/addon.cc: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Domino addon for Node.js 3 | * 4 | * Copyright (c) 2016 Nils T. Hjelme 5 | * 6 | * The MIT License (MIT) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | *******************************************************************************/ 26 | 27 | #include 28 | #include "document_async.h" 29 | #include "save_document_async.h" 30 | #include "view_async.h" 31 | #include "replicate_database_async.h" 32 | #include "makeresponse_document.h" 33 | #include "delete_document_async.h" 34 | #include "create_database.h" 35 | #include "delete_database.h" 36 | #include "nsf_search.h" 37 | #include 38 | #include "global.h" 39 | #include "nsfdb.h" 40 | #include "nsfdata.h" 41 | #include "osmisc.h" 42 | #include "osfile.h" 43 | #include "htmlapi.h" 44 | #include "notes_document.h" 45 | #include "notes_database.h" 46 | 47 | using v8::FunctionTemplate; 48 | using v8::Handle; 49 | using v8::Object; 50 | using v8::String; 51 | using node::AtExit; 52 | using Nan::GetFunction; 53 | using Nan::New; 54 | using Nan::Set; 55 | 56 | //LNNotesSession session; // session as a global, should maby be in a Persist object? 57 | 58 | void InitDominoSession(const Nan::FunctionCallbackInfo& info) { 59 | char *argv[] = { "./addon" }; 60 | STATUS error; 61 | if (error = NotesInitExtended(1, argv)) { 62 | printf("\n Unable to initialize Notes.\n"); 63 | 64 | } 65 | } 66 | 67 | void TermDominoSession(const Nan::FunctionCallbackInfo& info) { 68 | NotesTerm(); 69 | } 70 | 71 | void sinitThread(const Nan::FunctionCallbackInfo& info) { 72 | STATUS error = NOERROR; /* return status from API calls */ 73 | char *error_text = (char *) malloc(sizeof(char) * 200); 74 | if (error = NotesInitThread()) 75 | { 76 | DataHelper::GetAPIError(error,error_text); 77 | printf("error: %s", error_text); 78 | } 79 | } 80 | 81 | void stermThread(const Nan::FunctionCallbackInfo& info) { 82 | NotesTermThread(); 83 | } 84 | 85 | 86 | static void termAtExitDominoSession(void*) { 87 | 88 | 89 | } 90 | NAN_MODULE_INIT(InitAll) { 91 | Set(target, New("getDocumentAsync").ToLocalChecked(), 92 | GetFunction(New(GetDocumentAsync)).ToLocalChecked()); 93 | 94 | Set(target, New("saveDocumentAsync").ToLocalChecked(), 95 | GetFunction(New(SaveDocumentAsync)).ToLocalChecked()); 96 | 97 | 98 | Set(target, New("deleteDocumentAsync").ToLocalChecked(), 99 | GetFunction(New(DeleteDocumentAsync)).ToLocalChecked()); 100 | 101 | Set(target, New("makeResponseDocumentAsync").ToLocalChecked(), 102 | GetFunction(New(MakeResponseDocumentAsync)).ToLocalChecked()); 103 | 104 | Set(target, New("searchNsfAsync").ToLocalChecked(), 105 | GetFunction(New(SearchNsfAsync)).ToLocalChecked()); 106 | 107 | Set(target, New("sinitThread").ToLocalChecked(), 108 | GetFunction(New(sinitThread)).ToLocalChecked()); 109 | 110 | Set(target, New("stermThread").ToLocalChecked(), 111 | GetFunction(New(stermThread)).ToLocalChecked()); 112 | 113 | /** 114 | * Database methods 115 | * 116 | * */ 117 | Set(target, New("openDatabase").ToLocalChecked(), 118 | GetFunction(New(openDatabase)).ToLocalChecked()); 119 | 120 | Set(target, New("closeDatabase").ToLocalChecked(), 121 | GetFunction(New(closeDatabase)).ToLocalChecked()); 122 | 123 | Set(target, New("getDatabaseName").ToLocalChecked(), 124 | GetFunction(New(getDatabaseName)).ToLocalChecked()); 125 | 126 | Set(target, New("replicationSummary").ToLocalChecked(), 127 | GetFunction(New(replicationSummary)).ToLocalChecked()); 128 | 129 | Set(target, New("getNotesNote").ToLocalChecked(), 130 | GetFunction(New(getNotesNote)).ToLocalChecked()); 131 | 132 | Set(target, New("getNoteById").ToLocalChecked(), 133 | GetFunction(New(getNoteById)).ToLocalChecked()); 134 | 135 | Set(target, New("getNoteID").ToLocalChecked(), 136 | GetFunction(New(getNoteID)).ToLocalChecked()); 137 | 138 | 139 | Set(target, New("createNotesNote").ToLocalChecked(), 140 | GetFunction(New(createNotesNote)).ToLocalChecked()); 141 | 142 | 143 | /** 144 | * Document methods 145 | * */ 146 | Set(target, New("closeNote").ToLocalChecked(), 147 | GetFunction(New(closeNote)).ToLocalChecked()); 148 | 149 | Set(target, New("updateNote").ToLocalChecked(), 150 | GetFunction(New(updateNote)).ToLocalChecked()); 151 | 152 | Set(target, New("getNoteUNID").ToLocalChecked(), 153 | GetFunction(New(getNoteUNID)).ToLocalChecked()); 154 | 155 | Set(target, New("getItemText").ToLocalChecked(), 156 | GetFunction(New(getItemText)).ToLocalChecked()); 157 | 158 | Set(target, New("hasItem").ToLocalChecked(), 159 | GetFunction(New(hasItem)).ToLocalChecked()); 160 | 161 | Set(target, New("setItemText").ToLocalChecked(), 162 | GetFunction(New(setItemText)).ToLocalChecked()); 163 | 164 | Set(target, New("setAuthor").ToLocalChecked(), 165 | GetFunction(New(setAuthor)).ToLocalChecked()); 166 | 167 | Set(target, New("setItemValue").ToLocalChecked(), 168 | GetFunction(New(setItemValue)).ToLocalChecked()); 169 | 170 | Set(target, New("getItemNumber").ToLocalChecked(), 171 | GetFunction(New(getItemNumber)).ToLocalChecked()); 172 | 173 | Set(target, New("setItemNumber").ToLocalChecked(), 174 | GetFunction(New(setItemNumber)).ToLocalChecked()); 175 | 176 | Set(target, New("getItemDate").ToLocalChecked(), 177 | GetFunction(New(getItemDate)).ToLocalChecked()); 178 | 179 | Set(target, New("setItemDate").ToLocalChecked(), 180 | GetFunction(New(setItemDate)).ToLocalChecked()); 181 | 182 | Set(target, New("getItemValue").ToLocalChecked(), 183 | GetFunction(New(getItemValue)).ToLocalChecked()); 184 | 185 | Set(target, New("appendItemTextList").ToLocalChecked(), 186 | GetFunction(New(appendItemTextList)).ToLocalChecked()); 187 | 188 | Set(target, New("getMimeItem").ToLocalChecked(), 189 | GetFunction(New(getMimeItem)).ToLocalChecked()); 190 | 191 | Set(target, New("setMimeItem").ToLocalChecked(), 192 | GetFunction(New(setMimeItem)).ToLocalChecked()); 193 | 194 | Set(target, New("deleteItem").ToLocalChecked(), 195 | GetFunction(New(deleteItem)).ToLocalChecked()); 196 | 197 | /* 198 | Set(target, New("getResponseDocumentsAsync").ToLocalChecked(), 199 | GetFunction(New(GetResponseDocumentsAsync)).ToLocalChecked()); 200 | 201 | Set(target, New("replicateDatabaseAsync").ToLocalChecked(), 202 | GetFunction(New(ReplicateDatabaseAsync)).ToLocalChecked()); 203 | */ 204 | Set(target, New("createDatabase").ToLocalChecked(), 205 | GetFunction(New(createDatabase)).ToLocalChecked()); 206 | 207 | Set(target, New("deleteDatabase").ToLocalChecked(), 208 | GetFunction(New(deleteDatabase)).ToLocalChecked()); 209 | 210 | Set(target, New("getViewAsync").ToLocalChecked(), 211 | GetFunction(New(GetViewAsync)).ToLocalChecked()); 212 | 213 | Set(target, Nan::New("initSession").ToLocalChecked(), 214 | Nan::New(InitDominoSession)->GetFunction()); 215 | 216 | Set(target, Nan::New("termSession").ToLocalChecked(), 217 | Nan::New(TermDominoSession)->GetFunction()); 218 | 219 | AtExit(termAtExitDominoSession); 220 | 221 | } 222 | 223 | NODE_MODULE(addon, InitAll) 224 | -------------------------------------------------------------------------------- /src/create_database.cc: -------------------------------------------------------------------------------- 1 | #include "create_database.h" 2 | #include 3 | 4 | using v8::Function; 5 | using v8::Local; 6 | using v8::Number; 7 | using v8::Value; 8 | using v8::String; 9 | using v8::Object; 10 | using v8::Array; 11 | using Nan::AsyncQueueWorker; 12 | using Nan::AsyncWorker; 13 | using Nan::Callback; 14 | using Nan::HandleScope; 15 | using Nan::New; 16 | using Nan::Null; 17 | using Nan::To; 18 | 19 | 20 | NAN_METHOD(createDatabase) { 21 | STATUS error = NOERROR; /* return status from API calls */ 22 | char *error_text = (char *)malloc(sizeof(char) * 200); 23 | DBHANDLE db_handle; /* handle of source database */ 24 | NOTEHANDLE hIconNote; /* handle to the icon note */ 25 | char db_info[NSF_INFO_SIZE]; /* database info buffer */ 26 | char set_db_flags[100] = ""; /* modified icon note flags */ 27 | 28 | v8::Isolate* isolate = info.GetIsolate(); 29 | Local param = (info[0]->ToObject()); 30 | Local dbKey = String::NewFromUtf8(isolate, "database"); 31 | Local titleKey = String::NewFromUtf8(isolate, "title"); 32 | Local serverKey = String::NewFromUtf8(isolate, "server"); 33 | Local dbVal = param->Get(dbKey); 34 | Local titleVal = param->Get(titleKey); 35 | Local serverVal = param->Get(serverKey); 36 | 37 | String::Utf8Value db_name(dbVal->ToString()); 38 | String::Utf8Value db_title(titleVal->ToString()); 39 | Local errorObj = Nan::New(); 40 | 41 | 42 | if (error = NotesInitThread()) { 43 | DataHelper::GetAPIError(error, error_text); 44 | goto hasError; 45 | } 46 | 47 | 48 | if (error = NSFDbCreate (*db_name, DBCLASS_NOTEFILE, FALSE)) { 49 | DataHelper::GetAPIError(error, error_text); 50 | NotesTermThread(); 51 | goto hasError; 52 | } 53 | 54 | if (error = NSFDbOpen(*db_name, &db_handle)) { 55 | DataHelper::GetAPIError(error, error_text); 56 | NotesTermThread(); 57 | goto hasError;; 58 | } 59 | 60 | /* Get the output database information buffer */ 61 | if (error = NSFDbInfoGet (db_handle, db_info)) { 62 | NSFDbClose (db_handle); 63 | DataHelper::GetAPIError(error, error_text); 64 | NotesTermThread(); 65 | goto hasError;; 66 | } 67 | 68 | NSFDbInfoModify (db_info, INFOPARSE_TITLE, *db_title); 69 | 70 | if (error = NSFDbInfoSet (db_handle, db_info)) { 71 | NSFDbClose (db_handle); 72 | DataHelper::GetAPIError(error, error_text); 73 | NotesTermThread(); 74 | goto hasError;; 75 | } 76 | 77 | if (!NSFNoteOpen(db_handle, NOTE_ID_SPECIAL+NOTE_CLASS_ICON, 0, &hIconNote)) { 78 | 79 | /* Update the FIELD_TITLE ("$TITLE") field if present */ 80 | 81 | if (NSFItemIsPresent (hIconNote, FIELD_TITLE, (WORD) strlen (FIELD_TITLE)) ) { 82 | NSFItemSetText(hIconNote, FIELD_TITLE, db_info, MAXWORD); 83 | NSFNoteUpdate(hIconNote, 0); 84 | } 85 | 86 | /* Set the DESIGN_FLAGS ($Flags) field */ 87 | if (error = NSFItemSetText ( hIconNote, DESIGN_FLAGS, set_db_flags, MAXWORD)) { 88 | DataHelper::GetAPIError(error, error_text); 89 | NSFNoteClose (hIconNote); 90 | NSFDbClose (db_handle); 91 | NotesTermThread(); 92 | goto hasError;; 93 | } 94 | 95 | /* Update the note in the database */ 96 | if (error = NSFNoteUpdate (hIconNote, 0)) { 97 | DataHelper::GetAPIError(error, error_text); 98 | NSFNoteClose (hIconNote); 99 | NSFDbClose (db_handle); 100 | NotesTermThread(); 101 | goto hasError;; 102 | } 103 | } 104 | 105 | NSFNoteClose(hIconNote); 106 | 107 | if (error = NSFDbClose (db_handle)) { 108 | DataHelper::GetAPIError(error, error_text); 109 | NotesTermThread(); 110 | goto hasError; 111 | } 112 | 113 | 114 | hasError: if (error) { 115 | Nan::Set(errorObj, New("error").ToLocalChecked(), New(error_text).ToLocalChecked()); 116 | } 117 | 118 | Callback *callback = new Callback(info[1].As()); 119 | Local resDoc = Nan::New(); 120 | 121 | if (error == NOERROR) { 122 | Nan::Set(resDoc, New("database").ToLocalChecked(), dbVal); 123 | Nan::Set(resDoc, New("title").ToLocalChecked(), titleVal); 124 | Nan::Set(resDoc, New("server").ToLocalChecked(), serverVal); 125 | } 126 | 127 | 128 | free(error_text); 129 | Local argv[] = { errorObj,resDoc }; 130 | callback->Call(2, argv); 131 | } -------------------------------------------------------------------------------- /src/create_database.h: -------------------------------------------------------------------------------- 1 | 2 | /******************************************************************************* 3 | * Domino addon for Node.js 4 | * 5 | * Copyright (c) 2016 Nils T. Hjelme 6 | * 7 | * The MIT License (MIT) 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | *******************************************************************************/ 27 | 28 | #ifndef CREATE_DATABASE_H_ 29 | #define CREATE_DATABASE_H_ 30 | 31 | #include 32 | #include "global.h" 33 | #include 34 | #include "DataHelper.h" 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | NAN_METHOD(createDatabase); 41 | 42 | #endif // CREATE_DATABASE_H_ 43 | -------------------------------------------------------------------------------- /src/delete_database.cc: -------------------------------------------------------------------------------- 1 | #include "delete_database.h" 2 | #include 3 | 4 | using v8::Function; 5 | using v8::Local; 6 | using v8::Number; 7 | using v8::Value; 8 | using v8::String; 9 | using v8::Object; 10 | using v8::Array; 11 | using Nan::AsyncQueueWorker; 12 | using Nan::AsyncWorker; 13 | using Nan::Callback; 14 | using Nan::HandleScope; 15 | using Nan::New; 16 | using Nan::Null; 17 | using Nan::To; 18 | 19 | 20 | NAN_METHOD(deleteDatabase) { 21 | STATUS error = NOERROR; /* return status from API calls */ 22 | char *error_text = (char *)malloc(sizeof(char) * 200); 23 | 24 | v8::Isolate* isolate = info.GetIsolate(); 25 | Local param = (info[0]->ToObject()); 26 | Local dbKey = String::NewFromUtf8(isolate, "database"); 27 | Local serverKey = String::NewFromUtf8(isolate, "server"); 28 | Local dbVal = param->Get(dbKey); 29 | Local serverVal = param->Get(serverKey); 30 | 31 | String::Utf8Value db_name(dbVal->ToString()); 32 | Local errorObj = Nan::New(); 33 | Local resDoc = Nan::New(); 34 | 35 | 36 | if (error = NotesInitThread()) { 37 | DataHelper::GetAPIError(error, error_text); 38 | goto hasError; 39 | 40 | } 41 | 42 | if (error = NSFDbDelete(*db_name)) { 43 | DataHelper::GetAPIError(error, error_text); 44 | NotesTermThread(); 45 | goto hasError; 46 | } 47 | 48 | 49 | 50 | hasError: if (error) { 51 | Nan::Set(errorObj, New("error").ToLocalChecked(), New(error_text).ToLocalChecked()); 52 | } 53 | 54 | if (error == NOERROR) { 55 | Nan::Set(resDoc, New("status").ToLocalChecked(), New("deleted").ToLocalChecked()); 56 | } 57 | 58 | Callback *callback = new Callback(info[1].As()); 59 | 60 | free(error_text); 61 | Local argv[] = { errorObj,resDoc }; 62 | callback->Call(2, argv); 63 | } -------------------------------------------------------------------------------- /src/delete_database.h: -------------------------------------------------------------------------------- 1 | 2 | /******************************************************************************* 3 | * Domino addon for Node.js 4 | * 5 | * Copyright (c) 2016 Nils T. Hjelme 6 | * 7 | * The MIT License (MIT) 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | *******************************************************************************/ 27 | 28 | #ifndef DELETE_DATABASE_H_ 29 | #define DELETE_DATABASE_H_ 30 | 31 | #include 32 | #include "global.h" 33 | #include 34 | #include "DataHelper.h" 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | NAN_METHOD(deleteDatabase); 41 | 42 | #endif // DELETE_DATABASE_H_ 43 | -------------------------------------------------------------------------------- /src/delete_document_async.cc: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Domino addon for Node.js 3 | * 4 | * Copyright (c) 2016 Nils T. Hjelme 5 | * 6 | * The MIT License (MIT) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | *******************************************************************************/ 26 | 27 | #include 28 | #include "delete_document_async.h" 29 | #include "DataHelper.h" 30 | #include "global.h" 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | using v8::Function; 37 | using v8::Local; 38 | using v8::Number; 39 | using v8::Value; 40 | using v8::String; 41 | using v8::Object; 42 | using v8::Array; 43 | using Nan::AsyncQueueWorker; 44 | using Nan::AsyncWorker; 45 | using Nan::Callback; 46 | using Nan::HandleScope; 47 | using Nan::New; 48 | using Nan::Null; 49 | using Nan::To; 50 | 51 | class DeleteDocumentWorker : public AsyncWorker { 52 | public: 53 | DeleteDocumentWorker(Callback *callback, std::string serverName, std::string dbName, std::string unid) 54 | : AsyncWorker(callback), serverName(serverName), dbName(dbName), unid(unid) {} 55 | ~DeleteDocumentWorker() {} 56 | 57 | // Executed inside the worker-thread. 58 | // It is not safe to access V8, or V8 data structures 59 | // here, so everything we need for input and output 60 | // should go on `this`. 61 | void Execute() { 62 | DBHANDLE db_handle; /* handle of source database */ 63 | UNID note_unid; 64 | NOTEID note_id; 65 | STATUS error = NOERROR; /* return status from API calls */ 66 | char *error_text = (char *)malloc(sizeof(char) * 200); 67 | 68 | if (unid.length() != 32) { 69 | SetErrorMessage("Not a valid unid."); 70 | return; 71 | } 72 | 73 | if (error = NotesInitThread()) 74 | { 75 | DataHelper::GetAPIError(error, error_text); 76 | SetErrorMessage(error_text); 77 | } 78 | 79 | if (error = NSFDbOpen(dbName.c_str(), &db_handle)) 80 | { 81 | DataHelper::GetAPIError(error, error_text); 82 | SetErrorMessage(error_text); 83 | NotesTermThread(); 84 | return; 85 | } 86 | DataHelper::ToUNID(unid.c_str(), ¬e_unid); 87 | 88 | if (error = NSFDbGetNoteInfoByUNID( 89 | db_handle, /* database handle */ 90 | ¬e_unid, /* UniD */ 91 | ¬e_id, 92 | NULL, 93 | NULL, 94 | NULL)) 95 | { 96 | DataHelper::GetAPIError(error, error_text); 97 | SetErrorMessage(error_text); 98 | NSFDbClose(db_handle); 99 | return; 100 | } 101 | 102 | if (error = NSFNoteDelete(db_handle, note_id, 0)) { 103 | DataHelper::GetAPIError(error, error_text); 104 | SetErrorMessage(error_text); 105 | } 106 | NSFDbClose(db_handle); 107 | 108 | NotesTermThread(); 109 | } 110 | 111 | void HandleOKCallback() { 112 | HandleScope scope; 113 | Local resDoc = Nan::New(); 114 | Nan::Set(resDoc, New("status").ToLocalChecked(), New("deleted").ToLocalChecked()); 115 | Local argv[] = { 116 | Null() 117 | , resDoc 118 | }; 119 | 120 | callback->Call(2, argv); 121 | } 122 | 123 | void HandleErrorCallback() { 124 | HandleScope scope; 125 | Local errorObj = Nan::New(); 126 | Nan::Set(errorObj, New("errorMessage").ToLocalChecked(), New(ErrorMessage()).ToLocalChecked()); 127 | Local argv[] = { 128 | errorObj, 129 | Null() 130 | }; 131 | callback->Call(2, argv); 132 | } 133 | 134 | private: 135 | std::string serverName; 136 | std::string dbName; 137 | std::string unid; 138 | }; 139 | 140 | NAN_METHOD(DeleteDocumentAsync) { 141 | v8::Isolate* isolate = info.GetIsolate(); 142 | 143 | Local param = (info[0]->ToObject()); 144 | Local unidParam = (info[1]->ToString()); 145 | Local serverKey = String::NewFromUtf8(isolate, "server"); 146 | Local databaseKey = String::NewFromUtf8(isolate, "database"); 147 | Local serverVal = param->Get(serverKey); 148 | Local databaseVal = param->Get(databaseKey); 149 | 150 | String::Utf8Value serverName(serverVal->ToString()); 151 | String::Utf8Value dbName(databaseVal->ToString()); 152 | String::Utf8Value unid(unidParam->ToString()); 153 | 154 | std::string serverStr; 155 | std::string dbStr; 156 | std::string unidStr; 157 | serverStr = std::string(*serverName); 158 | dbStr = std::string(*dbName); 159 | unidStr = std::string(*unid); 160 | Callback *callback = new Callback(info[2].As()); 161 | 162 | AsyncQueueWorker(new DeleteDocumentWorker(callback, serverStr, dbStr, unidStr)); 163 | } -------------------------------------------------------------------------------- /src/delete_document_async.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Domino addon for Node.js 3 | * 4 | * Copyright (c) 2016 Nils T. Hjelme 5 | * 6 | * The MIT License (MIT) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | *******************************************************************************/ 26 | 27 | #ifndef DELETE_DOCUMENT_ASYNC_H_ 28 | #define DELETE_DOCUMENT_ASYNC_H_ 29 | 30 | #include 31 | 32 | NAN_METHOD(DeleteDocumentAsync); 33 | 34 | #endif // DELETE_DOCUMENT_ASYNC_H_ 35 | -------------------------------------------------------------------------------- /src/document_async.cc: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Domino addon for Node.js 3 | * 4 | * Copyright (c) 2016 Nils T. Hjelme 5 | * 6 | * The MIT License (MIT) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | *******************************************************************************/ 26 | 27 | #include 28 | #include "document_async.h" 29 | #include "DocumentItem.h" 30 | #include "DataHelper.h" 31 | #include "notes_document.h" 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | using v8::Function; 45 | using v8::Local; 46 | using v8::Number; 47 | using v8::Value; 48 | using v8::String; 49 | using v8::Object; 50 | using v8::Array; 51 | using Nan::AsyncQueueWorker; 52 | using Nan::AsyncWorker; 53 | using Nan::Callback; 54 | using Nan::HandleScope; 55 | using Nan::New; 56 | using Nan::Null; 57 | using Nan::To; 58 | 59 | NOTEHANDLE note_handle; 60 | std::vector items; 61 | 62 | template< typename T > 63 | struct delete_pointer_element 64 | { 65 | void operator()(T element) const 66 | { 67 | delete element; 68 | } 69 | }; 70 | 71 | class DocumentWorker : public AsyncWorker { 72 | public: 73 | DocumentWorker(Callback *callback, std::string serverName, std::string dbName, std::string unid,std::vector fields) 74 | : AsyncWorker(callback), serverName(serverName), dbName(dbName), unid(unid),fields(fields){ 75 | } 76 | ~DocumentWorker() { 77 | // delete name pointer 78 | for (size_t i = 0; i < items.size(); i++) { 79 | if (items[i]->name) { 80 | delete items[i]->name; 81 | } 82 | } 83 | } 84 | 85 | 86 | // Executed inside the worker-thread. 87 | // It is not safe to access V8, or V8 data structures 88 | // here, so everything we need for input and output 89 | // should go on `this`. 90 | void Execute() { 91 | DBHANDLE db_handle; /* handle of source database */ 92 | UNID temp_unid; 93 | NOTEID tempID; 94 | STATUS error = NOERROR; /* return status from API calls */ 95 | char *error_text = (char *) malloc(sizeof(char) * 200); 96 | 97 | if (unid.length() != 32) { 98 | SetErrorMessage("Not a valid unid."); 99 | free(error_text); 100 | return; 101 | } 102 | 103 | if (error = NotesInitThread()) 104 | { 105 | DataHelper::GetAPIError(error,error_text); 106 | SetErrorMessage(error_text); 107 | } 108 | 109 | if (error = NSFDbOpen(dbName.c_str(), &db_handle)) 110 | { 111 | DataHelper::GetAPIError(error,error_text); 112 | SetErrorMessage(error_text); 113 | NotesTermThread(); 114 | } 115 | 116 | DataHelper::ToUNID(unid.c_str(), &temp_unid); 117 | 118 | if (error = NSFNoteOpenByUNID( 119 | db_handle, /* database handle */ 120 | &temp_unid, /* note ID */ 121 | (WORD)0, /* open flags */ 122 | ¬e_handle)) /* note handle (return) */ 123 | { 124 | DataHelper::GetAPIError(error,error_text); 125 | SetErrorMessage(error_text); 126 | NSFDbClose(db_handle); 127 | free(error_text); 128 | return; 129 | } 130 | 131 | // repoen note by by note id 132 | NSFNoteGetInfo(note_handle, _NOTE_ID, &tempID); 133 | NSFNoteClose(note_handle); 134 | if (error = NSFNoteOpenExt(db_handle, tempID, 135 | OPEN_RAW_MIME_PART, ¬e_handle)) { 136 | printf("error opening notebyid \n"); 137 | DataHelper::GetAPIError(error,error_text); 138 | SetErrorMessage(error_text); 139 | NSFDbClose(db_handle); 140 | free(error_text); 141 | 142 | } 143 | if (fields.size()>0) { 144 | for (size_t j = 0; j < fields.size(); j++) { 145 | error = getItem(fields[j].c_str()); 146 | if (error!=NOERROR) { 147 | DataHelper::GetAPIError(error,error_text); 148 | SetErrorMessage(error_text); 149 | NSFNoteClose(note_handle); 150 | NSFDbClose(db_handle); 151 | free(error_text); 152 | return; 153 | } 154 | } 155 | } else { 156 | if (error = NSFItemScan( 157 | note_handle, /* note handle */ 158 | field_actions, /* action routine for fields */ 159 | ¬e_handle)) /* argument to action routine */ 160 | 161 | { 162 | DataHelper::GetAPIError(error,error_text); 163 | SetErrorMessage(error_text); 164 | NSFNoteClose(note_handle); 165 | NSFDbClose(db_handle); 166 | free(error_text); 167 | return; 168 | } 169 | } 170 | 171 | NSFNoteClose(note_handle); 172 | 173 | if (error = NSFDbClose(db_handle)) 174 | { 175 | DataHelper::GetAPIError(error,error_text); 176 | SetErrorMessage(error_text); 177 | } 178 | free(error_text); 179 | NotesTermThread(); 180 | 181 | } 182 | 183 | 184 | 185 | // Executed when the async work is complete 186 | // this function will be run inside the main event loop 187 | // so it is safe to use V8 again 188 | void HandleOKCallback() { 189 | HandleScope scope; 190 | Local resDoc = Nan::New(); 191 | Local metadata = Nan::New(); 192 | Local itemsMetaArray = Nan::New(); 193 | char *typeKey = "type"; 194 | Nan::Set(resDoc, New("@unid").ToLocalChecked(), New(unid).ToLocalChecked()); 195 | for (std::size_t i = 0; i < items.size(); i++) { 196 | DocumentItem *di = items[i]; 197 | Local itemKey = Nan::New(); 198 | Local itemMeta = Nan::New(); 199 | if (di->type == 1) { 200 | Nan::Set(itemMeta, New("type").ToLocalChecked(), New("string").ToLocalChecked()); 201 | Nan::Set(resDoc, New(di->name).ToLocalChecked(), New(di->stringValue).ToLocalChecked()); 202 | } 203 | else if (di->type == 2) { 204 | Nan::Set(itemMeta, New("type").ToLocalChecked(), New("number").ToLocalChecked()); 205 | Nan::Set(resDoc, New(di->name).ToLocalChecked(), New(di->numberValue)); 206 | } 207 | else if (di->type == 3) { 208 | Nan::Set(itemMeta, New("type").ToLocalChecked(), New("date").ToLocalChecked()); 209 | Nan::Set(resDoc, New(di->name).ToLocalChecked(), New(di->numberValue).ToLocalChecked()); 210 | } 211 | else if (di->type == 4) { 212 | Nan::Set(itemMeta, New("type").ToLocalChecked(), New("array").ToLocalChecked()); 213 | Local arr = New(); 214 | for (size_t j = 0; j < di->vectorStrValue.size(); j++) { 215 | if (di->vectorStrValue[j]) { 216 | Nan::Set(arr, j, Nan::New(di->vectorStrValue[j]).ToLocalChecked()); 217 | } 218 | } 219 | Nan::Set(resDoc, New(di->name).ToLocalChecked(), arr); 220 | } 221 | else if (di->type == 5) { 222 | printf("has mime type with value%s\n", di->stringValue.c_str()); 223 | Nan::Set(itemMeta, New("type").ToLocalChecked(), New("mime").ToLocalChecked()); 224 | Nan::Set(itemMeta, New("header").ToLocalChecked(), New(di->headerValue).ToLocalChecked()); 225 | Nan::Set(resDoc, New(di->name).ToLocalChecked(), New(di->stringValue).ToLocalChecked()); 226 | } 227 | Nan::Set(itemKey,New(di->name).ToLocalChecked(),itemMeta); 228 | Nan::Set(itemsMetaArray,i, itemKey); 229 | } 230 | Nan::Set(metadata, New("items").ToLocalChecked(), itemsMetaArray); 231 | Nan::Set(resDoc, New("@meta_data").ToLocalChecked(), metadata); 232 | Local argv[] = { 233 | Null() 234 | , resDoc 235 | }; 236 | 237 | callback->Call(2, argv); 238 | 239 | } 240 | 241 | void HandleErrorCallback() { 242 | HandleScope scope; 243 | Local errorObj = Nan::New(); 244 | Nan::Set(errorObj, New("errorMessage").ToLocalChecked(), New(this->ErrorMessage()).ToLocalChecked()); 245 | Local argv[] = { 246 | errorObj, 247 | Null() 248 | }; 249 | callback->Call(2, argv); 250 | } 251 | 252 | private: 253 | std::string serverName; 254 | std::string dbName; 255 | std::string unid; 256 | std::vector fields; 257 | }; 258 | 259 | STATUS getItem(const char *field_name) { 260 | WORD field_len; 261 | char field_text[132000]; 262 | STATUS error = NOERROR; 263 | NUMBER number_field; 264 | 265 | BLOCKID bidLinksItem; 266 | DWORD dwLinksValueLen; 267 | BLOCKID bidLinksValue; 268 | WORD item_type; 269 | WORD fldNameLenght = strlen(field_name); 270 | DocumentItem * di = new DocumentItem(); 271 | 272 | if (error = NSFItemInfo(note_handle, field_name, 273 | strlen(field_name), &bidLinksItem, 274 | &item_type, &bidLinksValue, 275 | &dwLinksValueLen)) { 276 | printf("error getting nsfitem info\n"); 277 | return (error); 278 | } 279 | if (item_type == TYPE_TEXT) { 280 | 281 | field_len = NSFItemGetText( 282 | note_handle, 283 | field_name, 284 | field_text, 285 | (WORD) sizeof(field_text)); 286 | 287 | char buf[MAXWORD]; 288 | OSTranslate(OS_TRANSLATE_LMBCS_TO_UTF8, field_text, MAXWORD, buf, MAXWORD); 289 | di->stringValue = std::string(buf); 290 | di->name = (char*)malloc(fldNameLenght + 1); 291 | if (di->name) { 292 | memcpy(di->name, field_name, fldNameLenght); 293 | di->name[fldNameLenght] = '\0'; 294 | } 295 | di->type = 1; 296 | items.push_back(di); 297 | 298 | } 299 | else if (item_type == TYPE_TEXT_LIST) { 300 | 301 | WORD num_entries = NSFItemGetTextListEntries(note_handle, 302 | field_name); 303 | std::vector vectorStrValue = std::vector(0); 304 | for (int counter = 0; counter < num_entries; counter++) 305 | { 306 | field_len = NSFItemGetTextListEntry(note_handle, 307 | field_name, counter, field_text, (WORD)(sizeof(field_text) - 1)); 308 | //text_buf2[text_len] = '\0'; 309 | // buf[MAXWORD]; 310 | char *buf = (char*)malloc(field_len + 1); 311 | OSTranslate(OS_TRANSLATE_LMBCS_TO_UTF8, field_text, MAXWORD, buf, MAXWORD); 312 | vectorStrValue.push_back(buf); 313 | 314 | } 315 | di->vectorStrValue = vectorStrValue; 316 | di->name = (char*)malloc(fldNameLenght + 1); 317 | if (di->name) { 318 | memcpy(di->name, field_name, fldNameLenght); 319 | di->name[fldNameLenght] = '\0'; 320 | } 321 | di->type = 4; 322 | items.push_back(di); 323 | } 324 | else if (item_type == TYPE_NUMBER) { 325 | NSFItemGetNumber( 326 | note_handle, 327 | field_name, 328 | &number_field); 329 | di->numberValue = (double)number_field; 330 | di->name = (char*)malloc(fldNameLenght + 1); 331 | if (di->name) { 332 | memcpy(di->name, field_name, fldNameLenght); 333 | di->name[fldNameLenght] = '\0'; 334 | } 335 | di->type = 2; 336 | items.push_back(di); 337 | } 338 | else if (item_type == TYPE_TIME) { 339 | TIMEDATE time_date; 340 | if (NSFItemGetTime(note_handle, 341 | field_name, 342 | &time_date)) { 343 | TIME tid; 344 | struct tm * timeinfo; 345 | 346 | tid.GM = time_date; 347 | tid.zone = 0; 348 | tid.dst = 0; 349 | TimeGMToLocalZone(&tid); 350 | 351 | time_t rawtime = time(0); 352 | timeinfo = localtime(&rawtime); 353 | timeinfo->tm_year = tid.year - 1900; 354 | timeinfo->tm_mon = tid.month-1; 355 | timeinfo->tm_mday = tid.day; 356 | 357 | timeinfo->tm_hour = tid.hour; 358 | timeinfo->tm_min = tid.minute-1; 359 | timeinfo->tm_sec = tid.second-1; 360 | 361 | double dtime = static_cast(mktime(timeinfo))+1; 362 | 363 | double dateTimeValue = dtime * 1000; // convert to double time 364 | di->numberValue = dateTimeValue; 365 | di->name = (char*)malloc(fldNameLenght + 1); 366 | if (di->name) { 367 | memcpy(di->name, field_name, fldNameLenght); 368 | di->name[fldNameLenght] = '\0'; 369 | } 370 | di->type = 3; 371 | items.push_back(di); 372 | } 373 | } else if (item_type == TYPE_MIME_PART) { 374 | std::map mime = nsfItemGetMime((unsigned short)note_handle, field_name); 375 | std::map::iterator it; 376 | di->name = (char*)malloc(fldNameLenght + 1); 377 | if (di->name) { 378 | memcpy(di->name, field_name, fldNameLenght); 379 | di->name[fldNameLenght] = '\0'; 380 | } 381 | di->type = 5; 382 | it = mime.find("value"); 383 | 384 | // Check if element exists in map or not 385 | if (it != mime.end()) 386 | { 387 | di->stringValue = it->second; 388 | 389 | } 390 | it = mime.find("header"); 391 | if (it != mime.end()) { 392 | di->headerValue = it->second; 393 | } 394 | items.push_back(di); 395 | } 396 | return error; 397 | } 398 | 399 | 400 | STATUS LNCALLBACK field_actions(WORD unused, WORD item_flags, char far *name_ptr, WORD name_len, void far *item_valu, DWORD item_value_len, void far *note_handle2) { 401 | STATUS error = NOERROR; 402 | char *field_name = (char*)malloc(name_len + 1); 403 | if (field_name) { 404 | memcpy(field_name, name_ptr, name_len); 405 | field_name[name_len] = '\0'; 406 | } 407 | 408 | error = getItem(field_name); 409 | if (error != NOERROR) { 410 | printf("error getitem:%s\n", field_name); 411 | free(field_name); 412 | return (error); 413 | } 414 | //free(field_name); 415 | 416 | //delete field_name; 417 | 418 | return(NOERROR); 419 | 420 | } 421 | 422 | NAN_METHOD(GetDocumentAsync) { 423 | v8::Isolate* isolate = info.GetIsolate(); 424 | Local param = (info[0]->ToObject()); 425 | Local unidParam = (info[1]->ToString()); 426 | std::vector fields; 427 | if (info.Length() ==4 ) { 428 | // option parameter 429 | Local options = (info[2]->ToObject()); 430 | 431 | Local fieldsArray = Local::Cast(options->Get(String::NewFromUtf8(isolate, "fields"))); 432 | unsigned int num_locations = fieldsArray->Length(); 433 | if (num_locations > 0) { 434 | 435 | for (unsigned int i = 0; i < num_locations; i++) { 436 | Local obj = Local::Cast(fieldsArray->Get(i)); 437 | String::Utf8Value value(obj->ToString()); 438 | std::string field_val = std::string(*value); 439 | fields.push_back(field_val); 440 | } 441 | } 442 | } 443 | Local serverKey = String::NewFromUtf8(isolate, "server"); 444 | Local databaseKey = String::NewFromUtf8(isolate, "database"); 445 | Local serverVal = param->Get(serverKey); 446 | Local databaseVal = param->Get(databaseKey); 447 | 448 | String::Utf8Value serverName(serverVal->ToString()); 449 | String::Utf8Value dbName(databaseVal->ToString()); 450 | String::Utf8Value unid(unidParam->ToString()); 451 | 452 | std::string serverStr; 453 | std::string dbStr; 454 | std::string unidStr; 455 | serverStr = std::string(*serverName); 456 | dbStr = std::string(*dbName); 457 | unidStr = std::string(*unid); 458 | Callback *callback; 459 | if (info.Length() ==4 ) { 460 | // has option parameter, callback is parameter 3 461 | callback = new Callback(info[3].As()); 462 | } else { 463 | callback = new Callback(info[2].As()); 464 | } 465 | 466 | AsyncQueueWorker(new DocumentWorker(callback, serverStr,dbStr,unidStr,fields)); 467 | } 468 | -------------------------------------------------------------------------------- /src/document_async.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Domino addon for Node.js 3 | * 4 | * Copyright (c) 2016 Nils T. Hjelme 5 | * 6 | * The MIT License (MIT) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | *******************************************************************************/ 26 | 27 | #ifndef ASYNC_DOCUMENT_ASYNC_H_ 28 | #define ASYNC_DOCUMENT_ASYNC_H_ 29 | 30 | #include 31 | #include "global.h" 32 | 33 | 34 | NAN_METHOD(GetDocumentAsync); 35 | STATUS getItem(const char *field_name); 36 | STATUS LNCALLBACK field_actions(WORD unused, WORD item_flags, char far *name_ptr, WORD name_len, void far *item_valu, DWORD item_value_len, void far *docRef); 37 | 38 | 39 | #endif // ASYNC_DOCUMENT_ASYNC_H_ 40 | -------------------------------------------------------------------------------- /src/getresponse_documents.cc: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Domino addon for Node.js 3 | * 4 | * Copyright (c) 2016 Nils T. Hjelme 5 | * 6 | * The MIT License (MIT) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | *******************************************************************************/ 26 | 27 | #include 28 | #include "getresponse_documents.h" 29 | #include "ItemValue.h" 30 | #include "DataHelper.h" 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | using v8::Function; 39 | using v8::Local; 40 | using v8::Number; 41 | using v8::Value; 42 | using v8::String; 43 | using v8::Object; 44 | using v8::Array; 45 | using Nan::AsyncQueueWorker; 46 | using Nan::AsyncWorker; 47 | using Nan::Callback; 48 | using Nan::HandleScope; 49 | using Nan::New; 50 | using Nan::Null; 51 | using Nan::To; 52 | 53 | 54 | 55 | class ResponseDocumentsWorker : public AsyncWorker { 56 | public: 57 | ResponseDocumentsWorker(Callback *callback, std::string serverName, std::string dbName, std::string unid) 58 | : AsyncWorker(callback), serverName(serverName), dbName(dbName), unid(unid), responses() {} 59 | ~ResponseDocumentsWorker() {} 60 | 61 | // Executed inside the worker-thread. 62 | // It is not safe to access V8, or V8 data structures 63 | // here, so everything we need for input and output 64 | // should go on `this`. 65 | void Execute() { 66 | LNSetThrowAllErrors(TRUE); 67 | LNNotesSession session; 68 | try { 69 | session.InitThread(); 70 | LNString DbTitle = ""; 71 | 72 | LNDatabase Db; 73 | LNDocumentArray documentResponses; 74 | LNINT responseCount; 75 | session.GetDatabase(dbName.c_str(), &Db, serverName.c_str()); 76 | Db.Open(); 77 | 78 | const LNString * lnstrUNID = new LNString(unid.c_str()); 79 | 80 | //Get UNID * 81 | LNUniversalID * lnUNID = new LNUniversalID(*lnstrUNID); 82 | const UNIVERSALNOTEID * unidUNID = lnUNID->GetUniversalID(); 83 | LNDocument Doc; 84 | Db.GetDocument(unidUNID, &Doc); 85 | Doc.Open(); 86 | Doc.GetResponses(&documentResponses); 87 | 88 | responseCount = documentResponses.GetCount(); 89 | for (int j = 0; j < responseCount; j++) { 90 | LNItemArray items; 91 | LNDocument responseDoc; 92 | std::map doc; 93 | 94 | responseDoc = documentResponses[j]; 95 | responseDoc.Open(); 96 | responseDoc.GetItems(&items); 97 | 98 | const UNIVERSALNOTEID * ln_unid = responseDoc.GetUniversalID(); 99 | LNUniversalID lnUnid = LNUniversalID(ln_unid); 100 | LNString unidStr = lnUnid.GetText(); 101 | std::string unidStdStr = unidStr; 102 | doc.insert(std::make_pair("@unid", ItemValue(unidStdStr))); 103 | 104 | 105 | for (LNINT i = 0; i < responseDoc.GetItemCount(); i++) { 106 | LNItem item = items[i]; 107 | 108 | LNITEMTYPE type = item.GetType(); 109 | LNString itemName = item.GetName(); 110 | std::string iName = itemName; 111 | 112 | if (type == LNITEMTYPE_RICHTEXT) { 113 | 114 | LNRichText rt = (LNRichText)item; 115 | LNString rtText; 116 | LNRTCursor beginCursor; 117 | LNRTCursor endCursor; 118 | rt.GetCursor(&beginCursor); 119 | rt.GetEndCursor(&endCursor); 120 | std::string rtString; 121 | LNSTATUS status = LNWARN_TOO_MUCH_TEXT; 122 | while (status == LNWARN_TOO_MUCH_TEXT) { 123 | //TODO: LNStringtranlsate seems removes text from end, find another solution. 124 | status = rt.GetText(beginCursor, endCursor, &rtText, &beginCursor); 125 | LNINT bufLength = rtText.GetLength(); 126 | rtString = rtText; 127 | char *buf = (char *)malloc(sizeof(char) *bufLength + 1); 128 | LNStringTranslate(rtText, LNCHARSET_UTF8, bufLength, buf); 129 | //OSTranslate(OS_TRANSLATE_LMBCS_TO_UTF8, rtText.GetTextPtr(), bufLength, buf, bufLength); 130 | rtString.append(buf); 131 | free(buf); 132 | } 133 | doc.insert(std::make_pair(iName, ItemValue(rtString))); 134 | 135 | } 136 | else { 137 | doc.insert(std::make_pair(iName, ItemValue(&item))); 138 | } 139 | 140 | } 141 | responses.push_back(doc); 142 | 143 | } 144 | 145 | session.TermThread(); 146 | } 147 | catch (LNSTATUS Lnerror) { 148 | char ErrorBuf[512]; 149 | LNGetErrorMessage(Lnerror, ErrorBuf, 512); 150 | if (session.IsInitialized()) { 151 | session.TermThread(); 152 | } 153 | SetErrorMessage(ErrorBuf); 154 | } 155 | } 156 | 157 | 158 | // Executed when the async work is complete 159 | // this function will be run inside the main event loop 160 | // so it is safe to use V8 again 161 | void HandleOKCallback() { 162 | HandleScope scope; 163 | Local viewRes = DataHelper::getV8Data(responses); 164 | Local argv[] = { 165 | Null() 166 | , viewRes 167 | }; 168 | 169 | callback->Call(2, argv); 170 | } 171 | 172 | void HandleErrorCallback() { 173 | HandleScope scope; 174 | Local errorObj = Nan::New(); 175 | Nan::Set(errorObj, New("errorMessage").ToLocalChecked(), New(ErrorMessage()).ToLocalChecked()); 176 | Local argv[] = { 177 | errorObj, 178 | Null() 179 | }; 180 | callback->Call(2, argv); 181 | } 182 | 183 | private: 184 | std::string serverName; 185 | std::string dbName; 186 | std::string unid; 187 | std::vector > responses; 188 | }; 189 | 190 | 191 | NAN_METHOD(GetResponseDocumentsAsync) { 192 | v8::Isolate* isolate = info.GetIsolate(); 193 | 194 | Local param = (info[0]->ToObject()); 195 | Local unidParam = (info[1]->ToString()); 196 | Local serverKey = String::NewFromUtf8(isolate, "server"); 197 | Local databaseKey = String::NewFromUtf8(isolate, "database"); 198 | Local serverVal = param->Get(serverKey); 199 | Local databaseVal = param->Get(databaseKey); 200 | 201 | String::Utf8Value serverName(serverVal->ToString()); 202 | String::Utf8Value dbName(databaseVal->ToString()); 203 | String::Utf8Value unid(unidParam->ToString()); 204 | 205 | std::string serverStr; 206 | std::string dbStr; 207 | std::string unidStr; 208 | serverStr = std::string(*serverName); 209 | dbStr = std::string(*dbName); 210 | unidStr = std::string(*unid); 211 | Callback *callback = new Callback(info[2].As()); 212 | 213 | AsyncQueueWorker(new ResponseDocumentsWorker(callback, serverStr, dbStr, unidStr)); 214 | } 215 | -------------------------------------------------------------------------------- /src/getresponse_documents.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Domino addon for Node.js 3 | * 4 | * Copyright (c) 2016 Nils T. Hjelme 5 | * 6 | * The MIT License (MIT) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | *******************************************************************************/ 26 | 27 | #ifndef GETRESPONSE_DOCUMENTS_H_ 28 | #define GETRESPONSE_DOCUMENTS_H_ 29 | 30 | #include 31 | 32 | NAN_METHOD(GetResponseDocumentsAsync); 33 | 34 | #endif // GETRESPONSE_DOCUMENT_H_ 35 | -------------------------------------------------------------------------------- /src/makeresponse_document.cc: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Domino addon for Node.js 3 | * 4 | * Copyright (c) 2016 Nils T. Hjelme 5 | * 6 | * The MIT License (MIT) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | *******************************************************************************/ 26 | 27 | #include 28 | #include "makeresponse_document.h" 29 | #include "DocumentItem.h" 30 | #include "DataHelper.h" 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | using v8::Function; 38 | using v8::Local; 39 | using v8::Number; 40 | using v8::Value; 41 | using v8::String; 42 | using v8::Object; 43 | using v8::Array; 44 | using Nan::AsyncQueueWorker; 45 | using Nan::AsyncWorker; 46 | using Nan::Callback; 47 | using Nan::HandleScope; 48 | using Nan::New; 49 | using Nan::Null; 50 | using Nan::To; 51 | 52 | 53 | class MakeResponseDocumentWorker : public AsyncWorker { 54 | public: 55 | MakeResponseDocumentWorker(Callback *callback, std::string serverName, std::string dbName, std::string unid, std::string responseUnid) 56 | : AsyncWorker(callback), serverName(serverName), dbName(dbName), unid(unid), responseUnid(responseUnid) {} 57 | ~MakeResponseDocumentWorker() {} 58 | 59 | // Executed inside the worker-thread. 60 | // It is not safe to access V8, or V8 data structures 61 | // here, so everything we need for input and output 62 | // should go on `this`. 63 | void Execute() { 64 | DBHANDLE db_handle; /* handle of source database */ 65 | STATUS error = NOERROR; /* return status from API calls */ 66 | char *error_text = (char *)malloc(sizeof(char) * 200); 67 | LIST ListHdr; 68 | UNID NoteUNID; 69 | UNID ResponseUNID; 70 | NOTEHANDLE note_handle; 71 | 72 | /* block of memory to hold the response reference list */ 73 | char *buf; 74 | 75 | buf = (char *)malloc(sizeof(LIST) + sizeof(UNID)); 76 | 77 | if (buf == NULL) 78 | { 79 | SetErrorMessage("malloc failed"); 80 | free(error_text); 81 | return; 82 | } 83 | 84 | if (error = NotesInitThread()) 85 | { 86 | SetErrorMessage("error init notes thread"); 87 | } 88 | 89 | // create response unid 90 | if (unid.length() != 32) { 91 | SetErrorMessage("Not valid parent document unid"); 92 | free(error_text); 93 | free(buf); 94 | return; 95 | } 96 | // create response unid 97 | if (responseUnid.length() != 32) { 98 | SetErrorMessage("Not valid response unid"); 99 | free(error_text); 100 | free(buf); 101 | return; 102 | } 103 | 104 | 105 | DataHelper::ToUNID(unid.c_str(), &NoteUNID); 106 | DataHelper::ToUNID(responseUnid.c_str(), &ResponseUNID); 107 | 108 | /* Initialize the LIST header part of the response reference list */ 109 | ListHdr.ListEntries = (USHORT)1; 110 | 111 | /* Pack the LIST and the UNID members of the Noteref list into 112 | a memory block. 113 | */ 114 | memcpy(buf, (char*)&ListHdr, sizeof(LIST)); 115 | memcpy((buf + sizeof(LIST)), (char*)&NoteUNID, sizeof(UNID)); 116 | 117 | if (error = NSFDbOpen(dbName.c_str(), &db_handle)) 118 | { 119 | SetErrorMessage("error opening database"); 120 | } 121 | 122 | if (error = NSFNoteOpenByUNID( 123 | db_handle, /* database handle */ 124 | &ResponseUNID, /* note ID */ 125 | (WORD)0, /* open flags */ 126 | ¬e_handle)) /* note handle (return) */ 127 | { 128 | DataHelper::GetAPIError(error, error_text); 129 | SetErrorMessage(error_text); 130 | NSFDbClose(db_handle); 131 | } 132 | 133 | 134 | if (error = NSFItemAppend(note_handle, 135 | ITEM_SUMMARY, 136 | FIELD_LINK, /* $REF */ 137 | (WORD)strlen(FIELD_LINK), 138 | TYPE_NOTEREF_LIST, /* data type */ 139 | buf, /* populated RESPONSE */ 140 | (DWORD)(sizeof(LIST) + sizeof(UNID)))) 141 | { 142 | NSFNoteClose(note_handle); 143 | SetErrorMessage("Failed to create response document"); 144 | free(error_text); 145 | free(buf); 146 | return; 147 | } 148 | 149 | free(buf); 150 | 151 | /* Update the note */ 152 | if (error = NSFNoteUpdate(note_handle, 0)) 153 | { 154 | NSFNoteClose(note_handle); 155 | DataHelper::GetAPIError(error, error_text); 156 | SetErrorMessage(error_text); 157 | return; 158 | } 159 | 160 | error = NSFNoteClose(note_handle); 161 | 162 | NSFDbClose(db_handle); 163 | 164 | NotesTermThread(); 165 | } 166 | 167 | void HandleOKCallback() { 168 | HandleScope scope; 169 | Local resDoc = Nan::New(); 170 | Nan::Set(resDoc, New("status").ToLocalChecked(), New("made response").ToLocalChecked()); 171 | Local argv[] = { 172 | Null() 173 | , resDoc 174 | }; 175 | callback->Call(2, argv); 176 | } 177 | 178 | void HandleErrorCallback() { 179 | HandleScope scope; 180 | Local errorObj = Nan::New(); 181 | Nan::Set(errorObj, New("errorMessage").ToLocalChecked(), New(ErrorMessage()).ToLocalChecked()); 182 | Local argv[] = { 183 | errorObj, 184 | Null() 185 | }; 186 | callback->Call(2, argv); 187 | } 188 | 189 | private: 190 | std::string serverName; 191 | std::string dbName; 192 | std::string unid; 193 | std::string responseUnid; 194 | }; 195 | 196 | NAN_METHOD(MakeResponseDocumentAsync) { 197 | v8::Isolate* isolate = info.GetIsolate(); 198 | 199 | Local param = (info[0]->ToObject()); 200 | Local unidParam = (info[1]->ToString()); 201 | Local parentUnidParam = (info[2]->ToString()); 202 | Local serverKey = String::NewFromUtf8(isolate, "server"); 203 | Local databaseKey = String::NewFromUtf8(isolate, "database"); 204 | Local serverVal = param->Get(serverKey); 205 | Local databaseVal = param->Get(databaseKey); 206 | 207 | String::Utf8Value serverName(serverVal->ToString()); 208 | String::Utf8Value dbName(databaseVal->ToString()); 209 | String::Utf8Value unid(unidParam->ToString()); 210 | String::Utf8Value parentUnid(parentUnidParam->ToString()); 211 | 212 | std::string serverStr; 213 | std::string dbStr; 214 | std::string unidStr; 215 | std::string parentUnidStr; 216 | serverStr = std::string(*serverName); 217 | dbStr = std::string(*dbName); 218 | unidStr = std::string(*unid); 219 | parentUnidStr = std::string(*parentUnid); 220 | Callback *callback = new Callback(info[3].As()); 221 | 222 | AsyncQueueWorker(new MakeResponseDocumentWorker(callback, serverStr, dbStr, unidStr,parentUnidStr)); 223 | } -------------------------------------------------------------------------------- /src/makeresponse_document.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Domino addon for Node.js 3 | * 4 | * Copyright (c) 2016 Nils T. Hjelme 5 | * 6 | * The MIT License (MIT) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | *******************************************************************************/ 26 | 27 | #ifndef MAKERESPONSE_DOCUMENT_ASYNC_H_ 28 | #define MAKERESPONSE_DOCUMENT_ASYNC_H_ 29 | 30 | #include 31 | #include 32 | 33 | NAN_METHOD(MakeResponseDocumentAsync); 34 | 35 | #endif // MAKERESPONSE_DOCUMENT_ASYNC_H_ 36 | -------------------------------------------------------------------------------- /src/notes_database.cc: -------------------------------------------------------------------------------- 1 | #include "notes_database.h" 2 | #include "DataHelper.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | NAN_METHOD(openDatabase) { 16 | v8::String::Utf8Value val(info[0]->ToString()); 17 | std::string dbName (*val); 18 | STATUS error = NOERROR; /* return status from API calls */ 19 | char *error_text = (char *) malloc(sizeof(char) * 200); 20 | DBHANDLE db_handle; /* handle of source database */ 21 | 22 | if (error = NSFDbOpen(dbName.c_str(), &db_handle)) { 23 | DataHelper::GetAPIError(error,error_text); 24 | printf("error: %s", error_text); 25 | } 26 | USHORT dh = (USHORT) db_handle; 27 | Local retval = Nan::New((double) dh); 28 | info.GetReturnValue().Set(retval); 29 | } 30 | 31 | NAN_METHOD(getDatabaseName) { 32 | double value = info[0]->NumberValue(); 33 | STATUS error = NOERROR; /* return status from API calls */ 34 | char *error_text = (char *) malloc(sizeof(char) * 200); 35 | DBHANDLE db_handle; /* handle of source database */ 36 | 37 | char title[NSF_INFO_SIZE] = ""; /* database title */ 38 | unsigned short db_h = (unsigned short) value; 39 | db_handle = (DHANDLE)db_h; 40 | char buffer[NSF_INFO_SIZE] = ""; /* database info buffer */ 41 | if (error = NSFDbInfoGet (db_handle, buffer)) 42 | { 43 | NSFDbClose (db_handle); 44 | } 45 | 46 | NSFDbInfoParse (buffer, INFOPARSE_TITLE, title, NSF_INFO_SIZE - 1); 47 | 48 | info.GetReturnValue().Set( 49 | Nan::New(title).ToLocalChecked()); 50 | } 51 | 52 | NAN_METHOD(closeDatabase) { 53 | DBHANDLE db_handle; /* handle of source database */ 54 | double value = info[0]->NumberValue(); 55 | unsigned short db_h = (unsigned short) value; 56 | db_handle = (DHANDLE)db_h; 57 | NSFDbClose (db_handle); 58 | } 59 | 60 | 61 | NAN_METHOD(replicationSummary) { 62 | STATUS error = NOERROR; /* return status from API calls */ 63 | DBHANDLE db_handle; /* handle of source database */ 64 | DHANDLE hReplHist; 65 | REPLHIST_SUMMARY ReplHist; 66 | REPLHIST_SUMMARY *pReplHist; 67 | char szTimedate[MAXALPHATIMEDATE+1]; 68 | WORD wLen; 69 | DWORD dwNumEntries, i; 70 | char *pServerName; /* terminating NULL not included */ 71 | char szServerName[MAXUSERNAME + 1]; 72 | char *pFileName; /* includes terminating NULL */ 73 | char szDirection[10]; /* NEVER, SEND, RECEIVE */ 74 | Local replicaRes = New(); 75 | double value = info[0]->NumberValue(); 76 | unsigned short db_h = (unsigned short) value; 77 | db_handle = (DHANDLE)db_h; 78 | 79 | error = NSFDbGetReplHistorySummary (db_handle, 0, &hReplHist, &dwNumEntries); 80 | if (error) 81 | { 82 | printf("error getting replica history\n"); 83 | } 84 | 85 | pReplHist = OSLock (REPLHIST_SUMMARY, hReplHist); 86 | for (i = 0; i < dwNumEntries; i++) 87 | { 88 | ReplHist = pReplHist[i]; 89 | error = ConvertTIMEDATEToText (NULL, NULL, &(ReplHist.ReplicationTime), 90 | szTimedate, MAXALPHATIMEDATE, &wLen); 91 | if (error) 92 | { 93 | OSUnlock (hReplHist); 94 | OSMemFree (hReplHist); 95 | } 96 | szTimedate[wLen] = '\0'; 97 | if (ReplHist.Direction == DIRECTION_NEVER) 98 | strcpy (szDirection, "NEVER"); 99 | else if (ReplHist.Direction == DIRECTION_SEND) 100 | strcpy (szDirection, "SEND"); 101 | else if (ReplHist.Direction == DIRECTION_RECEIVE) 102 | strcpy (szDirection, "RECEIVE"); 103 | else 104 | strcpy (szDirection, ""); 105 | 106 | pServerName = NSFGetSummaryServerNamePtr (pReplHist, i); 107 | strncpy (szServerName, pServerName, ReplHist.ServerNameLength); 108 | szServerName[ReplHist.ServerNameLength] = '\0'; 109 | /* FileName will be NULL terminated */ 110 | pFileName = NSFGetSummaryFileNamePtr (pReplHist, i); 111 | 112 | Local resDoc = Nan::New(); 113 | Nan::Set(resDoc, New("date").ToLocalChecked(), New(szTimedate).ToLocalChecked()); 114 | Nan::Set(resDoc, New("database").ToLocalChecked(), New(pFileName).ToLocalChecked()); 115 | Nan::Set(resDoc, New("server").ToLocalChecked(), New(szServerName).ToLocalChecked()); 116 | Nan::Set(resDoc, New("direction").ToLocalChecked(), New(szDirection).ToLocalChecked()); 117 | Nan::Set(replicaRes, i, resDoc); 118 | } 119 | OSUnlock (hReplHist); 120 | OSMemFree (hReplHist); 121 | info.GetReturnValue().Set(replicaRes); 122 | } -------------------------------------------------------------------------------- /src/notes_database.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Domino addon for Node.js 3 | * 4 | * Copyright (c) 2018 Nils T. Hjelme 5 | * 6 | * The MIT License (MIT) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | *******************************************************************************/ 26 | 27 | #ifndef NOTES_DATABASE_H_ 28 | #define NOTES_DATABASE_H_ 29 | #include 30 | #include "global.h" 31 | 32 | NAN_METHOD(openDatabase); 33 | NAN_METHOD(getDatabaseName); 34 | NAN_METHOD(closeDatabase); 35 | NAN_METHOD(replicationSummary); 36 | 37 | 38 | #endif // NOTES_DATABASE_H_ -------------------------------------------------------------------------------- /src/notes_document.cc: -------------------------------------------------------------------------------- 1 | #include "notes_document.h" 2 | #include "DataHelper.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #define BUFSIZE 185536 22 | 23 | char * fileContent; // global to keep mime fileContent. 24 | std::vector strVec; 25 | 26 | NAN_METHOD(closeNote) { 27 | //v8::Isolate* isolate = info.GetIsolate(); 28 | NOTEHANDLE note_handle; 29 | double value = info[0]->NumberValue(); 30 | unsigned short n_h = (unsigned short) value; 31 | note_handle = (NOTEHANDLE)n_h; 32 | NSFNoteClose(note_handle); 33 | } 34 | 35 | NAN_METHOD(getNoteById) { 36 | double value = info[0]->NumberValue(); 37 | double note_val(info[1]->NumberValue()); 38 | NOTEHANDLE note_handle; 39 | STATUS error = NOERROR; /* return status from API calls */ 40 | char *error_text = (char *) malloc(sizeof(char) * 200); 41 | DBHANDLE db_handle; /* handle of source database */ 42 | DWORD noteid = (DWORD) note_val; 43 | 44 | unsigned short db_h = (unsigned short) value; 45 | db_handle = (DHANDLE)db_h; 46 | if (error = NSFNoteOpenExt(db_handle, noteid, 47 | OPEN_RAW_MIME_PART, ¬e_handle)) { 48 | printf("error opening notebyid \n"); 49 | DataHelper::GetAPIError(error,error_text); 50 | //SetErrorMessage(error_text); 51 | printf("get note by id, error %s\n",error_text); 52 | 53 | } 54 | USHORT nh = (USHORT) note_handle; 55 | Local retval = Nan::New((double) nh); 56 | info.GetReturnValue().Set(retval); 57 | } 58 | 59 | NAN_METHOD(getNotesNote) { 60 | double value = info[0]->NumberValue(); 61 | v8::String::Utf8Value val(info[1]->ToString()); 62 | std::string unidStr (*val); 63 | NOTEHANDLE note_handle; 64 | STATUS error = NOERROR; /* return status from API calls */ 65 | char *error_text = (char *) malloc(sizeof(char) * 200); 66 | DBHANDLE db_handle; /* handle of source database */ 67 | UNID temp_unid; 68 | NOTEID tempID; 69 | char title[NSF_INFO_SIZE] = ""; /* database title */ 70 | unsigned short db_h = (unsigned short) value; 71 | db_handle = (DHANDLE)db_h; 72 | 73 | DataHelper::ToUNID(unidStr.c_str(), &temp_unid); 74 | 75 | if (error = NSFNoteOpenByUNID( 76 | db_handle, /* database handle */ 77 | &temp_unid, /* note ID */ 78 | (WORD)0, /* open flags */ 79 | ¬e_handle)) /* note handle (return) */ 80 | { 81 | DataHelper::GetAPIError(error,error_text); 82 | //SetErrorMessage(error_text); 83 | printf("get note by unid, error %s\n",error_text); 84 | NSFDbClose(db_handle); 85 | free(error_text); 86 | return; 87 | } 88 | 89 | // repoen note by by note id 90 | NSFNoteGetInfo(note_handle, _NOTE_ID, &tempID); 91 | NSFNoteClose(note_handle); 92 | if (error = NSFNoteOpenExt(db_handle, tempID, 93 | OPEN_RAW_MIME_PART, ¬e_handle)) { 94 | printf("error opening notebyid \n"); 95 | DataHelper::GetAPIError(error,error_text); 96 | //SetErrorMessage(error_text); 97 | printf("get note by id, error %s\n",error_text); 98 | 99 | } 100 | USHORT nh = (USHORT) note_handle; 101 | 102 | Local retval = Nan::New((double) nh); 103 | info.GetReturnValue().Set(retval); 104 | 105 | 106 | } 107 | 108 | NAN_METHOD(createNotesNote) { 109 | double value = info[0]->NumberValue(); 110 | NOTEHANDLE note_handle; 111 | STATUS error = NOERROR; /* return status from API calls */ 112 | char *error_text = (char *) malloc(sizeof(char) * 200); 113 | DBHANDLE db_handle; /* handle of source database */ 114 | unsigned short db_h = (unsigned short) value; 115 | db_handle = (DHANDLE)db_h; 116 | 117 | if (error = NSFNoteCreate(db_handle, ¬e_handle)) { 118 | printf("error creating document\n"); 119 | } 120 | USHORT nh = (USHORT) note_handle; 121 | Local retval = Nan::New((double) nh); 122 | info.GetReturnValue().Set(retval); 123 | } 124 | 125 | NAN_METHOD(updateNote) { 126 | double value = info[0]->NumberValue(); 127 | NOTEHANDLE note_handle; 128 | STATUS error = NOERROR; 129 | 130 | unsigned short n_h = (unsigned short) value; 131 | note_handle = (NOTEHANDLE)n_h; 132 | 133 | if (error = NSFNoteUpdate(note_handle, 0)) { 134 | printf("error updating note\n"); 135 | } 136 | } 137 | 138 | NAN_METHOD(getNoteUNID) { 139 | double value = info[0]->NumberValue(); 140 | NOTEHANDLE note_handle; 141 | STATUS error = NOERROR; /* return status from API calls */ 142 | OID tempOID; 143 | 144 | unsigned short n_h = (unsigned short) value; 145 | note_handle = (NOTEHANDLE)n_h; 146 | NSFNoteGetInfo(note_handle, _NOTE_OID, &tempOID); 147 | char unid_buffer[33]; 148 | snprintf(unid_buffer, 33, "%08X%08X%08X%08X", tempOID.File.Innards[1], tempOID.File.Innards[0], tempOID.Note.Innards[1], tempOID.Note.Innards[0]); 149 | info.GetReturnValue().Set( Nan::New(unid_buffer).ToLocalChecked()); 150 | } 151 | 152 | NAN_METHOD(getNoteID) { 153 | double value = info[0]->NumberValue(); 154 | NOTEHANDLE note_handle; 155 | 156 | DWORD tempID; 157 | STATUS error = NOERROR; /* return status from API calls */ 158 | 159 | unsigned short n_h = (unsigned short) value; 160 | note_handle = (NOTEHANDLE)n_h; 161 | 162 | NSFNoteGetInfo(note_handle, _NOTE_ID, &tempID); 163 | Local retval = Nan::New((double) tempID); 164 | info.GetReturnValue().Set(retval); 165 | 166 | } 167 | 168 | 169 | NAN_METHOD(setItemText) { 170 | double note_handle = info[0]->NumberValue(); 171 | v8::String::Utf8Value itemName(info[1]->ToString()); 172 | v8::String::Utf8Value val(info[2]->ToString()); 173 | 174 | std::string itemStr (*itemName); 175 | std::string itemValue (*val); 176 | nsfItemSetText((unsigned short) note_handle,itemStr.c_str(),itemValue.c_str()); 177 | 178 | } 179 | 180 | void nsfItemSetText(unsigned short nHandle, const char * itemName, const char * itemValue) { 181 | NOTEHANDLE note_handle; 182 | STATUS error = NOERROR; /* return status from API calls */ 183 | char *error_text = (char *) malloc(sizeof(char) * 200); 184 | char buf[MAXWORD]; 185 | note_handle = (NOTEHANDLE)nHandle; 186 | OSTranslate(OS_TRANSLATE_UTF8_TO_LMBCS, itemValue, MAXWORD, buf, MAXWORD); 187 | if (error = NSFItemSetText(note_handle, itemName,buf,MAXWORD)) { 188 | DataHelper::GetAPIError(error, error_text); 189 | printf("Error writing text item%s\n",error_text); 190 | free(error_text); 191 | } 192 | } 193 | 194 | std::map nsfItemGetMime(unsigned short nHandle, const char *itemName) { 195 | STATUS error = NOERROR; /* return status from API calls */ 196 | char *error_text = (char *) malloc(sizeof(char) * 200); 197 | char buf[MAXWORD]; 198 | BLOCKID bidLinksItem; 199 | DWORD dwLinksValueLen; 200 | BLOCKID bidLinksValue; 201 | WORD item_type; 202 | BOOL bMimeDataInFile; 203 | char pchFileName[512]; 204 | NOTEHANDLE note_handle; 205 | note_handle = (NOTEHANDLE)nHandle; 206 | std::map mimeItem; 207 | 208 | if (error = NSFItemInfo(note_handle, itemName, 209 | strlen(itemName), &bidLinksItem, 210 | &item_type, &bidLinksValue, 211 | &dwLinksValueLen)) { 212 | DataHelper::GetAPIError(error, error_text); 213 | printf("Error getting item info: %s\n",error_text); 214 | return mimeItem; 215 | } 216 | 217 | bMimeDataInFile = NSFIsMimePartInFile(note_handle, bidLinksItem, pchFileName,(WORD)512); 218 | 219 | if (bMimeDataInFile) { 220 | BLOCKID bkItem; 221 | WORD field_type; 222 | BLOCKID field_block; 223 | DWORD field_length; 224 | 225 | NSFItemInfo ( 226 | note_handle, /* note handle */ 227 | "$FILE", /* field we want */ 228 | (WORD)strlen("$FILE"), /* length of above */ 229 | &bkItem, /* full field (return) */ 230 | &field_type, /* field type (return) */ 231 | &field_block, /* field contents (return) */ 232 | &field_length); /* field length (return) */ 233 | error = NSFNoteExtractWithCallback(note_handle, bkItem, NULL, 0,ExtractwithCallback, (void*)0); 234 | std::string ret; 235 | for(const auto &s : strVec) { 236 | ret += s; 237 | } 238 | 239 | mimeItem.insert(std::make_pair("value",ret)); 240 | 241 | } else { 242 | char *pMime; 243 | WORD wPartType; 244 | DWORD dwFlags; 245 | WORD wReserved; 246 | WORD wPartOffset; 247 | WORD wPartLen; 248 | WORD wBoundaryOffset; 249 | WORD wBoundaryLen; 250 | WORD wHeadersOffset; 251 | WORD wHeadersLen; 252 | WORD wBodyOffset; 253 | WORD wBodyLen; 254 | 255 | DHANDLE hPart; 256 | if (error = NSFMimePartGetPart(bidLinksItem, &hPart)) { 257 | printf("error getting mime part\n"); 258 | } 259 | 260 | if (error = NSFMimePartGetInfoByBLOCKID(bidLinksItem, 261 | &wPartType, 262 | &dwFlags, 263 | &wReserved, 264 | &wPartOffset, 265 | &wPartLen, 266 | &wBoundaryOffset, 267 | &wBoundaryLen, 268 | &wHeadersOffset, 269 | &wHeadersLen, 270 | &wBodyOffset, 271 | &wBodyLen)) { 272 | printf("errr getting mimepartinfobyblockid\n"); 273 | return mimeItem; 274 | } 275 | 276 | pMime = OSLock(char, hPart); 277 | char *pText; 278 | char *header = (char *)malloc(wHeadersLen); 279 | memcpy(header,pMime,wHeadersLen); 280 | header[wHeadersLen-4] = '\0'; // remove last 4 char from header, do not know why, but it works. 281 | std::string headerValue = std::string(header); 282 | free(header); 283 | pText = (char *)pMime + wBoundaryLen+wHeadersLen; 284 | char *fieldText = (char *)malloc(wBodyLen); 285 | memcpy(fieldText, pText, wBodyLen); 286 | fieldText[wBodyLen] = '\0'; 287 | OSUnlock(hPart); 288 | free(hPart); 289 | std::string bodyValue = std::string(fieldText); 290 | free(fieldText); 291 | mimeItem.insert(std::make_pair("value",bodyValue)); 292 | mimeItem.insert(std::make_pair("header",headerValue)); 293 | } 294 | return mimeItem; 295 | } 296 | 297 | void nsfItemSetMime(unsigned short nHandle, const char * itemName, const char * itemValue, const char *headers) { 298 | STATUS error; 299 | 300 | WORD PARTLEN = ((strlen(headers)-1)+(strlen(itemValue)-1)); 301 | char *achPart = (char *)malloc(PARTLEN+1); 302 | NOTEHANDLE note_handle; 303 | note_handle = (NOTEHANDLE)nHandle; 304 | char *item_name = (char *)malloc(strlen(itemName)); 305 | strcpy(item_name,itemName); 306 | strcpy(achPart, headers); 307 | strcat(achPart, itemValue); 308 | error = NSFMimePartAppend(note_handle, 309 | item_name, 310 | strlen(item_name), 311 | MIME_PART_BODY, 312 | MIME_PART_HAS_HEADERS, 313 | achPart, 314 | PARTLEN); 315 | if (error) { 316 | char *error_text = (char *) malloc(sizeof(char) * 200); 317 | DataHelper::GetAPIError(error, error_text); 318 | printf("Error writeing mime item. %s\n",error_text); 319 | free(error_text); 320 | } 321 | free(item_name); 322 | free(achPart); 323 | 324 | } 325 | 326 | 327 | NAN_METHOD(getItemValue) { 328 | double value = info[0]->NumberValue(); 329 | v8::String::Utf8Value val(info[1]->ToString()); 330 | std::string itemName (*val); 331 | NOTEHANDLE note_handle; 332 | STATUS error = NOERROR; /* return status from API calls */ 333 | char *error_text = (char *) malloc(sizeof(char) * 200); 334 | char buf[MAXWORD]; 335 | BLOCKID bidLinksItem; 336 | DWORD dwLinksValueLen; 337 | BLOCKID bidLinksValue; 338 | WORD item_type; 339 | BOOL bMimeDataInFile; 340 | char pchFileName[512]; 341 | unsigned short n_h = (unsigned short) value; 342 | note_handle = (NOTEHANDLE)n_h; 343 | 344 | if (error = NSFItemInfo(note_handle, itemName.c_str(), 345 | strlen(itemName.c_str()), &bidLinksItem, 346 | &item_type, &bidLinksValue, 347 | &dwLinksValueLen)) { 348 | DataHelper::GetAPIError(error, error_text); 349 | printf("Error getting item info: %s\n",error_text); 350 | return; 351 | } 352 | 353 | 354 | 355 | if (item_type == TYPE_TEXT) { 356 | char buf[MAXWORD]; 357 | nsfGetItemText(n_h,itemName.c_str(),buf); 358 | info.GetReturnValue().Set( 359 | Nan::New(buf).ToLocalChecked()); 360 | 361 | } else if (item_type == TYPE_NUMBER) { 362 | double numberValue = nsfItemGetNumber(n_h, itemName.c_str()); 363 | Local retval = Nan::New(numberValue); 364 | info.GetReturnValue().Set(retval); 365 | } else if (item_type == TYPE_TEXT_LIST) { 366 | WORD field_len; 367 | char field_text[MAXWORD]; 368 | WORD num_entries = NSFItemGetTextListEntries(note_handle,itemName.c_str()); 369 | std::vector vectorStrValue = std::vector(0); 370 | Local arr = New(); 371 | for (size_t j = 0; j < num_entries; j++) { 372 | field_len = NSFItemGetTextListEntry(note_handle,itemName.c_str(), j, field_text, (WORD)(sizeof(field_text) - 1)); 373 | char *buf = (char*)malloc(field_len + 1); 374 | OSTranslate(OS_TRANSLATE_LMBCS_TO_UTF8, field_text, MAXWORD, buf, MAXWORD); 375 | Nan::Set(arr, j, Nan::New(buf).ToLocalChecked()); 376 | } 377 | info.GetReturnValue().Set(arr); 378 | 379 | } else if (item_type == TYPE_TIME) { 380 | double dateTimeValue = nsfGetItemDate(n_h,itemName.c_str()); 381 | Local retval = New(dateTimeValue).ToLocalChecked(); 382 | info.GetReturnValue().Set(retval); 383 | } else if (item_type== TYPE_MIME_PART) { 384 | std::map mime = nsfItemGetMime(n_h, itemName.c_str()); 385 | std::map::iterator it; 386 | it = mime.find("value"); 387 | if (it != mime.end()) 388 | { 389 | info.GetReturnValue().Set( 390 | Nan::New(it->second).ToLocalChecked()); 391 | } 392 | 393 | 394 | } 395 | } 396 | 397 | STATUS LNCALLBACK ExtractwithCallback(const BYTE* byte, DWORD length, void far* pParam) 398 | { 399 | char *localstr = (char*)byte; 400 | 401 | if (localstr != NULL) { 402 | char *mimeContentPart = (char*)malloc(length + 1); 403 | strncpy(mimeContentPart, localstr, length); 404 | mimeContentPart[length] = '\0'; 405 | strVec.push_back(mimeContentPart); 406 | } 407 | 408 | return NOERROR; 409 | } 410 | 411 | NAN_METHOD(getItemText) { 412 | double note_handle = info[0]->NumberValue(); 413 | v8::String::Utf8Value val(info[1]->ToString()); 414 | std::string itemStr (*val); 415 | 416 | char buf[MAXWORD]; 417 | 418 | nsfGetItemText((unsigned short) note_handle,itemStr.c_str(),buf); 419 | info.GetReturnValue().Set( 420 | Nan::New(buf).ToLocalChecked()); 421 | } 422 | 423 | NAN_METHOD(hasItem) { 424 | double note_handle = info[0]->NumberValue(); 425 | v8::String::Utf8Value val(info[1]->ToString()); 426 | std::string itemName (*val); 427 | 428 | v8::Local isPresent = Nan::False(); 429 | if (hasItem((unsigned short)note_handle,itemName.c_str())) { 430 | isPresent = Nan::True(); 431 | } 432 | info.GetReturnValue().Set(isPresent); 433 | } 434 | 435 | NAN_METHOD(deleteItem) { 436 | 437 | double note_handle = info[0]->NumberValue(); 438 | v8::String::Utf8Value val(info[1]->ToString()); 439 | std::string itemName (*val); 440 | STATUS error = NOERROR; 441 | char *error_text = (char *) malloc(sizeof(char) * 200); 442 | v8::Local deleted = Nan::True(); 443 | if (error = nsfDeleteItem((unsigned short)note_handle,itemName.c_str())) { 444 | deleted = Nan::False(); 445 | DataHelper::GetAPIError(error, error_text); 446 | printf("Error deleting item: %s\n",error_text); 447 | free(error_text); 448 | } 449 | info.GetReturnValue().Set(deleted); 450 | } 451 | 452 | NAN_METHOD(setItemDate) { 453 | double dNote_handle = info[0]->NumberValue(); 454 | v8::String::Utf8Value val(info[1]->ToString()); 455 | double unix_time; 456 | Local dateValue =info[2]; 457 | if (dateValue->IsDate()) { 458 | unix_time = v8::Date::Cast(*dateValue)->NumberValue(); 459 | } 460 | unsigned short usNHandle = (unsigned short) dNote_handle; 461 | 462 | std::string itemName (*val); 463 | nsfSetItemDate(usNHandle,itemName.c_str(),unix_time); 464 | } 465 | 466 | void nsfSetItemDate(unsigned short usNHandle, const char * itemName, double unix_time) { 467 | NOTEHANDLE note_handle; 468 | STATUS error = NOERROR; 469 | char *error_text = (char *) malloc(sizeof(char) * 200); 470 | TIME tid; 471 | note_handle = (NOTEHANDLE)usNHandle; 472 | std::time_t t = static_cast(unix_time / 1000); 473 | struct tm* ltime = localtime(&t); 474 | tid.year = ltime->tm_year + 1900; 475 | tid.month = ltime->tm_mon + 1; 476 | tid.day = ltime->tm_mday; 477 | tid.hour = ltime->tm_hour; 478 | tid.minute = ltime->tm_min + 1; 479 | tid.second = ltime->tm_sec-1; 480 | tid.zone = 0; 481 | tid.dst = 0; 482 | tid.hundredth = 0; 483 | 484 | if (error = TimeLocalToGM(&tid)) { 485 | DataHelper::GetAPIError(error, error_text); 486 | printf("Error converting Time Local to GM, %s\n",error_text); 487 | } 488 | 489 | if (error = NSFItemSetTime(note_handle, itemName, &tid.GM)) { 490 | DataHelper::GetAPIError(error, error_text); 491 | printf("Error setting time on item, %s",error_text); 492 | } 493 | } 494 | NAN_METHOD(setMimeItem) { 495 | double note_handle = info[0]->NumberValue(); 496 | v8::String::Utf8Value itemName(info[1]->ToString()); 497 | v8::String::Utf8Value val(info[2]->ToString()); 498 | v8::String::Utf8Value header(info[3]->ToString()); 499 | 500 | std::string itemStr (*itemName); 501 | std::string itemValue (*val); 502 | std::string headerValue (*header); 503 | headerValue.append("\015\012\015\012"); 504 | itemValue.append("\015\012"); 505 | 506 | nsfItemSetMime((unsigned short) note_handle,itemStr.c_str(),itemValue.c_str(),headerValue.c_str()); 507 | } 508 | 509 | NAN_METHOD(getMimeItem) { 510 | NOTEHANDLE note_handle; 511 | STATUS error = NOERROR; /* return status from API calls */ 512 | char *error_text = (char *) malloc(sizeof(char) * 200); 513 | double n_h = info[0]->NumberValue(); 514 | v8::String::Utf8Value val(info[1]->ToString()); 515 | std::string itemName (*val); 516 | unsigned short nHandle = (unsigned short) n_h; 517 | //note_handle = (NOTEHANDLE)nHandle; 518 | if (hasItem(nHandle,itemName.c_str())) { 519 | std::map mime = nsfItemGetMime(nHandle, itemName.c_str()); 520 | std::map::iterator it; 521 | Local mimeItem = Nan::New(); 522 | it = mime.find("value"); 523 | if (it != mime.end()) 524 | { 525 | Nan::Set(mimeItem, New("value").ToLocalChecked(),Nan::New(it->second).ToLocalChecked()); 526 | } 527 | it = mime.find("header"); 528 | if (it != mime.end()) { 529 | Nan::Set(mimeItem, New("header").ToLocalChecked(),Nan::New(it->second).ToLocalChecked()); 530 | } 531 | info.GetReturnValue().Set(mimeItem); 532 | } else { 533 | printf("can't find mime item by name: %s\n ", itemName.c_str()); 534 | info.GetReturnValue().Set( 535 | Nan::New("").ToLocalChecked()); 536 | } 537 | 538 | } 539 | 540 | NAN_METHOD(appendItemTextList) { 541 | double n_h = info[0]->NumberValue(); 542 | v8::String::Utf8Value val(info[1]->ToString()); 543 | v8::String::Utf8Value iValue(info[2]->ToString()); 544 | 545 | std::string itemValue (*iValue); 546 | std::string itemName (*val); 547 | 548 | nsfItemAppendTextList((unsigned short) n_h,itemName.c_str(),itemValue.c_str()); 549 | } 550 | 551 | NAN_METHOD(setAuthor) { 552 | NOTEHANDLE note_handle; 553 | STATUS error = NOERROR; /* return status from API calls */ 554 | char *error_text = (char *) malloc(sizeof(char) * 200); 555 | double n_h = info[0]->NumberValue(); 556 | v8::String::Utf8Value val(info[1]->ToString()); 557 | v8::String::Utf8Value iValue(info[2]->ToString()); 558 | 559 | std::string itemValue (*iValue); 560 | std::string itemName (*val); 561 | 562 | unsigned short nHandle = (unsigned short) n_h; 563 | note_handle = (NOTEHANDLE)nHandle; 564 | if (error = NSFItemAppend(note_handle,ITEM_SUMMARY | ITEM_READWRITERS | ITEM_NAMES, 565 | itemName.c_str(), strlen(itemName.c_str()), 566 | TYPE_TEXT, itemValue.c_str(), 567 | (DWORD) strlen(itemValue.c_str()))) 568 | { 569 | DataHelper::GetAPIError(error, error_text); 570 | printf("Error settin author on item: %s\n",error_text); 571 | } 572 | 573 | } 574 | 575 | BOOL hasItem(unsigned short nHandle,const char * itemName) { 576 | NOTEHANDLE note_handle; 577 | BOOL field_found; 578 | note_handle = (NOTEHANDLE)nHandle; 579 | field_found = NSFItemIsPresent (note_handle, itemName, (WORD) strlen (itemName)); 580 | return field_found; 581 | } 582 | 583 | STATUS nsfDeleteItem(unsigned short nHandle,const char * itemName) { 584 | NOTEHANDLE note_handle; 585 | STATUS error = NOERROR; 586 | note_handle = (NOTEHANDLE)nHandle; 587 | error = NSFItemDelete (note_handle, itemName, (WORD) strlen (itemName)); 588 | return error; 589 | } 590 | 591 | double nsfItemGetNumber(unsigned short nHandle, const char * itemName) { 592 | NOTEHANDLE note_handle; 593 | NUMBER number_field; 594 | BOOL success; 595 | note_handle = (NOTEHANDLE)nHandle; 596 | 597 | success = NSFItemGetNumber (note_handle, itemName, &number_field); 598 | if (!success) { 599 | printf("Error getItemNumber for item %s\n",itemName); 600 | } 601 | return (double) number_field; 602 | } 603 | 604 | void nsfGetItemText(unsigned short nHandle, const char * itemName,char *value) { 605 | NOTEHANDLE note_handle; 606 | char field_text[MAXWORD]; 607 | WORD field_len; 608 | BOOL field_found; 609 | 610 | note_handle = (NOTEHANDLE)nHandle; 611 | 612 | field_len = NSFItemGetText ( 613 | note_handle, 614 | itemName, 615 | field_text, 616 | (WORD) sizeof (field_text)); 617 | 618 | OSTranslate(OS_TRANSLATE_LMBCS_TO_UTF8, field_text, MAXWORD, value, MAXWORD); 619 | } 620 | 621 | NAN_METHOD(setItemNumber) { 622 | double handle_value = info[0]->NumberValue(); 623 | double value = info[2]->NumberValue(); 624 | v8::String::Utf8Value val(info[1]->ToString()); 625 | std::string itemStr (*val); 626 | nsfItemSetNumber(handle_value,itemStr.c_str(),&value); 627 | } 628 | 629 | NAN_METHOD(setItemValue) { 630 | double note_handle = info[0]->NumberValue(); 631 | v8::String::Utf8Value val(info[1]->ToString()); 632 | std::string itemName (*val); 633 | Local value = info[2]; 634 | if (value->IsString()) { 635 | String::Utf8Value itemVal(value->ToString()); 636 | std::string itemValue = std::string(*itemVal); 637 | nsfItemSetText(note_handle,itemName.c_str(),itemValue.c_str()); 638 | 639 | } else if (value->IsArray()) { 640 | Local arrVal = Local::Cast(value); 641 | unsigned int num_locations = arrVal->Length(); 642 | if (num_locations > 0) { 643 | for (unsigned int i = 0; i < num_locations; i++) { 644 | Local obj = Local::Cast(arrVal->Get(i)); 645 | String::Utf8Value value(obj->ToString()); 646 | std::string s_val = std::string(*value); 647 | if (i==0) { 648 | nsfItemCreateTextList(note_handle,itemName.c_str(),s_val.c_str()); 649 | } else { 650 | nsfItemAppendTextList(note_handle,itemName.c_str(),s_val.c_str()); 651 | } 652 | } 653 | } 654 | 655 | } else if (value->IsNumber()) { 656 | double itemValue = value->NumberValue(); 657 | nsfItemSetNumber(note_handle,itemName.c_str(), &itemValue); 658 | 659 | } else if (value->IsDate()) { 660 | double unix_time = v8::Date::Cast(*value)->NumberValue(); 661 | nsfSetItemDate(note_handle,itemName.c_str(),unix_time); 662 | } 663 | 664 | } 665 | 666 | 667 | void nsfItemSetNumber(unsigned short nHandle, const char * itemName, const double * itemValue) { 668 | NOTEHANDLE note_handle; 669 | NUMBER number_field; 670 | STATUS error = NOERROR; /* return status from API calls */ 671 | char *error_text = (char *) malloc(sizeof(char) * 200); 672 | char buf[MAXWORD]; 673 | note_handle = (NOTEHANDLE)nHandle; 674 | 675 | if (error = NSFItemSetNumber(note_handle, itemName, itemValue)) { 676 | DataHelper::GetAPIError(error, error_text); 677 | printf("Error setItemNumber%s\n",error_text); 678 | } 679 | } 680 | 681 | void nsfItemCreateTextList(unsigned short nHandle, const char * itemName, const char * itemValue) { 682 | NOTEHANDLE note_handle; 683 | STATUS error = NOERROR; /* return status from API calls */ 684 | char *error_text = (char *) malloc(sizeof(char) * 200); 685 | char buf[MAXWORD]; 686 | note_handle = (NOTEHANDLE)nHandle; 687 | OSTranslate(OS_TRANSLATE_UTF8_TO_LMBCS, itemValue, MAXWORD, buf, MAXWORD); 688 | 689 | if (error = NSFItemCreateTextList(note_handle, itemName,buf,strlen(itemValue))) { 690 | DataHelper::GetAPIError(error, error_text); 691 | printf("Error nsfItemCreateTextList%s\n",error_text); 692 | } 693 | 694 | } 695 | void nsfItemAppendTextList(unsigned short nHandle, const char * itemName, const char * itemValue) { 696 | NOTEHANDLE note_handle; 697 | STATUS error = NOERROR; /* return status from API calls */ 698 | char *error_text = (char *) malloc(sizeof(char) * 200); 699 | char buf[MAXWORD]; 700 | note_handle = (NOTEHANDLE)nHandle; 701 | OSTranslate(OS_TRANSLATE_UTF8_TO_LMBCS, itemValue, MAXWORD, buf, MAXWORD); 702 | if (error = NSFItemAppendTextList(note_handle, itemName,buf,strlen(itemValue),TRUE)) { 703 | DataHelper::GetAPIError(error, error_text); 704 | printf("Error nsfItemCreateTextList%s\n",error_text); 705 | } 706 | } 707 | 708 | NAN_METHOD(getItemNumber) { 709 | double note_handle = info[0]->NumberValue(); 710 | v8::String::Utf8Value val(info[1]->ToString()); 711 | std::string itemName (*val); 712 | 713 | double numberValue = nsfItemGetNumber(note_handle, itemName.c_str()); 714 | Local retval = Nan::New(numberValue); 715 | info.GetReturnValue().Set(retval); 716 | } 717 | 718 | NAN_METHOD(getItemDate) { 719 | double value = info[0]->NumberValue(); 720 | v8::String::Utf8Value val(info[1]->ToString()); 721 | std::string itemStr (*val); 722 | NUMBER number_field; 723 | double dateTimeValue = 0.0; 724 | STATUS error = NOERROR; /* return status from API calls */ 725 | char *error_text = (char *) malloc(sizeof(char) * 200); 726 | char buf[MAXWORD]; 727 | 728 | unsigned short n_h = (unsigned short) value; 729 | dateTimeValue = nsfGetItemDate(n_h,itemStr.c_str()); 730 | Local retval = New(dateTimeValue).ToLocalChecked(); 731 | info.GetReturnValue().Set(retval); 732 | } 733 | 734 | double nsfGetItemDate(unsigned short n_h, const char * itemName) { 735 | 736 | char field_text[MAXWORD]; 737 | WORD field_len; 738 | BOOL field_found; 739 | NOTEHANDLE note_handle; 740 | double dateTimeValue = 0.0; 741 | STATUS error = NOERROR; /* return status from API calls */ 742 | char *error_text = (char *) malloc(sizeof(char) * 200); 743 | 744 | note_handle = (NOTEHANDLE)n_h; 745 | 746 | field_found = NSFItemIsPresent ( 747 | note_handle, 748 | itemName, 749 | (WORD) strlen (itemName)); 750 | 751 | 752 | if (field_found) { 753 | TIMEDATE time_date; 754 | if (NSFItemGetTime(note_handle, 755 | itemName, 756 | &time_date)) { 757 | TIME tid; 758 | struct tm * timeinfo; 759 | 760 | tid.GM = time_date; 761 | tid.zone = 0; 762 | tid.dst = 0; 763 | TimeGMToLocalZone(&tid); 764 | 765 | time_t rawtime = time(0); 766 | timeinfo = localtime(&rawtime); 767 | timeinfo->tm_year = tid.year - 1900; 768 | timeinfo->tm_mon = tid.month-1; 769 | timeinfo->tm_mday = tid.day; 770 | 771 | timeinfo->tm_hour = tid.hour; 772 | timeinfo->tm_min = tid.minute-1; 773 | timeinfo->tm_sec = tid.second; 774 | 775 | double dtime = static_cast(mktime(timeinfo))+1; 776 | 777 | dateTimeValue = dtime * 1000; // convert to double time 778 | } 779 | } 780 | return dateTimeValue; 781 | } -------------------------------------------------------------------------------- /src/notes_document.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Domino addon for Node.js 3 | * 4 | * Copyright (c) 2016 Nils T. Hjelme 5 | * 6 | * The MIT License (MIT) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | *******************************************************************************/ 26 | 27 | #ifndef NOTES_DOCUMENT_H_ 28 | #define NOTES_DOCUMENT_H_ 29 | 30 | #include 31 | #include "global.h" 32 | #include 33 | 34 | NAN_METHOD(closeNote); 35 | NAN_METHOD(getNotesNote); 36 | NAN_METHOD(getNoteById); 37 | NAN_METHOD(createNotesNote); 38 | NAN_METHOD(updateNote); 39 | NAN_METHOD(getNoteUNID); 40 | NAN_METHOD(setItemText); 41 | NAN_METHOD(getItemText); 42 | NAN_METHOD(setItemNumber); 43 | NAN_METHOD(getItemNumber); 44 | NAN_METHOD(getItemDate); 45 | NAN_METHOD(setItemValue); 46 | NAN_METHOD(getItemValue); 47 | NAN_METHOD(hasItem); 48 | NAN_METHOD(setAuthor); 49 | NAN_METHOD(appendItemTextList); 50 | NAN_METHOD(getMimeItem); 51 | NAN_METHOD(setMimeItem); 52 | NAN_METHOD(deleteItem); 53 | NAN_METHOD(setItemDate); 54 | NAN_METHOD(getNoteID); 55 | 56 | //void nsfNoteId(unsigned short nHandle, NOTEID * noteId); 57 | STATUS LNCALLBACK ExtractwithCallback(const BYTE* byte, DWORD length, void far* pParam); 58 | void nsfItemSetText(unsigned short nHandle, const char * itemName, const char * itemValue); 59 | void nsfItemSetMime(unsigned short nHandle, const char * itemName, const char * itemValue, const char *headers); 60 | std::map nsfItemGetMime(unsigned short nHandle, const char *itemName); 61 | void nsfGetItemText(unsigned short nHandle, const char * itemName,char *value); 62 | void nsfItemSetNumber(unsigned short nHandle, const char * itemName, const double * itemValue); 63 | void nsfSetItemDate(unsigned short usNHandle, const char * itemName, double unix_time); 64 | double nsfGetItemDate(unsigned short n_h, const char * itemName); 65 | double nsfItemGetNumber(unsigned short nHandle, const char * itemName); 66 | void nsfItemCreateTextList(unsigned short nHandle, const char * itemName, const char * itemValue); 67 | void nsfItemAppendTextList(unsigned short nHandle, const char * itemName, const char * itemValue); 68 | BOOL hasItem(unsigned short nHandle,const char * itemName); 69 | STATUS nsfDeleteItem(unsigned short nHandle,const char * itemName); 70 | 71 | 72 | 73 | #endif // NOTES_DOCUMENT_H_ -------------------------------------------------------------------------------- /src/nsf_search.cc: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Domino addon for Node.js 3 | * 4 | * Copyright (c) 2016 Nils T. Hjelme 5 | * 6 | * The MIT License (MIT) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | *******************************************************************************/ 26 | 27 | #include 28 | #include "DocumentItem.h" 29 | #include "DataHelper.h" 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include "nsf_search.h" 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | using v8::Function; 44 | using v8::Local; 45 | using v8::Number; 46 | using v8::Value; 47 | using v8::String; 48 | using v8::Object; 49 | using v8::Array; 50 | using Nan::AsyncQueueWorker; 51 | using Nan::AsyncWorker; 52 | using Nan::Callback; 53 | using Nan::HandleScope; 54 | using Nan::New; 55 | using Nan::Null; 56 | using Nan::To; 57 | 58 | NOTEHANDLE note_handle_srch; 59 | std::vector items2; 60 | std::vector> view2; 61 | 62 | STATUS LNPUBLIC print_fields 63 | (void far *db_handle, 64 | SEARCH_MATCH far *pSearchMatch, 65 | ITEM_TABLE far *summary_info) 66 | { 67 | SEARCH_MATCH SearchMatch; 68 | 69 | OID tempOID; 70 | STATUS error; 71 | std::vector curr_match; 72 | items2 = curr_match; 73 | 74 | memcpy( (char*)&SearchMatch, (char*)pSearchMatch, sizeof(SEARCH_MATCH) ); 75 | 76 | /* Skip this note if it does not really match the search criteria (it is 77 | now deleted or modified). This is not necessary for full searches, 78 | but is shown here in case a starting date was used in the search. */ 79 | 80 | if (!(SearchMatch.SERetFlags & SE_FMATCH)) 81 | return (NOERROR); 82 | 83 | /* Open the note. */ 84 | 85 | if (error = NSFNoteOpen (*(DBHANDLE far *)db_handle,SearchMatch.ID.NoteID,0, ¬e_handle_srch)) { 86 | return (ERR(error)); 87 | } 88 | 89 | if (error = NSFItemScan( 90 | note_handle_srch, /* note handle */ 91 | field_actions2, /* action routine for fields */ 92 | ¬e_handle_srch)) /* argument to action routine */ 93 | 94 | { 95 | return(ERR(error)); 96 | } 97 | 98 | NSFNoteGetInfo(note_handle_srch, _NOTE_OID, &tempOID); 99 | char unid_buffer[33]; 100 | snprintf(unid_buffer, 33, "%08X%08X%08X%08X", tempOID.File.Innards[1], tempOID.File.Innards[0], tempOID.Note.Innards[1], tempOID.Note.Innards[0]); 101 | DocumentItem *di = new DocumentItem(); 102 | di->name = (char*)malloc(6); 103 | if (di->name) { 104 | strcpy(di->name, "@unid"); 105 | } 106 | di->type = 1; 107 | di->stringValue = std::string(unid_buffer); 108 | items2.push_back(di); 109 | view2.push_back(items2); 110 | 111 | if (error = NSFNoteClose (note_handle_srch)) 112 | return (ERR(error)); 113 | 114 | /* End of subroutine. */ 115 | return (NOERROR); 116 | } 117 | 118 | 119 | class NSFSearchWorker : public AsyncWorker { 120 | public: 121 | NSFSearchWorker(Callback *callback, std::string serverName, std::string dbName, std::string search_formula) 122 | : AsyncWorker(callback), serverName(serverName), dbName(dbName), search_formula(search_formula) {} 123 | ~NSFSearchWorker() {} 124 | 125 | // Executed inside the worker-thread. 126 | // It is not safe to access V8, or V8 data structures 127 | // here, so everything we need for input and output 128 | // should go on `this`. 129 | void Execute() { 130 | DBHANDLE db_handle; /* handle of source database */ 131 | char formula[] = "@All"; /* an ASCII selection formula. */ 132 | FORMULAHANDLE formula_handle; /* a compiled selection formula */ 133 | WORD wdc; /* a word we don't care about */ 134 | STATUS error = NOERROR; /* return status from API calls */ 135 | char *error_text = (char *)malloc(sizeof(char) * 200); 136 | if (error = NotesInitThread()) { 137 | SetErrorMessage("error init notes thread"); 138 | } 139 | 140 | if (error = NSFDbOpen (dbName.c_str(), &db_handle)) { 141 | NotesTermThread(); 142 | SetErrorMessage("error opening database\n"); 143 | return; 144 | } 145 | 146 | if (error = NSFFormulaCompile ( 147 | NULL, /* name of formula (none) */ 148 | (WORD) 0, /* length of name */ 149 | formula, /* the ASCII formula */ 150 | (WORD) strlen(formula), /* length of ASCII formula */ 151 | &formula_handle, /* handle to compiled formula */ 152 | &wdc, /* compiled formula length (don't care) */ 153 | &wdc, /* return code from compile (don't care) */ 154 | &wdc, &wdc, &wdc, &wdc)) /* compile error info (don't care) */ 155 | 156 | { 157 | NSFDbClose (db_handle); 158 | NotesTermThread(); 159 | DataHelper::GetAPIError(error, error_text); 160 | SetErrorMessage(error_text); 161 | return; 162 | 163 | } 164 | 165 | if (error = NSFSearch ( 166 | db_handle, /* database handle */ 167 | formula_handle, /* selection formula */ 168 | NULL, /* title of view in selection formula */ 169 | 0, /* search flags */ 170 | NOTE_CLASS_DOCUMENT,/* note class to find */ 171 | NULL, /* starting date (unused) */ 172 | print_fields, /* call for each note found */ 173 | &db_handle, /* argument to print_fields */ 174 | NULL)) /* returned ending date (unused) */ 175 | { 176 | NSFDbClose (db_handle); 177 | NotesTermThread(); 178 | DataHelper::GetAPIError(error, error_text); 179 | SetErrorMessage(error_text); 180 | return; 181 | 182 | } 183 | 184 | /* Free the memory allocated to the compiled formula. */ 185 | 186 | OSMemFree (formula_handle); 187 | NSFDbClose(db_handle); 188 | 189 | NotesTermThread(); 190 | } 191 | 192 | void HandleOKCallback() { 193 | HandleScope scope; 194 | Local viewRes = New();//DataHelper::getV8Data(viewResult); 195 | 196 | for (size_t j = 0; j < view2.size(); j++) { 197 | std::vector column = view2[j]; 198 | Local resDoc = Nan::New(); 199 | for (size_t k = 0; k < column.size(); k++) { 200 | DocumentItem *di = column[k]; 201 | if (di->type == 1) { 202 | Nan::Set(resDoc, New(di->name).ToLocalChecked(), New(di->stringValue).ToLocalChecked()); 203 | } 204 | else if (di->type == 2) { 205 | Nan::Set(resDoc, New(di->name).ToLocalChecked(), New(di->numberValue)); 206 | } 207 | else if (di->type == 3) { 208 | Nan::Set(resDoc, New(di->name).ToLocalChecked(), New(di->numberValue).ToLocalChecked()); 209 | } 210 | else if (di->type == 4) { 211 | Local arr = New(); 212 | for (size_t j = 0; j < di->vectorStrValue.size(); j++) { 213 | if (di->vectorStrValue[j]) { 214 | Nan::Set(arr, j, Nan::New(di->vectorStrValue[j]).ToLocalChecked()); 215 | } 216 | } 217 | Nan::Set(resDoc, New(di->name).ToLocalChecked(), arr); 218 | } 219 | } 220 | Nan::Set(viewRes, j, resDoc); 221 | } 222 | Local argv[] = { 223 | Null() 224 | , viewRes 225 | }; 226 | 227 | callback->Call(2, argv); 228 | } 229 | 230 | void HandleErrorCallback() { 231 | HandleScope scope; 232 | Local errorObj = Nan::New(); 233 | Nan::Set(errorObj, New("errorMessage").ToLocalChecked(), New(ErrorMessage()).ToLocalChecked()); 234 | Local argv[] = { 235 | errorObj, 236 | Null() 237 | }; 238 | callback->Call(2, argv); 239 | } 240 | 241 | private: 242 | std::string serverName; 243 | std::string dbName; 244 | std::string search_formula; 245 | }; 246 | 247 | STATUS LNCALLBACK field_actions2(WORD unused, WORD item_flags, char far *name_ptr, WORD name_len, void far *item_valu, DWORD item_value_len, void far *note_handle_srch2) { 248 | WORD field_len; 249 | char field_text[132000]; 250 | STATUS error = NOERROR; 251 | NUMBER number_field; 252 | 253 | BLOCKID bidLinksItem; 254 | DWORD dwLinksValueLen; 255 | BLOCKID bidLinksValue; 256 | WORD item_type; 257 | DocumentItem * di = new DocumentItem(); 258 | char error_text[200]; 259 | 260 | 261 | char *field_name = (char*)malloc(name_len + 1); 262 | if (field_name) { 263 | memcpy(field_name, name_ptr, name_len); 264 | field_name[name_len] = '\0'; 265 | } 266 | 267 | if (error = NSFItemInfo(note_handle_srch, field_name, 268 | strlen(field_name), &bidLinksItem, 269 | &item_type, &bidLinksValue, 270 | &dwLinksValueLen)) { 271 | DataHelper::GetAPIError(error, error_text); 272 | 273 | return (error); 274 | } 275 | if (item_type == TYPE_TEXT) { 276 | field_len = NSFItemGetText( 277 | note_handle_srch, 278 | field_name, 279 | field_text, 280 | (WORD) sizeof(field_text)); 281 | 282 | char buf[MAXWORD]; 283 | OSTranslate(OS_TRANSLATE_LMBCS_TO_UTF8, field_text, MAXWORD, buf, MAXWORD); 284 | di->stringValue = std::string(buf); 285 | di->name = (char*)malloc(name_len + 1); 286 | if (di->name) { 287 | memcpy(di->name, name_ptr, name_len); 288 | di->name[name_len] = '\0'; 289 | } 290 | di->type = 1; 291 | items2.push_back(di); 292 | 293 | } 294 | else if (item_type == TYPE_TEXT_LIST) { 295 | 296 | WORD num_entries = NSFItemGetTextListEntries(note_handle_srch, 297 | field_name); 298 | std::vector vectorStrValue = std::vector(0); 299 | for (int counter = 0; counter < num_entries; counter++) 300 | { 301 | field_len = NSFItemGetTextListEntry(note_handle_srch, 302 | field_name, counter, field_text, (WORD)(sizeof(field_text) - 1)); 303 | char *buf = (char*)malloc(field_len + 1); 304 | OSTranslate(OS_TRANSLATE_LMBCS_TO_UTF8, field_text, MAXWORD, buf, MAXWORD); 305 | vectorStrValue.push_back(buf); 306 | 307 | } 308 | di->vectorStrValue = vectorStrValue; 309 | di->name = field_name; 310 | di->type = 4; 311 | items2.push_back(di); 312 | } 313 | else if (item_type == TYPE_NUMBER) { 314 | NSFItemGetNumber( 315 | note_handle_srch, 316 | field_name, 317 | &number_field); 318 | di->numberValue = (double)number_field; 319 | di->name = field_name; 320 | di->type = 2; 321 | items2.push_back(di); 322 | } 323 | 324 | else if (item_type == TYPE_TIME) { 325 | TIMEDATE time_date; 326 | if (NSFItemGetTime(note_handle_srch, 327 | field_name, 328 | &time_date)) { 329 | TIME tid; 330 | struct tm * timeinfo; 331 | 332 | tid.GM = time_date; 333 | tid.zone = 0; 334 | tid.dst = 0; 335 | TimeGMToLocalZone(&tid); 336 | 337 | time_t rawtime = time(0); 338 | timeinfo = localtime(&rawtime); 339 | timeinfo->tm_year = tid.year - 1900; 340 | timeinfo->tm_mon = tid.month - 1; 341 | timeinfo->tm_mday = tid.day; 342 | 343 | timeinfo->tm_hour = tid.hour; 344 | timeinfo->tm_min = tid.minute - 1; 345 | timeinfo->tm_sec = tid.second - 1; 346 | 347 | double dtime = static_cast(mktime(timeinfo)); 348 | 349 | double dateTimeValue = dtime * 1000; // convert to double time 350 | di->numberValue = dateTimeValue; 351 | di->name = field_name; 352 | di->type = 3; 353 | items2.push_back(di); 354 | } 355 | 356 | 357 | } 358 | 359 | //delete field_name; 360 | 361 | return(NOERROR); 362 | 363 | } 364 | 365 | 366 | NAN_METHOD(SearchNsfAsync) { 367 | v8::Isolate* isolate = info.GetIsolate(); 368 | 369 | Local param = (info[0]->ToObject()); 370 | Local searchParam = (info[1]->ToString()); 371 | Local serverKey = String::NewFromUtf8(isolate, "server"); 372 | Local databaseKey = String::NewFromUtf8(isolate, "database"); 373 | Local serverVal = param->Get(serverKey); 374 | Local databaseVal = param->Get(databaseKey); 375 | 376 | String::Utf8Value serverName(serverVal->ToString()); 377 | String::Utf8Value dbName(databaseVal->ToString()); 378 | String::Utf8Value search_formula(searchParam->ToString()); 379 | 380 | std::string serverStr; 381 | std::string dbStr; 382 | std::string searchFormulaStr; 383 | serverStr = std::string(*serverName); 384 | dbStr = std::string(*dbName); 385 | searchFormulaStr = std::string(*search_formula); 386 | Callback *callback = new Callback(info[2].As()); 387 | 388 | AsyncQueueWorker(new NSFSearchWorker(callback, serverStr, dbStr, searchFormulaStr)); 389 | } -------------------------------------------------------------------------------- /src/nsf_search.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Domino addon for Node.js 3 | * 4 | * Copyright (c) 2016 Nils T. Hjelme 5 | * 6 | * The MIT License (MIT) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | *******************************************************************************/ 26 | 27 | #ifndef NSF_SEARCH_H_ 28 | #define NSF_SEARCH_H_ 29 | 30 | #include 31 | #include "global.h" 32 | 33 | NAN_METHOD(SearchNsfAsync); 34 | 35 | STATUS LNCALLBACK field_actions2(WORD unused, WORD item_flags, char far *name_ptr, WORD name_len, void far *item_valu, DWORD item_value_len, void far *docRef); 36 | 37 | 38 | #endif // NSF_SEARCH_H_ 39 | -------------------------------------------------------------------------------- /src/replicate_database_async.cc: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Domino addon for Node.js 3 | * 4 | * Copyright (c) 2016 Nils T. Hjelme 5 | * 6 | * The MIT License (MIT) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | *******************************************************************************/ 26 | 27 | #include 28 | #include "replicate_database_async.h" 29 | #include 30 | #include 31 | #include 32 | 33 | using v8::Function; 34 | using v8::Local; 35 | using v8::Number; 36 | using v8::Value; 37 | using v8::String; 38 | using v8::Object; 39 | using v8::Array; 40 | using Nan::AsyncQueueWorker; 41 | using Nan::AsyncWorker; 42 | using Nan::Callback; 43 | using Nan::HandleScope; 44 | using Nan::New; 45 | using Nan::Null; 46 | using Nan::To; 47 | 48 | class ReplicateDatabaseWorker : public AsyncWorker { 49 | public: 50 | ReplicateDatabaseWorker(Callback *callback, std::string serverName, std::string dbName) 51 | : AsyncWorker(callback), serverName(serverName), dbName(dbName), replicateTo(replicateTo) {} 52 | ~ReplicateDatabaseWorker() {} 53 | 54 | // Executed inside the worker-thread. 55 | // It is not safe to access V8, or V8 data structures 56 | // here, so everything we need for input and output 57 | // should go on `this`. 58 | void Execute() { 59 | LNSetThrowAllErrors(TRUE); 60 | 61 | LNNotesSession session; 62 | try { 63 | session.InitThread(); 64 | //LNDatabase Db; 65 | //session.GetDatabase(dbName.c_str(), &Db, serverName.c_str()); 66 | //Db.Open(); 67 | LNReplicationOptions RepOpt; 68 | LNReplicationStatistics Stats; 69 | 70 | RepOpt.SetCloseSession(FALSE); 71 | RepOpt.SetDirection(LNREPLICATIONDIRECTION_RECEIVE); 72 | 73 | LNText FileList; 74 | FileList.Append(dbName.c_str()); 75 | std::cout << "Replicate:" << dbName << std::endl; 76 | RepOpt.SetFileList(FileList); 77 | 78 | RepOpt.SetFileType(LNREPLICATIONFILETYPE_NSF); 79 | std::cout << "Starting replication" << std::endl; 80 | session.Replicate(serverName.c_str(), RepOpt, &Stats); 81 | std::cout << "Starting replicated" << std::endl; 82 | LNINT DocAdded = (Stats.GetReceivedStatistics()).GetNotesAdded(); 83 | repDocAdded = DocAdded; 84 | session.TermThread(); 85 | } 86 | catch (LNSTATUS Lnerror) { 87 | char ErrorBuf[512]; 88 | LNGetErrorMessage(Lnerror, ErrorBuf, 512); 89 | std::cout << "ReplicateError: " << ErrorBuf << std::endl; 90 | } 91 | } 92 | 93 | void HandleOKCallback() { 94 | HandleScope scope; 95 | Local resDoc = Nan::New(); 96 | Nan::Set(resDoc, New("status").ToLocalChecked(), New("replicated").ToLocalChecked()); 97 | Nan::Set(resDoc, New("docsAdded").ToLocalChecked(), New(repDocAdded)); 98 | Local argv[] = { 99 | Null() 100 | , resDoc 101 | }; 102 | 103 | callback->Call(2, argv); 104 | } 105 | 106 | private: 107 | std::string serverName; 108 | std::string dbName; 109 | std::string replicateTo; 110 | int repDocAdded; 111 | }; 112 | 113 | NAN_METHOD(ReplicateDatabaseAsync) { 114 | v8::Isolate* isolate = info.GetIsolate(); 115 | 116 | Local param = (info[0]->ToObject()); 117 | //Local replicateToParam = (info[1]->ToString()); 118 | Local serverKey = String::NewFromUtf8(isolate, "server"); 119 | Local databaseKey = String::NewFromUtf8(isolate, "database"); 120 | Local serverVal = param->Get(serverKey); 121 | Local databaseVal = param->Get(databaseKey); 122 | 123 | String::Utf8Value serverName(serverVal->ToString()); 124 | String::Utf8Value dbName(databaseVal->ToString()); 125 | //String::Utf8Value replicateTo(replicateToParam->ToString()); 126 | 127 | std::string serverStr; 128 | std::string dbStr; 129 | //std::string replicateToStr; 130 | serverStr = std::string(*serverName); 131 | dbStr = std::string(*dbName); 132 | //replicateToStr = std::string(*replicateTo); 133 | Callback *callback = new Callback(info[2].As()); 134 | 135 | AsyncQueueWorker(new ReplicateDatabaseWorker(callback, serverStr, dbStr)); 136 | } -------------------------------------------------------------------------------- /src/replicate_database_async.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Domino addon for Node.js 3 | * 4 | * Copyright (c) 2016 Nils T. Hjelme 5 | * 6 | * The MIT License (MIT) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | *******************************************************************************/ 26 | 27 | #ifndef REPLICATE_DATABASE_ASYNC_H_ 28 | #define REPLICATE_DATABASE_ASYNC_H_ 29 | 30 | #include 31 | 32 | NAN_METHOD(ReplicateDatabaseAsync); 33 | 34 | #endif // REPLICATE_DATABASE_ASYNC_H_ 35 | #pragma once 36 | -------------------------------------------------------------------------------- /src/save_document_async.cc: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Domino addon for Node.js 3 | * 4 | * Copyright (c) 2016 Nils T. Hjelme 5 | * 6 | * The MIT License (MIT) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | *******************************************************************************/ 26 | 27 | #include 28 | #include "save_document_async.h" 29 | #include "DocumentItem.h" 30 | #include "DataHelper.h" 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | using v8::Function; 43 | using v8::Local; 44 | using v8::Number; 45 | using v8::Value; 46 | using v8::String; 47 | using v8::Object; 48 | using v8::Array; 49 | using Nan::AsyncQueueWorker; 50 | using Nan::AsyncWorker; 51 | using Nan::Callback; 52 | using Nan::HandleScope; 53 | using Nan::New; 54 | using Nan::Null; 55 | using Nan::To; 56 | 57 | 58 | class SaveDocumentWorker : public AsyncWorker { 59 | public: 60 | SaveDocumentWorker(Callback *callback, std::string serverName, std::string dbName, std::string docUnid, std::vector items) 61 | : AsyncWorker(callback), serverName(serverName), dbName(dbName), unid(docUnid), items(items) {} 62 | ~SaveDocumentWorker() {} 63 | 64 | // Executed inside the worker-thread. 65 | // It is not safe to access V8, or V8 data structures 66 | // here, so everything we need for input and output 67 | // should go on `this`. 68 | void Execute() { 69 | DBHANDLE db_handle; /* handle of source database */ 70 | UNID temp_unid; 71 | OID tempOID; 72 | STATUS error = NOERROR; /* return status from API calls */ 73 | bool isEdit = false; 74 | NOTEHANDLE note_handle2; 75 | char *error_text = (char *)malloc(sizeof(char) * 200); 76 | 77 | if (error = NotesInitThread()) 78 | { 79 | SetErrorMessage("error init notes thread"); 80 | } 81 | 82 | if (error = NSFDbOpen(dbName.c_str(), &db_handle)) 83 | { 84 | printf("error opening database\n"); 85 | //DataHelper::GetAPIError(error,error_text); 86 | SetErrorMessage("error opening database"); 87 | } 88 | if (unid.length() == 32) { 89 | // edit document 90 | isEdit = true; 91 | 92 | DataHelper::ToUNID(unid.c_str(), &temp_unid); 93 | 94 | if (error = NSFNoteOpenByUNID( 95 | db_handle, /* database handle */ 96 | &temp_unid, /* note ID */ 97 | (WORD)0, /* open flags */ 98 | ¬e_handle2)) /* note handle (return) */ 99 | { 100 | printf("error opening document\n"); 101 | DataHelper::GetAPIError(error, error_text); 102 | SetErrorMessage(error_text); 103 | } 104 | } 105 | else { 106 | //create new document 107 | if (error = NSFNoteCreate(db_handle, ¬e_handle2)) { 108 | printf("error creating document\n"); 109 | NSFDbClose(db_handle); 110 | NotesTermThread(); 111 | //DataHelper::GetAPIError(error,error_text); 112 | //SetErrorMessage(error_text); 113 | } 114 | 115 | 116 | } 117 | 118 | 119 | for (std::size_t ii = 0; ii < items.size(); ii++) { 120 | 121 | if (items[ii]->type == 2) { 122 | if (error = NSFItemSetNumber(note_handle2, items[ii]->name, &items[ii]->numberValue)) 123 | { 124 | DataHelper::GetAPIError(error, error_text); 125 | SetErrorMessage(error_text); 126 | } 127 | } 128 | else if (items[ii]->type == 1) { 129 | // text 130 | char buf[MAXWORD]; 131 | OSTranslate(OS_TRANSLATE_UTF8_TO_LMBCS, items[ii]->stringValue.c_str(), MAXWORD, buf, MAXWORD); 132 | 133 | if (error = NSFItemSetText(note_handle2, 134 | items[ii]->name, 135 | buf, 136 | MAXWORD)) 137 | { 138 | DataHelper::GetAPIError(error, error_text); 139 | SetErrorMessage(error_text); 140 | } 141 | 142 | } 143 | else if (items[ii]->type == 4) { 144 | // text list 145 | 146 | 147 | 148 | for (size_t j = 0; j < items[ii]->vectorStrValue.size(); j++) { 149 | size_t val_len = strlen(items[ii]->vectorStrValue[j]); 150 | char *buf = (char*)malloc(val_len + 1); 151 | OSTranslate(OS_TRANSLATE_UTF8_TO_LMBCS, items[ii]->vectorStrValue[j], val_len, buf, val_len); 152 | if (j == 0) { 153 | 154 | if (error = NSFItemCreateTextList(note_handle2, 155 | items[ii]->name, 156 | buf, 157 | val_len)) 158 | { 159 | DataHelper::GetAPIError(error, error_text); 160 | SetErrorMessage(error_text); 161 | } 162 | } 163 | else { 164 | if (error = NSFItemAppendTextList(note_handle2, 165 | items[ii]->name, 166 | buf, 167 | val_len, 168 | TRUE)) 169 | { 170 | DataHelper::GetAPIError(error, error_text); 171 | SetErrorMessage(error_text); 172 | } 173 | } 174 | } 175 | 176 | 177 | } 178 | else if (items[ii]->type == 3) { 179 | // datetime 180 | TIME tid; 181 | 182 | std::time_t t = static_cast(items[ii]->numberValue / 1000); 183 | struct tm* ltime = localtime(&t); 184 | tid.year = ltime->tm_year + 1900; 185 | tid.month = ltime->tm_mon + 1; 186 | tid.day = ltime->tm_mday; 187 | tid.hour = ltime->tm_hour; 188 | tid.minute = ltime->tm_min + 1; 189 | tid.second = ltime->tm_sec-1; 190 | tid.zone = 0; 191 | tid.dst = 0; 192 | tid.hundredth = 0; 193 | 194 | if (error = TimeLocalToGM(&tid)) { 195 | DataHelper::GetAPIError(error, error_text); 196 | SetErrorMessage(error_text); 197 | } 198 | 199 | if (error = NSFItemSetTime(note_handle2, items[ii]->name, &tid.GM)) 200 | { 201 | DataHelper::GetAPIError(error, error_text); 202 | SetErrorMessage(error_text); 203 | } 204 | } 205 | 206 | } 207 | 208 | if (error = NSFNoteUpdate(note_handle2, 0)) { 209 | //DataHelper::GetAPIError(error,error_text); 210 | SetErrorMessage("error updating note"); 211 | NSFDbClose(db_handle); 212 | NotesTermThread(); 213 | return; 214 | } 215 | 216 | NSFNoteGetInfo(note_handle2, _NOTE_OID, &tempOID); 217 | char unid_buffer[33]; 218 | snprintf(unid_buffer, 33, "%08X%08X%08X%08X", tempOID.File.Innards[1], tempOID.File.Innards[0], tempOID.Note.Innards[1], tempOID.Note.Innards[0]); 219 | DocumentItem *di = new DocumentItem(); 220 | di->name = (char*)malloc(6); 221 | if (di->name) { 222 | strcpy(di->name, "@unid"); 223 | } 224 | di->type = 1; 225 | di->stringValue = std::string(unid_buffer); 226 | items.push_back(di); 227 | 228 | if (error = NSFNoteClose(note_handle2)) 229 | { 230 | //DataHelper::GetAPIError(error,error_text); 231 | SetErrorMessage("error closing notes"); 232 | NSFDbClose(db_handle); 233 | NotesTermThread(); 234 | return; 235 | } 236 | if (error = NSFDbClose(db_handle)) 237 | { 238 | //DataHelper::GetAPIError(error,error_text); 239 | SetErrorMessage("error closing db"); 240 | NotesTermThread(); 241 | return; 242 | } 243 | NotesTermThread(); 244 | 245 | 246 | } 247 | 248 | void HandleOKCallback() { 249 | HandleScope scope; 250 | Local resDoc = Nan::New(); 251 | for (std::size_t i = 0; i < items.size(); i++) { 252 | DocumentItem *di = items[i]; 253 | if (di->type == 1) { 254 | Nan::Set(resDoc, New(di->name).ToLocalChecked(), New(di->stringValue).ToLocalChecked()); 255 | } 256 | else if (di->type == 2) { 257 | Nan::Set(resDoc, New(di->name).ToLocalChecked(), New(di->numberValue)); 258 | } 259 | else if (di->type == 3) { 260 | Nan::Set(resDoc, New(di->name).ToLocalChecked(), New(di->numberValue).ToLocalChecked()); 261 | } 262 | else if (di->type == 4) { 263 | Local arr = New(); 264 | for (size_t j = 0; j < di->vectorStrValue.size(); j++) { 265 | if (di->vectorStrValue[j]) { 266 | Nan::Set(arr, j, Nan::New(di->vectorStrValue[j]).ToLocalChecked()); 267 | } 268 | } 269 | Nan::Set(resDoc, New(di->name).ToLocalChecked(), arr); 270 | } 271 | } 272 | 273 | Local argv[] = { 274 | Null() 275 | , resDoc 276 | }; 277 | callback->Call(2, argv); 278 | } 279 | 280 | void HandleErrorCallback() { 281 | HandleScope scope; 282 | Local errorObj = Nan::New(); 283 | Nan::Set(errorObj, New("errorMessage").ToLocalChecked(), New(ErrorMessage()).ToLocalChecked()); 284 | Local argv[] = { 285 | errorObj, 286 | Null() 287 | }; 288 | callback->Call(2, argv); 289 | } 290 | 291 | private: 292 | std::string serverName; 293 | std::string dbName; 294 | std::string unid; 295 | std::vector items; 296 | }; 297 | 298 | NAN_METHOD(SaveDocumentAsync) { 299 | v8::Isolate* isolate = info.GetIsolate(); 300 | Local param = (info[0]->ToObject()); 301 | Local document = (info[1]->ToObject()); 302 | Local serverKey = String::NewFromUtf8(isolate, "server"); 303 | Local databaseKey = String::NewFromUtf8(isolate, "database"); 304 | Local serverVal = param->Get(serverKey); 305 | Local databaseVal = param->Get(databaseKey); 306 | String::Utf8Value serverName(serverVal->ToString()); 307 | String::Utf8Value dbName(databaseVal->ToString()); 308 | std::string serverStr; 309 | std::string dbStr; 310 | std::string docUnid; 311 | if (document->Has(String::NewFromUtf8(isolate, "@unid"))) { 312 | Local unidVal = document->Get(String::NewFromUtf8(isolate, "@unid")); 313 | String::Utf8Value unid(unidVal->ToString()); 314 | docUnid = std::string(*unid); 315 | document->Delete(String::NewFromUtf8(isolate, "@unid")); 316 | } 317 | if (document->Has(String::NewFromUtf8(isolate, "@meta_data"))) { 318 | document->Delete(String::NewFromUtf8(isolate, "@meta_data")); 319 | } 320 | serverStr = std::string(*serverName); 321 | dbStr = std::string(*dbName); 322 | 323 | 324 | std::vector items = unpack_document(document); 325 | 326 | Callback *callback = new Callback(info[2].As()); 327 | 328 | AsyncQueueWorker(new SaveDocumentWorker(callback, serverStr, dbStr, docUnid, items)); 329 | } 330 | 331 | 332 | -------------------------------------------------------------------------------- /src/save_document_async.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Domino addon for Node.js 3 | * 4 | * Copyright (c) 2016 Nils T. Hjelme 5 | * 6 | * The MIT License (MIT) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | *******************************************************************************/ 26 | 27 | #ifndef SAVE_ASYNC_DOCUMENT_ASYNC_H_ 28 | #define SAVE_ASYNC_DOCUMENT_ASYNC_H_ 29 | 30 | #include 31 | 32 | NAN_METHOD(SaveDocumentAsync); 33 | 34 | #endif // SAVE_ASYNC_DOCUMENT_ASYNC_H_ 35 | -------------------------------------------------------------------------------- /src/view_async.cc: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Domino addon for Node.js 3 | * 4 | * Copyright (c) 2016 Nils T. Hjelme 5 | * 6 | * The MIT License (MIT) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | *******************************************************************************/ 26 | 27 | #include 28 | #include "view_async.h" 29 | #include "DocumentItem.h" 30 | #include "DataHelper.h" 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #define CATEGORY_LEVEL_BEING_SEARCHED 0 43 | #define MAIN_TOPIC_INDENT 0 44 | #define MALLOC_AMOUNT 6048 45 | 46 | using v8::Function; 47 | using v8::Local; 48 | using v8::Number; 49 | using v8::Value; 50 | using v8::String; 51 | using v8::Boolean; 52 | using v8::Object; 53 | using v8::Array; 54 | using Nan::AsyncQueueWorker; 55 | using Nan::AsyncWorker; 56 | using Nan::Callback; 57 | using Nan::HandleScope; 58 | using Nan::New; 59 | using Nan::Null; 60 | using Nan::To; 61 | 62 | //std::vector > viewResult; 63 | 64 | std::vector> view; 65 | 66 | 67 | STATUS PrintSummary(BYTE *pSummary,WORD entry_indent,char *unid) 68 | 69 | /* This function prints the items in the summary for one 70 | entry in a collection. 71 | 72 | The information in a view summary is as follows: 73 | 74 | header (total length of pSummary, number of items in pSummary) 75 | length of item #1 (including data type) 76 | length of item #2 (including data type) 77 | length of item #3 (including data type) 78 | ... 79 | data type of item #1 80 | value of item #1 81 | data type of item #2 82 | value of item #2 83 | data type of item #3 84 | value of item #3 85 | .... 86 | */ 87 | 88 | { 89 | 90 | /* Local constants */ 91 | 92 | #define MAX_ITEMS 20 93 | #define MAX_ITEM_LEN 255 94 | #define MAX_ITEM_NAME_LEN 100 95 | #define DATATYPE_SIZE sizeof(USHORT) 96 | #define ITEM_LENGTH_SIZE sizeof(USHORT) 97 | #define NUMERIC_SIZE sizeof(NUMBER) 98 | #define TIME_SIZE sizeof(TIMEDATE) 99 | 100 | /* cleanup flag values*/ 101 | #define DO_NOTHING 0x0000 102 | #define FREE_KEY1 0x0004 103 | #define FREE_TRANSLATEDKEY 0x0008 104 | #define FREE_PKEY 0x0011 105 | 106 | 107 | /* Local variables */ 108 | 109 | BYTE *pSummaryPos; /* current position in summary */ 110 | ITEM_TABLE ItemTable; /* header at start of summary */ 111 | USHORT ItemCount; /* number of items in summary */ 112 | USHORT NameLength; /* length of item name w/out terminator*/ 113 | USHORT ValueLength; /* length of item value, incl. type */ 114 | WORD DataType; /* item data type word */ 115 | 116 | USHORT i; /* counter for loop over items */ 117 | ITEM Items[MAX_ITEMS]; /* Stores the array of ITEMs */ 118 | char * ItemText; /* Text rendering of item value */ 119 | char ItemName[MAX_ITEM_NAME_LEN];/* Zero terminated item name */ 120 | NUMBER NumericItem; /* a numeric item */ 121 | TIMEDATE TimeItem; /* a time/date item */ 122 | 123 | USHORT ListCount; /* number of entries in a text list */ 124 | char *ListEntry; /* pointer to list entry */ 125 | WORD ListLen; /* total length of text list */ 126 | WORD EntryLen; /* length of one entry */ 127 | STATUS error; 128 | 129 | time_t rawtime; 130 | double dtime; 131 | double dateTimeValue; 132 | std::vector column; 133 | DocumentItem *di_indent = new DocumentItem(); 134 | di_indent->type = 2; 135 | di_indent->name = "@indent"; 136 | di_indent->numberValue = entry_indent; 137 | column.push_back(di_indent); 138 | DocumentItem *di_unid = new DocumentItem(); 139 | di_unid->type = 1; 140 | di_unid->name = "@unid"; 141 | di_unid->stringValue = unid; 142 | column.push_back(di_unid); 143 | 144 | 145 | /* pSummaryPos points to the beginning of the summary buffer. Copy 146 | the ITEM_TABLE header at the beginning of the summary buffer 147 | to a local variable. Advance pSummaryPos to point to the next 148 | byte in the summary buffer after the ITEM_TABLE. 149 | */ 150 | pSummaryPos = pSummary; 151 | 152 | memcpy((char*)(&ItemTable), pSummaryPos, sizeof(ITEM_TABLE)); 153 | pSummaryPos += sizeof(ItemTable); 154 | 155 | /* pSummaryPos now points to the first ITEM in an array of ITEM 156 | structures. Copy this array of ITEM structures into the global 157 | Items[] array. 158 | */ 159 | 160 | ItemCount = ItemTable.Items; 161 | for (i = 0; i < ItemCount; i++) 162 | { 163 | 164 | memcpy((char*)(&Items[i]), pSummaryPos, sizeof(ITEM)); 165 | pSummaryPos += sizeof(ITEM); 166 | } 167 | 168 | 169 | /* pSummaryPos now points to the first item name. Loop over each 170 | item, copying the item name into the ItemName variable and 171 | converting the item value to printable text in ItemText. 172 | */ 173 | for (i = 0; i < ItemCount; i++) { 174 | 175 | NameLength = Items[i].NameLength; 176 | memcpy(ItemName, pSummaryPos, NameLength); 177 | ItemName[NameLength] = '\0'; 178 | pSummaryPos += NameLength; 179 | 180 | if (Items[i].ValueLength == 0) { 181 | DocumentItem *di = new DocumentItem(); 182 | di->name =" * "; 183 | di->stringValue = '\0'; 184 | di->type = 1; 185 | column.push_back(di); 186 | } else { 187 | 188 | 189 | /* pSummaryPos now points to the item value. First get the 190 | data type. Then step over the data type word to the data 191 | value and convert the value to printable text. Store the 192 | text in ItemText. 193 | */ 194 | memcpy((char*)(&DataType), pSummaryPos, sizeof(WORD)); 195 | pSummaryPos += sizeof(WORD); 196 | 197 | ValueLength = Items[i].ValueLength - sizeof(WORD); 198 | /* If the item data type is text, copy into ItemText[]. */ 199 | 200 | DocumentItem *di = new DocumentItem(); 201 | di->name = (char*)malloc(NameLength + 1); 202 | if (di->name) { 203 | memcpy(di->name, ItemName, NameLength); 204 | di->name[NameLength] = '\0'; 205 | } 206 | 207 | switch (DataType) 208 | { 209 | 210 | /* Extract a text item from the pSummary. */ 211 | 212 | case TYPE_TEXT: 213 | ItemText = (char*)malloc(ValueLength + 1); 214 | memcpy(ItemText, pSummaryPos, ValueLength); 215 | 216 | ItemText[ValueLength] = '\0'; 217 | 218 | char buf[MAXWORD]; 219 | OSTranslate(OS_TRANSLATE_LMBCS_TO_UTF8, ItemText, MAXWORD, buf, MAXWORD); 220 | 221 | di->stringValue = buf; 222 | di->type = 1; 223 | column.push_back(di); 224 | free(ItemText); 225 | break; 226 | 227 | /* Extract a text list item from the pSummary. */ 228 | 229 | case TYPE_TEXT_LIST: 230 | memcpy(&ListCount, pSummaryPos, sizeof(ListCount)); 231 | ListLen = 0; 232 | for (WORD n = 0; n < ListCount; n++) 233 | { 234 | error = ListGetText( 235 | pSummaryPos, 236 | FALSE, /* DataType not prepended to list */ 237 | n, 238 | &ListEntry, 239 | &EntryLen); 240 | if (error) { 241 | return (ERR(error)); 242 | } 243 | char *buf = (char* )malloc(EntryLen + 1); 244 | OSTranslate(OS_TRANSLATE_LMBCS_TO_UTF8, ListEntry, EntryLen, buf, MAXWORD); 245 | di->vectorStrValue.push_back(buf); 246 | 247 | } 248 | di->type = 4; 249 | column.push_back(di); 250 | break; 251 | 252 | /* Extract a number item from the pSummary. */ 253 | case TYPE_NUMBER: 254 | memcpy(&NumericItem, pSummaryPos, NUMERIC_SIZE); 255 | di->numberValue = NumericItem; 256 | di->type = 2; 257 | column.push_back(di); 258 | break; 259 | 260 | /* Extract a time/date item from the pSummary. */ 261 | 262 | case TYPE_TIME: 263 | memcpy(&TimeItem, pSummaryPos, TIME_SIZE); 264 | TIME tid; 265 | struct tm * timeinfo; 266 | 267 | tid.GM = TimeItem; 268 | tid.zone = 0; 269 | tid.dst = 0; 270 | TimeGMToLocalZone(&tid); 271 | 272 | rawtime = time(0); 273 | timeinfo = localtime(&rawtime); 274 | timeinfo->tm_year = tid.year - 1900; 275 | timeinfo->tm_mon = tid.month - 1; 276 | timeinfo->tm_mday = tid.day; 277 | 278 | timeinfo->tm_hour = tid.hour; 279 | timeinfo->tm_min = tid.minute - 1; 280 | timeinfo->tm_sec = tid.second - 1; 281 | dtime = static_cast(mktime(timeinfo)); 282 | 283 | dateTimeValue = dtime * 1000; // convert to double time 284 | di->numberValue = dateTimeValue; 285 | di->type = 3; 286 | column.push_back(di); 287 | break; 288 | 289 | /* If the pSummary item is not one of the data types this program 290 | handles. */ 291 | 292 | default: 293 | break; 294 | } 295 | 296 | /* Advance to next item in the pSummary. */ 297 | pSummaryPos += ValueLength; 298 | //pSummaryPos += (ItemLength[i] - DATATYPE_SIZE); 299 | /* End of loop that is extracting each item in the pSummary. */ 300 | //viewResult.push_back(doc2); 301 | } // end else 302 | } 303 | view.push_back(column); 304 | /* End of function */ 305 | 306 | return (NOERROR); 307 | 308 | } 309 | 310 | 311 | 312 | class ViewWorker : public AsyncWorker { 313 | public: 314 | ViewWorker(Callback *callback, std::string serverName, std::string dbName, std::string viewName,std::string category,std::string findByKey,bool exact,unsigned long max_matches) 315 | : AsyncWorker(callback), serverName(serverName), dbName(dbName), viewName(viewName),category(category),findByKey(findByKey),exact(exact), max_matches(max_matches){} 316 | ~ViewWorker() { 317 | view.clear(); 318 | 319 | } 320 | 321 | // Executed inside the worker-thread. 322 | // It is not safe to access V8, or V8 data structures 323 | // here, so everything we need for input and output 324 | // should go on `this`. 325 | void Execute() { 326 | WORD cleanup = DO_NOTHING; 327 | DBHANDLE hDB; /* handle of the database */ 328 | NOTEID ViewID; /* note id of the view */ 329 | HCOLLECTION hCollection; /* collection handle */ 330 | COLLECTIONPOSITION CollPosition; /* index into collection */ 331 | DHANDLE hBuffer; /* handle to buffer of info */ 332 | BYTE *pBuffer; /* pointer into info buffer */ 333 | BYTE *pSummary; /* pointer into info buffer */ 334 | NOTEID EntryID; /* a collection entry id */ 335 | UNID EntryUNID; 336 | DWORD number_match; 337 | DWORD EntriesFound; /* number of entries found */ 338 | ITEM_TABLE ItemTable; /* table in pSummary buffer */ 339 | WORD SignalFlag; /* signal and share warning flags */ 340 | WORD entry_indent; /* "indent level" of entry */ 341 | STATUS error = NOERROR; /* return status from API calls */ 342 | BOOL FirstTime = TRUE; 343 | char *pTemp, *pKey; 344 | ITEM_TABLE Itemtbl; 345 | ITEM Item; 346 | WORD Word; 347 | char *Key1; /* secondary key */ 348 | WORD Item1ValueLen; /* len of actual primary text to match on */ 349 | WORD TranslatedKeyLen; 350 | char *TranslatedKey; /* Translated string key */ 351 | char *error_text = (char *) malloc(sizeof(char) * 200); 352 | 353 | number_match = max_matches; /* max number to read */ 354 | 355 | if (error = NotesInitThread()) 356 | { 357 | DataHelper::GetAPIError(error,error_text); 358 | SetErrorMessage(error_text); 359 | return; 360 | } 361 | 362 | if (error = NSFDbOpen(dbName.c_str(), &hDB)) 363 | { 364 | DataHelper::GetAPIError(error,error_text); 365 | SetErrorMessage(error_text); 366 | NotesTermThread(); 367 | return; 368 | } 369 | 370 | if (error = NIFFindView( 371 | hDB, 372 | viewName.c_str(), 373 | &ViewID)) 374 | { 375 | DataHelper::GetAPIError(error,error_text); 376 | SetErrorMessage(error_text); 377 | NSFDbClose(hDB); 378 | NotesTermThread(); 379 | return; 380 | } 381 | 382 | if (error = NIFOpenCollection( 383 | hDB, /* handle of db with view */ 384 | hDB, /* handle of db with data */ 385 | ViewID, /* note id of the view */ 386 | 0, /* collection open flags */ 387 | NULLHANDLE, /* handle to unread ID list (input and return) */ 388 | &hCollection, /* collection handle (return) */ 389 | NULLHANDLE, /* handle to open view note (return) */ 390 | NULL, /* universal note id of view (return) */ 391 | NULLHANDLE, /* handle to collapsed list (return) */ 392 | NULLHANDLE)) /* handle to selected list (return) */ 393 | 394 | { 395 | DataHelper::GetAPIError(error,error_text); 396 | SetErrorMessage(error_text); 397 | NSFDbClose(hDB); 398 | NotesTermThread(); 399 | return; 400 | } 401 | 402 | /*Set a COLLECTIONPOSITION to the beginning of the collection. */ 403 | 404 | CollPosition.Level = 0; 405 | CollPosition.Tumbler[0] = 0; 406 | 407 | 408 | 409 | if (category.length() > 0) { 410 | TranslatedKey = (char *)malloc(256); 411 | if (TranslatedKey == NULL) 412 | { 413 | printf("Error: Out of memory.\n"); 414 | } 415 | else 416 | cleanup |= FREE_TRANSLATEDKEY; 417 | TranslatedKeyLen = OSTranslate (OS_TRANSLATE_UTF8_TO_LMBCS, 418 | category.c_str(), 419 | (WORD) strlen (category.c_str()), 420 | TranslatedKey, 421 | 256); 422 | 423 | error = NIFFindByName(hCollection, TranslatedKey, FIND_CASE_INSENSITIVE, &CollPosition, &number_match); 424 | if (ERR(error) == ERR_NOT_FOUND) { 425 | SetErrorMessage("Category not found in the collection"); 426 | NIFCloseCollection(hCollection); 427 | NSFDbClose(hDB); 428 | NotesTermThread(); 429 | return; 430 | } 431 | if (error) { 432 | DataHelper::GetAPIError(error, error_text); 433 | SetErrorMessage(error_text); 434 | NIFCloseCollection(hCollection); 435 | NSFDbClose(hDB); 436 | NotesTermThread(); 437 | return; 438 | } 439 | } 440 | else if (findByKey.length()>0) { 441 | TranslatedKey = (char *)malloc(256); 442 | if (TranslatedKey == NULL) 443 | { 444 | printf("Error: Out of memory.\n"); 445 | } 446 | else 447 | cleanup |= FREE_TRANSLATEDKEY; 448 | Key1 = (char *)malloc(256); 449 | if (Key1 == NULL) 450 | { 451 | printf("Error: Out of memory.\n"); 452 | } 453 | else 454 | cleanup |= FREE_KEY1; 455 | /* Translate the input key to LMBCS */ 456 | TranslatedKeyLen = OSTranslate (OS_TRANSLATE_UTF8_TO_LMBCS, 457 | findByKey.c_str(), 458 | (WORD) strlen (findByKey.c_str()), 459 | TranslatedKey, 460 | 256); 461 | 462 | Item1ValueLen = TranslatedKeyLen + sizeof(WORD); 463 | pKey = (char *)malloc(MALLOC_AMOUNT); 464 | 465 | if (pKey == NULL) 466 | { 467 | printf("Error: Out of memory.\n"); 468 | } 469 | else 470 | cleanup |= FREE_PKEY; 471 | 472 | pTemp = pKey; 473 | 474 | Itemtbl.Length = (sizeof(Itemtbl) + 475 | (1 * (sizeof(Item))) + Item1ValueLen); 476 | Itemtbl.Items = 1; 477 | 478 | memcpy(pTemp, &Itemtbl, sizeof(Itemtbl)); 479 | pTemp += sizeof(Itemtbl); 480 | 481 | Item.NameLength = 0; 482 | Item.ValueLength = Item1ValueLen; 483 | memcpy(pTemp, &Item, sizeof(Item)); 484 | pTemp += sizeof(Item); 485 | 486 | Word = TYPE_TEXT; 487 | memcpy(pTemp, &Word, sizeof(Word)); 488 | pTemp += sizeof(Word); 489 | 490 | memcpy(pTemp, TranslatedKey, TranslatedKeyLen); 491 | pTemp += TranslatedKeyLen; 492 | 493 | if (exact) { 494 | error = NIFFindByKey(hCollection, pKey, FIND_CASE_INSENSITIVE, &CollPosition, &number_match); 495 | } 496 | else { 497 | error = NIFFindByName(hCollection, TranslatedKey, FIND_PARTIAL|FIND_CASE_INSENSITIVE, &CollPosition, &number_match); 498 | } 499 | if (ERR(error) == ERR_NOT_FOUND) { 500 | SetErrorMessage("Note not found in the collection"); 501 | NIFCloseCollection(hCollection); 502 | NSFDbClose(hDB); 503 | NotesTermThread(); 504 | return; 505 | } 506 | if (error) { 507 | DataHelper::GetAPIError(error, error_text); 508 | SetErrorMessage(error_text); 509 | NIFCloseCollection(hCollection); 510 | NSFDbClose(hDB); 511 | NotesTermThread(); 512 | return; 513 | } 514 | 515 | } 516 | else { 517 | FirstTime = FALSE; 518 | } 519 | 520 | 521 | /* Get the note ID and summary of every entry in the collection. In the 522 | returned buffer, first comes all of the info about the first entry, then 523 | all of the info about the 2nd entry, etc. For each entry, the info is 524 | arranged in the order of the bits in the READ_MASKs. */ 525 | 526 | do 527 | { 528 | 529 | if (error = NIFReadEntries( 530 | hCollection, /* handle to this collection */ 531 | &CollPosition, /* where to start in collection */ 532 | (WORD)(FirstTime ? NAVIGATE_CURRENT : NAVIGATE_NEXT), 533 | /* order to use when skipping */ 534 | FirstTime ? 0L : 1L, /* number to skip */ 535 | //NAVIGATE_NEXT, /* order to use when skipping */ 536 | //1L, /* number to skip */ 537 | NAVIGATE_NEXT, /* order to use when reading */ 538 | number_match, 539 | READ_MASK_NOTEID + /* info we want */ 540 | READ_MASK_INDENTLEVELS + 541 | READ_MASK_NOTEUNID+ 542 | READ_MASK_SUMMARY, 543 | &hBuffer, /* handle to info buffer (return) */ 544 | NULL, /* length of info buffer (return) */ 545 | NULL, /* entries skipped (return) */ 546 | &EntriesFound, /* entries read (return) */ 547 | &SignalFlag)) /* share warning and more signal flag 548 | (return) */ 549 | { 550 | NIFCloseCollection(hCollection); 551 | NSFDbClose(hDB); 552 | DataHelper::GetAPIError(error,error_text); 553 | SetErrorMessage(error_text); 554 | NotesTermThread(); 555 | return; 556 | } 557 | 558 | /* Check to make sure there was a buffer of information returned. */ 559 | 560 | if (hBuffer == NULLHANDLE) 561 | { 562 | 563 | NIFCloseCollection(hCollection); 564 | NSFDbClose(hDB); 565 | printf("\nEmpty buffer returned by NIFReadEntries.\n"); 566 | NotesTermThread(); 567 | return; 568 | } 569 | 570 | /* Lock down (freeze the location) of the information buffer. Cast 571 | the resulting pointer to the type we need. */ 572 | 573 | pBuffer = (BYTE *)OSLockObject(hBuffer); 574 | 575 | /* Start a loop that extracts the info about each collection entry from 576 | the information buffer. */ 577 | 578 | for (DWORD i = 1; i <= EntriesFound; i++) 579 | { 580 | 581 | /* Get the ID of this entry. */ 582 | 583 | memcpy(&EntryID, pBuffer, sizeof(EntryID)); 584 | 585 | /* Advance the pointer over the note id. */ 586 | pBuffer += sizeof(EntryID); 587 | 588 | 589 | /* get UNID*/ 590 | memcpy(&EntryUNID, pBuffer, sizeof(EntryUNID)); 591 | pBuffer += sizeof(EntryUNID); 592 | 593 | /* get ident level of entry*/ 594 | entry_indent = *(WORD*)pBuffer; 595 | pBuffer += sizeof(WORD); 596 | 597 | char unid_buffer[33]; 598 | snprintf(unid_buffer, 33, "%08X%08X%08X%08X", EntryUNID.File.Innards[1], EntryUNID.File.Innards[0], EntryUNID.Note.Innards[1], EntryUNID.Note.Innards[0]); 599 | 600 | /* 601 | 602 | entry_index_size = COLLECTIONPOSITIONSIZE 603 | ((COLLECTIONPOSITION*)pBuffer); 604 | */ 605 | /* Get the header for the summary items for this entry. */ 606 | 607 | memcpy(&ItemTable, pBuffer, sizeof(ItemTable)); 608 | 609 | /* Remember where the start of this entry's summary is. Then advance 610 | the main pointer over the summary. */ 611 | 612 | pSummary = pBuffer; 613 | pBuffer += ItemTable.Length; 614 | 615 | /*if (NOTEID_CATEGORY & EntryID) { 616 | entry_indent = 0; 617 | } 618 | else { 619 | entry_indent = 1; 620 | }*/ 621 | 622 | if (category.size() > 0) { 623 | 624 | if (CollPosition.Level == CATEGORY_LEVEL_BEING_SEARCHED) { 625 | /* Indicate that there is no more to do. */ 626 | SignalFlag &= ~SIGNAL_MORE_TO_DO; 627 | break; 628 | } 629 | } 630 | 631 | //if (NOTEID_CATEGORY & EntryID) continue; 632 | 633 | // if (entry_indent != MAIN_TOPIC_INDENT) continue; 634 | 635 | /* Call a local function to print the summary buffer. */ 636 | 637 | if (error = PrintSummary(pSummary,entry_indent,unid_buffer)) 638 | { 639 | printf("error printsummary\n"); 640 | OSUnlockObject(hBuffer); 641 | OSMemFree(hBuffer); 642 | NIFCloseCollection(hCollection); 643 | NSFDbClose(hDB); 644 | DataHelper::GetAPIError(error,error_text); 645 | SetErrorMessage(error_text); 646 | NotesTermThread(); 647 | return; 648 | } 649 | 650 | /* End of loop that gets info about each entry. */ 651 | 652 | } 653 | 654 | /* Unlock the list of note IDs. */ 655 | 656 | OSUnlockObject(hBuffer); 657 | 658 | /* Free the memory allocated by NIFReadEntries. */ 659 | 660 | OSMemFree(hBuffer); 661 | 662 | /* Loop if the end of the collection has not been reached because the buffer 663 | was full. */ 664 | if (FirstTime) 665 | FirstTime = FALSE; 666 | 667 | } while (SignalFlag & SIGNAL_MORE_TO_DO); 668 | 669 | 670 | if (error = NIFCloseCollection(hCollection)) 671 | { 672 | NSFDbClose(hDB); 673 | DataHelper::GetAPIError(error,error_text); 674 | SetErrorMessage(error_text); 675 | NotesTermThread(); 676 | return; 677 | } 678 | 679 | if (error = NSFDbClose(hDB)) 680 | { 681 | DataHelper::GetAPIError(error,error_text); 682 | SetErrorMessage(error_text); 683 | NotesTermThread(); 684 | return; 685 | } 686 | 687 | if (cleanup & FREE_KEY1) 688 | free(Key1); 689 | 690 | if (cleanup & FREE_TRANSLATEDKEY) 691 | free(TranslatedKey); 692 | 693 | if (cleanup & FREE_PKEY) 694 | free(pKey); 695 | NotesTermThread(); 696 | 697 | } 698 | 699 | // Executed when the async work is complete 700 | // this function will be run inside the main event loop 701 | // so it is safe to use V8 again 702 | void HandleOKCallback() { 703 | HandleScope scope; 704 | Local viewRes = New();//DataHelper::getV8Data(viewResult); 705 | 706 | for (size_t j = 0; j < view.size(); j++) { 707 | std::vector column = view[j]; 708 | Local resDoc = Nan::New(); 709 | for (size_t k = 0; k < column.size(); k++) { 710 | DocumentItem *di = column[k]; 711 | if (di->type == 1) { 712 | Nan::Set(resDoc, New(di->name).ToLocalChecked(), New(di->stringValue).ToLocalChecked()); 713 | } 714 | else if (di->type == 2) { 715 | Nan::Set(resDoc, New(di->name).ToLocalChecked(), New(di->numberValue)); 716 | } 717 | else if (di->type == 3) { 718 | Nan::Set(resDoc, New(di->name).ToLocalChecked(), New(di->numberValue).ToLocalChecked()); 719 | } 720 | else if (di->type == 4) { 721 | Local arr = New(); 722 | for (size_t j = 0; j < di->vectorStrValue.size(); j++) { 723 | if (di->vectorStrValue[j]) { 724 | Nan::Set(arr, j, Nan::New(di->vectorStrValue[j]).ToLocalChecked()); 725 | } 726 | } 727 | Nan::Set(resDoc, New(di->name).ToLocalChecked(), arr); 728 | } 729 | } 730 | Nan::Set(viewRes, j, resDoc); 731 | } 732 | Local argv[] = { 733 | Null() 734 | , viewRes 735 | }; 736 | 737 | callback->Call(2, argv); 738 | } 739 | 740 | void HandleErrorCallback() { 741 | HandleScope scope; 742 | Local errorObj = Nan::New(); 743 | Nan::Set(errorObj, New("errorMessage").ToLocalChecked(), New(ErrorMessage()).ToLocalChecked()); 744 | Local argv[] = { 745 | errorObj, 746 | Null() 747 | }; 748 | callback->Call(2, argv); 749 | } 750 | 751 | private: 752 | std::string serverName; 753 | std::string dbName; 754 | std::string viewName; 755 | std::string category; 756 | std::string findByKey; 757 | bool exact; 758 | unsigned long max_matches; 759 | 760 | 761 | }; 762 | 763 | 764 | NAN_METHOD(GetViewAsync) { 765 | v8::Isolate* isolate = info.GetIsolate(); 766 | Local param = (info[0]->ToObject()); 767 | Local viewParam = (info[1]->ToObject()); 768 | Local viewKey = String::NewFromUtf8(isolate, "view"); 769 | Local catKey = String::NewFromUtf8(isolate, "category"); 770 | Local findKey = String::NewFromUtf8(isolate, "findByKey"); 771 | Local exactKey = String::NewFromUtf8(isolate, "exact"); 772 | Local maxKey = String::NewFromUtf8(isolate, "max"); 773 | Local serverKey = String::NewFromUtf8(isolate, "server"); 774 | Local databaseKey = String::NewFromUtf8(isolate, "database"); 775 | Local serverVal = param->Get(serverKey); 776 | Local databaseVal = param->Get(databaseKey); 777 | 778 | Local viewVal = viewParam->Get(viewKey); 779 | 780 | 781 | std::string catStr; 782 | std::string findByKeyStr; 783 | bool exactMatch = false; 784 | unsigned long max = 0xFFFFFFFF; 785 | 786 | if (viewParam->Has(maxKey)) { 787 | Local maxVal = viewParam->Get(maxKey); 788 | max = maxVal->NumberValue(); 789 | } 790 | 791 | if (viewParam->Has(findKey)) { 792 | Local findVal = viewParam->Get(findKey); 793 | if (viewParam->Has(exactKey)) { 794 | Local exactVal = viewParam->Get(exactKey); 795 | exactMatch = exactVal->BooleanValue(); 796 | } 797 | 798 | String::Utf8Value find(findVal->ToString()); 799 | findByKeyStr = std::string(*find); 800 | 801 | 802 | } 803 | 804 | if (viewParam->Has(catKey)) { 805 | Local catVal = viewParam->Get(catKey); 806 | String::Utf8Value cat(catVal->ToString()); 807 | catStr = std::string(*cat); 808 | } 809 | 810 | String::Utf8Value serverName(serverVal->ToString()); 811 | String::Utf8Value dbName(databaseVal->ToString()); 812 | String::Utf8Value view(viewVal->ToString()); 813 | 814 | 815 | std::string serverStr; 816 | std::string dbStr; 817 | std::string viewStr; 818 | 819 | serverStr = std::string(*serverName); 820 | dbStr = std::string(*dbName); 821 | viewStr = std::string(*view); 822 | 823 | 824 | Callback *callback = new Callback(info[2].As()); 825 | 826 | AsyncQueueWorker(new ViewWorker(callback, serverStr, dbStr, viewStr,catStr,findByKeyStr,exactMatch,max)); 827 | } 828 | -------------------------------------------------------------------------------- /src/view_async.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Domino addon for Node.js 3 | * 4 | * Copyright (c) 2016 Nils T. Hjelme 5 | * 6 | * The MIT License (MIT) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | *******************************************************************************/ 26 | 27 | #ifndef ASYNC_VIEW_ASYNC_H_ 28 | #define ASYNC_VIEW_ASYNC_H_ 29 | 30 | #include 31 | #include "global.h" 32 | 33 | NAN_METHOD(GetViewAsync); 34 | 35 | #endif // ASYNC_VIEW_ASYNC_H_ 36 | -------------------------------------------------------------------------------- /test2.js: -------------------------------------------------------------------------------- 1 | var dominoDriver = require('./build/Release/addon'); --------------------------------------------------------------------------------